Iter 18b: RC runtime + --alloc=rc routing
Wires up reference-counting allocator end-to-end without any inc/dec emission. Programs run under --alloc=rc and produce correct stdout (validated against --alloc=gc); they leak every allocation, exactly like the pre-Boehm era. The point of 18b is to establish the runtime contract before 18c adds the inc/dec-emission codegen pass. runtime/rc.c — new file. 8-byte uint64 refcount header prepended to every payload; ailang_rc_alloc(size) returns a ptr to the payload (header at ptr-8). ailang_rc_inc / dec are declared but never called by codegen yet; they exist so 18c can wire codegen against a stable runtime ABI. dec frees on zero refcount but does NOT recursively dec child references — that's 18c's job once it has per-ctor type info. crates/ailang-codegen/src/lib.rs — AllocStrategy::Rc variant added; fn_name() returns "ailang_rc_alloc". Single-line extension because Iter 18a's bump path had already centralised the allocator-symbol decision on fn_name() for all four allocation sites. crates/ail/src/main.rs — --alloc=rc accepted by Build/Run; parse_alloc_strategy extended; locate_rc_runtime() helper mirrors locate_bump_runtime; new Rc arm in build_to compiles runtime/rc.c with clang -O2 -c and links the resulting .o into the final binary (no -lgc). E2E coverage: alloc_rc_produces_same_stdout_as_gc on list.ail.json (42), alloc_rc_matches_gc_on_std_list_demo for broader allocation-site coverage. Total e2e bundle: 51 tests (was 49). Hand-verified on: sum.ail.json --alloc=rc → 55 list.ail.json --alloc=rc → 42 borrow_own_demo.ail.json --alloc=rc → 3 then 6 std_list_demo.ail.json --alloc=rc → matches --alloc=gc cargo build/test --workspace green; git diff examples/ empty.
This commit is contained in:
@@ -116,11 +116,19 @@ type Result<T> = std::result::Result<T, CodegenError>;
|
||||
/// `Bump` swaps every `@GC_malloc` for `@bump_malloc`, which is supplied
|
||||
/// by `runtime/bump.c` — a no-free, statically-sized arena allocator
|
||||
/// used purely to quantify the GC's overhead via an A/B comparison.
|
||||
/// The IR is otherwise byte-identical between the two strategies.
|
||||
/// `Rc` (Iter 18b, Decision 10) routes allocation through
|
||||
/// `@ailang_rc_alloc` from `runtime/rc.c`, which prefixes every payload
|
||||
/// with an 8-byte refcount header. Iter 18b stops at allocator routing —
|
||||
/// codegen does not yet emit `inc`/`dec` calls, so programs leak
|
||||
/// every allocation under `Rc`. The actual instrumentation arrives in
|
||||
/// Iter 18c once uniqueness inference is wired up.
|
||||
/// The IR is otherwise byte-identical between the three strategies
|
||||
/// modulo the allocator symbol name.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AllocStrategy {
|
||||
Gc,
|
||||
Bump,
|
||||
Rc,
|
||||
}
|
||||
|
||||
impl Default for AllocStrategy {
|
||||
@@ -135,6 +143,7 @@ impl AllocStrategy {
|
||||
match self {
|
||||
AllocStrategy::Gc => "GC_malloc",
|
||||
AllocStrategy::Bump => "bump_malloc",
|
||||
AllocStrategy::Rc => "ailang_rc_alloc",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user