Files
wasm2go/testdata/eh_trampoline.wat
3e00ba5f1d Support WebAssembly exception-handling (setjmp/longjmp) transpilation (#22)
Transpile wasm modules that use the exception-handling proposal — the
try / catch / catch_all / throw / delegate / rethrow ops plus the tag
section. Clang lowers C/C++ setjmp/longjmp onto these ops under
`-mllvm -wasm-enable-sjlj`, so this is what lets wasm2go handle any
module built that way.

EH constructs are emitted as Go panic/recover: a throw becomes a
panic(*wasmExc); a try body runs inside a closure guarded by a deferred
recover; catch dispatches on the tag and narrows the operand slots.
setjmp-style resume — a longjmp re-entering the protected region — is
handled by a general recover-trampoline that wraps the whole function in
a `for { ... }` loop with a __pc dispatch, so re-entry is a loop
iteration rather than a goto across the closure boundary.

Pieces:

- Parser: decode the EH ops and the tag section.
- SSA / lower: throw -> BlockThrow terminator; try / catch / catch_all
  lowering with mutable locals; delegate + rethrow; no local phis at
  loop headers in mutable-locals mode.
- Codegen: emit try/catch/throw as panic/recover; real setjmp/longjmp
  exception-resume loops; EH in multi-package output; structured
  br_table + shared forward joins so more EH functions take the
  structured path; the general recover-trampoline for goto-EH /
  loop-spanning-try / resume; and bail a try-body function return to the
  trampoline (a plain return cannot escape the *wasmExc closure).
- gcasm: fall back to pure Go for non-replayable jump tables so the
  pure-Go asm backend never hard-fails a bundle.

New E2E coverage: EH try/catch, setjmp/longjmp resume loops, structured
br_table, multi-package EH, and the recover-trampoline, plus a
checked-in testdata wasm. go build ./..., go test ./... and golangci-lint
are green.


Claude-Session: https://claude.ai/code/session_01QWhxMdYGXtDRtDdKZXqnHG

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-09 11:57:39 +09:00

50 lines
1.3 KiB
WebAssembly Text Format

;; Forces the recover-TRAMPOLINE goto-EH path: a try/catch sits inside a loop
;; that has TWO distinct exit targets ($b1, $b2), so the structured emitter
;; bails (multi-exit loop) and the function is laid out via emitTrampoline.
;; run($x): each iteration increments $i, throws $i and catches it into $r; then
;; if $r == $x -> $b1 -> $r = 100
;; if $i >= 10 -> $b2 -> $r = 200
;; so run(3) = 100 (caught 3 == x on the 3rd iteration) and run(50) = 200.
(module
(tag $e (param i32))
(func $thrower (param i32)
local.get 0
throw $e)
(func (export "run") (param $x i32) (result i32)
(local $r i32)
(local $i i32)
block $done
block $b2
block $b1
loop $lp
local.get $i
i32.const 1
i32.add
local.set $i
try
local.get $i
call $thrower
catch $e
local.set $r
end
local.get $r
local.get $x
i32.eq
br_if $b1
local.get $i
i32.const 10
i32.ge_s
br_if $b2
br $lp
end
end
i32.const 100
local.set $r
br $done
end
i32.const 200
local.set $r
br $done
end
local.get $r))