| // Copyright 2025 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package runtime |
| |
| import ( |
| "internal/abi" |
| "internal/runtime/maps" |
| "internal/runtime/sys" |
| "unsafe" |
| ) |
| |
| // Legacy //go:linkname compatibility shims |
| // |
| // The functions below are unused by the toolchain, and exist only for |
| // compatibility with existing //go:linkname use in the ecosystem. |
| |
| // linknameIter is the it argument to mapiterinit and mapiternext. |
| // |
| // Callers of mapiterinit allocate their own iter structure, which has the |
| // layout of the pre-Go 1.24 hiter structure, shown here for posterity: |
| // |
| // type hiter struct { |
| // key unsafe.Pointer |
| // elem unsafe.Pointer |
| // t *maptype // old map abi.Type |
| // h *hmap |
| // buckets unsafe.Pointer |
| // bptr *bmap |
| // overflow *[]*bmap |
| // oldoverflow *[]*bmap |
| // startBucket uintptr |
| // offset uint8 |
| // wrapped bool |
| // B uint8 |
| // i uint8 |
| // bucket uintptr |
| // checkBucket uintptr |
| // } |
| // |
| // Our structure must maintain compatibility with the old structure. This |
| // means: |
| // |
| // - Our structure must be the same size or smaller than hiter. Otherwise we |
| // may write outside the caller's hiter allocation. |
| // - Our structure must have the same pointer layout as hiter, so that the GC |
| // tracks pointers properly. |
| // |
| // Based on analysis of the "hall of shame" users of these linknames: |
| // |
| // - The key and elem fields must be kept up to date with the current key/elem. |
| // Some users directly access the key and elem fields rather than calling |
| // reflect.mapiterkey/reflect.mapiterelem. |
| // - The t field must be non-nil after mapiterinit. gonum.org/v1/gonum uses |
| // this to verify the iterator is initialized. |
| // - github.com/segmentio/encoding and github.com/RomiChan/protobuf check if h |
| // is non-nil, but the code has no effect. Thus the value of h does not |
| // matter. See internal/runtime_reflect/map.go. |
| type linknameIter struct { |
| // Fields from hiter. |
| key unsafe.Pointer |
| elem unsafe.Pointer |
| typ *abi.MapType |
| |
| // The real iterator. |
| it *maps.Iter |
| } |
| |
| // mapiterinit is a compatibility wrapper for map iterator for users of |
| // //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| // should use reflect or the maps package. |
| // |
| // mapiterinit should be an internal detail, |
| // but widely used packages access it using linkname. |
| // Notable members of the hall of shame include: |
| // - github.com/bytedance/sonic |
| // - github.com/goccy/go-json |
| // - github.com/RomiChan/protobuf |
| // - github.com/segmentio/encoding |
| // - github.com/ugorji/go/codec |
| // - github.com/wI2L/jettison |
| // |
| // Do not remove or change the type signature. |
| // See go.dev/issue/67401. |
| // |
| //go:linkname mapiterinit |
| func mapiterinit(t *abi.MapType, m *maps.Map, it *linknameIter) { |
| if raceenabled && m != nil { |
| callerpc := sys.GetCallerPC() |
| racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapiterinit)) |
| } |
| |
| it.typ = t |
| |
| it.it = new(maps.Iter) |
| it.it.Init(t, m) |
| it.it.Next() |
| |
| it.key = it.it.Key() |
| it.elem = it.it.Elem() |
| } |
| |
| // reflect_mapiterinit is a compatibility wrapper for map iterator for users of |
| // //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| // should use reflect or the maps package. |
| // |
| // reflect_mapiterinit should be an internal detail, |
| // but widely used packages access it using linkname. |
| // Notable members of the hall of shame include: |
| // - github.com/modern-go/reflect2 |
| // - gitee.com/quant1x/gox |
| // - github.com/v2pro/plz |
| // - github.com/wI2L/jettison |
| // |
| // Do not remove or change the type signature. |
| // See go.dev/issue/67401. |
| // |
| //go:linkname reflect_mapiterinit reflect.mapiterinit |
| func reflect_mapiterinit(t *abi.MapType, m *maps.Map, it *linknameIter) { |
| mapiterinit(t, m, it) |
| } |
| |
| // mapiternext is a compatibility wrapper for map iterator for users of |
| // //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| // should use reflect or the maps package. |
| // |
| // mapiternext should be an internal detail, |
| // but widely used packages access it using linkname. |
| // Notable members of the hall of shame include: |
| // - github.com/bytedance/sonic |
| // - github.com/RomiChan/protobuf |
| // - github.com/segmentio/encoding |
| // - github.com/ugorji/go/codec |
| // - gonum.org/v1/gonum |
| // |
| // Do not remove or change the type signature. |
| // See go.dev/issue/67401. |
| // |
| //go:linkname mapiternext |
| func mapiternext(it *linknameIter) { |
| if raceenabled { |
| callerpc := sys.GetCallerPC() |
| racereadpc(unsafe.Pointer(it.it.Map()), callerpc, abi.FuncPCABIInternal(mapiternext)) |
| } |
| |
| it.it.Next() |
| |
| it.key = it.it.Key() |
| it.elem = it.it.Elem() |
| } |
| |
| // reflect_mapiternext is a compatibility wrapper for map iterator for users of |
| // //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| // should use reflect or the maps package. |
| // |
| // reflect_mapiternext is for package reflect, |
| // but widely used packages access it using linkname. |
| // Notable members of the hall of shame include: |
| // - gitee.com/quant1x/gox |
| // - github.com/modern-go/reflect2 |
| // - github.com/goccy/go-json |
| // - github.com/v2pro/plz |
| // - github.com/wI2L/jettison |
| // |
| // Do not remove or change the type signature. |
| // See go.dev/issue/67401. |
| // |
| //go:linkname reflect_mapiternext reflect.mapiternext |
| func reflect_mapiternext(it *linknameIter) { |
| mapiternext(it) |
| } |
| |
| // reflect_mapiterkey is a compatibility wrapper for map iterator for users of |
| // //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| // should use reflect or the maps package. |
| // |
| // reflect_mapiterkey should be an internal detail, |
| // but widely used packages access it using linkname. |
| // Notable members of the hall of shame include: |
| // - github.com/goccy/go-json |
| // - gonum.org/v1/gonum |
| // |
| // Do not remove or change the type signature. |
| // See go.dev/issue/67401. |
| // |
| //go:linkname reflect_mapiterkey reflect.mapiterkey |
| func reflect_mapiterkey(it *linknameIter) unsafe.Pointer { |
| return it.it.Key() |
| } |
| |
| // reflect_mapiterelem is a compatibility wrapper for map iterator for users of |
| // //go:linkname from before Go 1.24. It is not used by Go itself. New users |
| // should use reflect or the maps package. |
| // |
| // reflect_mapiterelem should be an internal detail, |
| // but widely used packages access it using linkname. |
| // Notable members of the hall of shame include: |
| // - github.com/goccy/go-json |
| // - gonum.org/v1/gonum |
| // |
| // Do not remove or change the type signature. |
| // See go.dev/issue/67401. |
| // |
| //go:linkname reflect_mapiterelem reflect.mapiterelem |
| func reflect_mapiterelem(it *linknameIter) unsafe.Pointer { |
| return it.it.Elem() |
| } |