mirror of
https://github.com/hanzoai/wasm2go.git
synced 2026-10-30 15:06:48 +00:00
The legacy-EH support added for clang's SjLj lowering only covered the single-tag patterns SjLj emits. Clang's -fwasm-exceptions C++ output (e.g. llama.cpp) additionally needs: - try with multiple catch clauses (catch $a / catch $b / catch_all), dispatched by tag in clause order - catch_all-only trys and rethrow inside catch_all (the cleanup-during- unwind shape), including `rethrow l` with l > 0 naming an OUTER catch's exception - `delegate l` forwarding to a specific outer try, skipping every try nested in between Lowering now resolves delegate and rethrow label depths to their target try regions (ctrl frames track handler state), records each region's protected-body block set — the CFG alone cannot delimit it, because a br that exits a try early makes its continuation reachable from inside — and handles `delegate` closing a try inside a dead region. The recover-trampoline emitter drops its single-non-catch_all-handler restriction: every region gets an active flag and its own caught- exception variable, the dispatch is an innermost-first if-chain with per-clause tag tests, a delegate arm clears the flags of the regions it skips, and any edge leaving a protected body clears its flag (a br out of a try previously left the flag set, so a later unrelated throw could misroute into the exited try's handler). The structured emitter registers per-region exception variables so outer-targeting rethrows resolve correctly, bails to the trampoline when a delegate's target is not what a plain re-panic would reach or when a body block escapes the region (its continuation would otherwise be duplicated inside the protective closure), and closes a try no path falls out of with trap+spin so Go's termination analysis accepts the function. SSA verification computes dominators over the CFG augmented with virtual entry-to-handler edges, so handler landing pads (which have no CFG predecessors) may use values defined before their try. gcasm routes functions that call their own EH closures to the pure fallback: the outer function of a structured try has no panic/recover runtime call of its own — the defer/recover lives inside the closure it calls. Verified this session: `go test -race -timeout 20m ./...` exit 0 (all packages ok). New fixtures cover multi-clause dispatch on both emit paths, catch_all+rethrow, a delegate skipping an intermediate handler, an outer-targeting rethrow, and the try-exit flag drop. A full llama.cpp module (wasm32-wasip1, -fwasm-exceptions, SIMD disabled) transpiles and generates correct text end-to-end. The googlesql/wasmify five-step e2e chain was NOT run this session. Co-authored-by: Claude Fable 5 <[email protected]>
22 lines
551 B
WebAssembly Text Format
22 lines
551 B
WebAssembly Text Format
;; `rethrow l` with a non-zero depth re-raises an OUTER catch's exception.
|
|
;; The inner catch_all holds $a(99) but rethrow 1 names the outer catch $a,
|
|
;; whose exception is $a(42); the top-level try must observe 42, not 99.
|
|
(module
|
|
(tag $a (param i32))
|
|
(func (export "run") (result i32)
|
|
try (result i32)
|
|
try (result i32)
|
|
i32.const 42
|
|
throw $a
|
|
catch $a
|
|
drop
|
|
try (result i32)
|
|
i32.const 99
|
|
throw $a
|
|
catch_all
|
|
rethrow 1
|
|
end
|
|
end
|
|
catch $a
|
|
end))
|