From 4972ab4a5cc750ddca198ff45d31cd94aa795da3 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 21 May 2026 02:58:30 +0900 Subject: [PATCH] =?UTF-8?q?cgen:=20loop/yield/defer=20fixed-max=20buffers?= =?UTF-8?q?=20raw-ptr=20=E2=86=92=20[]T=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 0 #9. cgen struct fields loopendbuf/loopcontbuf/yieldbuf/ deferbuf change from `*str`/`**node` over-allocated arena chunks to `[]str`/`[]*node` slices. The 4 alloc sites in cgeninit drop the byte-count form (`LOOP_MAX*24u64`, `DEFER_MAX*8u64`) for element-count (`LOOP_MAX: u64`, `DEFER_MAX: u64`). 10 caller sites in cgenstmt.ww/cgenexpr.ww use `[i]` indexing which works identically for slice-shaped struct fields. Two-line let-then-assign idiom for the 4 inits is a real checker limitation: alloc's element-deferred `[]u8` → `[]T` retype only fires in let-init (checkletassign N_TSLICE LHS), and cglet's alloc-slice writeback shortcut (cgenstmt.ww:577) only fires in let-init too. Direct `c.field = alloc([], N)!` would silently emit a scalar alloc with a junk slice header. Filed #49 for the checker enhancement; the let-then-assign is Hare-idiomatic in the meantime. Verified 132/132 + 995_self_rebuild byte-identity. --- selfhost/cmd/w6c/main.combined.ww | 24 ++++++++++++------------ selfhost/cmd/wcc/cgen.ww | 24 ++++++++++++------------ selfhost/cmd/wwdump/main.combined.ww | 24 ++++++++++++------------ 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 84c1ef0e..e3a3c137 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -21544,12 +21544,12 @@ type cgen = struct { // before walking the body. fnret: *node, // declared return type of current fn (or nil) looptop: i32, - loopendbuf: *str, // stack of end labels for break - loopcontbuf: *str, // stack of cont labels for continue + loopendbuf: []str, // stack of end labels for break + loopcontbuf: []str, // stack of cont labels for continue yieldtop: i32, - yieldbuf: *str, // stack of match end labels for yield + yieldbuf: []str, // stack of match end labels for yield defertop: i32, - deferbuf: **node, // stack of deferred exprs (LIFO at return) + deferbuf: []*node, // stack of deferred exprs (LIFO at return) // Variadic-call gather state. cgcall bumps this on each gather // emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per // callsite; mirrors cstage's mklabel("vararg_d/sl") freshness @@ -21609,16 +21609,16 @@ fn cgeninit(c: *cgen, a: *arena) void = { // persist across cgfn calls within one file. cgfile resets them // at the start of each compilation unit. c.looptop = 0; - // #35: per-slot stride is sizeof(str); the bare 16 is the str=16 - // width and undershoots under str=24, so indices past (LOOP_MAX*16)/24 - // = 10 would spill into the next amalloc. Bumped to 24/slot; +8/slot - // over-alloc under str=16 is harmless under the bump arena. - c.loopendbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; - c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; + let loopendbuf: []str = alloc([], LOOP_MAX: u64)!; + c.loopendbuf = loopendbuf; + let loopcontbuf: []str = alloc([], LOOP_MAX: u64)!; + c.loopcontbuf = loopcontbuf; c.yieldtop = 0; - c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; + let yieldbuf: []str = alloc([], LOOP_MAX: u64)!; + c.yieldbuf = yieldbuf; c.defertop = 0; - c.deferbuf = amalloc(a, (DEFER_MAX: u64) * 8u64): **node; + let deferbuf: []*node = alloc([], DEFER_MAX: u64)!; + c.deferbuf = deferbuf; }; // localalloc — append a slot for `name` without dedup. Used for diff --git a/selfhost/cmd/wcc/cgen.ww b/selfhost/cmd/wcc/cgen.ww index f98c2d36..d9cf57a5 100644 --- a/selfhost/cmd/wcc/cgen.ww +++ b/selfhost/cmd/wcc/cgen.ww @@ -469,12 +469,12 @@ type cgen = struct { // before walking the body. fnret: *node, // declared return type of current fn (or nil) looptop: i32, - loopendbuf: *str, // stack of end labels for break - loopcontbuf: *str, // stack of cont labels for continue + loopendbuf: []str, // stack of end labels for break + loopcontbuf: []str, // stack of cont labels for continue yieldtop: i32, - yieldbuf: *str, // stack of match end labels for yield + yieldbuf: []str, // stack of match end labels for yield defertop: i32, - deferbuf: **node, // stack of deferred exprs (LIFO at return) + deferbuf: []*node, // stack of deferred exprs (LIFO at return) // Variadic-call gather state. cgcall bumps this on each gather // emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per // callsite; mirrors cstage's mklabel("vararg_d/sl") freshness @@ -534,16 +534,16 @@ fn cgeninit(c: *cgen, a: *arena) void = { // persist across cgfn calls within one file. cgfile resets them // at the start of each compilation unit. c.looptop = 0; - // #35: per-slot stride is sizeof(str); the bare 16 is the str=16 - // width and undershoots under str=24, so indices past (LOOP_MAX*16)/24 - // = 10 would spill into the next amalloc. Bumped to 24/slot; +8/slot - // over-alloc under str=16 is harmless under the bump arena. - c.loopendbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; - c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; + let loopendbuf: []str = alloc([], LOOP_MAX: u64)!; + c.loopendbuf = loopendbuf; + let loopcontbuf: []str = alloc([], LOOP_MAX: u64)!; + c.loopcontbuf = loopcontbuf; c.yieldtop = 0; - c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; + let yieldbuf: []str = alloc([], LOOP_MAX: u64)!; + c.yieldbuf = yieldbuf; c.defertop = 0; - c.deferbuf = amalloc(a, (DEFER_MAX: u64) * 8u64): **node; + let deferbuf: []*node = alloc([], DEFER_MAX: u64)!; + c.deferbuf = deferbuf; }; // localalloc — append a slot for `name` without dedup. Used for diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 89df55d7..34c8323f 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -21544,12 +21544,12 @@ type cgen = struct { // before walking the body. fnret: *node, // declared return type of current fn (or nil) looptop: i32, - loopendbuf: *str, // stack of end labels for break - loopcontbuf: *str, // stack of cont labels for continue + loopendbuf: []str, // stack of end labels for break + loopcontbuf: []str, // stack of cont labels for continue yieldtop: i32, - yieldbuf: *str, // stack of match end labels for yield + yieldbuf: []str, // stack of match end labels for yield defertop: i32, - deferbuf: **node, // stack of deferred exprs (LIFO at return) + deferbuf: []*node, // stack of deferred exprs (LIFO at return) // Variadic-call gather state. cgcall bumps this on each gather // emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per // callsite; mirrors cstage's mklabel("vararg_d/sl") freshness @@ -21609,16 +21609,16 @@ fn cgeninit(c: *cgen, a: *arena) void = { // persist across cgfn calls within one file. cgfile resets them // at the start of each compilation unit. c.looptop = 0; - // #35: per-slot stride is sizeof(str); the bare 16 is the str=16 - // width and undershoots under str=24, so indices past (LOOP_MAX*16)/24 - // = 10 would spill into the next amalloc. Bumped to 24/slot; +8/slot - // over-alloc under str=16 is harmless under the bump arena. - c.loopendbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; - c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; + let loopendbuf: []str = alloc([], LOOP_MAX: u64)!; + c.loopendbuf = loopendbuf; + let loopcontbuf: []str = alloc([], LOOP_MAX: u64)!; + c.loopcontbuf = loopcontbuf; c.yieldtop = 0; - c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str; + let yieldbuf: []str = alloc([], LOOP_MAX: u64)!; + c.yieldbuf = yieldbuf; c.defertop = 0; - c.deferbuf = amalloc(a, (DEFER_MAX: u64) * 8u64): **node; + let deferbuf: []*node = alloc([], DEFER_MAX: u64)!; + c.deferbuf = deferbuf; }; // localalloc — append a slot for `name` without dedup. Used for