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