Skip to main content

SlotStack

Struct SlotStack 

Source
pub struct SlotStack<T: Copy> { /* private fields */ }
Expand description

The owner of one slot reservation and its header.

Two allocations, both made once and never resized. Not a Vec: a Vec that reallocated would invalidate the base pointer generated code holds in a Cranelift Variable for the duration of a call — a use-after-free reachable from any Praxis program deep enough to trigger the growth. A Box<[T]> allocated at its final size cannot move.

The header is separately boxed so Self::header_ptr survives a Runtime move: Runtime::new returns by value, and generated code holds the address this hands out for the whole program.

Generic in T because the mechanism is not specific to GC roots. The same shape serves any per-frame array of Copy slots whose zero value means “nothing here yet” — the crash debugger’s per-frame locals (SlotStack<Option<GcRef>>, whose zero is None by the NonNull niche) being the instantiation this shape was built with in view. The root stack and the debug value stack index different spaces: root slots are colored by live range, debug value slots are dense, one per Gc local (ADR-128).

Implementations§

Source§

impl<T: Copy> SlotStack<T>

Source

pub fn new(capacity: usize, zero: T) -> Self

Reserve capacity slots, all set to zero, and point a header at them.

zero is a parameter rather than a Default bound so the caller names the all-zero value — and because that is what lets this lower to a single alloc_zeroed. vec![zero; n] hits std’s IsZero specialization for raw pointers, so the 5.56 MiB shadow reservation is an mmap of untouched zero pages rather than a memset at every Runtime::new(). An instantiation whose zero std does not recognise as all-zero-bytes still works; it pays that memset.

Source

pub fn header_ptr(&mut self) -> *mut SlotStackHeader<T>

The address generated code bump-allocates against. Stable for the life of this SlotStack, including across moves of whatever owns it.

Source

pub fn header(&self) -> &SlotStackHeader<T>

Borrow the header — the collector’s door, and the tests’.

Source

pub fn reset(&mut self)

Drop every frame. Only correct between runs: a generated epilogue that later restored its saved base would undo this.

Source

pub fn len(&self) -> usize

How many slots are currently claimed.

Source

pub fn is_empty(&self) -> bool

True iff no frame is on the stack.

Source

pub fn capacity(&self) -> usize

The reservation’s capacity in slots.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.