frame allocs: a local shadowing a function is no edge, the drain's calls are no edges, HEAP keeps only a growth off the arena, and the arena starts at its first use

- the call graph is by name, and a local or a parameter named as a function (a float bd, part, bx)
  linked to that function: a name the function binds itself is never an edge now.
- drain_actions, generated, calls every reducer; a reducer is reached from its action's dispatch,
  so the drain's calls are not edges.
- a fresh value flowing into a local that also holds kept memory is still the frame's (storing it
  anywhere kept would have made it ESC): HEAP now keeps only a push's growth off the arena.
- the arena starts at its first use rather than at the first frame mark, so boot's temporaries are
  scratch too - dead once the Start handlers return - and a scratch site is never a birth.
Plus ludic.hints' rail and three of ludic.update's one-off lines declared. The arena goldens pass
poisoned. Maroon Lake (d79d189f): 39/11/66 -> 30/9/0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 20:23:28 +03:00
parent 8228597ade
commit d483c9283c
9 changed files with 62846 additions and 61736 deletions

View file

@ -294,6 +294,26 @@ function dr_index(name: pointer) -> int {
if n == null { return -1 }
return n.ival
}
# the names the function being walked binds itself - its parameters, lets and loop variables - which
# are not the top-level declarations of the same name (a local `bd` is not the function bd)
var g_dr_locals: []pointer = new []pointer
function dr_is_local(name: pointer) -> bool {
var i = 0
while i < len(g_dr_locals) { if (g_dr_locals[i] == name) { return true }; i += 1 }
return false
}
function dr_collect_locals(n: Node) -> void {
if n == null { return }
if (n.kind == S_LET or n.kind == S_FOR or n.kind == N_PARAM) and n.s != null { push(g_dr_locals, n.s) }
dr_collect_locals(n.a)
dr_collect_locals(n.b)
dr_collect_locals(n.c)
if n.kids != null {
var i = 0
while i < len(n.kids) { dr_collect_locals(n.kids[i]); i += 1 }
}
}
function dr_walk(n: Node, refs: []int) -> void {
if n == null { return }
if dr_port_member(n, refs) { return }
@ -322,7 +342,7 @@ function dr_walk(n: Node, refs: []int) -> void {
li += 1
}
}
if (n.kind == E_ID or n.kind == E_FNREF) and n.s != null {
if (n.kind == E_ID or n.kind == E_FNREF) and n.s != null and not (n.kind == E_ID and dr_is_local(n.s)) {
let k = dr_index(n.s)
if k >= 0 { push(refs, k) }
# a registry entry held in a local and handed on whole reaches the whole registry
@ -471,10 +491,23 @@ function deps_reach(f: pointer) -> void {
let nw = dr_words()
var j = 0
while j < len(g_dr_node) {
let refs = new []int
var refs = new []int
g_dr_rl_name = new []pointer
g_dr_rl_reg = new []pointer
dr_walk(g_dr_node[j], refs)
g_dr_locals = new []pointer
let dn = g_dr_node[j]
if dn.kind == N_FN or dn.kind == N_SYS or dn.kind == N_BLOCK { dr_collect_locals(dn) }
dr_walk(dn, refs)
# the generated drain calls every reducer; a reducer is reached from its action's dispatch instead
if dn.s != null and (dn.s == "drain_actions") {
let kept = new []int
var q = 0
while q < len(refs) {
if not str_starts(g_dr_name[refs[q]], "ludic_reduce__") { push(kept, refs[q]) }
q += 1
}
refs = kept
}
push(g_dr_refs, refs)
let bits = new []int
var w = 0