diff options
Diffstat (limited to 'src/runtime/mbitmap.go')
| -rw-r--r-- | src/runtime/mbitmap.go | 63 |
1 files changed, 56 insertions, 7 deletions
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index b342de600e..af89577703 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -88,6 +88,7 @@ const ( // addb returns the byte pointer p+n. //go:nowritebarrier +//go:nosplit func addb(p *byte, n uintptr) *byte { // Note: wrote out full expression instead of calling add(p, n) // to reduce the number of temporaries generated by the @@ -99,6 +100,7 @@ func addb(p *byte, n uintptr) *byte { // subtractb is typically used when traversing the pointer tables referred to by hbits // which are arranged in reverse order. //go:nowritebarrier +//go:nosplit func subtractb(p *byte, n uintptr) *byte { // Note: wrote out full expression instead of calling add(p, -n) // to reduce the number of temporaries generated by the @@ -108,6 +110,7 @@ func subtractb(p *byte, n uintptr) *byte { // add1 returns the byte pointer p+1. //go:nowritebarrier +//go:nosplit func add1(p *byte) *byte { // Note: wrote out full expression instead of calling addb(p, 1) // to reduce the number of temporaries generated by the @@ -596,10 +599,10 @@ func (h heapBits) setCheckmarked(size uintptr) { // heapBitsBulkBarrier executes writebarrierptr_nostore // for every pointer slot in the memory range [p, p+size), -// using the heap bitmap to locate those pointer slots. +// using the heap, data, or BSS bitmap to locate those pointer slots. // This executes the write barriers necessary after a memmove. // Both p and size must be pointer-aligned. -// The range [p, p+size) must lie within a single allocation. +// The range [p, p+size) must lie within a single object. // // Callers should call heapBitsBulkBarrier immediately after // calling memmove(p, src, size). This function is marked nosplit @@ -643,6 +646,22 @@ func heapBitsBulkBarrier(p, size uintptr) { systemstack(func() { gcUnwindBarriers(gp, p) }) + return + } + + // If p is a global, use the data or BSS bitmaps to + // execute write barriers. + for datap := &firstmoduledata; datap != nil; datap = datap.next { + if datap.data <= p && p < datap.edata { + bulkBarrierBitmap(p, size, p-datap.data, datap.gcdatamask.bytedata) + return + } + } + for datap := &firstmoduledata; datap != nil; datap = datap.next { + if datap.bss <= p && p < datap.ebss { + bulkBarrierBitmap(p, size, p-datap.bss, datap.gcbssmask.bytedata) + return + } } return } @@ -657,6 +676,36 @@ func heapBitsBulkBarrier(p, size uintptr) { } } +// bulkBarrierBitmap executes write barriers for [p, p+size) using a +// 1-bit pointer bitmap. p is assumed to start maskOffset bytes into +// the data covered by the bitmap in bits. +// +// This is used by heapBitsBulkBarrier for writes to data and BSS. +// +//go:nosplit +func bulkBarrierBitmap(p, size, maskOffset uintptr, bits *uint8) { + word := maskOffset / sys.PtrSize + bits = addb(bits, word/8) + mask := uint8(1) << (word % 8) + + for i := uintptr(0); i < size; i += sys.PtrSize { + if mask == 0 { + bits = addb(bits, 1) + if *bits == 0 { + // Skip 8 words. + i += 7 * sys.PtrSize + continue + } + mask = 1 + } + if *bits&mask != 0 { + x := (*uintptr)(unsafe.Pointer(p + i)) + writebarrierptr_nostore(x, *x) + } + mask <<= 1 + } +} + // typeBitsBulkBarrier executes writebarrierptr_nostore // for every pointer slot in the memory range [p, p+size), // using the type bitmap to locate those pointer slots. @@ -676,11 +725,11 @@ func typeBitsBulkBarrier(typ *_type, p, size uintptr) { throw("runtime: typeBitsBulkBarrier without type") } if typ.size != size { - println("runtime: typeBitsBulkBarrier with type ", typ._string, " of size ", typ.size, " but memory size", size) + println("runtime: typeBitsBulkBarrier with type ", typ.string(), " of size ", typ.size, " but memory size", size) throw("runtime: invalid typeBitsBulkBarrier") } if typ.kind&kindGCProg != 0 { - println("runtime: typeBitsBulkBarrier with type ", typ._string, " with GC prog") + println("runtime: typeBitsBulkBarrier with type ", typ.string(), " with GC prog") throw("runtime: invalid typeBitsBulkBarrier") } if !writeBarrier.needed { @@ -1128,7 +1177,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { } if nw == 0 { // No pointers! Caller was supposed to check. - println("runtime: invalid type ", typ._string) + println("runtime: invalid type ", typ.string()) throw("heapBitsSetType: called with non-pointer type") return } @@ -1314,7 +1363,7 @@ Phase4: if doubleCheck { end := heapBitsForAddr(x + size) if typ.kind&kindGCProg == 0 && (hbitp != end.bitp || (w == nw+2) != (end.shift == 2)) { - println("ended at wrong bitmap byte for", typ._string, "x", dataSize/typ.size) + println("ended at wrong bitmap byte for", typ.string(), "x", dataSize/typ.size) print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n") print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n") h0 := heapBitsForAddr(x) @@ -1350,7 +1399,7 @@ Phase4: } } if have != want { - println("mismatch writing bits for", typ._string, "x", dataSize/typ.size) + println("mismatch writing bits for", typ.string(), "x", dataSize/typ.size) print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n") print("kindGCProg=", typ.kind&kindGCProg != 0, "\n") print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n") |
