| 4590076f | 26-Jul-2025 |
Chris Fallin <[email protected]> |
Cranelift: support dynamic contexts in exception-handler lists. (#11321)
In #11285, we realized that Wasm semantics require us to match on dynamic instances of exception tags, rather than static tag
Cranelift: support dynamic contexts in exception-handler lists. (#11321)
In #11285, we realized that Wasm semantics require us to match on dynamic instances of exception tags, rather than static tag types. This fundamentally requires the unwinder to be able to resolve the current Wasm instance for each Wasm frame on the stack that has any handlers, and our frame format does not provide this today.
We discussed many options, some of which solve the more general problem (Wasm vmctx for any frame), but ultimately landed on a notion of "dynamic context for evaluating tags", specific to Cranelift's exception-catch metadata; and storing that context and carrying it through to a place that is named in the unwind metadata. The reasoning is fairly straightforward: we cannot afford a more general approach that stores vmctx in every frame (I measured this at 20% overhead for a recursive-Fibonacci benchmark that is call-intensive); and inlining means that we may have *multiple* contexts at any given program point, each associated with a different slice of the handler tags; so we need a mechanism that, *just for a try-call*, intersperses contexts with tags (or puts a context on each tag) and stores these somewhere that the exception-unwind ABI doesn't clobber (e.g., on the stack).
This PR implements "option 4" from that issue, namely, *dynamic exception contexts*. The idea is that this is the dual to exception payload: while payload lets the unwinder communicate state *to* the catching code, context lets the unwinder take state *from* the catching code that lets it decide whether the tag is a match. Because of inlining, we need to either associate (optional) context with every tag, or intersperse context-updates with handler tags. I've opted for the latter for efficiency at the CLIF level (in most cases there will be multiple tags per context), though they are isomorphic.
The new tag-matching semantics are: when walking up the stack, upon reaching a `try_call`, evaluate catch-clauses in listed order. A `context` clause sets the current context. A `tagN: block(...)` clause attempts to match the throwing exception against `tagN`, *evaluated in the current context*, and branches to the named block if it matches. A `default: block(...)` always branches to the named block.
Note that this lets us assume less about tags than before, and this particularly manifests in the changes to the inliner. Whereas before, `tagN` is `tagN` and an inner handler for that tag shadows an outer handler (that is, tags always alias if identical indices); and whereas before, `tagN` is not `tagM` and so we can order the tags arbitrarily (that is, tags never alias if non-identical indices); now any two static tag indices may or may not alias depending on the dynamic context of each. Or, even in the same context, two may alias, because we leave the match-predicate as an unspecified (user-chosen) algorithm during unwinding. (This mirrors the reality that, for example, a Wasm instance may import two tags, and dynamically these tags may be equal or different at runtime, even instantiation-to-instantiation.) Cranelift's only job is to faithfully carry the list of contexts and tags through to the compiled-code metadata; and to ensure that they remain in the order they were specified in the CLIF.
This PR introduces the Cranelift-level feature, and it will be used in a subsequent PR that introduces Wasm exception handling. Because of that, I've opted not to update the clif-utils runtest "runtime" to read out contexts and do something with them -- we will have plenty of test coverage via a bunch of Wasm tests for corner cases such as the above. This PR does include filetests that show that contexts are carried through to spillslots and those appear in the metadata.
Fixes #11285.
show more ...
|
| 8a23cc74 | 09-Jul-2025 |
Nick Fitzgerald <[email protected]> |
Cranelift: Make `ir::{Constant,Immediate}` considered entities (#11207)
* Cranelift: Make `ir::{Constant,Immediate}` considered entities
They reference data in out-of-line pools rather than storing
Cranelift: Make `ir::{Constant,Immediate}` considered entities (#11207)
* Cranelift: Make `ir::{Constant,Immediate}` considered entities
They reference data in out-of-line pools rather than storing their data inline in the instruction, and when an instruction containing them is moved from one `ir::Function` to another, they need their indices updated accordingly. Therefore, they really are entities rather than immediates.
This recategorization means that they will now be properly mapped in `ir::InstructionData::map` calls.
* fix tests
show more ...
|