@@ -32,6 +32,7 @@ package runtime
3232
3333import (
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.
8086func (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.
125131func (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