Skip to content
68. Release Construction Tracking When an Action Returns Nil
- An action that constructed temporary structs and returned nil skipped cleanup
of its construction tracker. Streams therefore held every temporary node.
Successful, nil and rejected action results now release tracking references;
Go clears the discarded slice tail as well as truncating it. Predicates and
bindings use the same cleanup, without changing values held in the
environment or returned trees. Generated Node/typed Go, direct typed nested
constructors and TypeScript mirror the cleanup; TS uses a finally block.
- For
item = "a" -> foldl(nil, list(V{N:1}), (acc,v)=>nil), a discarded
stream retained 20,000/60,000 tracked structs before cleanup. A closure
diagnostic sampled 8.3 → 24.0 MB of live heap (15 MiB additional retention).
The fixed regression on every engine/unit keeps tracking capacity at one;
heap growth from 20k to 60k is 0–6 KiB in the recorded run. Returned nodes
keep their identity, fields, spans and final-result labeling.
- Six interleaved before/after runs, Apple M3 Max, Go 1.27.1,
-benchtime=200ms, 10,000 code-point stream elements: closure B/op
4.20 → 3.89 MB (−7.4%), bytecode/iterative 4.92 → 4.61 MB (−6.3%);
17 fewer allocations per parse. Median time changes are −20%, −12% and
−15%. The existing Arith_OperatorsRule batch workload has unchanged allocation
volume: engine median time changes are within 2%, generated Node Go is
1.6–4.6% slower and generated typed Go 4.2% slower in this sample. Retain
the cleanup for bounded retention; these figures do not claim every action
path is faster. TS retained-state/semantic tests pass, but TS timing is not
measured here. The full benchmark refresh follows the stream-memory work.
- The baseline is daa364d (code unchanged from 9353e09), compared with the
action-reference cleanup in f259b37. Restore
eval.go/vm.go and the
generated benchmark parsers for the baseline overlay. Reproduce with
go test ./internal/engine -run '^$' -bench '^BenchmarkNilActionStream$' -benchmem.
Tests cover backing-array references and prefix ownership, stream heap on
both units/all engines, generated Go/typed direct rules and TS nil/error paths.