selfhost/cmd/wcc: delete mem.ww (γ-7, Phase 0 close)

mem.ww has 0 callers post-γ-6 — newarena/amalloc/grow/freearena/
roundup all unreferenced after the *arena cascade strip. Drop the
91-line module.

Makefile: remove mem.ww from 5 dep lists (wwdump_ww, w6c_ww,
w6a_ww, w6l_ww, ww_ww); drop `-I selfhost/cmd/wcc` from w6a_ww/
w6l_ww/ww_ww build invocations (wwdump_ww + w6c_ww still need it
for check.ww/cgen*.ww).

test/wcc/990_selfhost.c: drop 6 mem.ww entries from probe_codegen,
probe_dump_diff (×2), probe_resolve, probe_dump_stable, and
probe_cgen_match file lists.

lib/memio/memio.ww: dynamicgrow doc comment reframed as historical
context (collision source is gone, but task #9 keeps the
module-prefixed name conservative against future collisions).

Two dead `import mem;` lines remain in selfhost/cmd/w6a/asm.ww and
selfhost/test/uses.ww; tolerated silently by ww build, swept in
task #8.

main.combined.ww auto-regenerated for w6a/w6c/wwdump.

Verified 132/132 incl. 994_w6c_ww + 995_self_rebuild byte-identity.
Phase 0 closes.
This commit is contained in:
2026-05-21 13:24:27 +09:00
parent 353dffb5e8
commit 17765942f9
7 changed files with 24 additions and 217 deletions

View File

