Files
wasmtime/crates/runtime/src/traphandlers/windows.rs
Alex Crichton c8f55ed688 Optimize codegen slightly calling wasm functions
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.
2021-09-02 07:26:03 -07:00

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(())
}