Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for WASM Exceptions #334

Open
woodsmc opened this issue Jul 6, 2023 · 21 comments
Open

Add Support for WASM Exceptions #334

woodsmc opened this issue Jul 6, 2023 · 21 comments

Comments

@woodsmc
Copy link

woodsmc commented Jul 6, 2023

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)

@sunfishcode
Copy link
Member

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.

@woodsmc
Copy link
Author

woodsmc commented Jul 7, 2023

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.

@sbc100
Copy link
Member

sbc100 commented Jul 7, 2023

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: llvm/llvm-project@llvmorg-16.0.4...emscripten-core:emscripten-libs-16

@woodsmc
Copy link
Author

woodsmc commented Jul 7, 2023

Whooha... Rockstar's both of you, and I've got some reading to do. Thanks for the pointers. Let me take a look.

@abrown
Copy link
Collaborator

abrown commented Jul 25, 2023

There's also a draft PR with initial support for this in #198, which you may be interested in.

@aheejin
Copy link
Member

aheejin commented Aug 3, 2023

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 (WebAssembly/exception-handling#280) which can change the spec itself. I don't think the library side will change much with this though.

@aheejin
Copy link
Member

aheejin commented Sep 22, 2023

Thank you for the wait. Wasm EH's libcxxabi/libunwind changes have now been upstreamed:
llvm/llvm-project@e6cbba7
llvm/llvm-project@058222b

@sroussey
Copy link

sroussey commented Jan 6, 2024

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

@anuraaga
Copy link
Contributor

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?

@whitequark
Copy link
Contributor

I think you should be able to lower SjLj to exceptions.

@sbc100
Copy link
Member

sbc100 commented Jan 22, 2024

Indeed, llvm already uses wasm exception to implement SJLJ, when wasm exceptions are enabled, so it should just work once we enable exceptions.

@sunfishcode
Copy link
Member

Indeed, wasm exceptions is how we've always envisioned setjmp/longjmp would work.

@anuraaga
Copy link
Contributor

Thanks for confirming! I implemented stack unwind for wazero

tetratelabs/wazero#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)

@cpetig
Copy link

cpetig commented Jan 23, 2024

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

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.

@woodsmc
Copy link
Author

woodsmc commented Jan 25, 2024

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.

@sroussey
Copy link

That is a great explanation, thank you.

@aheejin
Copy link
Member

aheejin commented Jan 30, 2024

The library code has been already upstreamed, as I commented in #334 (comment). 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

@yamt
Copy link
Contributor

yamt commented Jan 30, 2024

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?

@aheejin
Copy link
Member

aheejin commented Jan 30, 2024

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)

@yamt
Copy link
Contributor

yamt commented Jan 31, 2024

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.)

@yamt
Copy link
Contributor

yamt commented Jan 31, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants