frame allocs: a click is not a frame, a reducer is its dispatch's, a capped push is bounded; ludic.photo at 0

The analysis made every component function a frame root, event handlers (cmp_x_on_delete) too, and
every reducer, whether its action is dispatched every frame or once a trip: a component's 'on'
handlers are no longer roots, and a dispatch is an edge to its action's reducers, so a reducer
counts only when frame code dispatches it. A push into a field declared @max(n) is bounded by the
fence's own check and no longer counted. Maroon Lake: frame_allocs 395 -> 337, frame_keeps 188 -> 169.

ludic.photo: the roll's order and a page of it are kept lists refilled in place (the pack's page
asked for both every frame), its kept lists say @max(256), and a shot's tags, a photograph's fact
and a new roll are declared (once per shot, sale or trip). 18 allocs and 9 keeps -> 0 and 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 20:02:47 +03:00
parent 5be2422c84
commit 3b9b4a589b
7 changed files with 58578 additions and 57763 deletions

View file

@ -304,6 +304,14 @@ function dr_walk(n: Node, refs: []int) -> void {
return
}
if dr_reg_field(n, refs) { return }
if n.kind == E_NEW and n.b != null and n.s != null { # 25.2: a dispatch reaches its action's reducers
let pre = `ludic_reduce__{n.s}__`
var ri = 0
while ri < len(g_dr_name) {
if str_starts(g_dr_name[ri], pre) { push(refs, ri) }
ri += 1
}
}
if n.kind == S_EMIT and n.s != null { # 25.2: an emit reaches its event's listeners
var li = 0
while li < len(g_onlisten) {