cfallin edited PR #11230.
cfallin has marked PR #11230 as ready for review.
cfallin requested alexcrichton for a review on PR #11230.
cfallin requested wasmtime-compiler-reviewers for a review on PR #11230.
cfallin requested wasmtime-core-reviewers for a review on PR #11230.
cfallin requested wasmtime-fuzz-reviewers for a review on PR #11230.
cfallin requested fitzgen for a review on PR #11230.
cfallin commented on PR #11230:
I think this is ready for a proper review now (and I've addressed comments from Alex and bjorn3 already -- thanks!).
fitzgen submitted PR review:
LGTM!
fitzgen created PR review comment:
Should this return a
StoreInstanceId(i.e. a(StoreId, InstanceId)pair) instead of a plainInstanceIdas the first tuple member here? That would make it fully "tamper-proof".I am not sure where this method is used yet tho...
fitzgen created PR review comment:
/// * `Ok(Ok(_))`: The allocation was successful.I guess the copy-paste source probably needs updates too...
fitzgen created PR review comment:
/// Allocate an uninitialized exception object with the given type"exceptino" would make a good pokemon name
github-actions[bot] commented on PR #11230:
Subscribe to Label Action
cc @fitzgen
<details>
This issue or pull request has been labeled: "fuzzing", "wasmtime:c-api"Thus the following users have been cc'd because of the following labels:
- fitzgen: fuzzing
To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.
Learn more.
</details>
jeffparsons submitted PR review.
jeffparsons created PR review comment:
Isn't that the evolution of _MissingNo._?
tschneidereit commented on PR #11230:
Perhaps with the exception of a setjmp/longjmp use-case in wasi-libc?
I think this is a very load-bearing "perhaps", fwiw: I can very very easily see people wanting to have smallest-possible Wasmtime builds and not use GC. And I can equally easily see wasi-libc switch to using sjlj based on EH.
None of this might be enough to put in the work to support exceptions without GC, of course. But if it's more a lack of signal for a need for it: I would bet good money on us getting that signal before too long
sunfishcode commented on PR #11230:
wasi-libc does have a setjmp/longjmp implementation using EH, and does not support setjmp/longjmp otherwise.
cfallin commented on PR #11230:
Yes, that's fair, and I did discuss this with Nick early on re: overheads of requiring GC. It seems that the lazy GC heap allocation means that we should be able to have GC enabled without paying a large penalty for it when not used. That, put against the huge duplication of code to also have a "GC-less exceptions" implementation (which would necessarily be almost fully separate, and would also require separate codegen paths), convinced me to go this route.
I'll note that the exceptions proposal's structuring unfortunately pushes us in this direction too: it does not hold back
catch_refclauses andthrow_refto a "when GC enabled" superset, but rather these are always available. It wouldn't be too bad to do an "unboxed exceptions" implementation that directly copies payload values and supports onlycatchclauses andthrow, and indeed I started designing down that route in the hope that I could make setjmp/longjmp a happy fastpath, but it's just too much duplication to be maintainable, and also once you need to support the full proposal and box into exception objects, it adds dynamic checks to support the full matrix of{boxed, unboxed} ^ 2.
alexcrichton commented on PR #11230:
Personally while I agree with @cfallin's conclusions about this direction being the way to go for now I also believe that this issue won't be put to rest and this is something we're going to have to deal with. One example is that allocating a GC heap is akin to a second linear memory meaning that the per-Store overhead will jump from one linear memory to two linear memories for "lean" languages such as Rust/C/C++, just to support exceptions. (assuming guests eventually get to the point of using exceptions by default). That's then additionally coupled with the fact that it's unlikely embedders will want to interact deeply with exceptions (e.g. make their own, read fields, etc) and nor will Rust/C/C++ use the GC-like behavior of exceptions (e.g. a
catch_refis probably immediately always followed by athrow_reflater in the control flow).I think these are all problems we're going to have to tackle at some point in the future. "Just turn on GC" as-is today I don't think is going to cut it in the long-term, but I also don't think that should apply stop-energy here either. This implementation is also going to be required in the fullness of time to support GC languages and the exceptions they throw/use. In essence I think that this implementation is basically inevitable and the only hypothetical missing piece is a leaner implementation of "only the exceptions bits needed for linear memory languages". That's hypothetical in that it's not certain we need it and it's also not certain what exact subset, if any, is needed.
cfallin created PR review comment:
I thought about that, but this is stored within an object within the store, and when we reconstitute a
&Tagwe use the store it came from, so I think we should be fine in this case (vs. adding 4 bytes to every exception object).
cfallin submitted PR review.
cfallin updated PR #11230.
cfallin created PR review comment:
Fixed!
cfallin submitted PR review.
cfallin submitted PR review.
cfallin created PR review comment:
Fixed!
And fwiw, I believe exceptinos are the subatomic particles that convey exception throws at the speed of light...
cfallin edited PR #11230:
This PR implements exception objects: the data model required to support Wasm exceptions, integrated with Wasm GC.
It builds out support for defining exception types (based on function signatures), and a host API to allocate and examine exception objects. It does not yet tie this into any exception-throwing or -catching instructions (
throw,throw_ref,try_table); that will come next.The design is a little fiddly because the type system has a nominal aspect to it: tags are per-instance entities and exceptions are associated with tags. The stack-switching work already added support for tags analogously to other instance entities (memories, tables, etc.). But, notably, because they are a runtime concept, they are not types per-se. Their signatures are, though, and
TagTypeis a thin wrapper aroundFuncTypeas a result. The Wasm proposal does not define any concrete type definitions for exception objects in the lattice, only providing top (exnref/(ref null exn)) and bottom (nullexnref/(ref null noexn)) types. In order to align with the way the rest of the GC system works, I've opted to define our own notion of structural types at the host API and type-interning layer built around the signatures; so all Wasm exception objects with the same func-type / signature are the same "type" as far as GC is concerned. The objects of that type are then associated with particular tag instances via runtime fields. In essence we are refining the Wasm types further to allow our implementation to precompute things (i.e., layouts); this is fine because this refinement is not exposed to Wasm.
cfallin has enabled auto merge for PR #11230.
cfallin merged PR #11230.
fitzgen commented on PR #11230:
I think we will want to keep the implementation of exceptions in terms of GC objects, with possible unboxing optimizations that are really orthogonal to the core discussion here, but we will want to add config knobs dedicated for GC heaps. Right now, GC heaps are always the same configuration as linear memories. For LIME-style deployments, however, they will want to configure the GC heap to be much smaller than 64KiB (effectively using custom-page-sizes for GC heap memories), after which
allocating a GC heap is akin to a second linear memory
is effectively resolved.
We really don't want to have to maintain two implementations of exceptions: one for LIME Wasm and one for GC Wasm. By allowing one to configure the GC heap so that it is tiny, we are effectively allowing the GC-based implementation to be tuned down into the equivalent side-table that we would implement for the LIME Wasm version.
tschneidereit commented on PR #11230:
is effectively resolved.
Does this allow us to set the allocation to 0, or something really very small? Because if it still requires at least one host page size of memory, I'm not sure it really is effectively resolved for all use cases.
Besides memory usage, I'm also concerned about the code size increase we incur by forcing the inclusion of full GC support for exception handling. Do we have a way to quantify / at least very roughly estimate how much larger a size-optimized binary becomes because of that?
sunfishcode commented on PR #11230:
It wouldn't be too bad to do an "unboxed exceptions" implementation that directly copies payload values and supports only
catchclauses andthrowIn the Lime series, we do have the ability to subset features, for exactly this reason, so perhaps we should to that for EH too.
It seems likely that other engines will want a subset too. And the setjmp/longjmp used by LLVM and wasi-libc already uses just
catchandthrow.
fitzgen commented on PR #11230:
Meta note: I am going to file a follow up issue for this discussion. Once I do so, let's move all this discussion there.
fitzgen commented on PR #11230:
Meta note: I am going to file a follow up issue for this discussion. Once I do so, let's move all this discussion there.
Filed https://github.com/bytecodealliance/wasmtime/issues/11256
Last updated: Dec 06 2025 at 07:03 UTC