use super::trap::UnwindReason;
use crate::Trap;
use std::{
any::Any, cell::Cell, convert::Infallible, error::Error, marker::PhantomData, sync::Mutex,
};
pub enum TrapHandlerFn<'a> {
#[doc(hidden)]
_Uninhabited(Infallible, PhantomData<&'a ()>),
}
pub struct VMConfig {
pub wasm_stack_size: Option<usize>,
}
pub const MAX_STACK_SIZE: usize = 0;
pub fn drain_stack_pool() {}
pub fn set_stack_size(_size: usize) {
panic!("set_stack_size is not supported in baremetal mode");
}
pub fn get_stack_size() -> usize {
panic!("get_stack_size is not supported in baremetal mode");
}
pub fn init_traps() {}
pub fn on_host_stack<F: FnOnce() -> T, T>(f: F) -> T {
f()
}
pub unsafe fn catch_traps<F, R: 'static>(
_trap_handler: Option<*const TrapHandlerFn<'static>>,
_config: &VMConfig,
closure: F,
) -> Result<R, Trap>
where
F: FnOnce() -> R + 'static,
{
Ok(closure())
}
static UNWINDER: Mutex<Option<Box<dyn Fn(UnwindReason) + Send>>> = Mutex::new(None);
pub fn install_unwinder(unwinder: Option<Box<dyn Fn(UnwindReason) + Send>>) {
*UNWINDER
.lock()
.expect("baremetal unwinder mutex poisoned in install_unwinder") = unwinder;
}
thread_local! {
static UNWINDING: Cell<bool> = const { Cell::new(false) };
}
struct UnwindingGuard;
impl UnwindingGuard {
fn acquire() -> Option<Self> {
UNWINDING.with(|u| {
if u.replace(true) {
None
} else {
Some(UnwindingGuard)
}
})
}
}
impl Drop for UnwindingGuard {
fn drop(&mut self) {
UNWINDING.with(|u| u.set(false));
}
}
fn unwind_with(reason: UnwindReason) -> ! {
let Some(_guard) = UnwindingGuard::acquire() else {
panic!("wasm trap raised inside the baremetal unwinder (re-entrant unwinding): {reason:?}");
};
let f = UNWINDER
.lock()
.expect("baremetal unwinder mutex poisoned in unwind_with")
.take();
match f {
Some(f) => {
let display = format!("{reason:?}");
f(reason);
unreachable!("baremetal unwinder must not return (trap was: {display})");
}
None => panic!("wasm trap with no baremetal unwinder installed: {reason:?}"),
}
}
pub unsafe fn raise_lib_trap(trap: Trap) -> ! {
unwind_with(UnwindReason::LibTrap(trap))
}
pub unsafe fn raise_user_trap(data: Box<dyn Error + Send + Sync>) -> ! {
unwind_with(UnwindReason::UserTrap(data))
}
pub unsafe fn resume_panic(payload: Box<dyn Any + Send>) -> ! {
unwind_with(UnwindReason::Panic(payload))
}