cgen: #50 append/insert tagged-dst VALUE boxes PRE-grow, both stages
The #34 value-store dispatch's tagged arm ran the widen choke-point (cg_widen_tagged_store / cgwidentaggedstore — which cgexprs the value internally) AFTER cg_append_grow, so a value expression reading the destination (xs.len) saw post-grow state. Hare evaluates arguments before the call's effects; the scalar/str/slice arms already ordered value-first. insert() inherited the bug through its desugar-to-append (9861f73) — one boxing choke-point, so this is the whole fix. Box the value into a fresh per-site @apptagscr frame scratch pre-grow (zero, BP-rooted widen store), then raw-copy the finished box into the new slot post-grow. Consumer evidence: regex fold-5b's {,0} rows (reviewer-5b's mutant; ken's corrected-root matrix /tmp/ken_silent, f50v4_tagged exit 15 both stages, byte-id, gate-blind). lib/regex.ww:643-647's pre-bound split_target workaround comment GRADUATES with this commit; the comment update itself rides the next regex touch per the standing rule. test/807: 57 -> 84 fixtures. New rows: tagged_pregrow_val (f50v4 exact), scalar_pregrow_val (no-regress control), tagged_selfref_val, tagged_str_payload, tagged_regex_minrep (the {,0} shape standalone), tagged_append_pregrow_val (direct append, the fix site), tagged_realloc_selfref_loop (ken k50a: old-base read across actual rt_ensure base moves), tagged_seq_positions (ken k50b: sequenced inserts at 0/mid, each len-reading) and tagged_void_variant (ken k50c: tag-only box through the fresh scratch). Mutation ate8977a4fails exactly the five eval-order-discriminating tagged rows, both stages. The STRUCT-LITERAL value arm keeps its post-grow field-expr fill — same eval-order class, different arm; filed (ww-core #59), cited at-site, not folded.
This commit is contained in:
@@ -8012,10 +8012,15 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
if (el_tagged || el_struct) {
|
||||
/* #34: no register form survives rt_ensure
|
||||
* for these — grow FIRST, then fill through
|
||||
* the dst pointer (tagged: the #12 widen
|
||||
* choke-point cgexprs the value internally;
|
||||
* struct: literal fill / ident word-copy). */
|
||||
* for these. struct: grow FIRST, then fill
|
||||
* through the dst pointer (literal fill /
|
||||
* ident word-copy). tagged: #50 — the #12
|
||||
* widen choke-point cgexprs the value
|
||||
* internally, so boxing must run PRE-grow
|
||||
* (Hare's argument order: a `xs.len` read
|
||||
* in v sees the pre-append len, like the
|
||||
* scalar arm); box into a frame scratch,
|
||||
* grow, raw-copy the finished box in. */
|
||||
/* #49 (#35's single-element sibling): a
|
||||
* place-chain source (indexed field
|
||||
* `threads[i].root_capture` regex.ha:819,
|
||||
@@ -8122,16 +8127,47 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
aplace = 1;
|
||||
}
|
||||
if (el_tagged) {
|
||||
/* Fresh slot per SITE, not the
|
||||
* shared per-size scratch: the
|
||||
* box must stay live across
|
||||
* rt_ensure, and a nested
|
||||
* append inside the value
|
||||
* expression would clobber a
|
||||
* dedup'd slot (the @apphdrscr
|
||||
* rationale; #25/#31). */
|
||||
int tg_scr = local_alloc(c,
|
||||
&locals, "@apptagscr", esz,
|
||||
cg_frame);
|
||||
ins2(c, A_XORQ, areg(D_AX),
|
||||
areg(D_AX));
|
||||
for (int zk = 0; zk < esz; zk += 8)
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BP, tg_scr + zk));
|
||||
cg_widen_tagged_store(c, &locals,
|
||||
esub, vn, D_BP, tg_scr, esz);
|
||||
cg_append_grow(c, sn_direct, sn_off,
|
||||
sn_scr, esz);
|
||||
cg_append_slot(c, sn_direct, sn_off,
|
||||
sn_scr, esz, D_BX);
|
||||
for (int ck = 0; ck < esz; ck += 8) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, tg_scr + ck),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BX, ck));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
cg_append_grow(c, sn_direct, sn_off,
|
||||
sn_scr, esz);
|
||||
cg_append_slot(c, sn_direct, sn_off,
|
||||
sn_scr, esz, D_BX);
|
||||
if (el_tagged) {
|
||||
cg_widen_tagged_store(c, &locals,
|
||||
esub, vn, D_BX, 0, esz);
|
||||
continue;
|
||||
}
|
||||
if (vn->kind == N_STRUCTLIT) {
|
||||
/* #59 (#50's eval-order kin):
|
||||
* the literal's field exprs
|
||||
* still eval POST-grow here —
|
||||
* filed, not folded. */
|
||||
if (cg_appendscr == 0)
|
||||
cg_appendscr = local_alloc(c,
|
||||
&locals, "@appendscr", 8,
|
||||
|
||||
Reference in New Issue
Block a user