Skip to content

Wasmtime exception support needs instance vmctx in each Wasm frame #11285

@cfallin

Description

@cfallin

I have come to a late realization in my quest to implement exception support: we will need to modify the Wasm calling convention to store the vmctx value in each frame. This will unfortunately pessimize common-case execution because it expands each frame by one word (possibly two with padding; 1.5 on average) and adds a store to every prologue.

The reason for this has to do with the nominal aspect of tag identities (see spec for throw_ref for details):

  • Tags to identify handlers are dynamic entities, instantiated as part of the state of a given instance in the store. The spec refers to "tag addresses" to denote this. Tag instances can be exported and imported just as memories, tables, and globals can be.
  • In Wasmtime, we represent tags with VMTagDefinitions inline in the vmctx, and VMTagImports that hold pointers to the tag definitions, similarly to memories and tables.
  • Exception objects reference tag instances by defining-instance ID and defined tag index in that instance, since we have to ensure that GC heap contents remain untrusted and bounds-checked on use, but this is otherwise equivalent: we are naming the dynamic instance.

When compiling a try_table, we emit tag identities for handlers with static TagIndexes, and those get serialized into the exception table. My thought has always been that on a throw's stack-walk, we will translate these to dynamic tag instances and compare to the dynamic tag instance in the thrown exception.

The problem is that as we walk the stack, we have PC and FP only; we can map PC to a particular static module, but one module may be instantiated multiple times within a store. And each of these instances will have different tag instances (in general) for a given static tag index. The vmctx is saved somewhere, but that's up to regalloc, and opaque to our stack-walk. We simply don't have enough information.

In the case where we have a single-instance store, and no imported tags (the former implies the latter actually, because we create dummy instances for host-created tags), we can get around this by comparing static tag indices directly. But that's a subset and we need to support the full spec.

Prior art in other engines seems to be that the instance (vmctx) is available during stackwalking -- e.g., in SpiderMonkey, caller and callee vmctx are saved in-frame in every Wasm frame.

For what it's worth, I believe we will run into this need eventually even independently of exception-handling: for example, debug support will also have a need to access instance state (vmctx) when introspecting stack frames. So far our stackwalking usage has been restricted to GC, where instance identity doesn't matter (GC refs are store-wide), and backtrace generation, where we only need static module identity to symbolicate. So this is the first time that dynamic instance identity matters, but likely not the last.

Metadata

Metadata

Assignees

No one assigned

    Labels

    wasm-proposal:exceptionsIssues for WebAssembly exceptions/exception-handling

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions