From 42c121476217595d9eddbded70cfb6500eca8442 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 24 Mar 2017 12:02:12 -0400 Subject: [PATCH] runtime: eliminate write barriers from alloc/mark bitmaps This introduces a new type, *gcBits, to use for alloc/mark bitmap allocations instead of *uint8. This type is marked go:notinheap, so uses of it correctly eliminate write barriers. Since we now have a type, this also extracts some common operations to methods both for convenience and to avoid (*uint8) casts at most use sites. For #19325. Change-Id: Id51f734fb2e96b8b7715caa348c8dcd4aef0696a Reviewed-on: https://go-review.googlesource.com/38580 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson --- src/runtime/mbitmap.go | 26 ++++++++++---------------- src/runtime/mheap.go | 28 ++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index eb36450508..8075f66115 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -182,10 +182,8 @@ type markBits struct { //go:nosplit func (s *mspan) allocBitsForIndex(allocBitIndex uintptr) markBits { - whichByte := allocBitIndex / 8 - whichBit := allocBitIndex % 8 - bytePtr := addb(s.allocBits, whichByte) - return markBits{bytePtr, uint8(1 << whichBit), allocBitIndex} + bytep, mask := s.allocBits.bitp(allocBitIndex) + return markBits{bytep, mask, allocBitIndex} } // refillaCache takes 8 bytes s.allocBits starting at whichByte @@ -193,7 +191,7 @@ func (s *mspan) allocBitsForIndex(allocBitIndex uintptr) markBits { // can be used. It then places these 8 bytes into the cached 64 bit // s.allocCache. func (s *mspan) refillAllocCache(whichByte uintptr) { - bytes := (*[8]uint8)(unsafe.Pointer(addb(s.allocBits, whichByte))) + bytes := (*[8]uint8)(unsafe.Pointer(s.allocBits.bytep(whichByte))) aCache := uint64(0) aCache |= uint64(bytes[0]) aCache |= uint64(bytes[1]) << (1 * 8) @@ -265,10 +263,8 @@ func (s *mspan) isFree(index uintptr) bool { if index < s.freeindex { return false } - whichByte := index / 8 - whichBit := index % 8 - byteVal := *addb(s.allocBits, whichByte) - return byteVal&uint8(1<sweepgen - 2, the span needs sweeping @@ -1417,6 +1417,22 @@ func freespecial(s *special, p unsafe.Pointer, size uintptr) { } } +// gcBits is an alloc/mark bitmap. This is always used as *gcBits. +// +//go:notinheap +type gcBits uint8 + +// bytep returns a pointer to the n'th byte of b. +func (b *gcBits) bytep(n uintptr) *uint8 { + return addb((*uint8)(b), n) +} + +// bitp returns a pointer to the byte containing bit n and a mask for +// selecting that bit from *bytep. +func (b *gcBits) bitp(n uintptr) (bytep *uint8, mask uint8) { + return b.bytep(n / 8), 1 << (n % 8) +} + const gcBitsChunkBytes = uintptr(64 << 10) const gcBitsHeaderBytes = unsafe.Sizeof(gcBitsHeader{}) @@ -1430,7 +1446,7 @@ type gcBitsArena struct { // gcBitsHeader // side step recursive type bug (issue 14620) by including fields by hand. free uintptr // free is the index into bits of the next free byte; read/write atomically next *gcBitsArena - bits [gcBitsChunkBytes - gcBitsHeaderBytes]uint8 + bits [gcBitsChunkBytes - gcBitsHeaderBytes]gcBits } var gcBitsArenas struct { @@ -1443,7 +1459,7 @@ var gcBitsArenas struct { // tryAlloc allocates from b or returns nil if b does not have enough room. // This is safe to call concurrently. -func (b *gcBitsArena) tryAlloc(bytes uintptr) *uint8 { +func (b *gcBitsArena) tryAlloc(bytes uintptr) *gcBits { if b == nil || atomic.Loaduintptr(&b.free)+bytes > uintptr(len(b.bits)) { return nil } @@ -1459,7 +1475,7 @@ func (b *gcBitsArena) tryAlloc(bytes uintptr) *uint8 { // newMarkBits returns a pointer to 8 byte aligned bytes // to be used for a span's mark bits. -func newMarkBits(nelems uintptr) *uint8 { +func newMarkBits(nelems uintptr) *gcBits { blocksNeeded := uintptr((nelems + 63) / 64) bytesNeeded := blocksNeeded * 8 @@ -1515,7 +1531,7 @@ func newMarkBits(nelems uintptr) *uint8 { // allocation bits. For spans not being initialized the // the mark bits are repurposed as allocation bits when // the span is swept. -func newAllocBits(nelems uintptr) *uint8 { +func newAllocBits(nelems uintptr) *gcBits { return newMarkBits(nelems) } -- 2.50.0