pub struct Heap { /* private fields */ }Expand description
the VM heap: a slab of [HeapSlot]s plus a free list of reusable indices.
alloc reuses a freed slot when one is available, else appends. each slot
is reference-counted; a slot whose count hits zero is pushed onto free.
every accessor takes a slot index and returns an Option – a bad index is
never an out-of-bounds panic.
reference cycles are NOT collected: two objects that point at each other keep each other’s refcount above zero forever. this is a documented v1 limitation – a cycle collector is a v2 concern, and Qala v1’s value semantics (no mutable cross-object references) make cycles hard to create.
Implementations§
Source§impl Heap
impl Heap
Sourcepub fn alloc(&mut self, obj: HeapObject) -> Option<u32>
pub fn alloc(&mut self, obj: HeapObject) -> Option<u32>
allocate obj into a slot and return the slot index. a freed slot is
reused if one is available, else the slab grows by one. the new slot’s
refcount starts at 1.
returns None when the slab is already at [MAX_HEAP] slots and no
free slot can be reused – the caller maps None to a Runtime “heap
exhausted” error so a runaway allocation never aborts the host. None
rather than Result<u32, ()> keeps the signature lint-clean (a unit
error type carries no information None does not).
Sourcepub fn get(&self, slot: u32) -> Option<&HeapObject>
pub fn get(&self, slot: u32) -> Option<&HeapObject>
borrow the object at slot. returns None for an out-of-range or
freed slot (a freed slot has refcount 0) – never an out-of-bounds
index.
Sourcepub fn get_mut(&mut self, slot: u32) -> Option<&mut HeapObject>
pub fn get_mut(&mut self, slot: u32) -> Option<&mut HeapObject>
mutably borrow the object at slot. returns None for an out-of-range
or freed slot – never an out-of-bounds index.
Sourcepub fn inc(&mut self, slot: u32)
pub fn inc(&mut self, slot: u32)
increment the refcount of the object at slot. a bad or freed slot is
a silent no-op – the VM never crashes on a stray inc.
v1 aliasing invariant: v1 does NOT alias heap values. every heap
object has exactly one logical owner; values are moved (or copied as
tagged scalars) rather than duplicated with shared ownership. as a
consequence, inc is currently unused – the opcode handlers that
could in principle produce a second reference to the same slot
(DUP of a pointer, GET_LOCAL, GET_GLOBAL, MAKE_ARRAY,
MAKE_TUPLE, MAKE_STRUCT, MAKE_ENUM_VARIANT) do not call inc
today. before any v2 work allows genuine aliasing, every one of those
sites must be audited and wired to inc first, or use-after-free
becomes possible. the #[allow(dead_code)] keeps this function present
as the documented extension point without triggering a compiler warning.
Sourcepub fn dec(&mut self, slot: u32) -> Option<HeapObject>
pub fn dec(&mut self, slot: u32) -> Option<HeapObject>
decrement the refcount of the object at slot.
when the count reaches zero the slot is freed: its index is pushed onto
the free list and the freed HeapObject is RETURNED so the caller can
inspect it. when the count is still positive after the decrement – or
the slot is out of range or already free – the result is None.
the return value is load-bearing: the file-handle leak check in
Vm::check_frame_handle_leaks needs dec to hand back the freed
object so the Vm can detect a still-open HeapObject::FileHandle
and push to Vm::leak_log. the leak-log push is the caller’s
responsibility – Heap has no access to Vm::leak_log; dec only
surfaces the freed object. this signature is the locked contract.