render3d's stream_new holds its pool through a local (`let live = s.chunks; push(live, new Chunk)`): the flow edge from s.chunks to live carried ESC to nothing, the Chunk records were LOCAL, and the arena reset them under the stream - the row and horse scenarios' crash at 0xdddd... in fn_stream_update. An ESC class is now HEAP too, so every alias of kept memory is, and a value stored through it is kept. Bidirectional alias edges were tried first and over-kept through returns (el_place, rim). - examples/lang/arena_alias.ludic: the stream_new shape; poisoned it read 3 3000, now 3 1518 - examples/modules/alloc_ok_private.ludic: @alloc_ok on a module's private function and on a statement in its private generic, declared at run time (it already passes: a guard) - the game: frame_allocs, frame_keeps, owned_leaks 0; the lab builds under `arena strict`; the row scenario poisoned (R3D_ARENA_CHECK=1, 2400 frames) runs clean, bad 0 kept 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
22 lines
746 B
Text
22 lines
746 B
Text
# memo/index.ludic - a module whose @alloc_ok helpers are private: renamed by the module rules, they
|
|
# must still be declared at run time (alloc_ok_private.ludic)
|
|
module memo
|
|
export property Rule { parts: []string = null }
|
|
export property Memo { rules: []Rule = new []Rule, ints: []int = new []int }
|
|
function kept<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
|
|
}
|
|
export function memo_miss(m: Memo, f: int) -> void {
|
|
@alloc_ok("the memo keeps a rule per text")
|
|
let r = new Rule { parts: split(`ab{f}`) }
|
|
kept(m.rules, r)
|
|
kept(m.ints, f)
|
|
}
|