Good time of the day
I'm trying to dig into internals of Go GC and found some issue, I can't full understand. According to ABI specification Go can pass arguments either in registers or in stack memory. This also applies to Go heap pointers. For instance the following code allocates an object and places a pointer to %rax register when calling both tell and innerTell functions:
var _g int
//go:noinline
func ask(x int) *int {
res := int(x) + 42
return &res
}
//go:noinline
func innerTell(p *int) {
_g += *p
}
//go:noinline
func tell(p *int) {
innerTell(p)
}
func main() {
p := ask(42)
tell(p)
}
Go GC uses two bit vectors for scanning stack memory and finding GC roots LocalPointersMap and ArgPointersMap. Both point to stack memory and as far as I understand the former points to callee frame and the latter to caller frame. However it seems that if pointer argument is in register Go runtime still tries to scan caller frame in order to mark pointer (I see arg pointer map filled in Compute). I must be missing something because this may cause live object being swept, can someone please clarify?
Another question is why two separate maps are used? Both callee arguments and caller locals share single stack frame, so single bit vector can be used can't it?
Thanks