Stream: git-wasmtime

Topic: wasmtime / issue #2459 Implement wasmtime GC tracing with...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 28 2022 at 22:57):

cfallin commented on issue #2459:

@fitzgen now that #4431 is merged (:tada: ) is this issue subsumed as well? I.e. I wonder if GC tracing works with unwinding info omitted?

view this post on Zulip Wasmtime GitHub notifications bot (Jul 28 2022 at 22:58):

cfallin commented on issue #2459:

(the other part of this issue is I guess discussing ways to avoid the need for stackmaps entirely, but the toplevel problem description is basically just "make do without libunwind")

view this post on Zulip Wasmtime GitHub notifications bot (Aug 01 2022 at 17:32):

fitzgen commented on issue #2459:

Yes, this issue should be resolved, but I'll leave it open until I can verify whether we can disable dynamically registering unwind info without breaking perf or what have you.

view this post on Zulip Wasmtime GitHub notifications bot (Aug 04 2022 at 16:34):

fitzgen commented on issue #2459:

I'm actually going to close this as complete, and handle the unwind info and all that in https://github.com/bytecodealliance/wasmtime/issues/4554

view this post on Zulip Wasmtime GitHub notifications bot (Aug 04 2022 at 16:34):

fitzgen closed issue #2459:

In wasmtime, GC tracing of reftype pointers currently works by using libunwind to iterate over stack frames, fetching a stackmap for each relevant PC and finding the stack slots with live pointers.

This works perfectly fine, but is potentially slower than we would like, because libunwind relies on DWARF info to understand stack frames. It is also more complex -- it relies on DWARF generation and interpretation to be correct -- which increases risk a little because GC-tracing bugs can lead to various security issues.

In contrast, many other high-performance JITs use explicit data structures of some sort on the stack so that tracing stack roots boils down to walking a linked list of some sort. For example, SpiderMonkey has a strict JIT-frame discipline allowing fast iteration (different from the system ABI), and V8 indirects object references through InstanceHandles that link themselves into a list on the thread context.

We should look into designing a mechanism that maintains a stack of frames reachable from the vmctx and walkable without any metadata (aside from the stackmaps). Two options that come to mind are:

Option 1: Shadow Stack of (SP, Stackmap) Tuples

Maintain a shadow stack (with top and limit pointers in vmctx) of (stackmap, SP) tuples. On function entry, allocate a tuple. At every safepoint, ensure that the stack pointer and stackmap for that safepoint are up-to-date in the tuple. Walking the stack for GC roots then simply requires (i) looping over these tuples, and (ii) tracing references at offsets indicated by the stackmap.

Some advantages of this scheme are:

Some disadvantages of this scheme are:

Option 2: Shadow Stack of References

Maintain a shadow stack that actually stores spilled references. On function entry, bounds-check that there is enough shadow-stack space for the maximal live-set of reftyped values at any safepoint in the function (this is statically known). At any safepoint, push all live reftyped values to the shadow stack; after the safepoint, restore them (if we implement a moving GC that may edit pointers) or bulk-pop them by bumping the top pointer.

Some advantages of this scheme are:

A disadvantage of this scheme is:

I tentatively prefer Option 2, but I can see both options as viable. Thoughts?

cc @fitzgen


Last updated: Dec 23 2024 at 12:05 UTC