frame allocs (25.2): what a frame can come to allocate, counted and ratcheted
deps_reach's graph gains the handlers and each @On body (an emit reaches its event's listeners).
Roots: a handler in a frame phase, every reducer, an @On body, and a function stored as a System's
tick. Every allocating construct in what they reach - new, a list literal, push (grow), text built
by + or a template, words/floats/buffer/bytes - is a falloc line with the shortest chain from a
root (root>..>last six), and the program's count is frame_allocs. @alloc_ok("why") on a function or
a handler takes it and what only it reaches out; the reason is required. ludic deps --allocs lists
them, and frame_allocs is a number --check ratchets. Maroon Lake starts at 2661.
Not yet: @frame on a step list's field (only 'tick' is a root field so far), statement-level
@alloc_ok, the three lints.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
691964877b
commit
76b1bd20ae
7 changed files with 82112 additions and 76450 deletions
|
|
@ -925,6 +925,7 @@ function parse_one_decl() -> void {
|
|||
var esys_phase: pointer = null
|
||||
var ns_name: pointer = null # @Namespace(Name) — a package-provided Foo.* namespace (#62)
|
||||
var is_det = false # @deterministic — no floating point inside (emit_float.ludic)
|
||||
var is_aok = false # @alloc_ok("why") — not counted by 25.2's frame allocations
|
||||
while is_op("@") {
|
||||
pi += 1; let a = eat_id() # collect a leading @annotation
|
||||
if a == "export" { is_export = true }
|
||||
|
|
@ -953,6 +954,13 @@ function parse_one_decl() -> void {
|
|||
else if a == "EngineSystem" { eat_op("("); esys_comp = eat_id(); eat_op(","); esys_phase = eat_id(); eat_op(")") } # @EngineSystem(Comp, Phase) package engine system (#62)
|
||||
else if a == "Namespace" { eat_op("("); ns_name = eat_id(); eat_op(")") } # @Namespace(Name) package Foo.* namespace (#62)
|
||||
else if a == "deterministic" { is_det = true }
|
||||
else if a == "alloc_ok" { # 25.2: @alloc_ok("why") - this allocates in a frame on purpose
|
||||
eat_op("(")
|
||||
let why = expr()
|
||||
if why.kind != E_STR or len(why.s) == 0 { perr("@alloc_ok needs its reason: @alloc_ok(\"a memo miss, bounded by MM_CAP\")") }
|
||||
eat_op(")")
|
||||
is_aok = true
|
||||
}
|
||||
else if a == "ClearColor" { # @ClearColor(colour) — Render auto-clear + auto-present (#86)
|
||||
eat_op("(")
|
||||
g_clear_color = expr() # a literal, a `const`, or a Color.Name — resolved when emitted
|
||||
|
|
@ -1024,6 +1032,7 @@ function parse_one_decl() -> void {
|
|||
if is_id("handler") {
|
||||
let h = parse_system()
|
||||
if is_det { push(g_det_names, h.s) }
|
||||
if is_aok { push(g_alloc_ok_names, h.s) }
|
||||
if (role != null) { if (role == "server") { h.ival = 1 } else { h.ival = 2 } } # N5: @Server=1 / @Predicted=2
|
||||
if (on_event != null) { register_onlisten(on_event, h.a); return } # @On(Event) listener
|
||||
if (onspawn_model != null) {
|
||||
|
|
@ -1094,6 +1103,7 @@ function parse_one_decl() -> void {
|
|||
let f = parse_fn()
|
||||
if is_unsafe { f.uns = 1 }
|
||||
if is_det { push(g_det_names, f.s) }
|
||||
if is_aok { push(g_alloc_ok_names, f.s) }
|
||||
if is_export { f.ival = 1 }
|
||||
if (sys_phase != null) { push(g_mod_sys_fn, f.s); push(g_mod_sys_phase, sys_phase) } # #64: register at load
|
||||
if (esys_comp != null) { push(g_esys_comp, esys_comp); push(g_esys_fn, f.s); push(g_esys_phase, esys_phase) } # #62: package engine system
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue