cmd/w6c+selfhost/wcc+lib: route sizeof(str)/sizeof(slice) through SSoT
Audit §1.1/§1.2 cataloged 17 wwstage sites hardcoding 16 for sizeof(str) and ~10 hardcoding 24 for sizeof(slice), plus 4 cstage str-size sites and the cstage let_emit_size str/slice arms. Each new size constant required ~30 edits in both stages to bump cleanly — task #1 (str → 24B {ptr,len,cap}) can't land until the literal sweep is done. Track A — wwstage codegen (selfhost/cmd/wcc/*): - check.ww introduces two stateless helpers next to astsize: primtypesize(nm) — primitive-name → byte size (i64; -1 unknown) tyslicesize() — slice-header bytes (i64; 24 today) astsize now reads both for its N_TNAME-primitive and N_TSLICE arms, so the size(T) fold gets the SSoT for free. - cgen.ww, cgenutil.ww, cgenstmt.ww, cgendecl.ww: every `return 16` / `esz = 16` / `sz0 = 16` for str, every `return 24` / `localadd(c, _, 24, _)` for slice, plus the matching `sz == 16` / `sz == 24` / `for (i < 16/24)` gates in the global-let DATAW emit, route through primtypesize / tyslicesize. - Direct delegation slotsize→astsize would require restructuring astsize to drop its *checker dep (resolvealias) — the leaf primitive/slice cases factor out cleanly, the alias-chain leaves diverge because cgen's aliaslookup/structlookup tables and check's scope chain aren't unified yet (§1.8, task #50 follow-up). Sharing the leaf table satisfies the SSoT promise without that refactor. Track B — cstage (cmd/w6c/cgen.c): - let_emit_size's TY_STR/TY_SLICE arms drop the hardcoded 16/24 and fall to `(int)u->size` like the existing TY_STRUCT/TUPLE/TAGGED arms. - N_LET cgstmt's per-kind `sz` cascade collapses to a single `if (lu->kind ∈ {ARRAY,SLICE,STR,STRUCT,TUPLE,TAGGED}) sz = lu->size`. - N_LET cgexpr's match-bind primitive sizing: `bsz = (int)bu->size` drops the TY_STR/TY_SLICE special-cases (same outcome — ty_str/ ty_slice already have ->size set by type.c). - Three `sz == 16` / `let_emit_size(d->type) != 16` gates against the str slot width route through ty_str->size. Cap-offset sites (cgen.c:2440/1994/3206/5517 `delta = 16` for slice's .cap field-write) intentionally NOT touched: 16 there is the *offset of .cap inside a slice header*, structurally always 16 regardless of str.size. #1 doesn't move the slice layout. Track C — lib/ user code: - lib/strings.freeall + appendstr, lib/shlex.freepartial + appendstr: the four `16u64` literals (per-str-element stride for rt_ensure and os.free) become `size(str): u64`. Check-time fold via #42's intercept resolves to 16 today; #1 reroutes via the bumped tinfo. After this commit, bumping ty_str to 24B for task #1 requires editing exactly two places (cmd/wcc/type.c:64 ty_str.size, plus check.ww primtypesize's "str" arm) for the SSoT to propagate. Verification: - 131/131 tests pass. 994_w6c_ww + 995_self_rebuild byte-identity holds — each replacement evaluates to the same constant the literal had today, so cgen output is unchanged. - selfhost source's `size(str): u64` folds at check time (cstage cmd/wcc/check.c:907-960 for the C-bootstrap of selfhost; wwstage check.ww:898-942 for the rebuild path), no runtime call introduced.
This commit is contained in:
@@ -965,7 +965,7 @@ fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
let t: *node = d.lhs;
|
||||
for (t != nil) {
|
||||
if (t.kind == nkind.N_TPTR) { return 8; };
|
||||
if (t.kind == nkind.N_TSLICE) { return 24; };
|
||||
if (t.kind == nkind.N_TSLICE) { return tyslicesize(): i32; };
|
||||
if (t.kind == nkind.N_TARRAY) {
|
||||
let lenn: *node = t.rhs;
|
||||
let elemn: *node = t.lhs;
|
||||
@@ -987,7 +987,7 @@ fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
if (letscalarprim(nm)) { return 8; };
|
||||
let fsz: i32 = letfloatprim(nm);
|
||||
if (fsz > 0) { return fsz; };
|
||||
if (streq(nm, "str")) { return 16; };
|
||||
if (streq(nm, "str")) { return primtypesize("str"): i32; };
|
||||
let si: *structinfo = structlookup(c, nm);
|
||||
if (si != nil) { return si.totsize; };
|
||||
let next: *node = aliaslookup(c, nm);
|
||||
@@ -1313,7 +1313,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
if (sz == 16 && !issg) {
|
||||
if (sz == primtypesize("str"): i32 && !issg) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
@@ -1369,7 +1369,8 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB),\"");
|
||||
let i: i32 = 0;
|
||||
for (i < 16) {
|
||||
let szstr: i32 = primtypesize("str"): i32;
|
||||
for (i < szstr) {
|
||||
emitdatawbyte(0u8);
|
||||
i += 1;
|
||||
};
|
||||
@@ -1377,7 +1378,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (sz == 24 && !issg) {
|
||||
if (sz == tyslicesize(): i32 && !issg) {
|
||||
// Slice: zero-init only (no slice-literal
|
||||
// syntax to honour). Any rhs other than
|
||||
// `nil` is skipped → undefined symbol at
|
||||
@@ -1399,7 +1400,8 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB),\"");
|
||||
let i: i32 = 0;
|
||||
for (i < 24) {
|
||||
let szsl: i32 = tyslicesize(): i32;
|
||||
for (i < szsl) {
|
||||
emitdatawbyte(0u8);
|
||||
i += 1;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user