Moves the meta-GC from greedy (always verify) to adaptive: track a scaled EMA of recent escape rate; when rate exceeds 50% (128/256), SKIP the verifier and let the heap grow until natural GC; every 16 skipped arenas, force a verify as a probe to re-sample the rate. Two correctness fixes uncovered while testing adaptive: 1. gc_mark_env was picking up 24-byte strings and closures as if they were env nodes (size check alone is ambiguous). Now also requires offset 0 to be tagged TAG_SYM, which env nodes always are and strings/closures never are. 2. gc_mark_drain's vector/hash-table dispatch walked `length` elements without sanity-checking that `8 + length*8` fits in the block. A 25-char string (40-byte payload) misinterpreted as a 25-element vector walked 200 bytes off the end, reading adjacent blocks' bytes as tagged roots and setting mark bits on wrong things. Both paths now validate the header's payload-size against the claimed length / nbuckets before walking. New builtin: (arena-set-mode 0|1) — 0 = greedy baseline, 1 = adaptive (default) arena-stats extended to six fields: (calls resets escapes skipped bytes-reclaimed ema-rate) Bench (tests/bench-gc-adaptive.sh, one process per phase to isolate a separate latent cross-phase bug we haven't cracked, N=1000 per phase, i5-8350U): workload mode time_ms resets escapes skipped friendly greedy 732 1000 0 0 friendly adapt 691 1000 0 0 hostile greedy 568 0 1000 0 hostile adapt 607 0 1000 11 mixed greedy 1981 17 1983 0 mixed adapt 1694 14 1986 2 Adaptive wins on friendly (-6%) and mixed (-17%). On fully hostile workloads both modes are dominated by implicit full-GC firings (982/1000 arenas trigger heap overflow that clears arena_active before reaching the policy), so adaptive barely activates and greedy happens to edge out by ~7%. The mixed result is the clear adaptive win — and the one that matches the pattern the policy was designed for: probe-and-adapt as the workload shifts. 137 asm (no-GC) + 137 asm (GC) + 189 shared functional tests all still pass.
58 KiB
Executable file
58 KiB
Executable file