wasm-eh and throwBoundary
The default engine configuration is application / ldc-master. That means --wasm-enable-eh, -mattr=+exception-handling, --foptimize-nothrow=false, a post-build copy of svelte-engine-raw.wasm, and then Binaryen ≥123 wasm-opt with --enable-exception-handling. Release adds -Oz --converge --strip-debug --strip-dwarf --strip-producers. Debug is -g -O0 so DWARF stays. Official 123 and 132 still Flatten-crash on --asyncify. The etcimon/binaryen fork (binaryen/, bun run build-wasm-opt) Flattens try_table and asyncifies the same module so {#await} can wait. svelte-d wasm uses that fork when it is on PATH or under ~/.svelte-d/toolchains/binaryen-svelte-d; otherwise it -Ozs only. Navbar-style try/catch and printed throwBoundary need try_table / catch_ref either way. Host 1.42, and 1.43-without-those-flags, emit a throw that JS captureException turns into an abort. The module links. The first catch dies.
--foptimize-nothrow is the LDC 1.43 default on Windows and wasm, because it makes an unrelated LLVM bug less likely. It also deletes landing pads inside nothrow functions. Almost every printed struct is nothrow:. Without --foptimize-nothrow=false, D catch vanishes and you will debug a “working” binary that never enters the catch. The engine’s dub.sdl already passes the flag. A hand-built wasm that omits it is not this cell.
throwBoundary is same-function try / throw / catch on the same struct as trip(), then failBoundary. Personality is first-catch-type only. An exception that crosses a function boundary is an abort. See await / boundary.
A function that both catches around .await is still unsound: rewind re-enters the export from the top and the personality slot is not part of Asyncify. Printed wireAwait calls .await (or .then on stock Binaryen) and reads libwasmAwaitFailed() after rewind. throwBoundary never mentions .await. Named ldc-1.42 / ldc-1.36 configs remain for the older abort-on-throw asyncify cells; they are not the default, and they do not do D catch.