Expand description
Mark-and-sweep garbage collector.
This module is the production GC for the Lua runtime — a single-threaded
precise tracing collector with incremental and generational paths plus
forward/backward write barriers. GcRef<T> (in lua-types) is a type
alias for this crate’s Gc<T>; an earlier revision backed GcRef<T>
with a plain Rc<T> instead.
§Vocabulary
- Gc
: a pointer-sized handle. Copy + Clone. ReplacesGcRef<T>. - GcBox
: the heap allocation; contains a header and the value. - GcHeader: per-object metadata (color, age, finalized flag, and an
intrusive
nextpointer for exactly one heap owner list). The grayagain revisit set is heap-owned (Heap::grayagain), not an intrusive link. - Trace: trait every GC-rooted type implements. The
tracemethod walks allGc<_>fields and callsMarker::markon each. - Marker: passed to
trace; carries the gray queue. - Heap: owns the allgc/finobj/tobefnz list heads, byte counters, and GC state machine.
§Safety model
All unsafe is confined to this crate (per harness/unsafe-budgets.toml).
The invariants are:
- Every
Gc<T>points to a valid, allocated, not-yet-sweptGcBox<T>. - The intrusive heap lists are consistent: traversing
header.nextfromHeap.head,Heap.finobj, andHeap.tobefnzreaches every live heap-ownedGcBoxexactly once. - After
Heap::full_collect(roots), everyGc<T>reachable fromrootsis still valid; unreachable boxes are dropped and deallocated.
§Allocation paths
GcRef::new(value) (in lua-types) allocates through
state.heap().allocate(value), joining the active heap’s owner lists; a
guard-less call panics rather than silently falling back to an
untracked allocation (issue #249). Gc::new_uncollected remains a
separate, explicit escape hatch for the rare detached/process-lifetime
case — it allocates a GcBox but does not register it in any heap.
Structs§
- AllGc
Cohort Stats - Diagnostic counts for the allgc list split by generational cursors.
- Bootstrap
Scope - RAII handle for a heap bootstrap window; created by
Heap::bootstrap_scope, ends the window on drop. Exists so error paths (?during stdlib install,lua_openfailure) cannot leave the heap stuck in bootstrap mode the way a manualend_bootstrapcall can. - Finalizer
Registry - Finalizer
Registry Stats - Gc
- A GC-managed pointer. Copy + Clone (one-machine-word). Replaces
GcRef<T>. - GcBox
- A heap-allocated, GC-tracked value plus its header.
- GcHeader
- Per-object GC metadata. Lives at the start of every
GcBox. - Heap
- Heap
Guard - A scoped guard for the currently-active heap. Pushed at entry to
state.run()/state.protected_call()/state.load(); popped on drop. Supports nesting (multiple LuaStates on one thread). - HeapRef
- A non-owning heap identity handle for weak references (issue #252):
holds a
Weak<Heap>, so aGcWeakthat outlives its heap answers “does the heap still contain my target” with a plainfalse— after sweep or after heap teardown, indistinguishably — instead of dereferencing freed memory. No unsafe, no outlives contract. - Marker
- Holds the gray queue during a mark phase. Passed to
Trace::trace. - Marker
Stats - Diagnostic counters for the latest mark phase.
- Step
Budget - Work budget for one incremental step.
- Sweep
Stats - Diagnostic counters for the latest sweep phase.
- Weak
Registry - Weak
Registry Snapshot - Weak
Registry Stats
Enums§
- Color
- A traced color in the tri-color invariant.
- GcAge
- Object age used by Lua’s generational collector.
- GcState
- Phases of the incremental collection cycle.
- Step
Outcome - Outcome of one call to
Heap::incremental_step_with_post_mark. - Weak
List Kind
Traits§
- Finalizer
Entry - Minimal metadata a finalizable VM object must expose for collector-owned finalizer-list bookkeeping.
- Trace
- Every GC-rooted type implements
Traceto expose itsGc<_>fields. - Udata51
Probe - A Lua 5.1 collect-time finalizability probe for a single userdata.
- Weak
Entry - Minimal operations needed for collector-owned weak-registry bookkeeping.
Functions§
- detached_
allocations - Total detached (
Gc::new_uncollected) allocations made on this thread since it started. Leak canaries assert a zero delta across embedding scenarios. This counter deliberately lives outside the heap’s own bookkeeping: detached boxes never touchbytes/objects, which is exactly the blind spot that hid issue #249 — a mechanism must not be verified with bookkeeping it maintains itself. - with_
current_ heap - Runs
fwith a reference to the currently-active heap, orNoneif noHeapGuardis in scope.