aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMauri de Souza Meneguzzo <mauri870@gmail.com>2023-09-01 18:26:49 +0000
committerGopher Robot <gobot@golang.org>2023-09-01 22:41:39 +0000
commit7015ed891c6f4e51ebaa642fce42ea8a1592b4e1 (patch)
treefa3841de5dffcbe813ff78069c476e6008fc08cd /src
parent227ec028244b8ad91c7dd5b69fca5150f99a4878 (diff)
downloadgo-7015ed891c6f4e51ebaa642fce42ea8a1592b4e1.tar.xz
sync: prevent (*Map).Range from always escaping
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>
Diffstat (limited to 'src')
-rw-r--r--src/sync/map.go3
-rw-r--r--src/sync/map_test.go14
2 files changed, 16 insertions, 1 deletions
diff --git a/src/sync/map.go b/src/sync/map.go
index e8ccf58b56..00b2446153 100644
--- a/src/sync/map.go
+++ b/src/sync/map.go
@@ -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
}
diff --git a/src/sync/map_test.go b/src/sync/map_test.go
index 1eb3fc68a5..20872f3b72 100644
--- a/src/sync/map_test.go
+++ b/src/sync/map_test.go
@@ -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)
+ }
+}