use super::{
super::{abort, intrinsic::intercept},
ThrowByPointer,
};
use core::mem::MaybeUninit;
pub const LITHIUM_EXCEPTION_CLASS: u64 = u64::from_ne_bytes(*b"RUSTIEX\0");
pub(crate) struct ActiveBackend;
unsafe impl ThrowByPointer for ActiveBackend {
type ExceptionHeader = Header;
fn new_header() -> Header {
Header {
class: LITHIUM_EXCEPTION_CLASS,
cleanup: Some(cleanup),
private1: core::ptr::null(),
private_rest: MaybeUninit::uninit(),
}
}
#[inline]
unsafe fn throw(ex: *mut Header) -> ! {
unsafe {
raise(ex.cast());
}
}
#[inline(always)]
fn intercept<Func: FnOnce() -> R, R>(func: Func) -> Result<R, *mut Header> {
let ex = match intercept(func, |ex| ex) {
Ok(value) => return Ok(value),
Err(ex) => ex,
};
#[expect(clippy::cast_ptr_alignment, reason = "See the safety comment above")]
let class = unsafe { *ex.cast::<u64>() };
if class != LITHIUM_EXCEPTION_CLASS {
unsafe {
raise(ex);
}
}
Err(ex.cast())
}
}
#[repr(C, align(16))]
pub struct Header {
class: u64,
cleanup: Option<unsafe extern "C" fn(i32, *mut Header)>,
private1: *const (),
private_rest: MaybeUninit<[*const (); get_unwinder_private_word_count() - 1]>,
}
const fn get_unwinder_private_word_count() -> usize {
if cfg!(target_arch = "x86") {
5
} else if cfg!(any(
all(target_arch = "x86_64"),
all(target_arch = "aarch64", target_pointer_width = "64"),
)) {
if cfg!(windows) {
6
} else {
2
}
} else if cfg!(target_arch = "arm") {
if cfg!(target_vendor = "apple") {
5
} else {
20
}
} else if cfg!(all(target_arch = "aarch64", target_pointer_width = "32")) {
5
} else if cfg!(target_os = "emscripten") {
20
} else if cfg!(all(target_arch = "hexagon", target_os = "linux")) {
35
} else if cfg!(any(
target_arch = "m68k",
target_arch = "mips",
target_arch = "mips32r6",
target_arch = "csky",
target_arch = "mips64",
target_arch = "mips64r6",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "s390x",
target_arch = "sparc",
target_arch = "sparc64",
target_arch = "riscv64",
target_arch = "riscv32",
target_arch = "loongarch64",
target_arch = "wasm32"
)) {
2
} else {
panic!("Unsupported architecture");
}
}
unsafe extern "C" fn cleanup(_code: i32, _ex: *mut Header) {
abort("A Lithium exception was caught by a non-Lithium catch mechanism. This is undefined behavior. The process will now terminate.\n");
}
#[cfg(not(target_arch = "wasm32"))]
unsafe extern "C-unwind" {
fn _Unwind_RaiseException(ex: *mut u8) -> !;
}
#[inline]
unsafe fn raise(ex: *mut u8) -> ! {
#[cfg(not(target_arch = "wasm32"))]
unsafe {
_Unwind_RaiseException(ex);
}
#[cfg(target_arch = "wasm32")]
unsafe {
core::arch::wasm32::throw::<0>(ex);
}
}