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 <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Cherry Mui 2024-12-21 15:54:34 -05:00
parent 06b191e11f
commit 500675a7c8
2 changed files with 10 additions and 4 deletions

View file

@ -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 { if n.X.Type().IsChan() && n.Op() == ir.OCAP {
s.Fatalf("cannot inline cap(chan)") // must use runtime.chancap now 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 { // if n == nil {
// return 0 // return 0
// } else { // } else {
// // len // // len, the actual loadType depends
// return *((*int)n) // return int(*((*loadType)n))
// // cap // // cap (chan only, not used for now)
// return *(((*int)n)+1) // return *(((*int)n)+1)
// } // }
lenType := n.Type() lenType := n.Type()
@ -5485,7 +5488,9 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
case ir.OLEN: case ir.OLEN:
if buildcfg.Experiment.SwissMap && n.X.Type().IsMap() { if buildcfg.Experiment.SwissMap && n.X.Type().IsMap() {
// length is stored in the first word. // 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 { } else {
// length is stored in the first word for map/chan // length is stored in the first word for map/chan
s.vars[n] = s.load(lenType, x) s.vars[n] = s.load(lenType, x)

View file

@ -194,6 +194,7 @@ func h2(h uintptr) uintptr {
type Map struct { type Map struct {
// The number of filled slots (i.e. the number of elements in all // The number of filled slots (i.e. the number of elements in all
// tables). Excludes deleted slots. // tables). Excludes deleted slots.
// Must be first (known by the compiler, for len() builtin).
used uint64 used uint64
// seed is the hash seed, computed as a unique random number per map. // seed is the hash seed, computed as a unique random number per map.