selfhost/cmd/wcc + lib/strings: restore SSoT routing for str/slice tinfo helpers
Phase A.5's tupleelemslot / fieldslotsize hardcoded 16u64 for TY_STR and 24u64 for TY_SLICE — bypassing the tinfo.size SSoT seeded by lib/ww/typ.ww:189 (the very pivot they were introduced to consult). Route those four arms through pt.size / ft.size so #1 (str→24) and #34 (slice graduation) land as a one-line bump at the seed. lib/strings/stringstest.ww carried 12 `(cap: u64) * 16u64` strides missed by #43's sweep over strings.ww + shlex.ww; convert to `* size(str): u64` so the #42 fold owns the constant. Doc comments in strings.ww (freeall + splitn) updated to the same SSoT form. No-op at today's str.size=16 / slice=24: tinfo.size already matches the literals these arms had baked in. Reviewer's pre/post asm-identity probe (struct{i64,str,i64} + (i32,str,i32) tuple + bare str) shows zero-byte diff. 131/131 + 994 + 995 + bootstrap (ww2==ww3==ww4) green. Forward-link to #1 (str→24B bump) and #64 (sizelint pre-commit gate); #65 filed for lib/bytes + lib/getopt sibling sites the reviewer surfaced. Forward of #64 will catch any future regressions of this class.
This commit is contained in:
@@ -148,8 +148,9 @@ export fn dupall(s: []str) ([]str | nomem) = {
|
|||||||
//
|
//
|
||||||
// Empty elements (`{nil, 0}` from a zero-length dup) are skipped:
|
// Empty elements (`{nil, 0}` from a zero-length dup) are skipped:
|
||||||
// os.free on a nil pointer at len 0 tickles the rt_free guard. The
|
// os.free on a nil pointer at len 0 tickles the rt_free guard. The
|
||||||
// slice header itself is freed at `cap * 16` (one str = 16B); a
|
// slice header itself is freed at `cap * size(str)` — the literal
|
||||||
// never-grown slice (cap == 0) skips the header free.
|
// would drift under #1's str-layout bump, so route through the
|
||||||
|
// typ.ww SSoT. A never-grown slice (cap == 0) skips the header free.
|
||||||
export fn freeall(s: []str) void = {
|
export fn freeall(s: []str) void = {
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) {
|
for (i < s.len) {
|
||||||
@@ -774,7 +775,7 @@ fn appendstr(slice: *[]str, item: str) void = {
|
|||||||
// within the result are borrowed from `in`.
|
// within the result are borrowed from `in`.
|
||||||
//
|
//
|
||||||
// The caller frees the returned slice via
|
// The caller frees the returned slice via
|
||||||
// `os.free(r.ptr: *void, (r.cap: u64) * 16u64)`.
|
// `os.free(r.ptr: *void, (r.cap: u64) * size(str): u64)`.
|
||||||
//
|
//
|
||||||
// Hare's `([]str | nomem)` collapses to `[]str` here: ww os.alloc
|
// Hare's `([]str | nomem)` collapses to `[]str` here: ww os.alloc
|
||||||
// has no recoverable failure path. Same precedent as
|
// has no recoverable failure path. Same precedent as
|
||||||
|
|||||||
@@ -1441,7 +1441,7 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
expect_str(t1, 1, "my");
|
expect_str(t1, 1, "my");
|
||||||
expect_str(t1, 2, "name");
|
expect_str(t1, 2, "name");
|
||||||
expect_str(t1, 3, "is Drew");
|
expect_str(t1, 3, "is Drew");
|
||||||
os.free(t1.ptr: *void, (t1.cap: u64) * 16u64);
|
os.free(t1.ptr: *void, (t1.cap: u64) * size(str): u64);
|
||||||
|
|
||||||
// ref/hare/strings/tokenize.ha:263 — n > tokens leaves a single
|
// ref/hare/strings/tokenize.ha:263 — n > tokens leaves a single
|
||||||
// slot holding the unchanged input (delim not found).
|
// slot holding the unchanged input (delim not found).
|
||||||
@@ -1449,21 +1449,21 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
let t2: []str = strings.splitn("one", "=", 2);
|
let t2: []str = strings.splitn("one", "=", 2);
|
||||||
if (t2.len != 1) { fail(); };
|
if (t2.len != 1) { fail(); };
|
||||||
expect_str(t2, 0, "one");
|
expect_str(t2, 0, "one");
|
||||||
os.free(t2.ptr: *void, (t2.cap: u64) * 16u64);
|
os.free(t2.ptr: *void, (t2.cap: u64) * size(str): u64);
|
||||||
|
|
||||||
// n == 1 — single slot holding the whole input as remainder.
|
// n == 1 — single slot holding the whole input as remainder.
|
||||||
signalled = 1742;
|
signalled = 1742;
|
||||||
let t3: []str = strings.splitn("a b c", " ", 1);
|
let t3: []str = strings.splitn("a b c", " ", 1);
|
||||||
if (t3.len != 1) { fail(); };
|
if (t3.len != 1) { fail(); };
|
||||||
expect_str(t3, 0, "a b c");
|
expect_str(t3, 0, "a b c");
|
||||||
os.free(t3.ptr: *void, (t3.cap: u64) * 16u64);
|
os.free(t3.ptr: *void, (t3.cap: u64) * size(str): u64);
|
||||||
|
|
||||||
// Empty input — empty result.
|
// Empty input — empty result.
|
||||||
signalled = 1743;
|
signalled = 1743;
|
||||||
let t4: []str = strings.splitn("", " ", 5);
|
let t4: []str = strings.splitn("", " ", 5);
|
||||||
if (t4.len != 0) { fail(); };
|
if (t4.len != 0) { fail(); };
|
||||||
if (t4.cap > 0) {
|
if (t4.cap > 0) {
|
||||||
os.free(t4.ptr: *void, (t4.cap: u64) * 16u64);
|
os.free(t4.ptr: *void, (t4.cap: u64) * size(str): u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Multi-byte delim set (byte-set semantics per
|
// Multi-byte delim set (byte-set semantics per
|
||||||
@@ -1475,7 +1475,7 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
expect_str(t5, 1, "world");
|
expect_str(t5, 1, "world");
|
||||||
expect_str(t5, 2, "foo");
|
expect_str(t5, 2, "foo");
|
||||||
expect_str(t5, 3, "bar");
|
expect_str(t5, 3, "bar");
|
||||||
os.free(t5.ptr: *void, (t5.cap: u64) * 16u64);
|
os.free(t5.ptr: *void, (t5.cap: u64) * size(str): u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
@test fn rsplitn_cases() void = {
|
@test fn rsplitn_cases() void = {
|
||||||
@@ -1488,7 +1488,7 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
expect_str(t1, 1, "name");
|
expect_str(t1, 1, "name");
|
||||||
expect_str(t1, 2, "is");
|
expect_str(t1, 2, "is");
|
||||||
expect_str(t1, 3, "Drew");
|
expect_str(t1, 3, "Drew");
|
||||||
os.free(t1.ptr: *void, (t1.cap: u64) * 16u64);
|
os.free(t1.ptr: *void, (t1.cap: u64) * size(str): u64);
|
||||||
|
|
||||||
// n > token count — done short-circuit returns toks UN-reversed
|
// n > token count — done short-circuit returns toks UN-reversed
|
||||||
// (last-token-first order). Mirrors bytes.rsplitn (Hare's
|
// (last-token-first order). Mirrors bytes.rsplitn (Hare's
|
||||||
@@ -1500,14 +1500,14 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
expect_str(t2, 0, "c");
|
expect_str(t2, 0, "c");
|
||||||
expect_str(t2, 1, "b");
|
expect_str(t2, 1, "b");
|
||||||
expect_str(t2, 2, "a");
|
expect_str(t2, 2, "a");
|
||||||
os.free(t2.ptr: *void, (t2.cap: u64) * 16u64);
|
os.free(t2.ptr: *void, (t2.cap: u64) * size(str): u64);
|
||||||
|
|
||||||
// n == 1 — single slot holding the whole input as remainder.
|
// n == 1 — single slot holding the whole input as remainder.
|
||||||
signalled = 1752;
|
signalled = 1752;
|
||||||
let t3: []str = strings.rsplitn("a b c", " ", 1);
|
let t3: []str = strings.rsplitn("a b c", " ", 1);
|
||||||
if (t3.len != 1) { fail(); };
|
if (t3.len != 1) { fail(); };
|
||||||
expect_str(t3, 0, "a b c");
|
expect_str(t3, 0, "a b c");
|
||||||
os.free(t3.ptr: *void, (t3.cap: u64) * 16u64);
|
os.free(t3.ptr: *void, (t3.cap: u64) * size(str): u64);
|
||||||
|
|
||||||
// delim absent — first next_token yields the entire input as the
|
// delim absent — first next_token yields the entire input as the
|
||||||
// sole token; second iter sees done and short-circuits with the
|
// sole token; second iter sees done and short-circuits with the
|
||||||
@@ -1516,7 +1516,7 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
let t4: []str = strings.rsplitn("abc", "=", 5);
|
let t4: []str = strings.rsplitn("abc", "=", 5);
|
||||||
if (t4.len != 1) { fail(); };
|
if (t4.len != 1) { fail(); };
|
||||||
expect_str(t4, 0, "abc");
|
expect_str(t4, 0, "abc");
|
||||||
os.free(t4.ptr: *void, (t4.cap: u64) * 16u64);
|
os.free(t4.ptr: *void, (t4.cap: u64) * size(str): u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
@test fn split_cases() void = {
|
@test fn split_cases() void = {
|
||||||
@@ -1530,7 +1530,7 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
expect_str(t1, 2, "name");
|
expect_str(t1, 2, "name");
|
||||||
expect_str(t1, 3, "is");
|
expect_str(t1, 3, "is");
|
||||||
expect_str(t1, 4, "Drew");
|
expect_str(t1, 4, "Drew");
|
||||||
os.free(t1.ptr: *void, (t1.cap: u64) * 16u64);
|
os.free(t1.ptr: *void, (t1.cap: u64) * size(str): u64);
|
||||||
|
|
||||||
// Leading + trailing delim — empty tokens at ends.
|
// Leading + trailing delim — empty tokens at ends.
|
||||||
signalled = 1761;
|
signalled = 1761;
|
||||||
@@ -1540,7 +1540,7 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
expect_str(t2, 1, "a");
|
expect_str(t2, 1, "a");
|
||||||
expect_str(t2, 2, "b");
|
expect_str(t2, 2, "b");
|
||||||
expect_str(t2, 3, "");
|
expect_str(t2, 3, "");
|
||||||
os.free(t2.ptr: *void, (t2.cap: u64) * 16u64);
|
os.free(t2.ptr: *void, (t2.cap: u64) * size(str): u64);
|
||||||
|
|
||||||
// Multi-byte delim set, byte-set semantics matching Hare's
|
// Multi-byte delim set, byte-set semantics matching Hare's
|
||||||
// strings::split example at ref/hare/strings/tokenize.ha:235.
|
// strings::split example at ref/hare/strings/tokenize.ha:235.
|
||||||
@@ -1551,7 +1551,7 @@ fn expect_str(toks: []str, i: i32, want: str) void = {
|
|||||||
expect_str(t3, 1, "world");
|
expect_str(t3, 1, "world");
|
||||||
expect_str(t3, 2, "foo");
|
expect_str(t3, 2, "foo");
|
||||||
expect_str(t3, 3, "bar");
|
expect_str(t3, 3, "bar");
|
||||||
os.free(t3.ptr: *void, (t3.cap: u64) * 16u64);
|
os.free(t3.ptr: *void, (t3.cap: u64) * size(str): u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---- lpad / rpad -----------------------------------------------------
|
// ---- lpad / rpad -----------------------------------------------------
|
||||||
|
|||||||
@@ -1985,8 +1985,9 @@ export fn dupall(s: []str) ([]str | nomem) = {
|
|||||||
//
|
//
|
||||||
// Empty elements (`{nil, 0}` from a zero-length dup) are skipped:
|
// Empty elements (`{nil, 0}` from a zero-length dup) are skipped:
|
||||||
// os.free on a nil pointer at len 0 tickles the rt_free guard. The
|
// os.free on a nil pointer at len 0 tickles the rt_free guard. The
|
||||||
// slice header itself is freed at `cap * 16` (one str = 16B); a
|
// slice header itself is freed at `cap * size(str)` — the literal
|
||||||
// never-grown slice (cap == 0) skips the header free.
|
// would drift under #1's str-layout bump, so route through the
|
||||||
|
// typ.ww SSoT. A never-grown slice (cap == 0) skips the header free.
|
||||||
export fn freeall(s: []str) void = {
|
export fn freeall(s: []str) void = {
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) {
|
for (i < s.len) {
|
||||||
@@ -2611,7 +2612,7 @@ fn appendstr(slice: *[]str, item: str) void = {
|
|||||||
// within the result are borrowed from `in`.
|
// within the result are borrowed from `in`.
|
||||||
//
|
//
|
||||||
// The caller frees the returned slice via
|
// The caller frees the returned slice via
|
||||||
// `os.free(r.ptr: *void, (r.cap: u64) * 16u64)`.
|
// `os.free(r.ptr: *void, (r.cap: u64) * size(str): u64)`.
|
||||||
//
|
//
|
||||||
// Hare's `([]str | nomem)` collapses to `[]str` here: ww os.alloc
|
// Hare's `([]str | nomem)` collapses to `[]str` here: ww os.alloc
|
||||||
// has no recoverable failure path. Same precedent as
|
// has no recoverable failure path. Same precedent as
|
||||||
@@ -7959,16 +7960,18 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
|||||||
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
||||||
// spills each element into its own register / 8B eightbyte, so narrow
|
// spills each element into its own register / 8B eightbyte, so narrow
|
||||||
// scalars pad to 8 (cgen's let_emit_size + AX:DX:CX positional layout).
|
// scalars pad to 8 (cgen's let_emit_size + AX:DX:CX positional layout).
|
||||||
// str stays 16 (composite primitive), slice 24, pointer/fn/chan 8;
|
// str/slice and composites consult `pt.size` so a future #1 bump on
|
||||||
// composites contribute their own slot-padded width. void contributes
|
// any primitive layout propagates through the typ.ww SSoT seed
|
||||||
// 0 (never appears in tuples emitted by user code, but kept for SSoT
|
// instead of getting baked into this detour. pointer/fn/chan stay
|
||||||
// symmetry with cgen's N_TNAME-"void" fallback arm).
|
// 8; void contributes 0 (never appears in tuples emitted by user
|
||||||
|
// code, but kept for SSoT symmetry with cgen's N_TNAME-"void"
|
||||||
|
// fallback arm).
|
||||||
fn tupleelemslot(pt: *tinfo) u64 = {
|
fn tupleelemslot(pt: *tinfo) u64 = {
|
||||||
if (pt == nil) { return 8u64; };
|
if (pt == nil) { return 8u64; };
|
||||||
let pk: tykind = pt.kind;
|
let pk: tykind = pt.kind;
|
||||||
if (pk == tykind.TY_VOID) { return 0u64; };
|
if (pk == tykind.TY_VOID) { return 0u64; };
|
||||||
if (pk == tykind.TY_STR) { return 16u64; };
|
if (pk == tykind.TY_STR) { return pt.size; };
|
||||||
if (pk == tykind.TY_SLICE) { return 24u64; };
|
if (pk == tykind.TY_SLICE) { return pt.size; };
|
||||||
if (pk == tykind.TY_PTR || pk == tykind.TY_FN ||
|
if (pk == tykind.TY_PTR || pk == tykind.TY_FN ||
|
||||||
pk == tykind.TY_CHAN || pk == tykind.TY_I64 ||
|
pk == tykind.TY_CHAN || pk == tykind.TY_I64 ||
|
||||||
pk == tykind.TY_U64 || pk == tykind.TY_INT ||
|
pk == tykind.TY_U64 || pk == tykind.TY_INT ||
|
||||||
@@ -7994,10 +7997,13 @@ fn fieldslotsize(ft: *tinfo) u64 = {
|
|||||||
if (fk == tykind.TY_STRUCT) { return ft.slotsize; };
|
if (fk == tykind.TY_STRUCT) { return ft.slotsize; };
|
||||||
if (fk == tykind.TY_ARRAY) { return ft.slotsize; };
|
if (fk == tykind.TY_ARRAY) { return ft.slotsize; };
|
||||||
if (fk == tykind.TY_TAGGED) { return ft.size; };
|
if (fk == tykind.TY_TAGGED) { return ft.size; };
|
||||||
if (fk == tykind.TY_SLICE) { return 24u64; };
|
// str / slice read ft.size so the typ.ww SSoT seed is the single
|
||||||
|
// source for #1 (str→24) / #34 (slice graduation) — no hardcoded
|
||||||
|
// literal here to drift.
|
||||||
|
if (fk == tykind.TY_SLICE) { return ft.size; };
|
||||||
if (fk == tykind.TY_PTR || fk == tykind.TY_FN ||
|
if (fk == tykind.TY_PTR || fk == tykind.TY_FN ||
|
||||||
fk == tykind.TY_CHAN) { return 8u64; };
|
fk == tykind.TY_CHAN) { return 8u64; };
|
||||||
if (fk == tykind.TY_STR) { return 16u64; };
|
if (fk == tykind.TY_STR) { return ft.size; };
|
||||||
// Primitives keep natural width inside structs (matches
|
// Primitives keep natural width inside structs (matches
|
||||||
// cgenutil fieldsize: primsize, not pad-to-8). TY_TUPLE inside a
|
// cgenutil fieldsize: primsize, not pad-to-8). TY_TUPLE inside a
|
||||||
// struct currently defaults to 8 in cgenutil — preserve that
|
// struct currently defaults to 8 in cgenutil — preserve that
|
||||||
|
|||||||
@@ -873,16 +873,18 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
|||||||
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
||||||
// spills each element into its own register / 8B eightbyte, so narrow
|
// spills each element into its own register / 8B eightbyte, so narrow
|
||||||
// scalars pad to 8 (cgen's let_emit_size + AX:DX:CX positional layout).
|
// scalars pad to 8 (cgen's let_emit_size + AX:DX:CX positional layout).
|
||||||
// str stays 16 (composite primitive), slice 24, pointer/fn/chan 8;
|
// str/slice and composites consult `pt.size` so a future #1 bump on
|
||||||
// composites contribute their own slot-padded width. void contributes
|
// any primitive layout propagates through the typ.ww SSoT seed
|
||||||
// 0 (never appears in tuples emitted by user code, but kept for SSoT
|
// instead of getting baked into this detour. pointer/fn/chan stay
|
||||||
// symmetry with cgen's N_TNAME-"void" fallback arm).
|
// 8; void contributes 0 (never appears in tuples emitted by user
|
||||||
|
// code, but kept for SSoT symmetry with cgen's N_TNAME-"void"
|
||||||
|
// fallback arm).
|
||||||
fn tupleelemslot(pt: *tinfo) u64 = {
|
fn tupleelemslot(pt: *tinfo) u64 = {
|
||||||
if (pt == nil) { return 8u64; };
|
if (pt == nil) { return 8u64; };
|
||||||
let pk: tykind = pt.kind;
|
let pk: tykind = pt.kind;
|
||||||
if (pk == tykind.TY_VOID) { return 0u64; };
|
if (pk == tykind.TY_VOID) { return 0u64; };
|
||||||
if (pk == tykind.TY_STR) { return 16u64; };
|
if (pk == tykind.TY_STR) { return pt.size; };
|
||||||
if (pk == tykind.TY_SLICE) { return 24u64; };
|
if (pk == tykind.TY_SLICE) { return pt.size; };
|
||||||
if (pk == tykind.TY_PTR || pk == tykind.TY_FN ||
|
if (pk == tykind.TY_PTR || pk == tykind.TY_FN ||
|
||||||
pk == tykind.TY_CHAN || pk == tykind.TY_I64 ||
|
pk == tykind.TY_CHAN || pk == tykind.TY_I64 ||
|
||||||
pk == tykind.TY_U64 || pk == tykind.TY_INT ||
|
pk == tykind.TY_U64 || pk == tykind.TY_INT ||
|
||||||
@@ -908,10 +910,13 @@ fn fieldslotsize(ft: *tinfo) u64 = {
|
|||||||
if (fk == tykind.TY_STRUCT) { return ft.slotsize; };
|
if (fk == tykind.TY_STRUCT) { return ft.slotsize; };
|
||||||
if (fk == tykind.TY_ARRAY) { return ft.slotsize; };
|
if (fk == tykind.TY_ARRAY) { return ft.slotsize; };
|
||||||
if (fk == tykind.TY_TAGGED) { return ft.size; };
|
if (fk == tykind.TY_TAGGED) { return ft.size; };
|
||||||
if (fk == tykind.TY_SLICE) { return 24u64; };
|
// str / slice read ft.size so the typ.ww SSoT seed is the single
|
||||||
|
// source for #1 (str→24) / #34 (slice graduation) — no hardcoded
|
||||||
|
// literal here to drift.
|
||||||
|
if (fk == tykind.TY_SLICE) { return ft.size; };
|
||||||
if (fk == tykind.TY_PTR || fk == tykind.TY_FN ||
|
if (fk == tykind.TY_PTR || fk == tykind.TY_FN ||
|
||||||
fk == tykind.TY_CHAN) { return 8u64; };
|
fk == tykind.TY_CHAN) { return 8u64; };
|
||||||
if (fk == tykind.TY_STR) { return 16u64; };
|
if (fk == tykind.TY_STR) { return ft.size; };
|
||||||
// Primitives keep natural width inside structs (matches
|
// Primitives keep natural width inside structs (matches
|
||||||
// cgenutil fieldsize: primsize, not pad-to-8). TY_TUPLE inside a
|
// cgenutil fieldsize: primsize, not pad-to-8). TY_TUPLE inside a
|
||||||
// struct currently defaults to 8 in cgenutil — preserve that
|
// struct currently defaults to 8 in cgenutil — preserve that
|
||||||
|
|||||||
@@ -1985,8 +1985,9 @@ export fn dupall(s: []str) ([]str | nomem) = {
|
|||||||
//
|
//
|
||||||
// Empty elements (`{nil, 0}` from a zero-length dup) are skipped:
|
// Empty elements (`{nil, 0}` from a zero-length dup) are skipped:
|
||||||
// os.free on a nil pointer at len 0 tickles the rt_free guard. The
|
// os.free on a nil pointer at len 0 tickles the rt_free guard. The
|
||||||
// slice header itself is freed at `cap * 16` (one str = 16B); a
|
// slice header itself is freed at `cap * size(str)` — the literal
|
||||||
// never-grown slice (cap == 0) skips the header free.
|
// would drift under #1's str-layout bump, so route through the
|
||||||
|
// typ.ww SSoT. A never-grown slice (cap == 0) skips the header free.
|
||||||
export fn freeall(s: []str) void = {
|
export fn freeall(s: []str) void = {
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) {
|
for (i < s.len) {
|
||||||
@@ -2611,7 +2612,7 @@ fn appendstr(slice: *[]str, item: str) void = {
|
|||||||
// within the result are borrowed from `in`.
|
// within the result are borrowed from `in`.
|
||||||
//
|
//
|
||||||
// The caller frees the returned slice via
|
// The caller frees the returned slice via
|
||||||
// `os.free(r.ptr: *void, (r.cap: u64) * 16u64)`.
|
// `os.free(r.ptr: *void, (r.cap: u64) * size(str): u64)`.
|
||||||
//
|
//
|
||||||
// Hare's `([]str | nomem)` collapses to `[]str` here: ww os.alloc
|
// Hare's `([]str | nomem)` collapses to `[]str` here: ww os.alloc
|
||||||
// has no recoverable failure path. Same precedent as
|
// has no recoverable failure path. Same precedent as
|
||||||
@@ -7959,16 +7960,18 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
|||||||
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
// tuple. Mirrors cgenutil.ww slotsize TTUPLE — cstage's tuple ABI
|
||||||
// spills each element into its own register / 8B eightbyte, so narrow
|
// spills each element into its own register / 8B eightbyte, so narrow
|
||||||
// scalars pad to 8 (cgen's let_emit_size + AX:DX:CX positional layout).
|
// scalars pad to 8 (cgen's let_emit_size + AX:DX:CX positional layout).
|
||||||
// str stays 16 (composite primitive), slice 24, pointer/fn/chan 8;
|
// str/slice and composites consult `pt.size` so a future #1 bump on
|
||||||
// composites contribute their own slot-padded width. void contributes
|
// any primitive layout propagates through the typ.ww SSoT seed
|
||||||
// 0 (never appears in tuples emitted by user code, but kept for SSoT
|
// instead of getting baked into this detour. pointer/fn/chan stay
|
||||||
// symmetry with cgen's N_TNAME-"void" fallback arm).
|
// 8; void contributes 0 (never appears in tuples emitted by user
|
||||||
|
// code, but kept for SSoT symmetry with cgen's N_TNAME-"void"
|
||||||
|
// fallback arm).
|
||||||
fn tupleelemslot(pt: *tinfo) u64 = {
|
fn tupleelemslot(pt: *tinfo) u64 = {
|
||||||
if (pt == nil) { return 8u64; };
|
if (pt == nil) { return 8u64; };
|
||||||
let pk: tykind = pt.kind;
|
let pk: tykind = pt.kind;
|
||||||
if (pk == tykind.TY_VOID) { return 0u64; };
|
if (pk == tykind.TY_VOID) { return 0u64; };
|
||||||
if (pk == tykind.TY_STR) { return 16u64; };
|
if (pk == tykind.TY_STR) { return pt.size; };
|
||||||
if (pk == tykind.TY_SLICE) { return 24u64; };
|
if (pk == tykind.TY_SLICE) { return pt.size; };
|
||||||
if (pk == tykind.TY_PTR || pk == tykind.TY_FN ||
|
if (pk == tykind.TY_PTR || pk == tykind.TY_FN ||
|
||||||
pk == tykind.TY_CHAN || pk == tykind.TY_I64 ||
|
pk == tykind.TY_CHAN || pk == tykind.TY_I64 ||
|
||||||
pk == tykind.TY_U64 || pk == tykind.TY_INT ||
|
pk == tykind.TY_U64 || pk == tykind.TY_INT ||
|
||||||
@@ -7994,10 +7997,13 @@ fn fieldslotsize(ft: *tinfo) u64 = {
|
|||||||
if (fk == tykind.TY_STRUCT) { return ft.slotsize; };
|
if (fk == tykind.TY_STRUCT) { return ft.slotsize; };
|
||||||
if (fk == tykind.TY_ARRAY) { return ft.slotsize; };
|
if (fk == tykind.TY_ARRAY) { return ft.slotsize; };
|
||||||
if (fk == tykind.TY_TAGGED) { return ft.size; };
|
if (fk == tykind.TY_TAGGED) { return ft.size; };
|
||||||
if (fk == tykind.TY_SLICE) { return 24u64; };
|
// str / slice read ft.size so the typ.ww SSoT seed is the single
|
||||||
|
// source for #1 (str→24) / #34 (slice graduation) — no hardcoded
|
||||||
|
// literal here to drift.
|
||||||
|
if (fk == tykind.TY_SLICE) { return ft.size; };
|
||||||
if (fk == tykind.TY_PTR || fk == tykind.TY_FN ||
|
if (fk == tykind.TY_PTR || fk == tykind.TY_FN ||
|
||||||
fk == tykind.TY_CHAN) { return 8u64; };
|
fk == tykind.TY_CHAN) { return 8u64; };
|
||||||
if (fk == tykind.TY_STR) { return 16u64; };
|
if (fk == tykind.TY_STR) { return ft.size; };
|
||||||
// Primitives keep natural width inside structs (matches
|
// Primitives keep natural width inside structs (matches
|
||||||
// cgenutil fieldsize: primsize, not pad-to-8). TY_TUPLE inside a
|
// cgenutil fieldsize: primsize, not pad-to-8). TY_TUPLE inside a
|
||||||
// struct currently defaults to 8 in cgenutil — preserve that
|
// struct currently defaults to 8 in cgenutil — preserve that
|
||||||
|
|||||||
@@ -1876,8 +1876,9 @@ export fn dupall(s: []str) ([]str | nomem) = {
|
|||||||
//
|
//
|
||||||
// Empty elements (`{nil, 0}` from a zero-length dup) are skipped:
|
// Empty elements (`{nil, 0}` from a zero-length dup) are skipped:
|
||||||
// os.free on a nil pointer at len 0 tickles the rt_free guard. The
|
// os.free on a nil pointer at len 0 tickles the rt_free guard. The
|
||||||
// slice header itself is freed at `cap * 16` (one str = 16B); a
|
// slice header itself is freed at `cap * size(str)` — the literal
|
||||||
// never-grown slice (cap == 0) skips the header free.
|
// would drift under #1's str-layout bump, so route through the
|
||||||
|
// typ.ww SSoT. A never-grown slice (cap == 0) skips the header free.
|
||||||
export fn freeall(s: []str) void = {
|
export fn freeall(s: []str) void = {
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) {
|
for (i < s.len) {
|
||||||
@@ -2502,7 +2503,7 @@ fn appendstr(slice: *[]str, item: str) void = {
|
|||||||
// within the result are borrowed from `in`.
|
// within the result are borrowed from `in`.
|
||||||
//
|
//
|
||||||
// The caller frees the returned slice via
|
// The caller frees the returned slice via
|
||||||
// `os.free(r.ptr: *void, (r.cap: u64) * 16u64)`.
|
// `os.free(r.ptr: *void, (r.cap: u64) * size(str): u64)`.
|
||||||
//
|
//
|
||||||
// Hare's `([]str | nomem)` collapses to `[]str` here: ww os.alloc
|
// Hare's `([]str | nomem)` collapses to `[]str` here: ww os.alloc
|
||||||
// has no recoverable failure path. Same precedent as
|
// has no recoverable failure path. Same precedent as
|
||||||
|
|||||||
Reference in New Issue
Block a user