Skip to content

Commit 500675a

Browse files
committed
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 06b191e commit 500675a

File tree

2 files changed

+10
-4
lines changed
  • src
    • cmd/compile/internal/ssagen
    • internal/runtime/maps

2 files changed

+10
-4
lines changed

src/cmd/compile/internal/ssagen/ssa.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -5452,12 +5452,15 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
54525452
if n.X.Type().IsChan() && n.Op() == ir.OCAP {
54535453
s.Fatalf("cannot inline cap(chan)") // must use runtime.chancap now
54545454
}
5455+
if n.X.Type().IsMap() && n.Op() == ir.OCAP {
5456+
s.Fatalf("cannot inline cap(map)") // cap(map) does not exist
5457+
}
54555458
// if n == nil {
54565459
// return 0
54575460
// } else {
5458-
// // len
5459-
// return *((*int)n)
5460-
// // cap
5461+
// // len, the actual loadType depends
5462+
// return int(*((*loadType)n))
5463+
// // cap (chan only, not used for now)
54615464
// return *(((*int)n)+1)
54625465
// }
54635466
lenType := n.Type()
@@ -5485,7 +5488,9 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
54855488
case ir.OLEN:
54865489
if buildcfg.Experiment.SwissMap && n.X.Type().IsMap() {
54875490
// length is stored in the first word.
5488-
s.vars[n] = s.load(lenType, x)
5491+
loadType := reflectdata.SwissMapType().Field(0).Type // uint64
5492+
load := s.load(loadType, x)
5493+
s.vars[n] = s.conv(nil, load, loadType, lenType) // integer conversion doesn't need Node
54895494
} else {
54905495
// length is stored in the first word for map/chan
54915496
s.vars[n] = s.load(lenType, x)

src/internal/runtime/maps/map.go

+1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ func h2(h uintptr) uintptr {
194194
type Map struct {
195195
// The number of filled slots (i.e. the number of elements in all
196196
// tables). Excludes deleted slots.
197+
// Must be first (known by the compiler, for len() builtin).
197198
used uint64
198199

199200
// seed is the hash seed, computed as a unique random number per map.

0 commit comments

Comments
 (0)