From 5408160d49d2850d6b7cfd43de07b463f79343c2 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 11 May 2026 16:56:46 +0900 Subject: [PATCH] rt: move slice append helpers from lib/slices/ into libwwrt.a --- Makefile | 11 ++++++++++- lib/slices/slices.ww => rt/append.ww | 22 +++++++++++----------- test/wcc/700_e2e.c | 22 ++-------------------- test/wcc/900_stdlib.c | 1 - test/wcc/990_selfhost.c | 1 - 5 files changed, 23 insertions(+), 34 deletions(-) rename lib/slices/slices.ww => rt/append.ww (51%) diff --git a/Makefile b/Makefile index 6da86e5a..b3536ca6 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,8 @@ W6L_SRC = cmd/w6l/main.c cmd/w6l/obj.c cmd/w6l/sym.c cmd/w6l/pass.c cmd/w6l/out. W6L_OBJ = $(W6L_SRC:cmd/w6l/%.c=$(OBJ)/w6l/%.o) RT_S = rt/start.s rt/syscall.s rt/alloc.s rt/streq.s rt/abort.s -RT_OBJ = $(RT_S:rt/%.s=$(OBJ)/rt/%.o) +RT_WW = rt/append.ww +RT_OBJ = $(RT_S:rt/%.s=$(OBJ)/rt/%.o) $(RT_WW:rt/%.ww=$(OBJ)/rt/%.o) # Cstage: one-time C bootstrap (see BOOTSTRAP.md). Built by `cc`. # Goes away at v1.0, replaced by a checked-in stage-0 binary. @@ -191,6 +192,14 @@ $(BIN)/ww_ww: selfhost/cmd/ww/main.ww selfhost/cmd/wcc/mem.ww lib/os/os.ww \ $(OBJ)/rt/%.o: rt/%.s $(BIN)/w6a | $(OBJ)/rt $(BIN)/w6a -o $@ $< +# ww-side runtime helpers (rt/*.ww): compile via w6c to .s, then w6a. +# Each .ww module is standalone — uses @symbol FFI for rt_alloc/rt_free +# rather than `use os;` so no bundling is required. +$(OBJ)/rt/%.s: rt/%.ww $(BIN)/w6c | $(OBJ)/rt + $(BIN)/w6c $< > $@ +$(OBJ)/rt/%.o: $(OBJ)/rt/%.s $(BIN)/w6a | $(OBJ)/rt + $(BIN)/w6a -o $@ $< + $(LIB)/libwwrt.a: $(RT_OBJ) | $(LIB) $(AR) rcs $@ $(RT_OBJ) diff --git a/lib/slices/slices.ww b/rt/append.ww similarity index 51% rename from lib/slices/slices.ww rename to rt/append.ww index 2a8d763c..312f2567 100644 --- a/lib/slices/slices.ww +++ b/rt/append.ww @@ -1,25 +1,25 @@ -// slices — generic slice helpers, written without generics. +// rt/append.ww — slice runtime helpers, archived into libwwrt.a. // -// CLAUDE.md forbids generics, so we mint per-element-type variants. -// Hare's `append` builtin is what these stand in for: each takes a -// *[]T plus an item, grows the storage if needed, and updates the -// slice header in place. The user passes `&s` because we mutate -// through the pointer. +// The compiler lowers `append(s, v)` to a CALL to one of these by +// element size (1 byte → appendu8, else → appendi64). User code +// never `use`s this — the symbol comes in via the runtime archive, +// like rt_alloc and rt_streq. -use os; +@symbol("rt_alloc") fn alloc(n: u64) *void; +@symbol("rt_free") fn free(p: *void, n: u64) void; export fn appendu8(s: *[]u8, v: u8) void = { if (s.len >= s.cap) { let nc: i32 = s.cap * 2; if (nc < 8) { nc = 8; }; - let np: *u8 = os.alloc(nc: u64): *u8; + let np: *u8 = alloc(nc: u64): *u8; let i: i32 = 0; for (i < s.len) { np[i] = s.ptr[i]; i += 1; }; if (s.cap > 0) { - os.free(s.ptr: *void, s.cap: u64); + free(s.ptr: *void, s.cap: u64); }; s.ptr = np; s.cap = nc; @@ -32,14 +32,14 @@ export fn appendi64(s: *[]i64, v: i64) void = { if (s.len >= s.cap) { let nc: i32 = s.cap * 2; if (nc < 8) { nc = 8; }; - let np: *i64 = os.alloc((nc * 8): u64): *i64; + let np: *i64 = alloc((nc * 8): u64): *i64; let i: i32 = 0; for (i < s.len) { np[i] = s.ptr[i]; i += 1; }; if (s.cap > 0) { - os.free(s.ptr: *void, (s.cap * 8): u64); + free(s.ptr: *void, (s.cap * 8): u64); }; s.ptr = np; s.cap = nc; diff --git a/test/wcc/700_e2e.c b/test/wcc/700_e2e.c index e63f6c4b..7ddf84d1 100644 --- a/test/wcc/700_e2e.c +++ b/test/wcc/700_e2e.c @@ -244,24 +244,10 @@ static const struct row rows[] = { " x *= 2; x <<= 1; x >>= 2;\n" " return x;\n" "};", 96 }, - /* user-defined slice append via *[]u8: stdlib slices.appendu8. - * Demonstrates allocator + ptr-to-slice fields + scaled index write. */ - { "use os;\n" - "use slices;\n" - "fn main() i32 = {\n" - " let s: []u8;\n" - " s.ptr = nil; s.len = 0; s.cap = 0;\n" - " slices.appendu8(&s, 65u8);\n" - " slices.appendu8(&s, 66u8);\n" - " slices.appendu8(&s, 67u8);\n" - " os.write(1, s.ptr, s.len: u64);\n" - " os.write(1, \"\\n\".ptr, 1u64);\n" - " return s.len;\n" - "};", 3 }, /* Hare-style builtins: append(s, v) and len(s). The compiler - * lowers these to slices.appendu8 / s.len access. */ + * lowers append to a CALL into libwwrt.a's appendu8 / appendi64 + * by element size — no `use rt;` or `use slices;` required. */ { "use os;\n" - "use slices;\n" "fn main() i32 = {\n" " let s: []u8;\n" " s.ptr = nil; s.len = 0; s.cap = 0;\n" @@ -281,7 +267,6 @@ static const struct row rows[] = { "};", 12 }, /* variadic append + static qualifier (Hare idiom) */ { "use os;\n" - "use slices;\n" "fn main() i32 = {\n" " let s: []u8;\n" " s.ptr = nil; s.len = 0; s.cap = 0;\n" @@ -298,7 +283,6 @@ static const struct row rows[] = { "};", 25 }, /* Hare-style range loop: for (let x .. slice) iterates elements */ { "use os;\n" - "use slices;\n" "fn main() i32 = {\n" " let s: []u8;\n" " s.ptr = nil; s.len = 0; s.cap = 0;\n" @@ -309,7 +293,6 @@ static const struct row rows[] = { "};", 100 }, /* alloc([], n): fresh empty slice with cap n */ { "use os;\n" - "use slices;\n" "fn main() i32 = {\n" " let s: []u8 = alloc([], 16);\n" " append(s, 72u8, 105u8);\n" @@ -317,7 +300,6 @@ static const struct row rows[] = { "};", 16 }, /* variadic spread: append(dst, src...) iterates src */ { "use os;\n" - "use slices;\n" "fn main() i32 = {\n" " let src: []u8;\n" " src.ptr = nil; src.len = 0; src.cap = 0;\n" diff --git a/test/wcc/900_stdlib.c b/test/wcc/900_stdlib.c index a62e4238..3ed5d942 100644 --- a/test/wcc/900_stdlib.c +++ b/test/wcc/900_stdlib.c @@ -28,7 +28,6 @@ static const char *modules[] = { "lib/bufio/bufio.ww", "lib/fmt/fmt.ww", "lib/net/net.ww", - "lib/slices/slices.ww", NULL }; diff --git a/test/wcc/990_selfhost.c b/test/wcc/990_selfhost.c index 46191916..28e5a712 100644 --- a/test/wcc/990_selfhost.c +++ b/test/wcc/990_selfhost.c @@ -210,7 +210,6 @@ probe_dump_diff(const char *bin) "lib/types/types.ww", "lib/sort/sort.ww", "lib/path/path.ww", - "lib/slices/slices.ww", "lib/net/net.ww", "lib/encoding/utf8/utf8.ww", "lib/encoding/hex/hex.ww",