boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit 600fbdc515633243f8e9ef9b04f9c84ff07af210
parent e77067e3f9ee54059d2c6e972d3265b0088f0cc9
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun,  3 May 2026 18:08:38 -0700

Update scheme1 for M1pp hex2pp pipeline

Diffstat:
Mdocs/DEBUG.md | 35+++++++++++++++++++----------------
Mscheme1/scheme1.P1pp | 2184+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mscripts/disasm-elf.sh | 23+++++++++++++----------
Mscripts/m1-symbols.py | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
4 files changed, 1192 insertions(+), 1140 deletions(-)

diff --git a/docs/DEBUG.md b/docs/DEBUG.md @@ -1,6 +1,6 @@ # DEBUG -Debugging facilities for the cc / P1pp / M1 / hex2 pipeline. Each +Debugging facilities for the cc / P1pp / M1pp / hex2pp pipeline. Each section: what the tool does, how to turn it on, what you get back. ## Tracepoints (`%trace` / `--cc-trace-emit`) @@ -36,7 +36,7 @@ Cost: register save/restore traffic plus one call per traced function. Off by default; the `%trace` macro itself lives in [P1/P1pp.P1pp](../P1/P1pp.P1pp) (§Tracepoint) and can also be invoked manually — drop a `%trace(&label, len)` into any `combined.M1pp` -snapshot under `build/$ARCH/.work/<src>/`, re-run the m1pp/M0/hex2 +snapshot under `build/$ARCH/.work/<src>/`, re-run the M1pp/hex2pp stages, and bisect by stderr position. `%trace` preserves the exposed P1 registers (`a0..a3`, `t0..t2`, `s0..s3`) by borrowing temporary stack space, so it is safe to add inside an active `%fn` body after @@ -48,14 +48,14 @@ To map an address back to its function, see the lookup tool below. ## Address → label lookup (`m1-symbols.py lookup`) Resolves a runtime address (e.g. from a `%trace` line) to its -enclosing function. Reads the label map straight out of `prog.hex2` -and finds the largest label address `<= target`, skipping M1pp's -mangled macro-locals (`:@name` → `:name__N`) so a trace address +enclosing function. Reads the label map straight out of `expanded.hex2pp` +(or legacy `prog.hex2`) and finds the largest label address `<= target`, +skipping M1pp's mangled macro-locals (`:@name` → `:name__N`) so a trace address resolves to the *function* containing it, not the trace's own `:@here`. ```sh -# Pass the ELF; the tool reads <ELF>.workdir to find prog.hex2. +# Pass the ELF; the tool reads <ELF>.workdir to find expanded.hex2pp. scripts/m1-symbols.py lookup --elf build/aarch64/tests/cc/007-call-with-args 0x6019fc 0x6018fc # 0x6019fc main+0x24 # 0x6018fc g+0x2c @@ -66,8 +66,9 @@ scripts/m1-symbols.py lookup --elf build/aarch64/tests/cc/007-call-with-args 0x6 | scripts/m1-symbols.py lookup --elf build/aarch64/tests/cc/007-call-with-args ``` -Other input modes: `--hex2 <prog.hex2>` (skip the sidecar lookup) or -`--map <file>` (use a pre-built map from `m1-symbols.py map`). Pass +Other input modes: `--hex2 <expanded.hex2pp|prog.hex2>` (skip the +sidecar lookup) or `--map <file>` (use a pre-built map from +`m1-symbols.py map`). Pass `--include-macro-locals` to see the closest label even when it's a `name__N` artifact — useful when you want to know which trace site fired vs. which function it sits in. @@ -78,7 +79,8 @@ Output is `0xADDR\tLABEL+0xN`, tab-separated, one per line. llvm-objdump wrapper that handles two quirks of our seed ELF: oversized ph_memsz (truncated to ph_filesz on a temp copy) and the absent section -table (replaced by labels injected from `prog.hex2`). The output has +table (replaced by labels injected from `expanded.hex2pp`, or legacy +`prog.hex2`). The output has real `<funcname>:` headers and `<PT_LOAD#0+0xNNN>` xrefs rewritten to `<label+offset>`: @@ -119,22 +121,23 @@ Every P1pp/P1 build leaves its intermediates next to the ELF: ``` build/$ARCH/.work/<src-path>/ combined.M1pp # backend + frontend + libp1pp + user TU, catm'd - expanded.M1 # m1pp output, ready for M0 - prog.hex2 # M0 output (hex2 with labels) - linked.hex2 # ELF header + prog.hex2 + expanded.hex2pp # M1pp output, ready for hex2pp + linked.hex2pp # ELF header + expanded.hex2pp cc.log # cc.scm stderr (if --cc-debug or trace-emit) - p1pp.log # m1pp/M0/hex2 stderr + p1pp.log # M1pp/hex2pp stderr ``` Each ELF also gets a one-line `<elf>.workdir` sidecar pointing at this directory — that's how `disasm-elf.sh` and `m1-symbols.py lookup ---elf` find `prog.hex2`. On a failing build the runner prints the +--elf` find `expanded.hex2pp` (or legacy `prog.hex2` for raw-P1 +builds). On a failing build the runner prints the partial-intermediates path; on a passing build the files stay around for inspection. To re-run a single intermediate stage by hand: edit the file in place -and invoke the next tool directly (`build/$ARCH/tools/M0 -prog.hex2.M0`, etc.). Useful for poking `%trace` calls into +and invoke the next tool directly (`build/$ARCH/M1pp/M1pp +combined.M1pp expanded.hex2pp`, then `build/$ARCH/hex2pp/hex2pp +-B 0x600000 linked.hex2pp out`). Useful for poking `%trace` calls into `combined.M1pp` without recompiling cc.scm. ## End-to-end debugging recipe diff --git a/scheme1/scheme1.P1pp b/scheme1/scheme1.P1pp @@ -2,7 +2,7 @@ # # Build chain: # catm P1-<arch>.M1pp P1.M1pp P1pp.P1pp scheme1/scheme1.P1pp \ -# | m1pp -> M0 -> hex2 -> ELF +# | m1pp -> hex2pp -> ELF # # Run chain: # catm scheme1/prelude.scm prog.scm | scheme1 @@ -148,19 +148,11 @@ %call(&runtime_error) %endm -# Intern a special-form name and stash the tagged-symbol value in a -# labeled slot. `name` and `slot` are written as full label refs -# (`&foo`) so the macro can substitute them verbatim into %la sites. -# Pad the string `str` (including its M1 auto-null) to an 8-byte boundary. -# Uses quoted-literal hex form required by riscv64 stage0 M0. -%macro align8_pad(str) - %select((= (% (+ (strlen str) 1) 8) 0), , - %select((= (% (+ (strlen str) 1) 8) 1), '00000000000000', - %select((= (% (+ (strlen str) 1) 8) 2), '000000000000', - %select((= (% (+ (strlen str) 1) 8) 3), '0000000000', - %select((= (% (+ (strlen str) 1) 8) 4), '00000000', - %select((= (% (+ (strlen str) 1) 8) 5), '000000', - %select((= (% (+ (strlen str) 1) 8) 6), '0000', '00'))))))) +# Emit an 8-aligned NUL-terminated string. +%macro cstr8(str) + str + 00 + .align 8 %endm # Intern `str` into `slot` and declare its padded string data inline. @@ -172,8 +164,7 @@ %st_global(a0, slot, t0) %b(&@end) :name_ ## key - str - %align8_pad(str) + %cstr8(str) :@end %endm @@ -268,7 +259,7 @@ # if argc < 2 goto usage %li(t0, 2) - %bltu(a0, t0, &::usage) + %bltu(a0, t0, &.usage) # Initialize %la(a0, &ELF_end) @@ -286,11 +277,11 @@ %call(&load_source) # read-eval loop - %loop_tag(eval, { + %loop_scoped({ # eof = skip_ws() %call(&skip_ws) # if eof break - %bnez(a0, &::eval_end) + %if_nez(a0, { %break }) # expr = parse_one() %call(&parse_one) # eval(expr, env=nil) @@ -302,7 +293,7 @@ %li(a0, 0) %eret - ::usage + :.usage %la(a0, &msg_usage) %call(&print_cstr) %li(a0, 2) @@ -320,103 +311,103 @@ # a0 = 1 if readbuf_pos >= readbuf_len after skipping (caller hit EOF), # else 0. Leaf. :skip_ws -%scope skip_ws +.scope %lda_global(t0, t2, &readbuf_pos) %ld_global(t1, &readbuf_len) - ::loop - %beq(t0, t1, &::done) + :.loop + %beq(t0, t1, &.done) %readbuf_byte(a0, t0) - %is_ws_branch(a1, a0, &::step) - %bceq(a0, -59, &::comment, a1) ; ';' - %b(&::done) - ::comment + %is_ws_branch(a1, a0, &.step) + %bceq(a0, -59, &.comment, a1) ; ';' + %b(&.done) + :.comment # Consume up to and including the next LF, or to EOF. %addi(t0, t0, 1) - %beq(t0, t1, &::done) + %beq(t0, t1, &.done) %readbuf_byte(a0, t0) - %bcne(a0, -10, &::comment, a1) ; LF - ::step + %bcne(a0, -10, &.comment, a1) ; LF + :.step %addi(t0, t0, 1) - %b(&::loop) - ::done + %b(&.loop) + :.done %st(t0, t2, 0) %li(a0, 1) - %beq(t0, t1, &::ret) + %beq(t0, t1, &.ret) %li(a0, 0) - ::ret + :.ret %ret -%endscope +.endscope # parse_one() -> tagged value in a0 %fn(parse_one, 0, { %call(&skip_ws) - %bnez(a0, &::eof) + %bnez(a0, &.eof) %ld_global(t0, &readbuf_pos) %readbuf_byte(a0, t0) - %bceq(a0, -40, &::lparen, a1) - %bceq(a0, -41, &::rparen, a1) - %bceq(a0, -35, &::hash, a1) - %bceq(a0, -39, &::quote, a1) - %bceq(a0, -44, &::comma, a1) - %bceq(a0, -34, &::string, a1) + %bceq(a0, -40, &.lparen, a1) + %bceq(a0, -41, &.rparen, a1) + %bceq(a0, -35, &.hash, a1) + %bceq(a0, -39, &.quote, a1) + %bceq(a0, -44, &.comma, a1) + %bceq(a0, -34, &.string, a1) %tail(&parse_atom) - ::lparen + :.lparen # Consume '(' and read items until ')'. %lda_global(t1, t0, &readbuf_pos) %readbuf_advance(t1, t0) %tail(&parse_list) - ::rparen + :.rparen %die(msg_unexp_rparen) - ::string + :.string # Consume opening '"' and tail to parse_string. parse_string scans # through the matching '"' (consuming it) and returns a tagged bv. %lda_global(t1, t0, &readbuf_pos) %readbuf_advance(t1, t0) %tail(&parse_string) - ::hash + :.hash # Consume '#' plus its type byte; dispatch on the type byte. %lda_global(t0, t2, &readbuf_pos) %addi(t0, t0, 1) - %readbuf_at_eof(t0, t1, &::eof) + %readbuf_at_eof(t0, t1, &.eof) %readbuf_byte(a0, t0) %readbuf_advance(t0, t2) - %bceq(a0, -116, &::true_lit, a1) ; 't' - %bceq(a0, -102, &::false_lit, a1) ; 'f' - %bceq(a0, -120, &::hex_lit, a1) ; 'x' - %bceq(a0, -88, &::hex_lit, a1) ; 'X' - %bceq(a0, -92, &::char_lit, a1) ; '\\' - %bceq(a0, -117, &::u8_lit, a1) ; 'u' + %bceq(a0, -116, &.true_lit, a1) ; 't' + %bceq(a0, -102, &.false_lit, a1) ; 'f' + %bceq(a0, -120, &.hex_lit, a1) ; 'x' + %bceq(a0, -88, &.hex_lit, a1) ; 'X' + %bceq(a0, -92, &.char_lit, a1) ; '\\' + %bceq(a0, -117, &.u8_lit, a1) ; 'u' %die(msg_bad_hash) - ::true_lit + :.true_lit %li(a0, %imm_val(%IMM.TRUE)) %eret - ::false_lit + :.false_lit %li(a0, %imm_val(%IMM.FALSE)) %eret - ::hex_lit + :.hex_lit # t0 sits at the first hex digit; t1 = readbuf_len. Scan to ws/paren/EOF, # then parse_hex over the slice (with optional leading '-'). %mov(a3, t0) - ::hex_scan - %beq(t0, t1, &::hex_end) + :.hex_scan + %beq(t0, t1, &.hex_end) %readbuf_byte(a0, t0) - %is_ws_branch(a1, a0, &::hex_end) - %bceq(a0, -40, &::hex_end, a1) - %bceq(a0, -41, &::hex_end, a1) + %is_ws_branch(a1, a0, &.hex_end) + %bceq(a0, -40, &.hex_end, a1) + %bceq(a0, -41, &.hex_end, a1) %addi(t0, t0, 1) - %b(&::hex_scan) - ::hex_end + %b(&.hex_scan) + :.hex_end %st_global(t0, &readbuf_pos, t2) %ld_global(a0, &readbuf_buf_ptr) @@ -424,11 +415,11 @@ %sub(a1, t0, a3) %lb(t2, a0, 0) %addi(t2, t2, -45) ; '-' - %beqz(t2, &::hex_neg) + %beqz(t2, &.hex_neg) %call(&parse_hex) %mkfix(a0, a0) %eret - ::hex_neg + :.hex_neg %addi(a0, a0, 1) %addi(a1, a1, -1) %call(&parse_hex) @@ -437,7 +428,7 @@ %mkfix(a0, a0) %eret - ::quote + :.quote # Consume the leading '\''; recurse into parse_one for the datum; # then build (quote <datum>). %lda_global(t0, t2, &readbuf_pos) @@ -450,7 +441,7 @@ %mov(a0, t0) %tail(&cons) - ::comma + :.comma # Consume the leading ','; recurse into parse_one for the datum; # build (unquote <datum>). The comma sugar exists so pmatch # patterns can be written as `,ident`. Outside pmatch @@ -466,29 +457,29 @@ %mov(a0, t0) %tail(&cons) - ::char_lit + :.char_lit # Cursor is already past '#\\'; parse_char scans the body and returns # a tagged fixnum (the u8 char value). %tail(&parse_char) - ::u8_lit + :.u8_lit # Cursor is past '#u'. Demand '8' then '('; consume both and tail to # parse_u8_body, which reads the element list and packs it into a bv. %lda_global(t0, t2, &readbuf_pos) - %readbuf_at_eof(t0, t1, &::u8_bad) + %readbuf_at_eof(t0, t1, &.u8_bad) %readbuf_byte(a0, t0) - %bcne(a0, -56, &::u8_bad, a1) ; '8' + %bcne(a0, -56, &.u8_bad, a1) ; '8' %addi(t0, t0, 1) - %beq(t0, t1, &::u8_bad) + %beq(t0, t1, &.u8_bad) %readbuf_byte(a0, t0) - %bcne(a0, -40, &::u8_bad, a1) ; '(' + %bcne(a0, -40, &.u8_bad, a1) ; '(' %readbuf_advance(t0, t2) %tail(&parse_u8_body) - ::u8_bad + :.u8_bad %die(msg_bad_hash) - ::eof + :.eof %die(msg_unexp_eof) }) @@ -503,25 +494,25 @@ %stl(t0, head) %stl(t0, tail) - ::loop + :.loop %call(&skip_ws) - %bnez(a0, &::eof) + %bnez(a0, &.eof) %ld_global(t0, &readbuf_pos) %ld_global(t1, &readbuf_len) %readbuf_byte(a0, t0) - %bceq(a0, -41, &::close, a1) + %bceq(a0, -41, &.close, a1) # Dotted-pair separator: '.' followed by ws/paren/EOF (otherwise the # '.' is part of an identifier and parse_atom handles it). - %bcne(a0, -46, &::not_dot, a1) ; '.' + %bcne(a0, -46, &.not_dot, a1) ; '.' %addi(a2, t0, 1) - %beq(a2, t1, &::do_dot) + %beq(a2, t1, &.do_dot) %readbuf_byte(a3, a2) - %is_ws_branch(a1, a3, &::do_dot) - %bceq(a3, -40, &::do_dot, a1) - %bceq(a3, -41, &::do_dot, a1) - ::not_dot + %is_ws_branch(a1, a3, &.do_dot) + %bceq(a3, -40, &.do_dot, a1) + %bceq(a3, -41, &.do_dot, a1) + :.not_dot # Not ')': parse one item, append. %call(&parse_one) @@ -530,19 +521,19 @@ # If head is NIL, both head and tail = new cons; else set-cdr! tail = new. %ldl(t0, head) - %bine(t0, %imm_val(%IMM.NIL), &::link, t1) + %bine(t0, %imm_val(%IMM.NIL), &.link, t1) %stl(a0, head) %stl(a0, tail) - %b(&::loop) + %b(&.loop) - ::link + :.link %ldl(t0, tail) # set-cdr! tail = a0 -> store a0 at [tail + 7] (raw + 8) %set_cdr(a0, t0) %stl(a0, tail) - %b(&::loop) + %b(&.loop) - ::do_dot + :.do_dot # Consume the '.', read one datum, splice it in as the cdr of the # tail cons. Then expect a closing ')' (with optional ws). %lda_global(t0, t1, &readbuf_pos) @@ -551,22 +542,22 @@ %ldl(t0, tail) %set_cdr(a0, t0) %call(&skip_ws) - %bnez(a0, &::eof) + %bnez(a0, &.eof) %lda_global(t0, t1, &readbuf_pos) %readbuf_byte(a0, t0) - %bcne(a0, -41, &::eof, a1) ; ')' + %bcne(a0, -41, &.eof, a1) ; ')' %readbuf_advance(t0, t1) %ldl(a0, head) %eret - ::close + :.close # Consume ')' and return head. %lda_global(t1, t0, &readbuf_pos) %readbuf_advance(t1, t0) %ldl(a0, head) %eret - ::eof + :.eof %die(msg_unterm_list) }) @@ -589,15 +580,15 @@ %heap_ld(t0, a0, %BV.data) %ldl(a0, list) ; list cursor - ::loop - %if_nil(t1, a0, &::done) + :.loop + %if_nil(t1, a0, &.done) %car(t1, a0) %untag_fix(t1, t1) %sb(t1, t0, 0) %addi(t0, t0, 1) %cdr(a0, a0) - %b(&::loop) - ::done + %b(&.loop) + :.done %ldl(a0, result) }) @@ -606,37 +597,37 @@ # digits, and the extended chars ! $ % & * + - . / : < = > ? @ ^ _ ~ . # Clobbers t0, t1, a1. :is_ident_byte -%scope is_ident_byte - %brange(a0, -48, 10, t0, t1, &::ok) ; '0'..'9' - %brange(a0, -65, 26, t0, t1, &::ok) ; 'A'..'Z' - %brange(a0, -97, 26, t0, t1, &::ok) ; 'a'..'z' - - %bceq(a0, -33, &::ok, t0) ; '!' - %bceq(a0, -36, &::ok, t0) ; '$' - %bceq(a0, -37, &::ok, t0) ; '%' - %bceq(a0, -38, &::ok, t0) ; '&' - %bceq(a0, -42, &::ok, t0) ; '*' - %bceq(a0, -43, &::ok, t0) ; '+' - %bceq(a0, -45, &::ok, t0) ; '-' - %bceq(a0, -46, &::ok, t0) ; '.' - %bceq(a0, -47, &::ok, t0) ; '/' - %bceq(a0, -58, &::ok, t0) ; ':' - %bceq(a0, -60, &::ok, t0) ; '<' - %bceq(a0, -61, &::ok, t0) ; '=' - %bceq(a0, -62, &::ok, t0) ; '>' - %bceq(a0, -63, &::ok, t0) ; '?' - %bceq(a0, -64, &::ok, t0) ; '@' - %bceq(a0, -94, &::ok, t0) ; '^' - %bceq(a0, -95, &::ok, t0) ; '_' - %bceq(a0, -126, &::ok, t0) ; '~' +.scope + %brange(a0, -48, 10, t0, t1, &.ok) ; '0'..'9' + %brange(a0, -65, 26, t0, t1, &.ok) ; 'A'..'Z' + %brange(a0, -97, 26, t0, t1, &.ok) ; 'a'..'z' + + %bceq(a0, -33, &.ok, t0) ; '!' + %bceq(a0, -36, &.ok, t0) ; '$' + %bceq(a0, -37, &.ok, t0) ; '%' + %bceq(a0, -38, &.ok, t0) ; '&' + %bceq(a0, -42, &.ok, t0) ; '*' + %bceq(a0, -43, &.ok, t0) ; '+' + %bceq(a0, -45, &.ok, t0) ; '-' + %bceq(a0, -46, &.ok, t0) ; '.' + %bceq(a0, -47, &.ok, t0) ; '/' + %bceq(a0, -58, &.ok, t0) ; ':' + %bceq(a0, -60, &.ok, t0) ; '<' + %bceq(a0, -61, &.ok, t0) ; '=' + %bceq(a0, -62, &.ok, t0) ; '>' + %bceq(a0, -63, &.ok, t0) ; '?' + %bceq(a0, -64, &.ok, t0) ; '@' + %bceq(a0, -94, &.ok, t0) ; '^' + %bceq(a0, -95, &.ok, t0) ; '_' + %bceq(a0, -126, &.ok, t0) ; '~' %li(a1, 0) %ret - ::ok + :.ok %li(a1, 1) %ret -%endscope +.endscope # parse_atom() -> tagged value (fixnum or symbol) in a0. # Reads until whitespace or paren or EOF, then dispatches by first byte. @@ -654,18 +645,18 @@ %ld_global(t2, &readbuf_len) - ::scan - %beq(t1, t2, &::end) + :.scan + %beq(t1, t2, &.end) %readbuf_byte(a0, t1) - %is_ws_branch(a1, a0, &::end) - %bceq(a0, -40, &::end, a1) ; '(' - %bceq(a0, -41, &::end, a1) ; ')' + %is_ws_branch(a1, a0, &.end) + %bceq(a0, -40, &.end, a1) ; '(' + %bceq(a0, -41, &.end, a1) ; ')' %addi(t1, t1, 1) - %b(&::scan) + %b(&.scan) - ::end + :.end %stl(t1, end) %st(t1, t0, 0) @@ -678,41 +669,41 @@ # '0'..'9' -> int %addi(a1, t1, -48) %li(a2, 10) - %bltu(a1, a2, &::is_int) + %bltu(a1, a2, &.is_int) # '-' or '+' followed by digit -> int. A lone '+' or '-' falls # through to is_sym (those tokens stay valid identifiers). - %bceq(t1, -45, &::sign, a1) ; '-' - %bceq(t1, -43, &::sign, a1) ; '+' - %b(&::is_sym) - ::sign + %bceq(t1, -45, &.sign, a1) ; '-' + %bceq(t1, -43, &.sign, a1) ; '+' + %b(&.is_sym) + :.sign %ldl(t2, end) %addi(t0, t0, 1) - %beq(t0, t2, &::is_sym) + %beq(t0, t2, &.is_sym) %readbuf_byte(a0, t0) %addi(a1, a0, -48) - %bltu(a1, a2, &::is_int) + %bltu(a1, a2, &.is_int) # fall through to is_sym - ::is_sym + :.is_sym # Validate every byte; abort on the first non-ident byte. %ldl(t0, start) %stl(t0, cursor) - ::sym_loop + :.sym_loop %ldl(t0, cursor) %ldl(t1, end) - %beq(t0, t1, &::sym_intern) + %beq(t0, t1, &.sym_intern) %readbuf_byte(a0, t0) %call(&is_ident_byte) - %beqz(a1, &::sym_bad) + %beqz(a1, &.sym_bad) %ldl(t0, cursor) %addi(t0, t0, 1) %stl(t0, cursor) - %b(&::sym_loop) + %b(&.sym_loop) - ::sym_bad + :.sym_bad %die(msg_bad_ident) - ::sym_intern + :.sym_intern %ldl(a0, start) %ld_global(t0, &readbuf_buf_ptr) %add(a0, t0, a0) @@ -721,7 +712,7 @@ %sub(a1, t1, t2) %tail(&intern) - ::is_int + :.is_int %ldl(t0, start) %ldl(t1, end) %ld_global(a0, &readbuf_buf_ptr) @@ -729,17 +720,17 @@ %sub(a1, t1, t0) ; len = end - start # P1pp's parse_dec handles '-' but not '+'; strip '+' here. %lb(t2, a0, 0) - %bcne(t2, -43, &::no_plus, t2) ; '+' + %bcne(t2, -43, &.no_plus, t2) ; '+' %addi(a0, a0, 1) %addi(a1, a1, -1) - ::no_plus + :.no_plus %stl(a1, cursor) ; save adjusted len (cursor slot is free on int path) %call(&parse_dec) ; P1pp: -> (raw_val=a0, consumed=a1) %ldl(t0, cursor) - %bne(a1, t0, &::int_bad) ; partial parse -> bad + %bne(a1, t0, &.int_bad) ; partial parse -> bad %mkfix(a0, a0) %eret - ::int_bad + :.int_bad %die(msg_bad_number) }) @@ -762,43 +753,43 @@ %ld_global(t2, &readbuf_len) %li(a0, 0) - ::scan - %beq(t1, t2, &::eof) + :.scan + %beq(t1, t2, &.eof) %readbuf_byte(a3, t1) - %bceq(a3, -34, &::scan_done, a1) ; '"' - %bceq(a3, -92, &::scan_esc, a1) ; '\\' + %bceq(a3, -34, &.scan_done, a1) ; '"' + %bceq(a3, -92, &.scan_esc, a1) ; '\\' %addi(t1, t1, 1) %addi(a0, a0, 1) - %b(&::scan) + %b(&.scan) - ::scan_esc + :.scan_esc # Backslash plus the next byte yield one decoded byte. \xHEX; runs # until the terminating ';' (validated in pass 2); every other escape # is exactly two source bytes. %addi(t1, t1, 1) - %beq(t1, t2, &::eof) + %beq(t1, t2, &.eof) %readbuf_byte(a3, t1) - %bceq(a3, -120, &::scan_hex, a1) ; 'x' + %bceq(a3, -120, &.scan_hex, a1) ; 'x' %addi(t1, t1, 1) %addi(a0, a0, 1) - %b(&::scan) + %b(&.scan) - ::scan_hex + :.scan_hex # Skip past 'x' and scan to the terminating ';'. EOF before ';' # falls into the unterminated-string path below, matching how an # unterminated body is reported. %addi(t1, t1, 1) - ::scan_hex_loop - %beq(t1, t2, &::eof) + :.scan_hex_loop + %beq(t1, t2, &.eof) %readbuf_byte(a3, t1) - %bceq(a3, -59, &::scan_hex_done, a1) ; ';' + %bceq(a3, -59, &.scan_hex_done, a1) ; ';' %addi(t1, t1, 1) - %b(&::scan_hex_loop) - ::scan_hex_done + %b(&.scan_hex_loop) + :.scan_hex_done %addi(t1, t1, 1) ; consume ';' %addi(a0, a0, 1) ; +1 output byte - %b(&::scan) - ::scan_done + %b(&.scan) + :.scan_done %stl(t1, end) %call(&str_alloc) @@ -809,41 +800,41 @@ %ldl(t2, end) %heap_ld(a3, a0, %BV.data) - ::fill - %beq(t1, t2, &::fill_done) + :.fill + %beq(t1, t2, &.fill_done) %readbuf_byte(a1, t1) - %bceq(a1, -92, &::fill_esc, a2) ; '\\' + %bceq(a1, -92, &.fill_esc, a2) ; '\\' %sb(a1, a3, 0) %addi(a3, a3, 1) %addi(t1, t1, 1) - %b(&::fill) + %b(&.fill) - ::fill_esc + :.fill_esc %addi(t1, t1, 1) ; consume backslash %readbuf_byte(a1, t1) - %bceq(a1, -110, &::esc_n, a2) ; 'n' - %bceq(a1, -116, &::esc_t, a2) ; 't' - %bceq(a1, -114, &::esc_r, a2) ; 'r' - %bceq(a1, -92, &::write_byte, a2) ; '\\' - %bceq(a1, -34, &::write_byte, a2) ; '"' - %bceq(a1, -120, &::esc_hex, a2) ; 'x' + %bceq(a1, -110, &.esc_n, a2) ; 'n' + %bceq(a1, -116, &.esc_t, a2) ; 't' + %bceq(a1, -114, &.esc_r, a2) ; 'r' + %bceq(a1, -92, &.write_byte, a2) ; '\\' + %bceq(a1, -34, &.write_byte, a2) ; '"' + %bceq(a1, -120, &.esc_hex, a2) ; 'x' %die(msg_bad_escape) - ::esc_n + :.esc_n %li(a1, 10) - %b(&::write_byte) - ::esc_t + %b(&.write_byte) + :.esc_t %li(a1, 9) - %b(&::write_byte) - ::esc_r + %b(&.write_byte) + :.esc_r %li(a1, 13) - ::write_byte + :.write_byte %sb(a1, a3, 0) %addi(a3, a3, 1) %addi(t1, t1, 1) - %b(&::fill) + %b(&.fill) - ::esc_hex + :.esc_hex # Skip past 'x'. parse_hex consumes hex digits; demand at least one, # value <= 255, and an immediate ';' terminator. parse_hex clobbers # t0/t1/t2 and a2/a3, so spill the cursor (t1) and write ptr (a3) @@ -855,31 +846,31 @@ %add(a0, t0, t1) ; ptr to first hex digit %sub(a1, t2, t1) ; max len (bytes left in body) %call(&parse_hex) ; -> (a0=value, a1=consumed) - %beqz(a1, &::hex_bad) + %beqz(a1, &.hex_bad) %li(t0, 255) - %bltu(t0, a0, &::hex_bad) + %bltu(t0, a0, &.hex_bad) %ldl(t1, start) %add(t1, t1, a1) ; t1 = position of expected ';' %ldl(t2, end) - %beq(t1, t2, &::hex_bad) + %beq(t1, t2, &.hex_bad) %readbuf_byte(t0, t1) - %bcne(t0, -59, &::hex_bad, t0) ; ';' + %bcne(t0, -59, &.hex_bad, t0) ; ';' %addi(t1, t1, 1) ; consume ';' %ldl(a3, spill) %sb(a0, a3, 0) %addi(a3, a3, 1) - %b(&::fill) + %b(&.fill) - ::hex_bad + :.hex_bad %die(msg_bad_escape) - ::fill_done + :.fill_done %addi(t1, t1, 1) ; consume closing '"' %st_global(t1, &readbuf_pos, t0) %ldl(a0, bv) %eret - ::eof + :.eof %die(msg_unterm_string) }) @@ -891,7 +882,7 @@ %la(a1, name_label) %li(a2, len) %call(&memcmp) - %bnez(a0, &::bad) + %bnez(a0, &.bad) %li(a0, value) %mkfix(a0, a0) %eret @@ -912,22 +903,22 @@ %ld_global(t2, &readbuf_len) - %beq(t1, t2, &::short) + %beq(t1, t2, &.short) # Always consume the first byte unconditionally — it might itself be # a delimiter (e.g., '(' in `#\(`) and is still the character value. %addi(t1, t1, 1) - ::scan - %beq(t1, t2, &::scan_done) + :.scan + %beq(t1, t2, &.scan_done) %readbuf_byte(a0, t1) - %is_ws_branch(a1, a0, &::scan_done) - %bceq(a0, -40, &::scan_done, a1) ; '(' - %bceq(a0, -41, &::scan_done, a1) ; ')' + %is_ws_branch(a1, a0, &.scan_done) + %bceq(a0, -40, &.scan_done, a1) ; '(' + %bceq(a0, -41, &.scan_done, a1) ; ')' %addi(t1, t1, 1) - %b(&::scan) + %b(&.scan) - ::scan_done + :.scan_done %stl(t1, end) %st(t1, t0, 0) @@ -935,7 +926,7 @@ %ldl(t1, end) %sub(a2, t1, t0) ; length - %bieq(a2, 1, &::single, a3) + %bieq(a2, 1, &.single, a3) %ld_global(t2, &readbuf_buf_ptr) %add(t2, t2, t0) ; t2 = slice ptr @@ -943,49 +934,49 @@ # Hex form: first byte is 'x'. %lb(a0, t2, 0) %addi(a1, a0, -120) ; 'x' - %beqz(a1, &::hex_form) + %beqz(a1, &.hex_form) # Named form: dispatch on length. - %bieq(a2, 3, &::try_tab, a3) - %bieq(a2, 4, &::try_null, a3) - %bieq(a2, 5, &::try_space, a3) - %bieq(a2, 6, &::try_return, a3) - %bieq(a2, 7, &::try_newline, a3) - %b(&::bad) - - ::single + %bieq(a2, 3, &.try_tab, a3) + %bieq(a2, 4, &.try_null, a3) + %bieq(a2, 5, &.try_space, a3) + %bieq(a2, 6, &.try_return, a3) + %bieq(a2, 7, &.try_newline, a3) + %b(&.bad) + + :.single %ld_global(t2, &readbuf_buf_ptr) %add(t2, t2, t0) %lb(a0, t2, 0) %mkfix(a0, a0) %eret - ::hex_form + :.hex_form %addi(a0, t2, 1) %addi(a1, a2, -1) %call(&parse_hex) %mkfix(a0, a0) %eret - ::try_tab + :.try_tab %match_named_char(&name_ch_tab, 3, 9) - ::try_null + :.try_null %match_named_char(&name_ch_null, 4, 0) - ::try_space + :.try_space %match_named_char(&name_ch_space, 5, 32) - ::try_return + :.try_return %match_named_char(&name_ch_return, 6, 13) - ::try_newline + :.try_newline %match_named_char(&name_ch_newline, 7, 10) - ::bad + :.bad %die(msg_bad_char) - ::short + :.short %die(msg_bad_char) }) @@ -1006,62 +997,62 @@ %stl(a1, env) %tagof(t0, a0) - %bieq(t0, %TAG.SYM, &::sym, t1) - %bieq(t0, %TAG.PAIR, &::pair, t1) + %bieq(t0, %TAG.SYM, &.sym, t1) + %bieq(t0, %TAG.PAIR, &.pair, t1) # FIXNUM, HEAP, IMM all self-evaluate. %eret - ::sym + :.sym # Walk the env alist. Each cell is ((sym . val) . rest). On hit, # return cdr(binding); on NIL, fall back to the symbol's global slot. # a0 still holds the tagged sym; a1 still holds env. - ::env_walk - %if_nil(t0, a1, &::env_miss) + :.env_walk + %if_nil(t0, a1, &.env_miss) %car(t1, a1) ; t1 = (sym . val) %car(t2, t1) ; t2 = sym in binding - %beq(t2, a0, &::env_hit) + %beq(t2, a0, &.env_hit) %cdr(a1, a1) - %b(&::env_walk) + %b(&.env_walk) - ::env_hit + :.env_hit %cdr(a0, t1) %eret - ::env_miss + :.env_miss %untag_sym(a0, a0) %call(&sym_global) - %bieq(a0, %imm_val(%IMM.UNBOUND), &::unbound, t0) + %bieq(a0, %imm_val(%IMM.UNBOUND), &.unbound, t0) %eret - ::unbound + :.unbound %die(msg_unbound) - ::pair + :.pair # Special-form dispatch: pointer-compare head against the cached # special-form symbol values. SYM is a distinct tag, so a head that # isn't a symbol cannot collide with any sym_* slot. %ldl(t0, expr) %car(t0, t0) ; t0 = head - %dispatch_form(&sym_quote, &::do_quote) - %dispatch_form(&sym_if, &::do_if) - %dispatch_form(&sym_lambda, &::do_lambda) - %dispatch_form(&sym_define, &::do_define) - %dispatch_form(&sym_begin, &::do_begin) - %dispatch_form(&sym_cond, &::do_cond) - %dispatch_form(&sym_let, &::do_let) - %dispatch_form(&sym_letstar, &::do_letstar) - %dispatch_form(&sym_let_values, &::do_let_values) - %dispatch_form(&sym_letstar_values, &::do_letstar_values) - %dispatch_form(&sym_and, &::do_and) - %dispatch_form(&sym_or, &::do_or) - %dispatch_form(&sym_when, &::do_when) - %dispatch_form(&sym_case, &::do_case) - %dispatch_form(&sym_setbang, &::do_setbang) - %dispatch_form(&sym_define_record_type, &::do_define_record_type) - %dispatch_form(&sym_pmatch, &::do_pmatch) - %dispatch_form(&sym_do, &::do_do) + %dispatch_form(&sym_quote, &.do_quote) + %dispatch_form(&sym_if, &.do_if) + %dispatch_form(&sym_lambda, &.do_lambda) + %dispatch_form(&sym_define, &.do_define) + %dispatch_form(&sym_begin, &.do_begin) + %dispatch_form(&sym_cond, &.do_cond) + %dispatch_form(&sym_let, &.do_let) + %dispatch_form(&sym_letstar, &.do_letstar) + %dispatch_form(&sym_let_values, &.do_let_values) + %dispatch_form(&sym_letstar_values, &.do_letstar_values) + %dispatch_form(&sym_and, &.do_and) + %dispatch_form(&sym_or, &.do_or) + %dispatch_form(&sym_when, &.do_when) + %dispatch_form(&sym_case, &.do_case) + %dispatch_form(&sym_setbang, &.do_setbang) + %dispatch_form(&sym_define_record_type, &.do_define_record_type) + %dispatch_form(&sym_pmatch, &.do_pmatch) + %dispatch_form(&sym_do, &.do_do) # Apply car to cdr # fn = eval(car(expr), env) @@ -1080,41 +1071,41 @@ %ldl(a0, fn) %tail(&apply) - ::do_quote + :.do_quote %tail_to_handler(&eval_quote) - ::do_if + :.do_if %tail_to_handler(&eval_if) - ::do_lambda + :.do_lambda %tail_to_handler(&eval_lambda) - ::do_define + :.do_define %tail_to_handler(&eval_define) - ::do_begin + :.do_begin %tail_to_handler(&eval_body) - ::do_cond + :.do_cond %tail_to_handler(&eval_cond) - ::do_let + :.do_let %tail_to_handler(&eval_let) - ::do_letstar + :.do_letstar %tail_to_handler(&eval_letstar) - ::do_let_values + :.do_let_values %tail_to_handler(&eval_let_values) - ::do_letstar_values + :.do_letstar_values %tail_to_handler(&eval_letstar_values) - ::do_and + :.do_and %tail_to_handler(&eval_and) - ::do_or + :.do_or %tail_to_handler(&eval_or) - ::do_when + :.do_when %tail_to_handler(&eval_when) - ::do_case + :.do_case %tail_to_handler(&eval_case) - ::do_setbang + :.do_setbang %tail_to_handler(&eval_setbang) - ::do_define_record_type + :.do_define_record_type %tail_to_handler(&eval_define_record_type) - ::do_pmatch + :.do_pmatch %tail_to_handler(&eval_pmatch) - ::do_do + :.do_do %tail_to_handler(&eval_do) }) @@ -1136,9 +1127,9 @@ %stl(t0, head) %stl(t0, tail) - ::loop + :.loop %ldl(t0, args) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) # val = eval(car(args), env) %car(a0, t0) @@ -1150,20 +1141,20 @@ %call(&cons) %ldl(t0, head) - %if_nil(t1, t0, &::first) + %if_nil(t1, t0, &.first) %ldl(t0, tail) %set_cdr(a0, t0) %stl(a0, tail) - %b(&::advance) + %b(&.advance) - ::first + :.first %stl(a0, head) %stl(a0, tail) - ::advance + :.advance %advance_walk(args) - %b(&::loop) - ::done + %b(&.loop) + :.done %ldl(a0, head) }) @@ -1178,10 +1169,10 @@ %stl(a1, args) %hdr_type(t0, a0) - %bieq(t0, %HDR.PRIM, &::prim, t1) - %bieq(t0, %HDR.CLOSURE, &::closure, t1) + %bieq(t0, %HDR.PRIM, &.prim, t1) + %bieq(t0, %HDR.CLOSURE, &.closure, t1) - ::prim + :.prim # Primitive calling convention: # a0 = args list (proper list of evaluated args) # a1 = the PRIM object itself (HEAP-tagged) @@ -1197,7 +1188,7 @@ %ldl(a0, args) %tailr(t0) - ::closure + :.closure # Closure layout (HEAP-tagged): [hdr][params][body][env] %heap_ld(t0, a0, %CLOSURE.params) %heap_ld(t1, a0, %CLOSURE.body) @@ -1274,7 +1265,7 @@ %car(a0, a0) %call(&eval) - %bieq(a0, %imm_val(%IMM.FALSE), &::else_branch, t0) + %bieq(a0, %imm_val(%IMM.FALSE), &.else_branch, t0) # then-branch: tail-eval(cadr(rest), env) %ldl(a0, rest) @@ -1283,19 +1274,19 @@ %ldl(a1, env) %tail(&eval) - ::else_branch + :.else_branch # If cddr(rest) is NIL, this is single-arm `if` -> UNSPEC. %ldl(t0, rest) %cdr(t0, t0) %cdr(t0, t0) - %if_nil(t1, t0, &::no_else) + %if_nil(t1, t0, &.no_else) # else-branch: tail-eval(car(cddr(rest)), env) %car(a0, t0) %ldl(a1, env) %tail(&eval) - ::no_else + :.no_else %li(a0, %imm_val(%IMM.UNSPEC)) }) @@ -1353,7 +1344,7 @@ # If car(rest) is a pair, this is the lambda-sugar form. %car(t0, a0) %tagof(t1, t0) - %bieq(t1, %TAG.PAIR, &::sugar, t2) + %bieq(t1, %TAG.PAIR, &.sugar, t2) # Plain define: value = eval(car(cdr(rest)), env) %ldl(t0, rest) @@ -1368,7 +1359,7 @@ %li(a0, %imm_val(%IMM.UNSPEC)) %eret - ::sugar + :.sugar # rest = ((name . params) . body); build (params . body) for eval_lambda. %ldl(t0, rest) %car(t0, t0) @@ -1414,24 +1405,24 @@ %ldl(t1, rest) %car(t1, t1) ; target sym - ::loop + :.loop %ldl(t2, env) - %if_nil(t0, t2, &::miss) + %if_nil(t0, t2, &.miss) %car(t0, t2) %car(t0, t0) ; cell sym - %beq(t0, t1, &::hit) + %beq(t0, t1, &.hit) %cdr(t2, t2) %stl(t2, env) - %b(&::loop) + %b(&.loop) - ::hit + :.hit %car(t0, t2) ; re-fetch binding cell %ldl(a0, saved) %set_cdr(a0, t0) ; mutate cell's cdr %li(a0, %imm_val(%IMM.UNSPEC)) %eret - ::miss + :.miss # Miss: rebind global. %ldl(a0, saved) %ldl(t0, rest) @@ -1455,21 +1446,21 @@ %stl(a0, clauses) %stl(a1, env) - ::loop + :.loop %ldl(t0, clauses) - %if_nil(t1, t0, &::no_match) + %if_nil(t1, t0, &.no_match) %car(t1, t0) ; clause %car(t2, t1) ; test_expr %ld_global(a0, &sym_else) - %beq(t2, a0, &::else_clause) + %beq(t2, a0, &.else_clause) %mov(a0, t2) %ldl(a1, env) %call(&eval) %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::next) + %beq(a0, t0, &.next) # Truthy. Spill test value and inspect cdr(clause): empty -> UNSPEC, # car == => -> arrow path, else regular body. @@ -1477,16 +1468,16 @@ %ldl(t0, clauses) %car(t0, t0) %cdr(t0, t0) - %if_nil(t1, t0, &::no_match) + %if_nil(t1, t0, &.no_match) %car(t1, t0) %ld_global(t2, &sym_arrow) - %beq(t1, t2, &::arrow) + %beq(t1, t2, &.arrow) %mov(a0, t0) ; regular body %ldl(a1, env) %tail(&eval_body) - ::arrow + :.arrow %cdr(t0, t0) %car(a0, t0) ; proc-expr %ldl(a1, env) @@ -1499,18 +1490,18 @@ %ldl(a0, proc) %tail(&apply) - ::else_clause + :.else_clause %ldl(t0, clauses) %car(t0, t0) %cdr(a0, t0) %ldl(a1, env) %tail(&eval_body) - ::next + :.next %advance_walk(clauses) - %b(&::loop) + %b(&.loop) - ::no_match + :.no_match %li(a0, %imm_val(%IMM.UNSPEC)) }) @@ -1533,7 +1524,7 @@ # Named let? %car(t0, a0) %tagof(t1, t0) - %bieq(t1, %TAG.SYM, &::named, t2) + %bieq(t1, %TAG.SYM, &.named, t2) %ldl(t0, rest) %car(t0, t0) ; bindings @@ -1541,9 +1532,9 @@ %ldl(t0, env) %stl(t0, new_env) ; new_env = env - ::loop + :.loop %ldl(t0, walk) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) %car(t1, t0) ; pair = (name init) %cdr(t2, t1) @@ -1568,15 +1559,15 @@ %stl(a0, new_env) %advance_walk(walk) - %b(&::loop) + %b(&.loop) - ::done + :.done %ldl(a0, rest) %cdr(a0, a0) ; body %ldl(a1, new_env) %tail(&eval_body) - ::named + :.named %ldl(a0, rest) %ldl(a1, env) %tail(&eval_let_named) @@ -1601,9 +1592,9 @@ %ldl(t0, env) %stl(t0, new_env) - ::loop + :.loop %ldl(t0, walk) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) %car(t1, t0) %cdr(t2, t1) @@ -1626,8 +1617,8 @@ %stl(a0, new_env) %advance_walk(walk) - %b(&::loop) - ::done + %b(&.loop) + :.done %ldl(a0, rest) %cdr(a0, a0) @@ -1656,9 +1647,9 @@ %ldl(t0, env) %stl(t0, new_env) ; new_env = env - ::loop + :.loop %ldl(t0, walk) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) %car(t1, t0) ; clause = (formals init) %cdr(t2, t1) @@ -1683,8 +1674,8 @@ %stl(a0, new_env) %advance_walk(walk) - %b(&::loop) - ::done + %b(&.loop) + :.done %ldl(a0, rest) %cdr(a0, a0) ; body @@ -1711,9 +1702,9 @@ %ldl(t0, env) %stl(t0, new_env) - ::loop + :.loop %ldl(t0, walk) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) %car(t1, t0) %cdr(t2, t1) @@ -1736,8 +1727,8 @@ %stl(a0, new_env) %advance_walk(walk) - %b(&::loop) - ::done + %b(&.loop) + :.done %ldl(a0, rest) %cdr(a0, a0) @@ -1755,36 +1746,36 @@ # env %fn2(eval_and, {rest env}, { %li(t0, %imm_val(%IMM.TRUE)) - %if_nil(t1, a0, &::done_imm) + %if_nil(t1, a0, &.done_imm) - ::loop + :.loop %stl(a0, rest) %stl(a1, env) # If cdr(rest) is NIL, the head is the last form -> tail-eval. %cdr(t0, a0) - %if_nil(t1, t0, &::last) + %if_nil(t1, t0, &.last) # Non-last: eval, short-circuit on #f, otherwise advance. %car(a0, a0) %call(&eval) %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::done) + %beq(a0, t0, &.done) %ldl(a0, rest) %cdr(a0, a0) %ldl(a1, env) - %b(&::loop) + %b(&.loop) - ::last + :.last %ldl(a0, rest) %car(a0, a0) %ldl(a1, env) %tail(&eval) - ::done + :.done %eret - ::done_imm + :.done_imm %mov(a0, t0) }) @@ -1798,33 +1789,33 @@ # env %fn2(eval_or, {rest env}, { %li(t0, %imm_val(%IMM.FALSE)) - %if_nil(t1, a0, &::done_imm) + %if_nil(t1, a0, &.done_imm) - ::loop + :.loop %stl(a0, rest) %stl(a1, env) %cdr(t0, a0) - %if_nil(t1, t0, &::last) + %if_nil(t1, t0, &.last) %car(a0, a0) %call(&eval) - %bine(a0, %imm_val(%IMM.FALSE), &::done, t0) + %bine(a0, %imm_val(%IMM.FALSE), &.done, t0) %ldl(a0, rest) %cdr(a0, a0) %ldl(a1, env) - %b(&::loop) + %b(&.loop) - ::last + :.last %ldl(a0, rest) %car(a0, a0) %ldl(a1, env) %tail(&eval) - ::done + :.done %eret - ::done_imm + :.done_imm %mov(a0, t0) }) @@ -1843,14 +1834,14 @@ %car(a0, a0) ; test %call(&eval) - %bieq(a0, %imm_val(%IMM.FALSE), &::skip, t0) + %bieq(a0, %imm_val(%IMM.FALSE), &.skip, t0) %ldl(a0, rest) %cdr(a0, a0) ; body %ldl(a1, env) %tail(&eval_body) - ::skip + :.skip %li(a0, %imm_val(%IMM.UNSPEC)) }) @@ -1881,49 +1872,49 @@ %call(&eval) %stl(a0, subject) - ::loop + :.loop %ldl(t0, clauses) - %if_nil(t1, t0, &::no_match) + %if_nil(t1, t0, &.no_match) %car(t1, t0) ; clause %car(t2, t1) ; head: datum-list or `else` %ld_global(a3, &sym_else) - %beq(t2, a3, &::do_else) + %beq(t2, a3, &.do_else) # Walk the datum list, eq?-compare each against subject. %stl(t2, datums) %ldl(a0, subject) - ::scan + :.scan %ldl(t0, datums) - %if_nil(t1, t0, &::next_clause) + %if_nil(t1, t0, &.next_clause) %car(t1, t0) ; datum - %beq(t1, a0, &::do_body) + %beq(t1, a0, &.do_body) %cdr(t0, t0) %stl(t0, datums) - %b(&::scan) + %b(&.scan) - ::do_body + :.do_body %ldl(t0, clauses) %car(t0, t0) %cdr(a0, t0) ; body %ldl(a1, env) %tail(&eval_body) - ::do_else + :.do_else %ldl(t0, clauses) %car(t0, t0) %cdr(a0, t0) ; body %ldl(a1, env) %tail(&eval_body) - ::next_clause + :.next_clause %ldl(t0, clauses) %cdr(t0, t0) %stl(t0, clauses) - %b(&::loop) + %b(&.loop) - ::no_match + :.no_match %li(a0, %imm_val(%IMM.UNSPEC)) }) @@ -1958,22 +1949,22 @@ %call(&eval) %stl(a0, subject) - ::loop + :.loop %ldl(t0, clauses) - %if_nil(t1, t0, &::no_match) + %if_nil(t1, t0, &.no_match) %car(t1, t0) ; clause %car(t2, t1) ; pat %ld_global(a3, &sym_else) - %beq(t2, a3, &::do_else) + %beq(t2, a3, &.do_else) # pmatch_match(pat, subject, env_outer) -> (a0=env_ext, a1=ok) %mov(a0, t2) %ldl(a1, subject) %ldl(a2, env_outer) %call(&pmatch_match) - %beqz(a1, &::next) + %beqz(a1, &.next) %stl(a0, env_ext) ; env_ext @@ -1985,13 +1976,13 @@ # Guard form? tail is a pair, car(tail) is a pair, head of car(tail) # eq? sym_guard. %tagof(t1, t0) - %bine(t1, %TAG.PAIR, &::body_simple, t2) + %bine(t1, %TAG.PAIR, &.body_simple, t2) %car(t1, t0) ; first form of tail %tagof(t2, t1) - %bine(t2, %TAG.PAIR, &::body_simple, a0) + %bine(t2, %TAG.PAIR, &.body_simple, a0) %car(a0, t1) ; head of first form %ld_global(a1, &sym_guard) - %bne(a0, a1, &::body_simple) + %bne(a0, a1, &.body_simple) # Guard clause. guards = cdr(car(tail)); body = cdr(tail). %cdr(a0, t1) @@ -1999,26 +1990,26 @@ %cdr(t0, t0) %stl(t0, body) - ::g_loop + :.g_loop %ldl(t0, guard) - %if_nil(t1, t0, &::body_run) + %if_nil(t1, t0, &.body_run) %car(a0, t0) ; guard expr %ldl(a1, env_ext) ; env_ext %call(&eval) - %bieq(a0, %imm_val(%IMM.FALSE), &::next, t0) + %bieq(a0, %imm_val(%IMM.FALSE), &.next, t0) %ldl(t0, guard) %cdr(t0, t0) %stl(t0, guard) - %b(&::g_loop) + %b(&.g_loop) - ::body_run + :.body_run %ldl(a0, body) %ldl(a1, env_ext) %tail(&eval_body) - ::body_simple + :.body_simple # tail itself is the body (no guard wrapper). Tail-call eval_body # with the extended env; tail position of the matched clause's body # is preserved. @@ -2026,20 +2017,20 @@ %ldl(a1, env_ext) %tail(&eval_body) - ::do_else + :.do_else %ldl(t0, clauses) %car(t0, t0) %cdr(a0, t0) ; body %ldl(a1, env_outer) ; env_outer (no bindings introduced) %tail(&eval_body) - ::next + :.next %ldl(t0, clauses) %cdr(t0, t0) %stl(t0, clauses) - %b(&::loop) + %b(&.loop) - ::no_match + :.no_match %die(msg_pmatch_no_match) }) @@ -2088,9 +2079,9 @@ %stl(t0, vals_head) %stl(t0, vals_tail) - ::init_loop + :.init_loop %ldl(t0, walk) - %if_nil(t1, t0, &::init_done) + %if_nil(t1, t0, &.init_done) # spec = car(walk); init-expr = car(cdr(spec)). %car(t1, t0) @@ -2122,37 +2113,37 @@ %call(&cons) %ldl(t0, pairs_head) - %if_nil(t1, t0, &::pairs_first) + %if_nil(t1, t0, &.pairs_first) %ldl(t0, pairs_tail) %set_cdr(a0, t0) %stl(a0, pairs_tail) - %b(&::vals_alloc) + %b(&.vals_alloc) - ::pairs_first + :.pairs_first %stl(a0, pairs_head) %stl(a0, pairs_tail) - ::vals_alloc + :.vals_alloc # vcell = cons(NIL, NIL). Append onto vals list. %li(a0, %imm_val(%IMM.NIL)) %li(a1, %imm_val(%IMM.NIL)) %call(&cons) %ldl(t0, vals_head) - %if_nil(t1, t0, &::vals_first) + %if_nil(t1, t0, &.vals_first) %ldl(t0, vals_tail) %set_cdr(a0, t0) %stl(a0, vals_tail) - %b(&::init_advance) + %b(&.init_advance) - ::vals_first + :.vals_first %stl(a0, vals_head) %stl(a0, vals_tail) - ::init_advance + :.init_advance %advance_walk(walk) - %b(&::init_loop) - ::init_done + %b(&.init_loop) + :.init_done # body = cddr(rest). %ldl(t0, rest) @@ -2160,7 +2151,7 @@ %cdr(t0, t0) %stl(t0, body) - ::iter_loop + :.iter_loop # test = car(car(cdr(rest))). Eval in new_env. %ldl(t0, rest) %cdr(t0, t0) @@ -2169,36 +2160,36 @@ %ldl(a1, new_env) %call(&eval) - %bieq(a0, %imm_val(%IMM.FALSE), &::commands, t0) + %bieq(a0, %imm_val(%IMM.FALSE), &.commands, t0) # Truthy: results = cdr(car(cdr(rest))). %ldl(t0, rest) %cdr(t0, t0) %car(t0, t0) %cdr(t0, t0) ; results - %if_nil(t1, t0, &::no_results) + %if_nil(t1, t0, &.no_results) %mov(a0, t0) %ldl(a1, new_env) %tail(&eval_body) - ::no_results + :.no_results %li(a0, %imm_val(%IMM.UNSPEC)) %eret - ::commands + :.commands %ldl(t0, body) %stl(t0, walk) - ::cmd_loop + :.cmd_loop %ldl(t0, walk) - %if_nil(t1, t0, &::step_phase) + %if_nil(t1, t0, &.step_phase) %car(a0, t0) %ldl(a1, new_env) %call(&eval) %advance_walk(walk) - %b(&::cmd_loop) + %b(&.cmd_loop) - ::step_phase + :.step_phase # Compute new step values. walk = specs, pair_walk = pairs_head, # val_walk = vals_head. For each spec: if spec has step (cddr non-NIL), # val = eval(step, new_env); else val = cdr(binding_pair) (current). @@ -2211,51 +2202,51 @@ %ldl(t0, vals_head) %stl(t0, val_walk) - ::step_loop + :.step_loop %ldl(t0, walk) - %if_nil(t1, t0, &::update_phase) + %if_nil(t1, t0, &.update_phase) %car(t1, t0) ; spec %cdr(t2, t1) %cdr(t2, t2) ; (step?) or NIL - %if_nil(t1, t2, &::no_step) + %if_nil(t1, t2, &.no_step) %car(a0, t2) ; step %ldl(a1, new_env) %call(&eval) - %b(&::store_val) + %b(&.store_val) - ::no_step + :.no_step %ldl(t0, pair_walk) %car(t0, t0) ; binding pair %cdr(a0, t0) ; current val - ::store_val + :.store_val %ldl(t0, val_walk) %set_car(a0, t0) %advance_walk(walk) %advance_walk(pair_walk) %advance_walk(val_walk) - %b(&::step_loop) + %b(&.step_loop) - ::update_phase + :.update_phase # Walk pairs_head and vals_head; set-cdr!(pair, val) for each. %ldl(t0, pairs_head) %stl(t0, pair_walk) %ldl(t0, vals_head) %stl(t0, val_walk) - ::update_loop + :.update_loop %ldl(t0, pair_walk) - %if_nil(t1, t0, &::iter_loop) + %if_nil(t1, t0, &.iter_loop) %car(t1, t0) ; binding pair %ldl(t0, val_walk) %car(t2, t0) ; new val %set_cdr(t2, t1) %advance_walk(pair_walk) %advance_walk(val_walk) - %b(&::update_loop) + %b(&.update_loop) }) # pmatch_match(pat=a0, subj=a1, env=a2) -> (env=a0, ok=a1) @@ -2296,34 +2287,34 @@ %tagof(t0, a0) %li(t1, %TAG.PAIR) - %beq(t0, t1, &::pair_pat) + %beq(t0, t1, &.pair_pat) # Atomic pattern. Identity covers fixnum / symbol / immediate / same # heap pointer. - %beq(a0, a1, &::ok) + %beq(a0, a1, &.ok) # HDR.BV equality. - %bine(t0, %TAG.HEAP, &::no, t1) + %bine(t0, %TAG.HEAP, &.no, t1) %hdr_type(t1, a0) - %bine(t1, %HDR.BV, &::no, t2) + %bine(t1, %HDR.BV, &.no, t2) %tagof(t1, a1) - %bine(t1, %TAG.HEAP, &::no, t2) + %bine(t1, %TAG.HEAP, &.no, t2) %hdr_type(t1, a1) - %bine(t1, %HDR.BV, &::no, t2) + %bine(t1, %HDR.BV, &.no, t2) %call(&bv_equal_check) - %bieq(a0, %imm_val(%IMM.TRUE), &::ok, t0) - %b(&::no) + %bieq(a0, %imm_val(%IMM.TRUE), &.ok, t0) + %b(&.no) - ::pair_pat + :.pair_pat %car(t0, a0) ; phead %ld_global(t1, &sym_unquote) - %beq(t0, t1, &::binder) + %beq(t0, t1, &.binder) %ld_global(t1, &sym_dollar) - %beq(t0, t1, &::record_pat) + %beq(t0, t1, &.record_pat) # Structural pair. subj must be a pair too. %tagof(t0, a1) - %bine(t0, %TAG.PAIR, &::no, t1) + %bine(t0, %TAG.PAIR, &.no, t1) # Recurse on the cars; on success, recurse on the cdrs as a tail call. %ldl(t0, pat) @@ -2332,7 +2323,7 @@ %car(a1, t0) %ldl(a2, env) %call(&pmatch_match) - %beqz(a1, &::no) + %beqz(a1, &.no) %mov(a2, a0) ; env_after_car %ldl(t0, pat) @@ -2341,22 +2332,22 @@ %cdr(a1, t0) %tail(&pmatch_match) - ::binder + :.binder # Validate (unquote <sym>): cdr(pat) is a pair, cdr(cdr(pat)) is NIL, # car(cdr(pat)) is a symbol. %ldl(t0, pat) %cdr(t1, t0) ; cdr(pat) %tagof(t0, t1) - %bine(t0, %TAG.PAIR, &::bad, t2) + %bine(t0, %TAG.PAIR, &.bad, t2) %cdr(t0, t1) ; cdr(cdr(pat)) - %bine(t0, %imm_val(%IMM.NIL), &::bad, t2) + %bine(t0, %imm_val(%IMM.NIL), &.bad, t2) %car(t0, t1) ; pident (kept in t0) %tagof(t2, t0) - %bine(t2, %TAG.SYM, &::bad, a3) + %bine(t2, %TAG.SYM, &.bad, a3) # Wildcard? Compare against sym_underscore; if so, no binding. %ld_global(t1, &sym_underscore) - %beq(t0, t1, &::ok) + %beq(t0, t1, &.ok) # Bind: env' = cons(cons(pident, subj), env). pident lives in t0; # cons clobbers t0..t2, so move it into a0 right away. @@ -2368,7 +2359,7 @@ %li(a1, 1) %eret - ::record_pat + :.record_pat # pat = ($ pred-sym (f1 p1) (f2 p2) ...). Resolve pred-sym -> PRIM via # eval, pull TD from PRIM.data, type-check subj, then iterate the # (fname pat_i) clauses. Clobbers `pat` local once we begin the loop: @@ -2377,10 +2368,10 @@ %ldl(t0, pat) %cdr(t1, t0) ; (pred-sym . clauses) %tagof(t0, t1) - %bine(t0, %TAG.PAIR, &::no, t2) + %bine(t0, %TAG.PAIR, &.no, t2) %car(t0, t1) ; t0 = pred-sym %tagof(t2, t0) - %bine(t2, %TAG.SYM, &::no, a3) + %bine(t2, %TAG.SYM, &.no, a3) %cdr(t2, t1) ; t2 = clauses %stl(t2, flw) @@ -2392,44 +2383,44 @@ # Verify HEAP / HDR.PRIM, entry == &prim_predicate_entry; extract TD # from PRIM.data; sanity-check TD is HEAP / HDR.TD. %tagof(t0, a0) - %bine(t0, %TAG.HEAP, &::no, t1) + %bine(t0, %TAG.HEAP, &.no, t1) %hdr_type(t0, a0) - %bine(t0, %HDR.PRIM, &::no, t1) + %bine(t0, %HDR.PRIM, &.no, t1) %heap_ld(t1, a0, %PRIM.entry_w) %la(t2, &prim_predicate_entry) - %bne(t1, t2, &::no) + %bne(t1, t2, &.no) %heap_ld(t1, a0, %PRIM.data) ; t1 = TD %tagof(t0, t1) %li(t2, %TAG.HEAP) - %bne(t0, t2, &::no) + %bne(t0, t2, &.no) %hdr_type(t0, t1) %li(t2, %HDR.TD) - %bne(t0, t2, &::no) + %bne(t0, t2, &.no) %stl(t1, td) # Verify subj is HDR.REC with REC.td == TD. %ldl(a0, subj) %tagof(t0, a0) %li(t1, %TAG.HEAP) - %bne(t0, t1, &::no) + %bne(t0, t1, &.no) %hdr_type(t0, a0) %li(t1, %HDR.REC) - %bne(t0, t1, &::no) + %bne(t0, t1, &.no) %heap_ld(t0, a0, %REC.td) %ldl(t1, td) - %bne(t0, t1, &::no) + %bne(t0, t1, &.no) - ::record_field_loop + :.record_field_loop # flw points at remaining (fname pat_i) clauses; NIL ends the loop. %ldl(t0, flw) - %if_nil(t1, t0, &::ok) + %if_nil(t1, t0, &.ok) %car(t1, t0) ; t1 = clause %tagof(t0, t1) - %bine(t0, %TAG.PAIR, &::no, t2) + %bine(t0, %TAG.PAIR, &.no, t2) %car(t2, t1) ; t2 = fname %cdr(t1, t1) ; t1 = (pat_i) %tagof(t0, t1) - %bine(t0, %TAG.PAIR, &::no, a3) + %bine(t0, %TAG.PAIR, &.no, a3) %car(a3, t1) ; a3 = pat_i %stl(a3, pat) ; reuse `pat` local for pat_i across recursion @@ -2439,15 +2430,15 @@ %ldl(t0, td) %heap_ld(t0, t0, %TD.fields) %li(t1, 0) - ::record_field_idx_loop - %if_nil(a3, t0, &::no) + :.record_field_idx_loop + %if_nil(a3, t0, &.no) %car(a3, t0) - %beq(a3, t2, &::record_field_found) + %beq(a3, t2, &.record_field_found) %cdr(t0, t0) %addi(t1, t1, 1) - %b(&::record_field_idx_loop) + %b(&.record_field_idx_loop) - ::record_field_found + :.record_field_found # val = ld(subj_tagged + (idx<<3) + 13). Same offset arithmetic as # prim_accessor_entry. Compute the address into a1 directly so the # recursive call's val arg is in place. @@ -2460,24 +2451,24 @@ %ldl(a0, pat) %ldl(a2, env) %call(&pmatch_match) - %beqz(a1, &::no) + %beqz(a1, &.no) %stl(a0, env) %ldl(t0, flw) %cdr(t0, t0) %stl(t0, flw) - %b(&::record_field_loop) + %b(&.record_field_loop) - ::ok + :.ok %ldl(a0, env) %li(a1, 1) %eret - ::no + :.no %li(a1, 0) %eret - ::bad + :.bad %die(msg_bad_unquote_pattern) }) @@ -2520,9 +2511,9 @@ %car(t0, t0) ; bindings %stl(t0, walk) - ::p1_loop + :.p1_loop %ldl(t0, walk) - %if_nil(t1, t0, &::p1_done) + %if_nil(t1, t0, &.p1_done) %car(t1, t0) %car(t2, t1) ; name @@ -2531,21 +2522,21 @@ %call(&cons) ; cell = (name . NIL) %ldl(t0, head) - %if_nil(t1, t0, &::p1_first) + %if_nil(t1, t0, &.p1_first) %ldl(t0, tail) %set_cdr(a0, t0) %stl(a0, tail) - %b(&::p1_advance) + %b(&.p1_advance) - ::p1_first + :.p1_first %stl(a0, head) %stl(a0, tail) - ::p1_advance + :.p1_advance %advance_walk(walk) - %b(&::p1_loop) + %b(&.p1_loop) - ::p1_done + :.p1_done %ldl(t0, head) %stl(t0, params) ; save params @@ -2558,9 +2549,9 @@ %car(t0, t0) %stl(t0, walk) - ::p2_loop + :.p2_loop %ldl(t0, walk) - %if_nil(t1, t0, &::p2_done) + %if_nil(t1, t0, &.p2_done) %car(t1, t0) %cdr(t2, t1) @@ -2573,21 +2564,21 @@ %call(&cons) ; cell = (val . NIL) %ldl(t0, head) - %if_nil(t1, t0, &::p2_first) + %if_nil(t1, t0, &.p2_first) %ldl(t0, tail) %set_cdr(a0, t0) %stl(a0, tail) - %b(&::p2_advance) + %b(&.p2_advance) - ::p2_first + :.p2_first %stl(a0, head) %stl(a0, tail) - ::p2_advance + :.p2_advance %advance_walk(walk) - %b(&::p2_loop) + %b(&.p2_loop) - ::p2_done + :.p2_done # 4. Closure: eval_lambda((params . body), self_env). %ldl(a0, params) ; params %ldl(t0, rest) @@ -2620,16 +2611,16 @@ %stl(a1, args) %stl(a2, env) - ::loop + :.loop %ldl(t0, params) %tagof(t1, t0) %li(t2, %TAG.PAIR) - %beq(t1, t2, &::pair) + %beq(t1, t2, &.pair) %li(t2, %TAG.SYM) - %beq(t1, t2, &::rest_bind) - %b(&::done) + %beq(t1, t2, &.rest_bind) + %b(&.done) - ::pair + :.pair # binding = cons(car(params), car(args)) %ldl(t0, params) %car(a0, t0) @@ -2645,9 +2636,9 @@ # advance params and args %advance_walk(params) %advance_walk(args) - %b(&::loop) + %b(&.loop) - ::rest_bind + :.rest_bind # binding = cons(params_sym, args_list); env = cons(binding, env) %ldl(a0, params) %ldl(a1, args) @@ -2656,7 +2647,7 @@ %call(&cons) %stl(a0, env) - ::done + :.done %ldl(a0, env) }) @@ -2673,7 +2664,7 @@ # body # env %fn2(eval_body, {body env}, { - ::loop + :.loop %stl(a0, body) %stl(a1, env) @@ -2682,16 +2673,16 @@ %car(t0, a0) ; form %tagof(t1, t0) %li(t2, %TAG.PAIR) - %bne(t1, t2, &::not_define) + %bne(t1, t2, &.not_define) %car(t1, t0) ; head sym %ld_global(t2, &sym_define) - %beq(t1, t2, &::internal_define) + %beq(t1, t2, &.internal_define) - ::not_define + :.not_define # If cdr(body) is NIL, body's car is the last form. %ldl(a0, body) %cdr(t0, a0) - %if_nil(t1, t0, &::last) + %if_nil(t1, t0, &.last) # Non-last form: eval and discard, advance. %car(a0, a0) @@ -2700,15 +2691,15 @@ %ldl(a0, body) %cdr(a0, a0) %ldl(a1, env) - %b(&::loop) + %b(&.loop) - ::last + :.last %ldl(a0, body) %car(a0, a0) %ldl(a1, env) %tail(&eval) - ::internal_define + :.internal_define %die(msg_internal_define) }) @@ -2732,23 +2723,23 @@ %ld_global(a1, &readbuf_buf_ptr) %li(a2, %READBUF_CAP_BYTES) %call(&read_file) - %bltz(a0, &::fail) + %bltz(a0, &.fail) # If the read filled (or would have filled) the buffer, the source # is at least cap bytes; refuse rather than silently truncate. # read_file does a single sys_read so n == cap is the only saturation # signal we have. We treat n >= cap as overflow defensively. %li(t0, %READBUF_CAP_BYTES) - %bltu(a0, t0, &::ok) + %bltu(a0, t0, &.ok) %die(msg_readbuf_full) - ::ok + :.ok %st_global(a0, &readbuf_len, t0) %li(a0, 0) %st_global(a0, &readbuf_pos, t0) %eret - ::fail + :.fail %die(msg_load_fail) }) @@ -2768,92 +2759,92 @@ # cons(car=a0, cdr=a1) -> tagged pair (a0). Allocates 16 bytes. :cons -%scope cons +.scope %ld_global(t2, &current_heap_next_ptr) %ld(t0, t2, 0) %addi(t1, t0, %PAIR.SIZE) %ld_global(a3, &current_heap_end_ptr) %ld(a3, a3, 0) - %bltu(a3, t1, &::oom) + %bltu(a3, t1, &.oom) %st(a0, t0, %PAIR.car) %st(a1, t0, %PAIR.cdr) %st(t1, t2, 0) %addi(a0, t0, %TAG.PAIR) %ret - ::oom + :.oom %b(&heap_oom_die) -%endscope +.endscope # cons_main(car=a0, cdr=a1) -> tagged pair (a0). Allocates in main # regardless of current heap selection. Used for process-global # interpreter metadata that is represented as Scheme pairs. :cons_main -%scope cons_main +.scope %la(t2, &heap_next) %ld(t0, t2, 0) %addi(t1, t0, %PAIR.SIZE) %ld_global(a3, &heap_end) - %bltu(a3, t1, &::oom) + %bltu(a3, t1, &.oom) %st(a0, t0, %PAIR.car) %st(a1, t0, %PAIR.cdr) %st(t1, t2, 0) %addi(a0, t0, %TAG.PAIR) %ret - ::oom + :.oom %die(msg_heap_full) -%endscope +.endscope # alloc_hdr(bytes=a0, hdr_word=a1) -> tagged heap obj (a0) # Rounds bytes up to a multiple of 8 and writes hdr_word at offset 0. :alloc_hdr -%scope alloc_hdr +.scope %alignup(a0, a0, 8, t0) %ld_global(t2, &current_heap_next_ptr) %ld(t0, t2, 0) %add(t1, t0, a0) %ld_global(a3, &current_heap_end_ptr) %ld(a3, a3, 0) - %bltu(a3, t1, &::oom) + %bltu(a3, t1, &.oom) %st(t1, t2, 0) %st(a1, t0, 0) %addi(a0, t0, 3) %ret - ::oom + :.oom %b(&heap_oom_die) -%endscope +.endscope # alloc_hdr_main(bytes=a0, hdr_word=a1) -> tagged heap obj (a0), allocated # in main regardless of current heap selection. :alloc_hdr_main -%scope alloc_hdr_main +.scope %alignup(a0, a0, 8, t0) %la(t2, &heap_next) %ld(t0, t2, 0) %add(t1, t0, a0) %ld_global(a3, &heap_end) - %bltu(a3, t1, &::oom) + %bltu(a3, t1, &.oom) %st(t1, t2, 0) %st(a1, t0, 0) %addi(a0, t0, 3) %ret - ::oom + :.oom %die(msg_heap_full) -%endscope +.endscope # list_length(list=a0) -> count (a0). Linear walk; clobbers a0 (used as # the cursor). Callers that need the list afterward must save it first. :list_length -%scope list_length +.scope %li(t0, 0) - ::loop - %if_nil(t1, a0, &::done) + :.loop + %if_nil(t1, a0, &.done) %addi(t0, t0, 1) %cdr(a0, a0) - %b(&::loop) - ::done + %b(&.loop) + :.done %mov(a0, t0) %ret -%endscope +.endscope # ========================================================================= # Multiple-values protocol @@ -2894,15 +2885,15 @@ %ldl(t0, list) %addi(t1, a0, 5) - ::loop - %if_nil(t2, t0, &::done) + :.loop + %if_nil(t2, t0, &.done) %car(t2, t0) %st(t2, t1, 0) %addi(t1, t1, 8) %cdr(t0, t0) - %b(&::loop) + %b(&.loop) - ::done + :.done %ldl(a0, mv) }) @@ -2916,9 +2907,9 @@ # count (remaining slot count) %fn2(mv_to_list, {ptr count}, { %tagof(t0, a0) - %bine(t0, %TAG.HEAP, &::single, t1) + %bine(t0, %TAG.HEAP, &.single, t1) %hdr_type(t0, a0) - %bine(t0, %HDR.MV, &::single, t1) + %bine(t0, %HDR.MV, &.single, t1) # MV-pack: count = (hdr >> 8); header sits at raw+0 = tagged-3. %ld(t0, a0, -3) @@ -2935,9 +2926,9 @@ %li(a0, %imm_val(%IMM.NIL)) - ::loop + :.loop %ldl(t0, count) - %beqz(t0, &::done) + %beqz(t0, &.done) %ldl(t1, ptr) %ld(t2, t1, 0) @@ -2951,12 +2942,12 @@ %ldl(t0, count) %addi(t0, t0, -1) %stl(t0, count) - %b(&::loop) + %b(&.loop) - ::done + :.done %eret - ::single + :.single # Non-MV: return (val . NIL). %li(a1, %imm_val(%IMM.NIL)) %tail(&cons) @@ -2978,43 +2969,43 @@ %li(t0, 0) %stl(t0, idx) - ::scan + :.scan # idx >= count? -> append %ldl(t0, idx) %ld_global(t1, &symtab_count) - %bltu(t0, t1, &::probe) - %b(&::append) + %bltu(t0, t1, &.probe) + %b(&.append) - ::probe + :.probe %symtab_entry(t1, t0, t2) %stl(t1, entry_ptr) # entry.name_len == name_len ? %ld(t2, t1, %SYMENT.name_len) %ldl(a2, name_len) - %bne(t2, a2, &::next) + %bne(t2, a2, &.next) # memcmp(entry.name_ptr, name_ptr, len) %ld(a0, t1, %SYMENT.name_ptr) %ldl(a1, name_ptr) %ldl(a2, name_len) %call(&memcmp) - %beqz(a0, &::found) + %beqz(a0, &.found) - ::next + :.next %ldl(t0, idx) %addi(t0, t0, 1) %stl(t0, idx) - %b(&::scan) + %b(&.scan) - ::append + :.append # Bounds check; on overflow exit 5 with a message. %ldl(t0, idx) %li(t1, %SYMTAB_CAP_SLOTS) - %bltu(t0, t1, &::append_ok) + %bltu(t0, t1, &.append_ok) %die(msg_symtab_full) - ::append_ok + :.append_ok # Copy the name into a stable main-heap buffer. The caller-provided # ptr may live in readbuf_buf (parse_atom), and the current heap may # be scratch while user code is being read/evaluated. Symtab names @@ -3041,7 +3032,7 @@ # fall through with idx in t0 = sp[16] - ::found + :.found %ldl(t0, idx) %shli(a0, t0, 3) %ori(a0, a0, %TAG.SYM) @@ -3087,10 +3078,10 @@ %la(t0, &prim_table_end) %stl(t0, end) - ::loop + :.loop %ldl(t0, walk) %ldl(t1, end) - %beq(t0, t1, &::done) + %beq(t0, t1, &.done) # alloc_hdr(24, HDR.PRIM) -> HEAP-tagged a0. The third slot (offset 13 # from tagged) holds per-instance data and stays zero for the @@ -3119,9 +3110,9 @@ %ldl(t0, walk) %addi(t0, t0, 24) %stl(t0, walk) - %b(&::loop) + %b(&.loop) - ::done + :.done }) %fn(register_globals, 0, { @@ -3175,44 +3166,44 @@ # of the two boolean immediates. :prim_nullq_entry -%scope prim_nullq +.scope %car(t0, a0) %li(a0, %imm_val(%IMM.TRUE)) - %if_nil(t1, t0, &::end) + %if_nil(t1, t0, &.end) %li(a0, %imm_val(%IMM.FALSE)) - ::end + :.end %ret -%endscope +.endscope :prim_pairq_entry -%scope prim_pairq +.scope %car(t0, a0) %tagof(t1, t0) %li(t2, %TAG.PAIR) %li(a0, %imm_val(%IMM.FALSE)) - %bne(t1, t2, &::end) + %bne(t1, t2, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope # (string? x) -- #t iff x is a HEAP-tagged HDR.BV. Bytevectors back the # string type until characters get a distinct repr; this prim is also # the bytevector? predicate. :prim_stringq_entry -%scope prim_stringq +.scope %car(t0, a0) %li(a0, %imm_val(%IMM.FALSE)) %tagof(t1, t0) %li(t2, %TAG.HEAP) - %bne(t1, t2, &::end) + %bne(t1, t2, &.end) %hdr_type(t1, t0) %li(t2, %HDR.BV) - %bne(t1, t2, &::end) + %bne(t1, t2, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope # (set-car! pair val) / (set-cdr! pair val) -- in-place pair mutation. # No type check (matches car/cdr's lax stance); both return UNSPEC. @@ -3243,18 +3234,18 @@ # advance via cdr, then car. Out-of-range is undefined behavior, same # as car/cdr on '(). :prim_list_ref_entry -%scope prim_list_ref +.scope %args2(t0, t1, a0) %sari(t1, t1, 3) - ::loop - %beqz(t1, &::done) + :.loop + %beqz(t1, &.done) %cdr(t0, t0) %addi(t1, t1, -1) - %b(&::loop) - ::done + %b(&.loop) + :.done %car(a0, t0) %ret -%endscope +.endscope # (assq key alist) -> matching pair or #f. Walks alist, comparing # car of each pair to key by identity (eq?); first match wins. Pure @@ -3262,22 +3253,22 @@ # define so file-scope alist lookups (e.g. cc.scm scope-bind!'s # redecl check) don't pay bind_params env-cons cost per step. :prim_assq_entry -%scope prim_assq +.scope %args2(t0, t1, a0) ; t0=key, t1=alist - ::loop - %if_nil(t2, t1, &::miss) + :.loop + %if_nil(t2, t1, &.miss) %car(t2, t1) ; pair = (car alist) %car(a0, t2) ; (car pair) - %beq(a0, t0, &::hit) + %beq(a0, t0, &.hit) %cdr(t1, t1) - %b(&::loop) - ::hit + %b(&.loop) + :.hit %mov(a0, t2) %ret - ::miss + :.miss %li(a0, %imm_val(%IMM.FALSE)) %ret -%endscope +.endscope # (assoc key alist) -> matching pair or #f. Same shape as assq but # the key compare goes through equal_recurse, which means we need a @@ -3292,25 +3283,25 @@ %stl(t0, key) %stl(t1, cursor) - ::loop + :.loop %ldl(t1, cursor) - %if_nil(t2, t1, &::miss) + %if_nil(t2, t1, &.miss) %car(t2, t1) ; pair = (car cursor) %stl(t2, pair) %car(a0, t2) ; (car pair) %ldl(a1, key) %call(&equal_recurse) - %bieq(a0, %imm_val(%IMM.FALSE), &::next, t0) + %bieq(a0, %imm_val(%IMM.FALSE), &.next, t0) %ldl(a0, pair) %eret - ::next + :.next %ldl(t1, cursor) %cdr(t1, t1) %stl(t1, cursor) - %b(&::loop) + %b(&.loop) - ::miss + :.miss %li(a0, %imm_val(%IMM.FALSE)) }) @@ -3328,9 +3319,9 @@ %li(t0, %imm_val(%IMM.NIL)) %stl(t0, acc) - ::loop + :.loop %ldl(t0, xs) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) %car(a0, t0) %ldl(a1, acc) %call(&cons) @@ -3338,9 +3329,9 @@ %ldl(t0, xs) %cdr(t0, t0) %stl(t0, xs) - %b(&::loop) + %b(&.loop) - ::done + :.done %ldl(a0, acc) }) @@ -3362,15 +3353,15 @@ %li(t0, 0) %mov(t1, a0) - ::sum_loop - %if_nil(t2, t1, &::sum_done) + :.sum_loop + %if_nil(t2, t1, &.sum_done) %car(t2, t1) %heap_ld(a0, t2, %BV.hdr) %shri(a0, a0, 8) %add(t0, t0, a0) %cdr(t1, t1) - %b(&::sum_loop) - ::sum_done + %b(&.sum_loop) + :.sum_done %stl(t0, total) %mov(a0, t0) @@ -3380,9 +3371,9 @@ %li(t0, 0) %stl(t0, write) - ::copy_loop + :.copy_loop %ldl(t0, args) - %if_nil(t1, t0, &::copy_done) + %if_nil(t1, t0, &.copy_done) %car(t1, t0) ; src bv %heap_ld(t2, t1, %BV.hdr) %shri(t2, t2, 8) ; src length @@ -3400,8 +3391,8 @@ %stl(t0, args) %call(&memcpy) - %b(&::copy_loop) - ::copy_done + %b(&.copy_loop) + :.copy_done %ldl(a0, result) }) @@ -3452,19 +3443,19 @@ %li(t0, 10) %stl(t0, radix) %cdr(t1, a0) - %if_nil(t0, t1, &::have_radix) + %if_nil(t0, t1, &.have_radix) %car(t0, t1) %sari(t0, t0, 3) %stl(t0, radix) - ::have_radix + :.have_radix %li(a0, 0) %call(&str_alloc) %ldl(a1, value) %ldl(t0, radix) - %bieq(t0, 16, &::hex, t1) + %bieq(t0, 16, &.hex, t1) %tail(&str_putint) - ::hex + :.hex %tail(&str_puthex) }) @@ -3479,9 +3470,9 @@ %car(t2, a0) %tagof(t0, t2) - %bine(t0, %TAG.HEAP, &::fail, t1) + %bine(t0, %TAG.HEAP, &.fail, t1) %hdr_type(t0, t2) - %bine(t0, %HDR.BV, &::fail, t1) + %bine(t0, %HDR.BV, &.fail, t1) %heap_ld(t0, t2, %BV.data) %heap_ld(t1, t2, %BV.hdr) @@ -3492,278 +3483,278 @@ # Inspect the optional radix arg. %ldl(t0, args) %cdr(t0, t0) - %if_nil(t1, t0, &::dec) + %if_nil(t1, t0, &.dec) %car(t1, t0) %sari(t1, t1, 3) - %bieq(t1, 16, &::hex, t2) + %bieq(t1, 16, &.hex, t2) - ::dec + :.dec %ldl(a0, ptr) %ldl(a1, len) - %beqz(a1, &::fail) + %beqz(a1, &.fail) %lb(t0, a0, 0) - %bcne(t0, -43, &::dec_no_plus, t0) ; '+' + %bcne(t0, -43, &.dec_no_plus, t0) ; '+' %addi(a0, a0, 1) %addi(a1, a1, -1) - %beqz(a1, &::fail) - ::dec_no_plus + %beqz(a1, &.fail) + :.dec_no_plus %stl(a1, len) ; save adjusted len %call(&parse_dec) ; P1pp: -> (raw_val=a0, consumed=a1) %ldl(t0, len) - %bne(a1, t0, &::fail) ; partial parse -> fail + %bne(a1, t0, &.fail) ; partial parse -> fail %mkfix(a0, a0) - %b(&::end) + %b(&.end) - ::hex + :.hex # Strip optional leading '+' / '-'. %li(t0, 0) %stl(t0, sign) %ldl(t0, len) - %beqz(t0, &::fail) + %beqz(t0, &.fail) %ldl(t1, ptr) %lb(t2, t1, 0) %addi(t0, t2, -45) ; '-' - %beqz(t0, &::hex_neg) + %beqz(t0, &.hex_neg) %addi(t0, t2, -43) ; '+' - %beqz(t0, &::hex_skip_sign) - %b(&::hex_parse) - ::hex_neg + %beqz(t0, &.hex_skip_sign) + %b(&.hex_parse) + :.hex_neg %li(t0, 1) %stl(t0, sign) - ::hex_skip_sign + :.hex_skip_sign %ldl(t0, ptr) %addi(t0, t0, 1) %stl(t0, ptr) %ldl(t0, len) %addi(t0, t0, -1) %stl(t0, len) - %beqz(t0, &::fail) + %beqz(t0, &.fail) - ::hex_parse + :.hex_parse %ldl(a0, ptr) %ldl(a1, len) %call(&parse_hex) ; -> (a0=value, a1=consumed) %ldl(t0, len) - %bne(a1, t0, &::fail) ; demand full consumption + %bne(a1, t0, &.fail) ; demand full consumption %ldl(t0, sign) - %beqz(t0, &::hex_pos) + %beqz(t0, &.hex_pos) %li(t1, 0) %sub(a0, t1, a0) - ::hex_pos + :.hex_pos %mkfix(a0, a0) - %b(&::end) + %b(&.end) - ::fail + :.fail %li(a0, %imm_val(%IMM.FALSE)) - ::end + :.end }) # (boolean? x) -- #t iff x is the IMM.FALSE or IMM.TRUE singleton. :prim_booleanq_entry -%scope prim_booleanq +.scope %car(t0, a0) %li(a0, %imm_val(%IMM.TRUE)) %li(t1, %imm_val(%IMM.FALSE)) - %beq(t0, t1, &::end) + %beq(t0, t1, &.end) %li(t1, %imm_val(%IMM.TRUE)) - %beq(t0, t1, &::end) + %beq(t0, t1, &.end) %li(a0, %imm_val(%IMM.FALSE)) - ::end + :.end %ret -%endscope +.endscope # (integer? x) -- #t iff x is a fixnum (low 3 tag bits == TAG.FIXNUM == 0). :prim_integerq_entry -%scope prim_integerq +.scope %car(t0, a0) %tagof(t1, t0) %li(a0, %imm_val(%IMM.FALSE)) - %bnez(t1, &::end) + %bnez(t1, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope # (symbol? x) -- #t iff x is TAG.SYM (interned symbol index, not a heap obj). :prim_symbolq_entry -%scope prim_symbolq +.scope %car(t0, a0) %tagof(t1, t0) %li(t2, %TAG.SYM) %li(a0, %imm_val(%IMM.FALSE)) - %bne(t1, t2, &::end) + %bne(t1, t2, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope # (procedure? x) -- #t iff x is HEAP-tagged with header HDR.CLOSURE or HDR.PRIM. :prim_procedureq_entry -%scope prim_procedureq +.scope %car(t0, a0) %tagof(t1, t0) %li(t2, %TAG.HEAP) %li(a0, %imm_val(%IMM.FALSE)) - %bne(t1, t2, &::end) + %bne(t1, t2, &.end) %hdr_type(t1, t0) %li(t2, %HDR.CLOSURE) - %beq(t1, t2, &::yes) + %beq(t1, t2, &.yes) %li(t2, %HDR.PRIM) - %beq(t1, t2, &::yes) - %b(&::end) - ::yes + %beq(t1, t2, &.yes) + %b(&.end) + :.yes %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope :prim_zeroq_entry -%scope prim_zeroq +.scope %car(t0, a0) %li(a0, %imm_val(%IMM.FALSE)) - %bnez(t0, &::end) + %bnez(t0, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope :prim_not_entry -%scope prim_not +.scope %car(t0, a0) %li(t1, %imm_val(%IMM.FALSE)) %li(a0, %imm_val(%IMM.FALSE)) - %bne(t0, t1, &::end) + %bne(t0, t1, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope :prim_eqq_entry -%scope prim_eqq +.scope %car(t0, a0) %cdr(t1, a0) %car(t1, t1) %li(a0, %imm_val(%IMM.FALSE)) - %bne(t0, t1, &::end) + %bne(t0, t1, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope # Variadic arithmetic. (+ ...) folds with identity 0; (* ...) folds with # identity 1; (- x) is unary negate, (- x y z ...) folds left. :prim_plus_entry -%scope prim_plus +.scope %li(t0, 0) ; tagged 0; tag bits stay 0 across %add - ::loop - %if_nil(t1, a0, &::done) + :.loop + %if_nil(t1, a0, &.done) %car(t1, a0) %add(t0, t0, t1) %cdr(a0, a0) - %b(&::loop) - ::done + %b(&.loop) + :.done %mov(a0, t0) %ret -%endscope +.endscope # (- x) -> -x; (- x y ...) -> x - y - ... . (-) is undefined behavior # per the primitive-failure policy. :prim_minus_entry -%scope prim_minus +.scope %car(t0, a0) ; seed = first arg (tagged) %cdr(a0, a0) - %if_nil(t1, a0, &::neg) - ::loop - %if_nil(t1, a0, &::done) + %if_nil(t1, a0, &.neg) + :.loop + %if_nil(t1, a0, &.done) %car(t1, a0) %sub(t0, t0, t1) %cdr(a0, a0) - %b(&::loop) - ::neg + %b(&.loop) + :.neg %li(t1, 0) ; unary: 0 - seed %sub(t0, t1, t0) - ::done + :.done %mov(a0, t0) %ret -%endscope +.endscope # Multiply keeps the accumulator tagged and untags each incoming arg: # (a<<3) * b == (a*b)<<3, so the loop preserves the fixnum tag. :prim_mult_entry -%scope prim_mult +.scope %li(t0, 8) ; tagged 1 = mkfix(1) - ::loop - %if_nil(t1, a0, &::done) + :.loop + %if_nil(t1, a0, &.done) %car(t1, a0) %untag_fix(t1, t1) %mul(t0, t0, t1) %cdr(a0, a0) - %b(&::loop) - ::done + %b(&.loop) + :.done %mov(a0, t0) %ret -%endscope +.endscope # Variadic chained comparisons: (op a b c ...) ⇔ (a op b) ∧ (b op c) ∧ ... # Walks the tail with a single live `prev` register; a0 is reused as the # args cursor and finally as the result. <2 args is undefined behavior. :prim_eq_entry -%scope prim_eq +.scope %car(t0, a0) ; prev = first %cdr(a0, a0) - ::loop - %if_nil(t1, a0, &::true) + :.loop + %if_nil(t1, a0, &.true) %car(t1, a0) ; curr - %bne(t0, t1, &::false) + %bne(t0, t1, &.false) %mov(t0, t1) %cdr(a0, a0) - %b(&::loop) - ::true + %b(&.loop) + :.true %li(a0, %imm_val(%IMM.TRUE)) %ret - ::false + :.false %li(a0, %imm_val(%IMM.FALSE)) %ret -%endscope +.endscope :prim_lt_entry -%scope prim_lt +.scope %car(t0, a0) %cdr(a0, a0) - ::loop - %if_nil(t1, a0, &::true) + :.loop + %if_nil(t1, a0, &.true) %car(t1, a0) - %blt(t0, t1, &::ok) ; prev < curr -> continue + %blt(t0, t1, &.ok) ; prev < curr -> continue %li(a0, %imm_val(%IMM.FALSE)) %ret - ::ok + :.ok %mov(t0, t1) %cdr(a0, a0) - %b(&::loop) - ::true + %b(&.loop) + :.true %li(a0, %imm_val(%IMM.TRUE)) %ret -%endscope +.endscope :prim_gt_entry -%scope prim_gt +.scope %car(t0, a0) %cdr(a0, a0) - ::loop - %if_nil(t1, a0, &::true) + :.loop + %if_nil(t1, a0, &.true) %car(t1, a0) - %blt(t1, t0, &::ok) ; curr < prev <=> prev > curr -> continue + %blt(t1, t0, &.ok) ; curr < prev <=> prev > curr -> continue %li(a0, %imm_val(%IMM.FALSE)) %ret - ::ok + :.ok %mov(t0, t1) %cdr(a0, a0) - %b(&::loop) - ::true + %b(&.loop) + :.true %li(a0, %imm_val(%IMM.TRUE)) %ret -%endscope +.endscope # (quotient x y) -- truncating integer division. Both fixnums are tagged # (real << 3); div(tagged, tagged) yields the raw quotient (the shifts @@ -3785,46 +3776,46 @@ # XOR with another tagged fixnum preserves the tag in the accumulator. # Identities: bit-and -> -1 (tagged -8), bit-or -> 0, bit-xor -> 0. :prim_bit_and_entry -%scope prim_bit_and +.scope %li(t0, -8) ; tagged -1; AND-identity preserves the tag - ::loop - %if_nil(t1, a0, &::done) + :.loop + %if_nil(t1, a0, &.done) %car(t1, a0) %and(t0, t0, t1) %cdr(a0, a0) - %b(&::loop) - ::done + %b(&.loop) + :.done %mov(a0, t0) %ret -%endscope +.endscope :prim_bit_or_entry -%scope prim_bit_or +.scope %li(t0, 0) - ::loop - %if_nil(t1, a0, &::done) + :.loop + %if_nil(t1, a0, &.done) %car(t1, a0) %or(t0, t0, t1) %cdr(a0, a0) - %b(&::loop) - ::done + %b(&.loop) + :.done %mov(a0, t0) %ret -%endscope +.endscope :prim_bit_xor_entry -%scope prim_bit_xor +.scope %li(t0, 0) - ::loop - %if_nil(t1, a0, &::done) + :.loop + %if_nil(t1, a0, &.done) %car(t1, a0) %xor(t0, t0, t1) %cdr(a0, a0) - %b(&::loop) - ::done + %b(&.loop) + :.done %mov(a0, t0) %ret -%endscope +.endscope # (bit-not n) -- bitwise complement. Untag, XOR with -1 (= ~n), retag. # Can't XOR the tagged value directly: that would flip the low 3 tag bits. @@ -3839,23 +3830,23 @@ # (arithmetic-shift n k): k > 0 means left shift; k < 0 means arith right. # Untag both, branch on sign of k, retag. :prim_arith_shift_entry -%scope prim_arith_shift +.scope %car(t0, a0) %cdr(t1, a0) %car(t1, t1) %untag_fix(t0, t0) %untag_fix(t1, t1) - %bltz(t1, &::right) + %bltz(t1, &.right) %shl(a0, t0, t1) %mkfix(a0, a0) %ret - ::right + :.right %li(t2, 0) %sub(t1, t2, t1) %sar(a0, t0, t1) %mkfix(a0, a0) %ret -%endscope +.endscope # Bytevectors are 24-byte HEAP-tagged wrappers pointing at a separately # allocated data buffer; this gives them dynamic-array semantics — capacity @@ -3881,54 +3872,54 @@ # alloc_bytes(size=a0) -> raw addr (a0). Untagged data buffer; size is # rounded up to 8 to keep the next bump 8-byte-aligned. :alloc_bytes -%scope alloc_bytes +.scope %alignup(a0, a0, 8, t0) %ld_global(t2, &current_heap_next_ptr) %ld(t1, t2, 0) %add(t0, t1, a0) %ld_global(a3, &current_heap_end_ptr) %ld(a3, a3, 0) - %bltu(a3, t0, &::oom) + %bltu(a3, t0, &.oom) %st(t0, t2, 0) %mov(a0, t1) %ret - ::oom + :.oom %b(&heap_oom_die) -%endscope +.endscope # alloc_bytes_main(size=a0) -> raw addr (a0). Untagged data buffer in the # main heap regardless of current heap selection. Used for interpreter- # owned stable storage such as symtab names, which must survive scratch # resets even when user code is currently allocating in scratch. :alloc_bytes_main -%scope alloc_bytes_main +.scope %alignup(a0, a0, 8, t0) %la(t2, &heap_next) %ld(t1, t2, 0) %add(t0, t1, a0) %ld_global(a3, &heap_end) - %bltu(a3, t0, &::oom) + %bltu(a3, t0, &.oom) %st(t0, t2, 0) %mov(a0, t1) %ret - ::oom + :.oom %die(msg_heap_full) -%endscope +.endscope # bv_capacity_for(n=a0) -> smallest power-of-two ≥ n, minimum 16. Pure # bytevector sizing -- no NUL slack. Callers building "strings" call # bv_capacity_for(raw_len + 1) to reserve room for the trailing NUL. :bv_capacity_for -%scope bv_capacity_for +.scope %li(t0, 16) - ::loop - %bltu(t0, a0, &::shift) ; t0 < a0: keep doubling + :.loop + %bltu(t0, a0, &.shift) ; t0 < a0: keep doubling %mov(a0, t0) ; t0 >= a0: done %ret - ::shift + :.shift %shli(t0, t0, 1) - %b(&::loop) -%endscope + %b(&.loop) +.endscope # bv_alloc(raw_len=a0) -> tagged bv (a0). Length = raw_len, capacity from # bv_capacity_for, data buffer uninitialized. data_ptr lives in a frame @@ -3972,15 +3963,15 @@ %stl(a1, min_cap) %ld(t0, a0, 13) ; bv.cap (raw offset 16; not in BV struct) - %bltu(t0, a1, &::need) + %bltu(t0, a1, &.need) %ldl(a0, bv) %eret - ::need - ::loop + :.need + :.loop %shli(t0, t0, 1) %ldl(t1, min_cap) - %bltu(t0, t1, &::loop) + %bltu(t0, t1, &.loop) %stl(t0, min_cap) %mov(a0, t0) @@ -4011,15 +4002,15 @@ %li(t2, 0) %cdr(t0, a0) - %if_nil(t1, t0, &::no_fill) + %if_nil(t1, t0, &.no_fill) %car(t0, t0) %sari(t2, t0, 3) - ::no_fill + :.no_fill %stl(t2, fill) %ldl(a0, args) %car_fix(a0, a0) - %bltz(a0, &::bad_len) + %bltz(a0, &.bad_len) %call(&bv_alloc) %stl(a0, wrapper) @@ -4030,18 +4021,18 @@ %heap_ld(t2, a1, %BV.data) %li(a1, 0) - ::fill_loop - %beq(a1, t0, &::fill_done) + :.fill_loop + %beq(a1, t0, &.fill_done) %sb(t1, t2, 0) %addi(t2, t2, 1) %addi(a1, a1, 1) - %b(&::fill_loop) - ::fill_done + %b(&.fill_loop) + :.fill_done %ldl(a0, wrapper) %eret - ::bad_len + :.bad_len %die(msg_bv_oob) }) @@ -4066,41 +4057,41 @@ }) :prim_bv_u8_ref_entry -%scope prim_bv_u8_ref +.scope %args2(t0, t1, a0) ; bv, tagged idx %sari(t1, t1, 3) ; raw idx - %bltz(t1, &::oob) + %bltz(t1, &.oob) %heap_ld(a0, t0, %BV.hdr) %shri(a0, a0, 8) ; length - %bltu(t1, a0, &::ok) - ::oob + %bltu(t1, a0, &.ok) + :.oob %die(msg_bv_oob) - ::ok + :.ok %heap_ld(t2, t0, %BV.data) %add(t2, t2, t1) %lb(a0, t2, 0) %mkfix(a0, a0) %ret -%endscope +.endscope :prim_bv_u8_set_entry -%scope prim_bv_u8_set +.scope %args3(t0, t2, t1, a0) ; bv, idx, val %sari(t2, t2, 3) ; raw idx %sari(t1, t1, 3) ; raw val - %bltz(t2, &::oob) + %bltz(t2, &.oob) %heap_ld(a0, t0, %BV.hdr) %shri(a0, a0, 8) ; length - %bltu(t2, a0, &::ok) - ::oob + %bltu(t2, a0, &.ok) + :.oob %die(msg_bv_oob) - ::ok + :.ok %heap_ld(a0, t0, %BV.data) %add(a0, a0, t2) %sb(t1, a0, 0) %li(a0, %imm_val(%IMM.UNSPEC)) %ret -%endscope +.endscope # (bytevector-copy src start end) -> fresh bv of length end-start. # Bounds: 0 <= start <= end <= src.length. @@ -4119,11 +4110,11 @@ # Bounds: start >= 0; end >= start (signed catches negative end since # start is now non-negative); src.length >= end. - %bltz(t2, &::oob) - %blt(t1, t2, &::oob) + %bltz(t2, &.oob) + %blt(t1, t2, &.oob) %heap_ld(a0, t0, %BV.hdr) %shri(a0, a0, 8) ; src.length - %blt(a0, t1, &::oob) + %blt(a0, t1, &.oob) %sub(a0, t1, t2) ; count %call(&bv_alloc) @@ -4141,20 +4132,20 @@ %heap_ld(a1, a3, %BV.hdr) %shri(a1, a1, 8) ; count - ::copy_loop - %beqz(a1, &::copy_done) + :.copy_loop + %beqz(a1, &.copy_done) %lb(t0, t2, 0) %sb(t0, a2, 0) %addi(t2, t2, 1) %addi(a2, a2, 1) %addi(a1, a1, -1) - %b(&::copy_loop) + %b(&.copy_loop) - ::copy_done + :.copy_done %ldl(a0, wrapper) %eret - ::oob + :.oob %die(msg_bv_oob) }) @@ -4189,25 +4180,25 @@ # src-start >= 0 %ldl(t0, src_start) - %bltz(t0, &::oob) + %bltz(t0, &.oob) # src-end >= src-start (signed catches negative src-end) %ldl(t1, src_end) - %blt(t1, t0, &::oob) + %blt(t1, t0, &.oob) # src-end <= src.length %ldl(t2, src) %heap_ld(a0, t2, %BV.hdr) %shri(a0, a0, 8) - %blt(a0, t1, &::oob) + %blt(a0, t1, &.oob) # dst-start >= 0 %ldl(t2, dst_start) - %bltz(t2, &::oob) + %bltz(t2, &.oob) # dst-start + count <= dst.length %sub(a0, t1, t0) ; count = src-end - src-start %add(a0, a0, t2) ; dst-start + count %ldl(t1, dst) %heap_ld(t2, t1, %BV.hdr) %shri(t2, t2, 8) - %blt(t2, a0, &::oob) + %blt(t2, a0, &.oob) # Set up copy. dst ptr = dst.data + dst-start; src ptr = src.data + # src-start; count = src-end - src-start. @@ -4222,20 +4213,20 @@ %ldl(a3, src_end) %sub(a3, a3, a2) ; count - ::loop - %beqz(a3, &::done) + :.loop + %beqz(a3, &.done) %lb(t1, a1, 0) %sb(t1, t0, 0) %addi(t0, t0, 1) %addi(a1, a1, 1) %addi(a3, a3, -1) - %b(&::loop) + %b(&.loop) - ::done + :.done %li(a0, %imm_val(%IMM.UNSPEC)) %eret - ::oob + :.oob %die(msg_bv_oob) }) @@ -4245,58 +4236,58 @@ # branch). Compares lengths first, then walks bytes; %lb is zero-extending # on every backend, so a single %bne is enough for the byte test. :bv_equal_check -%scope bv_equal_check +.scope %heap_ld(t0, a0, %BV.hdr) %shri(t0, t0, 8) ; len_a %heap_ld(t1, a1, %BV.hdr) %shri(t1, t1, 8) ; len_b - %bne(t0, t1, &::false) + %bne(t0, t1, &.false) %heap_ld(a2, a0, %BV.data) %heap_ld(a3, a1, %BV.data) - ::loop - %beqz(t0, &::true) + :.loop + %beqz(t0, &.true) %lb(t1, a2, 0) %lb(t2, a3, 0) - %bne(t1, t2, &::false) + %bne(t1, t2, &.false) %addi(a2, a2, 1) %addi(a3, a3, 1) %addi(t0, t0, -1) - %b(&::loop) + %b(&.loop) - ::true + :.true %li(a0, %imm_val(%IMM.TRUE)) %ret - ::false + :.false %li(a0, %imm_val(%IMM.FALSE)) %ret -%endscope +.endscope # (bytevector=? a b) -- structural equality on bytevectors. Non-bv # inputs return #f rather than aborting, matching the lax stance the # other predicates take until LISP.md pins a stricter policy. :prim_bytevector_eq_entry -%scope prim_bytevector_eq +.scope %args2(t0, t1, a0) %tagof(t2, t0) %li(a0, %TAG.HEAP) - %bne(t2, a0, &::false) + %bne(t2, a0, &.false) %tagof(t2, t1) - %bne(t2, a0, &::false) + %bne(t2, a0, &.false) %hdr_type(t2, t0) %li(a0, %HDR.BV) - %bne(t2, a0, &::false) + %bne(t2, a0, &.false) %hdr_type(t2, t1) - %bne(t2, a0, &::false) + %bne(t2, a0, &.false) %mov(a0, t0) %mov(a1, t1) %b(&bv_equal_check) - ::false + :.false %li(a0, %imm_val(%IMM.FALSE)) %ret -%endscope +.endscope # equal_recurse(a=a0, b=a1) -> a0 (IMM.TRUE / IMM.FALSE). Identity covers # fixnums, symbols, immediates, and any case where both arguments are the @@ -4312,59 +4303,59 @@ %stl(a0, a) %stl(a1, b) - %beq(a0, a1, &::true) + %beq(a0, a1, &.true) %tagof(t0, a0) %tagof(t1, a1) - %bne(t0, t1, &::false) + %bne(t0, t1, &.false) - %bieq(t0, %TAG.PAIR, &::pair, t1) - %bieq(t0, %TAG.HEAP, &::heap, t1) - %b(&::false) + %bieq(t0, %TAG.PAIR, &.pair, t1) + %bieq(t0, %TAG.HEAP, &.heap, t1) + %b(&.false) - ::pair + :.pair %ldl(t0, a) %ldl(t1, b) %car(a0, t0) %car(a1, t1) %call(&equal_recurse) - %bieq(a0, %imm_val(%IMM.FALSE), &::done, t0) + %bieq(a0, %imm_val(%IMM.FALSE), &.done, t0) %ldl(t0, a) %ldl(t1, b) %cdr(a0, t0) %cdr(a1, t1) %tail(&equal_recurse) - ::heap + :.heap %ldl(t0, a) %ldl(t1, b) %hdr_type(t2, t0) %hdr_type(a0, t1) - %bne(t2, a0, &::false) ; differing heap classes -> #f + %bne(t2, a0, &.false) ; differing heap classes -> #f %li(a0, %HDR.BV) - %beq(t2, a0, &::heap_bv) + %beq(t2, a0, &.heap_bv) %li(a0, %HDR.REC) - %beq(t2, a0, &::heap_rec) - %b(&::false) ; CLOSURE/PRIM/TD: identity-only + %beq(t2, a0, &.heap_rec) + %b(&.false) ; CLOSURE/PRIM/TD: identity-only - ::heap_bv + :.heap_bv %mov(a0, t0) %mov(a1, t1) %tail(&bv_equal_check) - ::heap_rec + :.heap_rec %mov(a0, t0) %mov(a1, t1) %tail(&rec_equal_check) - ::true + :.true %li(a0, %imm_val(%IMM.TRUE)) - %b(&::done) + %b(&.done) - ::false + :.false %li(a0, %imm_val(%IMM.FALSE)) - ::done + :.done }) # rec_equal_check(a=a0, b=a1) -> a0 (IMM.TRUE / IMM.FALSE). Both args @@ -4383,17 +4374,17 @@ %heap_ld(t0, a0, %REC.td) ; td_a %heap_ld(t1, a1, %REC.td) ; td_b - %bne(t0, t1, &::false) + %bne(t0, t1, &.false) %heap_ld(t1, t0, %TD.nfields) %stl(t1, nfields) %li(t0, 0) %stl(t0, i) ; i = 0 - ::loop + :.loop %ldl(t0, i) %ldl(t1, nfields) - %beq(t0, t1, &::true) + %beq(t0, t1, &.true) %shli(t2, t0, 3) %addi(t2, t2, 13) ; field offset = 13 + 8*i @@ -4404,21 +4395,21 @@ %add(t1, t1, t2) %ld(a1, t1, 0) ; b's field i %call(&equal_recurse) - %bieq(a0, %imm_val(%IMM.FALSE), &::done, t0) + %bieq(a0, %imm_val(%IMM.FALSE), &.done, t0) %ldl(t0, i) %addi(t0, t0, 1) %stl(t0, i) - %b(&::loop) + %b(&.loop) - ::true + :.true %li(a0, %imm_val(%IMM.TRUE)) - %b(&::done) + %b(&.done) - ::false + :.false %li(a0, %imm_val(%IMM.FALSE)) - ::done + :.done }) # (equal? a b) -- thin prim wrapper that unpacks the args list and falls @@ -4469,10 +4460,10 @@ %stl(t0, head) %stl(t0, tail) - ::loop + :.loop %ldl(t0, walk) %cdr(t1, t0) - %if_nil(t2, t1, &::last) + %if_nil(t2, t1, &.last) # cell = cons(car(walk), NIL); append to head/tail. %car(a0, t0) @@ -4480,32 +4471,32 @@ %call(&cons) %ldl(t0, head) - %if_nil(t1, t0, &::first) + %if_nil(t1, t0, &.first) %ldl(t0, tail) %set_cdr(a0, t0) %stl(a0, tail) - %b(&::advance) + %b(&.advance) - ::first + :.first %stl(a0, head) %stl(a0, tail) - ::advance + :.advance %advance_walk(walk) - %b(&::loop) + %b(&.loop) - ::last + :.last # car(walk) is the trailing list. If head is NIL there were no leading # args -- return the trailing list directly. Otherwise splice it onto # the tail and return head. %car(a0, t0) %ldl(t1, head) - %if_nil(t2, t1, &::done) + %if_nil(t2, t1, &.done) %ldl(t1, tail) %set_cdr(a0, t1) %ldl(a0, head) - ::done + :.done }) # Records: TDs (type descriptors) and instances. A TD is a 24-byte heap @@ -4565,34 +4556,34 @@ %ldl(t0, args) %addi(t1, a0, 13) - ::fill_loop - %if_nil(t2, t0, &::fill_done) + :.fill_loop + %if_nil(t2, t0, &.fill_done) %car(t2, t0) %st(t2, t1, 0) %addi(t1, t1, 8) %cdr(t0, t0) - %b(&::fill_loop) - ::fill_done + %b(&.fill_loop) + :.fill_done %ldl(a0, record) }) # predicate: prim.data = TD; args = (rec). :prim_predicate_entry -%scope prim_predicate +.scope %car(t0, a0) %heap_ld(t1, a1, %PRIM.data) %tagof(t2, t0) %li(a0, %imm_val(%IMM.FALSE)) - %bine(t2, %TAG.HEAP, &::end, a2) + %bine(t2, %TAG.HEAP, &.end, a2) %hdr_type(t2, t0) - %bine(t2, %HDR.REC, &::end, a2) + %bine(t2, %HDR.REC, &.end, a2) %heap_ld(t2, t0, %REC.td) - %bne(t2, t1, &::end) + %bne(t2, t1, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope # accessor: prim.data = tagged field index; args = (rec). :prim_accessor_entry @@ -4605,7 +4596,7 @@ # mutator: prim.data = tagged field index; args = (rec val). :prim_mutator_entry -%scope prim_mutator +.scope %car(t0, a0) %cdr(t1, a0) %car(t1, t1) @@ -4615,7 +4606,7 @@ %st(t1, t2, 0) %li(a0, %imm_val(%IMM.UNSPEC)) %ret -%endscope +.endscope # eval_define_record_type(rest=a0, env=a1) -> UNSPEC. # rest = (name (ctor f1 ...) pred clause1 clause2 ...) @@ -4674,9 +4665,9 @@ %ldl(t0, walk) %stl(t0, fl_cur) - ::fl_loop + :.fl_loop %ldl(t0, fl_cur) - %if_nil(t1, t0, &::fl_done) + %if_nil(t1, t0, &.fl_done) # cell = cons(car(car(fl_cur)), NIL) %car(t1, t0) %car(a0, t1) @@ -4685,21 +4676,21 @@ # Splice into list: if head is NIL, head = tail = cell. # Else set-cdr!(tail, cell); tail = cell. %ldl(t1, fl_head) - %bine(t1, %imm_val(%IMM.NIL), &::fl_append, t2) + %bine(t1, %imm_val(%IMM.NIL), &.fl_append, t2) %stl(a0, fl_head) %stl(a0, fl_tail) - %b(&::fl_next) - ::fl_append + %b(&.fl_next) + :.fl_append %ldl(t1, fl_tail) %set_cdr(a0, t1) %stl(a0, fl_tail) - ::fl_next + :.fl_next %ldl(t0, fl_cur) %cdr(t0, t0) %stl(t0, fl_cur) - %b(&::fl_loop) + %b(&.fl_loop) - ::fl_done + :.fl_done %ldl(t0, td) %ldl(t1, fl_head) %heap_st(t1, t0, %TD.fields) @@ -4728,9 +4719,9 @@ %li(t0, 0) %stl(t0, idx) - ::clause_loop + :.clause_loop %ldl(t0, walk) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) # accessor-prim with data = tagged idx; bind cadr(clause). %ldl(a1, idx) @@ -4749,7 +4740,7 @@ %car(t0, t0) %cdr(t0, t0) %cdr(t0, t0) - %if_nil(t1, t0, &::no_mutator) + %if_nil(t1, t0, &.no_mutator) %ldl(a1, idx) %mkfix(a1, a1) @@ -4763,14 +4754,14 @@ %car(t0, t0) %set_global(t0, a0) - ::no_mutator + :.no_mutator %advance_walk(walk) %ldl(t0, idx) %addi(t0, t0, 1) %stl(t0, idx) - %b(&::clause_loop) + %b(&.clause_loop) - ::done + :.done %li(a0, %imm_val(%IMM.UNSPEC)) }) @@ -4981,10 +4972,10 @@ %stl(a0, bv) %stl(a1, value) - %bltz(a1, &::neg) - %b(&::pos) + %bltz(a1, &.neg) + %b(&.pos) - ::neg + :.neg %ldl(a0, bv) %li(a1, 45) ; '-' %call(&str_putc) @@ -4993,7 +4984,7 @@ %sub(t0, t1, t0) %stl(t0, value) - ::pos + :.pos %la(a0, &writer_num_buf) %ldl(a1, value) %call(&fmt_hex) ; n_bytes (a0) @@ -5028,10 +5019,10 @@ %stl(a2, mode) %tagof(t0, a0) - %bieq(t0, %TAG.PAIR, &::pair, t1) - %bieq(t0, %TAG.SYM, &::sym, t1) - %bieq(t0, %TAG.HEAP, &::heap, t1) - %bieq(t0, %TAG.IMM, &::imm, t1) + %bieq(t0, %TAG.PAIR, &.pair, t1) + %bieq(t0, %TAG.SYM, &.sym, t1) + %bieq(t0, %TAG.HEAP, &.heap, t1) + %bieq(t0, %TAG.IMM, &.imm, t1) # Fall-through: FIXNUM (the only remaining tag). %ldl(a0, bv) @@ -5039,7 +5030,7 @@ %sari(a1, a1, 3) %tail(&str_putint) - ::sym + :.sym %ldl(a0, val) %sari(a0, a0, 3) %call(&sym_name) @@ -5048,24 +5039,24 @@ %ldl(a0, bv) %tail(&str_putn) - ::pair + :.pair %ldl(a0, val) %ldl(a1, bv) %ldl(a2, mode) %tail(&write_pair_to_bv) - ::heap + :.heap %hdr_type(t0, a0) - %bieq(t0, %HDR.BV, &::heap_bv, t1) - %bieq(t0, %HDR.CLOSURE, &::heap_closure, t1) - %bieq(t0, %HDR.PRIM, &::heap_prim, t1) - %bieq(t0, %HDR.TD, &::heap_td, t1) - %bieq(t0, %HDR.REC, &::heap_rec, t1) - %b(&::heap_unknown) - - ::heap_bv + %bieq(t0, %HDR.BV, &.heap_bv, t1) + %bieq(t0, %HDR.CLOSURE, &.heap_closure, t1) + %bieq(t0, %HDR.PRIM, &.heap_prim, t1) + %bieq(t0, %HDR.TD, &.heap_td, t1) + %bieq(t0, %HDR.REC, &.heap_rec, t1) + %b(&.heap_unknown) + + :.heap_bv %ldl(t0, mode) - %beqz(t0, &::heap_bv_raw) + %beqz(t0, &.heap_bv_raw) # write mode: emit `"`, then the raw bytes, then `"`. %ldl(a0, bv) %li(a1, 34) @@ -5078,7 +5069,7 @@ %li(a1, 34) %tail(&str_putc) - ::heap_bv_raw + :.heap_bv_raw %ldl(t0, val) %heap_ld(a1, t0, %BV.data) %heap_ld(a2, t0, %BV.hdr) @@ -5086,79 +5077,79 @@ %ldl(a0, bv) %tail(&str_putn) - ::heap_closure + :.heap_closure %la(a1, &str_closure) %li(a2, 10) %ldl(a0, bv) %tail(&str_putn) - ::heap_prim + :.heap_prim %la(a1, &str_prim) %li(a2, 7) %ldl(a0, bv) %tail(&str_putn) - ::heap_td + :.heap_td %la(a1, &str_td) %li(a2, 11) %ldl(a0, bv) %tail(&str_putn) - ::heap_rec + :.heap_rec %la(a1, &str_rec) %li(a2, 9) %ldl(a0, bv) %tail(&str_putn) - ::heap_unknown + :.heap_unknown %la(a1, &str_unknown) %li(a2, 10) %ldl(a0, bv) %tail(&str_putn) - ::imm + :.imm %ldl(a0, val) %sari(a0, a0, 3) - %beqz(a0, &::imm_false) + %beqz(a0, &.imm_false) %addi(t0, a0, -1) - %beqz(t0, &::imm_true) + %beqz(t0, &.imm_true) %addi(t0, a0, -2) - %beqz(t0, &::imm_nil) + %beqz(t0, &.imm_nil) %addi(t0, a0, -3) - %beqz(t0, &::imm_unspec) + %beqz(t0, &.imm_unspec) %addi(t0, a0, -4) - %beqz(t0, &::imm_unbound) + %beqz(t0, &.imm_unbound) # EOF (idx == 5) is the only remaining IMM. %la(a1, &str_eof) %li(a2, 5) %ldl(a0, bv) %tail(&str_putn) - ::imm_false + :.imm_false %la(a1, &str_false) %li(a2, 2) %ldl(a0, bv) %tail(&str_putn) - ::imm_true + :.imm_true %la(a1, &str_true) %li(a2, 2) %ldl(a0, bv) %tail(&str_putn) - ::imm_nil + :.imm_nil %la(a1, &str_nil) %li(a2, 2) %ldl(a0, bv) %tail(&str_putn) - ::imm_unspec + :.imm_unspec %la(a1, &str_unspec) %li(a2, 8) %ldl(a0, bv) %tail(&str_putn) - ::imm_unbound + :.imm_unbound %la(a1, &str_unbound) %li(a2, 9) %ldl(a0, bv) @@ -5185,7 +5176,7 @@ %li(a1, 40) %call(&str_putc) - ::loop + :.loop %ldl(t0, pair) %car(a0, t0) %ldl(a1, bv) @@ -5196,10 +5187,10 @@ %cdr(t0, t0) %stl(t0, pair) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) %tagof(t1, t0) %li(t2, %TAG.PAIR) - %beq(t1, t2, &::cont) + %beq(t1, t2, &.cont) # Dotted tail: emit ` . ` then write_to_bv(cdr). %ldl(a0, bv) @@ -5215,15 +5206,15 @@ %ldl(a1, bv) %ldl(a2, mode) %call(&write_to_bv) - %b(&::done) + %b(&.done) - ::cont + :.cont %ldl(a0, bv) %li(a1, 32) %call(&str_putc) - %b(&::loop) + %b(&.loop) - ::done + :.done %ldl(a0, bv) %li(a1, 41) %tail(&str_putc) @@ -5307,9 +5298,9 @@ %cdr(t0, t0) %stl(t0, walk) - ::loop + :.loop %ldl(t0, walk) - %if_nil(t1, t0, &::done) + %if_nil(t1, t0, &.done) %ldl(a0, bv) %li(a1, 32) @@ -5324,9 +5315,9 @@ %ldl(t0, walk) %cdr(t0, t0) %stl(t0, walk) - %b(&::loop) + %b(&.loop) - ::done + :.done %ldl(t0, bv) %heap_ld(a0, t0, %BV.data) %tail(&runtime_error) @@ -5360,19 +5351,19 @@ %li(t0, 0) %stl(t0, idx) - ::loop + :.loop %ldl(t1, template) %heap_ld(t2, t1, %BV.hdr) %shri(t2, t2, 8) ; template length %ldl(t0, idx) - %beq(t0, t2, &::done) + %beq(t0, t2, &.done) %heap_ld(a3, t1, %BV.data) %add(a3, a3, t0) %lb(a3, a3, 0) ; byte = template.data[idx] %addi(t1, a3, -126) ; '~' - %beqz(t1, &::tilde) + %beqz(t1, &.tilde) # Plain byte: emit and advance. %ldl(a0, out) @@ -5381,15 +5372,15 @@ %ldl(t0, idx) %addi(t0, t0, 1) %stl(t0, idx) - %b(&::loop) + %b(&.loop) - ::tilde + :.tilde %ldl(t0, idx) %addi(t0, t0, 1) %ldl(t1, template) %heap_ld(t2, t1, %BV.hdr) %shri(t2, t2, 8) - %beq(t0, t2, &::tilde_lit) + %beq(t0, t2, &.tilde_lit) %heap_ld(t1, t1, %BV.data) %add(t1, t1, t0) @@ -5399,17 +5390,17 @@ %stl(t0, idx) %addi(t1, a3, -97) ; 'a' - %beqz(t1, &::spec_a) + %beqz(t1, &.spec_a) %addi(t1, a3, -115) ; 's' - %beqz(t1, &::spec_s) + %beqz(t1, &.spec_s) %addi(t1, a3, -100) ; 'd' - %beqz(t1, &::spec_d) + %beqz(t1, &.spec_d) %addi(t1, a3, -120) ; 'x' - %beqz(t1, &::spec_x) + %beqz(t1, &.spec_x) %addi(t1, a3, -37) ; '%' - %beqz(t1, &::spec_pct) + %beqz(t1, &.spec_pct) %addi(t1, a3, -126) ; '~' - %beqz(t1, &::spec_tilde) + %beqz(t1, &.spec_tilde) # Unknown directive: emit `~` then the spec byte verbatim. Re-read # the spec byte from the template since str_putc may clobber a3. @@ -5424,9 +5415,9 @@ %lb(a1, t1, 0) %ldl(a0, out) %call(&str_putc) - %b(&::loop) + %b(&.loop) - ::tilde_lit + :.tilde_lit # `~` at end of template: emit literal `~` and finish next iter. %ldl(a0, out) %li(a1, 126) @@ -5434,9 +5425,9 @@ %ldl(t0, idx) %addi(t0, t0, 1) %stl(t0, idx) - %b(&::loop) + %b(&.loop) - ::spec_a + :.spec_a %ldl(t0, args) %car(a0, t0) %cdr(t0, t0) @@ -5444,9 +5435,9 @@ %ldl(a1, out) %li(a2, 0) %call(&write_to_bv) - %b(&::loop) + %b(&.loop) - ::spec_s + :.spec_s %ldl(t0, args) %car(a0, t0) %cdr(t0, t0) @@ -5454,9 +5445,9 @@ %ldl(a1, out) %li(a2, 1) %call(&write_to_bv) - %b(&::loop) + %b(&.loop) - ::spec_d + :.spec_d %ldl(t0, args) %car(t1, t0) %cdr(t0, t0) @@ -5464,9 +5455,9 @@ %sari(a1, t1, 3) %ldl(a0, out) %call(&str_putint) - %b(&::loop) + %b(&.loop) - ::spec_x + :.spec_x %ldl(t0, args) %car(t1, t0) %cdr(t0, t0) @@ -5474,21 +5465,21 @@ %sari(a1, t1, 3) %ldl(a0, out) %call(&str_puthex) - %b(&::loop) + %b(&.loop) - ::spec_pct + :.spec_pct %ldl(a0, out) %li(a1, 10) %call(&str_putc) - %b(&::loop) + %b(&.loop) - ::spec_tilde + :.spec_tilde %ldl(a0, out) %li(a1, 126) %call(&str_putc) - %b(&::loop) + %b(&.loop) - ::done + :.done %ldl(a0, out) }) @@ -5511,12 +5502,12 @@ %fn2(wrap_syscall_result, {raw pad}, { %stl(a0, raw) - %bltz(a0, &::err) + %bltz(a0, &.err) %mkfix(a1, a0) %li(a0, %imm_val(%IMM.TRUE)) %tail(&cons) - ::err + :.err %ldl(t0, raw) %li(t1, 0) %sub(t0, t1, t0) @@ -5594,16 +5585,16 @@ %ldl(t0, list) %ldl(t1, array) - ::fill_loop - %if_nil(t2, t0, &::fill_done) + :.fill_loop + %if_nil(t2, t0, &.fill_done) %car(a3, t0) %heap_ld(a2, a3, %BV.data) %st(a2, t1, 0) %addi(t1, t1, 8) %cdr(t0, t0) - %b(&::fill_loop) + %b(&.fill_loop) - ::fill_done + :.fill_done %li(t2, 0) %st(t2, t1, 0) @@ -5718,9 +5709,9 @@ %stl(t0, head) %stl(t0, tail) - ::loop + :.loop %ldl(t0, count) - %beqz(t0, &::done) + %beqz(t0, &.done) # len = strlen(*argv) %ldl(t0, argv) @@ -5748,41 +5739,41 @@ %call(&cons) %ldl(t0, head) - %if_nil(t1, t0, &::first) + %if_nil(t1, t0, &.first) %ldl(t0, tail) %set_cdr(a0, t0) %stl(a0, tail) - %b(&::advance) + %b(&.advance) - ::first + :.first %stl(a0, head) %stl(a0, tail) - ::advance + :.advance %ldl(t0, argv) %addi(t0, t0, 8) %stl(t0, argv) %ldl(t0, count) %addi(t0, t0, -1) %stl(t0, count) - %b(&::loop) + %b(&.loop) - ::done + :.done %ldl(a0, head) }) # (eof? x). The `eof` value itself is bound at startup in p1_main as a # direct global -> IMM.EOF, not via a primitive thunk. :prim_eofq_entry -%scope prim_eofq +.scope %car(t0, a0) %li(t1, %imm_val(%IMM.EOF)) %li(a0, %imm_val(%IMM.FALSE)) - %bne(t0, t1, &::end) + %bne(t0, t1, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope # (heap-usage) -> tagged fixnum: bytes consumed since heap_init # (heap_next - heap_buf_ptr). Used by cc to instrument per-phase @@ -5860,22 +5851,22 @@ # small sym indices) yield false because their masked values are far # below heap_buf_ptr. :prim_heap_in_main_q_entry -%scope prim_heap_in_main_q +.scope %car(t0, a0) %li(t1, -8) %and(t0, t0, t1) %ld_global(t1, &heap_buf_ptr) - %bltu(t0, t1, &::false) + %bltu(t0, t1, &.false) %li(t2, %HEAP_CAP_BYTES) %add(t1, t1, t2) - %bltu(t0, t1, &::true) - ::false + %bltu(t0, t1, &.true) + :.false %li(a0, %imm_val(%IMM.FALSE)) %ret - ::true + :.true %li(a0, %imm_val(%IMM.TRUE)) %ret -%endscope +.endscope # (heap-in-current? obj) -> bool. True iff obj's masked pointer falls # inside whichever heap is currently selected (main or scratch). @@ -5884,32 +5875,32 @@ # is current. Tag bits are masked off; non-pointer values yield #f. # Used by deep-copy as the "already in target arena" short-circuit. :prim_heap_in_current_q_entry -%scope prim_heap_in_current_q +.scope %car(t0, a0) %li(t1, -8) %and(t0, t0, t1) %ld_global(t1, &current_heap_next_ptr) %la(t2, &heap_next) - %bne(t1, t2, &::scratch) + %bne(t1, t2, &.scratch) %ld_global(t1, &heap_buf_ptr) - %bltu(t0, t1, &::false) + %bltu(t0, t1, &.false) %li(t2, %HEAP_CAP_BYTES) %add(t1, t1, t2) - %bltu(t0, t1, &::true) - %b(&::false) - ::scratch + %bltu(t0, t1, &.true) + %b(&.false) + :.scratch %ld_global(t1, &scratch_buf_ptr) - %bltu(t0, t1, &::false) + %bltu(t0, t1, &.false) %li(t2, %SCRATCH_CAP_BYTES) %add(t1, t1, t2) - %bltu(t0, t1, &::true) - ::false + %bltu(t0, t1, &.true) + :.false %li(a0, %imm_val(%IMM.FALSE)) %ret - ::true + :.true %li(a0, %imm_val(%IMM.TRUE)) %ret -%endscope +.endscope # Record introspection. Surfaces the unsafe %record-* helpers (heap # layout: [HDR.REC][td][f0..fN-1], field i at tagged + 13 + 8*i; @@ -5920,19 +5911,19 @@ # (record? obj) -> bool. True iff obj is HEAP-tagged with HDR.REC. :prim_recordq_entry -%scope prim_recordq +.scope %car(t0, a0) %li(a0, %imm_val(%IMM.FALSE)) %tagof(t1, t0) %li(t2, %TAG.HEAP) - %bne(t1, t2, &::end) + %bne(t1, t2, &.end) %hdr_type(t1, t0) %li(t2, %HDR.REC) - %bne(t1, t2, &::end) + %bne(t1, t2, &.end) %li(a0, %imm_val(%IMM.TRUE)) - ::end + :.end %ret -%endscope +.endscope # (record-td rec) -> td. Reads the TD slot from the record header. No # kind check; caller is expected to gate with record? if needed. @@ -5953,7 +5944,7 @@ # (record-set! rec idx val) -> unspec. In-place store at slot idx. :prim_record_set_bang_entry -%scope prim_record_set_bang +.scope %car(t0, a0) ; rec %cdr(a0, a0) %car(t1, a0) ; idx (tagged fixnum) @@ -5964,7 +5955,7 @@ %st(t2, t0, 0) %li(a0, %imm_val(%IMM.UNSPEC)) %ret -%endscope +.endscope # (make-record/td td) -> fresh record allocated in the current heap. # Reads td.nfields, allocates 16 + nfields*8 bytes with HDR.REC, sets @@ -5996,14 +5987,14 @@ %addi(t1, a0, 13) %li(t2, %imm_val(%IMM.UNSPEC)) - ::fill_loop - %beqz(t0, &::fill_done) + :.fill_loop + %beqz(t0, &.fill_done) %st(t2, t1, 0) %addi(t1, t1, 8) %addi(t0, t0, -1) - %b(&::fill_loop) + %b(&.fill_loop) - ::fill_done + :.fill_done %ldl(a0, record) }) @@ -6061,29 +6052,29 @@ # msg_heap_full vs msg_scratch_full by comparing current_heap_next_ptr # against &heap_next, then tails into runtime_error via %die. :heap_oom_die -%scope heap_oom_die +.scope %ld_global(t0, &current_heap_next_ptr) %la(t1, &heap_next) - %beq(t0, t1, &::main) + %beq(t0, t1, &.main) %die(msg_scratch_full) - ::main + :.main %die(msg_heap_full) -%endscope +.endscope # (values . xs) -- multiple-values producer. Single-arg case returns the # arg unchanged so (values x) is interchangeable with x in any 1-value # context; 0 or 2+ args materialize an MV-pack. :prim_values_entry -%scope prim_values - %if_nil(t0, a0, &::pack) +.scope + %if_nil(t0, a0, &.pack) %cdr(t0, a0) - %if_nil(t1, t0, &::single) - ::pack + %if_nil(t1, t0, &.single) + :.pack %b(&list_to_mv) - ::single + :.single %car(a0, a0) %ret -%endscope +.endscope # (call-with-values producer consumer) -- apply producer to no args, then # normalize its result (via mv_to_list) and tail-apply the consumer to the @@ -6149,108 +6140,109 @@ # disassembly so trailing strings don't decode as bogus instructions. :_text_end +.align 8 # Primitive surface names. -:name_sys_exit "sys-exit" '00000000000000' -:name_cons "cons" '000000' -:name_car "car" '00000000' -:name_cdr "cdr" '00000000' -:name_nullq "null?" '0000' -:name_pairq "pair?" '0000' -:name_stringq "string?" -:name_set_car "set-car!" '00000000000000' -:name_set_cdr "set-cdr!" '00000000000000' -:name_length "length" '00' -:name_list_ref "list-ref" '00000000000000' -:name_assq "assq" '000000' -:name_assoc "assoc" '0000' -:name_reverse "reverse" -:name_str_to_sym "string->symbol" '00' -:name_sym_to_str "symbol->string" '00' -:name_num_to_str "number->string" '00' -:name_str_to_num "string->number" '00' -:name_bv_append "bytevector-append" '000000000000' -:name_booleanq "boolean?" '00000000000000' -:name_integerq "integer?" '00000000000000' -:name_symbolq "symbol?" -:name_procedureq "procedure?" '0000000000' -:name_zeroq "zero?" '0000' -:name_not "not" '00000000' -:name_eqq "eq?" '00000000' -:name_equal "equal?" '00' -:name_plus "+" '000000000000' -:name_minus "-" '000000000000' -:name_mult "*" '000000000000' -:name_eq "=" '000000000000' -:name_lt "<" '000000000000' -:name_gt ">" '000000000000' -:name_quotient "quotient" '00000000000000' -:name_remainder "remainder" '000000000000' -:name_bit_and "bit-and" -:name_bit_or "bit-or" '00' -:name_bit_xor "bit-xor" -:name_bit_not "bit-not" -:name_arith_shift "arithmetic-shift" '00000000000000' -:name_apply "apply" '0000' -:name_make_bv "make-bytevector" -:name_bv_length "bytevector-length" '000000000000' -:name_string_length "string-length" '0000' -:name_bv_u8_ref "bytevector-u8-ref" '000000000000' -:name_bv_u8_set "bytevector-u8-set!" '0000000000' -:name_bv_copy "bytevector-copy" -:name_bv_copy_b "bytevector-copy!" '00000000000000' -:name_bv_eq "bytevector=?" '000000' - -:name_sys_read "sys-read" '00000000000000' -:name_sys_write "sys-write" '000000000000' -:name_sys_close "sys-close" '000000000000' -:name_sys_openat "sys-openat" '0000000000' -:name_sys_clone "sys-clone" '000000000000' -:name_sys_execve "sys-execve" '0000000000' -:name_sys_waitid "sys-waitid" '0000000000' -:name_sys_argv "sys-argv" '00000000000000' -:name_eof "eof" '00000000' -:name_eofq "eof?" '000000' -:name_values "values" '00' -:name_call_with_values "call-with-values" '00000000000000' -:name_display "display" -:name_write "write" '0000' -:name_error "error" '0000' -:name_format "format" '00' -:name_heap_mark "heap-mark" '000000000000' -:name_heap_rewind_bang "heap-rewind!" '000000' -:name_heap_usage "heap-usage" '0000000000' -:name_use_scratch_heap_bang "use-scratch-heap!" '000000000000' -:name_use_main_heap_bang "use-main-heap!" '00' -:name_reset_scratch_heap_bang "reset-scratch-heap!" '00000000' -:name_heap_in_main_q "heap-in-main?" '0000' -:name_heap_in_current_q "heap-in-current?" '00000000000000' -:name_recordq "record?" -:name_record_td "record-td" '000000000000' -:name_record_ref "record-ref" '0000000000' -:name_record_set_bang "record-set!" '00000000' -:name_make_record_td "make-record/td" '00' -:name_td_nfields "td-nfields" '0000000000' -:name_td_name "td-name" -:name_tagged_value "tagged-value" '000000' -:name_peek_u8 "peek-u8" -:name_current_heap_next "current-heap-next" '000000000000' +:name_sys_exit %cstr8("sys-exit") +:name_cons %cstr8("cons") +:name_car %cstr8("car") +:name_cdr %cstr8("cdr") +:name_nullq %cstr8("null?") +:name_pairq %cstr8("pair?") +:name_stringq %cstr8("string?") +:name_set_car %cstr8("set-car!") +:name_set_cdr %cstr8("set-cdr!") +:name_length %cstr8("length") +:name_list_ref %cstr8("list-ref") +:name_assq %cstr8("assq") +:name_assoc %cstr8("assoc") +:name_reverse %cstr8("reverse") +:name_str_to_sym %cstr8("string->symbol") +:name_sym_to_str %cstr8("symbol->string") +:name_num_to_str %cstr8("number->string") +:name_str_to_num %cstr8("string->number") +:name_bv_append %cstr8("bytevector-append") +:name_booleanq %cstr8("boolean?") +:name_integerq %cstr8("integer?") +:name_symbolq %cstr8("symbol?") +:name_procedureq %cstr8("procedure?") +:name_zeroq %cstr8("zero?") +:name_not %cstr8("not") +:name_eqq %cstr8("eq?") +:name_equal %cstr8("equal?") +:name_plus %cstr8("+") +:name_minus %cstr8("-") +:name_mult %cstr8("*") +:name_eq %cstr8("=") +:name_lt %cstr8("<") +:name_gt %cstr8(">") +:name_quotient %cstr8("quotient") +:name_remainder %cstr8("remainder") +:name_bit_and %cstr8("bit-and") +:name_bit_or %cstr8("bit-or") +:name_bit_xor %cstr8("bit-xor") +:name_bit_not %cstr8("bit-not") +:name_arith_shift %cstr8("arithmetic-shift") +:name_apply %cstr8("apply") +:name_make_bv %cstr8("make-bytevector") +:name_bv_length %cstr8("bytevector-length") +:name_string_length %cstr8("string-length") +:name_bv_u8_ref %cstr8("bytevector-u8-ref") +:name_bv_u8_set %cstr8("bytevector-u8-set!") +:name_bv_copy %cstr8("bytevector-copy") +:name_bv_copy_b %cstr8("bytevector-copy!") +:name_bv_eq %cstr8("bytevector=?") + +:name_sys_read %cstr8("sys-read") +:name_sys_write %cstr8("sys-write") +:name_sys_close %cstr8("sys-close") +:name_sys_openat %cstr8("sys-openat") +:name_sys_clone %cstr8("sys-clone") +:name_sys_execve %cstr8("sys-execve") +:name_sys_waitid %cstr8("sys-waitid") +:name_sys_argv %cstr8("sys-argv") +:name_eof %cstr8("eof") +:name_eofq %cstr8("eof?") +:name_values %cstr8("values") +:name_call_with_values %cstr8("call-with-values") +:name_display %cstr8("display") +:name_write %cstr8("write") +:name_error %cstr8("error") +:name_format %cstr8("format") +:name_heap_mark %cstr8("heap-mark") +:name_heap_rewind_bang %cstr8("heap-rewind!") +:name_heap_usage %cstr8("heap-usage") +:name_use_scratch_heap_bang %cstr8("use-scratch-heap!") +:name_use_main_heap_bang %cstr8("use-main-heap!") +:name_reset_scratch_heap_bang %cstr8("reset-scratch-heap!") +:name_heap_in_main_q %cstr8("heap-in-main?") +:name_heap_in_current_q %cstr8("heap-in-current?") +:name_recordq %cstr8("record?") +:name_record_td %cstr8("record-td") +:name_record_ref %cstr8("record-ref") +:name_record_set_bang %cstr8("record-set!") +:name_make_record_td %cstr8("make-record/td") +:name_td_nfields %cstr8("td-nfields") +:name_td_name %cstr8("td-name") +:name_tagged_value %cstr8("tagged-value") +:name_peek_u8 %cstr8("peek-u8") +:name_current_heap_next %cstr8("current-heap-next") # Writer string constants. Lengths are hard-coded at the str_putn call -# sites (write_to_bv branches). No NUL needed in the source bytes -- -# str_putn takes (ptr, n). -:str_false "#f" '000000000000' -:str_true "#t" '000000000000' -:str_nil "()" '000000000000' -:str_unspec "#!unspec" '0000000000000000' -:str_unbound "#!unbound" '00000000000000' -:str_eof "#!eof" '000000' -:str_closure "#<closure>" '000000000000' -:str_prim "#<prim>" '00' -:str_td "#<rec-type>" '0000000000' -:str_rec "#<record>" '00000000000000' -:str_unknown "#<unknown>" '000000000000' -:str_error_prefix "scheme1: error: " +# sites (write_to_bv branches). They are emitted through cstr8 so the +# labels remain aligned and are also safe as C strings if reused later. +:str_false %cstr8("#f") +:str_true %cstr8("#t") +:str_nil %cstr8("()") +:str_unspec %cstr8("#!unspec") +:str_unbound %cstr8("#!unbound") +:str_eof %cstr8("#!eof") +:str_closure %cstr8("#<closure>") +:str_prim %cstr8("#<prim>") +:str_td %cstr8("#<rec-type>") +:str_rec %cstr8("#<record>") +:str_unknown %cstr8("#<unknown>") +:str_error_prefix %cstr8("scheme1: error: ") # Primitive registration table. Each entry: 8-byte name_ptr (4-byte label # ref + 4 pad), 8-byte name_len, 8-byte entry_label (4 ref + 4 pad). @@ -6339,36 +6331,36 @@ &name_call_with_values %(0) $(16) &prim_call_with_values_entry %(0) :prim_table_end -;; Each :msg_ entry must be an exact multiple of 8 bytes so that entries -;; stay 8-aligned (text + M0-auto-NUL + '0a' + zero padding). -;; len+2+pad == 0 mod 8 (len = text chars, 2 = NUL+'0a', pad = trailing zeros). -:msg_usage "scheme1: usage: scheme1 SOURCE.scm" '0a' '00000000' ;; 34+1+1+4=40 -:msg_load_fail "scheme1: failed to read source" '0a' ;; 30+1+1+0=32 -:msg_symtab_full "scheme1: symbol table full" '0a' '00000000' ;; 26+1+1+4=32 -:msg_unexp_rparen "scheme1: unexpected ')'" '0a' '00000000000000' ;; 23+1+1+7=32 -:msg_bad_hash "scheme1: bad #-syntax" '0a' '00' ;; 21+1+1+1=24 -:msg_unexp_eof "scheme1: unexpected EOF in form" '0a' '00000000000000' ;; 31+1+1+7=40 -:msg_unterm_list "scheme1: unterminated list" '0a' '00000000' ;; 26+1+1+4=32 -:msg_unbound "scheme1: unbound variable" '0a' '0000000000' ;; 25+1+1+5=32 -:msg_not_proc "scheme1: not a procedure" '0a' '000000000000' ;; 24+1+1+6=32 -:msg_heap_full "scheme1: heap exhausted" '0a' '00000000000000' ;; 23+1+1+7=32 -:msg_scratch_full "scheme1: scratch exhausted" '0a' '00000000' ;; 26+1+1+4=32 -:msg_readbuf_full "scheme1: source buffer overflow" '0a' '00000000000000' ;; 31+1+1+7=40 -:msg_bv_oob "scheme1: bytevector index out of range" '0a' ;; 38+1+1+0=40 -:msg_unterm_string "scheme1: unterminated string literal" '0a' '0000' ;; 36+1+1+2=40 -:msg_bad_escape "scheme1: bad string escape" '0a' '00000000' ;; 26+1+1+4=32 -:msg_bad_char "scheme1: bad #\\ character literal" '0a' '00000000' ;; 34+1+1+4=40 -:msg_bad_number "scheme1: bad number literal" '0a' '000000' ;; 27+1+1+3=32 -:msg_bad_ident "scheme1: bad identifier" '0a' '00000000000000' ;; 23+1+1+7=32 -:msg_internal_define "scheme1: internal define is not supported" '0a' '0000000000' ;; 41+1+1+5=48 -:msg_pmatch_no_match "scheme1: pmatch: no clause matched" '0a' '00000000' ;; 34+1+1+4=40 -:msg_bad_unquote_pattern "scheme1: pmatch: malformed ,-pattern" '0a' '0000' ;; 36+1+1+2=40 - -:name_ch_tab "tab" '00000000' ;; 3+1+4=8 -:name_ch_null "null" '000000' ;; 4+1+3=8 -:name_ch_space "space" '0000' ;; 5+1+2=8 -:name_ch_return "return" '00' ;; 6+1+1=8 -:name_ch_newline "newline" ;; 7+1+0=8 +;; Error messages are NUL-terminated C strings. The embedded newline +;; keeps the old stderr formatting; runtime_error's panic path appends +;; another newline, which shell command substitution trims in tests. +:msg_usage %cstr8("scheme1: usage: scheme1 SOURCE.scm\n") +:msg_load_fail %cstr8("scheme1: failed to read source\n") +:msg_symtab_full %cstr8("scheme1: symbol table full\n") +:msg_unexp_rparen %cstr8("scheme1: unexpected ')'\n") +:msg_bad_hash %cstr8("scheme1: bad #-syntax\n") +:msg_unexp_eof %cstr8("scheme1: unexpected EOF in form\n") +:msg_unterm_list %cstr8("scheme1: unterminated list\n") +:msg_unbound %cstr8("scheme1: unbound variable\n") +:msg_not_proc %cstr8("scheme1: not a procedure\n") +:msg_heap_full %cstr8("scheme1: heap exhausted\n") +:msg_scratch_full %cstr8("scheme1: scratch exhausted\n") +:msg_readbuf_full %cstr8("scheme1: source buffer overflow\n") +:msg_bv_oob %cstr8("scheme1: bytevector index out of range\n") +:msg_unterm_string %cstr8("scheme1: unterminated string literal\n") +:msg_bad_escape %cstr8("scheme1: bad string escape\n") +:msg_bad_char %cstr8("scheme1: bad #\\ character literal\n") +:msg_bad_number %cstr8("scheme1: bad number literal\n") +:msg_bad_ident %cstr8("scheme1: bad identifier\n") +:msg_internal_define %cstr8("scheme1: internal define is not supported\n") +:msg_pmatch_no_match %cstr8("scheme1: pmatch: no clause matched\n") +:msg_bad_unquote_pattern %cstr8("scheme1: pmatch: malformed ,-pattern\n") + +:name_ch_tab %cstr8("tab") +:name_ch_null %cstr8("null") +:name_ch_space %cstr8("space") +:name_ch_return %cstr8("return") +:name_ch_newline %cstr8("newline") # ========================================================================= # BSS arena table diff --git a/scripts/disasm-elf.sh b/scripts/disasm-elf.sh @@ -1,5 +1,5 @@ #!/bin/sh -## disasm-elf.sh — disassemble a hex2-emitted ELF with llvm-objdump. +## disasm-elf.sh — disassemble a hex2pp-emitted ELF with llvm-objdump. ## ## Our seed ELF.hex2 sets ph_memsz to 512 MB (so the BSS region past ## ELF_end is mappable), but ph_filesz is just the on-disk size. @@ -18,9 +18,10 @@ ## override and see the header bytes. ## ## boot-build-p1*.sh writes a one-line sidecar at <elf>.workdir pointing -## at build/$ARCH/.work/<src-without-ext>/, where prog.hex2 lives. When -## that sidecar is present we extract a label map via scripts/m1-symbols.py -## and: +## at build/$ARCH/.work/<src-without-ext>/. P1pp builds store +## expanded.hex2pp there; legacy raw-P1 seed builds store prog.hex2. +## When that sidecar is present we extract a label map via +## scripts/m1-symbols.py and: ## - default --stop-address to :_text_end if that sentinel label is ## present, so trailing rodata doesn't decode as bogus instructions ## - inject "<label>:" headers and rewrite "<PT_LOAD#0+0xNNN>" xrefs @@ -86,10 +87,10 @@ if [ "$have_start" -eq 0 ]; then set -- "--start-address=0x$(printf '%x' "$ENTRY")" "$@" fi -# Locate prog.hex2 via the <elf>.workdir sidecar produced by -# boot-build-p1*.sh. The sidecar holds a repo-relative path -# (build/$ARCH/.work/<src>/), so resolve it against the repo root -# inferred from this script's location — works regardless of cwd. +# Locate expanded.hex2pp (new P1pp path) or prog.hex2 (legacy raw-P1 +# path) via the <elf>.workdir sidecar produced by boot-build-p1*.sh. +# The sidecar holds a repo-relative path (build/$ARCH/.work/<src>/), so +# resolve it against the repo root inferred from this script's location. HERE=$(dirname "$0") REPO_ROOT=$(cd "$HERE/.." && pwd) HEX2="" @@ -99,10 +100,12 @@ if [ -e "$ELF.workdir" ]; then /*) ;; # absolute, leave alone *) workdir="$REPO_ROOT/$workdir" ;; esac - if [ -e "$workdir/prog.hex2" ]; then + if [ -e "$workdir/expanded.hex2pp" ]; then + HEX2="$workdir/expanded.hex2pp" + elif [ -e "$workdir/prog.hex2" ]; then HEX2="$workdir/prog.hex2" else - echo "disasm-elf: $ELF.workdir -> $workdir, but no prog.hex2 there" >&2 + echo "disasm-elf: $ELF.workdir -> $workdir, but no expanded.hex2pp or prog.hex2 there" >&2 fi elif [ "${NO_LABELS:-0}" != "1" ]; then echo "disasm-elf: no $ELF.workdir sidecar; rebuild for label annotation" >&2 diff --git a/scripts/m1-symbols.py b/scripts/m1-symbols.py @@ -1,21 +1,29 @@ #!/usr/bin/env python3 -"""m1-symbols.py — extract labels from a hex2 file and annotate disassembly. +"""m1-symbols.py — extract labels from a hex2/hex2pp file and annotate disassembly. -The hex2 produced by M0 in this project uses a small grammar: +The expanded hex2pp produced by M1pp in this project uses a small grammar: :LABEL declares LABEL at the current byte offset (zero bytes) - &LABEL 4-byte absolute address reference (low 32 bits of LABEL) - 'XXXX... raw byte literal; (len(token)-1)/2 bytes (no closing quote) + !LABEL 1-byte relative label reference + @LABEL/$LABEL 2-byte label reference + ~LABEL 3-byte relative label reference + %LABEL/&LABEL ptrsize-byte label reference (4 by default) XXXX... bare hex; len(token)/2 bytes - # ... comment to end-of-line + .align N pads to N-byte boundary + .fill N B emits N copies of B + # ... / ; ... comment to end-of-line + +Legacy prog.hex2 files from the seed M0 path are still accepted; their +'XXXX... raw byte literals are counted as before. Label addresses = BASE + HEADER + cumulative byte offset, where BASE is the ELF load address (0x600000) and HEADER is the size of the on-disk ELF header -+ phdr that sits in front of M0's output (0x78 bytes for our seed ELF). ++ phdr that sits in front of expanded hex2pp/M0 output (0x78 bytes for our +seed ELF). Subcommands: - map <prog.hex2> [--base 0x600000] [--header 0x78] [--ref-size 4] + map <expanded.hex2pp|prog.hex2> [--base 0x600000] [--header 0x78] Print "0xADDR LABEL" lines, sorted by address. annotate <map> @@ -28,7 +36,8 @@ Subcommands: delta=0). Pairs with `%trace`'s stderr output: paste a trace address and get the enclosing function. With --elf, locates the sibling <ELF>.workdir sidecar (written by boot-build-p1*.sh) to - find prog.hex2, so you don't have to know the .work path. + find expanded.hex2pp or legacy prog.hex2, so you don't have to + know the .work path. Reads addresses from stdin if none are passed positionally. """ @@ -37,18 +46,61 @@ import re import sys +REF_WIDTH = { + '!': 1, + '@': 2, + '$': 2, + '~': 3, +} + + +def _parse_int(tok): + return int(tok, 0) + + def parse_hex2(path, ref_size=4): """Yield (offset, label) pairs in declaration order.""" offset = 0 + ptrsize = ref_size seen_unknown = set() with open(path) as f: for lineno, line in enumerate(f, 1): - line = line.split('#', 1)[0] - for tok in line.split(): + line = line.split('#', 1)[0].split(';', 1)[0] + toks = line.split() + i = 0 + while i < len(toks): + tok = toks[i] if tok.startswith(':'): yield offset, tok[1:] - elif tok.startswith('&'): - offset += ref_size + elif tok in ('.scope', '.endscope'): + pass + elif tok == '.ptrsize': + if i + 1 >= len(toks): + sys.stderr.write(f"{path}:{lineno}: missing .ptrsize value\n") + else: + ptrsize = _parse_int(toks[i + 1]) + i += 1 + elif tok == '.align': + if i + 1 >= len(toks): + sys.stderr.write(f"{path}:{lineno}: missing .align value\n") + else: + n = _parse_int(toks[i + 1]) + offset += (-offset) % n + # Optional pad pattern is a source token but does not + # change the number of emitted bytes beyond the pad. + if i + 2 < len(toks) and re.fullmatch(r'[0-9A-Fa-f]+', toks[i + 2]): + i += 1 + i += 1 + elif tok == '.fill': + if i + 2 >= len(toks): + sys.stderr.write(f"{path}:{lineno}: missing .fill args\n") + else: + offset += _parse_int(toks[i + 1]) + i += 2 + elif tok[:1] in ('%', '&'): + offset += ptrsize + elif tok[:1] in REF_WIDTH: + offset += REF_WIDTH[tok[:1]] elif tok.startswith("'"): offset += (len(tok) - 1) // 2 elif re.fullmatch(r'[0-9A-Fa-f]+', tok): @@ -63,6 +115,7 @@ def parse_hex2(path, ref_size=4): f"{path}:{lineno}: skipping unrecognized token " f"{tok!r} (subsequent same-prefix tokens silenced)\n" ) + i += 1 def cmd_map(args): @@ -183,10 +236,11 @@ def _resolve_hex2_from_elf(elf_path): repo_root = os.path.abspath( os.path.join(os.path.dirname(__file__), '..')) workdir = os.path.join(repo_root, workdir) - hex2 = os.path.join(workdir, 'prog.hex2') - if not os.path.exists(hex2): - sys.exit(f"m1-symbols: {sidecar} -> {workdir}, but no prog.hex2 there") - return hex2 + for name in ('expanded.hex2pp', 'prog.hex2'): + hex2 = os.path.join(workdir, name) + if os.path.exists(hex2): + return hex2 + sys.exit(f"m1-symbols: {sidecar} -> {workdir}, but no expanded.hex2pp or prog.hex2 there") def _build_map_from_args(args): @@ -241,8 +295,8 @@ def main(): help='resolve addrs to nearest preceding label') src = p_lk.add_mutually_exclusive_group(required=True) src.add_argument('--elf', help='ELF path; uses <ELF>.workdir sidecar ' - 'to find prog.hex2') - src.add_argument('--hex2', help='prog.hex2 path') + 'to find expanded.hex2pp or prog.hex2') + src.add_argument('--hex2', help='expanded.hex2pp or prog.hex2 path') src.add_argument('--map', help='pre-built address->label map ' '(from `m1-symbols.py map`)') p_lk.add_argument('--base', type=lambda s: int(s, 0), default=0x600000)