]> Cypherpunks repositories - gostls13.git/commitdiff
sync: prevent (*Map).Range from always escaping
authorMauri de Souza Meneguzzo <mauri870@gmail.com>
Fri, 1 Sep 2023 18:26:49 +0000 (18:26 +0000)
committerGopher Robot <gobot@golang.org>
Fri, 1 Sep 2023 22:41:39 +0000 (22:41 +0000)
After the change from CL 426074 the Range method on Map always
escape the read variable, leading to an allocation.

Since the compiler doesn't do live-range splitting for local variables we
need to use some hints to only escape in that particular branch.

Fixes #62404

Change-Id: I938a5e593647455fa827e3dd3ed8ea22c7365df1
GitHub-Last-Rev: fcbedb467c7b4e6f1d49e299d243cad70deb34e9
GitHub-Pull-Request: golang/go#62408
Reviewed-on: https://go-review.googlesource.com/c/go/+/524976
Auto-Submit: Bryan Mills <bcmills@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/sync/map.go
src/sync/map_test.go

index e8ccf58b56b34bf472aaedc737e631995dc1cb46..00b2446153c33e024a8f8696382fff4116e91f50 100644 (file)
@@ -461,7 +461,8 @@ func (m *Map) Range(f func(key, value any) bool) {
                read = m.loadReadOnly()
                if read.amended {
                        read = readOnly{m: m.dirty}
-                       m.read.Store(&read)
+                       copyRead := read
+                       m.read.Store(&copyRead)
                        m.dirty = nil
                        m.misses = 0
                }
index 1eb3fc68a5330dad8304d20cab0a1f36c11be674..20872f3b72ba447c142900ccf6d8709929d34d10 100644 (file)
@@ -5,6 +5,7 @@
 package sync_test
 
 import (
+       "internal/testenv"
        "math/rand"
        "reflect"
        "runtime"
@@ -280,3 +281,16 @@ func TestCompareAndSwap_NonExistingKey(t *testing.T) {
                t.Fatalf("CompareAndSwap on an non-existing key succeeded")
        }
 }
+
+func TestMapRangeNoAllocations(t *testing.T) { // Issue 62404
+       testenv.SkipIfOptimizationOff(t)
+       var m sync.Map
+       allocs := testing.AllocsPerRun(10, func() {
+               m.Range(func(key, value any) bool {
+                       return true
+               })
+       })
+       if allocs > 0 {
+               t.Errorf("AllocsPerRun of m.Range = %v; want 0", allocs)
+       }
+}