Commit 0234dfd4 authored by Russ Cox's avatar Russ Cox

runtime: use 2-bit heap bitmap (in place of 4-bit)

Previous CLs changed the representation of the non-heap type bitmaps
to be 1-bit bitmaps (pointer or not). Before this CL, the heap bitmap
stored a 2-bit type for each word and a mark bit and checkmark bit
for the first word of the object. (There used to be additional per-word bits.)

Reduce heap bitmap to 2-bit, with 1 dedicated to pointer or not,
and the other used for mark, checkmark, and "keep scanning forward
to find pointers in this object." See comments for details.

This CL replaces heapBitsSetType with very slow but obviously correct code.
A followup CL will optimize it. (Spoiler: the new code is faster than Go 1.4 was.)

Change-Id: I999577a133f3cfecacebdec9cdc3573c235c7fb9
Reviewed-on: https://go-review.googlesource.com/9703Reviewed-by: default avatarRick Hudson <rlh@golang.org>
Reviewed-by: default avatarAustin Clements <austin@google.com>
parent 6d8a147b
...@@ -10,6 +10,12 @@ import ( ...@@ -10,6 +10,12 @@ import (
"testing" "testing"
) )
const (
typeScalar = 0
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 ScalarPtr", &bssScalarPtr, infoScalarPtr) verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
...@@ -37,7 +43,9 @@ func TestGCInfo(t *testing.T) { ...@@ -37,7 +43,9 @@ func TestGCInfo(t *testing.T) {
verifyGCInfo(t, "stack iface", new(Iface), nonStackInfo(infoIface)) verifyGCInfo(t, "stack iface", new(Iface), nonStackInfo(infoIface))
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), infoPtr10)
verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), infoScalarPtr) verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), infoScalarPtr)
verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), infoScalarPtr4)
verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), infoPtrScalar) verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), infoPtrScalar)
verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), infoBigStruct()) verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), infoBigStruct())
verifyGCInfo(t, "heap string", escape(new(string)), infoString) verifyGCInfo(t, "heap string", escape(new(string)), infoString)
...@@ -78,18 +86,7 @@ func escape(p interface{}) interface{} { ...@@ -78,18 +86,7 @@ func escape(p interface{}) interface{} {
return p return p
} }
const ( var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
typeDead = iota
typeScalar
typePointer
)
const (
BitsString = iota // unused
BitsSlice // unused
BitsIface
BitsEface
)
type ScalarPtr struct { type ScalarPtr struct {
q int q int
...@@ -102,6 +99,8 @@ type ScalarPtr struct { ...@@ -102,6 +99,8 @@ type ScalarPtr struct {
var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer} var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
type PtrScalar struct { type PtrScalar struct {
q *int q *int
w int w int
......
...@@ -730,14 +730,13 @@ func makeheapobjbv(p uintptr, size uintptr) bitvector { ...@@ -730,14 +730,13 @@ func makeheapobjbv(p uintptr, size uintptr) bitvector {
i := uintptr(0) i := uintptr(0)
hbits := heapBitsForAddr(p) hbits := heapBitsForAddr(p)
for ; i < nptr; i++ { for ; i < nptr; i++ {
bits := hbits.typeBits() if i >= 2 && !hbits.isMarked() {
if bits == typeDead {
break // end of object break // end of object
} }
hbits = hbits.next() if hbits.isPointer() {
if bits == typePointer {
tmpbuf[i/8] |= 1 << (i % 8) tmpbuf[i/8] |= 1 << (i % 8)
} }
hbits = hbits.next()
} }
return bitvector{int32(i), &tmpbuf[0]} return bitvector{int32(i), &tmpbuf[0]}
} }
This diff is collapsed.
...@@ -597,20 +597,19 @@ func scanobject(b uintptr, gcw *gcWork) { ...@@ -597,20 +597,19 @@ func scanobject(b uintptr, gcw *gcWork) {
// Avoid needless hbits.next() on last iteration. // Avoid needless hbits.next() on last iteration.
hbits = hbits.next() hbits = hbits.next()
} }
bits := uintptr(hbits.typeBits()) // During checkmarking, 1-word objects store the checkmark
if bits == typeDead { // in the type bit for the one word. The only one-word objects
break // no more pointers in this object // are pointers, or else they'd be merged with other non-pointer
} // data into larger allocations.
if n != 1 {
if bits <= typeScalar { // typeScalar, typeDead, typeScalarMarked b := hbits.bits()
continue if i >= 2*ptrSize && b&bitMarked == 0 {
} break // no more pointers in this object
}
if bits&typePointer != typePointer { if b&bitPointer == 0 {
print("gc useCheckmark=", useCheckmark, " b=", hex(b), "\n") continue // not a pointer
throw("unexpected garbage collection bits") }
} }
// Work here is duplicated in scanblock. // Work here is duplicated in scanblock.
// If you make changes here, make changes there too. // If you make changes here, make changes there too.
...@@ -673,11 +672,11 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork ...@@ -673,11 +672,11 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
throw("checkmark found unmarked object") throw("checkmark found unmarked object")
} }
if hbits.isCheckmarked() { if hbits.isCheckmarked(span.elemsize) {
return return
} }
hbits.setCheckmarked() hbits.setCheckmarked(span.elemsize)
if !hbits.isCheckmarked() { if !hbits.isCheckmarked(span.elemsize) {
throw("setCheckmarked and isCheckmarked disagree") throw("setCheckmarked and isCheckmarked disagree")
} }
} else { } else {
...@@ -685,12 +684,11 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork ...@@ -685,12 +684,11 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
if hbits.isMarked() { if hbits.isMarked() {
return return
} }
hbits.setMarked() hbits.setMarked()
// If this is a noscan object, fast-track it to black // If this is a noscan object, fast-track it to black
// instead of greying it. // instead of greying it.
if hbits.typeBits() == typeDead { if !hbits.hasPointers(span.elemsize) {
gcw.bytesMarked += uint64(span.elemsize) gcw.bytesMarked += uint64(span.elemsize)
return return
} }
......
...@@ -352,6 +352,12 @@ func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) { ...@@ -352,6 +352,12 @@ func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
} }
} }
// Information from the compiler about the layout of stack frames.
type bitvector struct {
n int32 // # of bits
bytedata *uint8
}
type gobitvector struct { type gobitvector struct {
n uintptr n uintptr
bytedata []uint8 bytedata []uint8
......
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