lib: extract rt module from os, sweep imports
Hare puts runtime allocation in rt::, not os:: (ref/hare/rt/malloc.ha:27,
README). ww's `@symbol("rt_alloc") fn alloc(n: u64) *void;` lived at
lib/os/os.ww as a historical bootstrap shortcut; this commit relocates
it to a new lib/rt/malloc.ww and sweeps every site that depended on
`import os` for the alloc decl over to `import rt`.
This is commit 1 of 3 in the lib/rt extraction (#35):
1. (this) move decl, sweep imports — preserves shape
2. rename rt_alloc → rt_malloc (#38)
3. nullable return type + OOM-propagating builtin lowering (#39)
No rename here. Symbol stays rt_alloc, function stays `alloc`, return
stays *void. Behavior identical — same ffi resolution outcome, just
sourced from a different module file. The rt::ensure runtime helper at
selfhost/rt/ensure.ww is its own compilation unit with a local decl and
is untouched.
Side effect: every wcc cgen file used `rt` as a local *node variable
name for "return type." `import rt;` shadows the module, so each
selfhost/cmd/wcc/{check,cgenstmt,cgenexpr,cgenutil}.ww site renamed
to `rtyp`. Mechanical follow-through; only the wcc module-import was
forced to do this rename.
Verified 132/132 + 995_self_rebuild byte-identity (5 wwstage tools
round-trip byte-identical).
This commit is contained in:
10
Makefile
10
Makefile
@@ -113,7 +113,7 @@ $(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.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 \
|
||||||
lib/os/os.ww lib/time/time.ww lib/strconv/strconv.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \
|
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.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)/wwdump_ww.d
|
@mkdir -p $(BIN)/wwdump_ww.d
|
||||||
@@ -135,7 +135,7 @@ $(BIN)/w6c_ww: selfhost/cmd/w6c/main.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 \
|
||||||
lib/os/os.ww lib/time/time.ww lib/strconv/strconv.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.ww \
|
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/io/io.ww lib/memio/memio.ww lib/fmt/fmt.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)/w6c_ww.d
|
@mkdir -p $(BIN)/w6c_ww.d
|
||||||
@@ -154,7 +154,7 @@ $(BIN)/w6a_ww: selfhost/cmd/w6a/main.ww selfhost/cmd/w6a/types.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 \
|
selfhost/cmd/wcc/mem.ww \
|
||||||
lib/os/os.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
|
||||||
@@ -171,7 +171,7 @@ $(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 selfhost/cmd/wcc/mem.ww \
|
||||||
lib/os/os.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
|
||||||
@@ -184,7 +184,7 @@ $(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
|
|||||||
# ---- 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 selfhost/cmd/wcc
|
||||||
# (for the bump arena). It then orchestrates w6c/w6a/w6l like the C driver.
|
# (for the bump arena). It then orchestrates w6c/w6a/w6l like the C driver.
|
||||||
$(BIN)/ww_ww: selfhost/cmd/ww/main.ww selfhost/cmd/wcc/mem.ww lib/os/os.ww \
|
$(BIN)/ww_ww: selfhost/cmd/ww/main.ww selfhost/cmd/wcc/mem.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)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
package cmatrix;
|
package cmatrix;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import time;
|
import time;
|
||||||
import fmt;
|
import fmt;
|
||||||
|
|
||||||
@@ -200,18 +201,18 @@ fn now_ns() u64 = {
|
|||||||
// ---- cmat allocate / free ---------------------------------------------
|
// ---- cmat allocate / free ---------------------------------------------
|
||||||
|
|
||||||
fn cmat_alloc(w: i32, h: i32, r: *rng) *cmat = {
|
fn cmat_alloc(w: i32, h: i32, r: *rng) *cmat = {
|
||||||
let m = os.alloc(CMAT_SZ): *cmat;
|
let m = rt.alloc(CMAT_SZ): *cmat;
|
||||||
m.w = w;
|
m.w = w;
|
||||||
m.h = h;
|
m.h = h;
|
||||||
m.gspeed = -1;
|
m.gspeed = -1;
|
||||||
m.gtheme = theme.GREEN: i32;
|
m.gtheme = theme.GREEN: i32;
|
||||||
m.flash = 0;
|
m.flash = 0;
|
||||||
let n4 = (w: u64) * 4u64;
|
let n4 = (w: u64) * 4u64;
|
||||||
m.head = os.alloc(n4): *i32;
|
m.head = rt.alloc(n4): *i32;
|
||||||
m.length = os.alloc(n4): *i32;
|
m.length = rt.alloc(n4): *i32;
|
||||||
m.speed = os.alloc(n4): *i32;
|
m.speed = rt.alloc(n4): *i32;
|
||||||
m.counter = os.alloc(n4): *i32;
|
m.counter = rt.alloc(n4): *i32;
|
||||||
m.glyphs = os.alloc((w: u64) * (MAX_TRAIL: u64)): *u8;
|
m.glyphs = rt.alloc((w: u64) * (MAX_TRAIL: u64)): *u8;
|
||||||
let c = 0;
|
let c = 0;
|
||||||
for (c < w) {
|
for (c < w) {
|
||||||
m.head[c] = -rng_range(r, 0, h);
|
m.head[c] = -rng_range(r, 0, h);
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
package lisp;
|
package lisp;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import fmt;
|
import fmt;
|
||||||
import ascii;
|
import ascii;
|
||||||
import strconv;
|
import strconv;
|
||||||
@@ -158,7 +159,7 @@ let perm_arena: arena;
|
|||||||
let trans_arena: arena;
|
let trans_arena: arena;
|
||||||
|
|
||||||
fn arena_new_chunk(prev: *chunk) *chunk = {
|
fn arena_new_chunk(prev: *chunk) *chunk = {
|
||||||
let raw: *u8 = os.alloc(ARENA_CHUNK): *u8;
|
let raw: *u8 = rt.alloc(ARENA_CHUNK): *u8;
|
||||||
let c: *chunk = raw: *chunk;
|
let c: *chunk = raw: *chunk;
|
||||||
c.next = prev;
|
c.next = prev;
|
||||||
c.cur = 0u64;
|
c.cur = 0u64;
|
||||||
@@ -1565,10 +1566,10 @@ fn bind_one(e: **env, name: str, id: i32) void = {
|
|||||||
|
|
||||||
export fn initsyms() void = {
|
export fn initsyms() void = {
|
||||||
arena_init();
|
arena_init();
|
||||||
sym_off = os.alloc((SYM_CAP: u64) * 4u64): *i32;
|
sym_off = rt.alloc((SYM_CAP: u64) * 4u64): *i32;
|
||||||
sym_len = os.alloc((SYM_CAP: u64) * 4u64): *i32;
|
sym_len = rt.alloc((SYM_CAP: u64) * 4u64): *i32;
|
||||||
sym_blob = os.alloc(SYM_BLOBSZ: u64): *u8;
|
sym_blob = rt.alloc(SYM_BLOBSZ: u64): *u8;
|
||||||
obuf = os.alloc(OBUF_SZ: u64): *u8;
|
obuf = rt.alloc(OBUF_SZ: u64): *u8;
|
||||||
|
|
||||||
// Stash the special-form ids so classify_sform sees them.
|
// Stash the special-form ids so classify_sform sees them.
|
||||||
SID_QUOTE = intern("quote");
|
SID_QUOTE = intern("quote");
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ package fmt;
|
|||||||
import io;
|
import io;
|
||||||
import memio;
|
import memio;
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import strconv;
|
import strconv;
|
||||||
|
|
||||||
// i64dec_buf — scratch buffer for [[i64dec]] below. Module-level
|
// i64dec_buf — scratch buffer for [[i64dec]] below. Module-level
|
||||||
@@ -885,7 +886,7 @@ export fn asprintf(fmt: str, args: field...) str = {
|
|||||||
match (cres) { case void => {}; case io.closed => {}; };
|
match (cres) { case void => {}; case io.closed => {}; };
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
let tight: *u8 = os.alloc(view.len: u64): *u8;
|
let tight: *u8 = rt.alloc(view.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < view.len) {
|
for (i < view.len) {
|
||||||
tight[i] = view.ptr[i];
|
tight[i] = view.ptr[i];
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ package memio;
|
|||||||
|
|
||||||
import io;
|
import io;
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
// state — memio's per-stream bookkeeping. The caller owns the slot
|
// state — memio's per-stream bookkeeping. The caller owns the slot
|
||||||
// and passes its address into a constructor. `ptr/len/cap` are the
|
// and passes its address into a constructor. `ptr/len/cap` are the
|
||||||
@@ -196,7 +197,7 @@ fn grow(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; };
|
||||||
for (newcap < need) { newcap *= 2; };
|
for (newcap < need) { newcap *= 2; };
|
||||||
let nbuf: *u8 = os.alloc(newcap: u64): *u8;
|
let nbuf: *u8 = rt.alloc(newcap: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < m.len) {
|
for (i < m.len) {
|
||||||
nbuf[i] = m.ptr[i];
|
nbuf[i] = m.ptr[i];
|
||||||
|
|||||||
22
lib/os/os.ww
22
lib/os/os.ww
@@ -12,28 +12,6 @@ import time;
|
|||||||
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
||||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||||
|
|
||||||
// alloc / free — runtime mmap-backed page allocator. Untyped:
|
|
||||||
// `alloc(n)` returns a `*void` and `free(p, n)` requires the byte
|
|
||||||
// count back because rt_free is munmap-based and doesn't track
|
|
||||||
// mapping sizes (the kernel needs the length to release the
|
|
||||||
// reservation).
|
|
||||||
//
|
|
||||||
// Diverges from Hare. Hare exposes `alloc` / `free` as typed
|
|
||||||
// language builtins (`alloc(value, cap)?` / `free(ptr)`) that the
|
|
||||||
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
|
|
||||||
// so the rt-symbol surface is exposed directly. Stdlib callers
|
|
||||||
// that 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 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 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.
|
|
||||||
@symbol("rt_alloc") export fn alloc(n: u64) *void;
|
|
||||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||||
@symbol("rt_abort") fn abort(msg: str) void;
|
@symbol("rt_abort") fn abort(msg: str) void;
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
package os;
|
package os;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
let signalled: i32 = 0;
|
let signalled: i32 = 0;
|
||||||
|
|
||||||
@@ -102,7 +103,7 @@ fn streq(a: str, b: str) bool = {
|
|||||||
// dereferenceable, not just non-nil).
|
// dereferenceable, not just non-nil).
|
||||||
|
|
||||||
@test fn test_alloc_free_roundtrip() void = {
|
@test fn test_alloc_free_roundtrip() void = {
|
||||||
let p: *u8 = os.alloc(4096u64): *u8;
|
let p: *u8 = rt.alloc(4096u64): *u8;
|
||||||
if (p == nil: *u8) { fail(); };
|
if (p == nil: *u8) { fail(); };
|
||||||
// Write a sentinel at the head and tail of the page, read it
|
// Write a sentinel at the head and tail of the page, read it
|
||||||
// back. A miscompiled binding (wrong arg order, wrong ABI, etc.)
|
// back. A miscompiled binding (wrong arg order, wrong ABI, etc.)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package path;
|
package path;
|
||||||
|
|
||||||
import os;
|
import rt;
|
||||||
|
|
||||||
def SEP: u8 = 47u8; // '/'
|
def SEP: u8 = 47u8; // '/'
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ export fn extension(p: str) str = {
|
|||||||
// two-arg join (no variadic).
|
// two-arg join (no variadic).
|
||||||
export fn join(a: str, b: str) str = {
|
export fn join(a: str, b: str) str = {
|
||||||
if (abs(b)) {
|
if (abs(b)) {
|
||||||
let buf: *u8 = os.alloc(b.len: u64): *u8;
|
let buf: *u8 = rt.alloc(b.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < b.len) { buf[i] = b[i]; i += 1; };
|
for (i < b.len) { buf[i] = b[i]; i += 1; };
|
||||||
let r: str;
|
let r: str;
|
||||||
@@ -104,7 +104,7 @@ export fn join(a: str, b: str) str = {
|
|||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
if (a.len == 0) {
|
if (a.len == 0) {
|
||||||
let buf: *u8 = os.alloc(b.len: u64): *u8;
|
let buf: *u8 = rt.alloc(b.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < b.len) { buf[i] = b[i]; i += 1; };
|
for (i < b.len) { buf[i] = b[i]; i += 1; };
|
||||||
let r: str;
|
let r: str;
|
||||||
@@ -113,7 +113,7 @@ export fn join(a: str, b: str) str = {
|
|||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
if (b.len == 0) {
|
if (b.len == 0) {
|
||||||
let buf: *u8 = os.alloc(a.len: u64): *u8;
|
let buf: *u8 = rt.alloc(a.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < a.len) { buf[i] = a[i]; i += 1; };
|
for (i < a.len) { buf[i] = a[i]; i += 1; };
|
||||||
let r: str;
|
let r: str;
|
||||||
@@ -129,7 +129,7 @@ export fn join(a: str, b: str) str = {
|
|||||||
an -= 1;
|
an -= 1;
|
||||||
};
|
};
|
||||||
let total: i32 = an + 1 + b.len;
|
let total: i32 = an + 1 + b.len;
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < an) { buf[i] = a[i]; i += 1; };
|
for (i < an) { buf[i] = a[i]; i += 1; };
|
||||||
buf[an] = SEP;
|
buf[an] = SEP;
|
||||||
|
|||||||
22
lib/rt/malloc.ww
Normal file
22
lib/rt/malloc.ww
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// rt — runtime primitives exposed to ww programs.
|
||||||
|
// Mirrors Hare's rt:: module placement (ref/hare/rt/).
|
||||||
|
|
||||||
|
package rt;
|
||||||
|
|
||||||
|
// alloc — mmap-backed page allocator. Untyped: `alloc(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,
|
||||||
|
// so the rt-symbol surface is exposed directly. Stdlib callers that
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// 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;
|
||||||
@@ -97,6 +97,7 @@ package shlex;
|
|||||||
import io;
|
import io;
|
||||||
import memio;
|
import memio;
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
// rt_ensure is the runtime slice-growth helper invoked by the
|
// rt_ensure is the runtime slice-growth helper invoked by the
|
||||||
// `append(s, v)` builtin. We bind it directly because the builtin's
|
// `append(s, v)` builtin. We bind it directly because the builtin's
|
||||||
@@ -125,7 +126,7 @@ fn dupstr(s: str) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (s.len == 0) { return r; };
|
if (s.len == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(s.len: u64): *u8;
|
let buf: *u8 = rt.alloc(s.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
||||||
r.ptr = buf;
|
r.ptr = buf;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package strings;
|
|||||||
import bytes;
|
import bytes;
|
||||||
import encoding.utf8;
|
import encoding.utf8;
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import types;
|
import types;
|
||||||
|
|
||||||
// toutf8 — borrowed []u8 view of `s`. ref/hare/strings/utf8.ha:29.
|
// toutf8 — borrowed []u8 view of `s`. ref/hare/strings/utf8.ha:29.
|
||||||
@@ -98,7 +99,7 @@ export fn dup(s: str) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (s.len == 0) { return r; };
|
if (s.len == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(s.len: u64): *u8;
|
let buf: *u8 = rt.alloc(s.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
||||||
r.ptr = buf;
|
r.ptr = buf;
|
||||||
@@ -176,7 +177,7 @@ export fn concat(strs: str...) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (total == 0) { return r; };
|
if (total == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < strs.len) {
|
for (i < strs.len) {
|
||||||
@@ -209,7 +210,7 @@ export fn join(delim: str, strs: str...) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (total == 0) { return r; };
|
if (total == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < strs.len) {
|
for (i < strs.len) {
|
||||||
@@ -886,7 +887,7 @@ export fn lpad(s: str, p: rune, maxlen: i32) str = {
|
|||||||
if (s.len >= maxlen) { return dup(s); };
|
if (s.len >= maxlen) { return dup(s); };
|
||||||
let scratch: [4]u8;
|
let scratch: [4]u8;
|
||||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
let buf: *u8 = rt.alloc(maxlen: u64): *u8;
|
||||||
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
||||||
if (padwrite > maxlen) { padwrite = maxlen; };
|
if (padwrite > maxlen) { padwrite = maxlen; };
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
@@ -969,7 +970,7 @@ export fn rpad(s: str, p: rune, maxlen: i32) str = {
|
|||||||
if (s.len >= maxlen) { return dup(s); };
|
if (s.len >= maxlen) { return dup(s); };
|
||||||
let scratch: [4]u8;
|
let scratch: [4]u8;
|
||||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
let buf: *u8 = rt.alloc(maxlen: u64): *u8;
|
||||||
let k: i32 = 0;
|
let k: i32 = 0;
|
||||||
for (k < s.len) {
|
for (k < s.len) {
|
||||||
buf[k] = s[k];
|
buf[k] = s[k];
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
package w6a;
|
package w6a;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import types;
|
import types;
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ export fn emitbyte(a: *asm_, b: u8) void = {
|
|||||||
let nc: u64 = a.textcap;
|
let nc: u64 = a.textcap;
|
||||||
if (nc == 0u64) { nc = 4096u64; };
|
if (nc == 0u64) { nc = 4096u64; };
|
||||||
nc = nc * 2u64;
|
nc = nc * 2u64;
|
||||||
let nb: *u8 = os.alloc(nc): *u8;
|
let nb: *u8 = rt.alloc(nc): *u8;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
for (i < a.textlen) { nb[i] = a.text[i]; i += 1u64; };
|
for (i < a.textlen) { nb[i] = a.text[i]; i += 1u64; };
|
||||||
a.text = nb;
|
a.text = nb;
|
||||||
@@ -59,7 +60,7 @@ export fn emitdatabyte(a: *asm_, b: u8) void = {
|
|||||||
let nc: u64 = a.datacap;
|
let nc: u64 = a.datacap;
|
||||||
if (nc == 0u64) { nc = 256u64; };
|
if (nc == 0u64) { nc = 256u64; };
|
||||||
nc = nc * 2u64;
|
nc = nc * 2u64;
|
||||||
let nb: *u8 = os.alloc(nc): *u8;
|
let nb: *u8 = rt.alloc(nc): *u8;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
for (i < a.datalen) { nb[i] = a.data[i]; i += 1u64; };
|
for (i < a.datalen) { nb[i] = a.data[i]; i += 1u64; };
|
||||||
a.data = nb;
|
a.data = nb;
|
||||||
|
|||||||
@@ -110,28 +110,6 @@ import time;
|
|||||||
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
||||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||||
|
|
||||||
// alloc / free — runtime mmap-backed page allocator. Untyped:
|
|
||||||
// `alloc(n)` returns a `*void` and `free(p, n)` requires the byte
|
|
||||||
// count back because rt_free is munmap-based and doesn't track
|
|
||||||
// mapping sizes (the kernel needs the length to release the
|
|
||||||
// reservation).
|
|
||||||
//
|
|
||||||
// Diverges from Hare. Hare exposes `alloc` / `free` as typed
|
|
||||||
// language builtins (`alloc(value, cap)?` / `free(ptr)`) that the
|
|
||||||
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
|
|
||||||
// so the rt-symbol surface is exposed directly. Stdlib callers
|
|
||||||
// that 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 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 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.
|
|
||||||
@symbol("rt_alloc") export fn alloc(n: u64) *void;
|
|
||||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||||
@symbol("rt_abort") fn abort(msg: str) void;
|
@symbol("rt_abort") fn abort(msg: str) void;
|
||||||
|
|
||||||
@@ -749,6 +727,29 @@ export fn exists(path: str) bool = {
|
|||||||
return r >= 0i64;
|
return r >= 0i64;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// rt — runtime primitives exposed to ww programs.
|
||||||
|
// Mirrors Hare's rt:: module placement (ref/hare/rt/).
|
||||||
|
|
||||||
|
package rt;
|
||||||
|
|
||||||
|
// alloc — mmap-backed page allocator. Untyped: `alloc(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,
|
||||||
|
// so the rt-symbol surface is exposed directly. Stdlib callers that
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// 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;
|
||||||
|
|
||||||
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
||||||
//
|
//
|
||||||
// Bump arena allocator. Backed by the runtime page allocator
|
// Bump arena allocator. Backed by the runtime page allocator
|
||||||
@@ -762,6 +763,7 @@ export fn exists(path: str) bool = {
|
|||||||
package wcc;
|
package wcc;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
def ALIGN: u64 = 16u64;
|
def ALIGN: u64 = 16u64;
|
||||||
def INIT_CHUNK: u64 = 65536u64;
|
def INIT_CHUNK: u64 = 65536u64;
|
||||||
@@ -781,8 +783,8 @@ fn roundup(n: u64, a: u64) u64 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export fn newarena() *arena = {
|
export fn newarena() *arena = {
|
||||||
let a: *arena = os.alloc(ARENA_SZ): *arena;
|
let a: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
a.buf = os.alloc(INIT_CHUNK): *u8;
|
a.buf = rt.alloc(INIT_CHUNK): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = INIT_CHUNK;
|
a.cap = INIT_CHUNK;
|
||||||
a.next = nil;
|
a.next = nil;
|
||||||
@@ -799,14 +801,14 @@ fn grow(a: *arena, need: u64) bool = {
|
|||||||
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
||||||
if (want < need) { return false; }; // single allocation too big
|
if (want < need) { return false; }; // single allocation too big
|
||||||
|
|
||||||
let old: *arena = os.alloc(ARENA_SZ): *arena;
|
let old: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
old.buf = a.buf;
|
old.buf = a.buf;
|
||||||
old.off = a.off;
|
old.off = a.off;
|
||||||
old.cap = a.cap;
|
old.cap = a.cap;
|
||||||
old.next = a.next;
|
old.next = a.next;
|
||||||
old.total = 0u64;
|
old.total = 0u64;
|
||||||
|
|
||||||
a.buf = os.alloc(want): *u8;
|
a.buf = rt.alloc(want): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = want;
|
a.cap = want;
|
||||||
a.next = old;
|
a.next = old;
|
||||||
@@ -1747,6 +1749,7 @@ export fn parse(a: *asm_) i32 = {
|
|||||||
package w6a;
|
package w6a;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import types;
|
import types;
|
||||||
|
|
||||||
@@ -1757,7 +1760,7 @@ export fn emitbyte(a: *asm_, b: u8) void = {
|
|||||||
let nc: u64 = a.textcap;
|
let nc: u64 = a.textcap;
|
||||||
if (nc == 0u64) { nc = 4096u64; };
|
if (nc == 0u64) { nc = 4096u64; };
|
||||||
nc = nc * 2u64;
|
nc = nc * 2u64;
|
||||||
let nb: *u8 = os.alloc(nc): *u8;
|
let nb: *u8 = rt.alloc(nc): *u8;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
for (i < a.textlen) { nb[i] = a.text[i]; i += 1u64; };
|
for (i < a.textlen) { nb[i] = a.text[i]; i += 1u64; };
|
||||||
a.text = nb;
|
a.text = nb;
|
||||||
@@ -1794,7 +1797,7 @@ export fn emitdatabyte(a: *asm_, b: u8) void = {
|
|||||||
let nc: u64 = a.datacap;
|
let nc: u64 = a.datacap;
|
||||||
if (nc == 0u64) { nc = 256u64; };
|
if (nc == 0u64) { nc = 256u64; };
|
||||||
nc = nc * 2u64;
|
nc = nc * 2u64;
|
||||||
let nb: *u8 = os.alloc(nc): *u8;
|
let nb: *u8 = rt.alloc(nc): *u8;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
for (i < a.datalen) { nb[i] = a.data[i]; i += 1u64; };
|
for (i < a.datalen) { nb[i] = a.data[i]; i += 1u64; };
|
||||||
a.data = nb;
|
a.data = nb;
|
||||||
@@ -3009,6 +3012,7 @@ export fn emitelf(a: *asm_, fd: i32) i32 = {
|
|||||||
package main;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import types;
|
import types;
|
||||||
import lex;
|
import lex;
|
||||||
@@ -3054,7 +3058,7 @@ fn slurp(path: *u8) (*u8, u64) = {
|
|||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let nz: u64 = n: u64;
|
let nz: u64 = n: u64;
|
||||||
let buf: *u8 = os.alloc(nz + 1u64): *u8;
|
let buf: *u8 = rt.alloc(nz + 1u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, nz);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, nz);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
package main;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import types;
|
import types;
|
||||||
import lex;
|
import lex;
|
||||||
@@ -52,7 +53,7 @@ fn slurp(path: *u8) (*u8, u64) = {
|
|||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let nz: u64 = n: u64;
|
let nz: u64 = n: u64;
|
||||||
let buf: *u8 = os.alloc(nz + 1u64): *u8;
|
let buf: *u8 = rt.alloc(nz + 1u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, nz);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, nz);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
|
|||||||
@@ -110,28 +110,6 @@ import time;
|
|||||||
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
||||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||||
|
|
||||||
// alloc / free — runtime mmap-backed page allocator. Untyped:
|
|
||||||
// `alloc(n)` returns a `*void` and `free(p, n)` requires the byte
|
|
||||||
// count back because rt_free is munmap-based and doesn't track
|
|
||||||
// mapping sizes (the kernel needs the length to release the
|
|
||||||
// reservation).
|
|
||||||
//
|
|
||||||
// Diverges from Hare. Hare exposes `alloc` / `free` as typed
|
|
||||||
// language builtins (`alloc(value, cap)?` / `free(ptr)`) that the
|
|
||||||
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
|
|
||||||
// so the rt-symbol surface is exposed directly. Stdlib callers
|
|
||||||
// that 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 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 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.
|
|
||||||
@symbol("rt_alloc") export fn alloc(n: u64) *void;
|
|
||||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||||
@symbol("rt_abort") fn abort(msg: str) void;
|
@symbol("rt_abort") fn abort(msg: str) void;
|
||||||
|
|
||||||
@@ -749,6 +727,29 @@ export fn exists(path: str) bool = {
|
|||||||
return r >= 0i64;
|
return r >= 0i64;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// rt — runtime primitives exposed to ww programs.
|
||||||
|
// Mirrors Hare's rt:: module placement (ref/hare/rt/).
|
||||||
|
|
||||||
|
package rt;
|
||||||
|
|
||||||
|
// alloc — mmap-backed page allocator. Untyped: `alloc(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,
|
||||||
|
// so the rt-symbol surface is exposed directly. Stdlib callers that
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// 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;
|
||||||
|
|
||||||
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
||||||
//
|
//
|
||||||
// Bump arena allocator. Backed by the runtime page allocator
|
// Bump arena allocator. Backed by the runtime page allocator
|
||||||
@@ -762,6 +763,7 @@ export fn exists(path: str) bool = {
|
|||||||
package wcc;
|
package wcc;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
def ALIGN: u64 = 16u64;
|
def ALIGN: u64 = 16u64;
|
||||||
def INIT_CHUNK: u64 = 65536u64;
|
def INIT_CHUNK: u64 = 65536u64;
|
||||||
@@ -781,8 +783,8 @@ fn roundup(n: u64, a: u64) u64 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export fn newarena() *arena = {
|
export fn newarena() *arena = {
|
||||||
let a: *arena = os.alloc(ARENA_SZ): *arena;
|
let a: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
a.buf = os.alloc(INIT_CHUNK): *u8;
|
a.buf = rt.alloc(INIT_CHUNK): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = INIT_CHUNK;
|
a.cap = INIT_CHUNK;
|
||||||
a.next = nil;
|
a.next = nil;
|
||||||
@@ -799,14 +801,14 @@ fn grow(a: *arena, need: u64) bool = {
|
|||||||
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
||||||
if (want < need) { return false; }; // single allocation too big
|
if (want < need) { return false; }; // single allocation too big
|
||||||
|
|
||||||
let old: *arena = os.alloc(ARENA_SZ): *arena;
|
let old: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
old.buf = a.buf;
|
old.buf = a.buf;
|
||||||
old.off = a.off;
|
old.off = a.off;
|
||||||
old.cap = a.cap;
|
old.cap = a.cap;
|
||||||
old.next = a.next;
|
old.next = a.next;
|
||||||
old.total = 0u64;
|
old.total = 0u64;
|
||||||
|
|
||||||
a.buf = os.alloc(want): *u8;
|
a.buf = rt.alloc(want): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = want;
|
a.cap = want;
|
||||||
a.next = old;
|
a.next = old;
|
||||||
@@ -1864,6 +1866,7 @@ package strings;
|
|||||||
import bytes;
|
import bytes;
|
||||||
import encoding.utf8;
|
import encoding.utf8;
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import types;
|
import types;
|
||||||
|
|
||||||
// toutf8 — borrowed []u8 view of `s`. ref/hare/strings/utf8.ha:29.
|
// toutf8 — borrowed []u8 view of `s`. ref/hare/strings/utf8.ha:29.
|
||||||
@@ -1935,7 +1938,7 @@ export fn dup(s: str) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (s.len == 0) { return r; };
|
if (s.len == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(s.len: u64): *u8;
|
let buf: *u8 = rt.alloc(s.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
||||||
r.ptr = buf;
|
r.ptr = buf;
|
||||||
@@ -2013,7 +2016,7 @@ export fn concat(strs: str...) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (total == 0) { return r; };
|
if (total == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < strs.len) {
|
for (i < strs.len) {
|
||||||
@@ -2046,7 +2049,7 @@ export fn join(delim: str, strs: str...) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (total == 0) { return r; };
|
if (total == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < strs.len) {
|
for (i < strs.len) {
|
||||||
@@ -2723,7 +2726,7 @@ export fn lpad(s: str, p: rune, maxlen: i32) str = {
|
|||||||
if (s.len >= maxlen) { return dup(s); };
|
if (s.len >= maxlen) { return dup(s); };
|
||||||
let scratch: [4]u8;
|
let scratch: [4]u8;
|
||||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
let buf: *u8 = rt.alloc(maxlen: u64): *u8;
|
||||||
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
||||||
if (padwrite > maxlen) { padwrite = maxlen; };
|
if (padwrite > maxlen) { padwrite = maxlen; };
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
@@ -2806,7 +2809,7 @@ export fn rpad(s: str, p: rune, maxlen: i32) str = {
|
|||||||
if (s.len >= maxlen) { return dup(s); };
|
if (s.len >= maxlen) { return dup(s); };
|
||||||
let scratch: [4]u8;
|
let scratch: [4]u8;
|
||||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
let buf: *u8 = rt.alloc(maxlen: u64): *u8;
|
||||||
let k: i32 = 0;
|
let k: i32 = 0;
|
||||||
for (k < s.len) {
|
for (k < s.len) {
|
||||||
buf[k] = s[k];
|
buf[k] = s[k];
|
||||||
@@ -7901,15 +7904,15 @@ fn astoffset(c: *checker, dot: *node) i64 = {
|
|||||||
if (dot.kind != nkind.N_DOT) { return -1i64; };
|
if (dot.kind != nkind.N_DOT) { return -1i64; };
|
||||||
let recv: *node = scruttype(c, dot.lhs);
|
let recv: *node = scruttype(c, dot.lhs);
|
||||||
if (recv == nil) { return -1i64; };
|
if (recv == nil) { return -1i64; };
|
||||||
let rt: *node = resolvealias(c, unwrapbang(recv));
|
let rtyp: *node = resolvealias(c, unwrapbang(recv));
|
||||||
if (rt == nil) { return -1i64; };
|
if (rtyp == nil) { return -1i64; };
|
||||||
if (rt.kind == nkind.N_TPTR) {
|
if (rtyp.kind == nkind.N_TPTR) {
|
||||||
rt = resolvealias(c, unwrapbang(rt.lhs));
|
rtyp = resolvealias(c, unwrapbang(rtyp.lhs));
|
||||||
};
|
};
|
||||||
if (rt == nil) { return -1i64; };
|
if (rtyp == nil) { return -1i64; };
|
||||||
if (rt.kind != nkind.N_TSTRUCT) { return -1i64; };
|
if (rtyp.kind != nkind.N_TSTRUCT) { return -1i64; };
|
||||||
let off: i64 = 0i64;
|
let off: i64 = 0i64;
|
||||||
let f: *node = rt.list;
|
let f: *node = rtyp.list;
|
||||||
for (f != nil) {
|
for (f != nil) {
|
||||||
if (f.kind == nkind.N_TFIELD) {
|
if (f.kind == nkind.N_TFIELD) {
|
||||||
let fa: i64 = astalign(c, f.lhs);
|
let fa: i64 = astalign(c, f.lhs);
|
||||||
@@ -9727,9 +9730,9 @@ export fn taggedcallslot(c: *cgen, n: *node) i32 = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee == nil) { return 0; };
|
if (callee == nil) { return 0; };
|
||||||
if (callee.kind != nkind.N_IDENT) { return 0; };
|
if (callee.kind != nkind.N_IDENT) { return 0; };
|
||||||
let rt: *node = fnretlookup(c, callee.str);
|
let rtyp: *node = fnretlookup(c, callee.str);
|
||||||
if (!istaggedtype(c, rt)) { return 0; };
|
if (!istaggedtype(c, rtyp)) { return 0; };
|
||||||
return slotsize(c, rt);
|
return slotsize(c, rtyp);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn nodeisslice(c: *cgen, n: *node) bool = {
|
fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||||
@@ -9758,8 +9761,8 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee != nil) {
|
if (callee != nil) {
|
||||||
if (callee.kind == nkind.N_IDENT) {
|
if (callee.kind == nkind.N_IDENT) {
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, c.curmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
|
||||||
return isslicetype(c, rt);
|
return isslicetype(c, rtyp);
|
||||||
};
|
};
|
||||||
if (callee.kind == nkind.N_DOT) {
|
if (callee.kind == nkind.N_DOT) {
|
||||||
let cmod: str;
|
let cmod: str;
|
||||||
@@ -9769,8 +9772,8 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
|||||||
cmod = callee.lhs.str;
|
cmod = callee.lhs.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, cmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
|
||||||
return isslicetype(c, rt);
|
return isslicetype(c, rtyp);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
@@ -9885,8 +9888,8 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee != nil) {
|
if (callee != nil) {
|
||||||
if (callee.kind == nkind.N_IDENT) {
|
if (callee.kind == nkind.N_IDENT) {
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, c.curmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
|
||||||
return isstrtype(c, rt);
|
return isstrtype(c, rtyp);
|
||||||
};
|
};
|
||||||
// #34: cross-module N_DOT — route through fnretlookupmod
|
// #34: cross-module N_DOT — route through fnretlookupmod
|
||||||
// so a same-leaf caller-module fn (different return shape)
|
// so a same-leaf caller-module fn (different return shape)
|
||||||
@@ -9899,8 +9902,8 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
|||||||
cmod = callee.lhs.str;
|
cmod = callee.lhs.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, cmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
|
||||||
return isstrtype(c, rt);
|
return isstrtype(c, rtyp);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
@@ -10816,8 +10819,8 @@ export fn callsretsize(c: *cgen, n: *node) i32 = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cn.len == 0) { return 0; };
|
if (cn.len == 0) { return 0; };
|
||||||
let rt: *node = fnretlookupmod(c, cn, cmod);
|
let rtyp: *node = fnretlookupmod(c, cn, cmod);
|
||||||
return sretretsize(c, rt);
|
return sretretsize(c, rtyp);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn structlookup(c: *cgen, name: str) *structinfo = {
|
fn structlookup(c: *cgen, name: str) *structinfo = {
|
||||||
@@ -11074,16 +11077,16 @@ fn inferletcalltype(c: *cgen, rhs: *node) *node = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len == 0) { return nil; };
|
if (cname.len == 0) { return nil; };
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt == nil) { return nil; };
|
if (rtyp == nil) { return nil; };
|
||||||
if (unwrap) {
|
if (unwrap) {
|
||||||
// Strip error variants — success type is the first
|
// Strip error variants — success type is the first
|
||||||
// variant of the tagged return.
|
// variant of the tagged return.
|
||||||
if (rt.kind != nkind.N_TTAGGED) { return nil; };
|
if (rtyp.kind != nkind.N_TTAGGED) { return nil; };
|
||||||
return rt.list;
|
return rtyp.list;
|
||||||
};
|
};
|
||||||
// Plain call: declared return type is the local's type.
|
// Plain call: declared return type is the local's type.
|
||||||
return rt;
|
return rtyp;
|
||||||
};
|
};
|
||||||
|
|
||||||
// letslotsize — slot size for a `let` binding. Like slotsize, but
|
// letslotsize — slot size for a `let` binding. Like slotsize, but
|
||||||
@@ -11550,8 +11553,8 @@ fn matchscrutt(c: *cgen, scrut: *node) *node = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cnm.len > 0) {
|
if (cnm.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cnm, cmod);
|
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||||
if (rt != nil) { return resolvetagged(c, rt); };
|
if (rtyp != nil) { return resolvetagged(c, rtyp); };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return nil;
|
return nil;
|
||||||
@@ -11745,9 +11748,9 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
|||||||
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
|
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
|
||||||
};
|
};
|
||||||
if (nm.len > 0) {
|
if (nm.len > 0) {
|
||||||
let rt: *node = fnretlookup(c, nm);
|
let rtyp: *node = fnretlookup(c, nm);
|
||||||
if (isf32type(c, rt)) { return 1; };
|
if (isf32type(c, rtyp)) { return 1; };
|
||||||
if (isfloattype(c, rt)) { return 2; };
|
if (isfloattype(c, rtyp)) { return 2; };
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
@@ -12266,9 +12269,9 @@ fn rhstaggedabicall(c: *cgen, src: *node) bool = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (calleename.len > 0) {
|
if (calleename.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (istaggedtype(c, rt)) { return true; };
|
if (istaggedtype(c, rtyp)) { return true; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -13380,10 +13383,10 @@ fn cgtryprop(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len > 0) {
|
if (cname.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTAGGED) {
|
if (rtyp.kind == nkind.N_TTAGGED) {
|
||||||
let first: *node = rt.list;
|
let first: *node = rtyp.list;
|
||||||
if (first != nil) {
|
if (first != nil) {
|
||||||
if (isstrtype(c, first)) {
|
if (isstrtype(c, first)) {
|
||||||
succisstr = true;
|
succisstr = true;
|
||||||
@@ -13436,10 +13439,10 @@ fn cgtryunw(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len > 0) {
|
if (cname.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTAGGED) {
|
if (rtyp.kind == nkind.N_TTAGGED) {
|
||||||
let first: *node = rt.list;
|
let first: *node = rtyp.list;
|
||||||
if (first != nil) {
|
if (first != nil) {
|
||||||
if (isstrtype(c, first)) {
|
if (isstrtype(c, first)) {
|
||||||
succisstr = true;
|
succisstr = true;
|
||||||
@@ -13816,8 +13819,8 @@ fn cgident(c: *cgen, n: *node) void = {
|
|||||||
// in one go, so a body-less FFI binding emits the C symbol
|
// in one go, so a body-less FFI binding emits the C symbol
|
||||||
// it was declared with via @symbol(), not the ww-side ident.
|
// it was declared with via @symbol(), not the ww-side ident.
|
||||||
// Bare ident → same-module by ww's resolver, hint with c.curmod.
|
// Bare ident → same-module by ww's resolver, hint with c.curmod.
|
||||||
let rt: *node = fnretlookup(c, nm);
|
let rtyp: *node = fnretlookup(c, nm);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
emitline("\tLEAQ\t");
|
emitline("\tLEAQ\t");
|
||||||
emitfnname(c, nm, c.curmod);
|
emitfnname(c, nm, c.curmod);
|
||||||
emitline("(SB), AX\n");
|
emitline("(SB), AX\n");
|
||||||
@@ -16630,8 +16633,8 @@ fn cgcall(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (isstrtype(c, rt)) {
|
if (isstrtype(c, rtyp)) {
|
||||||
emitline("\tMOVQ\tDX, BX\n");
|
emitline("\tMOVQ\tDX, BX\n");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -19193,8 +19196,8 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (calleename.len > 0) {
|
if (calleename.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (istaggedtype(c, rt)) { forwardtagged = true; };
|
if (istaggedtype(c, rtyp)) { forwardtagged = true; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -20234,10 +20237,10 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cnm.len > 0) {
|
if (cnm.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cnm, cmod);
|
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTUPLE) {
|
if (rtyp.kind == nkind.N_TTUPLE) {
|
||||||
p0t = rt.list;
|
p0t = rtyp.list;
|
||||||
if (p0t != nil) { p1t = p0t.next; };
|
if (p0t != nil) { p1t = p0t.next; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -23165,6 +23168,7 @@ export fn fargregname(i: i32) str = {
|
|||||||
package main;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import tok;
|
import tok;
|
||||||
import lex;
|
import lex;
|
||||||
@@ -23213,7 +23217,7 @@ fn slurp(path: *u8) (*u8, u64) = {
|
|||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let nz: u64 = n: u64;
|
let nz: u64 = n: u64;
|
||||||
let buf: *u8 = os.alloc(nz + 1u64): *u8;
|
let buf: *u8 = rt.alloc(nz + 1u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, nz);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, nz);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
package main;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import tok;
|
import tok;
|
||||||
import lex;
|
import lex;
|
||||||
@@ -61,7 +62,7 @@ fn slurp(path: *u8) (*u8, u64) = {
|
|||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let nz: u64 = n: u64;
|
let nz: u64 = n: u64;
|
||||||
let buf: *u8 = os.alloc(nz + 1u64): *u8;
|
let buf: *u8 = rt.alloc(nz + 1u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, nz);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, nz);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ fn slurpso(path: *u8) (*u8, u64) = {
|
|||||||
case let v: i64 => n = v;
|
case let v: i64 => n = v;
|
||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let buf: *u8 = os.alloc(n: u64): *u8;
|
let buf: *u8 = rt.alloc(n: u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -657,7 +658,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ---- assemble file buffer ----
|
// ---- assemble file buffer ----
|
||||||
let filebuf: *u8 = os.alloc(fileend): *u8;
|
let filebuf: *u8 = rt.alloc(fileend): *u8;
|
||||||
if (filebuf == nil) {
|
if (filebuf == nil) {
|
||||||
os.write(2, "w6l: out of memory\n".ptr, 18u64);
|
os.write(2, "w6l: out of memory\n".ptr, 18u64);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -110,28 +110,6 @@ import time;
|
|||||||
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
||||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||||
|
|
||||||
// alloc / free — runtime mmap-backed page allocator. Untyped:
|
|
||||||
// `alloc(n)` returns a `*void` and `free(p, n)` requires the byte
|
|
||||||
// count back because rt_free is munmap-based and doesn't track
|
|
||||||
// mapping sizes (the kernel needs the length to release the
|
|
||||||
// reservation).
|
|
||||||
//
|
|
||||||
// Diverges from Hare. Hare exposes `alloc` / `free` as typed
|
|
||||||
// language builtins (`alloc(value, cap)?` / `free(ptr)`) that the
|
|
||||||
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
|
|
||||||
// so the rt-symbol surface is exposed directly. Stdlib callers
|
|
||||||
// that 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 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 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.
|
|
||||||
@symbol("rt_alloc") export fn alloc(n: u64) *void;
|
|
||||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||||
@symbol("rt_abort") fn abort(msg: str) void;
|
@symbol("rt_abort") fn abort(msg: str) void;
|
||||||
|
|
||||||
@@ -749,6 +727,29 @@ export fn exists(path: str) bool = {
|
|||||||
return r >= 0i64;
|
return r >= 0i64;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// rt — runtime primitives exposed to ww programs.
|
||||||
|
// Mirrors Hare's rt:: module placement (ref/hare/rt/).
|
||||||
|
|
||||||
|
package rt;
|
||||||
|
|
||||||
|
// alloc — mmap-backed page allocator. Untyped: `alloc(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,
|
||||||
|
// so the rt-symbol surface is exposed directly. Stdlib callers that
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// 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;
|
||||||
|
|
||||||
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
||||||
//
|
//
|
||||||
// Bump arena allocator. Backed by the runtime page allocator
|
// Bump arena allocator. Backed by the runtime page allocator
|
||||||
@@ -762,6 +763,7 @@ export fn exists(path: str) bool = {
|
|||||||
package wcc;
|
package wcc;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
def ALIGN: u64 = 16u64;
|
def ALIGN: u64 = 16u64;
|
||||||
def INIT_CHUNK: u64 = 65536u64;
|
def INIT_CHUNK: u64 = 65536u64;
|
||||||
@@ -781,8 +783,8 @@ fn roundup(n: u64, a: u64) u64 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export fn newarena() *arena = {
|
export fn newarena() *arena = {
|
||||||
let a: *arena = os.alloc(ARENA_SZ): *arena;
|
let a: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
a.buf = os.alloc(INIT_CHUNK): *u8;
|
a.buf = rt.alloc(INIT_CHUNK): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = INIT_CHUNK;
|
a.cap = INIT_CHUNK;
|
||||||
a.next = nil;
|
a.next = nil;
|
||||||
@@ -799,14 +801,14 @@ fn grow(a: *arena, need: u64) bool = {
|
|||||||
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
||||||
if (want < need) { return false; }; // single allocation too big
|
if (want < need) { return false; }; // single allocation too big
|
||||||
|
|
||||||
let old: *arena = os.alloc(ARENA_SZ): *arena;
|
let old: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
old.buf = a.buf;
|
old.buf = a.buf;
|
||||||
old.off = a.off;
|
old.off = a.off;
|
||||||
old.cap = a.cap;
|
old.cap = a.cap;
|
||||||
old.next = a.next;
|
old.next = a.next;
|
||||||
old.total = 0u64;
|
old.total = 0u64;
|
||||||
|
|
||||||
a.buf = os.alloc(want): *u8;
|
a.buf = rt.alloc(want): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = want;
|
a.cap = want;
|
||||||
a.next = old;
|
a.next = old;
|
||||||
@@ -983,6 +985,7 @@ export fn lookup(l: *lnk, name: str) *lsym = {
|
|||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -1058,7 +1061,7 @@ fn slurp(path: *u8) (*u8, u64) = {
|
|||||||
case let v: i64 => n = v;
|
case let v: i64 => n = v;
|
||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let buf: *u8 = os.alloc(n: u64): *u8;
|
let buf: *u8 = rt.alloc(n: u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
@@ -1080,7 +1083,7 @@ fn emittext(l: *lnk, src: *u8, n: u64) void = {
|
|||||||
// Grow by mmap'ing a fresh region and copying. The old buffer
|
// Grow by mmap'ing a fresh region and copying. The old buffer
|
||||||
// is leaked into the page allocator; for a linker run this is
|
// is leaked into the page allocator; for a linker run this is
|
||||||
// trivial waste.
|
// trivial waste.
|
||||||
let nb: *u8 = os.alloc(nc): *u8;
|
let nb: *u8 = rt.alloc(nc): *u8;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
for (i < l.textlen) {
|
for (i < l.textlen) {
|
||||||
nb[i] = l.text[i];
|
nb[i] = l.text[i];
|
||||||
@@ -1102,7 +1105,7 @@ fn emitdata(l: *lnk, src: *u8, n: u64) void = {
|
|||||||
let nc: u64 = l.datacap;
|
let nc: u64 = l.datacap;
|
||||||
if (nc == 0u64) { nc = 256u64; };
|
if (nc == 0u64) { nc = 256u64; };
|
||||||
for (nc < l.datalen + n) { nc = nc * 2u64; };
|
for (nc < l.datalen + n) { nc = nc * 2u64; };
|
||||||
let nb: *u8 = os.alloc(nc): *u8;
|
let nb: *u8 = rt.alloc(nc): *u8;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
for (i < l.datalen) {
|
for (i < l.datalen) {
|
||||||
nb[i] = l.data[i];
|
nb[i] = l.data[i];
|
||||||
@@ -1594,6 +1597,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -1717,7 +1721,7 @@ fn slurpso(path: *u8) (*u8, u64) = {
|
|||||||
case let v: i64 => n = v;
|
case let v: i64 => n = v;
|
||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let buf: *u8 = os.alloc(n: u64): *u8;
|
let buf: *u8 = rt.alloc(n: u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
@@ -2145,6 +2149,7 @@ export fn relocate(l: *lnk, textva: u64, datava: u64) i32 = {
|
|||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -2777,7 +2782,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ---- assemble file buffer ----
|
// ---- assemble file buffer ----
|
||||||
let filebuf: *u8 = os.alloc(fileend): *u8;
|
let filebuf: *u8 = rt.alloc(fileend): *u8;
|
||||||
if (filebuf == nil) {
|
if (filebuf == nil) {
|
||||||
os.write(2, "w6l: out of memory\n".ptr, 18u64);
|
os.write(2, "w6l: out of memory\n".ptr, 18u64);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -2889,6 +2894,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
|||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import sym;
|
import sym;
|
||||||
import dynout;
|
import dynout;
|
||||||
|
|
||||||
@@ -2967,7 +2973,7 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
|||||||
let datafilelen: u64 = l.datalen - bsslen;
|
let datafilelen: u64 = l.datalen - bsslen;
|
||||||
|
|
||||||
// One contiguous header buffer covering [0..0x1000), then .text.
|
// One contiguous header buffer covering [0..0x1000), then .text.
|
||||||
let hdr: *u8 = os.alloc(TEXT_OFF): *u8; // zero-initialised by mmap
|
let hdr: *u8 = rt.alloc(TEXT_OFF): *u8; // zero-initialised by mmap
|
||||||
|
|
||||||
// --- Ehdr (64 bytes) ---
|
// --- Ehdr (64 bytes) ---
|
||||||
hdr[0u64] = 127u8; // 0x7f
|
hdr[0u64] = 127u8; // 0x7f
|
||||||
@@ -3067,6 +3073,7 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
|||||||
package main;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import sym;
|
import sym;
|
||||||
import obj;
|
import obj;
|
||||||
@@ -3121,7 +3128,7 @@ fn appenddec(dst: *u8, i: u64, n: u64) u64 = {
|
|||||||
dst[i] = 48u8;
|
dst[i] = 48u8;
|
||||||
return i + 1u64;
|
return i + 1u64;
|
||||||
};
|
};
|
||||||
let buf: *u8 = os.alloc(16u64): *u8;
|
let buf: *u8 = rt.alloc(16u64): *u8;
|
||||||
let k: u64 = 0u64;
|
let k: u64 = 0u64;
|
||||||
let v: u64 = n;
|
let v: u64 = n;
|
||||||
for (v > 0u64) {
|
for (v > 0u64) {
|
||||||
@@ -3160,7 +3167,7 @@ fn buildpathv(dst: *u8, dir: *u8, name: *u8, v: u64) u64 = {
|
|||||||
fn islinkable(path: *u8) bool = {
|
fn islinkable(path: *u8) bool = {
|
||||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||||
if (fd < 0) { return false; };
|
if (fd < 0) { return false; };
|
||||||
let mp: *u8 = os.alloc(8u64): *u8;
|
let mp: *u8 = rt.alloc(8u64): *u8;
|
||||||
let n: i64 = os.read(fd, mp, 8u64);
|
let n: i64 = os.read(fd, mp, 8u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
if (n < 4i64) { return false; };
|
if (n < 4i64) { return false; };
|
||||||
@@ -3188,7 +3195,7 @@ fn islinkable(path: *u8) bool = {
|
|||||||
// then lib<name>.a. Return arena-owned NUL-terminated path on success,
|
// then lib<name>.a. Return arena-owned NUL-terminated path on success,
|
||||||
// nil on miss.
|
// nil on miss.
|
||||||
fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
||||||
let bufp: *u8 = os.alloc(1024u64): *u8;
|
let bufp: *u8 = rt.alloc(1024u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < nlibdirs) {
|
for (i < nlibdirs) {
|
||||||
let dir: *u8 = libdirs[i];
|
let dir: *u8 = libdirs[i];
|
||||||
@@ -3229,7 +3236,7 @@ fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
|||||||
fn isso(path: *u8) i32 = {
|
fn isso(path: *u8) i32 = {
|
||||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||||
if (fd < 0) { return 0; };
|
if (fd < 0) { return 0; };
|
||||||
let mp: *u8 = os.alloc(20u64): *u8;
|
let mp: *u8 = rt.alloc(20u64): *u8;
|
||||||
let n: i64 = os.read(fd, mp, 20u64);
|
let n: i64 = os.read(fd, mp, 20u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
if (n < 20i64) { return 0; };
|
if (n < 20i64) { return 0; };
|
||||||
@@ -3246,11 +3253,11 @@ fn isso(path: *u8) i32 = {
|
|||||||
export fn main(argc: i32, argv: **u8) i32 = {
|
export fn main(argc: i32, argv: **u8) i32 = {
|
||||||
let outpath: *u8 = nil;
|
let outpath: *u8 = nil;
|
||||||
let maxinputs: i32 = 64;
|
let maxinputs: i32 = 64;
|
||||||
let inputs: **u8 = os.alloc((maxinputs: u64) * 8u64): **u8;
|
let inputs: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||||
let ninputs: i32 = 0;
|
let ninputs: i32 = 0;
|
||||||
let libdirs: **u8 = os.alloc((maxinputs: u64) * 8u64): **u8;
|
let libdirs: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||||
let nlibdirs: i32 = 0;
|
let nlibdirs: i32 = 0;
|
||||||
let lflags: **u8 = os.alloc((maxinputs: u64) * 8u64): **u8;
|
let lflags: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||||
let nlflags: i32 = 0;
|
let nlflags: i32 = 0;
|
||||||
|
|
||||||
let i: i32 = 1;
|
let i: i32 = 1;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
package main;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import sym;
|
import sym;
|
||||||
import obj;
|
import obj;
|
||||||
@@ -63,7 +64,7 @@ fn appenddec(dst: *u8, i: u64, n: u64) u64 = {
|
|||||||
dst[i] = 48u8;
|
dst[i] = 48u8;
|
||||||
return i + 1u64;
|
return i + 1u64;
|
||||||
};
|
};
|
||||||
let buf: *u8 = os.alloc(16u64): *u8;
|
let buf: *u8 = rt.alloc(16u64): *u8;
|
||||||
let k: u64 = 0u64;
|
let k: u64 = 0u64;
|
||||||
let v: u64 = n;
|
let v: u64 = n;
|
||||||
for (v > 0u64) {
|
for (v > 0u64) {
|
||||||
@@ -102,7 +103,7 @@ fn buildpathv(dst: *u8, dir: *u8, name: *u8, v: u64) u64 = {
|
|||||||
fn islinkable(path: *u8) bool = {
|
fn islinkable(path: *u8) bool = {
|
||||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||||
if (fd < 0) { return false; };
|
if (fd < 0) { return false; };
|
||||||
let mp: *u8 = os.alloc(8u64): *u8;
|
let mp: *u8 = rt.alloc(8u64): *u8;
|
||||||
let n: i64 = os.read(fd, mp, 8u64);
|
let n: i64 = os.read(fd, mp, 8u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
if (n < 4i64) { return false; };
|
if (n < 4i64) { return false; };
|
||||||
@@ -130,7 +131,7 @@ fn islinkable(path: *u8) bool = {
|
|||||||
// then lib<name>.a. Return arena-owned NUL-terminated path on success,
|
// then lib<name>.a. Return arena-owned NUL-terminated path on success,
|
||||||
// nil on miss.
|
// nil on miss.
|
||||||
fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
||||||
let bufp: *u8 = os.alloc(1024u64): *u8;
|
let bufp: *u8 = rt.alloc(1024u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < nlibdirs) {
|
for (i < nlibdirs) {
|
||||||
let dir: *u8 = libdirs[i];
|
let dir: *u8 = libdirs[i];
|
||||||
@@ -171,7 +172,7 @@ fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
|||||||
fn isso(path: *u8) i32 = {
|
fn isso(path: *u8) i32 = {
|
||||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||||
if (fd < 0) { return 0; };
|
if (fd < 0) { return 0; };
|
||||||
let mp: *u8 = os.alloc(20u64): *u8;
|
let mp: *u8 = rt.alloc(20u64): *u8;
|
||||||
let n: i64 = os.read(fd, mp, 20u64);
|
let n: i64 = os.read(fd, mp, 20u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
if (n < 20i64) { return 0; };
|
if (n < 20i64) { return 0; };
|
||||||
@@ -188,11 +189,11 @@ fn isso(path: *u8) i32 = {
|
|||||||
export fn main(argc: i32, argv: **u8) i32 = {
|
export fn main(argc: i32, argv: **u8) i32 = {
|
||||||
let outpath: *u8 = nil;
|
let outpath: *u8 = nil;
|
||||||
let maxinputs: i32 = 64;
|
let maxinputs: i32 = 64;
|
||||||
let inputs: **u8 = os.alloc((maxinputs: u64) * 8u64): **u8;
|
let inputs: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||||
let ninputs: i32 = 0;
|
let ninputs: i32 = 0;
|
||||||
let libdirs: **u8 = os.alloc((maxinputs: u64) * 8u64): **u8;
|
let libdirs: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||||
let nlibdirs: i32 = 0;
|
let nlibdirs: i32 = 0;
|
||||||
let lflags: **u8 = os.alloc((maxinputs: u64) * 8u64): **u8;
|
let lflags: **u8 = rt.alloc((maxinputs: u64) * 8u64): **u8;
|
||||||
let nlflags: i32 = 0;
|
let nlflags: i32 = 0;
|
||||||
|
|
||||||
let i: i32 = 1;
|
let i: i32 = 1;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ fn slurp(path: *u8) (*u8, u64) = {
|
|||||||
case let v: i64 => n = v;
|
case let v: i64 => n = v;
|
||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let buf: *u8 = os.alloc(n: u64): *u8;
|
let buf: *u8 = rt.alloc(n: u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, n: u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
@@ -108,7 +109,7 @@ fn emittext(l: *lnk, src: *u8, n: u64) void = {
|
|||||||
// Grow by mmap'ing a fresh region and copying. The old buffer
|
// Grow by mmap'ing a fresh region and copying. The old buffer
|
||||||
// is leaked into the page allocator; for a linker run this is
|
// is leaked into the page allocator; for a linker run this is
|
||||||
// trivial waste.
|
// trivial waste.
|
||||||
let nb: *u8 = os.alloc(nc): *u8;
|
let nb: *u8 = rt.alloc(nc): *u8;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
for (i < l.textlen) {
|
for (i < l.textlen) {
|
||||||
nb[i] = l.text[i];
|
nb[i] = l.text[i];
|
||||||
@@ -130,7 +131,7 @@ fn emitdata(l: *lnk, src: *u8, n: u64) void = {
|
|||||||
let nc: u64 = l.datacap;
|
let nc: u64 = l.datacap;
|
||||||
if (nc == 0u64) { nc = 256u64; };
|
if (nc == 0u64) { nc = 256u64; };
|
||||||
for (nc < l.datalen + n) { nc = nc * 2u64; };
|
for (nc < l.datalen + n) { nc = nc * 2u64; };
|
||||||
let nb: *u8 = os.alloc(nc): *u8;
|
let nb: *u8 = rt.alloc(nc): *u8;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
for (i < l.datalen) {
|
for (i < l.datalen) {
|
||||||
nb[i] = l.data[i];
|
nb[i] = l.data[i];
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import sym;
|
import sym;
|
||||||
import dynout;
|
import dynout;
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
|||||||
let datafilelen: u64 = l.datalen - bsslen;
|
let datafilelen: u64 = l.datalen - bsslen;
|
||||||
|
|
||||||
// One contiguous header buffer covering [0..0x1000), then .text.
|
// One contiguous header buffer covering [0..0x1000), then .text.
|
||||||
let hdr: *u8 = os.alloc(TEXT_OFF): *u8; // zero-initialised by mmap
|
let hdr: *u8 = rt.alloc(TEXT_OFF): *u8; // zero-initialised by mmap
|
||||||
|
|
||||||
// --- Ehdr (64 bytes) ---
|
// --- Ehdr (64 bytes) ---
|
||||||
hdr[0u64] = 127u8; // 0x7f
|
hdr[0u64] = 127u8; // 0x7f
|
||||||
|
|||||||
@@ -171,10 +171,10 @@ fn cgtryprop(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len > 0) {
|
if (cname.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTAGGED) {
|
if (rtyp.kind == nkind.N_TTAGGED) {
|
||||||
let first: *node = rt.list;
|
let first: *node = rtyp.list;
|
||||||
if (first != nil) {
|
if (first != nil) {
|
||||||
if (isstrtype(c, first)) {
|
if (isstrtype(c, first)) {
|
||||||
succisstr = true;
|
succisstr = true;
|
||||||
@@ -227,10 +227,10 @@ fn cgtryunw(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len > 0) {
|
if (cname.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTAGGED) {
|
if (rtyp.kind == nkind.N_TTAGGED) {
|
||||||
let first: *node = rt.list;
|
let first: *node = rtyp.list;
|
||||||
if (first != nil) {
|
if (first != nil) {
|
||||||
if (isstrtype(c, first)) {
|
if (isstrtype(c, first)) {
|
||||||
succisstr = true;
|
succisstr = true;
|
||||||
@@ -607,8 +607,8 @@ fn cgident(c: *cgen, n: *node) void = {
|
|||||||
// in one go, so a body-less FFI binding emits the C symbol
|
// in one go, so a body-less FFI binding emits the C symbol
|
||||||
// it was declared with via @symbol(), not the ww-side ident.
|
// it was declared with via @symbol(), not the ww-side ident.
|
||||||
// Bare ident → same-module by ww's resolver, hint with c.curmod.
|
// Bare ident → same-module by ww's resolver, hint with c.curmod.
|
||||||
let rt: *node = fnretlookup(c, nm);
|
let rtyp: *node = fnretlookup(c, nm);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
emitline("\tLEAQ\t");
|
emitline("\tLEAQ\t");
|
||||||
emitfnname(c, nm, c.curmod);
|
emitfnname(c, nm, c.curmod);
|
||||||
emitline("(SB), AX\n");
|
emitline("(SB), AX\n");
|
||||||
@@ -3421,8 +3421,8 @@ fn cgcall(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (isstrtype(c, rt)) {
|
if (isstrtype(c, rtyp)) {
|
||||||
emitline("\tMOVQ\tDX, BX\n");
|
emitline("\tMOVQ\tDX, BX\n");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -184,8 +184,8 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (calleename.len > 0) {
|
if (calleename.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (istaggedtype(c, rt)) { forwardtagged = true; };
|
if (istaggedtype(c, rtyp)) { forwardtagged = true; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1225,10 +1225,10 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cnm.len > 0) {
|
if (cnm.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cnm, cmod);
|
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTUPLE) {
|
if (rtyp.kind == nkind.N_TTUPLE) {
|
||||||
p0t = rt.list;
|
p0t = rtyp.list;
|
||||||
if (p0t != nil) { p1t = p0t.next; };
|
if (p0t != nil) { p1t = p0t.next; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -516,9 +516,9 @@ export fn taggedcallslot(c: *cgen, n: *node) i32 = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee == nil) { return 0; };
|
if (callee == nil) { return 0; };
|
||||||
if (callee.kind != nkind.N_IDENT) { return 0; };
|
if (callee.kind != nkind.N_IDENT) { return 0; };
|
||||||
let rt: *node = fnretlookup(c, callee.str);
|
let rtyp: *node = fnretlookup(c, callee.str);
|
||||||
if (!istaggedtype(c, rt)) { return 0; };
|
if (!istaggedtype(c, rtyp)) { return 0; };
|
||||||
return slotsize(c, rt);
|
return slotsize(c, rtyp);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn nodeisslice(c: *cgen, n: *node) bool = {
|
fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||||
@@ -547,8 +547,8 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee != nil) {
|
if (callee != nil) {
|
||||||
if (callee.kind == nkind.N_IDENT) {
|
if (callee.kind == nkind.N_IDENT) {
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, c.curmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
|
||||||
return isslicetype(c, rt);
|
return isslicetype(c, rtyp);
|
||||||
};
|
};
|
||||||
if (callee.kind == nkind.N_DOT) {
|
if (callee.kind == nkind.N_DOT) {
|
||||||
let cmod: str;
|
let cmod: str;
|
||||||
@@ -558,8 +558,8 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
|||||||
cmod = callee.lhs.str;
|
cmod = callee.lhs.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, cmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
|
||||||
return isslicetype(c, rt);
|
return isslicetype(c, rtyp);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
@@ -674,8 +674,8 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee != nil) {
|
if (callee != nil) {
|
||||||
if (callee.kind == nkind.N_IDENT) {
|
if (callee.kind == nkind.N_IDENT) {
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, c.curmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
|
||||||
return isstrtype(c, rt);
|
return isstrtype(c, rtyp);
|
||||||
};
|
};
|
||||||
// #34: cross-module N_DOT — route through fnretlookupmod
|
// #34: cross-module N_DOT — route through fnretlookupmod
|
||||||
// so a same-leaf caller-module fn (different return shape)
|
// so a same-leaf caller-module fn (different return shape)
|
||||||
@@ -688,8 +688,8 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
|||||||
cmod = callee.lhs.str;
|
cmod = callee.lhs.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, cmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
|
||||||
return isstrtype(c, rt);
|
return isstrtype(c, rtyp);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
@@ -1605,8 +1605,8 @@ export fn callsretsize(c: *cgen, n: *node) i32 = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cn.len == 0) { return 0; };
|
if (cn.len == 0) { return 0; };
|
||||||
let rt: *node = fnretlookupmod(c, cn, cmod);
|
let rtyp: *node = fnretlookupmod(c, cn, cmod);
|
||||||
return sretretsize(c, rt);
|
return sretretsize(c, rtyp);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn structlookup(c: *cgen, name: str) *structinfo = {
|
fn structlookup(c: *cgen, name: str) *structinfo = {
|
||||||
@@ -1863,16 +1863,16 @@ fn inferletcalltype(c: *cgen, rhs: *node) *node = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len == 0) { return nil; };
|
if (cname.len == 0) { return nil; };
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt == nil) { return nil; };
|
if (rtyp == nil) { return nil; };
|
||||||
if (unwrap) {
|
if (unwrap) {
|
||||||
// Strip error variants — success type is the first
|
// Strip error variants — success type is the first
|
||||||
// variant of the tagged return.
|
// variant of the tagged return.
|
||||||
if (rt.kind != nkind.N_TTAGGED) { return nil; };
|
if (rtyp.kind != nkind.N_TTAGGED) { return nil; };
|
||||||
return rt.list;
|
return rtyp.list;
|
||||||
};
|
};
|
||||||
// Plain call: declared return type is the local's type.
|
// Plain call: declared return type is the local's type.
|
||||||
return rt;
|
return rtyp;
|
||||||
};
|
};
|
||||||
|
|
||||||
// letslotsize — slot size for a `let` binding. Like slotsize, but
|
// letslotsize — slot size for a `let` binding. Like slotsize, but
|
||||||
@@ -2339,8 +2339,8 @@ fn matchscrutt(c: *cgen, scrut: *node) *node = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cnm.len > 0) {
|
if (cnm.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cnm, cmod);
|
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||||
if (rt != nil) { return resolvetagged(c, rt); };
|
if (rtyp != nil) { return resolvetagged(c, rtyp); };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return nil;
|
return nil;
|
||||||
@@ -2534,9 +2534,9 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
|||||||
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
|
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
|
||||||
};
|
};
|
||||||
if (nm.len > 0) {
|
if (nm.len > 0) {
|
||||||
let rt: *node = fnretlookup(c, nm);
|
let rtyp: *node = fnretlookup(c, nm);
|
||||||
if (isf32type(c, rt)) { return 1; };
|
if (isf32type(c, rtyp)) { return 1; };
|
||||||
if (isfloattype(c, rt)) { return 2; };
|
if (isfloattype(c, rtyp)) { return 2; };
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
@@ -3055,9 +3055,9 @@ fn rhstaggedabicall(c: *cgen, src: *node) bool = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (calleename.len > 0) {
|
if (calleename.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (istaggedtype(c, rt)) { return true; };
|
if (istaggedtype(c, rtyp)) { return true; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -812,15 +812,15 @@ fn astoffset(c: *checker, dot: *node) i64 = {
|
|||||||
if (dot.kind != nkind.N_DOT) { return -1i64; };
|
if (dot.kind != nkind.N_DOT) { return -1i64; };
|
||||||
let recv: *node = scruttype(c, dot.lhs);
|
let recv: *node = scruttype(c, dot.lhs);
|
||||||
if (recv == nil) { return -1i64; };
|
if (recv == nil) { return -1i64; };
|
||||||
let rt: *node = resolvealias(c, unwrapbang(recv));
|
let rtyp: *node = resolvealias(c, unwrapbang(recv));
|
||||||
if (rt == nil) { return -1i64; };
|
if (rtyp == nil) { return -1i64; };
|
||||||
if (rt.kind == nkind.N_TPTR) {
|
if (rtyp.kind == nkind.N_TPTR) {
|
||||||
rt = resolvealias(c, unwrapbang(rt.lhs));
|
rtyp = resolvealias(c, unwrapbang(rtyp.lhs));
|
||||||
};
|
};
|
||||||
if (rt == nil) { return -1i64; };
|
if (rtyp == nil) { return -1i64; };
|
||||||
if (rt.kind != nkind.N_TSTRUCT) { return -1i64; };
|
if (rtyp.kind != nkind.N_TSTRUCT) { return -1i64; };
|
||||||
let off: i64 = 0i64;
|
let off: i64 = 0i64;
|
||||||
let f: *node = rt.list;
|
let f: *node = rtyp.list;
|
||||||
for (f != nil) {
|
for (f != nil) {
|
||||||
if (f.kind == nkind.N_TFIELD) {
|
if (f.kind == nkind.N_TFIELD) {
|
||||||
let fa: i64 = astalign(c, f.lhs);
|
let fa: i64 = astalign(c, f.lhs);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
package wcc;
|
package wcc;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
def ALIGN: u64 = 16u64;
|
def ALIGN: u64 = 16u64;
|
||||||
def INIT_CHUNK: u64 = 65536u64;
|
def INIT_CHUNK: u64 = 65536u64;
|
||||||
@@ -30,8 +31,8 @@ fn roundup(n: u64, a: u64) u64 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export fn newarena() *arena = {
|
export fn newarena() *arena = {
|
||||||
let a: *arena = os.alloc(ARENA_SZ): *arena;
|
let a: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
a.buf = os.alloc(INIT_CHUNK): *u8;
|
a.buf = rt.alloc(INIT_CHUNK): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = INIT_CHUNK;
|
a.cap = INIT_CHUNK;
|
||||||
a.next = nil;
|
a.next = nil;
|
||||||
@@ -48,14 +49,14 @@ fn grow(a: *arena, need: u64) bool = {
|
|||||||
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
||||||
if (want < need) { return false; }; // single allocation too big
|
if (want < need) { return false; }; // single allocation too big
|
||||||
|
|
||||||
let old: *arena = os.alloc(ARENA_SZ): *arena;
|
let old: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
old.buf = a.buf;
|
old.buf = a.buf;
|
||||||
old.off = a.off;
|
old.off = a.off;
|
||||||
old.cap = a.cap;
|
old.cap = a.cap;
|
||||||
old.next = a.next;
|
old.next = a.next;
|
||||||
old.total = 0u64;
|
old.total = 0u64;
|
||||||
|
|
||||||
a.buf = os.alloc(want): *u8;
|
a.buf = rt.alloc(want): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = want;
|
a.cap = want;
|
||||||
a.next = old;
|
a.next = old;
|
||||||
|
|||||||
@@ -110,28 +110,6 @@ import time;
|
|||||||
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
||||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||||
|
|
||||||
// alloc / free — runtime mmap-backed page allocator. Untyped:
|
|
||||||
// `alloc(n)` returns a `*void` and `free(p, n)` requires the byte
|
|
||||||
// count back because rt_free is munmap-based and doesn't track
|
|
||||||
// mapping sizes (the kernel needs the length to release the
|
|
||||||
// reservation).
|
|
||||||
//
|
|
||||||
// Diverges from Hare. Hare exposes `alloc` / `free` as typed
|
|
||||||
// language builtins (`alloc(value, cap)?` / `free(ptr)`) that the
|
|
||||||
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
|
|
||||||
// so the rt-symbol surface is exposed directly. Stdlib callers
|
|
||||||
// that 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 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 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.
|
|
||||||
@symbol("rt_alloc") export fn alloc(n: u64) *void;
|
|
||||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||||
@symbol("rt_abort") fn abort(msg: str) void;
|
@symbol("rt_abort") fn abort(msg: str) void;
|
||||||
|
|
||||||
@@ -749,6 +727,29 @@ export fn exists(path: str) bool = {
|
|||||||
return r >= 0i64;
|
return r >= 0i64;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// rt — runtime primitives exposed to ww programs.
|
||||||
|
// Mirrors Hare's rt:: module placement (ref/hare/rt/).
|
||||||
|
|
||||||
|
package rt;
|
||||||
|
|
||||||
|
// alloc — mmap-backed page allocator. Untyped: `alloc(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,
|
||||||
|
// so the rt-symbol surface is exposed directly. Stdlib callers that
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// 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;
|
||||||
|
|
||||||
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
||||||
//
|
//
|
||||||
// Bump arena allocator. Backed by the runtime page allocator
|
// Bump arena allocator. Backed by the runtime page allocator
|
||||||
@@ -762,6 +763,7 @@ export fn exists(path: str) bool = {
|
|||||||
package wcc;
|
package wcc;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
def ALIGN: u64 = 16u64;
|
def ALIGN: u64 = 16u64;
|
||||||
def INIT_CHUNK: u64 = 65536u64;
|
def INIT_CHUNK: u64 = 65536u64;
|
||||||
@@ -781,8 +783,8 @@ fn roundup(n: u64, a: u64) u64 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export fn newarena() *arena = {
|
export fn newarena() *arena = {
|
||||||
let a: *arena = os.alloc(ARENA_SZ): *arena;
|
let a: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
a.buf = os.alloc(INIT_CHUNK): *u8;
|
a.buf = rt.alloc(INIT_CHUNK): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = INIT_CHUNK;
|
a.cap = INIT_CHUNK;
|
||||||
a.next = nil;
|
a.next = nil;
|
||||||
@@ -799,14 +801,14 @@ fn grow(a: *arena, need: u64) bool = {
|
|||||||
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
||||||
if (want < need) { return false; }; // single allocation too big
|
if (want < need) { return false; }; // single allocation too big
|
||||||
|
|
||||||
let old: *arena = os.alloc(ARENA_SZ): *arena;
|
let old: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
old.buf = a.buf;
|
old.buf = a.buf;
|
||||||
old.off = a.off;
|
old.off = a.off;
|
||||||
old.cap = a.cap;
|
old.cap = a.cap;
|
||||||
old.next = a.next;
|
old.next = a.next;
|
||||||
old.total = 0u64;
|
old.total = 0u64;
|
||||||
|
|
||||||
a.buf = os.alloc(want): *u8;
|
a.buf = rt.alloc(want): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = want;
|
a.cap = want;
|
||||||
a.next = old;
|
a.next = old;
|
||||||
@@ -874,6 +876,7 @@ export fn freearena(a: *arena) void = {
|
|||||||
package main;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
|
|
||||||
// All path/string scratch buffers go on the runtime page allocator.
|
// All path/string scratch buffers go on the runtime page allocator.
|
||||||
@@ -998,7 +1001,7 @@ fn selfdirinto(dst: *u8, dstsz: u64, argv0: *u8) void = {
|
|||||||
|
|
||||||
// Build "$dir/$name" (NUL-terminated) into a fresh page-sized buffer.
|
// Build "$dir/$name" (NUL-terminated) into a fresh page-sized buffer.
|
||||||
fn joinpath(dir: *u8, name: *u8) *u8 = {
|
fn joinpath(dir: *u8, name: *u8) *u8 = {
|
||||||
let buf: *u8 = os.alloc(PATH_MAX): *u8;
|
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let off: u64 = cstrinto(buf, 0u64, dir);
|
let off: u64 = cstrinto(buf, 0u64, dir);
|
||||||
off = byteinto(buf, off, 47u8);
|
off = byteinto(buf, off, 47u8);
|
||||||
off = cstrinto(buf, off, name);
|
off = cstrinto(buf, off, name);
|
||||||
@@ -1008,7 +1011,7 @@ fn joinpath(dir: *u8, name: *u8) *u8 = {
|
|||||||
|
|
||||||
// Same, but the second component is a ww `str` literal.
|
// Same, but the second component is a ww `str` literal.
|
||||||
fn joinpathlit(dir: *u8, name: str) *u8 = {
|
fn joinpathlit(dir: *u8, name: str) *u8 = {
|
||||||
let buf: *u8 = os.alloc(PATH_MAX): *u8;
|
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let off: u64 = cstrinto(buf, 0u64, dir);
|
let off: u64 = cstrinto(buf, 0u64, dir);
|
||||||
off = byteinto(buf, off, 47u8);
|
off = byteinto(buf, off, 47u8);
|
||||||
off = strinto(buf, off, name);
|
off = strinto(buf, off, name);
|
||||||
@@ -1259,7 +1262,7 @@ fn enumeratedir(a: *arena, dirpath: *u8) (**u8, i32) = {
|
|||||||
let names: **u8 = amalloc(a, (maxnames: u64) * 8u64): **u8;
|
let names: **u8 = amalloc(a, (maxnames: u64) * 8u64): **u8;
|
||||||
let nlens: *u64 = amalloc(a, (maxnames: u64) * 8u64): *u64;
|
let nlens: *u64 = amalloc(a, (maxnames: u64) * 8u64): *u64;
|
||||||
let n: i32 = 0;
|
let n: i32 = 0;
|
||||||
let buf: *u8 = os.alloc(8192u64): *u8;
|
let buf: *u8 = rt.alloc(8192u64): *u8;
|
||||||
let r: i64 = os.getdents64(fd, buf, 8192u64);
|
let r: i64 = os.getdents64(fd, buf, 8192u64);
|
||||||
for (r > 0i64) {
|
for (r > 0i64) {
|
||||||
let off: u64 = 0u64;
|
let off: u64 = 0u64;
|
||||||
@@ -1321,7 +1324,7 @@ fn slurp(pathcs: *u8) (*u8, u64) = {
|
|||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let nu: u64 = n: u64;
|
let nu: u64 = n: u64;
|
||||||
let buf: *u8 = os.alloc(nu + 1u64): *u8;
|
let buf: *u8 = rt.alloc(nu + 1u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, nu);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, nu);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
@@ -1428,7 +1431,7 @@ fn expand(c: *expctx, pathcs: *u8) void = {
|
|||||||
fn peekpackage(a: *arena, pathcs: *u8) *u8 = {
|
fn peekpackage(a: *arena, pathcs: *u8) *u8 = {
|
||||||
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
|
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
|
||||||
if (fd < 0) { return nil; };
|
if (fd < 0) { return nil; };
|
||||||
let buf: *u8 = os.alloc(2048u64): *u8;
|
let buf: *u8 = rt.alloc(2048u64): *u8;
|
||||||
let n: i64 = os.read(fd, buf, 2048u64);
|
let n: i64 = os.read(fd, buf, 2048u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
if (n <= 0i64) { return nil; };
|
if (n <= 0i64) { return nil; };
|
||||||
@@ -1575,7 +1578,7 @@ fn makestem(stem: *u8, src: *u8) void = {
|
|||||||
|
|
||||||
// Append a literal suffix to `stem` (which already lives in a buffer).
|
// Append a literal suffix to `stem` (which already lives in a buffer).
|
||||||
fn appendlit(stem: *u8, suffix: str) *u8 = {
|
fn appendlit(stem: *u8, suffix: str) *u8 = {
|
||||||
let buf: *u8 = os.alloc(PATH_MAX): *u8;
|
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let off: u64 = cstrinto(buf, 0u64, stem);
|
let off: u64 = cstrinto(buf, 0u64, stem);
|
||||||
off = strinto(buf, off, suffix);
|
off = strinto(buf, off, suffix);
|
||||||
cstrseal(buf, off);
|
cstrseal(buf, off);
|
||||||
@@ -1613,7 +1616,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
|
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
|
||||||
|
|
||||||
// Default lib search path: <selfdir>/../../lib
|
// Default lib search path: <selfdir>/../../lib
|
||||||
let dotdotlib: *u8 = os.alloc(PATH_MAX): *u8;
|
let dotdotlib: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
{
|
{
|
||||||
let off: u64 = cstrinto(dotdotlib, 0u64, selfdir);
|
let off: u64 = cstrinto(dotdotlib, 0u64, selfdir);
|
||||||
off = strinto(dotdotlib, off, "/../../lib");
|
off = strinto(dotdotlib, off, "/../../lib");
|
||||||
@@ -1626,7 +1629,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
// convention assumes you're running from the module dir; our
|
// convention assumes you're running from the module dir; our
|
||||||
// wrappers don't cd, so dirname(src) stands in as the closest
|
// wrappers don't cd, so dirname(src) stands in as the closest
|
||||||
// analog. Source-dir wins ties over the system path (cc -I.).
|
// analog. Source-dir wins ties over the system path (cc -I.).
|
||||||
let srcd: *u8 = os.alloc(PATH_MAX): *u8;
|
let srcd: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
if (entryisdir != 0) {
|
if (entryisdir != 0) {
|
||||||
let slen: u64 = cstrlen(src);
|
let slen: u64 = cstrlen(src);
|
||||||
let k: u64 = 0u64;
|
let k: u64 = 0u64;
|
||||||
@@ -1660,7 +1663,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Compose searchpath: srcd + ':' + incs + ':' + dotdotlib.
|
// Compose searchpath: srcd + ':' + incs + ':' + dotdotlib.
|
||||||
let searchpath: *u8 = os.alloc(PATH_MAX * 3u64): *u8;
|
let searchpath: *u8 = rt.alloc(PATH_MAX * 3u64): *u8;
|
||||||
{
|
{
|
||||||
let off: u64 = cstrinto(searchpath, 0u64, srcd);
|
let off: u64 = cstrinto(searchpath, 0u64, srcd);
|
||||||
off = byteinto(searchpath, off, 58u8); // ':'
|
off = byteinto(searchpath, off, 58u8); // ':'
|
||||||
@@ -1674,7 +1677,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
|
|
||||||
// Stem for .s/.o/.combined.ww side files. Dir entry: <dir>/<base>;
|
// Stem for .s/.o/.combined.ww side files. Dir entry: <dir>/<base>;
|
||||||
// file entry: src stripped of .ww.
|
// file entry: src stripped of .ww.
|
||||||
let stem: *u8 = os.alloc(PATH_MAX): *u8;
|
let stem: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
if (entryisdir != 0) {
|
if (entryisdir != 0) {
|
||||||
let dlen: u64 = cstrlen(srcd);
|
let dlen: u64 = cstrlen(srcd);
|
||||||
let bo: u64 = basenameoff(srcd, dlen);
|
let bo: u64 = basenameoff(srcd, dlen);
|
||||||
@@ -1691,7 +1694,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
let combined: *u8 = appendlit(stem, ".combined.ww");
|
let combined: *u8 = appendlit(stem, ".combined.ww");
|
||||||
|
|
||||||
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
|
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
|
||||||
let libwwrt: *u8 = os.alloc(PATH_MAX): *u8;
|
let libwwrt: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
{
|
{
|
||||||
let off: u64 = cstrinto(libwwrt, 0u64, selfdir);
|
let off: u64 = cstrinto(libwwrt, 0u64, selfdir);
|
||||||
off = strinto(libwwrt, off, "/../lib/libwwrt.a");
|
off = strinto(libwwrt, off, "/../lib/libwwrt.a");
|
||||||
@@ -1718,7 +1721,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
|
|
||||||
// Step 2: w6c -o <stem>.s <stem>.combined.ww
|
// Step 2: w6c -o <stem>.s <stem>.combined.ww
|
||||||
{
|
{
|
||||||
let argv: **u8 = os.alloc(40u64): **u8;
|
let argv: **u8 = rt.alloc(40u64): **u8;
|
||||||
argv[0] = "w6c\0".ptr;
|
argv[0] = "w6c\0".ptr;
|
||||||
argv[1] = "-o\0".ptr;
|
argv[1] = "-o\0".ptr;
|
||||||
argv[2] = asmf;
|
argv[2] = asmf;
|
||||||
@@ -1732,7 +1735,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
|
|
||||||
// Step 3: w6a -o <stem>.o <stem>.s
|
// Step 3: w6a -o <stem>.o <stem>.s
|
||||||
{
|
{
|
||||||
let argv: **u8 = os.alloc(40u64): **u8;
|
let argv: **u8 = rt.alloc(40u64): **u8;
|
||||||
argv[0] = "w6a\0".ptr;
|
argv[0] = "w6a\0".ptr;
|
||||||
argv[1] = "-o\0".ptr;
|
argv[1] = "-o\0".ptr;
|
||||||
argv[2] = objf;
|
argv[2] = objf;
|
||||||
@@ -1761,7 +1764,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
// + 2 * nlibs (-l, name)
|
// + 2 * nlibs (-l, name)
|
||||||
// + 1 nil terminator.
|
// + 1 nil terminator.
|
||||||
let total: i32 = 5 + 2 * nldirs + 2 * nllibs + 1;
|
let total: i32 = 5 + 2 * nldirs + 2 * nllibs + 1;
|
||||||
let argv: **u8 = os.alloc((total: u64) * 8u64): **u8;
|
let argv: **u8 = rt.alloc((total: u64) * 8u64): **u8;
|
||||||
argv[0] = "w6l\0".ptr;
|
argv[0] = "w6l\0".ptr;
|
||||||
argv[1] = "-o\0".ptr;
|
argv[1] = "-o\0".ptr;
|
||||||
argv[2] = out;
|
argv[2] = out;
|
||||||
@@ -1933,7 +1936,7 @@ fn defaultoutpath(src: *u8) *u8 = {
|
|||||||
if (src[i] == 47u8) { start = i + 1u64; }; // '/'
|
if (src[i] == 47u8) { start = i + 1u64; }; // '/'
|
||||||
i += 1u64;
|
i += 1u64;
|
||||||
};
|
};
|
||||||
let out: *u8 = os.alloc(PATH_MAX): *u8;
|
let out: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let off: u64 = 0u64;
|
let off: u64 = 0u64;
|
||||||
let j: u64 = start;
|
let j: u64 = start;
|
||||||
for (j < n) {
|
for (j < n) {
|
||||||
@@ -1958,14 +1961,14 @@ fn defaultoutpath(src: *u8) *u8 = {
|
|||||||
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||||
let a: *arena = newarena();
|
let a: *arena = newarena();
|
||||||
let src: *u8 = nil;
|
let src: *u8 = nil;
|
||||||
let incs: *u8 = os.alloc(PATH_MAX * 2u64): *u8;
|
let incs: *u8 = rt.alloc(PATH_MAX * 2u64): *u8;
|
||||||
let incoff: u64 = 0u64;
|
let incoff: u64 = 0u64;
|
||||||
cstrseal(incs, 0u64);
|
cstrseal(incs, 0u64);
|
||||||
|
|
||||||
let maxlflags: i32 = 32;
|
let maxlflags: i32 = 32;
|
||||||
let libdirs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
|
let libdirs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
|
||||||
let nlibdirs: i32 = 0;
|
let nlibdirs: i32 = 0;
|
||||||
let libs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
|
let libs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
|
||||||
let nlibs: i32 = 0;
|
let nlibs: i32 = 0;
|
||||||
|
|
||||||
let i: i32 = start;
|
let i: i32 = start;
|
||||||
@@ -2055,7 +2058,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
rlen -= 1u64;
|
rlen -= 1u64;
|
||||||
};
|
};
|
||||||
let bo: u64 = basenameoff(resolved, rlen);
|
let bo: u64 = basenameoff(resolved, rlen);
|
||||||
out = os.alloc(PATH_MAX): *u8;
|
out = rt.alloc(PATH_MAX): *u8;
|
||||||
let i: u64 = bo;
|
let i: u64 = bo;
|
||||||
let off: u64 = 0u64;
|
let off: u64 = 0u64;
|
||||||
for (i < rlen) { out[off] = resolved[i]; off += 1u64; i += 1u64; };
|
for (i < rlen) { out[off] = resolved[i]; off += 1u64; i += 1u64; };
|
||||||
@@ -2105,14 +2108,14 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
let a: *arena = newarena();
|
let a: *arena = newarena();
|
||||||
let src: *u8 = nil;
|
let src: *u8 = nil;
|
||||||
let passstart: i32 = -1; // first argv idx to pass through to program
|
let passstart: i32 = -1; // first argv idx to pass through to program
|
||||||
let incs: *u8 = os.alloc(PATH_MAX * 2u64): *u8;
|
let incs: *u8 = rt.alloc(PATH_MAX * 2u64): *u8;
|
||||||
let incoff: u64 = 0u64;
|
let incoff: u64 = 0u64;
|
||||||
cstrseal(incs, 0u64);
|
cstrseal(incs, 0u64);
|
||||||
|
|
||||||
let maxlflags: i32 = 32;
|
let maxlflags: i32 = 32;
|
||||||
let libdirs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
|
let libdirs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
|
||||||
let nlibdirs: i32 = 0;
|
let nlibdirs: i32 = 0;
|
||||||
let libs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
|
let libs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
|
||||||
let nlibs: i32 = 0;
|
let nlibs: i32 = 0;
|
||||||
|
|
||||||
let i: i32 = start;
|
let i: i32 = start;
|
||||||
@@ -2202,7 +2205,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
|
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
makeruntmp(tmp);
|
makeruntmp(tmp);
|
||||||
let lf: lflags;
|
let lf: lflags;
|
||||||
lf.libdirs = libdirs;
|
lf.libdirs = libdirs;
|
||||||
@@ -2218,7 +2221,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
let nextra: i32 = 0;
|
let nextra: i32 = 0;
|
||||||
if (passstart >= 0) { nextra = argc - passstart; };
|
if (passstart >= 0) { nextra = argc - passstart; };
|
||||||
let total: i32 = nextra + 2;
|
let total: i32 = nextra + 2;
|
||||||
let execargv: **u8 = os.alloc((total: u64) * 8u64): **u8;
|
let execargv: **u8 = rt.alloc((total: u64) * 8u64): **u8;
|
||||||
execargv[0] = tmp;
|
execargv[0] = tmp;
|
||||||
let k: i32 = 0;
|
let k: i32 = 0;
|
||||||
for (k < nextra) {
|
for (k < nextra) {
|
||||||
@@ -2239,13 +2242,13 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
// report ok/FAIL per file, return 0 iff all pass.
|
// report ok/FAIL per file, return 0 iff all pass.
|
||||||
|
|
||||||
fn runsingletest(selfdir: *u8, src: *u8) i32 = {
|
fn runsingletest(selfdir: *u8, src: *u8) i32 = {
|
||||||
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
|
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
makeruntmp(tmp);
|
makeruntmp(tmp);
|
||||||
if (buildone(selfdir, src, 0, tmp, "\0".ptr, nil) != 0) {
|
if (buildone(selfdir, src, 0, tmp, "\0".ptr, nil) != 0) {
|
||||||
os.remove(pathstr(tmp));
|
os.remove(pathstr(tmp));
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
let execargv: **u8 = os.alloc(16u64): **u8;
|
let execargv: **u8 = rt.alloc(16u64): **u8;
|
||||||
execargv[0] = tmp;
|
execargv[0] = tmp;
|
||||||
execargv[1] = nil;
|
execargv[1] = nil;
|
||||||
let rc: i32 = procrun(tmp, execargv);
|
let rc: i32 = procrun(tmp, execargv);
|
||||||
@@ -2262,7 +2265,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
|||||||
|
|
||||||
let pass: i32 = 0;
|
let pass: i32 = 0;
|
||||||
let fail: i32 = 0;
|
let fail: i32 = 0;
|
||||||
let buf: *u8 = os.alloc(8192u64): *u8;
|
let buf: *u8 = rt.alloc(8192u64): *u8;
|
||||||
let dirlen: u64 = cstrlen(dir);
|
let dirlen: u64 = cstrlen(dir);
|
||||||
|
|
||||||
let n: i64 = os.getdents64(fd, buf, 8192u64);
|
let n: i64 = os.getdents64(fd, buf, 8192u64);
|
||||||
@@ -2278,7 +2281,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
|||||||
if (cstrendswithlit(name, "_test.ww")) {
|
if (cstrendswithlit(name, "_test.ww")) {
|
||||||
let nlen: u64 = cstrlen(name);
|
let nlen: u64 = cstrlen(name);
|
||||||
// path = <dir>/<name>
|
// path = <dir>/<name>
|
||||||
let path: *u8 = os.alloc(PATH_MAX): *u8;
|
let path: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let poff: u64 = cstrinto(path, 0u64, dir);
|
let poff: u64 = cstrinto(path, 0u64, dir);
|
||||||
path[poff] = 47u8; poff += 1u64;
|
path[poff] = 47u8; poff += 1u64;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
@@ -2286,10 +2289,10 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
|||||||
poff += nlen;
|
poff += nlen;
|
||||||
cstrseal(path, poff);
|
cstrseal(path, poff);
|
||||||
// incs = <dir> so test files can `use ` siblings
|
// incs = <dir> so test files can `use ` siblings
|
||||||
let tincs: *u8 = os.alloc(PATH_MAX): *u8;
|
let tincs: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let ic: u64 = cstrinto(tincs, 0u64, dir);
|
let ic: u64 = cstrinto(tincs, 0u64, dir);
|
||||||
cstrseal(tincs, ic);
|
cstrseal(tincs, ic);
|
||||||
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
|
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
makeruntmp(tmp);
|
makeruntmp(tmp);
|
||||||
let bres: i32 = buildone(selfdir, path, 0, tmp, tincs, nil);
|
let bres: i32 = buildone(selfdir, path, 0, tmp, tincs, nil);
|
||||||
if (bres != 0) {
|
if (bres != 0) {
|
||||||
@@ -2298,7 +2301,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
|||||||
os.write(2, name, nlen);
|
os.write(2, name, nlen);
|
||||||
os.write(2, " (build)\n".ptr, 9u64);
|
os.write(2, " (build)\n".ptr, 9u64);
|
||||||
} else {
|
} else {
|
||||||
let execargv: **u8 = os.alloc(16u64): **u8;
|
let execargv: **u8 = rt.alloc(16u64): **u8;
|
||||||
execargv[0] = tmp;
|
execargv[0] = tmp;
|
||||||
execargv[1] = nil;
|
execargv[1] = nil;
|
||||||
let rc: i32 = procrun(tmp, execargv);
|
let rc: i32 = procrun(tmp, execargv);
|
||||||
@@ -2355,7 +2358,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// selfdir = dirname(argv[0])
|
// selfdir = dirname(argv[0])
|
||||||
let selfdir: *u8 = os.alloc(PATH_MAX): *u8;
|
let selfdir: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
selfdirinto(selfdir, PATH_MAX, argv[0]);
|
selfdirinto(selfdir, PATH_MAX, argv[0]);
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
package main;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import mem;
|
import mem;
|
||||||
|
|
||||||
// All path/string scratch buffers go on the runtime page allocator.
|
// All path/string scratch buffers go on the runtime page allocator.
|
||||||
@@ -138,7 +139,7 @@ fn selfdirinto(dst: *u8, dstsz: u64, argv0: *u8) void = {
|
|||||||
|
|
||||||
// Build "$dir/$name" (NUL-terminated) into a fresh page-sized buffer.
|
// Build "$dir/$name" (NUL-terminated) into a fresh page-sized buffer.
|
||||||
fn joinpath(dir: *u8, name: *u8) *u8 = {
|
fn joinpath(dir: *u8, name: *u8) *u8 = {
|
||||||
let buf: *u8 = os.alloc(PATH_MAX): *u8;
|
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let off: u64 = cstrinto(buf, 0u64, dir);
|
let off: u64 = cstrinto(buf, 0u64, dir);
|
||||||
off = byteinto(buf, off, 47u8);
|
off = byteinto(buf, off, 47u8);
|
||||||
off = cstrinto(buf, off, name);
|
off = cstrinto(buf, off, name);
|
||||||
@@ -148,7 +149,7 @@ fn joinpath(dir: *u8, name: *u8) *u8 = {
|
|||||||
|
|
||||||
// Same, but the second component is a ww `str` literal.
|
// Same, but the second component is a ww `str` literal.
|
||||||
fn joinpathlit(dir: *u8, name: str) *u8 = {
|
fn joinpathlit(dir: *u8, name: str) *u8 = {
|
||||||
let buf: *u8 = os.alloc(PATH_MAX): *u8;
|
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let off: u64 = cstrinto(buf, 0u64, dir);
|
let off: u64 = cstrinto(buf, 0u64, dir);
|
||||||
off = byteinto(buf, off, 47u8);
|
off = byteinto(buf, off, 47u8);
|
||||||
off = strinto(buf, off, name);
|
off = strinto(buf, off, name);
|
||||||
@@ -399,7 +400,7 @@ fn enumeratedir(a: *arena, dirpath: *u8) (**u8, i32) = {
|
|||||||
let names: **u8 = amalloc(a, (maxnames: u64) * 8u64): **u8;
|
let names: **u8 = amalloc(a, (maxnames: u64) * 8u64): **u8;
|
||||||
let nlens: *u64 = amalloc(a, (maxnames: u64) * 8u64): *u64;
|
let nlens: *u64 = amalloc(a, (maxnames: u64) * 8u64): *u64;
|
||||||
let n: i32 = 0;
|
let n: i32 = 0;
|
||||||
let buf: *u8 = os.alloc(8192u64): *u8;
|
let buf: *u8 = rt.alloc(8192u64): *u8;
|
||||||
let r: i64 = os.getdents64(fd, buf, 8192u64);
|
let r: i64 = os.getdents64(fd, buf, 8192u64);
|
||||||
for (r > 0i64) {
|
for (r > 0i64) {
|
||||||
let off: u64 = 0u64;
|
let off: u64 = 0u64;
|
||||||
@@ -461,7 +462,7 @@ fn slurp(pathcs: *u8) (*u8, u64) = {
|
|||||||
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
case let e: os.oserror => { os.close(fd); return nil, 0u64; };
|
||||||
};
|
};
|
||||||
let nu: u64 = n: u64;
|
let nu: u64 = n: u64;
|
||||||
let buf: *u8 = os.alloc(nu + 1u64): *u8;
|
let buf: *u8 = rt.alloc(nu + 1u64): *u8;
|
||||||
let rr: (i64 | os.oserror) = os.readall(fd, buf, nu);
|
let rr: (i64 | os.oserror) = os.readall(fd, buf, nu);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
let got: i64 = 0i64;
|
let got: i64 = 0i64;
|
||||||
@@ -568,7 +569,7 @@ fn expand(c: *expctx, pathcs: *u8) void = {
|
|||||||
fn peekpackage(a: *arena, pathcs: *u8) *u8 = {
|
fn peekpackage(a: *arena, pathcs: *u8) *u8 = {
|
||||||
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
|
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
|
||||||
if (fd < 0) { return nil; };
|
if (fd < 0) { return nil; };
|
||||||
let buf: *u8 = os.alloc(2048u64): *u8;
|
let buf: *u8 = rt.alloc(2048u64): *u8;
|
||||||
let n: i64 = os.read(fd, buf, 2048u64);
|
let n: i64 = os.read(fd, buf, 2048u64);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
if (n <= 0i64) { return nil; };
|
if (n <= 0i64) { return nil; };
|
||||||
@@ -715,7 +716,7 @@ fn makestem(stem: *u8, src: *u8) void = {
|
|||||||
|
|
||||||
// Append a literal suffix to `stem` (which already lives in a buffer).
|
// Append a literal suffix to `stem` (which already lives in a buffer).
|
||||||
fn appendlit(stem: *u8, suffix: str) *u8 = {
|
fn appendlit(stem: *u8, suffix: str) *u8 = {
|
||||||
let buf: *u8 = os.alloc(PATH_MAX): *u8;
|
let buf: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let off: u64 = cstrinto(buf, 0u64, stem);
|
let off: u64 = cstrinto(buf, 0u64, stem);
|
||||||
off = strinto(buf, off, suffix);
|
off = strinto(buf, off, suffix);
|
||||||
cstrseal(buf, off);
|
cstrseal(buf, off);
|
||||||
@@ -753,7 +754,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
|
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
|
||||||
|
|
||||||
// Default lib search path: <selfdir>/../../lib
|
// Default lib search path: <selfdir>/../../lib
|
||||||
let dotdotlib: *u8 = os.alloc(PATH_MAX): *u8;
|
let dotdotlib: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
{
|
{
|
||||||
let off: u64 = cstrinto(dotdotlib, 0u64, selfdir);
|
let off: u64 = cstrinto(dotdotlib, 0u64, selfdir);
|
||||||
off = strinto(dotdotlib, off, "/../../lib");
|
off = strinto(dotdotlib, off, "/../../lib");
|
||||||
@@ -766,7 +767,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
// convention assumes you're running from the module dir; our
|
// convention assumes you're running from the module dir; our
|
||||||
// wrappers don't cd, so dirname(src) stands in as the closest
|
// wrappers don't cd, so dirname(src) stands in as the closest
|
||||||
// analog. Source-dir wins ties over the system path (cc -I.).
|
// analog. Source-dir wins ties over the system path (cc -I.).
|
||||||
let srcd: *u8 = os.alloc(PATH_MAX): *u8;
|
let srcd: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
if (entryisdir != 0) {
|
if (entryisdir != 0) {
|
||||||
let slen: u64 = cstrlen(src);
|
let slen: u64 = cstrlen(src);
|
||||||
let k: u64 = 0u64;
|
let k: u64 = 0u64;
|
||||||
@@ -800,7 +801,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Compose searchpath: srcd + ':' + incs + ':' + dotdotlib.
|
// Compose searchpath: srcd + ':' + incs + ':' + dotdotlib.
|
||||||
let searchpath: *u8 = os.alloc(PATH_MAX * 3u64): *u8;
|
let searchpath: *u8 = rt.alloc(PATH_MAX * 3u64): *u8;
|
||||||
{
|
{
|
||||||
let off: u64 = cstrinto(searchpath, 0u64, srcd);
|
let off: u64 = cstrinto(searchpath, 0u64, srcd);
|
||||||
off = byteinto(searchpath, off, 58u8); // ':'
|
off = byteinto(searchpath, off, 58u8); // ':'
|
||||||
@@ -814,7 +815,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
|
|
||||||
// Stem for .s/.o/.combined.ww side files. Dir entry: <dir>/<base>;
|
// Stem for .s/.o/.combined.ww side files. Dir entry: <dir>/<base>;
|
||||||
// file entry: src stripped of .ww.
|
// file entry: src stripped of .ww.
|
||||||
let stem: *u8 = os.alloc(PATH_MAX): *u8;
|
let stem: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
if (entryisdir != 0) {
|
if (entryisdir != 0) {
|
||||||
let dlen: u64 = cstrlen(srcd);
|
let dlen: u64 = cstrlen(srcd);
|
||||||
let bo: u64 = basenameoff(srcd, dlen);
|
let bo: u64 = basenameoff(srcd, dlen);
|
||||||
@@ -831,7 +832,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
let combined: *u8 = appendlit(stem, ".combined.ww");
|
let combined: *u8 = appendlit(stem, ".combined.ww");
|
||||||
|
|
||||||
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
|
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
|
||||||
let libwwrt: *u8 = os.alloc(PATH_MAX): *u8;
|
let libwwrt: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
{
|
{
|
||||||
let off: u64 = cstrinto(libwwrt, 0u64, selfdir);
|
let off: u64 = cstrinto(libwwrt, 0u64, selfdir);
|
||||||
off = strinto(libwwrt, off, "/../lib/libwwrt.a");
|
off = strinto(libwwrt, off, "/../lib/libwwrt.a");
|
||||||
@@ -858,7 +859,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
|
|
||||||
// Step 2: w6c -o <stem>.s <stem>.combined.ww
|
// Step 2: w6c -o <stem>.s <stem>.combined.ww
|
||||||
{
|
{
|
||||||
let argv: **u8 = os.alloc(40u64): **u8;
|
let argv: **u8 = rt.alloc(40u64): **u8;
|
||||||
argv[0] = "w6c\0".ptr;
|
argv[0] = "w6c\0".ptr;
|
||||||
argv[1] = "-o\0".ptr;
|
argv[1] = "-o\0".ptr;
|
||||||
argv[2] = asmf;
|
argv[2] = asmf;
|
||||||
@@ -872,7 +873,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
|
|
||||||
// Step 3: w6a -o <stem>.o <stem>.s
|
// Step 3: w6a -o <stem>.o <stem>.s
|
||||||
{
|
{
|
||||||
let argv: **u8 = os.alloc(40u64): **u8;
|
let argv: **u8 = rt.alloc(40u64): **u8;
|
||||||
argv[0] = "w6a\0".ptr;
|
argv[0] = "w6a\0".ptr;
|
||||||
argv[1] = "-o\0".ptr;
|
argv[1] = "-o\0".ptr;
|
||||||
argv[2] = objf;
|
argv[2] = objf;
|
||||||
@@ -901,7 +902,7 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
|||||||
// + 2 * nlibs (-l, name)
|
// + 2 * nlibs (-l, name)
|
||||||
// + 1 nil terminator.
|
// + 1 nil terminator.
|
||||||
let total: i32 = 5 + 2 * nldirs + 2 * nllibs + 1;
|
let total: i32 = 5 + 2 * nldirs + 2 * nllibs + 1;
|
||||||
let argv: **u8 = os.alloc((total: u64) * 8u64): **u8;
|
let argv: **u8 = rt.alloc((total: u64) * 8u64): **u8;
|
||||||
argv[0] = "w6l\0".ptr;
|
argv[0] = "w6l\0".ptr;
|
||||||
argv[1] = "-o\0".ptr;
|
argv[1] = "-o\0".ptr;
|
||||||
argv[2] = out;
|
argv[2] = out;
|
||||||
@@ -1073,7 +1074,7 @@ fn defaultoutpath(src: *u8) *u8 = {
|
|||||||
if (src[i] == 47u8) { start = i + 1u64; }; // '/'
|
if (src[i] == 47u8) { start = i + 1u64; }; // '/'
|
||||||
i += 1u64;
|
i += 1u64;
|
||||||
};
|
};
|
||||||
let out: *u8 = os.alloc(PATH_MAX): *u8;
|
let out: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let off: u64 = 0u64;
|
let off: u64 = 0u64;
|
||||||
let j: u64 = start;
|
let j: u64 = start;
|
||||||
for (j < n) {
|
for (j < n) {
|
||||||
@@ -1098,14 +1099,14 @@ fn defaultoutpath(src: *u8) *u8 = {
|
|||||||
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||||
let a: *arena = newarena();
|
let a: *arena = newarena();
|
||||||
let src: *u8 = nil;
|
let src: *u8 = nil;
|
||||||
let incs: *u8 = os.alloc(PATH_MAX * 2u64): *u8;
|
let incs: *u8 = rt.alloc(PATH_MAX * 2u64): *u8;
|
||||||
let incoff: u64 = 0u64;
|
let incoff: u64 = 0u64;
|
||||||
cstrseal(incs, 0u64);
|
cstrseal(incs, 0u64);
|
||||||
|
|
||||||
let maxlflags: i32 = 32;
|
let maxlflags: i32 = 32;
|
||||||
let libdirs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
|
let libdirs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
|
||||||
let nlibdirs: i32 = 0;
|
let nlibdirs: i32 = 0;
|
||||||
let libs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
|
let libs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
|
||||||
let nlibs: i32 = 0;
|
let nlibs: i32 = 0;
|
||||||
|
|
||||||
let i: i32 = start;
|
let i: i32 = start;
|
||||||
@@ -1195,7 +1196,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
rlen -= 1u64;
|
rlen -= 1u64;
|
||||||
};
|
};
|
||||||
let bo: u64 = basenameoff(resolved, rlen);
|
let bo: u64 = basenameoff(resolved, rlen);
|
||||||
out = os.alloc(PATH_MAX): *u8;
|
out = rt.alloc(PATH_MAX): *u8;
|
||||||
let i: u64 = bo;
|
let i: u64 = bo;
|
||||||
let off: u64 = 0u64;
|
let off: u64 = 0u64;
|
||||||
for (i < rlen) { out[off] = resolved[i]; off += 1u64; i += 1u64; };
|
for (i < rlen) { out[off] = resolved[i]; off += 1u64; i += 1u64; };
|
||||||
@@ -1245,14 +1246,14 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
let a: *arena = newarena();
|
let a: *arena = newarena();
|
||||||
let src: *u8 = nil;
|
let src: *u8 = nil;
|
||||||
let passstart: i32 = -1; // first argv idx to pass through to program
|
let passstart: i32 = -1; // first argv idx to pass through to program
|
||||||
let incs: *u8 = os.alloc(PATH_MAX * 2u64): *u8;
|
let incs: *u8 = rt.alloc(PATH_MAX * 2u64): *u8;
|
||||||
let incoff: u64 = 0u64;
|
let incoff: u64 = 0u64;
|
||||||
cstrseal(incs, 0u64);
|
cstrseal(incs, 0u64);
|
||||||
|
|
||||||
let maxlflags: i32 = 32;
|
let maxlflags: i32 = 32;
|
||||||
let libdirs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
|
let libdirs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
|
||||||
let nlibdirs: i32 = 0;
|
let nlibdirs: i32 = 0;
|
||||||
let libs: **u8 = os.alloc((maxlflags: u64) * 8u64): **u8;
|
let libs: **u8 = rt.alloc((maxlflags: u64) * 8u64): **u8;
|
||||||
let nlibs: i32 = 0;
|
let nlibs: i32 = 0;
|
||||||
|
|
||||||
let i: i32 = start;
|
let i: i32 = start;
|
||||||
@@ -1342,7 +1343,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
|
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
makeruntmp(tmp);
|
makeruntmp(tmp);
|
||||||
let lf: lflags;
|
let lf: lflags;
|
||||||
lf.libdirs = libdirs;
|
lf.libdirs = libdirs;
|
||||||
@@ -1358,7 +1359,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
let nextra: i32 = 0;
|
let nextra: i32 = 0;
|
||||||
if (passstart >= 0) { nextra = argc - passstart; };
|
if (passstart >= 0) { nextra = argc - passstart; };
|
||||||
let total: i32 = nextra + 2;
|
let total: i32 = nextra + 2;
|
||||||
let execargv: **u8 = os.alloc((total: u64) * 8u64): **u8;
|
let execargv: **u8 = rt.alloc((total: u64) * 8u64): **u8;
|
||||||
execargv[0] = tmp;
|
execargv[0] = tmp;
|
||||||
let k: i32 = 0;
|
let k: i32 = 0;
|
||||||
for (k < nextra) {
|
for (k < nextra) {
|
||||||
@@ -1379,13 +1380,13 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
// report ok/FAIL per file, return 0 iff all pass.
|
// report ok/FAIL per file, return 0 iff all pass.
|
||||||
|
|
||||||
fn runsingletest(selfdir: *u8, src: *u8) i32 = {
|
fn runsingletest(selfdir: *u8, src: *u8) i32 = {
|
||||||
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
|
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
makeruntmp(tmp);
|
makeruntmp(tmp);
|
||||||
if (buildone(selfdir, src, 0, tmp, "\0".ptr, nil) != 0) {
|
if (buildone(selfdir, src, 0, tmp, "\0".ptr, nil) != 0) {
|
||||||
os.remove(pathstr(tmp));
|
os.remove(pathstr(tmp));
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
let execargv: **u8 = os.alloc(16u64): **u8;
|
let execargv: **u8 = rt.alloc(16u64): **u8;
|
||||||
execargv[0] = tmp;
|
execargv[0] = tmp;
|
||||||
execargv[1] = nil;
|
execargv[1] = nil;
|
||||||
let rc: i32 = procrun(tmp, execargv);
|
let rc: i32 = procrun(tmp, execargv);
|
||||||
@@ -1402,7 +1403,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
|||||||
|
|
||||||
let pass: i32 = 0;
|
let pass: i32 = 0;
|
||||||
let fail: i32 = 0;
|
let fail: i32 = 0;
|
||||||
let buf: *u8 = os.alloc(8192u64): *u8;
|
let buf: *u8 = rt.alloc(8192u64): *u8;
|
||||||
let dirlen: u64 = cstrlen(dir);
|
let dirlen: u64 = cstrlen(dir);
|
||||||
|
|
||||||
let n: i64 = os.getdents64(fd, buf, 8192u64);
|
let n: i64 = os.getdents64(fd, buf, 8192u64);
|
||||||
@@ -1418,7 +1419,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
|||||||
if (cstrendswithlit(name, "_test.ww")) {
|
if (cstrendswithlit(name, "_test.ww")) {
|
||||||
let nlen: u64 = cstrlen(name);
|
let nlen: u64 = cstrlen(name);
|
||||||
// path = <dir>/<name>
|
// path = <dir>/<name>
|
||||||
let path: *u8 = os.alloc(PATH_MAX): *u8;
|
let path: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let poff: u64 = cstrinto(path, 0u64, dir);
|
let poff: u64 = cstrinto(path, 0u64, dir);
|
||||||
path[poff] = 47u8; poff += 1u64;
|
path[poff] = 47u8; poff += 1u64;
|
||||||
let i: u64 = 0u64;
|
let i: u64 = 0u64;
|
||||||
@@ -1426,10 +1427,10 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
|||||||
poff += nlen;
|
poff += nlen;
|
||||||
cstrseal(path, poff);
|
cstrseal(path, poff);
|
||||||
// incs = <dir> so test files can `use ` siblings
|
// incs = <dir> so test files can `use ` siblings
|
||||||
let tincs: *u8 = os.alloc(PATH_MAX): *u8;
|
let tincs: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
let ic: u64 = cstrinto(tincs, 0u64, dir);
|
let ic: u64 = cstrinto(tincs, 0u64, dir);
|
||||||
cstrseal(tincs, ic);
|
cstrseal(tincs, ic);
|
||||||
let tmp: *u8 = os.alloc(PATH_MAX): *u8;
|
let tmp: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
makeruntmp(tmp);
|
makeruntmp(tmp);
|
||||||
let bres: i32 = buildone(selfdir, path, 0, tmp, tincs, nil);
|
let bres: i32 = buildone(selfdir, path, 0, tmp, tincs, nil);
|
||||||
if (bres != 0) {
|
if (bres != 0) {
|
||||||
@@ -1438,7 +1439,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
|||||||
os.write(2, name, nlen);
|
os.write(2, name, nlen);
|
||||||
os.write(2, " (build)\n".ptr, 9u64);
|
os.write(2, " (build)\n".ptr, 9u64);
|
||||||
} else {
|
} else {
|
||||||
let execargv: **u8 = os.alloc(16u64): **u8;
|
let execargv: **u8 = rt.alloc(16u64): **u8;
|
||||||
execargv[0] = tmp;
|
execargv[0] = tmp;
|
||||||
execargv[1] = nil;
|
execargv[1] = nil;
|
||||||
let rc: i32 = procrun(tmp, execargv);
|
let rc: i32 = procrun(tmp, execargv);
|
||||||
@@ -1495,7 +1496,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// selfdir = dirname(argv[0])
|
// selfdir = dirname(argv[0])
|
||||||
let selfdir: *u8 = os.alloc(PATH_MAX): *u8;
|
let selfdir: *u8 = rt.alloc(PATH_MAX): *u8;
|
||||||
selfdirinto(selfdir, PATH_MAX, argv[0]);
|
selfdirinto(selfdir, PATH_MAX, argv[0]);
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
|
|||||||
@@ -110,28 +110,6 @@ import time;
|
|||||||
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
||||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||||
|
|
||||||
// alloc / free — runtime mmap-backed page allocator. Untyped:
|
|
||||||
// `alloc(n)` returns a `*void` and `free(p, n)` requires the byte
|
|
||||||
// count back because rt_free is munmap-based and doesn't track
|
|
||||||
// mapping sizes (the kernel needs the length to release the
|
|
||||||
// reservation).
|
|
||||||
//
|
|
||||||
// Diverges from Hare. Hare exposes `alloc` / `free` as typed
|
|
||||||
// language builtins (`alloc(value, cap)?` / `free(ptr)`) that the
|
|
||||||
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
|
|
||||||
// so the rt-symbol surface is exposed directly. Stdlib callers
|
|
||||||
// that 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 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 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.
|
|
||||||
@symbol("rt_alloc") export fn alloc(n: u64) *void;
|
|
||||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||||
@symbol("rt_abort") fn abort(msg: str) void;
|
@symbol("rt_abort") fn abort(msg: str) void;
|
||||||
|
|
||||||
@@ -749,6 +727,29 @@ export fn exists(path: str) bool = {
|
|||||||
return r >= 0i64;
|
return r >= 0i64;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// rt — runtime primitives exposed to ww programs.
|
||||||
|
// Mirrors Hare's rt:: module placement (ref/hare/rt/).
|
||||||
|
|
||||||
|
package rt;
|
||||||
|
|
||||||
|
// alloc — mmap-backed page allocator. Untyped: `alloc(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,
|
||||||
|
// so the rt-symbol surface is exposed directly. Stdlib callers that
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// 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;
|
||||||
|
|
||||||
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
||||||
//
|
//
|
||||||
// Bump arena allocator. Backed by the runtime page allocator
|
// Bump arena allocator. Backed by the runtime page allocator
|
||||||
@@ -762,6 +763,7 @@ export fn exists(path: str) bool = {
|
|||||||
package wcc;
|
package wcc;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
|
|
||||||
def ALIGN: u64 = 16u64;
|
def ALIGN: u64 = 16u64;
|
||||||
def INIT_CHUNK: u64 = 65536u64;
|
def INIT_CHUNK: u64 = 65536u64;
|
||||||
@@ -781,8 +783,8 @@ fn roundup(n: u64, a: u64) u64 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export fn newarena() *arena = {
|
export fn newarena() *arena = {
|
||||||
let a: *arena = os.alloc(ARENA_SZ): *arena;
|
let a: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
a.buf = os.alloc(INIT_CHUNK): *u8;
|
a.buf = rt.alloc(INIT_CHUNK): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = INIT_CHUNK;
|
a.cap = INIT_CHUNK;
|
||||||
a.next = nil;
|
a.next = nil;
|
||||||
@@ -799,14 +801,14 @@ fn grow(a: *arena, need: u64) bool = {
|
|||||||
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
||||||
if (want < need) { return false; }; // single allocation too big
|
if (want < need) { return false; }; // single allocation too big
|
||||||
|
|
||||||
let old: *arena = os.alloc(ARENA_SZ): *arena;
|
let old: *arena = rt.alloc(ARENA_SZ): *arena;
|
||||||
old.buf = a.buf;
|
old.buf = a.buf;
|
||||||
old.off = a.off;
|
old.off = a.off;
|
||||||
old.cap = a.cap;
|
old.cap = a.cap;
|
||||||
old.next = a.next;
|
old.next = a.next;
|
||||||
old.total = 0u64;
|
old.total = 0u64;
|
||||||
|
|
||||||
a.buf = os.alloc(want): *u8;
|
a.buf = rt.alloc(want): *u8;
|
||||||
a.off = 0u64;
|
a.off = 0u64;
|
||||||
a.cap = want;
|
a.cap = want;
|
||||||
a.next = old;
|
a.next = old;
|
||||||
@@ -1864,6 +1866,7 @@ package strings;
|
|||||||
import bytes;
|
import bytes;
|
||||||
import encoding.utf8;
|
import encoding.utf8;
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import types;
|
import types;
|
||||||
|
|
||||||
// toutf8 — borrowed []u8 view of `s`. ref/hare/strings/utf8.ha:29.
|
// toutf8 — borrowed []u8 view of `s`. ref/hare/strings/utf8.ha:29.
|
||||||
@@ -1935,7 +1938,7 @@ export fn dup(s: str) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (s.len == 0) { return r; };
|
if (s.len == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(s.len: u64): *u8;
|
let buf: *u8 = rt.alloc(s.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
||||||
r.ptr = buf;
|
r.ptr = buf;
|
||||||
@@ -2013,7 +2016,7 @@ export fn concat(strs: str...) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (total == 0) { return r; };
|
if (total == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < strs.len) {
|
for (i < strs.len) {
|
||||||
@@ -2046,7 +2049,7 @@ export fn join(delim: str, strs: str...) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (total == 0) { return r; };
|
if (total == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < strs.len) {
|
for (i < strs.len) {
|
||||||
@@ -2723,7 +2726,7 @@ export fn lpad(s: str, p: rune, maxlen: i32) str = {
|
|||||||
if (s.len >= maxlen) { return dup(s); };
|
if (s.len >= maxlen) { return dup(s); };
|
||||||
let scratch: [4]u8;
|
let scratch: [4]u8;
|
||||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
let buf: *u8 = rt.alloc(maxlen: u64): *u8;
|
||||||
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
||||||
if (padwrite > maxlen) { padwrite = maxlen; };
|
if (padwrite > maxlen) { padwrite = maxlen; };
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
@@ -2806,7 +2809,7 @@ export fn rpad(s: str, p: rune, maxlen: i32) str = {
|
|||||||
if (s.len >= maxlen) { return dup(s); };
|
if (s.len >= maxlen) { return dup(s); };
|
||||||
let scratch: [4]u8;
|
let scratch: [4]u8;
|
||||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
let buf: *u8 = rt.alloc(maxlen: u64): *u8;
|
||||||
let k: i32 = 0;
|
let k: i32 = 0;
|
||||||
for (k < s.len) {
|
for (k < s.len) {
|
||||||
buf[k] = s[k];
|
buf[k] = s[k];
|
||||||
@@ -7901,15 +7904,15 @@ fn astoffset(c: *checker, dot: *node) i64 = {
|
|||||||
if (dot.kind != nkind.N_DOT) { return -1i64; };
|
if (dot.kind != nkind.N_DOT) { return -1i64; };
|
||||||
let recv: *node = scruttype(c, dot.lhs);
|
let recv: *node = scruttype(c, dot.lhs);
|
||||||
if (recv == nil) { return -1i64; };
|
if (recv == nil) { return -1i64; };
|
||||||
let rt: *node = resolvealias(c, unwrapbang(recv));
|
let rtyp: *node = resolvealias(c, unwrapbang(recv));
|
||||||
if (rt == nil) { return -1i64; };
|
if (rtyp == nil) { return -1i64; };
|
||||||
if (rt.kind == nkind.N_TPTR) {
|
if (rtyp.kind == nkind.N_TPTR) {
|
||||||
rt = resolvealias(c, unwrapbang(rt.lhs));
|
rtyp = resolvealias(c, unwrapbang(rtyp.lhs));
|
||||||
};
|
};
|
||||||
if (rt == nil) { return -1i64; };
|
if (rtyp == nil) { return -1i64; };
|
||||||
if (rt.kind != nkind.N_TSTRUCT) { return -1i64; };
|
if (rtyp.kind != nkind.N_TSTRUCT) { return -1i64; };
|
||||||
let off: i64 = 0i64;
|
let off: i64 = 0i64;
|
||||||
let f: *node = rt.list;
|
let f: *node = rtyp.list;
|
||||||
for (f != nil) {
|
for (f != nil) {
|
||||||
if (f.kind == nkind.N_TFIELD) {
|
if (f.kind == nkind.N_TFIELD) {
|
||||||
let fa: i64 = astalign(c, f.lhs);
|
let fa: i64 = astalign(c, f.lhs);
|
||||||
@@ -9727,9 +9730,9 @@ export fn taggedcallslot(c: *cgen, n: *node) i32 = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee == nil) { return 0; };
|
if (callee == nil) { return 0; };
|
||||||
if (callee.kind != nkind.N_IDENT) { return 0; };
|
if (callee.kind != nkind.N_IDENT) { return 0; };
|
||||||
let rt: *node = fnretlookup(c, callee.str);
|
let rtyp: *node = fnretlookup(c, callee.str);
|
||||||
if (!istaggedtype(c, rt)) { return 0; };
|
if (!istaggedtype(c, rtyp)) { return 0; };
|
||||||
return slotsize(c, rt);
|
return slotsize(c, rtyp);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn nodeisslice(c: *cgen, n: *node) bool = {
|
fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||||
@@ -9758,8 +9761,8 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee != nil) {
|
if (callee != nil) {
|
||||||
if (callee.kind == nkind.N_IDENT) {
|
if (callee.kind == nkind.N_IDENT) {
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, c.curmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
|
||||||
return isslicetype(c, rt);
|
return isslicetype(c, rtyp);
|
||||||
};
|
};
|
||||||
if (callee.kind == nkind.N_DOT) {
|
if (callee.kind == nkind.N_DOT) {
|
||||||
let cmod: str;
|
let cmod: str;
|
||||||
@@ -9769,8 +9772,8 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
|||||||
cmod = callee.lhs.str;
|
cmod = callee.lhs.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, cmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
|
||||||
return isslicetype(c, rt);
|
return isslicetype(c, rtyp);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
@@ -9885,8 +9888,8 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
|||||||
let callee: *node = n.lhs;
|
let callee: *node = n.lhs;
|
||||||
if (callee != nil) {
|
if (callee != nil) {
|
||||||
if (callee.kind == nkind.N_IDENT) {
|
if (callee.kind == nkind.N_IDENT) {
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, c.curmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
|
||||||
return isstrtype(c, rt);
|
return isstrtype(c, rtyp);
|
||||||
};
|
};
|
||||||
// #34: cross-module N_DOT — route through fnretlookupmod
|
// #34: cross-module N_DOT — route through fnretlookupmod
|
||||||
// so a same-leaf caller-module fn (different return shape)
|
// so a same-leaf caller-module fn (different return shape)
|
||||||
@@ -9899,8 +9902,8 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
|||||||
cmod = callee.lhs.str;
|
cmod = callee.lhs.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, callee.str, cmod);
|
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
|
||||||
return isstrtype(c, rt);
|
return isstrtype(c, rtyp);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
@@ -10816,8 +10819,8 @@ export fn callsretsize(c: *cgen, n: *node) i32 = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cn.len == 0) { return 0; };
|
if (cn.len == 0) { return 0; };
|
||||||
let rt: *node = fnretlookupmod(c, cn, cmod);
|
let rtyp: *node = fnretlookupmod(c, cn, cmod);
|
||||||
return sretretsize(c, rt);
|
return sretretsize(c, rtyp);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn structlookup(c: *cgen, name: str) *structinfo = {
|
fn structlookup(c: *cgen, name: str) *structinfo = {
|
||||||
@@ -11074,16 +11077,16 @@ fn inferletcalltype(c: *cgen, rhs: *node) *node = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len == 0) { return nil; };
|
if (cname.len == 0) { return nil; };
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt == nil) { return nil; };
|
if (rtyp == nil) { return nil; };
|
||||||
if (unwrap) {
|
if (unwrap) {
|
||||||
// Strip error variants — success type is the first
|
// Strip error variants — success type is the first
|
||||||
// variant of the tagged return.
|
// variant of the tagged return.
|
||||||
if (rt.kind != nkind.N_TTAGGED) { return nil; };
|
if (rtyp.kind != nkind.N_TTAGGED) { return nil; };
|
||||||
return rt.list;
|
return rtyp.list;
|
||||||
};
|
};
|
||||||
// Plain call: declared return type is the local's type.
|
// Plain call: declared return type is the local's type.
|
||||||
return rt;
|
return rtyp;
|
||||||
};
|
};
|
||||||
|
|
||||||
// letslotsize — slot size for a `let` binding. Like slotsize, but
|
// letslotsize — slot size for a `let` binding. Like slotsize, but
|
||||||
@@ -11550,8 +11553,8 @@ fn matchscrutt(c: *cgen, scrut: *node) *node = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cnm.len > 0) {
|
if (cnm.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cnm, cmod);
|
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||||
if (rt != nil) { return resolvetagged(c, rt); };
|
if (rtyp != nil) { return resolvetagged(c, rtyp); };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return nil;
|
return nil;
|
||||||
@@ -11745,9 +11748,9 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
|||||||
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
|
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
|
||||||
};
|
};
|
||||||
if (nm.len > 0) {
|
if (nm.len > 0) {
|
||||||
let rt: *node = fnretlookup(c, nm);
|
let rtyp: *node = fnretlookup(c, nm);
|
||||||
if (isf32type(c, rt)) { return 1; };
|
if (isf32type(c, rtyp)) { return 1; };
|
||||||
if (isfloattype(c, rt)) { return 2; };
|
if (isfloattype(c, rtyp)) { return 2; };
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
@@ -12266,9 +12269,9 @@ fn rhstaggedabicall(c: *cgen, src: *node) bool = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (calleename.len > 0) {
|
if (calleename.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (istaggedtype(c, rt)) { return true; };
|
if (istaggedtype(c, rtyp)) { return true; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -13380,10 +13383,10 @@ fn cgtryprop(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len > 0) {
|
if (cname.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTAGGED) {
|
if (rtyp.kind == nkind.N_TTAGGED) {
|
||||||
let first: *node = rt.list;
|
let first: *node = rtyp.list;
|
||||||
if (first != nil) {
|
if (first != nil) {
|
||||||
if (isstrtype(c, first)) {
|
if (isstrtype(c, first)) {
|
||||||
succisstr = true;
|
succisstr = true;
|
||||||
@@ -13436,10 +13439,10 @@ fn cgtryunw(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cname.len > 0) {
|
if (cname.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cname, cmod);
|
let rtyp: *node = fnretlookupmod(c, cname, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTAGGED) {
|
if (rtyp.kind == nkind.N_TTAGGED) {
|
||||||
let first: *node = rt.list;
|
let first: *node = rtyp.list;
|
||||||
if (first != nil) {
|
if (first != nil) {
|
||||||
if (isstrtype(c, first)) {
|
if (isstrtype(c, first)) {
|
||||||
succisstr = true;
|
succisstr = true;
|
||||||
@@ -13816,8 +13819,8 @@ fn cgident(c: *cgen, n: *node) void = {
|
|||||||
// in one go, so a body-less FFI binding emits the C symbol
|
// in one go, so a body-less FFI binding emits the C symbol
|
||||||
// it was declared with via @symbol(), not the ww-side ident.
|
// it was declared with via @symbol(), not the ww-side ident.
|
||||||
// Bare ident → same-module by ww's resolver, hint with c.curmod.
|
// Bare ident → same-module by ww's resolver, hint with c.curmod.
|
||||||
let rt: *node = fnretlookup(c, nm);
|
let rtyp: *node = fnretlookup(c, nm);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
emitline("\tLEAQ\t");
|
emitline("\tLEAQ\t");
|
||||||
emitfnname(c, nm, c.curmod);
|
emitfnname(c, nm, c.curmod);
|
||||||
emitline("(SB), AX\n");
|
emitline("(SB), AX\n");
|
||||||
@@ -16630,8 +16633,8 @@ fn cgcall(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (isstrtype(c, rt)) {
|
if (isstrtype(c, rtyp)) {
|
||||||
emitline("\tMOVQ\tDX, BX\n");
|
emitline("\tMOVQ\tDX, BX\n");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -19193,8 +19196,8 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (calleename.len > 0) {
|
if (calleename.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, calleename, cmod);
|
let rtyp: *node = fnretlookupmod(c, calleename, cmod);
|
||||||
if (istaggedtype(c, rt)) { forwardtagged = true; };
|
if (istaggedtype(c, rtyp)) { forwardtagged = true; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -20234,10 +20237,10 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (cnm.len > 0) {
|
if (cnm.len > 0) {
|
||||||
let rt: *node = fnretlookupmod(c, cnm, cmod);
|
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||||
if (rt != nil) {
|
if (rtyp != nil) {
|
||||||
if (rt.kind == nkind.N_TTUPLE) {
|
if (rtyp.kind == nkind.N_TTUPLE) {
|
||||||
p0t = rt.list;
|
p0t = rtyp.list;
|
||||||
if (p0t != nil) { p1t = p0t.next; };
|
if (p0t != nil) { p1t = p0t.next; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -110,28 +110,6 @@ import time;
|
|||||||
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
@symbol("rt_syscall") fn syscall3(num: nr, a: i64, b: i64, c: i64) i64;
|
||||||
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
@symbol("rt_syscall") fn syscall4(num: nr, a: i64, b: i64, c: i64, d: i64) i64;
|
||||||
|
|
||||||
// alloc / free — runtime mmap-backed page allocator. Untyped:
|
|
||||||
// `alloc(n)` returns a `*void` and `free(p, n)` requires the byte
|
|
||||||
// count back because rt_free is munmap-based and doesn't track
|
|
||||||
// mapping sizes (the kernel needs the length to release the
|
|
||||||
// reservation).
|
|
||||||
//
|
|
||||||
// Diverges from Hare. Hare exposes `alloc` / `free` as typed
|
|
||||||
// language builtins (`alloc(value, cap)?` / `free(ptr)`) that the
|
|
||||||
// compiler lowers to rt::malloc/rt::free; ww has no such builtins,
|
|
||||||
// so the rt-symbol surface is exposed directly. Stdlib callers
|
|
||||||
// that 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 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 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.
|
|
||||||
@symbol("rt_alloc") export fn alloc(n: u64) *void;
|
|
||||||
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
@symbol("rt_free") export fn free(p: *void, n: u64) void;
|
||||||
@symbol("rt_abort") fn abort(msg: str) void;
|
@symbol("rt_abort") fn abort(msg: str) void;
|
||||||
|
|
||||||
@@ -1726,6 +1704,29 @@ export fn position(d: *decoder) i32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// rt — runtime primitives exposed to ww programs.
|
||||||
|
// Mirrors Hare's rt:: module placement (ref/hare/rt/).
|
||||||
|
|
||||||
|
package rt;
|
||||||
|
|
||||||
|
// alloc — mmap-backed page allocator. Untyped: `alloc(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,
|
||||||
|
// so the rt-symbol surface is exposed directly. Stdlib callers that
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// 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;
|
||||||
|
|
||||||
// strings — operations over str ({ptr,len}). Hare port; see
|
// strings — operations over str ({ptr,len}). Hare port; see
|
||||||
// ref/hare/strings/.
|
// ref/hare/strings/.
|
||||||
//
|
//
|
||||||
@@ -1755,6 +1756,7 @@ package strings;
|
|||||||
import bytes;
|
import bytes;
|
||||||
import encoding.utf8;
|
import encoding.utf8;
|
||||||
import os;
|
import os;
|
||||||
|
import rt;
|
||||||
import types;
|
import types;
|
||||||
|
|
||||||
// toutf8 — borrowed []u8 view of `s`. ref/hare/strings/utf8.ha:29.
|
// toutf8 — borrowed []u8 view of `s`. ref/hare/strings/utf8.ha:29.
|
||||||
@@ -1826,7 +1828,7 @@ export fn dup(s: str) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (s.len == 0) { return r; };
|
if (s.len == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(s.len: u64): *u8;
|
let buf: *u8 = rt.alloc(s.len: u64): *u8;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
for (i < s.len) { buf[i] = s[i]; i += 1; };
|
||||||
r.ptr = buf;
|
r.ptr = buf;
|
||||||
@@ -1904,7 +1906,7 @@ export fn concat(strs: str...) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (total == 0) { return r; };
|
if (total == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < strs.len) {
|
for (i < strs.len) {
|
||||||
@@ -1937,7 +1939,7 @@ export fn join(delim: str, strs: str...) str = {
|
|||||||
r.ptr = nil;
|
r.ptr = nil;
|
||||||
r.len = 0;
|
r.len = 0;
|
||||||
if (total == 0) { return r; };
|
if (total == 0) { return r; };
|
||||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
let buf: *u8 = rt.alloc(total: u64): *u8;
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < strs.len) {
|
for (i < strs.len) {
|
||||||
@@ -2614,7 +2616,7 @@ export fn lpad(s: str, p: rune, maxlen: i32) str = {
|
|||||||
if (s.len >= maxlen) { return dup(s); };
|
if (s.len >= maxlen) { return dup(s); };
|
||||||
let scratch: [4]u8;
|
let scratch: [4]u8;
|
||||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
let buf: *u8 = rt.alloc(maxlen: u64): *u8;
|
||||||
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
||||||
if (padwrite > maxlen) { padwrite = maxlen; };
|
if (padwrite > maxlen) { padwrite = maxlen; };
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
@@ -2697,7 +2699,7 @@ export fn rpad(s: str, p: rune, maxlen: i32) str = {
|
|||||||
if (s.len >= maxlen) { return dup(s); };
|
if (s.len >= maxlen) { return dup(s); };
|
||||||
let scratch: [4]u8;
|
let scratch: [4]u8;
|
||||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
let buf: *u8 = rt.alloc(maxlen: u64): *u8;
|
||||||
let k: i32 = 0;
|
let k: i32 = 0;
|
||||||
for (k < s.len) {
|
for (k < s.len) {
|
||||||
buf[k] = s[k];
|
buf[k] = s[k];
|
||||||
|
|||||||
@@ -152,8 +152,9 @@ static const struct row rows[] = {
|
|||||||
/* alloc + free via mmap-backed runtime — write through allocated
|
/* alloc + free via mmap-backed runtime — write through allocated
|
||||||
* memory and free it. exit = 0 if the allocation succeeded. */
|
* memory and free it. exit = 0 if the allocation succeeded. */
|
||||||
{ "import os;\n"
|
{ "import os;\n"
|
||||||
|
"import rt;\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *void = os.alloc(4096u64);\n"
|
" let p: *void = rt.alloc(4096u64);\n"
|
||||||
" if (p == nil) { return 1; };\n"
|
" if (p == nil) { return 1; };\n"
|
||||||
" let bp: *u8 = p: *u8;\n"
|
" let bp: *u8 = p: *u8;\n"
|
||||||
" bp[0] = 65u8;\n"
|
" bp[0] = 65u8;\n"
|
||||||
@@ -280,7 +281,7 @@ static const struct row rows[] = {
|
|||||||
* builtin via the inherited os.alloc decl. Task #30 graduated
|
* builtin via the inherited os.alloc decl. Task #30 graduated
|
||||||
* the builtin to `(*T | nomem)`; the `!` aborts on OOM. */
|
* the builtin to `(*T | nomem)`; the `!` aborts on OOM. */
|
||||||
{ "package main;\n"
|
{ "package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"type point = struct { x: i32, y: i32 };\n"
|
"type point = struct { x: i32, y: i32 };\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *point = alloc(point { x = 3, y = 4 })!;\n"
|
" let p: *point = alloc(point { x = 3, y = 4 })!;\n"
|
||||||
@@ -301,7 +302,7 @@ static const struct row rows[] = {
|
|||||||
* Task #30 graduated the slice form to `([]T | nomem)`; the `!`
|
* Task #30 graduated the slice form to `([]T | nomem)`; the `!`
|
||||||
* aborts on OOM. */
|
* aborts on OOM. */
|
||||||
{ "package main;\n"
|
{ "package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let s: []u8 = alloc([], 16)!;\n"
|
" let s: []u8 = alloc([], 16)!;\n"
|
||||||
" append(s, 72u8, 105u8);\n"
|
" append(s, 72u8, 105u8);\n"
|
||||||
@@ -311,14 +312,14 @@ static const struct row rows[] = {
|
|||||||
* `[]rune` is 4B-per-element; the cgen shortcut scales count by
|
* `[]rune` is 4B-per-element; the cgen shortcut scales count by
|
||||||
* size(T). Returns s.cap = 8. */
|
* size(T). Returns s.cap = 8. */
|
||||||
{ "package main;\n"
|
{ "package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let s: []rune = alloc([], 8)!;\n"
|
" let s: []rune = alloc([], 8)!;\n"
|
||||||
" return s.cap;\n"
|
" return s.cap;\n"
|
||||||
"};", 8 },
|
"};", 8 },
|
||||||
/* #45: same as above for `[]str` (16B-per-element). */
|
/* #45: same as above for `[]str` (16B-per-element). */
|
||||||
{ "package main;\n"
|
{ "package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let s: []str = alloc([], 4)!;\n"
|
" let s: []str = alloc([], 4)!;\n"
|
||||||
" return s.cap;\n"
|
" return s.cap;\n"
|
||||||
@@ -327,7 +328,7 @@ static const struct row rows[] = {
|
|||||||
* return; the alloc-slice shortcut emits MOVQ $nomem_tag, AX +
|
* return; the alloc-slice shortcut emits MOVQ $nomem_tag, AX +
|
||||||
* propret on null. doit returns 12 on success; main unwraps. */
|
* propret on null. doit returns 12 on success; main unwraps. */
|
||||||
{ "package main;\n"
|
{ "package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"fn doit() (i32 | nomem) = {\n"
|
"fn doit() (i32 | nomem) = {\n"
|
||||||
" let s: []str = alloc([], 12)?;\n"
|
" let s: []str = alloc([], 12)?;\n"
|
||||||
" return s.cap: i32;\n"
|
" return s.cap: i32;\n"
|
||||||
@@ -393,6 +394,7 @@ static const struct row rows[] = {
|
|||||||
* builtin to a fallible signature; the `!` aborts on OOM. */
|
* builtin to a fallible signature; the `!` aborts on OOM. */
|
||||||
{ "package main;\n"
|
{ "package main;\n"
|
||||||
"import os;\n"
|
"import os;\n"
|
||||||
|
"import rt;\n"
|
||||||
"type point = struct { x: i64, y: i64 };\n"
|
"type point = struct { x: i64, y: i64 };\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *point = alloc(point { x = 7, y = 35 })!;\n"
|
" let p: *point = alloc(point { x = 7, y = 35 })!;\n"
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ static const struct row rows[] = {
|
|||||||
/* Singleton str field. Pre-fix p.s.len stayed 0; post-fix 5. */
|
/* Singleton str field. Pre-fix p.s.len stayed 0; post-fix 5. */
|
||||||
{ "alloc_str_singleton",
|
{ "alloc_str_singleton",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"type holder = struct { s: str };\n"
|
"type holder = struct { s: str };\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *holder = alloc(holder { s = \"hello\" })!;\n"
|
" let p: *holder = alloc(holder { s = \"hello\" })!;\n"
|
||||||
@@ -72,7 +72,7 @@ static const struct row rows[] = {
|
|||||||
* unaffected. Pre-fix: 100 + 0 = 100; post-fix: 100 + 2 = 102. */
|
* unaffected. Pre-fix: 100 + 0 = 100; post-fix: 100 + 2 = 102. */
|
||||||
{ "alloc_i32_then_str",
|
{ "alloc_i32_then_str",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"type holder = struct { n: i32, s: str };\n"
|
"type holder = struct { n: i32, s: str };\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *holder = alloc(holder { n = 100, s = \"hi\" })!;\n"
|
" let p: *holder = alloc(holder { n = 100, s = \"hi\" })!;\n"
|
||||||
@@ -84,7 +84,7 @@ static const struct row rows[] = {
|
|||||||
* post-fix: 5 + 7 = 12. */
|
* post-fix: 5 + 7 = 12. */
|
||||||
{ "alloc_str_then_i32",
|
{ "alloc_str_then_i32",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"type holder = struct { s: str, n: i32 };\n"
|
"type holder = struct { s: str, n: i32 };\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *holder = alloc(holder { s = \"world\", n = 7 })!;\n"
|
" let p: *holder = alloc(holder { s = \"world\", n = 7 })!;\n"
|
||||||
@@ -95,7 +95,7 @@ static const struct row rows[] = {
|
|||||||
* Pins that `fi = nil` advances correctly between str fields. */
|
* Pins that `fi = nil` advances correctly between str fields. */
|
||||||
{ "alloc_two_str",
|
{ "alloc_two_str",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"type holder = struct { a: str, b: str };\n"
|
"type holder = struct { a: str, b: str };\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *holder = alloc(holder { a = \"foo\", b = \"barbaz\" })!;\n"
|
" let p: *holder = alloc(holder { a = \"foo\", b = \"barbaz\" })!;\n"
|
||||||
@@ -108,7 +108,7 @@ static const struct row rows[] = {
|
|||||||
* without disrupting either. */
|
* without disrupting either. */
|
||||||
{ "alloc_f64_str_i32",
|
{ "alloc_f64_str_i32",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"type holder = struct { f: f64, s: str, n: i32 };\n"
|
"type holder = struct { f: f64, s: str, n: i32 };\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *holder = alloc(holder { f = 1.5f64, s = \"abc\", n = 10 })!;\n"
|
" let p: *holder = alloc(holder { f = 1.5f64, s = \"abc\", n = 10 })!;\n"
|
||||||
@@ -121,7 +121,7 @@ static const struct row rows[] = {
|
|||||||
* Indexes the string by hand to avoid pulling in stdlib. */
|
* Indexes the string by hand to avoid pulling in stdlib. */
|
||||||
{ "alloc_str_readback",
|
{ "alloc_str_readback",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"type holder = struct { s: str };\n"
|
"type holder = struct { s: str };\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let p: *holder = alloc(holder { s = \"hi\" })!;\n"
|
" let p: *holder = alloc(holder { s = \"hi\" })!;\n"
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ main(void)
|
|||||||
/* #45: alloc-slice `!` form, []T element ≠ u8. */
|
/* #45: alloc-slice `!` form, []T element ≠ u8. */
|
||||||
{ "alloc_slice_rune_unw",
|
{ "alloc_slice_rune_unw",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"fn main() i32 = {\n"
|
"fn main() i32 = {\n"
|
||||||
" let s: []rune = alloc([], 8)!;\n"
|
" let s: []rune = alloc([], 8)!;\n"
|
||||||
" return s.cap;\n"
|
" return s.cap;\n"
|
||||||
@@ -211,7 +211,7 @@ main(void)
|
|||||||
* enclosing fn's tagged return. */
|
* enclosing fn's tagged return. */
|
||||||
{ "alloc_slice_str_prop",
|
{ "alloc_slice_str_prop",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
"import os;\n"
|
"import rt;\n"
|
||||||
"fn doit() (i32 | nomem) = {\n"
|
"fn doit() (i32 | nomem) = {\n"
|
||||||
" let s: []str = alloc([], 4)?;\n"
|
" let s: []str = alloc([], 4)?;\n"
|
||||||
" return s.cap: i32;\n"
|
" return s.cap: i32;\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user