[Emscripten-EH] Implement __cxa_throw in terms of _Unwind_RaiseException - #27498
Conversation
5f0e9ae to
637ec5b
Compare
6dcdb9f to
4f4cd6d
Compare
|
I could potentially split this change up, land an NFC that just moves the old unwind code into its own file? Would that be useful? |
__cxa_throw in terms of _Unwind_RaiseException
Extract `_Unwind_*` functions and `uncaughtExceptionCount` / `exceptionLast` JS state from libcore.js and libexceptions.js into a dedicated `libunwind.js`. This new libunwind.js is included as long as wasm EH is not being used. Also, invert the dependency between `__cxa_throw` and `_Unwind_RaiseException` so that `__cxa_throw` now calls `_Unwind_RaiseException` rather than the other way around. This is important as it allows C programs (or rather non-C++ programs like Rust) to call `_Unwind_RaiseException` without linking as C++. Inspired by emscripten-core#27496
|
The reason we see a light code size saving here is because |
|
Funny how I can work on compilers for decades and not be aware of how/when libunwind function are linked / used... |
| $uncaughtExceptionCount: '0', | ||
| #if !DISABLE_EXCEPTION_CATCHING | ||
| $exceptionLast: null, | ||
| #endif |
There was a problem hiding this comment.
In libcxxabi native code (and thus in Wasm EH), managing information like uncaught exception count and last exception is done by libcxxabi, not libunwind. It is true in libcxxabi/libunwind that __cxa_throw calls _Unwind_RaiseException, but all exception status managing is done within libcxxabi. Wouldn't it be consistent to manage it within libexceptions.js and leave libunwind simple?
There was a problem hiding this comment.
Sure, we can make it consistent in that way. I'll make a followup PR.
#27496) This makes `-fwasm-exceptions` link the Wasm EH runtime independently of C++ linking. Wasm EH objects can be produced by non-C++ frontends - notably rustc, whose precompiled std uses Wasm exceptions for unwinding and which invokes `emcc` (not `em++`) as its linker. Since `DEFAULT_TO_CXX` was disabled by default in #27469, any rust-driven emcc link now fails with: ``` wasm-ld: error: libstd-*.rlib: undefined symbol: __cpp_exception wasm-ld: error: libpanic_unwind-*.rlib: undefined symbol: _Unwind_RaiseException ``` because both libunwind and the `__cpp_exception` tag (previously defined in libc++abi) were only linked under `LINK_AS_CXX`. The tag and the unwinding runtime are language-agnostic runtime support for the Wasm EH LLVM lowering, not part of the C++ ABI surface. This PR now includes #27498 as its base, which provides the same `_Unwind_*` linkability for the non-Wasm-EH modes on the JS side. What's implemented: * The `__cpp_exception` tag definition moves from libc++abi (`__cpp_exception.S`) into libunwind's `Unwind-wasm.c` as inline asm, matching upstream llvm/llvm-project#185770. * libunwind is linked whenever `WASM_EXCEPTIONS` is enabled, rather than only when linking as C++. Test coverage extends `test_libunwind` from #27498 with `wasm_eh` and `wasm_legacy_eh` variants (completing its TODO), and adds `test_cpp_exception_tag` linking an asm object that throws the tag directly from a C caller - the same reference pattern as rustc-generated catch/throw sites - which fails to link without this change. The now-unneeded `DEFAULT_TO_CXX` workaround is dropped from `test_wasi_with_sjlj`. Existing C++ Wasm EH coverage (`core0.test_exceptions_*`) passes unchanged. _Made with AI assistance under my review_
emscripten-core#27498 moved EH status management (`uncaughtExceptionCount` and `exceptionLast` from `libexceptions.js` to `libunwind.js`, but because in the native libcxxabi and libunwind, the management is done within libcxxabi, I think it'd be more consistent if we do the same for the JS libraries.
#27498 moved EH status management (`uncaughtExceptionCount` and `exceptionLast` from `libexceptions.js` to `libunwind.js`, but because in the native libcxxabi and libunwind, the management is done within libcxxabi, I think it'd be more consistent if we do the same for the JS libraries.
It turns out the libunwind symbols are supposed to always be available, enen non-C++ programs. This means that
__cxa_throwshould be implemented in terms of_Unwind_RaiseExceptionand not the other way around._Unwind_Resume__cxa_throwand other exception-handling APIs in terms of the lower level_UnwindAPI.Inspired by #27496