region rule (25.3c): keep() and intern(), frame_keeps, and --arena-strict

keep(x) copies a string, a slice (header and elements) or a record (shallow) onto the heap; intern(s)
hands back one heap string per distinct text from a fixed table in the runtime (FNV-1a, 65536 slots,
copied the first time; past 49152 only copied). Both are how frame code keeps what it made on purpose:
the escape analysis takes the copy as the heap's and leaves the argument LOCAL.

The analysis now records why a class escapes (the store, the event, the global it reached) and
ludic deps lists every allocation frame code makes and keeps - fkeep lines, 'ludic deps --keeps',
the frame_keeps number --check ratchets - leaving out what is under @alloc_ok and a push's growth
(25.5's capacities). --arena-strict (or 'arena strict') makes each an error naming the store, before
anything is emitted. A test: a template stored into a state is the one error; keep and intern of the
next two, an @alloc_ok push and a scratch temporary are not; 195 frames of arena resets under
R3D_ARENA_CHECK=1 later the kept and interned texts read as made, and intern gives the same string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 16:33:53 +03:00
parent cd71da9330
commit a0b030290b
10 changed files with 80528 additions and 76677 deletions

View file

@ -120,6 +120,7 @@ function fence_flag(a: pointer) -> bool {
if str_starts(a, "--fence-warm=") { g_fence_warm = fence_int(a[13..len(a)]); g_fence_flagged = true; return true }
if str_starts(a, "--fence-census=") { g_fence_census = a[15..len(a)]; g_fence_flagged = true; return true }
if (a == "--arena") { g_arena = true; return true }
if (a == "--arena-strict") { g_arena = true; g_arena_strict = true; return true }
return false
}
@ -152,6 +153,7 @@ function fence_manifest_read(txt: pointer) -> void {
if (len(ws) == 3) and (ws[0] == "fence") and (ws[1] == "warm") { g_fence_warm = fence_int(ws[2]) }
if (len(ws) == 3) and (ws[0] == "fence") and (ws[1] == "census") { g_fence_census = ws[2] }
if (len(ws) == 2) and (ws[0] == "arena") and (ws[1] == "on") { g_arena = true }
if (len(ws) == 2) and (ws[0] == "arena") and (ws[1] == "strict") { g_arena = true; g_arena_strict = true }
i = e + 1
}
}
@ -182,6 +184,7 @@ function fence_table(name: pointer, ty: pointer, vals: []pointer) -> void {
# the runtime, and the tables this program's sites size
function emit_fence_runtime() -> void {
emit_fence_intern()
if g_target_win { emit_fence_win(); return }
if not g_fprintf_declared { emith("declare i32 @fprintf(ptr, ptr, ...)\n"); g_fprintf_declared = true }
if not g_atexit_declared { emith("declare i32 @atexit(ptr)\n"); g_atexit_declared = true }