wasi-sdk
wasi-sdk copied to clipboard
Add Support for WASM Exceptions
There are plans to add support for exceptions in WAMR. Are there any plans to add support to the WASI-SDK tool chain to support Native WASM Exceptions?
(edit: fix link)
The rough plan is to look at Emscripten's port of libunwind to see if it can be either ported to upstream LLVM, or if not, ported to wasi-sdk. I don't know of anyone working on this yet.
It's also worth noting that Wasm Exceptions are not yet standardized; currently the proposal is in phase 3.
We hope to have an initial contribution to WAMR with exception support in the next few months. There is such a swathe of C++ software in-particular that is excluded from the WASM ecosystem because of the lack of exception support. It would be awesome to see a solution.
Although, digging through the code that is generated by the emscripten tool chain we can see, that at least for C++ it generates a single WASM exception throw
and catch
. This mimics almost exactly the approach used by traditional C++ compilers, but it means that the majority of the, quite elegant and nuanced behavior described in the WASM Exception proposal is rarely used. - This might be different for other programming languages - I've not checked.
As Dan mentioned, the easy part is enabling exceptions in the compiler (e.g. passing -fwasm-exceptions
). The more compex/nuanced part is getting libc++abi/libunwind configured correctly.
To see that current differences from upstream that were made in emscripten you can take a look here: https://github.com/emscripten-core/emscripten/blob/main/system/lib/libcxxabi/readme.txt. Specifically check out the link at the end that shows you the diffs from upstream llvm 16: https://github.com/llvm/llvm-project/compare/llvmorg-16.0.4...emscripten-core:emscripten-libs-16
Whooha... Rockstar's both of you, and I've got some reading to do. Thanks for the pointers. Let me take a look.
There's also a draft PR with initial support for this in #198, which you may be interested in.
I have a plan to upstream the current libc++abi/libunwind changes to the upstream LLVM. I think it can happen within a couple months if having this is a priority; the timeline can depend on the receptions from the reviewers though.
By the way there is a discussions going on (https://github.com/WebAssembly/exception-handling/issues/280) which can change the spec itself. I don't think the library side will change much with this though.
Thank you for the wait. Wasm EH's libcxxabi/libunwind changes have now been upstreamed: https://github.com/llvm/llvm-project/commit/e6cbba749490a20127359a3fbd05d8db7faef535 https://github.com/llvm/llvm-project/commit/058222b2316615194c089f2bc68d11341f39d26e
What does -fwasm-exceptions
do? Adding or removing that makes no difference, I still end up with
wasm-ld: error: /var/folders/74/djsf8lv965l2tkgr29ybpz4h0000gn/T/lib-858918.o: undefined symbol: __cxa_allocate_exception
wasm-ld: error: /var/folders/74/djsf8lv965l2tkgr29ybpz4h0000gn/T/lib-858918.o: undefined symbol: __cxa_free_exception
wasm-ld: error: /var/folders/74/djsf8lv965l2tkgr29ybpz4h0000gn/T/lib-858918.o: undefined symbol: __cxa_throw
thx
Just wanted to check, would WASM exceptions make sense for implementing C setjmp
/ longjmp
(i.e., how postgres uses them to implement exceptions), or are they too different and only make sense with language-native exceptions like in C++? If the latter, is there currently no plan that would be able to support setjmp
/ longjmp
in WASI?
I think you should be able to lower SjLj to exceptions.
Indeed, llvm already uses wasm exception to implement SJLJ, when wasm exceptions are enabled, so it should just work once we enable exceptions.
Indeed, wasm exceptions is how we've always envisioned setjmp
/longjmp
would work.
Thanks for confirming! I implemented stack unwind for wazero
https://github.com/tetratelabs/wazero/pull/1808
and look forward to trying it out with wasi SDK (from my reading of the thread it isn't quite ready yet for use with the published SDKs)
What does
-fwasm-exceptions
do? Adding or removing that makes no difference, I still end up withwasm-ld: error: /var/folders/74/djsf8lv965l2tkgr29ybpz4h0000gn/T/lib-858918.o: undefined symbol: __cxa_allocate_exception wasm-ld: error: /var/folders/74/djsf8lv965l2tkgr29ybpz4h0000gn/T/lib-858918.o: undefined symbol: __cxa_free_exception wasm-ld: error: /var/folders/74/djsf8lv965l2tkgr29ybpz4h0000gn/T/lib-858918.o: undefined symbol: __cxa_throw
thx
I found that llvm 17 was branched off end of June and above exception patches were merged mid September, so we need to wait for llvm 18 (should branch off today, first RC on Friday) or upgrade to a git version.
The -fwasm-exceptions
flag allows the compiler to output the try / catch and other exception handling instructions in WebAssembly bytecode. But it is up to the language implementation to determine how these instructions are used.
Languages aren't used to dealing with WASM exception instructions. Instead they traditionally use setjmp / longjmp, C++ is a good example of this. Therefore the language's supporting library (also confusingly called the C++ runtime) needs to be updated to use exception handling.
When the C++ compiler encounters an exception in the code you are attempting to compile, behind the scenes it generates calls to it's runtime library to implement the exception handling. It is inside the runtime library that the exception instructions are used.
The error your seeing is an error generated by WASI-SDK, which bundles the C++ runtime library, the version of the library supplied by WASI-SDK doesn't include the three functions listed above - which are all designed for exception handling.
So when you compile C++ with an exception in your code, the compiler generates it faithfully, with calls to functions in the C++ runtime library which do not exist, this is why, at link time you get the error message you mentioned.
The Emscripten folks have worked on this and have an update which includes the C++ runtime functions we're missing. I understand they were hoping to upstream this to LLVM, and then WASI-SDK would be able to pull this down. - I'm not sure of the current state of this work, @sunfishcode and @aheejin and, I think the best folks to be able to help on that front.
That is a great explanation, thank you.
The library code has been already upstreamed, as I commented in https://github.com/WebAssembly/wasi-sdk/issues/334#issuecomment-1730976179. But given that Emscripten uses our custom build system and not the LLVM's CMake build system, how it works well with the native LLVM has not been well tested and you might need some adjustment on the build files. I'm not familiar with what build system WASI uses (Is that the LLVM's or something separate?), but that will require changes as well. For example, from libunwind we only use Unwind-wasm.c
and nothing else: https://github.com/emscripten-core/emscripten/blob/4aefde3f78e0d3d6327105b123c99dbe3283f779/tools/system_libs.py#L1635
Indeed, llvm already uses wasm exception to implement SJLJ, when wasm exceptions are enabled, so it should just work once we enable exceptions.
do you mean to use saveSetjmp getTempRet0 etc for WASI as well?
Indeed, llvm already uses wasm exception to implement SJLJ, when wasm exceptions are enabled, so it should just work once we enable exceptions.
do you mean to use saveSetjmp getTempRet0 etc for WASI as well?
Right, and this seems to have been moved to compiler-rt in Emscripten: https://github.com/emscripten-core/emscripten/blob/main/system/lib/compiler-rt/emscripten_setjmp.c
Even though the file name says 'emscripten', some of the functions in there are also used by Wasm SjLj handling (which is, SjLj handling using the instructions in the Wasm EH proposal) That file was newly added in Emscripten and didn't come from the compiler-rt in LLVM.
I understand this is getting confusing somewhat, which I think stemmed from that Emscipten uses its custom build system.. I guess we should consider making LLVM's CMake system to reflect the Emscripten setup. In the meantime, this is the list of library files created/modified for Wasm EH in Emscripten:
compiler-rt: https://github.com/emscripten-core/emscripten/blob/main/system/lib/compiler-rt/emscripten_setjmp.c (created)
libc++abi: https://github.com/llvm/llvm-project/blob/main/libcxxabi/src/cxa_personality.cpp (modified) https://github.com/llvm/llvm-project/blob/main/libcxxabi/src/cxa_exception.cpp (modified) https://github.com/llvm/llvm-project/blob/main/libcxxabi/src/cxa_exception.h (modified)
libunwind: https://github.com/llvm/llvm-project/blob/main/libunwind/src/Unwind-wasm.c (created)
Indeed, llvm already uses wasm exception to implement SJLJ, when wasm exceptions are enabled, so it should just work once we enable exceptions.
do you mean to use saveSetjmp getTempRet0 etc for WASI as well?
Right, and this seems to have been moved to compiler-rt in Emscripten: https://github.com/emscripten-core/emscripten/blob/main/system/lib/compiler-rt/emscripten_setjmp.c
Even though the file name says 'emscripten', some of the functions in there are also used by Wasm SjLj handling (which is, SjLj handling using the instructions in the Wasm EH proposal) That file was newly added in Emscripten and didn't come from the compiler-rt in LLVM.
I understand this is getting confusing somewhat, which I think stemmed from that Emscipten uses its custom build system.. I guess we should consider making LLVM's CMake system to reflect the Emscripten setup. In the meantime, this is the list of library files created/modified for Wasm EH in Emscripten:
compiler-rt: https://github.com/emscripten-core/emscripten/blob/main/system/lib/compiler-rt/emscripten_setjmp.c (created)
libc++abi: https://github.com/llvm/llvm-project/blob/main/libcxxabi/src/cxa_personality.cpp (modified) https://github.com/llvm/llvm-project/blob/main/libcxxabi/src/cxa_exception.cpp (modified) https://github.com/llvm/llvm-project/blob/main/libcxxabi/src/cxa_exception.h (modified)
libunwind: https://github.com/emscripten-core/emscripten/blob/main/system/lib/libunwind/src/Unwind-wasm.c (created)
thank you. i did an experiment to use sjlj with wasi. it seems working well. https://github.com/yamt/garbage/tree/master/wasm/longjmp (i wrote the runtime (rt.c) by myself because i didn't know where emscripten version was.)
https://github.com/WebAssembly/wasi-libc/pull/467