From 6faf00223eb9be1d834bd95a06ef84b9be363656 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 21 May 2026 12:00:46 +0900 Subject: [PATCH] =?UTF-8?q?selfhost/cmd/w6l:=20strip=20*arena=20cascade=20?= =?UTF-8?q?(=CE=B3-4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit amalloc has 0 callers post-γ-2; the *arena threaded through w6l's mklnk/resolvelib/cstrtostr/elfglobals/dcstrtostr and the lnk.a field are vestigial. Drop `import mem;` from sym/main/obj/dyn/dynout, remove lnk.a struct field, strip *arena from the five signatures, update 13 call sites. Drop a dead `let a: *arena = l.a;` in dynout. Comments at pass.ww/obj.ww/main.ww retidied to match post-strip reality. main.combined.ww auto-regenerated. Verified 132/132 incl. 992_w6l_ww + 996_dyn_ww + 995_self_rebuild byte-identity. --- selfhost/cmd/w6l/dyn.ww | 9 +- selfhost/cmd/w6l/dynout.ww | 2 - selfhost/cmd/w6l/main.combined.ww | 149 +++++------------------------- selfhost/cmd/w6l/main.ww | 16 ++-- selfhost/cmd/w6l/obj.ww | 25 +++-- selfhost/cmd/w6l/pass.ww | 2 +- selfhost/cmd/w6l/sym.ww | 3 - 7 files changed, 48 insertions(+), 158 deletions(-) diff --git a/selfhost/cmd/w6l/dyn.ww b/selfhost/cmd/w6l/dyn.ww index 33f8169d..75aa93eb 100644 --- a/selfhost/cmd/w6l/dyn.ww +++ b/selfhost/cmd/w6l/dyn.ww @@ -12,7 +12,6 @@ package w6l; import os; import rt; -import mem; import strings; import sym; @@ -107,7 +106,7 @@ fn dcstrlen(p: *u8) u64 = { return n; }; -fn dcstrtostr(a: *arena, p: *u8) str = { +fn dcstrtostr(p: *u8) str = { let n: u64 = dcstrlen(p); let view: str; view.ptr = p; @@ -295,7 +294,7 @@ export fn loadso(l: *lnk, path: *u8) i32 = { // Build the lso. Exports are appended in dynsym order so // soprovides_v's first-match semantics match the C version. - let so: *lso = alloc(lso { path = dcstrtostr(l.a, path), soname = dcstrtostr(l.a, sonamecs) })!; + let so: *lso = alloc(lso { path = dcstrtostr(path), soname = dcstrtostr(sonamecs) })!; let tail: *lexport = nil; let si: u64 = 1u64; @@ -347,9 +346,9 @@ export fn loadso(l: *lnk, path: *u8) i32 = { }; if (keep != 0) { - let e: *lexport = alloc(lexport { name = dcstrtostr(l.a, nmp) })!; + let e: *lexport = alloc(lexport { name = dcstrtostr(nmp) })!; if (vernamecs != nil) { - e.version = dcstrtostr(l.a, vernamecs); + e.version = dcstrtostr(vernamecs); }; if (tail == nil) { so.exports = e; diff --git a/selfhost/cmd/w6l/dynout.ww b/selfhost/cmd/w6l/dynout.ww index d86cf371..8868f948 100644 --- a/selfhost/cmd/w6l/dynout.ww +++ b/selfhost/cmd/w6l/dynout.ww @@ -26,7 +26,6 @@ package w6l; import os; import rt; -import mem; import sym; // ELF constants @@ -170,7 +169,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = { // Placed after .dynamic so the segment is one contiguous run; // relocate runs from here so the dyn layout's datava lands in // patched offsets. - let a: *arena = l.a; let n: i32 = l.dynn; let nu: u64 = n: u64; diff --git a/selfhost/cmd/w6l/main.combined.ww b/selfhost/cmd/w6l/main.combined.ww index 622cbdab..837b2a28 100644 --- a/selfhost/cmd/w6l/main.combined.ww +++ b/selfhost/cmd/w6l/main.combined.ww @@ -750,98 +750,6 @@ package rt; // a future task (task #39). ref/hare/rt/malloc.ha:27. @symbol("rt_malloc") export fn malloc(n: u64) *void; -// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c. -// -// Bump arena allocator. Backed by the runtime page allocator -// (rt_malloc / rt_free), no libc. Each chunk is mmap'd; when the -// current chunk runs out we link a fresh one. Freeing the arena -// unmaps the chain. -// -// Memory handed out is 16-byte aligned. The C version under -// cmd/wcc/ is retained until the three-stage bootstrap diffs clean. - -package wcc; - -import os; -import rt; - -def ALIGN: u64 = 16u64; -def INIT_CHUNK: u64 = 65536u64; -def MAX_CHUNK: u64 = 4194304u64; -def ARENA_SZ: u64 = 48u64; // sizeof(arena), kept in sync below - -type arena = struct { - buf: *u8, - off: u64, - cap: u64, - next: *arena, - total: u64, -}; - -fn roundup(n: u64, a: u64) u64 = { - return (n + a - 1u64) & ~(a - 1u64); -}; - -export fn newarena() *arena = { - let a: *arena = rt.malloc(ARENA_SZ): *arena; - a.buf = rt.malloc(INIT_CHUNK): *u8; - a.off = 0u64; - a.cap = INIT_CHUNK; - a.next = nil; - a.total = 0u64; - return a; -}; - -// Grow: link a fresh chunk in front of the head. We push the old -// chunk into `next` so the head always describes the current bump -// region. Chunk size doubles up to MAX_CHUNK. -fn grow(a: *arena, need: u64) bool = { - let want: u64 = a.cap * 2u64; - if (want < need) { want = need; }; - if (want > MAX_CHUNK) { want = MAX_CHUNK; }; - if (want < need) { return false; }; // single allocation too big - - let old: *arena = rt.malloc(ARENA_SZ): *arena; - old.buf = a.buf; - old.off = a.off; - old.cap = a.cap; - old.next = a.next; - old.total = 0u64; - - a.buf = rt.malloc(want): *u8; - a.off = 0u64; - a.cap = want; - a.next = old; - return true; -}; - -export fn amalloc(a: *arena, n: u64) *void = { - let need: u64 = roundup(n, ALIGN); - if (need > a.cap - a.off) { - if (!grow(a, need)) { return nil; }; - }; - let p: *u8 = a.buf + a.off; - a.off += need; - a.total += need; - // Zero the region. Plan 9 amalloc zeroes; we mirror that here so - // the checker can assume freshly allocated nodes start at 0. - let i: u64 = 0u64; - for (i < need) { - p[i] = 0u8; - i += 1u64; - }; - return p: *void; -}; - -export fn freearena(a: *arena) void = { - for (a != nil) { - let next: *arena = a.next; - os.free(a.buf: *void, a.cap); - os.free(a: *void, ARENA_SZ); - a = next; - }; -}; - // selfhost/cmd/w6l/sym.ww — port of cmd/w6l/sym.c. // // Linker symbol table. Singly-linked list, usually a few hundred @@ -849,8 +757,6 @@ export fn freearena(a: *arena) void = { package w6l; -import mem; - type lsym = struct { name: str, val: u64, // offset within combined .text (or .data when @@ -907,7 +813,6 @@ type lso = struct { }; type lnk = struct { - a: *arena, objs: *lobj, sos: *lso, syms: *lsym, @@ -2899,7 +2804,6 @@ package w6l; import os; import rt; -import mem; import strings; import sym; @@ -3045,7 +2949,7 @@ fn cstrlen(p: *u8) u64 = { return n; }; -// pathstr — view a NUL-terminated *u8 as a str. Bridges argv/arena +// pathstr — view a NUL-terminated *u8 as a str. Bridges argv-style // callers to lib/os entrypoints (str post-task-#23). Shared with // main.ww and dyn.ww via the w6l bundle. fn pathstr(p: *u8) str = { @@ -3068,7 +2972,7 @@ fn cstreq(p: *u8, lit: str) bool = { }; // Build a ww str from a NUL-terminated *u8 (for passing to intern). -fn cstrtostr(a: *arena, p: *u8) str = { +fn cstrtostr(p: *u8) str = { let n: u64 = cstrlen(p); let view: str; view.ptr = p; @@ -3088,7 +2992,7 @@ type defent = struct { }; type armember = struct { - data: *u8, // arena copy of the member's ELF bytes + data: *u8, // owned heap copy of the member's ELF bytes size: u64, defs: *defent, // linked list of defined globals loaded: i32, @@ -3123,9 +3027,9 @@ fn arfield(p: *u8, n: u64) u64 = { }; // elfglobals — return a linked list of names of globally-defined -// (STB_GLOBAL) symbols whose section is `.text`. Names are arena -// copies, so the source ELF buffer can be freed afterward. -fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = { +// (STB_GLOBAL) symbols whose section is `.text`. Names are owned +// heap copies, so the source ELF buffer can be freed afterward. +fn elfglobals(buf: *u8, len: u64) *defent = { if (len < EHDR_SIZE) { return nil; }; if (buf[0u64] != 127u8) { return nil; }; if (buf[1u64] != 69u8) { return nil; }; @@ -3189,7 +3093,7 @@ fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = { if (intext || indt) { let nmp: *u8 = strtab + (stname: u64); if (nmp[0u64] != 0u8) { - let nm: str = cstrtostr(a, nmp); + let nm: str = cstrtostr(nmp); let de: *defent = alloc(defent { name = nm, dnext = head })!; head = de; }; @@ -3242,7 +3146,7 @@ fn loadarchive(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { i += 1u64; }; m.data = mb; - m.defs = elfglobals(l.a, mb, hdrsize); + m.defs = elfglobals(mb, hdrsize); if (head == nil) { head = m; } else { tail.mnext = m; }; tail = m; @@ -3360,7 +3264,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { // Track this object. let ob: *lobj = alloc(lobj { - path = cstrtostr(l.a, path), + path = cstrtostr(path), buf = buf, len = len, textoff = l.textlen, @@ -3391,7 +3295,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { let stvalue: u64 = rdu64(buf, symp + SYM_VALUE); let nmp: *u8 = strtab + (stname: u64); if (nmp[0u64] != 0u8) { - let nm: str = cstrtostr(l.a, nmp); + let nm: str = cstrtostr(nmp); let gs: *lsym = intern(l, nm); if (stshndx != 0u16) { let intext: bool = (stshndx: i32) == idxtext; @@ -3455,7 +3359,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { let sname: u32 = rdu32(buf, sp + SYM_NAME); let snm: *u8 = strtab + (sname: u64); if (snm[0u64] != 0u8) { - let nm: str = cstrtostr(l.a, snm); + let nm: str = cstrtostr(snm); nr.sym = intern(l, nm); }; }; @@ -3491,7 +3395,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { let sname: u32 = rdu32(buf, sp + SYM_NAME); let snm: *u8 = strtab + (sname: u64); if (snm[0u64] != 0u8) { - let nm: str = cstrtostr(l.a, snm); + let nm: str = cstrtostr(snm); nr.sym = intern(l, nm); }; }; @@ -3517,7 +3421,6 @@ package w6l; import os; import rt; -import mem; import strings; import sym; @@ -3612,7 +3515,7 @@ fn dcstrlen(p: *u8) u64 = { return n; }; -fn dcstrtostr(a: *arena, p: *u8) str = { +fn dcstrtostr(p: *u8) str = { let n: u64 = dcstrlen(p); let view: str; view.ptr = p; @@ -3800,7 +3703,7 @@ export fn loadso(l: *lnk, path: *u8) i32 = { // Build the lso. Exports are appended in dynsym order so // soprovides_v's first-match semantics match the C version. - let so: *lso = alloc(lso { path = dcstrtostr(l.a, path), soname = dcstrtostr(l.a, sonamecs) })!; + let so: *lso = alloc(lso { path = dcstrtostr(path), soname = dcstrtostr(sonamecs) })!; let tail: *lexport = nil; let si: u64 = 1u64; @@ -3852,9 +3755,9 @@ export fn loadso(l: *lnk, path: *u8) i32 = { }; if (keep != 0) { - let e: *lexport = alloc(lexport { name = dcstrtostr(l.a, nmp) })!; + let e: *lexport = alloc(lexport { name = dcstrtostr(nmp) })!; if (vernamecs != nil) { - e.version = dcstrtostr(l.a, vernamecs); + e.version = dcstrtostr(vernamecs); }; if (tail == nil) { so.exports = e; @@ -3934,7 +3837,7 @@ def R_X86_64_PC32: i32 = 2; def R_X86_64_PLT32: i32 = 4; export fn resolve(l: *lnk) i32 = { - // Initialise dynamic-linking sentinels. amalloc zeroes, so + // Initialise dynamic-linking sentinels. alloc(T{})! zeroes, so // isdyn/dynlib start clean — but pltidx and dynsymidx // must be -1, not 0. let si: *lsym = l.syms; @@ -4074,7 +3977,6 @@ package w6l; import os; import rt; -import mem; import sym; // ELF constants @@ -4218,7 +4120,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = { // Placed after .dynamic so the segment is one contiguous run; // relocate runs from here so the dyn layout's datava lands in // patched offsets. - let a: *arena = l.a; let n: i32 = l.dynn; let nu: u64 = n: u64; @@ -4996,7 +4897,6 @@ package main; import os; import rt; -import mem; import sym; import obj; import dyn; @@ -5006,8 +4906,8 @@ import out; def BASE: u64 = 4194304u64; // 0x400000 def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000 -fn mklnk(a: *arena) *lnk = { - let l: *lnk = alloc(lnk { a = a })!; +fn mklnk() *lnk = { + let l: *lnk = alloc(lnk { })!; return l; }; @@ -5114,9 +5014,9 @@ fn islinkable(path: *u8) bool = { }; // Walk libdirs[0..n) trying lib.so, then lib.so.{0..8}, -// then lib.a. Return arena-owned NUL-terminated path on success, -// nil on miss. -fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = { +// then lib.a. Return a heap-allocated NUL-terminated path on +// success, nil on miss. +fn resolvelib(name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = { let bufp: []u8 = alloc([], 1024u64)!; bufp.len = 1024; let i: i32 = 0; @@ -5254,8 +5154,7 @@ export fn main(argc: i32, argv: **u8) i32 = { return 2; }; - let a: *arena = newarena(); - let l: *lnk = mklnk(a); + let l: *lnk = mklnk(); // Seed _start so libwwrt-style start.o is recognised as wanted. intern(l, "_start"); @@ -5273,7 +5172,7 @@ export fn main(argc: i32, argv: **u8) i32 = { // objects register their exports. let lf: i32 = 0; for (lf < nlflags) { - let p: *u8 = resolvelib(a, lflags[lf], libdirs.ptr, nlibdirs); + let p: *u8 = resolvelib(lflags[lf], libdirs.ptr, nlibdirs); if (p == nil) { os.write(2, "w6l: cannot find -l".ptr, 18u64); let nm: *u8 = lflags[lf]; diff --git a/selfhost/cmd/w6l/main.ww b/selfhost/cmd/w6l/main.ww index 797b00c6..9c428c06 100644 --- a/selfhost/cmd/w6l/main.ww +++ b/selfhost/cmd/w6l/main.ww @@ -10,7 +10,6 @@ package main; import os; import rt; -import mem; import sym; import obj; import dyn; @@ -20,8 +19,8 @@ import out; def BASE: u64 = 4194304u64; // 0x400000 def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000 -fn mklnk(a: *arena) *lnk = { - let l: *lnk = alloc(lnk { a = a })!; +fn mklnk() *lnk = { + let l: *lnk = alloc(lnk { })!; return l; }; @@ -128,9 +127,9 @@ fn islinkable(path: *u8) bool = { }; // Walk libdirs[0..n) trying lib.so, then lib.so.{0..8}, -// then lib.a. Return arena-owned NUL-terminated path on success, -// nil on miss. -fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = { +// then lib.a. Return a heap-allocated NUL-terminated path on +// success, nil on miss. +fn resolvelib(name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = { let bufp: []u8 = alloc([], 1024u64)!; bufp.len = 1024; let i: i32 = 0; @@ -268,8 +267,7 @@ export fn main(argc: i32, argv: **u8) i32 = { return 2; }; - let a: *arena = newarena(); - let l: *lnk = mklnk(a); + let l: *lnk = mklnk(); // Seed _start so libwwrt-style start.o is recognised as wanted. intern(l, "_start"); @@ -287,7 +285,7 @@ export fn main(argc: i32, argv: **u8) i32 = { // objects register their exports. let lf: i32 = 0; for (lf < nlflags) { - let p: *u8 = resolvelib(a, lflags[lf], libdirs.ptr, nlibdirs); + let p: *u8 = resolvelib(lflags[lf], libdirs.ptr, nlibdirs); if (p == nil) { os.write(2, "w6l: cannot find -l".ptr, 18u64); let nm: *u8 = lflags[lf]; diff --git a/selfhost/cmd/w6l/obj.ww b/selfhost/cmd/w6l/obj.ww index 0e82724f..c2392ec2 100644 --- a/selfhost/cmd/w6l/obj.ww +++ b/selfhost/cmd/w6l/obj.ww @@ -12,7 +12,6 @@ package w6l; import os; import rt; -import mem; import strings; import sym; @@ -158,7 +157,7 @@ fn cstrlen(p: *u8) u64 = { return n; }; -// pathstr — view a NUL-terminated *u8 as a str. Bridges argv/arena +// pathstr — view a NUL-terminated *u8 as a str. Bridges argv-style // callers to lib/os entrypoints (str post-task-#23). Shared with // main.ww and dyn.ww via the w6l bundle. fn pathstr(p: *u8) str = { @@ -181,7 +180,7 @@ fn cstreq(p: *u8, lit: str) bool = { }; // Build a ww str from a NUL-terminated *u8 (for passing to intern). -fn cstrtostr(a: *arena, p: *u8) str = { +fn cstrtostr(p: *u8) str = { let n: u64 = cstrlen(p); let view: str; view.ptr = p; @@ -201,7 +200,7 @@ type defent = struct { }; type armember = struct { - data: *u8, // arena copy of the member's ELF bytes + data: *u8, // owned heap copy of the member's ELF bytes size: u64, defs: *defent, // linked list of defined globals loaded: i32, @@ -236,9 +235,9 @@ fn arfield(p: *u8, n: u64) u64 = { }; // elfglobals — return a linked list of names of globally-defined -// (STB_GLOBAL) symbols whose section is `.text`. Names are arena -// copies, so the source ELF buffer can be freed afterward. -fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = { +// (STB_GLOBAL) symbols whose section is `.text`. Names are owned +// heap copies, so the source ELF buffer can be freed afterward. +fn elfglobals(buf: *u8, len: u64) *defent = { if (len < EHDR_SIZE) { return nil; }; if (buf[0u64] != 127u8) { return nil; }; if (buf[1u64] != 69u8) { return nil; }; @@ -302,7 +301,7 @@ fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = { if (intext || indt) { let nmp: *u8 = strtab + (stname: u64); if (nmp[0u64] != 0u8) { - let nm: str = cstrtostr(a, nmp); + let nm: str = cstrtostr(nmp); let de: *defent = alloc(defent { name = nm, dnext = head })!; head = de; }; @@ -355,7 +354,7 @@ fn loadarchive(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { i += 1u64; }; m.data = mb; - m.defs = elfglobals(l.a, mb, hdrsize); + m.defs = elfglobals(mb, hdrsize); if (head == nil) { head = m; } else { tail.mnext = m; }; tail = m; @@ -473,7 +472,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { // Track this object. let ob: *lobj = alloc(lobj { - path = cstrtostr(l.a, path), + path = cstrtostr(path), buf = buf, len = len, textoff = l.textlen, @@ -504,7 +503,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { let stvalue: u64 = rdu64(buf, symp + SYM_VALUE); let nmp: *u8 = strtab + (stname: u64); if (nmp[0u64] != 0u8) { - let nm: str = cstrtostr(l.a, nmp); + let nm: str = cstrtostr(nmp); let gs: *lsym = intern(l, nm); if (stshndx != 0u16) { let intext: bool = (stshndx: i32) == idxtext; @@ -568,7 +567,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { let sname: u32 = rdu32(buf, sp + SYM_NAME); let snm: *u8 = strtab + (sname: u64); if (snm[0u64] != 0u8) { - let nm: str = cstrtostr(l.a, snm); + let nm: str = cstrtostr(snm); nr.sym = intern(l, nm); }; }; @@ -604,7 +603,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = { let sname: u32 = rdu32(buf, sp + SYM_NAME); let snm: *u8 = strtab + (sname: u64); if (snm[0u64] != 0u8) { - let nm: str = cstrtostr(l.a, snm); + let nm: str = cstrtostr(snm); nr.sym = intern(l, nm); }; }; diff --git a/selfhost/cmd/w6l/pass.ww b/selfhost/cmd/w6l/pass.ww index d4b34d9c..928e883d 100644 --- a/selfhost/cmd/w6l/pass.ww +++ b/selfhost/cmd/w6l/pass.ww @@ -21,7 +21,7 @@ def R_X86_64_PC32: i32 = 2; def R_X86_64_PLT32: i32 = 4; export fn resolve(l: *lnk) i32 = { - // Initialise dynamic-linking sentinels. amalloc zeroes, so + // Initialise dynamic-linking sentinels. alloc(T{})! zeroes, so // isdyn/dynlib start clean — but pltidx and dynsymidx // must be -1, not 0. let si: *lsym = l.syms; diff --git a/selfhost/cmd/w6l/sym.ww b/selfhost/cmd/w6l/sym.ww index c6a3c5a2..1cefcb19 100644 --- a/selfhost/cmd/w6l/sym.ww +++ b/selfhost/cmd/w6l/sym.ww @@ -5,8 +5,6 @@ package w6l; -import mem; - type lsym = struct { name: str, val: u64, // offset within combined .text (or .data when @@ -63,7 +61,6 @@ type lso = struct { }; type lnk = struct { - a: *arena, objs: *lobj, sos: *lso, syms: *lsym,