Source File
mbitmap.go
Belonging Package
runtime
package runtime
import (
)
const (
bitPointer = 1 << 0
bitScan = 1 << 4
heapBitsShift = 1 // shift offset between successive bitPointer or bitScan entries
wordsPerBitmapByte = 8 / 2 // heap words described by one bitmap byte
bitScanAll = bitScan | bitScan<<heapBitsShift | bitScan<<(2*heapBitsShift) | bitScan<<(3*heapBitsShift)
bitPointerAll = bitPointer | bitPointer<<heapBitsShift | bitPointer<<(2*heapBitsShift) | bitPointer<<(3*heapBitsShift)
)
var _ = heapBits{arena: (1<<heapAddrBits)/heapArenaBytes - 1}
func ( *mspan) ( uintptr) {
:= (*[8]uint8)(unsafe.Pointer(.allocBits.bytep()))
:= uint64(0)
|= uint64([0])
|= uint64([1]) << (1 * 8)
|= uint64([2]) << (2 * 8)
|= uint64([3]) << (3 * 8)
|= uint64([4]) << (4 * 8)
|= uint64([5]) << (5 * 8)
|= uint64([6]) << (6 * 8)
|= uint64([7]) << (7 * 8)
.allocCache = ^
}
= ( + 64) &^ (64 - 1)
if >= {
.freeindex =
return
}
.refillAllocCache()
= .allocCache
}
:= + uintptr()
if >= {
.freeindex =
return
}
.allocCache >>= uint( + 1)
= + 1
:= / 8
.refillAllocCache()
}
.freeindex =
return
}
return >> .divShift
}
return uintptr(((uint64() >> .divShift) * uint64(.divMul)) >> .divShift2)
}
func ( uintptr) markBits {
:= spanOf()
:= .objIndex()
return .markBitsForIndex()
}
func ( *mspan) ( uintptr) markBits {
, := .gcmarkBits.bitp()
return markBits{, , }
}
func ( *mspan) () markBits {
return markBits{(*uint8)(.gcmarkBits), uint8(1), 0}
}
func ( uintptr) ( markBits) {
= markBitsForAddr()
if .mask != 1 {
throw("markBitsForSpan: unaligned start")
}
return
}
:= arenaIndex()
printlock()
print("runtime: pointer ", hex())
:= .state.get()
if != mSpanInUse {
print(" to unallocated span")
} else {
print(" to unused region of span")
}
print(" span.base()=", hex(.base()), " span.limit=", hex(.limit), " span.state=", , "\n")
if != 0 {
print("runtime: found in object at *(", hex(), "+", hex(), ")\n")
gcDumpObject("object", , )
}
getg().m.traceback = 2
throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)")
}
if == nil {
return
if == mSpanManual {
return
if debug.invalidptr != 0 {
badPointer(, , , )
}
return
} else {
= .base()
return .nextArena()
}
return
}
func ( heapBits) () bool {
return .bits()&bitPointer != 0
}
for , := range activeModules() {
if .data <= && < .edata {
bulkBarrierBitmap(, , , -.data, .gcdatamask.bytedata)
return
}
}
for , := range activeModules() {
if .bss <= && < .ebss {
bulkBarrierBitmap(, , , -.bss, .gcbssmask.bytedata)
return
}
}
return
return
}
:= &getg().m.p.ptr().wbBuf
:= heapBitsForAddr()
if == 0 {
for := uintptr(0); < ; += sys.PtrSize {
if .isPointer() {
:= (*uintptr)(unsafe.Pointer( + ))
if !.putFast(*, 0) {
wbBufFlush(nil, 0)
}
}
= .next()
}
} else {
for := uintptr(0); < ; += sys.PtrSize {
if .isPointer() {
:= (*uintptr)(unsafe.Pointer( + ))
:= (*uintptr)(unsafe.Pointer( + ))
if !.putFast(*, *) {
wbBufFlush(nil, 0)
}
}
= .next()
}
}
}
func (, , uintptr) {
if (||)&(sys.PtrSize-1) != 0 {
throw("bulkBarrierPreWrite: unaligned arguments")
}
if !writeBarrier.needed {
return
}
:= &getg().m.p.ptr().wbBuf
:= heapBitsForAddr()
for := uintptr(0); < ; += sys.PtrSize {
if .isPointer() {
:= (*uintptr)(unsafe.Pointer( + ))
if !.putFast(0, *) {
wbBufFlush(nil, 0)
}
}
= .next()
}
}
func ( *_type, , , uintptr) {
if == nil {
throw("runtime: typeBitsBulkBarrier without type")
}
if .size != {
println("runtime: typeBitsBulkBarrier with type ", .string(), " of size ", .size, " but memory size", )
throw("runtime: invalid typeBitsBulkBarrier")
}
if .kind&kindGCProg != 0 {
println("runtime: typeBitsBulkBarrier with type ", .string(), " with GC prog")
throw("runtime: invalid typeBitsBulkBarrier")
}
if !writeBarrier.needed {
return
}
:= .gcdata
:= &getg().m.p.ptr().wbBuf
var uint32
for := uintptr(0); < .ptrdata; += sys.PtrSize {
if &(sys.PtrSize*8-1) == 0 {
= uint32(*)
= addb(, 1)
} else {
= >> 1
}
if &1 != 0 {
:= (*uintptr)(unsafe.Pointer( + ))
:= (*uintptr)(unsafe.Pointer( + ))
if !.putFast(*, *) {
wbBufFlush(nil, 0)
}
}
}
}
:= (.npages << _PageShift) / sys.PtrSize
if %wordsPerBitmapByte != 0 {
throw("initSpan: unaligned length")
}
if .shift != 0 {
throw("initSpan: unaligned base")
}
:= sys.PtrSize == 8 && .elemsize == sys.PtrSize
for > 0 {
, := .forwardOrBoundary()
:= / wordsPerBitmapByte
if {
:= .bitp
for := uintptr(0); < ; ++ {
* = bitPointerAll | bitScanAll
= add1()
}
} else {
memclrNoHeapPointers(unsafe.Pointer(.bitp), )
}
=
-=
}
}
:= *(*uint64)(unsafe.Pointer(.gcmarkBits.bytep()))
+= sys.OnesCount64()
}
return
}
func (, , uintptr, *_type) {
const = false // slow but helpful; enable to test modifications to this code
const (
= bitPointer | bitScan // 00010001
= bitPointer | bitScan | <<heapBitsShift // 00110011
= bitPointer | bitScan | <<heapBitsShift // 01110111
)
if {
:= heapBitsForAddr()
if !.isPointer() {
throw("heapBitsSetType: pointer bit missing")
}
if !.morePointers() {
throw("heapBitsSetType: scan bit missing")
}
}
return
}
:= heapBitsForAddr()
:= .gcdata // start of 1-bit pointer mask (or GC program, handled below)
*.bitp &^= (bitPointer | bitScan | (bitPointer|bitScan)<<heapBitsShift) << .shift
*.bitp |= (bitPointer | bitScan) << .shift
*.bitp |= (bitPointer | bitScan | (bitPointer|bitScan)<<heapBitsShift) << .shift
}
return
*.bitp &^= (bitPointer | bitScan | ((bitPointer | bitScan) << heapBitsShift)) << .shift
*.bitp |= uint8( << .shift)
return
} else if == 3*sys.PtrSize {
:= uint8(*)
if {
if == 0 {
println("runtime: invalid type ", .string())
throw("heapBitsSetType: called with non-pointer type")
}
if sys.PtrSize != 8 {
throw("heapBitsSetType: unexpected 3 pointer wide size class on 32 bit")
}
if .kind&kindGCProg != 0 {
throw("heapBitsSetType: unexpected GC prog for 3 pointer wide size class")
}
if .size == 2*sys.PtrSize {
print("runtime: heapBitsSetType size=", , " but typ.size=", .size, "\n")
throw("heapBitsSetType: inconsistent object sizes")
}
}
= 7
}
|= & (bitScan << (2 * heapBitsShift)) >> 1
:= false
if .kind&kindGCProg != 0 {
heapBitsSetTypeGCProg(, .ptrdata, .size, , , addb(.gcdata, 4))
lock(&debugPtrmask.lock)
if debugPtrmask.data == nil {
debugPtrmask.data = (*byte)(persistentalloc(1<<20, 1, &memstats.other_sys))
}
= debugPtrmask.data
runGCProg(addb(.gcdata, 4), nil, , 1)
}
goto
}
=
switch {
default:
throw("heapBitsSetType: unexpected shift")
= & bitPointerAll
|= bitScanAll
if += 4; >= {
goto
}
* = uint8()
= add1()
>>= 4
-= 4
= ( & (bitPointer | bitPointer<<heapBitsShift)) << (2 * heapBitsShift)
|= bitScan << (2 * heapBitsShift)
if > 1 {
|= bitScan << (3 * heapBitsShift)
}
>>= 2
-= 2
* &^= uint8((bitPointer | bitScan | ((bitPointer | bitScan) << heapBitsShift)) << (2 * heapBitsShift))
* |= uint8()
= add1()
= 0
+= 4
goto
}
}
-= 4
= & bitPointerAll
|= bitScanAll
if += 4; >= {
break
}
* = uint8()
= add1()
>>= 4
-= 8
}
if < 8 {
|= <<
+=
}
-= 8 // for next iteration
= & bitPointerAll
|= bitScanAll
if += 4; >= {
break
}
* = uint8()
= add1()
>>= 4
}
:= uintptr(1)<<(4-(-)) - 1
&= | <<4 // apply mask to both pointer bits and scan bits
}
if == +2 {
* = *&^(bitPointer|bitScan|(bitPointer|bitScan)<<heapBitsShift) | uint8()
}
if {
if !(.shift == 0 || .shift == 2) {
print("x=", , " size=", , " cnw=", .shift, "\n")
throw("bad start shift")
}
}
if .shift == 2 {
*.bitp = *.bitp&^((bitPointer|bitScan|(bitPointer|bitScan)<<heapBitsShift)<<(2*heapBitsShift)) | *
= .next().next()
-= 2
= addb(, 1)
, := .forwardOrBoundary( / 4 * 4)
= .bitp
:= heapBitsForAddr( + - sys.PtrSize)
= .next()
.shift += heapBitsShift
if .shift == 4*heapBitsShift {
.bitp, .shift = add1(.bitp), 0
}
}
if .kind&kindGCProg == 0 && ( != .bitp || ( == +2) != (.shift == 2)) {
println("ended at wrong bitmap byte for", .string(), "x", /.size)
print("typ.size=", .size, " typ.ptrdata=", .ptrdata, " dataSize=", , " size=", , "\n")
print("w=", , " nw=", , " b=", hex(), " nb=", , " hb=", hex(), "\n")
:= heapBitsForAddr()
print("initial bits h0.bitp=", .bitp, " h0.shift=", .shift, "\n")
print("ended at hbitp=", , " but next starts at bitp=", .bitp, " shift=", .shift, "\n")
throw("bad heapBitsSetType")
}
= bitScan
}
} else {
if < && (*addb(, /8)>>(%8))&1 != 0 {
|= bitPointer
}
|= bitScan
}
if != {
println("mismatch writing bits for", .string(), "x", /.size)
print("typ.size=", .size, " typ.ptrdata=", .ptrdata, " dataSize=", , " size=", , "\n")
print("kindGCProg=", .kind&kindGCProg != 0, " outOfPlace=", , "\n")
print("w=", , " nw=", , " b=", hex(), " nb=", , " hb=", hex(), "\n")
:= heapBitsForAddr()
print("initial bits h0.bitp=", .bitp, " h0.shift=", .shift, "\n")
print("current bits h.bitp=", .bitp, " h.shift=", .shift, " *h.bitp=", hex(*.bitp), "\n")
print("ptrmask=", , " p=", , " endp=", , " endnb=", , " pbits=", hex(), " b=", hex(), " nb=", , "\n")
println("at word", , "offset", *sys.PtrSize, "have", hex(), "want", hex())
if .kind&kindGCProg != 0 {
println("GC program:")
dumpGCProg(addb(.gcdata, 4))
}
throw("bad heapBitsSetType")
}
= .next()
}
if == debugPtrmask.data {
unlock(&debugPtrmask.lock)
}
}
}
var debugPtrmask struct {
lock mutex
data *byte
}
var [40]byte // 3 varints (max 10 each) + some bytes
:= 0
[] = 0x01
++
[] = 0
++
func ( *byte, uintptr) bitvector {
:= (/sys.PtrSize + 7) / 8
:= (*[1 << 30]byte)(persistentalloc(+1, 1, &memstats.buckhash_sys))[:+1]
[len()-1] = 0xa1 // overflow check sentinel
= runGCProg(, nil, &[0], 1)
if [len()-1] != 0xa1 {
throw("progToPointerMask: overflow")
}
return bitvector{int32(), &[0]}
}
for ; >= 8; -= 8 {
if == 1 {
* = uint8()
= add1()
>>= 8
} else {
:= &bitPointerAll | bitScanAll
* = uint8()
= add1()
>>= 4
= &bitPointerAll | bitScanAll
* = uint8()
= add1()
>>= 4
}
}
if != nil {
=
= nil
continue
}
break
}
:= / 8
for := uintptr(0); < ; ++ {
|= uintptr(*) <<
= add1()
if == 1 {
* = uint8()
= add1()
>>= 8
} else {
:= &0xf | bitScanAll
* = uint8()
= add1()
>>= 4
= &0xf | bitScanAll
* = uint8()
= add1()
>>= 4
}
}
if %= 8; > 0 {
|= uintptr(*) <<
= add1()
+=
}
continue
}
:=
:=
if > {
>>= -
=
}
if == 1 {
= 1<< - 1
=
} else {
=
}
} else {
:=
:=
= / *
&= 1<< - 1
=
=
}
}
for ; >= ; -= {
|= <<
+=
if == 1 {
for >= 8 {
* = uint8()
= add1()
>>= 8
-= 8
}
} else {
for >= 4 {
* = uint8(&0xf | bitScanAll)
= add1()
>>= 4
-= 4
}
}
}
if > 0 {
&= 1<< - 1
|= <<
+=
}
continue
}
:= - // n > nbits because n > maxBits and nbits <= 7
if %= 8; > 0 {
|= (uintptr(*) & (1<< - 1)) <<
+=
}
for := / 4; > 0; -- {
|= (uintptr(*) & 0xf) <<
= add1()
* = uint8(&0xf | bitScanAll)
= add1()
>>= 4
if %= 4; > 0 {
|= (uintptr(*) & (1<< - 1)) <<
+=
}
}
}
:= divRoundUp(, pageSize)
:= mheap_.allocManual(, spanAllocPtrScalarBits)
runGCProg(addb(, 4), nil, (*byte)(unsafe.Pointer(.startAddr)), 1)
return
}
func ( *mspan) {
mheap_.freeManual(, spanAllocPtrScalarBits)
}
func ( *byte) {
:= 0
for {
:= *
= add1()
if == 0 {
print("\t", , " end\n")
break
}
if &0x80 == 0 {
print("\t", , " lit ", , ":")
:= int(+7) / 8
for := 0; < ; ++ {
print(" ", hex(*))
= add1()
}
print("\n")
+= int()
} else {
:= int( &^ 0x80)
if == 0 {
for := uint(0); ; += 7 {
:= *
= add1()
|= int(&0x7f) <<
if &0x80 == 0 {
break
}
}
}
:= 0
for := uint(0); ; += 7 {
:= *
= add1()
|= int(&0x7f) <<
if &0x80 == 0 {
break
}
}
print("\t", , " repeat ", , " × ", , "\n")
+= *
}
}
}
if := getg(); .m.curg.stack.lo <= uintptr() && uintptr() < .m.curg.stack.hi {
var stkframe
.sp = uintptr()
:= getg()
gentraceback(.m.curg.sched.pc, .m.curg.sched.sp, 0, .m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&)), 0)
if .fn.valid() {
, , := getStackMap(&, nil, false)
if .n == 0 {
return
}
:= uintptr(.n) * sys.PtrSize
:= (*ptrtype)(unsafe.Pointer()).elem.size
= make([]byte, /sys.PtrSize)
for := uintptr(0); < ; += sys.PtrSize {
:= (uintptr() + - .varp + ) / sys.PtrSize
[/sys.PtrSize] = .ptrbit()
}
}
return
}
return
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |