GC stack map scanning question

316 views
Skip to first unread message

evgeny777

unread,
Nov 2, 2022, 2:32:36 PM11/2/22
to golang-dev
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

David Chase

unread,
Nov 2, 2022, 3:08:20 PM11/2/22
to evgeny777, golang-dev
If a goroutine needs to be interrupted for scheduling or GC, and it has just entered a function F, there is code
in F's prologue to spill register arguments into memory, so that the old arguments-on-stack scanning code
does the right thing.

No idea off-hand why two maps instead of just one. 

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-dev/0303b82e-1567-4315-bad0-906c6cc64eaan%40googlegroups.com.

Keith Randall

unread,
Nov 2, 2022, 3:10:23 PM11/2/22
to evgeny777, golang-dev
> 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?

Sometimes there are arguments but no frame. For instance, defer'd or go'd functions, or functions that just called into growstack. We still need to be able to scan their arguments.
But you could probably get away with merging those two bitmaps and just not use all of them if the locals don't exist yet.


--
Reply all
Reply to author
Forward
0 new messages