sync: prevent (*Map).Range from always escaping

After the change from CL 426074 the Range method on Map always escape
the read variable, generating 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
This commit is contained in:
Mauri de Souza Meneguzzo 2023-08-31 22:15:34 -03:00
parent ffc4ccea07
commit fcbedb467c
2 changed files with 16 additions and 1 deletions

View 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
}

View 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)
}
}