From 500675a7c8c72bd6b1054a7eb4daaf61970f5ad7 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Sat, 21 Dec 2024 15:54:34 -0500 Subject: [PATCH] cmd/compile: load map length with the right type len(map) is lowered to loading the first field of the map structure, which is the length. Currently it is a load of an int. With the old map, the first field is indeed an int. With Swiss map, however, it is a uint64. On big-endian 32-bit machine, loading an (32-bit) int from a uint64 would load just the high bits, which are (probably) all 0. Change to a load with the proper type. Fixes #70248. Change-Id: I39cf2d1e6658dac5a8de25c858e1580e2a14b894 Reviewed-on: https://go-review.googlesource.com/c/go/+/638375 Run-TryBot: Cherry Mui LUCI-TryBot-Result: Go LUCI TryBot-Result: Gopher Robot Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssagen/ssa.go | 13 +++++++++---- src/internal/runtime/maps/map.go | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index dc9b508c01ed12..edd1ffb0c915e8 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -5452,12 +5452,15 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value { if n.X.Type().IsChan() && n.Op() == ir.OCAP { s.Fatalf("cannot inline cap(chan)") // must use runtime.chancap now } + if n.X.Type().IsMap() && n.Op() == ir.OCAP { + s.Fatalf("cannot inline cap(map)") // cap(map) does not exist + } // if n == nil { // return 0 // } else { - // // len - // return *((*int)n) - // // cap + // // len, the actual loadType depends + // return int(*((*loadType)n)) + // // cap (chan only, not used for now) // return *(((*int)n)+1) // } lenType := n.Type() @@ -5485,7 +5488,9 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value { case ir.OLEN: if buildcfg.Experiment.SwissMap && n.X.Type().IsMap() { // length is stored in the first word. - s.vars[n] = s.load(lenType, x) + loadType := reflectdata.SwissMapType().Field(0).Type // uint64 + load := s.load(loadType, x) + s.vars[n] = s.conv(nil, load, loadType, lenType) // integer conversion doesn't need Node } else { // length is stored in the first word for map/chan s.vars[n] = s.load(lenType, x) diff --git a/src/internal/runtime/maps/map.go b/src/internal/runtime/maps/map.go index ffafcacdea1bc7..62463351c7d2de 100644 --- a/src/internal/runtime/maps/map.go +++ b/src/internal/runtime/maps/map.go @@ -194,6 +194,7 @@ func h2(h uintptr) uintptr { type Map struct { // The number of filled slots (i.e. the number of elements in all // tables). Excludes deleted slots. + // Must be first (known by the compiler, for len() builtin). used uint64 // seed is the hash seed, computed as a unique random number per map.