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:
@@ -135,7 +135,7 @@ fn slurpso(path: *u8) (*u8, u64) = {
|
||||
case let v: i64 => n = v;
|
||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||
};
|
||||
let buf: *u8 = rt.alloc(n: u64): *u8;
|
||||
let buf: *u8 = rt.malloc(n: u64): *u8;
|
||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
||||
os.close(fd);
|
||||
let got: i64 = 0i64;
|
||||
|
||||
@@ -658,7 +658,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
};
|
||||
|
||||
// ---- assemble file buffer ----
|
||||
let filebuf: *u8 = rt.alloc(fileend): *u8;
|
||||
let filebuf: *u8 = rt.malloc(fileend): *u8;
|
||||
if (filebuf == nil) {
|
||||
os.write(2, "w6l: out of memory\n".ptr, 18u64);
|
||||
return 1;
|
||||
|
||||
@@ -438,7 +438,7 @@ export fn getdents64(fd: i32, buf: *u8, n: u64) i64 = {
|
||||
|
||||
// rt_envp — runtime-side getter. rt/start.s captures envp into a DATAW
|
||||
// slot before calling main; this binding lifts the captured pointer
|
||||
// into ww. Same FFI shape as rt_syscall / rt_alloc / rt_abort: a TEXT
|
||||
// into ww. Same FFI shape as rt_syscall / rt_malloc / rt_abort: a TEXT
|
||||
// symbol the linker resolves. The returned `**u8` is a NUL-terminated
|
||||
// table of `*u8` entries, each pointing at a NUL-terminated
|
||||
// "NAME=VALUE" byte sequence.
|
||||
@@ -732,7 +732,7 @@ export fn exists(path: str) bool = {
|
||||
|
||||
package rt;
|
||||
|
||||
// alloc — mmap-backed page allocator. Untyped: `alloc(n)` returns a
|
||||
// malloc — mmap-backed page allocator. Untyped: `malloc(n)` returns a
|
||||
// `*void`; callers cast to the target type. Diverges from Hare: Hare
|
||||
// exposes `alloc` / `free` as typed language builtins that the
|
||||
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
|
||||
@@ -740,20 +740,20 @@ package rt;
|
||||
// need a typed allocation pattern wrap this with a cast plus a stored
|
||||
// capacity (see [[strings.dup]], [[memio.dynamic]]).
|
||||
//
|
||||
// OOM: rt_alloc is a bare mmap(MAP_ANON|MAP_PRIVATE) wrapper with no
|
||||
// OOM: rt_malloc is a bare mmap(MAP_ANON|MAP_PRIVATE) wrapper with no
|
||||
// error path. The raw Linux mmap syscall returns a negative errno cast
|
||||
// to `*void` on failure (e.g. `(void*)-12` for ENOMEM); the
|
||||
// `MAP_FAILED` (`(void*)-1`) value is a libc-wrapper convention that
|
||||
// rt_alloc doesn't apply. Neither `== nil` nor `== (void*)-1` catches
|
||||
// rt_malloc doesn't apply. Neither `== nil` nor `== (void*)-1` catches
|
||||
// it; any deref of such a return faults. Today the stdlib does not
|
||||
// check; OOM faults on first dereference. A typed fallible variant is
|
||||
// a future task (task #39). ref/hare/rt/malloc.ha:27.
|
||||
@symbol("rt_alloc") export fn alloc(n: u64) *void;
|
||||
@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_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.
|
||||
//
|
||||
@@ -783,8 +783,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;
|
||||
@@ -801,14 +801,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;
|
||||
@@ -1061,7 +1061,7 @@ fn slurp(path: *u8) (*u8, u64) = {
|
||||
case let v: i64 => n = v;
|
||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||
};
|
||||
let buf: *u8 = rt.alloc(n: u64): *u8;
|
||||
let buf: *u8 = rt.malloc(n: u64): *u8;
|
||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
||||
os.close(fd);
|
||||
let got: i64 = 0i64;
|
||||
@@ -1083,7 +1083,7 @@ fn emittext(l: *lnk, src: *u8, n: u64) void = {
|
||||
// Grow by mmap'ing a fresh region and copying. The old buffer
|
||||
// is leaked into the page allocator; for a linker run this is
|
||||
// trivial waste.
|
||||
let nb: *u8 = rt.alloc(nc): *u8;
|
||||
let nb: *u8 = rt.malloc(nc): *u8;
|
||||
let i: u64 = 0u64;
|
||||
for (i < l.textlen) {
|
||||
nb[i] = l.text[i];
|
||||
@@ -1105,7 +1105,7 @@ fn emitdata(l: *lnk, src: *u8, n: u64) void = {
|
||||
let nc: u64 = l.datacap;
|
||||
if (nc == 0u64) { nc = 256u64; };
|
||||
for (nc < l.datalen + n) { nc = nc * 2u64; };
|
||||
let nb: *u8 = rt.alloc(nc): *u8;
|
||||
let nb: *u8 = rt.malloc(nc): *u8;
|
||||
let i: u64 = 0u64;
|
||||
for (i < l.datalen) {
|
||||
nb[i] = l.data[i];
|
||||
@@ -1721,7 +1721,7 @@ fn slurpso(path: *u8) (*u8, u64) = {
|
||||
case let v: i64 => n = v;
|
||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||
};
|
||||
let buf: *u8 = rt.alloc(n: u64): *u8;
|
||||
let buf: *u8 = rt.malloc(n: u64): *u8;
|
||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
||||
os.close(fd);
|
||||
let got: i64 = 0i64;
|
||||
@@ -2782,7 +2782,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
};
|
||||
|
||||
// ---- assemble file buffer ----
|
||||
let filebuf: *u8 = rt.alloc(fileend): *u8;
|
||||
let filebuf: *u8 = rt.malloc(fileend): *u8;
|
||||
if (filebuf == nil) {
|
||||
os.write(2, "w6l: out of memory\n".ptr, 18u64);
|
||||
return 1;
|
||||
@@ -2973,7 +2973,7 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
let datafilelen: u64 = l.datalen - bsslen;
|
||||
|
||||
// One contiguous header buffer covering [0..0x1000), then .text.
|
||||
let hdr: *u8 = rt.alloc(TEXT_OFF): *u8; // zero-initialised by mmap
|
||||
let hdr: *u8 = rt.malloc(TEXT_OFF): *u8; // zero-initialised by mmap
|
||||
|
||||
// --- Ehdr (64 bytes) ---
|
||||
hdr[0u64] = 127u8; // 0x7f
|
||||
@@ -3128,7 +3128,7 @@ fn appenddec(dst: *u8, i: u64, n: u64) u64 = {
|
||||
dst[i] = 48u8;
|
||||
return i + 1u64;
|
||||
};
|
||||
let buf: *u8 = rt.alloc(16u64): *u8;
|
||||
let buf: *u8 = rt.malloc(16u64): *u8;
|
||||
let k: u64 = 0u64;
|
||||
let v: u64 = n;
|
||||
for (v > 0u64) {
|
||||
@@ -3167,7 +3167,7 @@ fn buildpathv(dst: *u8, dir: *u8, name: *u8, v: u64) u64 = {
|
||||
fn islinkable(path: *u8) bool = {
|
||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||
if (fd < 0) { return false; };
|
||||
let mp: *u8 = rt.alloc(8u64): *u8;
|
||||
let mp: *u8 = rt.malloc(8u64): *u8;
|
||||
let n: i64 = os.read(fd, mp, 8u64);
|
||||
os.close(fd);
|
||||
if (n < 4i64) { return false; };
|
||||
@@ -3195,7 +3195,7 @@ fn islinkable(path: *u8) bool = {
|
||||
// then lib<name>.a. Return arena-owned NUL-terminated path on success,
|
||||
// nil on miss.
|
||||
fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
||||
let bufp: *u8 = rt.alloc(1024u64): *u8;
|
||||
let bufp: *u8 = rt.malloc(1024u64): *u8;
|
||||
let i: i32 = 0;
|
||||
for (i < nlibdirs) {
|
||||
let dir: *u8 = libdirs[i];
|
||||
@@ -3236,7 +3236,7 @@ fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
||||
fn isso(path: *u8) i32 = {
|
||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||
if (fd < 0) { return 0; };
|
||||
let mp: *u8 = rt.alloc(20u64): *u8;
|
||||
let mp: *u8 = rt.malloc(20u64): *u8;
|
||||
let n: i64 = os.read(fd, mp, 20u64);
|
||||
os.close(fd);
|
||||
if (n < 20i64) { return 0; };
|
||||
@@ -3253,11 +3253,11 @@ fn isso(path: *u8) i32 = {
|
||||
export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let outpath: *u8 = nil;
|
||||
let maxinputs: i32 = 64;
|
||||
let inputs: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||
let inputs: **u8 = rt.malloc((maxinputs: u64) * 8u64): **u8;
|
||||
let ninputs: i32 = 0;
|
||||
let libdirs: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||
let libdirs: **u8 = rt.malloc((maxinputs: u64) * 8u64): **u8;
|
||||
let nlibdirs: i32 = 0;
|
||||
let lflags: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||
let lflags: **u8 = rt.malloc((maxinputs: u64) * 8u64): **u8;
|
||||
let nlflags: i32 = 0;
|
||||
|
||||
let i: i32 = 1;
|
||||
|
||||
@@ -64,7 +64,7 @@ fn appenddec(dst: *u8, i: u64, n: u64) u64 = {
|
||||
dst[i] = 48u8;
|
||||
return i + 1u64;
|
||||
};
|
||||
let buf: *u8 = rt.alloc(16u64): *u8;
|
||||
let buf: *u8 = rt.malloc(16u64): *u8;
|
||||
let k: u64 = 0u64;
|
||||
let v: u64 = n;
|
||||
for (v > 0u64) {
|
||||
@@ -103,7 +103,7 @@ fn buildpathv(dst: *u8, dir: *u8, name: *u8, v: u64) u64 = {
|
||||
fn islinkable(path: *u8) bool = {
|
||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||
if (fd < 0) { return false; };
|
||||
let mp: *u8 = rt.alloc(8u64): *u8;
|
||||
let mp: *u8 = rt.malloc(8u64): *u8;
|
||||
let n: i64 = os.read(fd, mp, 8u64);
|
||||
os.close(fd);
|
||||
if (n < 4i64) { return false; };
|
||||
@@ -131,7 +131,7 @@ fn islinkable(path: *u8) bool = {
|
||||
// then lib<name>.a. Return arena-owned NUL-terminated path on success,
|
||||
// nil on miss.
|
||||
fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
||||
let bufp: *u8 = rt.alloc(1024u64): *u8;
|
||||
let bufp: *u8 = rt.malloc(1024u64): *u8;
|
||||
let i: i32 = 0;
|
||||
for (i < nlibdirs) {
|
||||
let dir: *u8 = libdirs[i];
|
||||
@@ -172,7 +172,7 @@ fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
||||
fn isso(path: *u8) i32 = {
|
||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||
if (fd < 0) { return 0; };
|
||||
let mp: *u8 = rt.alloc(20u64): *u8;
|
||||
let mp: *u8 = rt.malloc(20u64): *u8;
|
||||
let n: i64 = os.read(fd, mp, 20u64);
|
||||
os.close(fd);
|
||||
if (n < 20i64) { return 0; };
|
||||
@@ -189,11 +189,11 @@ fn isso(path: *u8) i32 = {
|
||||
export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let outpath: *u8 = nil;
|
||||
let maxinputs: i32 = 64;
|
||||
let inputs: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||
let inputs: **u8 = rt.malloc((maxinputs: u64) * 8u64): **u8;
|
||||
let ninputs: i32 = 0;
|
||||
let libdirs: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||
let libdirs: **u8 = rt.malloc((maxinputs: u64) * 8u64): **u8;
|
||||
let nlibdirs: i32 = 0;
|
||||
let lflags: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||
let lflags: **u8 = rt.malloc((maxinputs: u64) * 8u64): **u8;
|
||||
let nlflags: i32 = 0;
|
||||
|
||||
let i: i32 = 1;
|
||||
|
||||
@@ -87,7 +87,7 @@ fn slurp(path: *u8) (*u8, u64) = {
|
||||
case let v: i64 => n = v;
|
||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||
};
|
||||
let buf: *u8 = rt.alloc(n: u64): *u8;
|
||||
let buf: *u8 = rt.malloc(n: u64): *u8;
|
||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
||||
os.close(fd);
|
||||
let got: i64 = 0i64;
|
||||
@@ -109,7 +109,7 @@ fn emittext(l: *lnk, src: *u8, n: u64) void = {
|
||||
// Grow by mmap'ing a fresh region and copying. The old buffer
|
||||
// is leaked into the page allocator; for a linker run this is
|
||||
// trivial waste.
|
||||
let nb: *u8 = rt.alloc(nc): *u8;
|
||||
let nb: *u8 = rt.malloc(nc): *u8;
|
||||
let i: u64 = 0u64;
|
||||
for (i < l.textlen) {
|
||||
nb[i] = l.text[i];
|
||||
@@ -131,7 +131,7 @@ fn emitdata(l: *lnk, src: *u8, n: u64) void = {
|
||||
let nc: u64 = l.datacap;
|
||||
if (nc == 0u64) { nc = 256u64; };
|
||||
for (nc < l.datalen + n) { nc = nc * 2u64; };
|
||||
let nb: *u8 = rt.alloc(nc): *u8;
|
||||
let nb: *u8 = rt.malloc(nc): *u8;
|
||||
let i: u64 = 0u64;
|
||||
for (i < l.datalen) {
|
||||
nb[i] = l.data[i];
|
||||
|
||||
@@ -89,7 +89,7 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
let datafilelen: u64 = l.datalen - bsslen;
|
||||
|
||||
// One contiguous header buffer covering [0..0x1000), then .text.
|
||||
let hdr: *u8 = rt.alloc(TEXT_OFF): *u8; // zero-initialised by mmap
|
||||
let hdr: *u8 = rt.malloc(TEXT_OFF): *u8; // zero-initialised by mmap
|
||||
|
||||
// --- Ehdr (64 bytes) ---
|
||||
hdr[0u64] = 127u8; // 0x7f
|
||||
|
||||
Reference in New Issue
Block a user