wcc/ww: per-unit prefix on _S_ strlit labels (#49)
Strlit labels were emitted as `_S_<n>` from a global counter with no per-unit prefix (cgen.c intern_strlit + wwstage internstrlit twin). Under separate compilation two str-bearing packages both emit `_S_0`.. -> w6l link collision. Prefix the label with the owning package PATH (`<module>._S_<n>`, matching mklabel's spelling). The prefix is c->cur_mod, set per-fn by cgfn and now per-decl by let_pre_intern (save/restore so the later emit passes, which read cur_mod for fn-ptr relocs, are unaffected). Pure function of the module path — NOT a build-nonce — so the self-host fixed-point holds across ww2/ww3/ww4. Both stages, symmetric. Transparent rename on the live combined path: the label is interned once and shared by every reference, so ref and def move in lockstep. cs==ww byte-id holds; the w6c/wwdump combined.ww embed wcc/cgen.ww and are regenerated. 746_strdef_inline: the strdef-inline sentinel pinned the bare `LEAQ\t_S_` shape; update to the module-prefixed form (alpha._S_ for the in-module def, beta._S_ for the use-site-interned cross-module inline). 989_m3sep_run: add the #49 LINK leg. The str sub-fixture (sleaf+smid) was keystone-only — never linked — precisely because the global counter made both emit `_S_0`. With the prefix, compile both `-c` separately, link (w6l) + run (sroot reads a distinguishing byte through each string's .ptr, so a collided label would corrupt the exit), both stages + cs==ww final exe.
This commit is contained in:
@@ -42162,18 +42162,26 @@ fn internstrlit(c: *cgen, bytes: str) str = {
|
||||
};
|
||||
s = s.slnext;
|
||||
};
|
||||
// New label "_S_<seq>".
|
||||
let buf: [32]u8;
|
||||
buf[0] = 95u8; buf[1] = 83u8; buf[2] = 95u8; // "_S_"
|
||||
// New label "<module>._S_<seq>" (bare "_S_<seq>" when curmod empty).
|
||||
// #49: per-unit prefix so two str-bearing packages don't both emit
|
||||
// `_S_0`.. and collide at w6l link. Pure function of the module path
|
||||
// (matching mklabel's spelling), so the self-host fixed-point holds.
|
||||
let buf: [128]u8;
|
||||
let i: i32 = 0;
|
||||
let mname: str = c.curmod;
|
||||
let j: i32 = 0;
|
||||
for (j < mname.len) { buf[i] = mname[j]; i += 1; j += 1; };
|
||||
if (mname.len > 0) { buf[i] = '.'; i += 1; };
|
||||
buf[i] = 95u8; i += 1; buf[i] = 83u8; i += 1; buf[i] = 95u8; i += 1; // "_S_"
|
||||
let ns: str = strconv.i64tos(c.strlitseq: i64, strconv.base.DEC);
|
||||
let n: i32 = ns.len;
|
||||
let dk: i32 = 0;
|
||||
for (dk < n) { buf[3 + dk] = ns.ptr[dk]; dk += 1; };
|
||||
for (dk < n) { buf[i + dk] = ns.ptr[dk]; dk += 1; };
|
||||
c.strlitseq += 1;
|
||||
let total: i32 = 3 + n;
|
||||
let total: i32 = i + n;
|
||||
let p: []u8 = alloc([], (total: u64) + 1u64)!;
|
||||
let i: i32 = 0;
|
||||
for (i < total) { p[i] = buf[i]; i += 1; };
|
||||
let k: i32 = 0;
|
||||
for (k < total) { p[k] = buf[k]; k += 1; };
|
||||
p[total] = 0u8;
|
||||
let lab: str;
|
||||
lab.ptr = p.ptr;
|
||||
@@ -42676,8 +42684,15 @@ fn preinternstrarray(c: *cgen, au: *tinfo, r: *node) void = {
|
||||
// DATAW lets) section order and break byte-identity.
|
||||
export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
if (file == nil) { return; };
|
||||
// #49: strlit labels allocated here (static-data initialisers) take
|
||||
// the OWNING decl's module prefix, not the stale last-fn curmod.
|
||||
// Save/restore so the later emit passes — which read curmod for
|
||||
// fn-ptr relocs — see the same value they did before; letpreintern
|
||||
// itself only interns, so driving curmod here has no other effect.
|
||||
let savedmod: str = c.curmod;
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
c.curmod = d.nmod;
|
||||
// #22 M3: skip imported deps so the strlit table (and its _S_
|
||||
// sequence) is a pure function of THIS package's own decls. A
|
||||
// dep's body initializer would intern here, but its `.wwi` (init
|
||||
@@ -42850,6 +42865,7 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
};
|
||||
d = d.next;
|
||||
};
|
||||
c.curmod = savedmod;
|
||||
};
|
||||
|
||||
// emitletdataw — DATAW directive per top-level `let` global.
|
||||
|
||||
Reference in New Issue
Block a user