diff options
| author | Noa <coolreader18@gmail.com> | 2024-02-21 17:32:58 -0600 |
|---|---|---|
| committer | Noa <coolreader18@gmail.com> | 2024-02-22 16:45:26 -0600 |
| commit | 3908a935ef821c2828a7d825eac859f8ff54702a (patch) | |
| tree | dd62444f5a135976635b66ee483fe4bae0a79101 /library/panic_unwind/src | |
| parent | f8131a48a46ac3bc8a3d0fe0477055b132cffdc3 (diff) | |
| download | rust-3908a935ef821c2828a7d825eac859f8ff54702a.tar.gz rust-3908a935ef821c2828a7d825eac859f8ff54702a.zip | |
std support for wasm32 panic=unwind
Diffstat (limited to 'library/panic_unwind/src')
| -rw-r--r-- | library/panic_unwind/src/lib.rs | 13 | ||||
| -rw-r--r-- | library/panic_unwind/src/wasm.rs | 32 |
2 files changed, 44 insertions, 1 deletions
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 7a0bae34642..bc3c9363d8a 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -16,6 +16,10 @@ #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![feature(core_intrinsics)] #![feature(lang_items)] +#![cfg_attr( + all(target_family = "wasm", not(target_os = "emscripten")), + feature(link_llvm_intrinsics) +)] #![feature(panic_unwind)] #![feature(staged_api)] #![feature(std_internals)] @@ -56,9 +60,16 @@ cfg_if::cfg_if! { ))] { #[path = "gcc.rs"] mod real_imp; + } else if #[cfg(all(target_family = "wasm", panic = "unwind"))] { + // for now, PanicStrategy::Unwind is not the default for wasm targets, + // so we need the panic = "unwind" in the cfg above. to use llvm.wasm.throw, + // we need to pass -wasm-enable-eh to LLVM, but that only happens if rustc + // is compiling with -C panic=unwind. So, this lets us -Zbuild-std with + // panic=unwind, while keeping the default panic=abort working. + #[path = "wasm.rs"] + mod real_imp; } else { // Targets that don't support unwinding. - // - family=wasm // - os=none ("bare metal" targets) // - os=uefi // - os=espidf diff --git a/library/panic_unwind/src/wasm.rs b/library/panic_unwind/src/wasm.rs new file mode 100644 index 00000000000..b11fb912b63 --- /dev/null +++ b/library/panic_unwind/src/wasm.rs @@ -0,0 +1,32 @@ +//! Unwinding panics for wasm32. +use alloc::boxed::Box; +use core::any::Any; + +// The type of the exception payload that the wasm engine propagates +// through unwinding for us. LLVM requires that it be a thin pointer. +type Payload = Box<Box<dyn Any + Send>>; + +extern "C" { + /// LLVM lowers this intrinsic to the `throw` instruction. + #[link_name = "llvm.wasm.throw"] + fn wasm_throw(tag: i32, ptr: *mut u8) -> !; +} + +pub unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 { + // The payload we pass to `wasm_throw` will be exactly the argument we get + // in `cleanup` below. So we just box it up once, to get something pointer-sized. + let payload_box: Payload = Box::new(payload); + // The wasm `throw` instruction takes a "tag", which differentiates certain + // types of exceptions from others. LLVM currently just identifies these + // via integers, with 0 corresponding to C++ exceptions and 1 to C setjmp()/longjmp(). + // Ideally, we'd be able to choose something unique for Rust, such that we + // don't try to treat a C++ exception payload as a `Box<Box<dyn Any>>`, but + // otherwise, pretending to be C++ works for now. + wasm_throw(0, Box::into_raw(payload_box) as *mut u8) +} + +pub unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> { + // Recover the underlying `Box`. + let payload_box: Payload = Box::from_raw(payload_box as *mut _); + *payload_box +} |
