@@ -32,6 +32,7 @@ package runtime
3232
3333import (
3434 "internal/task"
35+ "math/bits"
3536 "runtime/interrupt"
3637 "unsafe"
3738)
@@ -74,6 +75,11 @@ const (
7475 blockStateMask blockState = 3 // 11
7576)
7677
78+ // blockStateByteAllTails is a byte containing 4 times blockStateTail bits.
79+ // It assumes there are 2 state bits per block, otherwise it might have to be
80+ // turned into variable and assigned using inline function.
81+ const blockStateByteAllTails = uint8 (blockStateTail << (stateBits * 3 ) | blockStateTail << (stateBits * 2 ) | blockStateTail << (stateBits * 1 ) | blockStateTail << (stateBits * 0 ))
82+
7783// String returns a human-readable version of the block state, for debugging.
7884func (s blockState ) String () string {
7985 switch s {
@@ -121,9 +127,32 @@ func (b gcBlock) address() uintptr {
121127// points to an allocated object. It returns the same block if this block
122128// already points to the head.
123129func (b gcBlock ) findHead () gcBlock {
124- for b .state () == blockStateTail {
125- b --
130+ stateBytePtr := (* uint8 )(unsafe .Add (metadataStart , b / blocksPerStateByte ))
131+
132+ // XOR the stateByte with byte containing all tails to turn tail bits to 0
133+ // and shift out the bits that are not part of the object
134+ stateByte := ((* stateBytePtr ) ^ blockStateByteAllTails ) << ((blocksPerStateByte - (b % blocksPerStateByte + 1 )) * stateBits )
135+ // if stateByte is 0 that means all blocks are tails so we loop trough subsequent states,
136+ // byte at a time to find the first byte that is not all tails
137+ if stateByte == 0 {
138+ // subtract the number of object blocks that were in the first byte
139+ b -= (b % blocksPerStateByte + 1 )
140+ // skip to next byte
141+ stateBytePtr = (* uint8 )(unsafe .Add (unsafe .Pointer (stateBytePtr ), - 1 ))
142+ // loop until state byte is not all tails
143+ for (* stateBytePtr )^ blockStateByteAllTails == 0 {
144+ stateBytePtr = (* uint8 )(unsafe .Add (unsafe .Pointer (stateBytePtr ), - 1 ))
145+ b -= blocksPerStateByte
146+ }
147+ // set stateByte variable to the first byte that is not all tails and turn all tail bits to zeroes
148+ stateByte = (* stateBytePtr ) ^ blockStateByteAllTails
126149 }
150+
151+ // at this point stateByte is set to the first state byte of the object that we encountered which is not all tails
152+ // and all tail bits in it are turned to zero. We count number of bytes that are 0 (tail) using LeadingZeros8
153+ // and divide it by stateBits to get the number of tail blocks in state bits.
154+ b -= gcBlock (bits .LeadingZeros8 (stateByte ) / stateBits )
155+
127156 if gcAsserts {
128157 if b .state () != blockStateHead && b .state () != blockStateMark {
129158 runtimePanic ("gc: found tail without head" )
0 commit comments