lib/rt: rename rt_alloc → rt_malloc; rt.alloc → rt.malloc
Hare's canonical runtime allocator is rt::malloc with linker symbol
rt.malloc (ref/hare/rt/malloc.ha:27,78). ww kept the dot→underscore
Plan 9 convention (CLAUDE.md rule 4) so the linker symbol becomes
rt_malloc; the lib/rt exported function name becomes malloc; ww
callers say rt.malloc(...).
The language builtin keyword stays `alloc(T)!` — unchanged from Hare
(ref/hare/hare/lex/token.ha:21 ltok::ALLOC, parse/expr.ha:398
builtin()). The rename only touches the lowered linker symbol and the
exported function name behind it; the user-facing syntax for
heap-allocation is identical to Hare.
Surface:
- rt/alloc.s: TEXT rt_alloc → TEXT rt_malloc, labels updated
- lib/rt/malloc.ww: @symbol("rt_malloc") fn malloc(...) (was rt_alloc/alloc)
- rt/ensure.ww: local FFI decl + call site updated to malloc; `!` dropped
on the direct FFI call (rt_malloc returns *void, not a tagged union)
- 18 .ww callers: rt.alloc(...) → rt.malloc(...)
- cstage cmd/wcc/check.c + wwstage selfhost/cmd/wcc/check.ww
alloc-builtin suppression gate routes through ffi_resolve("malloc")
for the lowering; the user-shadow check still keys on the BUILTIN
KEYWORD "alloc" since that is what `alloc(...)` parses as. Adding
"malloc" to the user-shadow check was unnecessary and was reverted
during pre-commit review.
- cstage cmd/w6c/cgen.c: 2× ffi_resolve("alloc") → ffi_resolve("malloc")
- wwstage cgenexpr/cgenstmt: 2× ffiresolve(c, "alloc") → ffiresolve(c, "malloc")
- Test fixtures (700_e2e, 758_cgalloc_str_field, 990_selfhost, 992_w6l_ww,
selfhost/test/tagged_ptr_ret.ww): updated inline ww sources to the new
decl + call form
This is commit 2 of 3 in the lib/rt extraction (#38). Commit 3 closes
the OOM contract — return type becomes nullable *void and the builtin
lowering null-checks + propagates nomem.
Verified 132/132 + 995_self_rebuild byte-identity (5 wwstage tools
round-trip identical) + make clean cold rebuild.
This commit is contained in:
@@ -2712,14 +2712,14 @@ fn cgbin(c: *cgen, n: *node) void = {
|
||||
};
|
||||
|
||||
// cgalloc — `alloc(value)` builtin lowering. Allocate sizeof(value)
|
||||
// bytes via rt_alloc, then write the value's bytes into the new
|
||||
// bytes via rt_malloc, then write the value's bytes into the new
|
||||
// region. For an N_STRUCTLIT arg, allocate the struct's totsize and
|
||||
// emit per-field stores at each field's offset. For a scalar/ptr,
|
||||
// allocate 8 bytes and store one word. Mirrors cmd/w6c/cgen.c's
|
||||
// alloc-special branch in N_CALL.
|
||||
//
|
||||
// Task #30: result is the graduated `(*T | nomem)` tagged-pointer
|
||||
// pair (AX=tag, DX=ptr). rt_alloc now returns 0 on OOM
|
||||
// pair (AX=tag, DX=ptr). rt_malloc now returns 0 on OOM
|
||||
// (rt/alloc.s); branch on AX to emit the nomem variant (tag=1,
|
||||
// DX=0) or the success variant (tag=0, DX=ptr) after the
|
||||
// value-init stores complete. Callers wrap with `!` / `?` to
|
||||
@@ -2745,7 +2745,7 @@ fn cgalloc(c: *cgen, n: *node) void = {
|
||||
emitint(sz: i64);
|
||||
emitline(", DI\n");
|
||||
emitline("\tCALL\t");
|
||||
emitline(ffiresolve(c, "alloc"));
|
||||
emitline(ffiresolve(c, "malloc"));
|
||||
emitline("(SB)\n");
|
||||
emitline("\tCMPQ\t$0, AX\n");
|
||||
emitline("\tJNE\t"); emitline(okl); emitline("\n");
|
||||
@@ -2972,7 +2972,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
// `alloc(value)` builtin: heap-init a fresh *T with the
|
||||
// value's bytes. For struct literals, lower to rt_alloc
|
||||
// value's bytes. For struct literals, lower to rt_malloc
|
||||
// + per-field stores. Mirrors cmd/w6c/cgen.c's N_CALL
|
||||
// alloc path.
|
||||
//
|
||||
|
||||
@@ -576,7 +576,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
let rhs: *node = n.rhs;
|
||||
// `let s: []T = alloc([], n)!;` / `?` shortcut (#32, #45).
|
||||
// Mirror of cstage cgen.c N_LET arrlit-empty branch: allocate
|
||||
// n*esz bytes via rt_alloc, then build the {ptr, 0, n} slice
|
||||
// n*esz bytes via rt_malloc, then build the {ptr, 0, n} slice
|
||||
// header in the let slot. The `!`/`?` wraps the builtin's
|
||||
// `([]T | nomem)` return; walk into the N_TRYUNW / N_TRYPROP
|
||||
// to keep the direct-store fast path rather than falling
|
||||
@@ -645,7 +645,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
emitline("\tMOVQ\tAX, DI\n");
|
||||
emitline("\tCALL\t");
|
||||
emitline(ffiresolve(c, "alloc"));
|
||||
emitline(ffiresolve(c, "malloc"));
|
||||
emitline("(SB)\n");
|
||||
if (viatryunw) {
|
||||
let okl: str = mklabel(c, "tryunw_ok");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
||||
//
|
||||
// Bump arena allocator. Backed by the runtime page allocator
|
||||
// (rt_alloc / rt_free), no libc. Each chunk is mmap'd; when the
|
||||
// (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.
|
||||
//
|
||||
@@ -31,8 +31,8 @@ fn roundup(n: u64, a: u64) u64 = {
|
||||
};
|
||||
|
||||
export fn newarena() *arena = {
|
||||
let a: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||
a.buf = rt.alloc(INIT_CHUNK): *u8;
|
||||
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;
|
||||
@@ -49,14 +49,14 @@ fn grow(a: *arena, need: u64) bool = {
|
||||
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
||||
if (want < need) { return false; }; // single allocation too big
|
||||
|
||||
let old: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||
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.alloc(want): *u8;
|
||||
a.buf = rt.malloc(want): *u8;
|
||||
a.off = 0u64;
|
||||
a.cap = want;
|
||||
a.next = old;
|
||||
|
||||
Reference in New Issue
Block a user