]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: load map length with the right type
authorCherry Mui <cherryyz@google.com>
Sat, 21 Dec 2024 20:54:34 +0000 (15:54 -0500)
committerCherry Mui <cherryyz@google.com>
Sun, 22 Dec 2024 03:25:03 +0000 (19:25 -0800)
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>
src/cmd/compile/internal/ssagen/ssa.go
src/internal/runtime/maps/map.go

index dc9b508c01ed12c69970eb9797f5f55c4e3fc47f..edd1ffb0c915e89d2c2b82a16b3fc7a191a2fd55 100644 (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 {
                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)
index ffafcacdea1bc77e9c737a158c5793a8afea212d..62463351c7d2de4a28a1ab317aba2afbdc92da3b 100644 (file)
@@ -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.