ludic/examples/lang/alloc_fence_declared.ludic
Orkuncakilkaya 5aa7c03022 fence: declared bytes are never judged nor listed; the scan's sites sorted by bytes, as many as asked, and all to a file
What @alloc_ok covers (a function and its callees, a statement, a statement in a generic's body on
every instance) was counted apart in the frame's verdict, but its sites still carried the bytes the
report and the census rank by, so a declared site was listed as if the frame failed for it. Declared
bytes now have their own per-site counter and never enter live, a site's row or the verdict:
examples/lang/alloc_fence_declared.ludic, all three forms after warm-up, passes the failing fence
('bad 0 kept 0', 1488 bytes declared), with and without the arena, and an undeclared site in the same
frame is still the one listed.

The reachability scan's sites are now the largest first (R3D_ALLOC_SCAN_TOP, 24 by default), and
R3D_ALLOC_SCAN_FILE=<file> appends every site that holds unreachable bytes: the whole table to triage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:03:00 +03:00

34 lines
1.2 KiB
Text

# alloc_fence_declared.ludic - what @alloc_ok covers is declared at run time too, in each form: a
# function (and what it calls), one statement, and a statement inside a generic's body (every
# instance). A frame that makes only declared memory is not judged, so the fence - failing by
# default - lets the run through: `bad 0 kept 0`. Declared bytes are counted apart in the census.
program AllocFenceDeclared {
property Rule { parts: []string = null }
property Memo { rules: []Rule = new []Rule, ints: []int = new []int }
function kept_push<T>(xs: []T, v: T) -> void {
@alloc_ok("a kept list: grows to the most it held")
push(xs, v)
}
@alloc_ok("a memo miss")
function split(s: string) -> []string {
let out = new []string
push(out, s[0 .. 1])
push(out, s[1 .. 2])
return out
}
function miss(m: Memo, f: int) -> void {
@alloc_ok("the memo keeps a rule per text")
let r = new Rule { parts: split(`ab{f}`) }
kept_push(m.rules, r)
kept_push(m.ints, f)
}
entry {
let m = new Memo
for f in 0 .. 900 {
if f > 650 and f % 25 == 0 { miss(m, f) }
Mem.frame()
}
let kept_now = Mem.kept()
print(`bad {Mem.bad_frames()} kept {kept_now}`)
}
}