@@ -104,12 +104,12 @@ $(OBJ)/w6l/%.o: cmd/w6l/%.c cmd/w6l/l.h | $(OBJ)/w6l
# ---- ww-side wwdump (the lexer port, exercised by 990_selfhost) -------- # ---- ww-side wwdump (the lexer port, exercised by 990_selfhost) --------
# Built via the user-facing ww driver. The introspection ports (lex, # Built via the user-facing ww driver. The introspection ports (lex,
# tok, ast, parse, typ, sym) live in lib/ww/; the compiler-only bits # tok, ast, parse, typ, sym) live in lib/ww/; the compiler-only bits
# (mem, check, cgen*) stay in selfhost/cmd/wcc/. Output named wwdump_ww # (check, cgen*) stay in selfhost/cmd/wcc/. Output named wwdump_ww
# to avoid colliding with the C-side wwdump in $(BIN). # to avoid colliding with the C-side wwdump in $(BIN).
$(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \ $(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
lib/ww/lex/lex.ww lib/ww/lex/tok.ww lib/ww/ast.ww \ lib/ww/lex/lex.ww lib/ww/lex/tok.ww lib/ww/ast.ww \
lib/ww/parse/parse.ww lib/ww/parse/expr.ww lib/ww/parse/stmt.ww lib/ww/parse/decl.ww lib/ww/typ.ww lib/ww/sym.ww \ lib/ww/parse/parse.ww lib/ww/parse/expr.ww lib/ww/parse/stmt.ww lib/ww/parse/decl.ww lib/ww/typ.ww lib/ww/sym.ww \
selfhost/cmd/wcc/mem.ww selfhost/cmd/wcc/check.ww \ selfhost/cmd/wcc/check.ww \
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \ selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \ selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
selfhost/cmd/wcc/cgendecl.ww \ selfhost/cmd/wcc/cgendecl.ww \
@@ -131,7 +131,7 @@ $(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
$(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \ $(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
lib/ww/lex/lex.ww lib/ww/lex/tok.ww lib/ww/ast.ww \ lib/ww/lex/lex.ww lib/ww/lex/tok.ww lib/ww/ast.ww \
lib/ww/parse/parse.ww lib/ww/parse/expr.ww lib/ww/parse/stmt.ww lib/ww/parse/decl.ww lib/ww/typ.ww lib/ww/sym.ww \ lib/ww/parse/parse.ww lib/ww/parse/expr.ww lib/ww/parse/stmt.ww lib/ww/parse/decl.ww lib/ww/typ.ww lib/ww/sym.ww \
selfhost/cmd/wcc/mem.ww selfhost/cmd/wcc/check.ww \ selfhost/cmd/wcc/check.ww \
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \ selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \ selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
selfhost/cmd/wcc/cgendecl.ww \ selfhost/cmd/wcc/cgendecl.ww \
@@ -149,48 +149,44 @@ $(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
# ---- ww-side w6a (assembler port, exercised by 991_w6a_ww) ------------ # ---- ww-side w6a (assembler port, exercised by 991_w6a_ww) ------------
# Built like wwdump_ww. Needs -I selfhost/cmd/w6a for the local types/lex/ # Built like wwdump_ww. Needs -I selfhost/cmd/w6a for the local types/lex/
# parse/asm/obj modules and -I selfhost/cmd/wcc to find `mem`. # parse/asm/obj modules.
$(BIN)/w6a_ww: selfhost/cmd/w6a/main.ww selfhost/cmd/w6a/opcodes.ww \ $(BIN)/w6a_ww: selfhost/cmd/w6a/main.ww selfhost/cmd/w6a/opcodes.ww \
selfhost/cmd/w6a/lex.ww selfhost/cmd/w6a/parse.ww \ selfhost/cmd/w6a/lex.ww selfhost/cmd/w6a/parse.ww \
selfhost/cmd/w6a/asm.ww selfhost/cmd/w6a/obj.ww \ selfhost/cmd/w6a/asm.ww selfhost/cmd/w6a/obj.ww \
selfhost/cmd/wcc/mem.ww \
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww \ lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN) $(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/w6a_ww.d @mkdir -p $(BIN)/w6a_ww.d
cd $(BIN)/w6a_ww.d && $(CURDIR)/$(BIN)/ww build \ cd $(BIN)/w6a_ww.d && $(CURDIR)/$(BIN)/ww build \
-I $(CURDIR)/selfhost/cmd/w6a \ -I $(CURDIR)/selfhost/cmd/w6a \
-I $(CURDIR)/selfhost/cmd/wcc \
$(CURDIR)/selfhost/cmd/w6a/main.ww $(CURDIR)/selfhost/cmd/w6a/main.ww
mv $(BIN)/w6a_ww.d/main $@ mv $(BIN)/w6a_ww.d/main $@
# ---- ww-side w6l (linker port, exercised by 992_w6l_ww) --------------- # ---- ww-side w6l (linker port, exercised by 992_w6l_ww) ---------------
# Built like 6a_ww. Needs -I selfhost/cmd/w6l for the local sym/obj/pass/ # Built like 6a_ww. Needs -I selfhost/cmd/w6l for the local sym/obj/pass/
# out modules and -I selfhost/cmd/wcc to find `mem`. # out modules.
$(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \ $(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
selfhost/cmd/w6l/obj.ww selfhost/cmd/w6l/dyn.ww \ selfhost/cmd/w6l/obj.ww selfhost/cmd/w6l/dyn.ww \
selfhost/cmd/w6l/pass.ww selfhost/cmd/w6l/dynout.ww \ selfhost/cmd/w6l/pass.ww selfhost/cmd/w6l/dynout.ww \
selfhost/cmd/w6l/out.ww selfhost/cmd/wcc/mem.ww \ selfhost/cmd/w6l/out.ww \
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww \ lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN) $(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/w6l_ww.d @mkdir -p $(BIN)/w6l_ww.d
cd $(BIN)/w6l_ww.d && $(CURDIR)/$(BIN)/ww build \ cd $(BIN)/w6l_ww.d && $(CURDIR)/$(BIN)/ww build \
-I $(CURDIR)/selfhost/cmd/w6l \ -I $(CURDIR)/selfhost/cmd/w6l \
-I $(CURDIR)/selfhost/cmd/wcc \
$(CURDIR)/selfhost/cmd/w6l/main.ww $(CURDIR)/selfhost/cmd/w6l/main.ww
mv $(BIN)/w6l_ww.d/main $@ mv $(BIN)/w6l_ww.d/main $@
# ---- ww-side ww driver (exercised by 993_ww_ww) ------------------------ # ---- ww-side ww driver (exercised by 993_ww_ww) ------------------------
# The driver pulls in lib/os (default search path) and selfhost/cmd/wcc # The driver pulls in lib/os (default search path) and orchestrates
# (for the bump arena). It then orchestrates w6c/w6a/w6l like the C driver. # w6c/w6a/w6l like the C driver.
$(BIN)/ww_ww: selfhost/cmd/ww/main.ww selfhost/cmd/wcc/mem.ww lib/os/os.ww lib/rt/malloc.ww \ $(BIN)/ww_ww: selfhost/cmd/ww/main.ww lib/os/os.ww lib/rt/malloc.ww \
lib/time/time.ww lib/strconv/strconv.ww \ lib/time/time.ww lib/strconv/strconv.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN) $(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/ww_ww.d @mkdir -p $(BIN)/ww_ww.d
cd $(BIN)/ww_ww.d && $(CURDIR)/$(BIN)/ww build \ cd $(BIN)/ww_ww.d && $(CURDIR)/$(BIN)/ww build \
-I $(CURDIR)/selfhost/cmd/wcc \
$(CURDIR)/selfhost/cmd/ww/main.ww $(CURDIR)/selfhost/cmd/ww/main.ww
mv $(BIN)/ww_ww.d/main $@ mv $(BIN)/ww_ww.d/main $@

View File

@@ -195,11 +195,11 @@ fn closenoop(s: *io.stream) (void | io.closed) = {
// small write bursts without a tail of reallocs. // small write bursts without a tail of reallocs.
// //
// `dynamicgrow`, not Hare's bare `grow`: cstage bundles all imported // `dynamicgrow`, not Hare's bare `grow`: cstage bundles all imported
// modules into a flat TU and resolves private fns by unqualified // modules into a flat TU and resolves private fns by unqualified name,
// name, so two `fn grow` decls (here + selfhost/cmd/wcc/mem.ww's // so historically two `fn grow` decls (here + the now-deleted bump
// arena `grow`) collide. Module-prefixed name keeps the symmetry // arena's `grow`) would have collided. Module-prefixed name kept the
// with `dynamicwrite`/`dynamicclose` until task #9 (module-aware // symmetry with `dynamicwrite`/`dynamicclose`; retained pending task
// private-fn scoping in cstage) lands. // #9 (module-aware private-fn scoping in cstage).
fn dynamicgrow(m: *state, need: i32) void = { fn dynamicgrow(m: *state, need: i32) void = {
let newcap: i32 = m.cap; let newcap: i32 = m.cap;
if (newcap < 8) { newcap = 8; }; if (newcap < 8) { newcap = 8; };

View File

@@ -3555,98 +3555,6 @@ export fn parse(a: *asm_) i32 = {
return a.errs; return a.errs;
}; };
// 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/w6a/asm.ww — port of cmd/w6a/asm.c. // selfhost/cmd/w6a/asm.ww — port of cmd/w6a/asm.c.
// //
// Encode the parsed aprog list into amd64 machine bytes, appending to // Encode the parsed aprog list into amd64 machine bytes, appending to

View File

@@ -9291,11 +9291,11 @@ fn closenoop(s: *io.stream) (void | io.closed) = {
// small write bursts without a tail of reallocs. // small write bursts without a tail of reallocs.
// //
// `dynamicgrow`, not Hare's bare `grow`: cstage bundles all imported // `dynamicgrow`, not Hare's bare `grow`: cstage bundles all imported
// modules into a flat TU and resolves private fns by unqualified // modules into a flat TU and resolves private fns by unqualified name,
// name, so two `fn grow` decls (here + selfhost/cmd/wcc/mem.ww's // so historically two `fn grow` decls (here + the now-deleted bump
// arena `grow`) collide. Module-prefixed name keeps the symmetry // arena's `grow`) would have collided. Module-prefixed name kept the
// with `dynamicwrite`/`dynamicclose` until task #9 (module-aware // symmetry with `dynamicwrite`/`dynamicclose`; retained pending task
// private-fn scoping in cstage) lands. // #9 (module-aware private-fn scoping in cstage).
fn dynamicgrow(m: *state, need: i32) void = { fn dynamicgrow(m: *state, need: i32) void = {
let newcap: i32 = m.cap; let newcap: i32 = m.cap;
if (newcap < 8) { newcap = 8; }; if (newcap < 8) { newcap = 8; };

View File

@@ -1,91 +0,0 @@
// 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;
};
};

View File

@@ -9291,11 +9291,11 @@ fn closenoop(s: *io.stream) (void | io.closed) = {
// small write bursts without a tail of reallocs. // small write bursts without a tail of reallocs.
// //
// `dynamicgrow`, not Hare's bare `grow`: cstage bundles all imported // `dynamicgrow`, not Hare's bare `grow`: cstage bundles all imported
// modules into a flat TU and resolves private fns by unqualified // modules into a flat TU and resolves private fns by unqualified name,
// name, so two `fn grow` decls (here + selfhost/cmd/wcc/mem.ww's // so historically two `fn grow` decls (here + the now-deleted bump
// arena `grow`) collide. Module-prefixed name keeps the symmetry // arena's `grow`) would have collided. Module-prefixed name kept the
// with `dynamicwrite`/`dynamicclose` until task #9 (module-aware // symmetry with `dynamicwrite`/`dynamicclose`; retained pending task
// private-fn scoping in cstage) lands. // #9 (module-aware private-fn scoping in cstage).
fn dynamicgrow(m: *state, need: i32) void = { fn dynamicgrow(m: *state, need: i32) void = {
let newcap: i32 = m.cap; let newcap: i32 = m.cap;
if (newcap < 8) { newcap = 8; }; if (newcap < 8) { newcap = 8; };

View File

@@ -70,7 +70,6 @@ static int
probe_codegen(const char *bin) probe_codegen(const char *bin)
{ {
static const char *files[] = { static const char *files[] = {
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww", "selfhost/cmd/wcc/err.ww",
NULL, NULL,
}; };
@@ -169,7 +168,6 @@ static int
probe_dump_diff(const char *bin) probe_dump_diff(const char *bin)
{ {
const char *tok_inputs[] = { const char *tok_inputs[] = {
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww", "selfhost/cmd/wcc/err.ww",
"lib/ww/lex/lex.ww", "lib/ww/lex/lex.ww",
"lib/ww/lex/tok.ww", "lib/ww/lex/tok.ww",
@@ -187,7 +185,6 @@ probe_dump_diff(const char *bin)
const char *ast_inputs[] = { const char *ast_inputs[] = {
"selfhost/test/uses.ww", "selfhost/test/uses.ww",
"selfhost/cmd/wcc/err.ww", "selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/mem.ww",
"lib/ww/lex/lex.ww", "lib/ww/lex/lex.ww",
"lib/ww/lex/tok.ww", "lib/ww/lex/tok.ww",
"lib/ww/ast.ww", "lib/ww/ast.ww",
@@ -531,7 +528,6 @@ probe_resolve(const char *bin)
if (getcwd(cwd, sizeof cwd) == NULL) return -1; if (getcwd(cwd, sizeof cwd) == NULL) return -1;
const char *complete[] = { const char *complete[] = {
"selfhost/cmd/wcc/err.ww", "selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/mem.ww",
"lib/ww/lex/tok.ww", "lib/ww/lex/tok.ww",
"selfhost/test/smoke.ww", "selfhost/test/smoke.ww",
NULL, NULL,
@@ -560,7 +556,6 @@ probe_dump_stable(const char *bin)
char cwd[1024]; char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return -1; if (getcwd(cwd, sizeof cwd) == NULL) return -1;
const char *inputs[] = { const char *inputs[] = {
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww", "selfhost/cmd/wcc/err.ww",
"selfhost/test/smoke.ww", "selfhost/test/smoke.ww",
NULL, NULL,
@@ -812,7 +807,6 @@ static int
probe_cgen_match(const char *bin) probe_cgen_match(const char *bin)
{ {
const char *files[] = { const char *files[] = {
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww", "selfhost/cmd/wcc/err.ww",
"lib/ww/lex/tok.ww", "lib/ww/lex/tok.ww",
"selfhost/test/smoke.ww", "selfhost/test/smoke.ww",