Currently wasm-calls work with `Result<T, Trap>` internally but `Trap` is an enum defined in `wasmtime-runtime` which is actually quite large. Since traps are supposed to be rare this commit changes these functions to return a `Box<Trap>` which is un-boxed later up in the `wasmtime` crate within a `#[cold]` function.
81 lines
3.0 KiB
Rust
81 lines
3.0 KiB
Rust
use crate::traphandlers::{tls, wasmtime_longjmp, Trap};
|
|
use std::io;
|
|
use winapi::um::errhandlingapi::*;
|
|
use winapi::um::minwinbase::*;
|
|
use winapi::um::winnt::*;
|
|
use winapi::vc::excpt::*;
|
|
|
|
/// Function which may handle custom signals while processing traps.
|
|
pub type SignalHandler<'a> =
|
|
dyn Fn(winapi::um::winnt::PEXCEPTION_POINTERS) -> bool + Send + Sync + 'a;
|
|
|
|
pub unsafe fn platform_init() {
|
|
// our trap handler needs to go first, so that we can recover from
|
|
// wasm faults and continue execution, so pass `1` as a true value
|
|
// here.
|
|
if AddVectoredExceptionHandler(1, Some(exception_handler)).is_null() {
|
|
panic!(
|
|
"failed to add exception handler: {}",
|
|
io::Error::last_os_error()
|
|
);
|
|
}
|
|
}
|
|
|
|
unsafe extern "system" fn exception_handler(exception_info: PEXCEPTION_POINTERS) -> LONG {
|
|
// Check the kind of exception, since we only handle a subset within
|
|
// wasm code. If anything else happens we want to defer to whatever
|
|
// the rest of the system wants to do for this exception.
|
|
let record = &*(*exception_info).ExceptionRecord;
|
|
if record.ExceptionCode != EXCEPTION_ACCESS_VIOLATION
|
|
&& record.ExceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION
|
|
&& record.ExceptionCode != EXCEPTION_INT_DIVIDE_BY_ZERO
|
|
&& record.ExceptionCode != EXCEPTION_INT_OVERFLOW
|
|
{
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
// FIXME: this is what the previous C++ did to make sure that TLS
|
|
// works by the time we execute this trap handling code. This isn't
|
|
// exactly super easy to call from Rust though and it's not clear we
|
|
// necessarily need to do so. Leaving this here in case we need this
|
|
// in the future, but for now we can probably wait until we see a
|
|
// strange fault before figuring out how to reimplement this in
|
|
// Rust.
|
|
//
|
|
// if (!NtCurrentTeb()->Reserved1[sThreadLocalArrayPointerIndex]) {
|
|
// return EXCEPTION_CONTINUE_SEARCH;
|
|
// }
|
|
|
|
// This is basically the same as the unix version above, only with a
|
|
// few parameters tweaked here and there.
|
|
tls::with(|info| {
|
|
let info = match info {
|
|
Some(info) => info,
|
|
None => return EXCEPTION_CONTINUE_SEARCH,
|
|
};
|
|
cfg_if::cfg_if! {
|
|
if #[cfg(target_arch = "x86_64")] {
|
|
let ip = (*(*exception_info).ContextRecord).Rip as *const u8;
|
|
} else if #[cfg(target_arch = "x86")] {
|
|
let ip = (*(*exception_info).ContextRecord).Eip as *const u8;
|
|
} else {
|
|
compile_error!("unsupported platform");
|
|
}
|
|
}
|
|
let jmp_buf = info.jmp_buf_if_trap(ip, |handler| handler(exception_info));
|
|
if jmp_buf.is_null() {
|
|
EXCEPTION_CONTINUE_SEARCH
|
|
} else if jmp_buf as usize == 1 {
|
|
EXCEPTION_CONTINUE_EXECUTION
|
|
} else {
|
|
info.capture_backtrace(ip);
|
|
wasmtime_longjmp(jmp_buf)
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn lazy_per_thread_init() -> Result<(), Box<Trap>> {
|
|
// Unused on Windows
|
|
Ok(())
|
|
}
|