Branch ast-stage-c. Tags v3-fix-arrrecfield (code),
v3-arrrecfield-complete (this summary).
A record's array field is stored inline as a descriptor
({ l <len>, data }), so its length word must be initialised wherever
the record lives. For a standalone record RecItems does this, and
for a fixed top-level array ArrData does. But in static
array-of-record data the elements were emitted as one compact zero
blob (z n*size), so each element's embedded length word stayed 0.
Passing such a field as an open-array actual made the callee read
length 0 and trap (docs/wip/arrrec-field-openarray.mod, rc 134;
docs/summary_l3_selfhost_fix.md). V3-built compilers miscompiled this;
Lower's own tables avoided it by using flat arrays.
1. Small record arrays: inline expansion (2ebf662).
QbeGen.ArrBodyItems / ArrData expand record/class elements per
element so each inline array field's length word is in the static data.
The predicate was generalised from HasNestedArray (only
ARRAY OF ARRAY) to HasArrayField (any array field, recursively).
2. Large record arrays: run-time init (0ee6029).
Expanding a huge table would blow the 4 MiB image — AST.arena is
ARRAY [0..262143] OF NodeRec (262144 records; even an interleaved
l <len>, z <n> form needs ~2.6 MB of text). So arrays whose element
data exceeds a budget stay compact and their length words are set by a
generated init loop:
QbeGen.RecArrayExpanded(n, t) centralises the budget
(n * TypeSize(elem) <= 131072).QbeGen.RecArrayNeedsInit(n, t) — array of record/class that
(recursively) has array fields and is too big to expand.QbeGen.DeclRecTemplate(varName, rec) emits
data $<mod>_<var>_tmpl = { <one record with counts set> } (plus any
nested sub-descriptors).QbeGen.InitRecArray(varName, arrT) emits the loop that copies the
template over each element: element i is at base + 8 + i*stride.Lower.EmitVarNames records module-level globals that need it
(declaring the template alongside their data); Lower.EmitCountInits
runs the loops in the unit's init — emitting an init even for a unit
with no BEGIN body, since main calls every registered init.Together the two paths cover all sizes; the latent 0-count bug is gone.
Slot4/LoadW/StoreW); using a temp made the
condition reload the initial 0 and loop forever.Op3 takes a 5th isReal argument.docs/wip/arrrec-field-openarray.mod → exit 0 (was rc 134).t_arrrecfld.mod (small, inline path) → 42; t_arrrecbig.mod
(5000 records, run-time path) → 42.AST.arena is now initialised by the generated loop at
each startup (cheap: one memcpy-per-element loop).0ee6029 fix: run-time init of large array-of-record inline length words
2ebf662 fix: init inline array-field length in array-of-record static data