-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of #113247 - mirkootter:test-wasm-exceptions-nostd, r=Ma…
…rk-Simulacrum Add Tests for native wasm exceptions ### Motivation In PR #111322, I added support for native WASM exceptions. I was asked by ``@davidtwco`` to add some tests for it in a follow up PR, which seems like a very good idea. This PR adds three tests for this feature: * codegen: ensure the correct LLVM instructions are used * assembly: ensure the correct WASM instructions are used * run-make: ensure the exception handling works; the WASM code is run using a small nodejs script which demonstrates the exception handling ### Complications There are a few changes beside adding the tests, which were necessary * Tests for the wasm32-unknown-unknown target are (as far as I know) only run on `test-various`. Its docker image uses nodejs-15, which is very old. Experimental support for wasm-exceptions was added in nodejs16. In nodejs 18.12 (LTS), they are stable. - --> increase nodejs to 18.12 in `test-various` * codegen/assembly tests are not performed for the wasm32-unknown-unknown target yet - --> add those to `test-various` as well Due to the last point, some tests are run which have not run before (assembly+codegen tests for wasm32-unknown-unknown). I added `// ignore wasm32-bare` for those which failed ### Local testing I run all tests locally using both `test-various` and `wasm32`. As far as I know, none of the other systems run any test for wasm32 targets.
- Loading branch information
Showing
11 changed files
with
369 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// only-wasm32-bare | ||
// assembly-output: emit-asm | ||
// compile-flags: -C target-feature=+exception-handling | ||
// compile-flags: -C panic=unwind | ||
// compile-flags: -C llvm-args=-wasm-enable-eh | ||
|
||
#![crate_type = "lib"] | ||
#![feature(core_intrinsics)] | ||
#![feature(rustc_attrs)] | ||
|
||
extern { | ||
fn may_panic(); | ||
|
||
#[rustc_nounwind] | ||
fn log_number(number: usize); | ||
} | ||
|
||
struct LogOnDrop; | ||
|
||
impl Drop for LogOnDrop { | ||
fn drop(&mut self) { | ||
unsafe { log_number(0); } | ||
} | ||
} | ||
|
||
// CHECK-LABEL: test_cleanup: | ||
#[no_mangle] | ||
pub fn test_cleanup() { | ||
let _log_on_drop = LogOnDrop; | ||
unsafe { may_panic(); } | ||
|
||
// CHECK-NOT: call | ||
// CHECK: try | ||
// CHECK: call may_panic | ||
// CHECK: catch_all | ||
// CHECK: rethrow | ||
// CHECK: end_try | ||
} | ||
|
||
// CHECK-LABEL: test_rtry: | ||
#[no_mangle] | ||
pub fn test_rtry() { | ||
unsafe { | ||
core::intrinsics::r#try(|_| { | ||
may_panic(); | ||
}, core::ptr::null_mut(), |data, exception| { | ||
log_number(data as usize); | ||
log_number(exception as usize); | ||
}); | ||
} | ||
|
||
// CHECK-NOT: call | ||
// CHECK: try | ||
// CHECK: call may_panic | ||
// CHECK: catch | ||
// CHECK: call log_number | ||
// CHECK: call log_number | ||
// CHECK-NOT: rethrow | ||
// CHECK: end_try | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// only-wasm32-bare | ||
// compile-flags: -C panic=unwind | ||
|
||
#![crate_type = "lib"] | ||
#![feature(core_intrinsics)] | ||
#![feature(rustc_attrs)] | ||
|
||
extern { | ||
fn may_panic(); | ||
|
||
#[rustc_nounwind] | ||
fn log_number(number: usize); | ||
} | ||
|
||
struct LogOnDrop; | ||
|
||
impl Drop for LogOnDrop { | ||
fn drop(&mut self) { | ||
unsafe { log_number(0); } | ||
} | ||
} | ||
|
||
// CHECK-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0 | ||
#[no_mangle] | ||
pub fn test_cleanup() { | ||
let _log_on_drop = LogOnDrop; | ||
unsafe { may_panic(); } | ||
|
||
// CHECK-NOT: call | ||
// CHECK: invoke void @may_panic() | ||
// CHECK: %cleanuppad = cleanuppad within none [] | ||
} | ||
|
||
// CHECK-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0 | ||
#[no_mangle] | ||
pub fn test_rtry() { | ||
unsafe { | ||
core::intrinsics::r#try(|_| { | ||
may_panic(); | ||
}, core::ptr::null_mut(), |data, exception| { | ||
log_number(data as usize); | ||
log_number(exception as usize); | ||
}); | ||
} | ||
|
||
// CHECK-NOT: call | ||
// CHECK: invoke void @may_panic() | ||
// CHECK: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller | ||
// CHECK: {{.*}} = catchpad within {{.*}} [ptr null] | ||
// CHECK: catchret | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
include ../tools.mk | ||
|
||
# only-wasm32-bare | ||
|
||
# Add a few command line args to make exceptions work | ||
RUSTC := $(RUSTC) -C llvm-args=-wasm-enable-eh | ||
RUSTC := $(RUSTC) -C target-feature=+exception-handling | ||
RUSTC := $(RUSTC) -C panic=unwind | ||
|
||
all: | ||
$(RUSTC) src/lib.rs --target wasm32-unknown-unknown | ||
$(NODE) verify.mjs $(TMPDIR)/lib.wasm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
use core::alloc::{GlobalAlloc, Layout}; | ||
use core::cell::UnsafeCell; | ||
|
||
#[global_allocator] | ||
static ALLOCATOR: ArenaAllocator = ArenaAllocator::new(); | ||
|
||
/// Very simple allocator which never deallocates memory | ||
/// | ||
/// Based on the example from | ||
/// https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html | ||
pub struct ArenaAllocator { | ||
arena: UnsafeCell<Arena>, | ||
} | ||
|
||
impl ArenaAllocator { | ||
pub const fn new() -> Self { | ||
Self { | ||
arena: UnsafeCell::new(Arena::new()), | ||
} | ||
} | ||
} | ||
|
||
/// Safe because we are singlethreaded | ||
unsafe impl Sync for ArenaAllocator {} | ||
|
||
unsafe impl GlobalAlloc for ArenaAllocator { | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
let arena = &mut *self.arena.get(); | ||
arena.alloc(layout) | ||
} | ||
|
||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} | ||
} | ||
|
||
const ARENA_SIZE: usize = 64 * 1024; // more than enough | ||
|
||
#[repr(C, align(4096))] | ||
struct Arena { | ||
buf: [u8; ARENA_SIZE], // aligned at 4096 | ||
allocated: usize, | ||
} | ||
|
||
impl Arena { | ||
pub const fn new() -> Self { | ||
Self { | ||
buf: [0x55; ARENA_SIZE], | ||
allocated: 0, | ||
} | ||
} | ||
|
||
pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 { | ||
if layout.align() > 4096 || layout.size() > ARENA_SIZE { | ||
return core::ptr::null_mut(); | ||
} | ||
|
||
let align_minus_one = layout.align() - 1; | ||
let start = (self.allocated + align_minus_one) & !align_minus_one; // round up | ||
let new_cursor = start + layout.size(); | ||
|
||
if new_cursor >= ARENA_SIZE { | ||
return core::ptr::null_mut(); | ||
} | ||
|
||
self.allocated = new_cursor; | ||
self.buf.as_mut_ptr().add(start) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#![no_std] | ||
#![crate_type = "cdylib"] | ||
|
||
// Allow a few unstable features because we create a panic | ||
// runtime for native wasm exceptions from scratch | ||
|
||
#![feature(core_intrinsics)] | ||
#![feature(lang_items)] | ||
#![feature(link_llvm_intrinsics)] | ||
#![feature(panic_info_message)] | ||
|
||
extern crate alloc; | ||
|
||
/// This module allows us to use `Box`, `String`, ... even in no-std | ||
mod arena_alloc; | ||
|
||
/// This module allows logging text, even in no-std | ||
mod logging; | ||
|
||
/// This module allows exceptions, even in no-std | ||
#[cfg(target_arch = "wasm32")] | ||
mod panicking; | ||
|
||
use alloc::boxed::Box; | ||
use alloc::string::String; | ||
|
||
struct LogOnDrop; | ||
|
||
impl Drop for LogOnDrop { | ||
fn drop(&mut self) { | ||
logging::log_str("Dropped"); | ||
} | ||
} | ||
|
||
#[allow(unreachable_code)] | ||
#[allow(unconditional_panic)] | ||
#[no_mangle] | ||
pub extern "C" fn start() -> usize { | ||
let data = 0x1234usize as *mut u8; // Something to recognize | ||
|
||
unsafe { | ||
core::intrinsics::r#try(|data: *mut u8| { | ||
let _log_on_drop = LogOnDrop; | ||
|
||
logging::log_str(&alloc::format!("`r#try` called with ptr {:?}", data)); | ||
let x = [12]; | ||
let _ = x[4]; // should panic | ||
|
||
logging::log_str("This line should not be visible! :("); | ||
}, data, |data, exception| { | ||
let exception = *Box::from_raw(exception as *mut String); | ||
logging::log_str("Caught something!"); | ||
logging::log_str(&alloc::format!(" data : {:?}", data)); | ||
logging::log_str(&alloc::format!(" exception: {:?}", exception)); | ||
}); | ||
} | ||
|
||
logging::log_str("This program terminates correctly."); | ||
0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
extern "C" { | ||
fn __log_utf8(ptr: *const u8, size: usize); | ||
} | ||
|
||
pub fn log_str(text: &str) { | ||
unsafe { | ||
__log_utf8(text.as_ptr(), text.len()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#[lang = "eh_personality"] | ||
fn eh_personality() {} | ||
|
||
mod internal { | ||
extern "C" { | ||
#[link_name = "llvm.wasm.throw"] | ||
pub fn wasm_throw(tag: i32, ptr: *mut u8) -> !; | ||
} | ||
} | ||
|
||
unsafe fn wasm_throw(ptr: *mut u8) -> ! { | ||
internal::wasm_throw(0, ptr); | ||
} | ||
|
||
#[panic_handler] | ||
fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { | ||
use alloc::boxed::Box; | ||
use alloc::string::ToString; | ||
|
||
let msg = info | ||
.message() | ||
.map(|msg| msg.to_string()) | ||
.unwrap_or("(no message)".to_string()); | ||
let exception = Box::new(msg.to_string()); | ||
unsafe { | ||
let exception_raw = Box::into_raw(exception); | ||
wasm_throw(exception_raw as *mut u8); | ||
} | ||
} |
Oops, something went wrong.