#![no_std]
#![feature(naked_functions, asm_const)]
#![deny(warnings, missing_docs)]
mod entire;
mod fast;
mod hal;
pub use entire::*;
pub use fast::*;
pub use hal::{load_direct_trap_entry, reuse_stack_for_trap, soft_trap, trap_entry, FlowContext};
use core::{
alloc::Layout,
marker::PhantomPinned,
mem::{align_of, forget, MaybeUninit},
ops::Range,
ptr::NonNull,
};
pub struct FreeTrapStack(NonNull<TrapHandler>);
pub struct LoadedTrapStack(usize);
#[derive(Debug)]
pub struct IllegalStack;
impl FreeTrapStack {
pub fn new(
range: Range<usize>,
drop: fn(Range<usize>),
context_ptr: NonNull<FlowContext>,
fast_handler: FastHandler,
) -> Result<Self, IllegalStack> {
const LAYOUT: Layout = Layout::new::<TrapHandler>();
let bottom = range.start;
let top = range.end;
let ptr = (top - LAYOUT.size()) & !(LAYOUT.align() - 1);
if ptr >= bottom {
let handler = unsafe { &mut *(ptr as *mut TrapHandler) };
handler.range = range;
handler.drop = drop;
handler.context = context_ptr;
handler.fast_handler = fast_handler;
Ok(Self(unsafe { NonNull::new_unchecked(handler) }))
} else {
Err(IllegalStack)
}
}
#[inline]
pub fn load(self) -> LoadedTrapStack {
let scratch = hal::exchange_scratch(self.0.as_ptr() as _);
forget(self);
LoadedTrapStack(scratch)
}
}
impl Drop for FreeTrapStack {
#[inline]
fn drop(&mut self) {
unsafe {
let handler = self.0.as_ref();
(handler.drop)(handler.range.clone());
}
}
}
impl LoadedTrapStack {
#[inline]
pub const fn val(&self) -> usize {
self.0
}
#[inline]
pub fn unload(self) -> FreeTrapStack {
let ans = unsafe { self.unload_unchecked() };
forget(self);
ans
}
#[inline]
unsafe fn unload_unchecked(&self) -> FreeTrapStack {
let ptr = hal::exchange_scratch(self.0) as *mut TrapHandler;
let handler = unsafe { NonNull::new_unchecked(ptr) };
FreeTrapStack(handler)
}
}
impl Drop for LoadedTrapStack {
#[inline]
fn drop(&mut self) {
drop(unsafe { self.unload_unchecked() })
}
}
#[repr(C)]
struct TrapHandler {
context: NonNull<FlowContext>,
fast_handler: FastHandler,
scratch: usize,
range: Range<usize>,
drop: fn(Range<usize>),
pinned: PhantomPinned,
}
impl TrapHandler {
#[inline]
fn locate_fast_mail<T>(&mut self) -> *mut MaybeUninit<T> {
let top = self.range.end as *mut u8;
let offset = top.align_offset(align_of::<T>());
unsafe { &mut *top.add(offset).cast() }
}
}