Repository navigation
wasm: unify browser exception handling on native SjLj - #2734
Draft
zhouguangyuan0718 wants to merge 5 commits into
Draft
zhouguangyuan0718 wants to merge 5 commits into
zhouguangyuan0718 wants to merge 5 commits into
Conversation
LLGo WebAssembly build benchmarks
WebAssembly output sizes
LLGo WebAssembly build measurements
Compared with |
LLGo baseline benchmarks
Program measurements
Core language and compiler benchmarks
Timer runtime benchmarks
Compared with |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Known compatibility regression; keep this PR draft: the previous JavaScript EH path supports the tested C++ catch -> Go callback -> Sleep -> resume sequence. Using the unmodified pre-change compiler
ec9c2488b, both direct and indirect callbacks resumed and returned normally at O0 and O2 in Node and Chrome on Emscripten wasm32 (eight passing runs). The native Wasm EH/Asyncify path does not support suspension while the catch is active. The new negative-test assertions detect this loss of capability; they do not fix it. The default switch must be reconsidered against this regression before merge.Browser targets currently lower Go panic/recover through Emscripten's JavaScript SjLj wrappers, while WASI uses native Wasm exceptions. JS wrappers cannot carry
v128, requiring the SIMD call bridges and late-inlining restrictions in #2722. This PR selects native Wasm SjLj for GoJS, Emscripten wasm32, and Emscripten Memory64.Compile and link with
-sSUPPORT_LONGJMP=wasm -fwasm-exceptions. Both are needed: Emscripten bindings can reference C++ exception support even when the entry package contains only Go. The matching-LLVM Memory64 IR compiler uses native SjLj instead of-enable-emscripten-sjlj. Validate environment options and final package link arguments against incompatible SjLj settings andasyncify-ignore-unwind-from-catch.Go's runtime retains its existing setjmp/longjmp implementation of defer/panic/recover. Browser builds retain Emscripten's legacy Wasm EH encoding for Asyncify; this is distinct from JavaScript SjLj. WASI retains its standard Wasm EH encoding. C++ exceptions must remain contained inside C++ wrappers and return a C ABI status to Go.
Qualification exposed three problems fixed here:
-ltochanged the LLGo optimization pipeline without enabling browser-driver LTO.emarfor Emscripten archives and MRI merging, preservingLLGO_ARoverrides. Host LLVM 22 cannot index some C++ bitcode from the SDK's LLVM 24.Asyncify has an explicit unsupported boundary: a callback must not suspend while a foreign Wasm catch is active. The Go/C++ fixture keeps its catch-status function behind a volatile function pointer because LLVM
noinlinealone does not preserve that boundary through Binaryen optimization. After returning from the wrapper, Go sleeps, collects, panics, and sleeps/collects again in the recovering defer.The acceptance matrix enables existing Binaryen
asyncify-assertswith EmscriptenASSERTIONS=0, and verifies that direct and indirect callbacks that deliberately suspend inside a C++ catch enter the callback, trap withunreachable, and never resume. These fixed negative callbacks are declarednoexcept; nested cleanup/unwind shapes are not comprehensively qualified.The extra assertions are only enabled for this focused acceptance matrix, not default application builds. The same Binaryen switch also rejects LLGo's intentional reflection trampoline suspension;
TestReflectCallAndMethodpasses with the default profile and traps with the extra assertions. There is no catch-only switch in the pinned Binaryen. This PR makes no new Binaryen or Emscripten patch, keeps the generic Asyncify/native-EH warning, and does not implement static analysis or automatic rejection of every unsupported catch/suspension path. Assertions detect unsupported behavior; they do not make it supported.No SIMD implementation changes are included. This branch is based directly on main
ec9c2488b, independently of #2722.Validation on macOS arm64 with Go 1.27.0, LLGo LLVM 22.1.8, Emscripten 6.0.8, LLGo Binaryen
llgo-v132.3, Node 24.19.0, Chrome, and Wasmer 7.5.0:invoke_*imports.Draft for review of the default-policy change. The pinned toolchain and explicit runtime matrix are required; this PR does not claim compatibility with arbitrary SDKs, arbitrary foreign catch/control-flow shapes, or foreign exceptions unwinding through suspended Go frames. CI remains in progress. The observed README link-check failure was a Codecov TLS HandshakeFailure, unrelated to these source changes; a green CI result would not resolve the compatibility regression above.