|
| 1 | +// Copyright 2025 The Go Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style |
| 3 | +// license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +//go:build goexperiment.swissmap |
| 6 | + |
| 7 | +package runtime |
| 8 | + |
| 9 | +import ( |
| 10 | + "internal/abi" |
| 11 | + "internal/runtime/maps" |
| 12 | + "internal/runtime/sys" |
| 13 | + "unsafe" |
| 14 | +) |
| 15 | + |
| 16 | +// Legacy //go:linkname compatibility shims |
| 17 | +// |
| 18 | +// The functions below are unused by the toolchain, and exist only for |
| 19 | +// compatibility with existing //go:linkname use in the ecosystem (and in |
| 20 | +// map_noswiss.go for normal use via GOEXPERIMENT=noswissmap). |
| 21 | + |
| 22 | +// linknameIter is the it argument to mapiterinit and mapiternext. |
| 23 | +// |
| 24 | +// Callers of mapiterinit allocate their own iter structure, which has the |
| 25 | +// layout of the pre-Go 1.24 hiter structure, shown here for posterity: |
| 26 | +// |
| 27 | +// type hiter struct { |
| 28 | +// key unsafe.Pointer |
| 29 | +// elem unsafe.Pointer |
| 30 | +// t *maptype |
| 31 | +// h *hmap |
| 32 | +// buckets unsafe.Pointer |
| 33 | +// bptr *bmap |
| 34 | +// overflow *[]*bmap |
| 35 | +// oldoverflow *[]*bmap |
| 36 | +// startBucket uintptr |
| 37 | +// offset uint8 |
| 38 | +// wrapped bool |
| 39 | +// B uint8 |
| 40 | +// i uint8 |
| 41 | +// bucket uintptr |
| 42 | +// checkBucket uintptr |
| 43 | +// } |
| 44 | +// |
| 45 | +// Our structure must maintain compatibility with the old structure. This |
| 46 | +// means: |
| 47 | +// |
| 48 | +// - Our structure must be the same size or smaller than hiter. Otherwise we |
| 49 | +// may write outside the caller's hiter allocation. |
| 50 | +// - Our structure must have the same pointer layout as hiter, so that the GC |
| 51 | +// tracks pointers properly. |
| 52 | +// |
| 53 | +// Based on analysis of the "hall of shame" users of these linknames: |
| 54 | +// |
| 55 | +// - The key and elem fields must be kept up to date with the current key/elem. |
| 56 | +// Some users directly access the key and elem fields rather than calling |
| 57 | +// reflect.mapiterkey/reflect.mapiterelem. |
| 58 | +// - The t field must be non-nil after mapiterinit. gonum.org/v1/gonum uses |
| 59 | +// this to verify the iterator is initialized. |
| 60 | +// - github.com/segmentio/encoding and github.com/RomiChan/protobuf check if h |
| 61 | +// is non-nil, but the code has no effect. Thus the value of h does not |
| 62 | +// matter. See internal/runtime_reflect/map.go. |
| 63 | +type linknameIter struct { |
| 64 | + // Fields from hiter. |
| 65 | + key unsafe.Pointer |
| 66 | + elem unsafe.Pointer |
| 67 | + typ *abi.SwissMapType |
| 68 | + |
| 69 | + // The real iterator. |
| 70 | + it *maps.Iter |
| 71 | +} |
| 72 | + |
| 73 | +// mapiterinit is a compatibility wrapper for map iterator for users of |
| 74 | +// //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| 75 | +// should use reflect or the maps package. |
| 76 | +// |
| 77 | +// mapiterinit should be an internal detail, |
| 78 | +// but widely used packages access it using linkname. |
| 79 | +// Notable members of the hall of shame include: |
| 80 | +// - github.com/bytedance/sonic |
| 81 | +// - github.com/goccy/go-json |
| 82 | +// - github.com/RomiChan/protobuf |
| 83 | +// - github.com/segmentio/encoding |
| 84 | +// - github.com/ugorji/go/codec |
| 85 | +// - github.com/wI2L/jettison |
| 86 | +// |
| 87 | +// Do not remove or change the type signature. |
| 88 | +// See go.dev/issue/67401. |
| 89 | +// |
| 90 | +//go:linkname mapiterinit |
| 91 | +func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *linknameIter) { |
| 92 | + if raceenabled && m != nil { |
| 93 | + callerpc := sys.GetCallerPC() |
| 94 | + racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapiterinit)) |
| 95 | + } |
| 96 | + |
| 97 | + it.typ = t |
| 98 | + |
| 99 | + it.it = new(maps.Iter) |
| 100 | + it.it.Init(t, m) |
| 101 | + it.it.Next() |
| 102 | + |
| 103 | + it.key = it.it.Key() |
| 104 | + it.elem = it.it.Elem() |
| 105 | +} |
| 106 | + |
| 107 | +// reflect_mapiterinit is a compatibility wrapper for map iterator for users of |
| 108 | +// //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| 109 | +// should use reflect or the maps package. |
| 110 | +// |
| 111 | +// reflect_mapiterinit should be an internal detail, |
| 112 | +// but widely used packages access it using linkname. |
| 113 | +// Notable members of the hall of shame include: |
| 114 | +// - github.com/modern-go/reflect2 |
| 115 | +// - gitee.com/quant1x/gox |
| 116 | +// - github.com/v2pro/plz |
| 117 | +// - github.com/wI2L/jettison |
| 118 | +// |
| 119 | +// Do not remove or change the type signature. |
| 120 | +// See go.dev/issue/67401. |
| 121 | +// |
| 122 | +//go:linkname reflect_mapiterinit reflect.mapiterinit |
| 123 | +func reflect_mapiterinit(t *abi.SwissMapType, m *maps.Map, it *linknameIter) { |
| 124 | + mapiterinit(t, m, it) |
| 125 | +} |
| 126 | + |
| 127 | +// mapiternext is a compatibility wrapper for map iterator for users of |
| 128 | +// //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| 129 | +// should use reflect or the maps package. |
| 130 | +// |
| 131 | +// mapiternext should be an internal detail, |
| 132 | +// but widely used packages access it using linkname. |
| 133 | +// Notable members of the hall of shame include: |
| 134 | +// - github.com/bytedance/sonic |
| 135 | +// - github.com/RomiChan/protobuf |
| 136 | +// - github.com/segmentio/encoding |
| 137 | +// - github.com/ugorji/go/codec |
| 138 | +// - gonum.org/v1/gonum |
| 139 | +// |
| 140 | +// Do not remove or change the type signature. |
| 141 | +// See go.dev/issue/67401. |
| 142 | +// |
| 143 | +//go:linkname mapiternext |
| 144 | +func mapiternext(it *linknameIter) { |
| 145 | + if raceenabled { |
| 146 | + callerpc := sys.GetCallerPC() |
| 147 | + racereadpc(unsafe.Pointer(it.it.Map()), callerpc, abi.FuncPCABIInternal(mapiternext)) |
| 148 | + } |
| 149 | + |
| 150 | + it.it.Next() |
| 151 | + |
| 152 | + it.key = it.it.Key() |
| 153 | + it.elem = it.it.Elem() |
| 154 | +} |
| 155 | + |
| 156 | +// reflect_mapiternext is a compatibility wrapper for map iterator for users of |
| 157 | +// //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| 158 | +// should use reflect or the maps package. |
| 159 | +// |
| 160 | +// reflect_mapiternext is for package reflect, |
| 161 | +// but widely used packages access it using linkname. |
| 162 | +// Notable members of the hall of shame include: |
| 163 | +// - gitee.com/quant1x/gox |
| 164 | +// - github.com/modern-go/reflect2 |
| 165 | +// - github.com/goccy/go-json |
| 166 | +// - github.com/v2pro/plz |
| 167 | +// - github.com/wI2L/jettison |
| 168 | +// |
| 169 | +// Do not remove or change the type signature. |
| 170 | +// See go.dev/issue/67401. |
| 171 | +// |
| 172 | +//go:linkname reflect_mapiternext reflect.mapiternext |
| 173 | +func reflect_mapiternext(it *linknameIter) { |
| 174 | + mapiternext(it) |
| 175 | +} |
| 176 | + |
| 177 | +// reflect_mapiterkey is a compatibility wrapper for map iterator for users of |
| 178 | +// //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| 179 | +// should use reflect or the maps package. |
| 180 | +// |
| 181 | +// reflect_mapiterkey should be an internal detail, |
| 182 | +// but widely used packages access it using linkname. |
| 183 | +// Notable members of the hall of shame include: |
| 184 | +// - github.com/goccy/go-json |
| 185 | +// - gonum.org/v1/gonum |
| 186 | +// |
| 187 | +// Do not remove or change the type signature. |
| 188 | +// See go.dev/issue/67401. |
| 189 | +// |
| 190 | +//go:linkname reflect_mapiterkey reflect.mapiterkey |
| 191 | +func reflect_mapiterkey(it *linknameIter) unsafe.Pointer { |
| 192 | + return it.it.Key() |
| 193 | +} |
| 194 | + |
| 195 | +// reflect_mapiterelem is a compatibility wrapper for map iterator for users of |
| 196 | +// //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| 197 | +// should use reflect or the maps package. |
| 198 | +// |
| 199 | +// reflect_mapiterelem should be an internal detail, |
| 200 | +// but widely used packages access it using linkname. |
| 201 | +// Notable members of the hall of shame include: |
| 202 | +// - github.com/goccy/go-json |
| 203 | +// - gonum.org/v1/gonum |
| 204 | +// |
| 205 | +// Do not remove or change the type signature. |
| 206 | +// See go.dev/issue/67401. |
| 207 | +// |
| 208 | +//go:linkname reflect_mapiterelem reflect.mapiterelem |
| 209 | +func reflect_mapiterelem(it *linknameIter) unsafe.Pointer { |
| 210 | + return it.it.Elem() |
| 211 | +} |
0 commit comments