Commit c5e648d6 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: fix getgcmask

bv.data is an array of uint32s but the code was using
offsets computed for an array of bytes.
Add a test for stack GC info.
Fixes #8531.

LGTM=rsc
R=golang-codereviews
CC=golang-codereviews, khr, rsc
https://golang.org/cl/124450043
parent 7f40e5e6
...@@ -12,24 +12,30 @@ import ( ...@@ -12,24 +12,30 @@ import (
// TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info. // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
func TestGCInfo(t *testing.T) { func TestGCInfo(t *testing.T) {
verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr) verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr))
verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar) verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, nonStackInfo(infoPtrScalar))
verifyGCInfo(t, "bss Complex", &bssComplex, infoComplex()) verifyGCInfo(t, "bss Complex", &bssComplex, nonStackInfo(infoComplex()))
verifyGCInfo(t, "bss string", &bssString, infoString) verifyGCInfo(t, "bss string", &bssString, nonStackInfo(infoString))
verifyGCInfo(t, "bss eface", &bssEface, infoEface) verifyGCInfo(t, "bss eface", &bssEface, nonStackInfo(infoEface))
verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr) verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, nonStackInfo(infoScalarPtr))
verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar) verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, nonStackInfo(infoPtrScalar))
verifyGCInfo(t, "data Complex", &dataComplex, infoComplex()) verifyGCInfo(t, "data Complex", &dataComplex, nonStackInfo(infoComplex()))
verifyGCInfo(t, "data string", &dataString, infoString) verifyGCInfo(t, "data string", &dataString, nonStackInfo(infoString))
verifyGCInfo(t, "data eface", &dataEface, infoEface) verifyGCInfo(t, "data eface", &dataEface, nonStackInfo(infoEface))
verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
verifyGCInfo(t, "stack Complex", new(Complex), infoComplex())
verifyGCInfo(t, "stack string", new(string), infoString)
verifyGCInfo(t, "stack eface", new(interface{}), infoEface)
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), infoScalarPtr) verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr))
verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), infoPtrScalar) verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), nonStackInfo(infoPtrScalar))
verifyGCInfo(t, "heap Complex", escape(new(Complex)), infoComplex()) verifyGCInfo(t, "heap Complex", escape(new(Complex)), nonStackInfo(infoComplex()))
verifyGCInfo(t, "heap string", escape(new(string)), infoString) verifyGCInfo(t, "heap string", escape(new(string)), nonStackInfo(infoString))
verifyGCInfo(t, "heap eface", escape(new(interface{})), infoEface) verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface))
} }
} }
...@@ -46,6 +52,20 @@ func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) { ...@@ -46,6 +52,20 @@ func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
} }
} }
func nonStackInfo(mask []byte) []byte {
// BitsDead is replaced with BitsScalar everywhere except stacks.
mask1 := make([]byte, len(mask))
mw := false
for i, v := range mask {
if !mw && v == BitsDead {
v = BitsScalar
}
mw = !mw && v == BitsMultiWord
mask1[i] = v
}
return mask1
}
var gcinfoSink interface{} var gcinfoSink interface{}
func escape(p interface{}) interface{} { func escape(p interface{}) interface{} {
...@@ -106,20 +126,20 @@ func infoComplex() []byte { ...@@ -106,20 +126,20 @@ func infoComplex() []byte {
return []byte{ return []byte{
BitsPointer, BitsScalar, BitsScalar, BitsScalar, BitsPointer, BitsScalar, BitsScalar, BitsScalar,
BitsScalar, BitsScalar, BitsMultiWord, BitsSlice, BitsScalar, BitsScalar, BitsMultiWord, BitsSlice,
BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, BitsScalar,
BitsScalar, BitsMultiWord, BitsString, BitsScalar, BitsMultiWord, BitsString,
} }
case "amd64": case "amd64":
return []byte{ return []byte{
BitsPointer, BitsScalar, BitsScalar, BitsScalar, BitsPointer, BitsScalar, BitsScalar, BitsScalar,
BitsMultiWord, BitsSlice, BitsScalar, BitsScalar, BitsMultiWord, BitsSlice, BitsDead, BitsScalar,
BitsScalar, BitsScalar, BitsMultiWord, BitsString, BitsScalar, BitsScalar, BitsMultiWord, BitsString,
} }
case "amd64p32": case "amd64p32":
return []byte{ return []byte{
BitsPointer, BitsScalar, BitsScalar, BitsScalar, BitsPointer, BitsScalar, BitsScalar, BitsScalar,
BitsScalar, BitsScalar, BitsMultiWord, BitsSlice, BitsScalar, BitsScalar, BitsMultiWord, BitsSlice,
BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, BitsDead,
BitsScalar, BitsScalar, BitsMultiWord, BitsString, BitsScalar, BitsScalar, BitsMultiWord, BitsString,
} }
default: default:
......
...@@ -2087,7 +2087,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) ...@@ -2087,7 +2087,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
*mask = runtime·mallocgc(*len, nil, 0); *mask = runtime·mallocgc(*len, nil, 0);
for(i = 0; i < n; i += PtrSize) { for(i = 0; i < n; i += PtrSize) {
off = (p+i-frame.varp+size)/PtrSize; off = (p+i-frame.varp+size)/PtrSize;
bits = (bv.data[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; bits = (bv.data[off*BitsPerPointer/32] >> ((off*BitsPerPointer)%32))&BitsMask;
(*mask)[i/PtrSize] = bits; (*mask)[i/PtrSize] = bits;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment