; Bench fixture: closure-pair allocation under load. ; ; Each iteration of `run_loop` introduces a fresh `let-rec helper` ; whose body captures the outer fn-param `i`. The let-rec name is ; passed as a value to `apply_thrice`, which forces eta-Lam wrapping ; (the 16b.5 / 8b ABI shape) — codegen allocates a `{ thunk, env }` ; closure pair where `env` holds the captured `i`. Under ; --alloc=rc the allocation goes through `ailang_rc_alloc` and the ; per-type drop fn `build_pair_drop_fn` is generated for the ; closure-pair type. (The 18c.4 doubled-braces bug lived in exactly ; this drop fn; this fixture is the canonical exerciser.) ; ; The helper body is (body i) — it ignores its parameter and ; returns the capture. apply_thrice(helper, x) therefore evaluates ; to i regardless of x. Each run_loop iteration thus contributes ; `i` to the accumulator. Total = sum 0..n-1 = n*(n-1)/2. ; ; Sizes (Implicit-mode RC leaks the closure pairs by design — the ; gc/bump arms are the meaningful allocator comparison, the rc arm ; reports alloc-tax-only): ; n = 10_000 -> 49_995_000 (1k closure-pair allocs) ; n = 100_000 -> 4_999_950_000 (100k allocs) ; n = 500_000 -> 124_999_750_000 (500k allocs) (module bench_closure_chain (fn apply_thrice (doc "Higher-order: apply f three times to seed.") (type (fn-type (params (fn-type (params (con Int)) (ret (con Int))) (con Int)) (ret (con Int)))) (params f seed) (body (app f (app f (app f seed))))) (fn run_loop (doc "For each i in [n-1, n-2, ..., 0], build a closure capturing i, pass to apply_thrice, accumulate. Tail-recursive on i and acc.") (type (fn-type (params (con Int) (con Int)) (ret (con Int)))) (params i acc) (body (if (app lt i 0) acc (let-rec helper (params x) (type (fn-type (params (con Int)) (ret (con Int)))) (body i) (in (let r (app apply_thrice helper i) (tail-app run_loop (app - i 1) (app + acc r)))))))) (fn run (doc "Drive run_loop from i=n-1 down to 0.") (type (fn-type (params (con Int)) (ret (con Int)))) (params n) (body (app run_loop (app - n 1) 0))) (fn main (type (fn-type (params) (ret (con Unit)) (effects IO))) (params) (body (seq (app print (app run 10000)) (seq (app print (app run 100000)) (app print (app run 500000)))))))