escape (fix): the arena took ludic.ui's pooled nodes - a generic's call and an unknown callee now keep what they are handed
memory_final's gate crashed in all 13 scenarios at the first frame of play, R3D_ARENA_CHECK=1 reading 0xDD in ludic.ui's nd_take: a node the pool keeps had come from the frame's scratch. Two holes: - a call to a generic (ui_kept(list, n)) names the generic, and the analysis knows only its instances (ui_kept$UiNode), so the callee looked unknown - and an unknown callee was taken to keep nothing. A generic's call now reaches every instance, and an unknown callee keeps everything it is handed, but for a short list of intrinsics known to keep nothing; view() shares its list's storage. - a push's growth into a parameter's list was LOCAL whenever the list was not seen kept, though a parameter may be a state's list. A site is LOCAL now only when its class is neither ESC nor HEAP. examples/lang/arena_pool.ludic is the shape (a pool keeping records across frames through a generic push): built with --arena it prints '7 3498' poisoned on every reset and with the arena off, in ludic-dev test. On the valley every ludic.ui pool site is kept; 5480 sites local, 6431 kept. Also, from ECS: a record's field defaults are stored into it when it is made, a global's initializer is kept, and a component's own functions are frame roots (they run while its page is open). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a6364199da
commit
c8a588b2de
6 changed files with 62210 additions and 59807 deletions
|
|
@ -817,6 +817,17 @@ function alloc_fence_auto_case() -> void {
|
|||
else { bad2(lbl, `rc={string(rc)} head=[{head}] count=[{through}]`) }
|
||||
}
|
||||
|
||||
# 25.3: a pool that keeps records across frames through a generic push must not take them from the
|
||||
# frame's scratch - poisoned on every reset it prints what the heap does
|
||||
function arena_pool_case() -> void {
|
||||
let lbl = "arena_pool.ludic (--arena: a generic push into a kept pool keeps its records and its buffer on the heap; 0xDD poison changes nothing)"
|
||||
let b = `{tmp_dir()}/e_arena_pool`
|
||||
if not shq(`bin/ludicc --arena examples/lang/arena_pool.ludic -o {b} 2>/dev/null`) { bad2(lbl, "did not build"); return }
|
||||
let poisoned = capture_line(`R3D_ARENA_CHECK=1 R3D_ALLOC_FENCE=off {b} < /dev/null`)
|
||||
let heap = capture_line(`R3D_ARENA=0 R3D_ALLOC_FENCE=off {b} < /dev/null`)
|
||||
if (poisoned == "7 3498") and (heap == "7 3498") { ok(lbl) } else { bad2(lbl, `poisoned [{poisoned}] heap [{heap}]`) }
|
||||
}
|
||||
|
||||
# issue #45: `bin/ludic-dev test --coverage`. Compile each test-spec with `--coverage`,
|
||||
# run it with LUDIC_COVERAGE pointed at a per-file dump, then aggregate the dumps
|
||||
# into a clean per-file line-coverage report. The instrumentation is flag-gated,
|
||||
|
|
@ -1115,6 +1126,7 @@ function cmd_dev_test() -> int {
|
|||
feat_case("lang/alloc_fence", "", "frames 300 kept 0 bad 0", "alloc_fence.ludic (25.1: a frame that makes only what it frees or reuses keeps nothing, and the fence passes it)")
|
||||
alloc_fence_leak_case()
|
||||
alloc_fence_auto_case()
|
||||
arena_pool_case()
|
||||
feat_case("lang/nested_templates", "", "outer [inner 3 {x}] \"`}\" end", "nested_templates.ludic (a template literal inside another's hole)")
|
||||
feat_case("lang/aliases", "", "10 5 3", "aliases.ludic (L6: a namespace method declared as an alias of a function, labelled or by its parameters)")
|
||||
reject_case("rejected/alias_arity", "this call to Trail.length leaves out to, which has no default", "an alias's arguments are checked against its target")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue