Skip to content

Commit bc0ab19

Browse files
Scan optimization
1 parent d5f1953 commit bc0ab19

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

src/runtime/gc_blocks.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ package runtime
3232

3333
import (
3434
"internal/task"
35+
"math/bits"
3536
"runtime/interrupt"
3637
"unsafe"
3738
)
@@ -76,6 +77,11 @@ const (
7677
blockStateMask blockState = 3 // 11
7778
)
7879

80+
// blockStateByteAllTails is a byte containing 4 times blockStateTail bits.
81+
// It assumes there are 2 state bits per block, otherwise it might have to be
82+
// turned into variable and assigned using inline function.
83+
const blockStateByteAllTails = uint8(blockStateTail<<(stateBits*3) | blockStateTail<<(stateBits*2) | blockStateTail<<(stateBits*1) | blockStateTail<<(stateBits*0))
84+
7985
// String returns a human-readable version of the block state, for debugging.
8086
func (s blockState) String() string {
8187
switch s {
@@ -123,9 +129,32 @@ func (b gcBlock) address() uintptr {
123129
// points to an allocated object. It returns the same block if this block
124130
// already points to the head.
125131
func (b gcBlock) findHead() gcBlock {
126-
for b.state() == blockStateTail {
127-
b--
132+
stateBytePtr := (*uint8)(unsafe.Add(metadataStart, b/blocksPerStateByte))
133+
134+
// XOR the stateByte with byte containing all tails to turn tail bits to 0
135+
// and shift out the bits that are not part of the object
136+
stateByte := ((*stateBytePtr) ^ blockStateByteAllTails) << ((blocksPerStateByte - (b%blocksPerStateByte + 1)) * stateBits)
137+
// if stateByte is 0 that means all blocks are tails so we loop trough subsequent states,
138+
// byte at a time to find the first byte that is not all tails
139+
if stateByte == 0 {
140+
// subtract the number of object blocks that were in the first byte
141+
b -= (b%blocksPerStateByte + 1)
142+
// skip to next byte
143+
stateBytePtr = (*uint8)(unsafe.Add(unsafe.Pointer(stateBytePtr), -1))
144+
// loop until state byte is not all tails
145+
for (*stateBytePtr)^blockStateByteAllTails == 0 {
146+
stateBytePtr = (*uint8)(unsafe.Add(unsafe.Pointer(stateBytePtr), -1))
147+
b -= blocksPerStateByte
148+
}
149+
// set stateByte variable to the first byte that is not all tails and turn all tail bits to zeroes
150+
stateByte = (*stateBytePtr) ^ blockStateByteAllTails
128151
}
152+
153+
// at this point stateByte is set to the first state byte of the object that we encountered which is not all tails
154+
// and all tail bits in it are turned to zero. We count number of bytes that are 0 (tail) using LeadingZeros8
155+
// and divide it by stateBits to get the number of tail blocks in state bits.
156+
b -= gcBlock(bits.LeadingZeros8(stateByte) / stateBits)
157+
129158
if gcAsserts {
130159
if b.state() != blockStateHead && b.state() != blockStateMark {
131160
runtimePanic("gc: found tail without head")

0 commit comments

Comments
 (0)