aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/map.go
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2025-07-25 15:35:36 -0400
committerGopher Robot <gobot@golang.org>2025-07-30 11:47:14 -0700
commit2ae059ccaf982c3304fae0b48c1d78ad7192cbdd (patch)
treedc3fda38ac232193ff6b3978978dc41e9906bbe0 /src/runtime/map.go
parentcc571dab91e73413cf2ba1546a4ba485038cf2d1 (diff)
downloadgo-2ae059ccaf982c3304fae0b48c1d78ad7192cbdd.tar.xz
all: remove GOEXPERIMENT=swissmap
For #54766. Change-Id: I6a6a636c40b5fe2e8b0d4a5e23933492bc8bb76e Reviewed-on: https://go-review.googlesource.com/c/go/+/691595 Reviewed-by: Keith Randall <khr@google.com> Auto-Submit: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/runtime/map.go')
-rw-r--r--src/runtime/map.go329
1 files changed, 329 insertions, 0 deletions
diff --git a/src/runtime/map.go b/src/runtime/map.go
new file mode 100644
index 0000000000..facf86e494
--- /dev/null
+++ b/src/runtime/map.go
@@ -0,0 +1,329 @@
+// Copyright 2014 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"
+)
+
+const (
+ // TODO: remove? These are used by tests but not the actual map
+ loadFactorNum = 7
+ loadFactorDen = 8
+)
+
+//go:linkname maps_errNilAssign internal/runtime/maps.errNilAssign
+var maps_errNilAssign error = plainError("assignment to entry in nil map")
+
+func makemap64(t *abi.SwissMapType, hint int64, m *maps.Map) *maps.Map {
+ if int64(int(hint)) != hint {
+ hint = 0
+ }
+ return makemap(t, int(hint), m)
+}
+
+// makemap_small implements Go map creation for make(map[k]v) and
+// make(map[k]v, hint) when hint is known to be at most abi.SwissMapGroupSlots
+// at compile time and the map needs to be allocated on the heap.
+//
+// makemap_small 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
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname makemap_small
+func makemap_small() *maps.Map {
+ return maps.NewEmptyMap()
+}
+
+// makemap implements Go map creation for make(map[k]v, hint).
+// If the compiler has determined that the map or the first group
+// can be created on the stack, m and optionally m.dirPtr may be non-nil.
+// If m != nil, the map can be created directly in m.
+// If m.dirPtr != nil, it points to a group usable for a small map.
+//
+// makemap should be an internal detail,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/ugorji/go/codec
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname makemap
+func makemap(t *abi.SwissMapType, hint int, m *maps.Map) *maps.Map {
+ if hint < 0 {
+ hint = 0
+ }
+
+ return maps.NewMap(t, uintptr(hint), m, maxAlloc)
+}
+
+// mapaccess1 returns a pointer to h[key]. Never returns nil, instead
+// it will return a reference to the zero object for the elem type if
+// the key is not in the map.
+// NOTE: The returned pointer may keep the whole map live, so don't
+// hold onto it for very long.
+//
+// mapaccess1 is pushed from internal/runtime/maps. We could just call it, but
+// we want to avoid one layer of call.
+//
+//go:linkname mapaccess1
+func mapaccess1(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) unsafe.Pointer
+
+// mapaccess2 should be an internal detail,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/ugorji/go/codec
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname mapaccess2
+func mapaccess2(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) (unsafe.Pointer, bool)
+
+func mapaccess1_fat(t *abi.SwissMapType, m *maps.Map, key, zero unsafe.Pointer) unsafe.Pointer {
+ e := mapaccess1(t, m, key)
+ if e == unsafe.Pointer(&zeroVal[0]) {
+ return zero
+ }
+ return e
+}
+
+func mapaccess2_fat(t *abi.SwissMapType, m *maps.Map, key, zero unsafe.Pointer) (unsafe.Pointer, bool) {
+ e := mapaccess1(t, m, key)
+ if e == unsafe.Pointer(&zeroVal[0]) {
+ return zero, false
+ }
+ return e, true
+}
+
+// mapassign is pushed from internal/runtime/maps. We could just call it, but
+// we want to avoid one layer of call.
+//
+// mapassign 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
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname mapassign
+func mapassign(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) unsafe.Pointer
+
+// mapdelete should be an internal detail,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/ugorji/go/codec
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname mapdelete
+func mapdelete(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) {
+ if raceenabled && m != nil {
+ callerpc := sys.GetCallerPC()
+ pc := abi.FuncPCABIInternal(mapdelete)
+ racewritepc(unsafe.Pointer(m), callerpc, pc)
+ raceReadObjectPC(t.Key, key, callerpc, pc)
+ }
+ if msanenabled && m != nil {
+ msanread(key, t.Key.Size_)
+ }
+ if asanenabled && m != nil {
+ asanread(key, t.Key.Size_)
+ }
+
+ m.Delete(t, key)
+}
+
+// mapIterStart initializes the Iter struct used for ranging over maps and
+// performs the first step of iteration. The Iter struct pointed to by 'it' is
+// allocated on the stack by the compilers order pass or on the heap by
+// reflect. Both need to have zeroed it since the struct contains pointers.
+func mapIterStart(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) {
+ if raceenabled && m != nil {
+ callerpc := sys.GetCallerPC()
+ racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapIterStart))
+ }
+
+ it.Init(t, m)
+ it.Next()
+}
+
+// mapIterNext performs the next step of iteration. Afterwards, the next
+// key/elem are in it.Key()/it.Elem().
+func mapIterNext(it *maps.Iter) {
+ if raceenabled {
+ callerpc := sys.GetCallerPC()
+ racereadpc(unsafe.Pointer(it.Map()), callerpc, abi.FuncPCABIInternal(mapIterNext))
+ }
+
+ it.Next()
+}
+
+// mapclear deletes all keys from a map.
+func mapclear(t *abi.SwissMapType, m *maps.Map) {
+ if raceenabled && m != nil {
+ callerpc := sys.GetCallerPC()
+ pc := abi.FuncPCABIInternal(mapclear)
+ racewritepc(unsafe.Pointer(m), callerpc, pc)
+ }
+
+ m.Clear(t)
+}
+
+// Reflect stubs. Called from ../reflect/asm_*.s
+
+// reflect_makemap 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/RomiChan/protobuf
+// - github.com/segmentio/encoding
+// - github.com/v2pro/plz
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname reflect_makemap reflect.makemap
+func reflect_makemap(t *abi.SwissMapType, cap int) *maps.Map {
+ // Check invariants and reflects math.
+ if t.Key.Equal == nil {
+ throw("runtime.reflect_makemap: unsupported map key type")
+ }
+ // TODO: other checks
+
+ return makemap(t, cap, nil)
+}
+
+// reflect_mapaccess 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/v2pro/plz
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname reflect_mapaccess reflect.mapaccess
+func reflect_mapaccess(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) unsafe.Pointer {
+ elem, ok := mapaccess2(t, m, key)
+ if !ok {
+ // reflect wants nil for a missing element
+ elem = nil
+ }
+ return elem
+}
+
+//go:linkname reflect_mapaccess_faststr reflect.mapaccess_faststr
+func reflect_mapaccess_faststr(t *abi.SwissMapType, m *maps.Map, key string) unsafe.Pointer {
+ elem, ok := mapaccess2_faststr(t, m, key)
+ if !ok {
+ // reflect wants nil for a missing element
+ elem = nil
+ }
+ return elem
+}
+
+// reflect_mapassign 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/v2pro/plz
+//
+// Do not remove or change the type signature.
+//
+//go:linkname reflect_mapassign reflect.mapassign0
+func reflect_mapassign(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer, elem unsafe.Pointer) {
+ p := mapassign(t, m, key)
+ typedmemmove(t.Elem, p, elem)
+}
+
+//go:linkname reflect_mapassign_faststr reflect.mapassign_faststr0
+func reflect_mapassign_faststr(t *abi.SwissMapType, m *maps.Map, key string, elem unsafe.Pointer) {
+ p := mapassign_faststr(t, m, key)
+ typedmemmove(t.Elem, p, elem)
+}
+
+//go:linkname reflect_mapdelete reflect.mapdelete
+func reflect_mapdelete(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) {
+ mapdelete(t, m, key)
+}
+
+//go:linkname reflect_mapdelete_faststr reflect.mapdelete_faststr
+func reflect_mapdelete_faststr(t *abi.SwissMapType, m *maps.Map, key string) {
+ mapdelete_faststr(t, m, key)
+}
+
+// reflect_maplen is for package reflect,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/goccy/go-json
+// - github.com/wI2L/jettison
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname reflect_maplen reflect.maplen
+func reflect_maplen(m *maps.Map) int {
+ if m == nil {
+ return 0
+ }
+ if raceenabled {
+ callerpc := sys.GetCallerPC()
+ racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(reflect_maplen))
+ }
+ return int(m.Used())
+}
+
+//go:linkname reflect_mapclear reflect.mapclear
+func reflect_mapclear(t *abi.SwissMapType, m *maps.Map) {
+ mapclear(t, m)
+}
+
+//go:linkname reflectlite_maplen internal/reflectlite.maplen
+func reflectlite_maplen(m *maps.Map) int {
+ if m == nil {
+ return 0
+ }
+ if raceenabled {
+ callerpc := sys.GetCallerPC()
+ racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(reflect_maplen))
+ }
+ return int(m.Used())
+}
+
+// mapinitnoop is a no-op function known the Go linker; if a given global
+// map (of the right size) is determined to be dead, the linker will
+// rewrite the relocation (from the package init func) from the outlined
+// map init function to this symbol. Defined in assembly so as to avoid
+// complications with instrumentation (coverage, etc).
+func mapinitnoop()
+
+// mapclone for implementing maps.Clone
+//
+//go:linkname mapclone maps.clone
+func mapclone(m any) any {
+ e := efaceOf(&m)
+ typ := (*abi.SwissMapType)(unsafe.Pointer(e._type))
+ map_ := (*maps.Map)(e.data)
+ map_ = map_.Clone(typ)
+ e.data = (unsafe.Pointer)(map_)
+ return m
+}