runtime: half-retirement of Boehm — flip CLI default to --alloc=rc
The dual-allocator policy from 2026-05-08 made Boehm the CLI default
"for general workloads", with rc selected explicitly for real-time-
sensitive code. That asymmetry contradicted Decision 10: rc + uniqueness
inference is the canonical memory model AILang's typechecker enforces,
and the CLI was teaching the opposite mental model to users and prompt-
fed LLMs.
This iter flips the asymmetry without removing Boehm:
- main.rs: default_value gc -> rc for build/run; help text rewritten
so rc is the canonical path and gc is the parity oracle.
- DESIGN.md Decision 9 retitled "RC canonical, Boehm parity oracle"
and rewritten end-to-end. Migration plan step 6 updated to a
two-step retirement (default-flip done, full removal gated).
- DESIGN.md pipeline diagram: rc-first, gc-as-oracle.
- JOURNAL: 2026-05-09 entry recording the call, what shipped,
the bug the flip surfaced, the gating condition for full
Boehm removal.
Bug surfaced by the flip and fixed in the same iter:
codegen/drop.rs build_pair_drop_fn emitted `getelementptr inbounds
{{ ptr, ptr }}, ...` via push_str (not format!), so the doubled
braces leaked verbatim into the IR. LLVM parsed it as a struct-of-
struct, the GEP referenced a non-existent field, and clang failed.
Invisible under the old gc default (no per-type drop fns) and
invisible to the 8 explicit _with_alloc("rc") tests (none of them
escaped a closure-with-captures). Caught immediately by two corpus
tests once rc became the baseline: closure_captures_let_n,
local_rec_as_value_capture_demo. Fix: single braces. Tests stay
as the regression guard.
The episode is the canonical justification for keeping the GC arm
as a parity oracle for now — a months-old codegen bug found by
flipping the baseline column.
288 passed / 0 failed / 3 ignored, unchanged.
This commit is contained in:
@@ -871,8 +871,14 @@ impl<'a> Emitter<'a> {
|
||||
out.push_str(" br i1 %is_null, label %ret, label %live\n");
|
||||
out.push_str("live:\n");
|
||||
if has_env {
|
||||
// The pair layout is `{ ptr thunk, ptr env }`; env is the
|
||||
// second field. Note the single braces — this is a plain
|
||||
// `push_str`, not a `format!` call, so brace-escaping does
|
||||
// not apply. (Iter 18c.4 originally shipped doubled braces
|
||||
// here; surfaced when the rc backend became the corpus
|
||||
// default and a closure-with-captures escaped.)
|
||||
out.push_str(
|
||||
" %ea = getelementptr inbounds {{ ptr, ptr }}, ptr %p, i64 0, i32 1\n",
|
||||
" %ea = getelementptr inbounds { ptr, ptr }, ptr %p, i64 0, i32 1\n",
|
||||
);
|
||||
out.push_str(" %env = load ptr, ptr %ea, align 8\n");
|
||||
out.push_str(&format!(" call void @{env_drop}(ptr %env)\n"));
|
||||
|
||||
Reference in New Issue
Block a user