mirror of
https://github.com/golang/go
synced 2024-11-18 09:54:57 -07:00
cmd/gc: fix noscan maps
Change 85e7bee
introduced a bug:
it marks map buckets as noscan when key and val do not contain pointers.
However, buckets with large/outline key or val do contain pointers.
This change takes key/val size into consideration when
marking buckets as noscan.
Change-Id: I7172a0df482657be39faa59e2579dd9f209cb54d
Reviewed-on: https://go-review.googlesource.com/4901
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
2dd7a6d41f
commit
52dadc1f31
@ -179,7 +179,8 @@ mapbucket(Type *t)
|
||||
bucket->width += widthreg - widthptr;
|
||||
|
||||
// See comment on hmap.overflow in ../../runtime/hashmap.go.
|
||||
if(!haspointers(t->type) && !haspointers(t->down))
|
||||
if(!haspointers(t->type) && !haspointers(t->down) &&
|
||||
t->type->width <= MAXKEYSIZE && t->down->width <= MAXVALSIZE)
|
||||
bucket->haspointers = 1; // no pointers
|
||||
|
||||
t->bucket = bucket;
|
||||
|
@ -1659,7 +1659,8 @@ const (
|
||||
func bucketOf(ktyp, etyp *rtype) *rtype {
|
||||
// See comment on hmap.overflow in ../runtime/hashmap.go.
|
||||
var kind uint8
|
||||
if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 {
|
||||
if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 &&
|
||||
ktyp.size <= maxKeySize && etyp.size <= maxValSize {
|
||||
kind = kindNoPointers
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ type hmap struct {
|
||||
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
|
||||
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
|
||||
|
||||
// If both key and value do not contain pointers, then we mark bucket
|
||||
// If both key and value do not contain pointers and are inline, then we mark bucket
|
||||
// type as containing no pointers. This avoids scanning such maps.
|
||||
// However, bmap.overflow is a pointer. In order to keep overflow buckets
|
||||
// alive, we store pointers to all overflow buckets in hmap.overflow.
|
||||
|
@ -515,6 +515,61 @@ func TestMapStringBytesLookup(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapLargeKeyNoPointer(t *testing.T) {
|
||||
const (
|
||||
I = 1000
|
||||
N = 64
|
||||
)
|
||||
type T [N]int
|
||||
m := make(map[T]int)
|
||||
for i := 0; i < I; i++ {
|
||||
var v T
|
||||
for j := 0; j < N; j++ {
|
||||
v[j] = i + j
|
||||
}
|
||||
m[v] = i
|
||||
}
|
||||
runtime.GC()
|
||||
for i := 0; i < I; i++ {
|
||||
var v T
|
||||
for j := 0; j < N; j++ {
|
||||
v[j] = i + j
|
||||
}
|
||||
if m[v] != i {
|
||||
t.Fatalf("corrupted map: want %+v, got %+v", i, m[v])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapLargeValNoPointer(t *testing.T) {
|
||||
const (
|
||||
I = 1000
|
||||
N = 64
|
||||
)
|
||||
type T [N]int
|
||||
m := make(map[int]T)
|
||||
for i := 0; i < I; i++ {
|
||||
var v T
|
||||
for j := 0; j < N; j++ {
|
||||
v[j] = i + j
|
||||
}
|
||||
m[i] = v
|
||||
}
|
||||
runtime.GC()
|
||||
for i := 0; i < I; i++ {
|
||||
var v T
|
||||
for j := 0; j < N; j++ {
|
||||
v[j] = i + j
|
||||
}
|
||||
v1 := m[i]
|
||||
for j := 0; j < N; j++ {
|
||||
if v1[j] != v[j] {
|
||||
t.Fatalf("corrupted map: want %+v, got %+v", v, v1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkMapPop(b *testing.B, n int) {
|
||||
m := map[int]int{}
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
Loading…
Reference in New Issue
Block a user