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>
impl<T: Copy> SlotStack<T>
Sourcepub fn new(capacity: usize, zero: T) -> Self
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.
Sourcepub fn header_ptr(&mut self) -> *mut SlotStackHeader<T>
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.
Sourcepub fn header(&self) -> &SlotStackHeader<T>
pub fn header(&self) -> &SlotStackHeader<T>
Borrow the header — the collector’s door, and the tests’.