mirror of
https://github.com/golang/go.git
synced 2025-05-16 21:04:38 +00:00
runtime: test and fix heap bitmap for 1-pointer allocation on 32-bit system
Change-Id: Ic064fe7c6bd3304dcc8c3f7b3b5393870b5387c2 Reviewed-on: https://go-review.googlesource.com/10119 Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
parent
8fa14ea8b4
commit
c3c047a6a3
@ -150,3 +150,5 @@ func BenchSetType(n int, x interface{}) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PtrSize = ptrSize
|
||||||
|
@ -13,11 +13,11 @@ import (
|
|||||||
const (
|
const (
|
||||||
typeScalar = 0
|
typeScalar = 0
|
||||||
typePointer = 1
|
typePointer = 1
|
||||||
typeDead = 255
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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 Ptr", &bssPtr, infoPtr)
|
||||||
verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
|
verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
|
||||||
verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
|
verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
|
||||||
verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
|
verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
|
||||||
@ -26,6 +26,7 @@ func TestGCInfo(t *testing.T) {
|
|||||||
verifyGCInfo(t, "bss eface", &bssEface, infoEface)
|
verifyGCInfo(t, "bss eface", &bssEface, infoEface)
|
||||||
verifyGCInfo(t, "bss iface", &bssIface, infoIface)
|
verifyGCInfo(t, "bss iface", &bssIface, infoIface)
|
||||||
|
|
||||||
|
verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr)
|
||||||
verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
|
verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
|
||||||
verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
|
verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
|
||||||
verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
|
verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
|
||||||
@ -34,6 +35,7 @@ func TestGCInfo(t *testing.T) {
|
|||||||
verifyGCInfo(t, "data eface", &dataEface, infoEface)
|
verifyGCInfo(t, "data eface", &dataEface, infoEface)
|
||||||
verifyGCInfo(t, "data iface", &dataIface, infoIface)
|
verifyGCInfo(t, "data iface", &dataIface, infoIface)
|
||||||
|
|
||||||
|
verifyGCInfo(t, "stack Ptr", new(Ptr), infoPtr)
|
||||||
verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
|
verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
|
||||||
verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
|
verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
|
||||||
verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct())
|
verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct())
|
||||||
@ -43,6 +45,7 @@ func TestGCInfo(t *testing.T) {
|
|||||||
verifyGCInfo(t, "stack iface", new(Iface), infoIface)
|
verifyGCInfo(t, "stack iface", new(Iface), infoIface)
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
|
verifyGCInfo(t, "heap Ptr", escape(new(Ptr)), trimDead(padDead(infoPtr)))
|
||||||
verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
|
verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
|
||||||
verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), trimDead(infoScalarPtr))
|
verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), trimDead(infoScalarPtr))
|
||||||
verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
|
verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
|
||||||
@ -52,21 +55,28 @@ func TestGCInfo(t *testing.T) {
|
|||||||
verifyGCInfo(t, "heap eface", escape(new(interface{})), trimDead(infoEface))
|
verifyGCInfo(t, "heap eface", escape(new(interface{})), trimDead(infoEface))
|
||||||
verifyGCInfo(t, "heap iface", escape(new(Iface)), trimDead(infoIface))
|
verifyGCInfo(t, "heap iface", escape(new(Iface)), trimDead(infoIface))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
|
func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
|
||||||
mask := runtime.GCMask(p)
|
mask := runtime.GCMask(p)
|
||||||
if len(mask) > len(mask0) {
|
|
||||||
mask0 = append(mask0, typeDead)
|
|
||||||
mask = mask[:len(mask0)]
|
|
||||||
}
|
|
||||||
if bytes.Compare(mask, mask0) != 0 {
|
if bytes.Compare(mask, mask0) != 0 {
|
||||||
t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask)
|
t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func padDead(mask []byte) []byte {
|
||||||
|
// Because the dead bit isn't encoded until the third word,
|
||||||
|
// and because on 32-bit systems a one-word allocation
|
||||||
|
// uses a two-word block, the pointer info for a one-word
|
||||||
|
// object needs to be expanded to include an extra scalar
|
||||||
|
// on 32-bit systems to match the heap bitmap.
|
||||||
|
if runtime.PtrSize == 4 && len(mask) == 1 {
|
||||||
|
return []byte{mask[0], 0}
|
||||||
|
}
|
||||||
|
return mask
|
||||||
|
}
|
||||||
|
|
||||||
func trimDead(mask []byte) []byte {
|
func trimDead(mask []byte) []byte {
|
||||||
for len(mask) > 2 && mask[len(mask)-1] == typeScalar {
|
for len(mask) > 2 && mask[len(mask)-1] == typeScalar {
|
||||||
mask = mask[:len(mask)-1]
|
mask = mask[:len(mask)-1]
|
||||||
@ -81,6 +91,12 @@ func escape(p interface{}) interface{} {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var infoPtr = []byte{typePointer}
|
||||||
|
|
||||||
|
type Ptr struct {
|
||||||
|
*byte
|
||||||
|
}
|
||||||
|
|
||||||
var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
|
var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
|
||||||
|
|
||||||
type ScalarPtr struct {
|
type ScalarPtr struct {
|
||||||
@ -160,6 +176,7 @@ func (IfaceImpl) f() {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// BSS
|
// BSS
|
||||||
|
bssPtr Ptr
|
||||||
bssScalarPtr ScalarPtr
|
bssScalarPtr ScalarPtr
|
||||||
bssPtrScalar PtrScalar
|
bssPtrScalar PtrScalar
|
||||||
bssBigStruct BigStruct
|
bssBigStruct BigStruct
|
||||||
@ -169,6 +186,7 @@ var (
|
|||||||
bssIface Iface
|
bssIface Iface
|
||||||
|
|
||||||
// DATA
|
// DATA
|
||||||
|
dataPtr = Ptr{new(byte)}
|
||||||
dataScalarPtr = ScalarPtr{q: 1}
|
dataScalarPtr = ScalarPtr{q: 1}
|
||||||
dataPtrScalar = PtrScalar{w: 1}
|
dataPtrScalar = PtrScalar{w: 1}
|
||||||
dataBigStruct = BigStruct{w: 1}
|
dataBigStruct = BigStruct{w: 1}
|
||||||
|
@ -583,7 +583,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
|
|||||||
// The checks for size == ptrSize and size == 2*ptrSize can therefore
|
// The checks for size == ptrSize and size == 2*ptrSize can therefore
|
||||||
// assume that dataSize == size without checking it explicitly.
|
// assume that dataSize == size without checking it explicitly.
|
||||||
|
|
||||||
if size == ptrSize {
|
if ptrSize == 8 && size == ptrSize {
|
||||||
// It's one word and it has pointers, it must be a pointer.
|
// It's one word and it has pointers, it must be a pointer.
|
||||||
// In general we'd need an atomic update here if the
|
// In general we'd need an atomic update here if the
|
||||||
// concurrent GC were marking objects in this span,
|
// concurrent GC were marking objects in this span,
|
||||||
@ -635,11 +635,28 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
|
|||||||
// are 4-word aligned (because they're all 16-byte aligned).
|
// are 4-word aligned (because they're all 16-byte aligned).
|
||||||
if size == 2*ptrSize {
|
if size == 2*ptrSize {
|
||||||
if typ.size == ptrSize {
|
if typ.size == ptrSize {
|
||||||
// 2-element slice of pointer.
|
// We're allocating a block big enough to hold two pointers.
|
||||||
if gcphase == _GCoff {
|
// On 64-bit, that means the actual object must be two pointers,
|
||||||
*h.bitp |= (bitPointer | bitPointer<<heapBitsShift) << h.shift
|
// or else we'd have used the one-pointer-sized block.
|
||||||
|
// On 32-bit, however, this is the 8-byte block, the smallest one.
|
||||||
|
// So it could be that we're allocating one pointer and this was
|
||||||
|
// just the smallest block available. Distinguish by checking dataSize.
|
||||||
|
// (In general the number of instances of typ being allocated is
|
||||||
|
// dataSize/typ.size.)
|
||||||
|
if ptrSize == 4 && dataSize == ptrSize {
|
||||||
|
// 1 pointer.
|
||||||
|
if gcphase == _GCoff {
|
||||||
|
*h.bitp |= bitPointer << h.shift
|
||||||
|
} else {
|
||||||
|
atomicor8(h.bitp, bitPointer<<h.shift)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
atomicor8(h.bitp, (bitPointer|bitPointer<<heapBitsShift)<<h.shift)
|
// 2-element slice of pointer.
|
||||||
|
if gcphase == _GCoff {
|
||||||
|
*h.bitp |= (bitPointer | bitPointer<<heapBitsShift) << h.shift
|
||||||
|
} else {
|
||||||
|
atomicor8(h.bitp, (bitPointer|bitPointer<<heapBitsShift)<<h.shift)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user