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 } 212