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:
@@ -4132,7 +4132,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* `alloc` shadows the builtin (task #23).
|
||||
*
|
||||
* Result is the graduated `(*T | nomem)` tagged-pointer
|
||||
* ABI (AX=tag, DX=ptr) — task #30. rt_alloc returns 0
|
||||
* ABI (AX=tag, DX=ptr) — task #30. rt_malloc returns 0
|
||||
* on OOM (rt/alloc.s); we branch on AX, building tag=1
|
||||
* (nomem, DX=0) on null and tag=0 (success, DX=ptr)
|
||||
* after the value-init stores complete. Callers wrap
|
||||
@@ -4146,7 +4146,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
char *alloc_ok = mklabel(c, "alloc_ok");
|
||||
char *alloc_done = mklabel(c, "alloc_done");
|
||||
ins2(c, A_MOVQ, aimm(sz), areg(D_DI));
|
||||
ins1(c, A_CALL, asym(ffi_resolve("alloc")));
|
||||
ins1(c, A_CALL, asym(ffi_resolve("malloc")));
|
||||
ins2(c, A_CMPQ, aimm(0), areg(D_AX));
|
||||
ins1(c, A_JNE, abranch(alloc_ok));
|
||||
ins2(c, A_MOVQ, aimm(1), areg(D_AX));
|
||||
@@ -6403,7 +6403,7 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
ins2(c, A_IMULQ, areg(D_BX), areg(D_AX));
|
||||
}
|
||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_DI));
|
||||
ins1(c, A_CALL, asym(ffi_resolve("alloc")));
|
||||
ins1(c, A_CALL, asym(ffi_resolve("malloc")));
|
||||
if (via_tryunw) {
|
||||
char *ok = mklabel(c, "tryunw_ok");
|
||||
ins2(c, A_CMPQ, aimm(0), areg(D_AX));
|
||||
|
||||
@@ -968,16 +968,13 @@ cexpr(Checker *c, Node *n)
|
||||
return n->type;
|
||||
}
|
||||
/* `alloc(value)` Hare-style builtin — suppressed when the
|
||||
* current module declares its own `alloc` (lib/os/os.ww,
|
||||
* rt/ensure.ww). Without the gate, the bare same-module call
|
||||
* lands in the typed-builtin path and silently allocates
|
||||
* sizeof(arg-type) bytes against rt_alloc, shadowing the
|
||||
* user decl. Strict same-module check (not scope_lookup_prefer):
|
||||
* `use os;` in a primary brings os.alloc into the flat scope
|
||||
* as a fallback match — that's what the `abort` precedent
|
||||
* sidesteps by leaving os.abort un-exported, but os.alloc IS
|
||||
* exported. c->cur_mod==NULL is the primary unit; gate only
|
||||
* fires when a same-module decl is registered. Task #23. */
|
||||
* current module declares its own `alloc` (user shadow, task
|
||||
* #23). Strict same-module check (not scope_lookup_prefer):
|
||||
* `import rt;` brings rt.malloc into a separate qualified
|
||||
* scope, not flat — only a same-module `fn alloc` registers
|
||||
* here. The Hare builtin name is `alloc` (ref/hare/hare/lex/
|
||||
* token.ha:21, ltok::ALLOC); a hypothetical user `fn malloc`
|
||||
* does not shadow it. Task #23. */
|
||||
if (n->lhs && n->lhs->kind == N_IDENT &&
|
||||
n->lhs->str && strcmp(n->lhs->str, "alloc") == 0 &&
|
||||
n->list != NULL && n->list->next == NULL &&
|
||||
@@ -987,7 +984,7 @@ cexpr(Checker *c, Node *n)
|
||||
Type *def = type_default(t);
|
||||
Type *pt = type_ptr(c->a, def ? def : ty_void);
|
||||
/* Task #30 — graduate to Hare's `(*T | nomem)` shape;
|
||||
* the cgen branches on rt_alloc's null return to emit
|
||||
* the cgen branches on rt_malloc's null return to emit
|
||||
* the nomem variant. Two-variant union with TY_PTR +
|
||||
* TY_NAMED(nomem) does not trip the nullable-pointer
|
||||
* fold (#25), so the result rides the general AX=tag,
|
||||
@@ -1053,7 +1050,7 @@ cexpr(Checker *c, Node *n)
|
||||
/* alloc([], n) — Hare-style fresh slice with cap n. We pin
|
||||
* the element type to u8 by default; the caller's declared
|
||||
* slice type drives the actual element size at codegen.
|
||||
* Same scope_lookup_in_module gate as the value-form (#23). */
|
||||
* Same single-key `alloc` gate as the value-form above. */
|
||||
if (n->lhs && n->lhs->kind == N_IDENT &&
|
||||
n->lhs->str && strcmp(n->lhs->str, "alloc") == 0 &&
|
||||
n->list && n->list->kind == N_ARRLIT &&
|
||||
|
||||
Reference in New Issue
Block a user