Skip to content

Commit 3deaacf

Browse files
committed
Use inline asm rather than llvm intrinsic for panics on wasm
This way we don't have to support unwinding llvm intrinsics in the codegen backends.
1 parent 683dd08 commit 3deaacf

File tree

3 files changed

+19
-35
lines changed

3 files changed

+19
-35
lines changed

library/unwind/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
88
#![cfg_attr(
99
all(target_family = "wasm", any(not(target_os = "emscripten"), emscripten_wasm_eh)),
10-
feature(link_llvm_intrinsics, simd_wasm64)
10+
feature(asm_experimental_arch, asm_unwind, simd_wasm64)
1111
)]
1212
#![allow(internal_features)]
1313
#![deny(unsafe_op_in_unsafe_fn)]

library/unwind/src/wasm.rs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,33 +47,17 @@ pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwi
4747
// enabled exceptions via `-Z build-std` with `-C panic=unwind`.
4848
cfg_select! {
4949
panic = "unwind" => {
50-
// It's important that this intrinsic is defined here rather than in `core`. Since it
51-
// unwinds, invoking it from Rust code compiled with `-C panic=unwind` immediately
52-
// forces `panic_unwind` as the required panic runtime.
53-
//
54-
// We ship unwinding `core` on Emscripten, so making this intrinsic part of `core` would
55-
// prevent linking precompiled `core` into `-C panic=abort` binaries. Unlike `core`,
56-
// this particular module is never precompiled with `-C panic=unwind` because it's only
57-
// used for bare-metal targets, so an error can only arise if the user both manually
58-
// recompiles `std` with `-C panic=unwind` and manually compiles the binary crate with
59-
// `-C panic=abort`, which we don't care to support.
60-
//
61-
// See https://github.com/rust-lang/rust/issues/148246.
62-
unsafe extern "C-unwind" {
63-
/// LLVM lowers this intrinsic to the `throw` instruction.
64-
#[link_name = "llvm.wasm.throw"]
65-
fn wasm_throw(tag: i32, ptr: *mut u8) -> !;
66-
}
67-
68-
// The wasm `throw` instruction takes a "tag", which differentiates certain types of
69-
// exceptions from others. LLVM currently just identifies these via integers, with 0
70-
// corresponding to C++ exceptions and 1 to C setjmp()/longjmp(). Ideally, we'd be able
71-
// to choose something unique for Rust, but for now, we pretend to be C++ and implement
72-
// the Itanium exception-handling ABI.
73-
// corresponds with llvm::WebAssembly::Tag::CPP_EXCEPTION
74-
// in llvm-project/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h
75-
const CPP_EXCEPTION_TAG: i32 = 0;
76-
wasm_throw(CPP_EXCEPTION_TAG, exception.cast())
50+
// LLVM currently only runs cleanup code for exception using the C++ exception tag and
51+
// not those for any other exception tag like the longjmp exception tag. Ideally, we'd
52+
// be able to choose something unique for Rust, but for now, we pretend to be C++ and
53+
// implement the Itanium exception-handling ABI.
54+
// This is using inline asm rather than the llvm.wasm.throw llvm intrinsic as supporting
55+
// unwinding for llvm intrinsics complicates things in the backend.
56+
core::arch::asm!("
57+
.tagtype __cpp_exception i32
58+
local.get {exc}
59+
throw __cpp_exception
60+
", exc = in(local) core::ptr::null_mut::<()>(), options(may_unwind, noreturn, nostack));
7761
}
7862
_ => {
7963
let _ = exception;

tests/codegen-llvm/wasm_exceptions.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//@ [WASMEXN] compile-flags: -C panic=unwind -Z emscripten-wasm-eh
44

55
#![crate_type = "lib"]
6-
#![feature(core_intrinsics, link_llvm_intrinsics)]
6+
#![feature(asm_experimental_arch, asm_unwind, core_intrinsics)]
77

88
extern "C-unwind" {
99
fn may_panic();
@@ -82,15 +82,15 @@ pub fn test_rtry() {
8282
pub fn test_intrinsic() {
8383
let _log_on_drop = LogOnDrop;
8484

85-
unsafe extern "C-unwind" {
86-
#[link_name = "llvm.wasm.throw"]
87-
fn wasm_throw(tag: i32, ptr: *mut u8) -> !;
88-
}
8985
unsafe {
90-
wasm_throw(0, core::ptr::null_mut());
86+
std::arch::asm!("
87+
.tagtype __cpp_exception i32
88+
local.get {exc}
89+
throw __cpp_exception
90+
", exc = in(local) core::ptr::null_mut::<()>(), options(may_unwind, noreturn, nostack));
9191
}
9292

9393
// WASMEXN-NOT: call
94-
// WASMEXN: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null)
94+
// WASMEXN: invoke void asm sideeffect unwind
9595
// WASMEXN: %cleanuppad = cleanuppad within none []
9696
}

0 commit comments

Comments
 (0)