From 846f441e3a487ec9dabdba983774d98ed1829b36 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Sun, 20 Sep 2026 09:33:20 +0800 Subject: [PATCH] =?UTF-8?q?stage2=20=E5=A4=A7=E9=87=8F=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BD=BF=E5=85=B6=E8=87=AA=E4=B8=BE=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E6=97=B6=E9=97=B4=E5=A4=A7=E5=B9=85=E7=BC=A9=E7=9F=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nob.c | 2 + stage0/spl_cli.c | 11 + stage0/spl_mcode.h | 3 + stage0/spl_syscall.c | 641 +++++++++++++++++++++++++++++++++++++ stage0/spl_vm.c | 494 ++++++++++++++++------------ stage0/spl_vm.h | 6 +- stage1/ir_opt.c | 612 +++++++++++++++++++++++++++++++++++ stage1/ir_opt.h | 11 + stage1/spl_ir2vm.c | 353 ++++++++++++++++++-- stage1/spl_ir2vm.h | 3 +- stage1/spl_sema.c | 21 +- stage1/splc0.c | 37 ++- stage1/vm_opt.c | 165 ++++++++++ stage1/vm_opt.h | 11 + stage2/ast.spl | 7 +- stage2/ast2ir.spl | 8 +- stage2/attr.spl | 6 +- stage2/def.spl | 6 +- stage2/intrin.spl | 5 +- stage2/ir.spl | 58 +--- stage2/ir2vm.spl | 14 +- stage2/ir_builder.spl | 4 +- stage2/lang_type.spl | 10 +- stage2/layout.spl | 6 +- stage2/lexer.spl | 7 +- stage2/mcode.spl | 97 ++++-- stage2/parser.spl | 16 +- stage2/scope.spl | 10 +- stage2/sema.spl | 11 +- stage2/sys/time.spl | 4 + stage2/token.spl | 88 +++-- stage2/type_table.spl | 17 +- stage2/utils/byte_view.spl | 10 +- stage2/utils/map.spl | 235 +++----------- stage2/utils/memory.spl | 28 +- stage2/utils/set.spl | 16 +- stage2/utils/source.spl | 4 +- stage2/utils/vec.spl | 216 +++---------- 38 files changed, 2418 insertions(+), 835 deletions(-) create mode 100644 stage1/ir_opt.c create mode 100644 stage1/ir_opt.h create mode 100644 stage1/vm_opt.c create mode 100644 stage1/vm_opt.h diff --git a/nob.c b/nob.c index f7cffef..7cd1c9a 100644 --- a/nob.c +++ b/nob.c @@ -42,6 +42,8 @@ static const char *splc0_srcs[] = { "stage1/spl_ast2ir.c", "stage1/spl_layout.c", "stage1/spl_ir2vm.c", + "stage1/ir_opt.c", + "stage1/vm_opt.c", "stage0/spl_mcode.c", }; /* clang-format on */ diff --git a/stage0/spl_cli.c b/stage0/spl_cli.c index 1a04cdf..d5b4ab4 100644 --- a/stage0/spl_cli.c +++ b/stage0/spl_cli.c @@ -33,6 +33,7 @@ typedef struct { int profile; int profile_interval; const char *profile_out; + int stats; const char *entry; const char *path; /* file.sir */ const char **args; /* spl 程序参数(file.sir 之后) */ @@ -48,6 +49,7 @@ static void usage(void) { " --trace print every instruction\n" " --profile[=N] native sampling profiler (every N insns, default 10000)\n" " --profile-out

profile output prefix (default build/profile)\n" + " --stats print executed instructions / call count at exit\n" " -h, --help show help\n"); } @@ -72,6 +74,8 @@ static int parse_args(int argc, const char **argv, cli_opts_t *o) { o->trace = 1; } else if (strcmp(a, "--disasm") == 0) { o->disasm = 1; + } else if (strcmp(a, "--stats") == 0) { + o->stats = 1; } else if (strcmp(a, "--profile") == 0) { o->profile = 1; } else if (strncmp(a, "--profile=", 10) == 0) { @@ -656,6 +660,8 @@ int main(int argc, const char **argv) { if (o.debug) { fprintf(stderr, "spl_cli: debug mode on\n"); spl_vm_set_debug(&vm, 1); + } else { + spl_vm_set_debug(&vm, 0); } if (o.trace) { fprintf(stderr, "spl_cli: trace mode on\n"); @@ -710,6 +716,11 @@ int main(int argc, const char **argv) { fprintf(stderr, "spl_cli: hit breakpoint (run with -g to debug)\n"); } + if (o.stats) { + fprintf(stderr, "spl_cli: stats steps=%llu calls=%llu\n", (unsigned long long)vm.steps, + (unsigned long long)vm.ncalls); + } + if (o.profile) { const char *prefix = o.profile_out ? o.profile_out : "build/profile"; char folded[1024]; diff --git a/stage0/spl_mcode.h b/stage0/spl_mcode.h index ae7e0fb..d0d0ced 100644 --- a/stage0/spl_mcode.h +++ b/stage0/spl_mcode.h @@ -103,6 +103,7 @@ typedef enum { #define X(opcode, name, argc, pop, push, desc) opcode, SPL_OPCODES(X) #undef X + SPL_OPCODE_COUNT, } spl_vm_opcode_t; /* @@ -191,6 +192,8 @@ void spl_prog_init(spl_prog_t *prog); void spl_prog_drop(spl_prog_t *prog); void spl_prog_dump(spl_prog_t *prog); + + int spl_prog_load_from_file(const char *fname, spl_prog_t *prog); int spl_prog_store_to_file(const char *fname, spl_prog_t *prog); diff --git a/stage0/spl_syscall.c b/stage0/spl_syscall.c index ef6d0a3..33a96fd 100644 --- a/stage0/spl_syscall.c +++ b/stage0/spl_syscall.c @@ -348,6 +348,10 @@ static spl_vm_val_t vm_timestamp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { if (!_vm) return 0; return (spl_vm_val_t)_vm->steps; + case 5: + if (!_vm) + return 0; + return (spl_vm_val_t)_vm->ncalls; case 4: return has_time ? (spl_vm_val_t)((unsigned long long)ts.tv_sec * 1000000000ull + (unsigned long long)ts.tv_nsec) @@ -493,6 +497,623 @@ SYSCALL_1(vm_run, spl_vm_t *, spl_vm_run_until(a1, 0)) * prog->natives against known syscall names and hooks up impl_fn. * ================================================================= */ +/* ================================================================= + * Native std containers (spike: Vec valid/push_raw/get) + * + * 布局镜像 stage2/utils/vec.spl 的 Vec: + * raw, data, len, cap, elem_size, elem_align (均为机器字) + * 结构体按值传递/复制由 SPL 负责,native 只按指针操作。 + * ================================================================= */ + +typedef struct { + uintptr_t raw; + uintptr_t data; + uintptr_t len; + uintptr_t cap; + uintptr_t elem_size; + uintptr_t elem_align; +} spl_vec_t; + +static int spl_vec_is_valid(const spl_vec_t *v) { + if (v->elem_size == 0) + return 0; + uintptr_t a = v->elem_align; + if (a == 0 || (a & (a - 1)) != 0) + return 0; + if (v->len > v->cap) + return 0; + if (v->cap == 0) + return v->raw == 0 && v->data == 0 && v->len == 0; + if (v->raw == 0 || v->data == 0) + return 0; + return (v->data & (a - 1)) == 0; +} + +static spl_vm_val_t vm_vec_valid(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_valid", 1); + const spl_vec_t *v = (const spl_vec_t *)(uintptr_t)args[0]; + return (spl_vm_val_t)(v ? spl_vec_is_valid(v) : 0); +} + +static spl_vm_val_t vm_vec_push_raw(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_push_raw", 2); + spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0]; + const void *elem = (const void *)(uintptr_t)args[1]; + if (!v || !elem) + return 0; + if (v->len < v->cap) { + memcpy((void *)(v->data + v->len * v->elem_size), elem, v->elem_size); + v->len++; + return 1; + } + return 0; +} + +/* out 接收元素指针;返回 0 成功,1 无效参数,2 越界。 */ +static int spl_vec_reserve_raw(spl_vec_t *v, uintptr_t need); + +static spl_vm_val_t vm_vec_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_push", 2); + spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0]; + const void *elem = (const void *)(uintptr_t)args[1]; + if (!v || !elem || !spl_vec_is_valid(v)) + return 1; + if (v->len < v->cap) { + memcpy((void *)(v->data + v->len * v->elem_size), elem, v->elem_size); + v->len++; + return 0; + } + int rc = spl_vec_reserve_raw(v, v->len + 1); + if (rc) + return rc; + memmove((void *)(v->data + v->len * v->elem_size), elem, v->elem_size); + v->len++; + return 0; +} + +static spl_vm_val_t vm_vec_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_get", 3); + const spl_vec_t *v = (const spl_vec_t *)(uintptr_t)args[0]; + uintptr_t index = (uintptr_t)args[1]; + uintptr_t *out = (uintptr_t *)(uintptr_t)args[2]; + if (!v || !out) + return 1; + if (!spl_vec_is_valid(v)) + return 1; + if (index >= v->len) + return 2; + *out = v->data + index * v->elem_size; + return 0; +} + +/* 错误码统一:0 ok / 1 InvalidArgument / 2 OutOfRange / 3 Overflow / 4 InvalidAlignment */ + +static int spl_align_ok(uintptr_t a) { return a != 0 && (a & (a - 1)) == 0; } + +static int spl_grow_capacity(uintptr_t current, uintptr_t min_cap, uintptr_t need, + uintptr_t *out) { + uintptr_t cap = current < min_cap ? min_cap : current; + uintptr_t limit = ~(uintptr_t)0; + while (cap < need) { + if (cap > limit / 2) { + cap = need; + break; + } + cap = cap * 2; + } + *out = cap; + return 0; +} + +static int spl_vec_allocate(spl_vec_t *out, uintptr_t capacity, uintptr_t elem_size, + uintptr_t elem_align) { + if (elem_size == 0) + return 1; + if (!spl_align_ok(elem_align)) + return 4; + out->raw = 0; + out->data = 0; + out->len = 0; + out->cap = 0; + out->elem_size = elem_size; + out->elem_align = elem_align; + if (capacity == 0) + return 0; + if (capacity > ~(uintptr_t)0 / elem_size) + return 3; + uintptr_t bytes = capacity * elem_size; + uintptr_t mask = elem_align - 1; + if (bytes > ~(uintptr_t)0 - mask) + return 3; + uintptr_t total = bytes + mask; + void *raw = malloc(total); + if (!raw) + return 3; + uintptr_t addr = (uintptr_t)raw; + if (addr > ~(uintptr_t)0 - mask) { + free(raw); + return 3; + } + out->raw = addr; + out->data = (addr + mask) & ~mask; + out->cap = capacity; + return 0; +} + +static spl_vm_val_t vm_vec_allocate(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_allocate", 4); + spl_vec_t *out = (spl_vec_t *)(uintptr_t)args[0]; + if (!out) + return 1; + return (spl_vm_val_t)spl_vec_allocate(out, (uintptr_t)args[1], (uintptr_t)args[2], + (uintptr_t)args[3]); +} + +static int spl_vec_reserve_raw(spl_vec_t *v, uintptr_t need) { + if (need <= v->cap) + return 0; + uintptr_t new_cap = 0; + spl_grow_capacity(v->cap, 8, need, &new_cap); + spl_vec_t fresh; + int rc = spl_vec_allocate(&fresh, new_cap, v->elem_size, v->elem_align); + if (rc) + return rc; + uintptr_t used = 0; + if (v->len != 0) { + if (v->len > ~(uintptr_t)0 / v->elem_size) { + free((void *)fresh.raw); + return 3; + } + used = v->len * v->elem_size; + } + if (used != 0) + memcpy((void *)fresh.data, (void *)v->data, used); + fresh.len = v->len; + uintptr_t old = v->raw; + *v = fresh; + if (old) + free((void *)old); + return 0; +} + +static spl_vm_val_t vm_vec_reserve_raw(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_reserve_raw", 2); + spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0]; + if (!v) + return 1; + return (spl_vm_val_t)spl_vec_reserve_raw(v, (uintptr_t)args[1]); +} + +static spl_vm_val_t vm_vec_append(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_append", 3); + spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0]; + const void *elems = (const void *)(uintptr_t)args[1]; + uintptr_t count = (uintptr_t)args[2]; + if (!v || !spl_vec_is_valid(v)) + return 1; + if (count == 0) + return 0; + if (!elems) + return 1; + if (count > ~(uintptr_t)0 / v->elem_size) + return 3; + uintptr_t copy_bytes = count * v->elem_size; + if (v->len > ~(uintptr_t)0 - count) + return 3; + uintptr_t new_len = v->len + count; + uintptr_t used = v->len * v->elem_size; + int source_inside = 0; + uintptr_t source_offset = 0; + if (used != 0) { + uintptr_t base = v->data; + uintptr_t source = (uintptr_t)elems; + if (source >= base && source - base < used) { + source_offset = source - base; + if (copy_bytes > used - source_offset) + return 2; + source_inside = 1; + } + } + int rc = spl_vec_reserve_raw(v, new_len); + if (rc) + return rc; + if (source_inside) + elems = (const void *)(v->data + source_offset); + memmove((void *)(v->data + used), elems, copy_bytes); + v->len = new_len; + return 0; +} + +static spl_vm_val_t vm_vec_set(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_set", 3); + spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0]; + uintptr_t index = (uintptr_t)args[1]; + const void *elem = (const void *)(uintptr_t)args[2]; + if (!v || !elem || !spl_vec_is_valid(v)) + return 1; + if (index >= v->len) + return 2; + memmove((void *)(v->data + index * v->elem_size), elem, v->elem_size); + return 0; +} + +static spl_vm_val_t vm_vec_pop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_pop", 2); + spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0]; + void *out = (void *)(uintptr_t)args[1]; + if (!v || !out || !spl_vec_is_valid(v)) + return 1; + if (v->len == 0) + return 2; + memmove(out, (void *)(v->data + (v->len - 1) * v->elem_size), v->elem_size); + v->len--; + return 0; +} + +static spl_vm_val_t vm_vec_clone(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_clone", 2); + spl_vec_t *out = (spl_vec_t *)(uintptr_t)args[0]; + const spl_vec_t *src = (const spl_vec_t *)(uintptr_t)args[1]; + if (!out || !src || !spl_vec_is_valid(out) || !spl_vec_is_valid(src)) + return 1; + if (out->elem_size != src->elem_size || out->elem_align != src->elem_align) + return 1; + spl_vec_t fresh; + fresh.raw = 0; + fresh.data = 0; + fresh.len = 0; + fresh.cap = 0; + fresh.elem_size = src->elem_size; + fresh.elem_align = src->elem_align; + int rc = spl_vec_reserve_raw(&fresh, src->len); + if (rc) + return rc; + uintptr_t bytes = src->len * src->elem_size; + if (bytes != 0) + memcpy((void *)fresh.data, (void *)src->data, bytes); + fresh.len = src->len; + if (out->raw) + free((void *)out->raw); + *out = fresh; + return 0; +} + +static spl_vm_val_t vm_vec_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_vec_drop", 1); + spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0]; + if (!v) + return 0; + uintptr_t es = v->elem_size; + uintptr_t ea = v->elem_align; + if (v->raw) + free((void *)v->raw); + v->raw = 0; + v->data = 0; + v->len = 0; + v->cap = 0; + v->elem_size = es; + v->elem_align = ea; + return 0; +} + +static spl_vm_val_t vm_memmove(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_memmove", 3); + void *dst = (void *)(uintptr_t)args[0]; + const void *src = (const void *)(uintptr_t)args[1]; + size_t size = (size_t)args[2]; + if (size == 0) + return (spl_vm_val_t)(uintptr_t)dst; + ADDRCHECK(_vm, dst, size, "vm_memmove(dst)"); + ADDRCHECK(_vm, src, size, "vm_memmove(src)"); + memmove(dst, src, size); + return (spl_vm_val_t)(uintptr_t)dst; +} + +/* ================================================================= + * Native Map(开放寻址 + 墓碑),布局镜像 stage2/utils/map.spl 的 Map。 + * hash_kind: 0 = usize;1 = ByteView(按内容);2 = 常量(仅测试用)。 + * ================================================================= */ + +typedef struct { + spl_vec_t keys; + spl_vec_t vals; + spl_vec_t states; + uintptr_t size; + uintptr_t key_size; + uintptr_t val_size; + uintptr_t hash_kind; +} spl_map_t; + +static void spl_vec_release(spl_vec_t *v) { + uintptr_t es = v->elem_size; + uintptr_t ea = v->elem_align; + if (v->raw) + free((void *)v->raw); + v->raw = 0; + v->data = 0; + v->len = 0; + v->cap = 0; + v->elem_size = es; + v->elem_align = ea; +} + +static uintptr_t spl_hash_usize_value(uintptr_t value) { + uintptr_t prime = 1099511628211ull; + uintptr_t h = value; + h = (h ^ (h >> 30)) * prime; + h = h ^ (h >> 27); + h = h * prime; + h = h ^ (h >> 31); + if (h == 0) + return prime; + return h; +} + +static uintptr_t spl_hash_bytes(const void *data, uintptr_t len) { + const unsigned char *p = (const unsigned char *)data; + uintptr_t h = 14695981039346656037ull; + uintptr_t prime = 1099511628211ull; + for (uintptr_t i = 0; i < len; i++) + h = (h ^ (uintptr_t)p[i]) * prime; + return h; +} + +static uintptr_t spl_map_hash(const spl_map_t *m, const void *key) { + if (m->hash_kind == 0) + return spl_hash_usize_value(*(const uintptr_t *)key); + if (m->hash_kind == 2) + return 3; + const uintptr_t *v = (const uintptr_t *)key; /* ByteView { ptr, len } */ + return spl_hash_bytes((const void *)v[0], v[1]); +} + +static int spl_map_eq(const spl_map_t *m, const void *a, const void *b) { + if (m->hash_kind == 0 || m->hash_kind == 2) + return *(const uintptr_t *)a == *(const uintptr_t *)b; + const uintptr_t *x = (const uintptr_t *)a; + const uintptr_t *y = (const uintptr_t *)b; + if (x[1] != y[1]) + return 0; + if (x[1] == 0) + return 1; + return memcmp((const void *)x[0], (const void *)y[0], x[1]) == 0; +} + +static int spl_map_valid(const spl_map_t *m) { + if (m->key_size == 0 || m->val_size == 0) + return 0; + if (m->keys.len != m->states.len || m->vals.len != m->states.len) + return 0; + if (m->size > m->states.len) + return 0; + return 1; +} + +static uintptr_t spl_map_find_slot(const spl_map_t *m, const void *key) { + if (m->states.cap == 0) + return ~(uintptr_t)0; + uintptr_t mask = m->states.cap - 1; + uintptr_t i = spl_map_hash(m, key) & mask; + unsigned char *st = (unsigned char *)m->states.data; + uintptr_t probes = 0; + while (probes < m->states.cap && st[i] != 0) { + if (st[i] == 1 && spl_map_eq(m, (const void *)(m->keys.data + i * m->key_size), key)) + return i; + i = (i + 1) & mask; + probes++; + } + return ~(uintptr_t)0; +} + +static void spl_map_place(spl_map_t *m, const void *key, const void *val) { + uintptr_t mask = m->states.cap - 1; + uintptr_t i = spl_map_hash(m, key) & mask; + unsigned char *st = (unsigned char *)m->states.data; + uintptr_t first_deleted = ~(uintptr_t)0; + uintptr_t probes = 0; + while (probes < m->states.cap && st[i] != 0) { + if (st[i] == 2 && first_deleted == ~(uintptr_t)0) + first_deleted = i; + i = (i + 1) & mask; + probes++; + } + if (first_deleted != ~(uintptr_t)0) + i = first_deleted; + memcpy((void *)(m->keys.data + i * m->key_size), key, m->key_size); + memcpy((void *)(m->vals.data + i * m->val_size), val, m->val_size); + st[i] = 1; + m->size++; +} + +static int spl_map_reserve(spl_map_t *m, uintptr_t need) { + if (!spl_map_valid(m)) + return 1; + if (need <= m->states.cap) + return 0; + uintptr_t new_cap = 0; + spl_grow_capacity(m->states.cap, 8, need, &new_cap); + + spl_map_t fresh = *m; + fresh.keys.raw = 0; + fresh.keys.data = 0; + fresh.keys.len = 0; + fresh.keys.cap = 0; + fresh.vals.raw = 0; + fresh.vals.data = 0; + fresh.vals.len = 0; + fresh.vals.cap = 0; + fresh.states.raw = 0; + fresh.states.data = 0; + fresh.states.len = 0; + fresh.states.cap = 0; + fresh.size = 0; + + int rc = spl_vec_reserve_raw(&fresh.keys, new_cap); + if (rc) + goto fail; + rc = spl_vec_reserve_raw(&fresh.vals, new_cap); + if (rc) + goto fail; + rc = spl_vec_reserve_raw(&fresh.states, new_cap); + if (rc) + goto fail; + fresh.keys.len = new_cap; + fresh.vals.len = new_cap; + fresh.states.len = new_cap; + memset((void *)fresh.states.data, 0, new_cap); + + for (uintptr_t i = 0; i < m->states.len; i++) { + if (((unsigned char *)m->states.data)[i] == 1) + spl_map_place(&fresh, (const void *)(m->keys.data + i * m->key_size), + (const void *)(m->vals.data + i * m->val_size)); + } + + spl_vec_release(&m->keys); + spl_vec_release(&m->vals); + spl_vec_release(&m->states); + *m = fresh; + return 0; +fail: + spl_vec_release(&fresh.keys); + spl_vec_release(&fresh.vals); + spl_vec_release(&fresh.states); + return rc; +} + +static spl_vm_val_t vm_bytes_eq(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_bytes_eq", 4); + const void *a = (const void *)(uintptr_t)args[0]; + uintptr_t alen = (uintptr_t)args[1]; + const void *b = (const void *)(uintptr_t)args[2]; + uintptr_t blen = (uintptr_t)args[3]; + if (alen != blen) + return 0; + if (alen == 0) + return 1; + if (!a || !b) + return 0; + return memcmp(a, b, alen) == 0; +} + +static spl_vm_val_t vm_map_valid(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_map_valid", 1); + const spl_map_t *m = (const spl_map_t *)(uintptr_t)args[0]; + return (spl_vm_val_t)(m ? spl_map_valid(m) : 0); +} + +static spl_vm_val_t vm_map_reserve(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_map_reserve", 2); + spl_map_t *m = (spl_map_t *)(uintptr_t)args[0]; + if (!m) + return 1; + return (spl_vm_val_t)spl_map_reserve(m, (uintptr_t)args[1]); +} + +static spl_vm_val_t vm_map_put(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_map_put", 3); + spl_map_t *m = (spl_map_t *)(uintptr_t)args[0]; + const void *key = (const void *)(uintptr_t)args[1]; + const void *val = (const void *)(uintptr_t)args[2]; + if (!m || !key || !val || !spl_map_valid(m)) + return 1; + uintptr_t existing = spl_map_find_slot(m, key); + if (existing != ~(uintptr_t)0) { + memcpy((void *)(m->vals.data + existing * m->val_size), val, m->val_size); + return 0; + } + if (m->states.cap == 0) { + int rc = spl_map_reserve(m, 8); + if (rc) + return rc; + } else { + if (m->size > ~(uintptr_t)0 - 1) + return 3; + uintptr_t next_size = m->size + 1; + if (next_size > ~(uintptr_t)0 / 128) + return 3; + uintptr_t scaled = next_size * 128; + if (scaled / m->states.cap >= 70) { + if (m->states.cap > ~(uintptr_t)0 / 2) + return 3; + int rc = spl_map_reserve(m, m->states.cap * 2); + if (rc) + return rc; + } + } + spl_map_place(m, key, val); + return 0; +} + +static spl_vm_val_t vm_map_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_map_get", 3); + spl_map_t *m = (spl_map_t *)(uintptr_t)args[0]; + const void *key = (const void *)(uintptr_t)args[1]; + void *out = (void *)(uintptr_t)args[2]; + if (!m || !key || !out || !spl_map_valid(m)) + return 1; + uintptr_t i = spl_map_find_slot(m, key); + if (i == ~(uintptr_t)0) + return 1; + memcpy(out, (void *)(m->vals.data + i * m->val_size), m->val_size); + return 0; +} + +static spl_vm_val_t vm_map_del(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_map_del", 2); + spl_map_t *m = (spl_map_t *)(uintptr_t)args[0]; + const void *key = (const void *)(uintptr_t)args[1]; + if (!m || !key || !spl_map_valid(m)) + return 1; + uintptr_t i = spl_map_find_slot(m, key); + if (i == ~(uintptr_t)0) + return 1; + ((unsigned char *)m->states.data)[i] = 2; + m->size--; + return 0; +} + +static spl_vm_val_t vm_map_clear(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_map_clear", 1); + spl_map_t *m = (spl_map_t *)(uintptr_t)args[0]; + if (!m) + return 0; + if (m->states.data && m->states.len) + memset((void *)m->states.data, 0, m->states.len); + m->size = 0; + return 0; +} + +static spl_vm_val_t vm_map_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_map_drop", 1); + spl_map_t *m = (spl_map_t *)(uintptr_t)args[0]; + if (!m) + return 0; + spl_vec_release(&m->keys); + spl_vec_release(&m->vals); + spl_vec_release(&m->states); + m->size = 0; + return 0; +} + void spl_syscall_register(spl_prog_t *prog) { static spl_vm_native_t table[] = { /* OS operations */ @@ -516,6 +1137,26 @@ void spl_syscall_register(spl_prog_t *prog) { {"vm_memcpy", 0, vm_memcpy}, {"vm_memcmp", 0, vm_memcmp}, {"vm_printf", 0, vm_printf}, + {"vm_vec_valid", 0, vm_vec_valid}, + {"vm_vec_push_raw", 0, vm_vec_push_raw}, + {"vm_vec_push", 0, vm_vec_push}, + {"vm_vec_get", 0, vm_vec_get}, + {"vm_vec_allocate", 0, vm_vec_allocate}, + {"vm_vec_reserve_raw", 0, vm_vec_reserve_raw}, + {"vm_vec_append", 0, vm_vec_append}, + {"vm_vec_set", 0, vm_vec_set}, + {"vm_vec_pop", 0, vm_vec_pop}, + {"vm_vec_clone", 0, vm_vec_clone}, + {"vm_vec_drop", 0, vm_vec_drop}, + {"vm_memmove", 0, vm_memmove}, + {"vm_bytes_eq", 0, vm_bytes_eq}, + {"vm_map_valid", 0, vm_map_valid}, + {"vm_map_reserve", 0, vm_map_reserve}, + {"vm_map_put", 0, vm_map_put}, + {"vm_map_get", 0, vm_map_get}, + {"vm_map_del", 0, vm_map_del}, + {"vm_map_clear", 0, vm_map_clear}, + {"vm_map_drop", 0, vm_map_drop}, {"vm_timestamp", 0, vm_timestamp}, /* VM operations (comptime) */ diff --git a/stage0/spl_vm.c b/stage0/spl_vm.c index 8f651ff..535c265 100644 --- a/stage0/spl_vm.c +++ b/stage0/spl_vm.c @@ -11,6 +11,7 @@ #include #include #include +#include static void spl_vm_profile_free(spl_vm_t *vm); @@ -67,7 +68,7 @@ static int spl_type_size(spl_vm_kind_t t) { case SPL_USIZE: case SPL_PTR: return sizeof(void *); - case SPL_TYPE_COUNT: + default: return 0; } return 0; @@ -570,6 +571,7 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) { vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0; vm->steps = 0; + vm->ncalls = 0; vm->profile = NULL; vm->profile_interval = 0; vm->prog = NULL; @@ -708,22 +710,29 @@ void spl_vm_set_debug(spl_vm_t *vm, int enabled) { static inline int spl_vm_call(spl_vm_t *vm, spl_vm_val_t addr, spl_vm_val_t nargs) { if (vm->cp >= vm->config.max_call_depth) VM_ERROR("call depth exceeded"); - // spl_vm_stackdump(vm, vm->sp); - PUSH(SPL_STACK_CANARY); - /* Shift args right by 1 to create gap for canary at fp-1 */ - for (usize i = vm->sp; i >= vm->sp - nargs; --i) { - vm->stacks.data[i] = vm->stacks.data[i - 1]; + + uintptr_t saved_sp; + if (vm->debug) { + /* debug:在 fp-1 留金丝雀位,需要把实参右移一格。 */ + PUSH(SPL_STACK_CANARY); + for (usize i = vm->sp; i >= vm->sp - nargs; --i) + vm->stacks.data[i] = vm->stacks.data[i - 1]; + saved_sp = vm->sp - nargs - 1; + } else { + /* 非 debug:不做金丝雀搬移;实参在 sp-nargs..sp-1,fp 指向 arg0。 */ + saved_sp = vm->sp - nargs; } - vm->frames.data[vm->cp].saved_sp = vm->sp - nargs - 1; - vm->frames.data[vm->cp].saved_fp = vm->fp; - vm->frames.data[vm->cp].saved_ip = vm->ip; - vm->frames.data[vm->cp].nargs = nargs; + + spl_callframe_t *fr = &vm->frames.data[vm->cp]; + fr->saved_sp = saved_sp; + fr->saved_fp = vm->fp; + fr->saved_ip = vm->ip; + fr->nargs = nargs; vm->cp++; vm->ip = addr; vm->fp = vm->sp - nargs; - if (vm->fp > 0) + if (vm->debug && vm->fp > 0) STACK_CANARY(vm) = SPL_STACK_CANARY; - // spl_vm_stackdump(vm, vm->sp); return 0; } @@ -800,6 +809,13 @@ static int func_index_by_ip(spl_prog_t *prog, spl_vm_val_t ip) { return -1; } +static uint64_t prof_now_ns(void) { + struct timespec ts; + if (timespec_get(&ts, TIME_UTC) != TIME_UTC) + return 0; + return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec; +} + static void spl_vm_sample(spl_vm_t *vm) { spl_prof_t *p = (spl_prof_t *)vm->profile; spl_prog_t *prog = vm->prog; @@ -823,6 +839,17 @@ static void spl_vm_sample(spl_vm_t *vm) { } } int leaf = func_index_by_ip(prog, vm->ip > 0 ? vm->ip - 1 : 0); + + /* time-slice:把两次采样之间的时间记到当前活跃函数(leaf)。 */ + uint64_t now = prof_now_ns(); + if (p->last_ns != 0 && now > p->last_ns) { + uint64_t d = now - p->last_ns; + p->total_ns += d; + if (leaf >= 0 && (usize)leaf < vec_size(p->self_ns)) + p->self_ns.data[leaf] += d; + } + p->last_ns = now; + const char *ln = leaf >= 0 ? vec_at(prog->funcs, (usize)leaf).name : "?"; size_t ll = strlen(ln); if (len + ll + 1 < sizeof(buf)) { @@ -853,10 +880,13 @@ void spl_vm_profile_enable(spl_vm_t *vm, usize interval) { memset(p, 0, sizeof(*p)); map_init(p->stacks, MAP_HASH_STR, MAP_CMP_STR); vec_init(p->self_samples); + vec_init(p->self_ns); if (vm->prog) { usize n = vec_size(vm->prog->funcs); - for (usize i = 0; i < n; i++) + for (usize i = 0; i < n; i++) { vec_push(p->self_samples, (usize)0); + vec_push(p->self_ns, (uint64_t)0); + } } vm->profile = p; vm->profile_interval = interval ? interval : 100000; @@ -869,6 +899,7 @@ static void spl_vm_profile_free(spl_vm_t *vm) { map_for(p->stacks, i) { free((void *)p->stacks.data[i].key); } map_free(p->stacks); vec_free(p->self_samples); + vec_free(p->self_ns); free(p); vm->profile = NULL; } @@ -891,20 +922,67 @@ void spl_vm_profile_dump_table(spl_vm_t *vm, const char *path) { FILE *f = fopen(path, "wb"); if (!f) return; - fprintf(f, "samples=%zu interval=%zu\n", p->samples, vm->profile_interval); - fprintf(f, "func\tself_samples\tpercent\n"); + fprintf(f, "samples=%zu interval=%zu total_ns=%llu\n", p->samples, vm->profile_interval, + (unsigned long long)p->total_ns); + fprintf(f, "func\tself_samples\tpct_samples\tself_ns\tpct_ns\tns_per_step\n"); for (usize i = 0; i < vec_size(vm->prog->funcs); i++) { usize c = i < vec_size(p->self_samples) ? p->self_samples.data[i] : 0; if (c == 0) continue; + uint64_t t = i < vec_size(p->self_ns) ? p->self_ns.data[i] : 0; spl_vm_func_t *fn = &vec_at(vm->prog->funcs, i); - fprintf(f, "%s\t%zu\t%.2f\n", fn->name, c, - p->samples ? (100.0 * (double)c / (double)p->samples) : 0.0); + double ps = p->samples ? (100.0 * (double)c / (double)p->samples) : 0.0; + double pt = p->total_ns ? (100.0 * (double)t / (double)p->total_ns) : 0.0; + double nps = c ? ((double)t / (double)c) : 0.0; + fprintf(f, "%s\t%zu\t%.2f\t%llu\t%.2f\t%.1f\n", fn->name, c, ps, (unsigned long long)t, pt, + nps); } fclose(f); } -int spl_vm_run_once(spl_vm_t *vm) { +/* 单步执行核心(static,便于内联进热循环)。 */ +/* computed-goto 调度:每个 opcode 直接跳到对应标签;limit=SIZE_MAX 表示不限步。 */ +#define DT(op) [op] = &&L_##op + +#define FETCH() \ + do { \ + if (vm->ip >= (spl_vm_val_t)vec_size(prog->insns)) { \ + fprintf(stderr, "vm: ip=%zd out of bounds\n", vm->ip); \ + vm->exit_code = 1; \ + return -1; \ + } \ + ins = &vec_at(prog->insns, vm->ip); \ + vm->ip++; \ + vm->steps++; \ + if (vm->profile && vm->profile_interval && (vm->steps % vm->profile_interval) == 0) \ + spl_vm_sample(vm); \ + if (vm->trace) { \ + fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1, \ + spl_vm_opcode_name(ins->opcode), spl_vm_type_kind_name(ins->type), ins->imm, \ + vm->sp, vm->fp); \ + } \ + } while (0) + +#define DISPATCH() \ + do { \ + if (vm->debug && vm->fp > 0 && STACK_CANARY(vm) != SPL_STACK_CANARY) { \ + snprintf(vm->error_msg, sizeof(vm->error_msg), \ + "STACK CANARY CORRUPTED at ip=%zd, fp=%zd\n", vm->ip - 1, vm->fp); \ + VM_ERROR(vm->error_msg); \ + } \ + if (limit && --limit == 0) \ + return 0; \ + if (ip_breakpoint_hit(vm)) { \ + if (vm->skip_bp) \ + vm->skip_bp = 0; \ + else \ + return 2; \ + } \ + FETCH(); \ + goto *vm_dispatch[ins->opcode]; \ + } while (0) + +static int vm_loop(spl_vm_t *vm, size_t limit) { const spl_vm_ins_t *ins; spl_prog_t *prog; @@ -912,73 +990,78 @@ int spl_vm_run_once(spl_vm_t *vm) { return -1; prog = vm->prog; - if (vm->ip >= vec_size(prog->insns)) { - fprintf(stderr, "vm: ip=%zd out of bounds\n", vm->ip); - vm->exit_code = 1; - return -1; - } + static void *vm_dispatch[SPL_OPCODE_COUNT] = { + DT(SPL_PUSH), DT(SPL_DUP), DT(SPL_DROP), + DT(SPL_SWAP), DT(SPL_PICK), DT(SPL_ROT), + DT(SPL_ADD), DT(SPL_SUB), DT(SPL_MUL), + DT(SPL_DIV_S), DT(SPL_DIV_U), DT(SPL_REM_S), + DT(SPL_REM_U), DT(SPL_NEG), DT(SPL_AND), + DT(SPL_OR), DT(SPL_XOR), DT(SPL_NOT), + DT(SPL_SHL), DT(SPL_SHR_U), DT(SPL_SHR_S), + DT(SPL_EQ), DT(SPL_NE), DT(SPL_SLT), + DT(SPL_SLE), DT(SPL_ULT), DT(SPL_ULE), + DT(SPL_SGT), DT(SPL_SGE), DT(SPL_UGT), + DT(SPL_UGE), DT(SPL_TRUNC), DT(SPL_SEXT), + DT(SPL_ZEXT), DT(SPL_JMP), DT(SPL_BZ), + DT(SPL_BNZ), DT(SPL_HALT), DT(SPL_CALL), + DT(SPL_CALLI), DT(SPL_RET), DT(SPL_ALLOC), + DT(SPL_LADDR), DT(SPL_GADDR), DT(SPL_LOAD), + DT(SPL_STORE), DT(SPL_NCALL), DT(SPL_NLIB), + DT(SPL_BK), DT(SPL_DBG), [SPL_ERROR] = &&L_default, + }; - /* 断点:即将执行的指令命中 ip 断点 -> 暂停(返回 2)。 - * skip_bp 置位时执行当前指令(continue 越过当前断点)。 */ + if (limit == 0) + return 0; if (ip_breakpoint_hit(vm)) { - if (vm->skip_bp) { + if (vm->skip_bp) vm->skip_bp = 0; - } else { + else return 2; - } } + FETCH(); + goto *vm_dispatch[ins->opcode]; - ins = &vec_at(prog->insns, vm->ip); - vm->ip++; - vm->steps++; - if (vm->profile && vm->profile_interval && (vm->steps % vm->profile_interval) == 0) - spl_vm_sample(vm); +/* ========== Stack ========== */ +L_SPL_PUSH: + PUSH(ins->imm); + DISPATCH(); - if (vm->trace) { - fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1, - spl_vm_opcode_name(ins->opcode), spl_vm_type_kind_name(ins->type), ins->imm, vm->sp, - vm->fp); - } - - switch (ins->opcode) { - - /* ========== Stack ========== */ - case SPL_PUSH: - PUSH(ins->imm); - break; - - case SPL_DUP: { +L_SPL_DUP: + { if (vm->sp < 1) VM_ERROR("DUP: stack underflow"); spl_vm_val_t _v = vm->stacks.data[vm->sp - 1]; PUSH(_v); - break; + DISPATCH(); } - case SPL_DROP: - if (vm->sp < 1) - VM_ERROR("DROP: stack underflow"); - vm->sp--; - break; +L_SPL_DROP: + if (vm->sp < 1) + VM_ERROR("DROP: stack underflow"); + vm->sp--; + DISPATCH(); - case SPL_SWAP: { +L_SPL_SWAP: + { if (vm->sp < 2) VM_ERROR("SWAP: stack underflow"); spl_vm_val_t _t = vm->stacks.data[vm->sp - 1]; vm->stacks.data[vm->sp - 1] = vm->stacks.data[vm->sp - 2]; vm->stacks.data[vm->sp - 2] = _t; - break; + DISPATCH(); } - case SPL_PICK: { +L_SPL_PICK: + { isize _idx = ins->imm; if ((usize)_idx >= vm->sp) VM_ERROR("PICK: index out of range"); PUSH(vm->stacks.data[vm->sp - 1 - _idx]); - break; + DISPATCH(); } - case SPL_ROT: { +L_SPL_ROT: + { if (vm->sp < 3) VM_ERROR("ROT: stack underflow"); spl_vm_val_t _a = vm->stacks.data[vm->sp - 3]; @@ -987,34 +1070,35 @@ int spl_vm_run_once(spl_vm_t *vm) { vm->stacks.data[vm->sp - 3] = _b; vm->stacks.data[vm->sp - 2] = _c; vm->stacks.data[vm->sp - 1] = _a; - break; + DISPATCH(); } - /* ========== Arithmetic ========== */ - case SPL_ADD: - ARITH_BINOP(+); - break; - case SPL_SUB: - ARITH_BINOP(-); - break; - case SPL_MUL: - ARITH_BINOP(*); - break; +/* ========== Arithmetic ========== */ +L_SPL_ADD: + ARITH_BINOP(+); + DISPATCH(); +L_SPL_SUB: + ARITH_BINOP(-); + DISPATCH(); +L_SPL_MUL: + ARITH_BINOP(*); + DISPATCH(); - case SPL_DIV_S: - DIV_REM_S(/); - break; - case SPL_DIV_U: - DIV_REM_U(/); - break; - case SPL_REM_S: - DIV_REM_S(%); - break; - case SPL_REM_U: - DIV_REM_U(%); - break; +L_SPL_DIV_S: + DIV_REM_S(/); + DISPATCH(); +L_SPL_DIV_U: + DIV_REM_U(/); + DISPATCH(); +L_SPL_REM_S: + DIV_REM_S(%); + DISPATCH(); +L_SPL_REM_U: + DIV_REM_U(%); + DISPATCH(); - case SPL_NEG: { +L_SPL_NEG: + { spl_vm_val_t _a = POP(); if (spl_is_float((spl_vm_kind_t)ins->type)) { double _d; @@ -1032,115 +1116,129 @@ int spl_vm_run_once(spl_vm_t *vm) { } else { PUSH(-(int64_t)_a); } - break; + DISPATCH(); } - /* ========== Bitwise ========== */ - case SPL_AND: { +/* ========== Bitwise ========== */ +L_SPL_AND: + { spl_vm_val_t _b = POP(), _a = POP(); PUSH(_a & _b); - break; + DISPATCH(); } - case SPL_OR: { +L_SPL_OR: + { spl_vm_val_t _b = POP(), _a = POP(); PUSH(_a | _b); - break; + DISPATCH(); } - case SPL_XOR: { +L_SPL_XOR: + { spl_vm_val_t _b = POP(), _a = POP(); PUSH(_a ^ _b); - break; + DISPATCH(); } - case SPL_NOT: { +L_SPL_NOT: + { PUSH(~POP()); - break; + DISPATCH(); } - case SPL_SHL: { +L_SPL_SHL: + { int _s = (int)(POP() & 63); PUSH(POP() << _s); - break; + DISPATCH(); } - case SPL_SHR_U: { +L_SPL_SHR_U: + { int _s = (int)(POP() & 63); PUSH(POP() >> _s); - break; + DISPATCH(); } - case SPL_SHR_S: { +L_SPL_SHR_S: + { int _s = (int)(POP() & 63); PUSH(POP() >> _s); - break; + DISPATCH(); } - /* ========== Comparison ========== */ - case SPL_EQ: - CMP_ALL(==); - break; - case SPL_NE: - CMP_ALL(!=); - break; - case SPL_SLT: - CMP_S(<); - break; - case SPL_SLE: - CMP_S(<=); - break; - case SPL_SGT: - CMP_S(>); - break; - case SPL_SGE: - CMP_S(>=); - break; - case SPL_ULT: - CMP_U(<); - break; - case SPL_ULE: - CMP_U(<=); - break; - case SPL_UGT: - CMP_U(>); - break; - case SPL_UGE: - CMP_U(>=); - break; +/* ========== Comparison ========== */ +L_SPL_EQ: + CMP_ALL(==); + DISPATCH(); +L_SPL_NE: + CMP_ALL(!=); + DISPATCH(); +L_SPL_SLT: + CMP_S(<); + DISPATCH(); +L_SPL_SLE: + CMP_S(<=); + DISPATCH(); +L_SPL_SGT: + CMP_S(>); + DISPATCH(); +L_SPL_SGE: + CMP_S(>=); + DISPATCH(); +L_SPL_ULT: + CMP_U(<); + DISPATCH(); +L_SPL_ULE: + CMP_U(<=); + DISPATCH(); +L_SPL_UGT: + CMP_U(>); + DISPATCH(); +L_SPL_UGE: + CMP_U(>=); + DISPATCH(); - /* ========== Control Flow (relative offset) ========== */ - case SPL_JMP: - vm->ip = vm->ip + ins->imm; - break; +/* ========== Control Flow (relative offset) ========== */ +L_SPL_JMP: + vm->ip = vm->ip + ins->imm; + DISPATCH(); - case SPL_BZ: { +L_SPL_BZ: + { if (POP() == 0) vm->ip = vm->ip + ins->imm; - break; + DISPATCH(); } - case SPL_BNZ: { +L_SPL_BNZ: + { if (POP() != 0) vm->ip = vm->ip + ins->imm; - break; + DISPATCH(); } - case SPL_CALL: { +L_SPL_CALL: + { spl_vm_val_t _nargs = ins->imm; spl_vm_val_t _addr = POP(); + vm->ncalls++; int _hit = fn_breakpoint_hit(vm, _addr); spl_vm_call(vm, _addr, _nargs); if (_hit) return 2; /* 已进入函数,暂停在函数入口 */ - break; + DISPATCH(); } - case SPL_CALLI: { +L_SPL_CALLI: + { spl_vm_val_t _addr = POP(); spl_vm_val_t _nargs = POP(); + vm->ncalls++; int _hit = fn_breakpoint_hit(vm, _addr); spl_vm_call(vm, _addr, _nargs); if (_hit) return 2; - break; + DISPATCH(); } - case SPL_RET: { +L_SPL_RET: + { spl_vm_val_t _retval = 0; if (ins->type != SPL_VOID) _retval = POP(); @@ -1161,16 +1259,17 @@ int spl_vm_run_once(spl_vm_t *vm) { if (ins->type != SPL_VOID) PUSH(_retval); // spl_vm_stackdump(vm, vm->sp); - break; + DISPATCH(); } - case SPL_HALT: - if (ins->imm) - vm->exit_code = (int)ins->imm; - return 1; +L_SPL_HALT: + if (ins->imm) + vm->exit_code = (int)ins->imm; + return 1; - /* ========== Stack / Frame Local Memory ========== */ - case SPL_ALLOC: { +/* ========== Stack / Frame Local Memory ========== */ +L_SPL_ALLOC: + { spl_vm_val_t _k = ins->imm; uintptr_t _new_sp = vm->sp + _k; if (_new_sp > vm->config.max_stack_depth) @@ -1178,14 +1277,15 @@ int spl_vm_run_once(spl_vm_t *vm) { for (uintptr_t _i = vm->sp; _i < _new_sp; _i++) vm->stacks.data[_i] = 0; vm->sp = _new_sp; - break; + DISPATCH(); } - case SPL_LADDR: - PUSH((spl_vm_val_t)((char *)(vm->stacks.data + vm->fp) + ins->imm)); - break; +L_SPL_LADDR: + PUSH((spl_vm_val_t)((char *)(vm->stacks.data + vm->fp) + ins->imm)); + DISPATCH(); - case SPL_GADDR: { +L_SPL_GADDR: + { spl_vm_val_t _idx = ins->imm; if (_idx == 0 || _idx >= vec_size(prog->gdata)) VM_ERROR("GADDR: global data index out of range"); @@ -1193,11 +1293,12 @@ int spl_vm_run_once(spl_vm_t *vm) { if (!gd->data) VM_ERROR("GADDR: null gdata entry"); PUSH((spl_vm_val_t)(uintptr_t)gd->data); - break; + DISPATCH(); } - /* ========== Indirect Memory (load/store with types) ========== */ - case SPL_LOAD: { +/* ========== Indirect Memory (load/store with types) ========== */ +L_SPL_LOAD: + { void *_addr = (void *)POP(); CHECK_ADDR(_addr, "LOAD"); spl_vm_val_t _v = 0; @@ -1209,18 +1310,20 @@ int spl_vm_run_once(spl_vm_t *vm) { _v = (spl_vm_val_t)(((isize)(_v << _shift)) >> _shift); } PUSH(_v); - break; + DISPATCH(); } - case SPL_STORE: { +L_SPL_STORE: + { spl_vm_val_t _v = POP(); void *_addr = (void *)POP(); CHECK_ADDR(_addr, "STORE"); memcpy(_addr, &_v, spl_type_size(ins->type)); - break; + DISPATCH(); } - /* ========== Type Conversion ========== */ - case SPL_TRUNC: { +/* ========== Type Conversion ========== */ +L_SPL_TRUNC: + { spl_vm_val_t _v = POP(); intptr_t _bits = ins->imm; if (_bits < 1 || _bits > 64) @@ -1230,10 +1333,11 @@ int spl_vm_run_once(spl_vm_t *vm) { _v &= _mask; } PUSH(_v); - break; + DISPATCH(); } - case SPL_SEXT: { +L_SPL_SEXT: + { spl_vm_val_t _v = POP(); intptr_t _bits = ins->imm; if (_bits < 1 || _bits > 64) @@ -1246,10 +1350,11 @@ int spl_vm_run_once(spl_vm_t *vm) { _v |= ~_mask; } PUSH(_v); - break; + DISPATCH(); } - case SPL_ZEXT: { +L_SPL_ZEXT: + { spl_vm_val_t _v = POP(); intptr_t _bits = ins->imm; if (_bits < 1 || _bits > 64) @@ -1257,11 +1362,12 @@ int spl_vm_run_once(spl_vm_t *vm) { if (_bits < 64) _v &= ((spl_vm_val_t)1 << _bits) - 1; PUSH(_v); - break; + DISPATCH(); } - /* ========== Native Interface ========== */ - case SPL_NCALL: { +/* ========== Native Interface ========== */ +L_SPL_NCALL: + { intptr_t _nargs = ins->imm; spl_vm_val_t _nat_idx = POP(); spl_vm_native_t *_nat; @@ -1287,10 +1393,11 @@ int spl_vm_run_once(spl_vm_t *vm) { } vm->sp -= _nargs; PUSH(_result); - break; + DISPATCH(); } - case SPL_NLIB: { +L_SPL_NLIB: + { spl_vm_val_t _si = ins->imm; const char *_lib; if (_si >= vec_size(prog->strtab) || !vec_at(prog->strtab, _si)) @@ -1303,11 +1410,12 @@ int spl_vm_run_once(spl_vm_t *vm) { } else { PUSH(_handle); } - break; + DISPATCH(); } - /* ========== Debug ========== */ - case SPL_DBG: { +/* ========== Debug ========== */ +L_SPL_DBG: + { fprintf(stderr, "---DGB: current ip %zu---\n", vm->ip); spl_vm_dump_instr(vm, vm->ip - 6); spl_vm_dump_instr(vm, vm->ip - 5); @@ -1320,44 +1428,26 @@ int spl_vm_run_once(spl_vm_t *vm) { spl_vm_backtrace(vm, vm->fp); spl_vm_stackdump(vm, vm->sp); fprintf(stderr, "---DGB END ---\n"); - break; + DISPATCH(); } - case SPL_BK: { +L_SPL_BK: + { return 2; /* breakpoint: pause execution */ } - default: - fprintf(stderr, "vm: unknown opcode %d at ip=%zd\n", ins->opcode, vm->ip - 1); - vm->exit_code = 1; - return -1; - } - - /* canary check in debug mode (canary is at fp-1, invisible to compiled code) */ - if (vm->debug && vm->fp > 0) { - if (STACK_CANARY(vm) != SPL_STACK_CANARY) { - snprintf(vm->error_msg, sizeof(vm->error_msg), - "STACK CANARY CORRUPTED at ip=%zd, fp=%zd\n", vm->ip - 1, vm->fp); - VM_ERROR(vm->error_msg); - } - } - - return 0; +L_default: + fprintf(stderr, "vm: unknown opcode %d at ip=%zd\n", ins->opcode, vm->ip - 1); + vm->exit_code = 1; + return -1; } +int spl_vm_run_once(spl_vm_t *vm) { return vm_loop(vm, 1); } + int spl_vm_run_until(spl_vm_t *vm, size_t step) { - size_t _count = 0; - int _ret; if (!vm) return -1; - while (1) { - if (step > 0 && _count >= step) - return 0; - _ret = spl_vm_run_once(vm); - if (_ret != 0) - return _ret; - _count++; - } + return vm_loop(vm, step ? step : (size_t)-1); } static const char *func_name_by_ip(spl_prog_t *prog, spl_vm_val_t ip) { diff --git a/stage0/spl_vm.h b/stage0/spl_vm.h index d07c2d6..a4b3cbe 100644 --- a/stage0/spl_vm.h +++ b/stage0/spl_vm.h @@ -23,6 +23,9 @@ typedef VEC(spl_callframe_t) spl_frame_vec_t; typedef struct { MAP(const char *, usize) stacks; VEC(usize) self_samples; + VEC(uint64_t) self_ns; /* 每函数 time-slice 累加(纳秒) */ + uint64_t last_ns; + uint64_t total_ns; usize samples; } spl_prof_t; @@ -34,7 +37,8 @@ typedef struct spl_vm { uintptr_t fp; // frame pointer uintptr_t cp; // call pointer uintptr_t ip; // instr pointer - uint64_t steps; // 已执行指令数(供性能分析参考) + uint64_t steps; // 已执行指令数(供性能分析参考) + uint64_t ncalls; // 已执行 CALL/CALLI 次数(供性能分析参考) int exit_code; int trace; /* non-zero to print each instruction */ int debug; /* non-zero to enable canary checks */ diff --git a/stage1/ir_opt.c b/stage1/ir_opt.c new file mode 100644 index 0000000..3d2e74b --- /dev/null +++ b/stage1/ir_opt.c @@ -0,0 +1,612 @@ +/* ir_opt.c - IR 层优化 pass + * + * 通用函数内联(任意大小/形状的 callee,不再限叶子): + * - callee 体内允许 control.call(嵌套调用)、分支/循环、多个返回、unit 返回; + * - 参数:克隆体内 Param 的“使用处”替换为调用实参 ref; + * - 控制流:克隆体追加到调用者末尾,内部 br/jmp/label 整体 +shift; + * - 返回: + * * 有返回值:在调用者追加 ret 槽(MemAlloca)与常量 1;每个 Ret 改为 + * jmp 到“MemStore(槽, val) + jmp(join)”,join 处 MemLoad(槽) 供使用者; + * * 无返回值(unit):每个 Ret 直接 jmp 到调用点之后。 + * - 调用点改为 jmp 到克隆体入口;其使用者改指到 join 的 MemLoad(或 0)。 + * - 防环:若 callee(传递)可达 caller,则拒绝内联,保证调用图保持无环、 + * 内联过程终止(直接/间接递归都不会被内联)。 + * - 迭代到不动点(无环调用图上轮数有上界)。 + * 默认关闭(splc0 --opt 驱动),且只内联显式 `#inline` 标记的 callee。 */ + +#include "ir_opt.h" + +#include +#include + +typedef struct { + spl_ir_t *ir; + spl_ir_func_ref_t caller; + spl_ir_func_ref_t callee; + spl_ir_node_ref_t shift; /* new = old + shift */ + usize nparams; + spl_ir_node_ref_t *param_ref; + spl_ir_node_ref_t *param_arg; +} inline_ctx_t; + +static spl_ir_node_t *nd(spl_ir_t *ir, spl_ir_func_ref_t fid, spl_ir_node_ref_t ref) { + return spl_ir_node(ir, fid, ref); +} + +/* ---- 引用重写(克隆体旧 ref -> 新 ref) ---- */ + +static spl_ir_node_ref_t rw(inline_ctx_t *c, spl_ir_node_ref_t r) { + if (r == 0) + return 0; + for (usize i = 0; i < c->nparams; i++) + if (c->param_ref[i] == r) + return c->param_arg[i]; + return r + c->shift; +} + +static void rw_vec(inline_ctx_t *c, spl_ir_node_ref_vec_t *v) { + for (usize i = 0; i < vec_size(*v); i++) + vec_at(*v, i) = rw(c, vec_at(*v, i)); +} + +static void rw_node(inline_ctx_t *c, spl_ir_node_t *n) { + switch (n->kind) { + case SPL_IR_ARITH_ADD: case SPL_IR_ARITH_SUB: case SPL_IR_ARITH_MUL: + case SPL_IR_ARITH_DIV: case SPL_IR_ARITH_REM: case SPL_IR_ARITH_NEG: + case SPL_IR_ARITH_ABS: case SPL_IR_ARITH_AND: case SPL_IR_ARITH_OR: + case SPL_IR_ARITH_XOR: case SPL_IR_ARITH_SHL: case SPL_IR_ARITH_SHR: + case SPL_IR_ARITH_NOT: + n->arith.left = rw(c, n->arith.left); + n->arith.right = rw(c, n->arith.right); + break; + case SPL_IR_CMP_EQ: case SPL_IR_CMP_NE: case SPL_IR_CMP_LT: + case SPL_IR_CMP_LE: case SPL_IR_CMP_GT: case SPL_IR_CMP_GE: + n->cmp.a = rw(c, n->cmp.a); + n->cmp.b = rw(c, n->cmp.b); + break; + case SPL_IR_CAST_TRUNC: case SPL_IR_CAST_ZEXT: case SPL_IR_CAST_SEXT: + case SPL_IR_CAST_FEXT: case SPL_IR_CAST_FTRUNC: case SPL_IR_CAST_BITCAST: + case SPL_IR_CAST_PTR2INT: case SPL_IR_CAST_INT2PTR: case SPL_IR_CAST_BOOL2INT: + case SPL_IR_CASE_INT2FLOAT: case SPL_IR_CASE_FLOAT2INT: + n->cast.val = rw(c, n->cast.val); + break; + case SPL_IR_MEM_ALLOCA: + n->mem_alloc.count = rw(c, n->mem_alloc.count); + break; + case SPL_IR_MEM_GLOBAL_ALLOC: + n->mem_global_alloc.const_node = rw(c, n->mem_global_alloc.const_node); + break; + case SPL_IR_MEM_LOAD: + n->mem_load.ptr = rw(c, n->mem_load.ptr); + break; + case SPL_IR_MEM_STORE: + n->mem_store.ptr = rw(c, n->mem_store.ptr); + n->mem_store.val = rw(c, n->mem_store.val); + break; + case SPL_IR_MEM_OFFSET: + n->mem_offset.ptr = rw(c, n->mem_offset.ptr); + n->mem_offset.offset = rw(c, n->mem_offset.offset); + break; + case SPL_IR_MEM_FIELD_PTR: + n->mem_field_ptr.agg = rw(c, n->mem_field_ptr.agg); + break; + case SPL_IR_MEM_COPY: + n->mem_copy.dst = rw(c, n->mem_copy.dst); + n->mem_copy.src = rw(c, n->mem_copy.src); + n->mem_copy.size = rw(c, n->mem_copy.size); + break; + case SPL_IR_MEM_SET: + n->mem_set.dst = rw(c, n->mem_set.dst); + n->mem_set.val = rw(c, n->mem_set.val); + n->mem_set.size = rw(c, n->mem_set.size); + break; + case SPL_IR_TYPE_OFFSETOF: + n->ir_offsetof.field_idx = rw(c, n->ir_offsetof.field_idx); + break; + case SPL_IR_AGG_CONSTRUCT: + rw_vec(c, &n->agg_construct.fields); + break; + case SPL_IR_AGG_EXTRACT: + n->agg_extract.val = rw(c, n->agg_extract.val); + break; + case SPL_IR_AGG_INSERT: + n->agg_insert.agg = rw(c, n->agg_insert.agg); + n->agg_insert.field = rw(c, n->agg_insert.field); + break; + case SPL_IR_CONTROL_SELECT: + n->control_select.cond = rw(c, n->control_select.cond); + n->control_select.true_val = rw(c, n->control_select.true_val); + n->control_select.false_val = rw(c, n->control_select.false_val); + break; + case SPL_IR_CONTROL_BR: + n->control_br.cond = rw(c, n->control_br.cond); + n->control_br.true_label = rw(c, n->control_br.true_label); + n->control_br.false_label = rw(c, n->control_br.false_label); + break; + case SPL_IR_CONTROL_JMP: + n->control_jmp.label = rw(c, n->control_jmp.label); + break; + case SPL_IR_CONTROL_PARAM: + n->control_param.idx = rw(c, n->control_param.idx); + break; + case SPL_IR_CONTROL_RET: + n->control_ret.val = rw(c, n->control_ret.val); + break; + case SPL_IR_CONTROL_CALL: + n->control_call.func = rw(c, n->control_call.func); + rw_vec(c, &n->control_call.params); + break; + default: + break; + } +} + +/* ---- 克隆 ---- */ + +static void clone_ref_vec(spl_ir_node_ref_vec_t *dst, const spl_ir_node_ref_vec_t *src) { + dst->size = 0; + dst->cap = 0; + dst->data = NULL; + usize n = vec_size(*src); + if (n == 0) + return; + spl_ir_node_ref_t *p = (spl_ir_node_ref_t *)malloc(sizeof(spl_ir_node_ref_t) * n); + if (!p) + return; + memcpy(p, src->data, sizeof(spl_ir_node_ref_t) * n); + dst->data = p; + dst->size = n; + dst->cap = n; +} + +static void clone_node(spl_ir_t *ir, spl_ir_func_ref_t caller, spl_ir_node_ref_t dst_ref, + const spl_ir_node_t *src) { + spl_ir_node_t *dst = nd(ir, caller, dst_ref); + memcpy(dst, src, sizeof(*dst)); + dst->attrs.data = NULL; + dst->attrs.size = 0; + dst->attrs.cap = 0; + if (vec_size(src->attrs) != 0) + clone_ref_vec((spl_ir_node_ref_vec_t *)&dst->attrs, + (const spl_ir_node_ref_vec_t *)&src->attrs); + if (src->kind == SPL_IR_AGG_CONSTRUCT) + clone_ref_vec(&dst->agg_construct.fields, &src->agg_construct.fields); + else if (src->kind == SPL_IR_CONTROL_CALL) + clone_ref_vec(&dst->control_call.params, &src->control_call.params); +} + +/* ---- 调用图可达性(防环) ---- */ + +static spl_ir_func_ref_t call_callee(spl_ir_t *ir, spl_ir_func_ref_t fid, spl_ir_node_t *call) { + spl_ir_node_t *fn = nd(ir, fid, call->control_call.func); + if (!fn || fn->kind != SPL_IR_TYPE_CONST) + return 0; + return fn->type_const.fn; +} + +static bool reaches(spl_ir_t *ir, spl_ir_func_ref_t from, spl_ir_func_ref_t target, + unsigned char *mark) { + if (from == 0) + return false; + if (from == target) + return true; + if (mark[from]) + return false; + mark[from] = 1; + spl_ir_func_t *f = spl_ir_func(ir, from); + if (!f) + return false; + usize n = vec_size(f->nodes); + for (usize i = 1; i < n; i++) { + spl_ir_node_t *x = nd(ir, from, i); + if (x && x->kind == SPL_IR_CONTROL_CALL) { + spl_ir_func_ref_t c = call_callee(ir, from, x); + if (c != 0 && reaches(ir, c, target, mark)) + return true; + } + } + return false; +} + +/* 从 from 的直接被调者出发是否能到达 target(用于判断 from 自身是否递归/自可达)。 */ +static bool reaches_succ(spl_ir_t *ir, spl_ir_func_ref_t from, spl_ir_func_ref_t target, + unsigned char *mark) { + spl_ir_func_t *f = spl_ir_func(ir, from); + if (!f) + return false; + usize n = vec_size(f->nodes); + for (usize i = 1; i < n; i++) { + spl_ir_node_t *x = nd(ir, from, i); + if (x && x->kind == SPL_IR_CONTROL_CALL) { + spl_ir_func_ref_t c = call_callee(ir, from, x); + if (c != 0 && reaches(ir, c, target, mark)) + return true; + } + } + return false; +} + +/* ---- 内联一个调用点 ---- */ + +typedef struct { + spl_ir_node_ref_t clone_ref; + spl_ir_node_ref_t val; +} ret_rec_t; + +static bool param_index(spl_ir_t *ir, spl_ir_func_ref_t fid, spl_ir_node_t *p, usize *out) { + spl_ir_node_t *idx = nd(ir, fid, p->control_param.idx); + if (!idx || idx->kind != SPL_IR_TYPE_CONST) + return false; + *out = idx->type_const.int_lit; + return true; +} + +static spl_ir_node_ref_t find_const_src(spl_ir_t *ir, spl_ir_func_ref_t fid) { + spl_ir_func_t *f = spl_ir_func(ir, fid); + if (!f) + return 0; + for (usize i = 1; i < vec_size(f->nodes); i++) { + spl_ir_node_t *x = nd(ir, fid, i); + if (x && x->kind == SPL_IR_TYPE_CONST) + return i; + } + return 0; +} + +static bool try_inline(spl_ir_t *ir, spl_ir_func_ref_t caller, spl_ir_node_ref_t ci, + spl_ir_func_ref_t callee) { + spl_ir_func_t *cf = spl_ir_func(ir, caller); + spl_ir_func_t *calf = spl_ir_func(ir, callee); + if (!cf || !calf || callee == caller) + return false; + + spl_ir_node_t *call = nd(ir, caller, ci); + if (!call || call->kind != SPL_IR_CONTROL_CALL) + return false; + + usize orig_len = vec_size(cf->nodes); + if (ci + 1 >= orig_len) + return false; + + usize nargs = vec_size(call->control_call.params); + + /* 统计参数与返回,分配动态映射。 */ + usize cnodes = vec_size(calf->nodes); + usize in_params = 0; + usize in_rets = 0; + for (usize i = 1; i < cnodes; i++) { + spl_ir_node_t *x = nd(ir, callee, i); + if (!x) + return false; + if (x->kind == SPL_IR_CONTROL_PARAM) + in_params++; + else if (x->kind == SPL_IR_CONTROL_RET) + in_rets++; + } + if (in_rets == 0 || in_params != nargs) + return false; + + inline_ctx_t c; + memset(&c, 0, sizeof(c)); + c.ir = ir; + c.caller = caller; + c.callee = callee; + c.nparams = in_params; + c.param_ref = (spl_ir_node_ref_t *)malloc(sizeof(spl_ir_node_ref_t) * (in_params ? in_params : 1)); + c.param_arg = (spl_ir_node_ref_t *)malloc(sizeof(spl_ir_node_ref_t) * (in_params ? in_params : 1)); + ret_rec_t *recs = (ret_rec_t *)malloc(sizeof(ret_rec_t) * (in_rets ? in_rets : 1)); + if (!c.param_ref || !c.param_arg || !recs) { + free(c.param_ref); + free(c.param_arg); + free(recs); + return false; + } + + spl_type_id_t ret_tid = call->control_call.tid; + + /* 参数映射(旧 ref -> 实参 ref)。 */ + usize pi = 0; + for (usize i = 1; i < cnodes; i++) { + spl_ir_node_t *x = nd(ir, callee, i); + if (x && x->kind == SPL_IR_CONTROL_PARAM) { + usize idx = 0; + if (!param_index(ir, callee, x, &idx) || idx >= nargs) { + free(c.param_ref); + free(c.param_arg); + free(recs); + return false; + } + c.param_ref[pi] = i; + c.param_arg[pi] = vec_at(call->control_call.params, idx); + pi++; + } + } + + bool has_val = false; + for (usize i = 1; i < cnodes; i++) { + spl_ir_node_t *x = nd(ir, callee, i); + if (x && x->kind == SPL_IR_CONTROL_RET && x->control_ret.val != 0) + has_val = true; + } + spl_ir_node_ref_t const_src = find_const_src(ir, callee); + if (has_val && const_src == 0) { + free(c.param_ref); + free(c.param_arg); + free(recs); + return false; + } + + /* 释放调用点原 params(随后 ci 改为 jmp) */ + vec_free(call->control_call.params); + + /* 克隆体入口前置:常量 1 + ret 槽 */ + spl_ir_node_ref_t body_entry = 0; + spl_ir_node_ref_t slot_ref = 0; + if (has_val) { + spl_ir_node_ref_t c_ref = spl_ir_alloc_node(ir, caller); + clone_node(ir, caller, c_ref, nd(ir, callee, const_src)); + spl_ir_node_t *cn = nd(ir, caller, c_ref); + cn->kind = SPL_IR_TYPE_CONST; + cn->type_const.int_lit = 1; + + slot_ref = spl_ir_alloc_node(ir, caller); + spl_ir_node_t *sn = nd(ir, caller, slot_ref); + memset(sn, 0, sizeof(*sn)); + sn->kind = SPL_IR_MEM_ALLOCA; + sn->mem_alloc.tid = ret_tid; + sn->mem_alloc.count = c_ref; + + body_entry = c_ref; + } + + c.shift = vec_size(cf->nodes) - 1; + if (!has_val) + body_entry = vec_size(cf->nodes); + + /* 克隆体 */ + usize nrec = 0; + for (usize i = 1; i < cnodes; i++) { + spl_ir_node_ref_t dst_ref = spl_ir_alloc_node(ir, caller); + if (dst_ref == 0) { + free(c.param_ref); + free(c.param_arg); + free(recs); + return false; + } + spl_ir_node_t *src = nd(ir, callee, i); + clone_node(ir, caller, dst_ref, src); + rw_node(&c, nd(ir, caller, dst_ref)); + spl_ir_node_t *x = nd(ir, caller, dst_ref); + /* 克隆进来的 Param 使用处已替换为实参,节点本身不能留在调用者里 + * 改变其参数个数;退化为无害常量。 */ + if (src->kind == SPL_IR_CONTROL_PARAM) { + x->kind = SPL_IR_TYPE_CONST; + x->type_const.tid = 0; + x->type_const.int_lit = 0; + continue; + } + if (x->kind == SPL_IR_CONTROL_RET) { + recs[nrec].clone_ref = dst_ref; + recs[nrec].val = x->control_ret.val; + nrec++; + x->kind = SPL_IR_CONTROL_JMP; + x->control_jmp.label = 0; /* 稍后回填 */ + } + } + + spl_ir_node_ref_t ret_new = 0; + if (has_val) { + spl_ir_node_ref_t join = spl_ir_alloc_node(ir, caller); + spl_ir_node_t *jn = nd(ir, caller, join); + memset(jn, 0, sizeof(*jn)); + jn->kind = SPL_IR_MEM_LOAD; + jn->mem_load.tid = ret_tid; + jn->mem_load.ptr = slot_ref; + + /* join 之后跳回调用点的后继(原代码此处靠 fallthrough)。 */ + spl_ir_node_ref_t jc = spl_ir_alloc_node(ir, caller); + spl_ir_node_t *jcn = nd(ir, caller, jc); + memset(jcn, 0, sizeof(*jcn)); + jcn->kind = SPL_IR_CONTROL_JMP; + jcn->control_jmp.label = ci + 1; + + for (usize k = 0; k < nrec; k++) { + spl_ir_node_ref_t st = spl_ir_alloc_node(ir, caller); + spl_ir_node_t *stn = nd(ir, caller, st); + memset(stn, 0, sizeof(*stn)); + stn->kind = SPL_IR_MEM_STORE; + stn->mem_store.tid = ret_tid; + stn->mem_store.ptr = slot_ref; + stn->mem_store.val = recs[k].val; + + spl_ir_node_ref_t jr = spl_ir_alloc_node(ir, caller); + spl_ir_node_t *jrn = nd(ir, caller, jr); + memset(jrn, 0, sizeof(*jrn)); + jrn->kind = SPL_IR_CONTROL_JMP; + jrn->control_jmp.label = join; + + spl_ir_node_t *rn = nd(ir, caller, recs[k].clone_ref); + rn->control_jmp.label = st; + } + ret_new = join; + } else { + for (usize k = 0; k < nrec; k++) { + spl_ir_node_t *rn = nd(ir, caller, recs[k].clone_ref); + rn->control_jmp.label = ci + 1; + } + } + + /* 调用点 -> jmp 到克隆体入口 */ + call = nd(ir, caller, ci); + call->kind = SPL_IR_CONTROL_JMP; + call->control_jmp.label = body_entry; + + /* 使用者替换:只把等于 ci 的引用改为 ret_new(不动其它 ref) */ + for (usize j = 1; j < orig_len; j++) { + spl_ir_node_t *x = nd(ir, caller, j); + if (!x) + continue; + switch (x->kind) { + case SPL_IR_ARITH_ADD: case SPL_IR_ARITH_SUB: case SPL_IR_ARITH_MUL: + case SPL_IR_ARITH_DIV: case SPL_IR_ARITH_REM: case SPL_IR_ARITH_NEG: + case SPL_IR_ARITH_ABS: case SPL_IR_ARITH_AND: case SPL_IR_ARITH_OR: + case SPL_IR_ARITH_XOR: case SPL_IR_ARITH_SHL: case SPL_IR_ARITH_SHR: + case SPL_IR_ARITH_NOT: + if (x->arith.left == ci) x->arith.left = ret_new; + if (x->arith.right == ci) x->arith.right = ret_new; + break; + case SPL_IR_CMP_EQ: case SPL_IR_CMP_NE: case SPL_IR_CMP_LT: + case SPL_IR_CMP_LE: case SPL_IR_CMP_GT: case SPL_IR_CMP_GE: + if (x->cmp.a == ci) x->cmp.a = ret_new; + if (x->cmp.b == ci) x->cmp.b = ret_new; + break; + case SPL_IR_CAST_TRUNC: case SPL_IR_CAST_ZEXT: case SPL_IR_CAST_SEXT: + case SPL_IR_CAST_FEXT: case SPL_IR_CAST_FTRUNC: case SPL_IR_CAST_BITCAST: + case SPL_IR_CAST_PTR2INT: case SPL_IR_CAST_INT2PTR: case SPL_IR_CAST_BOOL2INT: + case SPL_IR_CASE_INT2FLOAT: case SPL_IR_CASE_FLOAT2INT: + if (x->cast.val == ci) x->cast.val = ret_new; + break; + case SPL_IR_MEM_ALLOCA: + if (x->mem_alloc.count == ci) x->mem_alloc.count = ret_new; + break; + case SPL_IR_MEM_GLOBAL_ALLOC: + if (x->mem_global_alloc.const_node == ci) x->mem_global_alloc.const_node = ret_new; + break; + case SPL_IR_MEM_LOAD: + if (x->mem_load.ptr == ci) x->mem_load.ptr = ret_new; + break; + case SPL_IR_MEM_STORE: + if (x->mem_store.ptr == ci) x->mem_store.ptr = ret_new; + if (x->mem_store.val == ci) x->mem_store.val = ret_new; + break; + case SPL_IR_MEM_OFFSET: + if (x->mem_offset.ptr == ci) x->mem_offset.ptr = ret_new; + if (x->mem_offset.offset == ci) x->mem_offset.offset = ret_new; + break; + case SPL_IR_MEM_FIELD_PTR: + if (x->mem_field_ptr.agg == ci) x->mem_field_ptr.agg = ret_new; + break; + case SPL_IR_MEM_COPY: + if (x->mem_copy.dst == ci) x->mem_copy.dst = ret_new; + if (x->mem_copy.src == ci) x->mem_copy.src = ret_new; + if (x->mem_copy.size == ci) x->mem_copy.size = ret_new; + break; + case SPL_IR_MEM_SET: + if (x->mem_set.dst == ci) x->mem_set.dst = ret_new; + if (x->mem_set.val == ci) x->mem_set.val = ret_new; + if (x->mem_set.size == ci) x->mem_set.size = ret_new; + break; + case SPL_IR_TYPE_OFFSETOF: + if (x->ir_offsetof.field_idx == ci) x->ir_offsetof.field_idx = ret_new; + break; + case SPL_IR_AGG_CONSTRUCT: + for (usize k = 0; k < vec_size(x->agg_construct.fields); k++) + if (vec_at(x->agg_construct.fields, k) == ci) + vec_at(x->agg_construct.fields, k) = ret_new; + break; + case SPL_IR_AGG_EXTRACT: + if (x->agg_extract.val == ci) x->agg_extract.val = ret_new; + break; + case SPL_IR_AGG_INSERT: + if (x->agg_insert.agg == ci) x->agg_insert.agg = ret_new; + if (x->agg_insert.field == ci) x->agg_insert.field = ret_new; + break; + case SPL_IR_CONTROL_SELECT: + if (x->control_select.cond == ci) x->control_select.cond = ret_new; + if (x->control_select.true_val == ci) x->control_select.true_val = ret_new; + if (x->control_select.false_val == ci) x->control_select.false_val = ret_new; + break; + case SPL_IR_CONTROL_BR: + if (x->control_br.cond == ci) x->control_br.cond = ret_new; + break; + case SPL_IR_CONTROL_CALL: + if (x->control_call.func == ci) x->control_call.func = ret_new; + for (usize k = 0; k < vec_size(x->control_call.params); k++) + if (vec_at(x->control_call.params, k) == ci) + vec_at(x->control_call.params, k) = ret_new; + break; + case SPL_IR_CONTROL_PARAM: + if (x->control_param.idx == ci) x->control_param.idx = ret_new; + break; + case SPL_IR_CONTROL_RET: + if (x->control_ret.val == ci) x->control_ret.val = ret_new; + break; + default: + break; + } + } + + free(c.param_ref); + free(c.param_arg); + free(recs); + return true; +} + +static bool func_has_attr(const spl_attr_t *attr, const spl_ir_func_t *f, const char *name); + +static int opt_function(spl_ir_t *ir, spl_ir_func_ref_t fid, const spl_attr_t *attr, + unsigned char *mark, usize nfuncs) { + spl_ir_func_t *f = spl_ir_func(ir, fid); + if (!f) + return 0; + int done = 0; + usize orig = vec_size(f->nodes); + for (usize ci = 1; ci < orig; ci++) { + spl_ir_node_t *x = nd(ir, fid, ci); + if (!x || x->kind != SPL_IR_CONTROL_CALL) + continue; + spl_ir_func_ref_t callee = call_callee(ir, fid, x); + if (callee == 0 || callee == fid || callee >= nfuncs) + continue; + spl_ir_func_t *calf = spl_ir_func(ir, callee); + if (!func_has_attr(attr, calf, "inline") || func_has_attr(attr, calf, "noinline")) + continue; + /* extern 是占位体,绝不能内联。 */ + if (func_has_attr(attr, calf, "extern")) + continue; + /* 防环:callee 传递可达 caller 时拒绝(覆盖直接/间接互递归)。 */ + memset(mark, 0, nfuncs); + if (reaches(ir, callee, fid, mark)) + continue; + /* 防爆炸:callee 自身递归时拒绝(否则不动点会反复内联其内部调用)。 */ + memset(mark, 0, nfuncs); + if (reaches_succ(ir, callee, callee, mark)) + continue; + if (try_inline(ir, fid, ci, callee)) + done++; + } + return done; +} + +/* 是否带有指定名字的属性/tag。 */ +static bool func_has_attr(const spl_attr_t *attr, const spl_ir_func_t *f, const char *name) { + if (!attr || !f) + return false; + for (usize i = 0; i < vec_size(f->attrs); ++i) { + spl_attr_node_t *a = spl_attr_node((spl_attr_t *)attr, vec_at(f->attrs, i)); + if (!a || !a->info) + continue; + if (strcmp(a->info->name, name) == 0) + return true; + } + return false; +} + +void spl_ir_opt(spl_ir_t *ir, const spl_attr_t *attr) { + if (!ir) + return; + usize nfuncs = vec_size(ir->funcs); + unsigned char *mark = (unsigned char *)malloc(nfuncs ? nfuncs : 1); + if (!mark) + return; + /* 无环调用图上,最多 nfuncs 轮即可到不动点。 */ + for (usize pass = 0; pass <= nfuncs; pass++) { + int total = 0; + usize n = vec_size(ir->funcs); + for (spl_ir_func_ref_t fid = 1; fid < n && fid < nfuncs; fid++) + total += opt_function(ir, fid, attr, mark, nfuncs); + if (total == 0) + break; + } + free(mark); +} diff --git a/stage1/ir_opt.h b/stage1/ir_opt.h new file mode 100644 index 0000000..648d489 --- /dev/null +++ b/stage1/ir_opt.h @@ -0,0 +1,11 @@ +#ifndef __IR_OPT_H__ +#define __IR_OPT_H__ + +/* IR 层优化 pass:输入输出都是 spl_ir_t(节点 arena),纯函数式、可开关。 + * 由 splc0 --opt 在 ast2ir 之后、ir2vm 之前调用。 */ + +#include "spl_ir.h" + +void spl_ir_opt(spl_ir_t *ir, const spl_attr_t *attr); + +#endif /* __IR_OPT_H__ */ diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index 6be271d..ec4d4c4 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -344,6 +344,13 @@ typedef struct { frame_layout_t frame; VEC(usize) node_ip; fix_vec_t *fixups; + /* 块内栈化(opt) */ + int opt; + uint8_t *stk_loc; /* per node: 1 = 值当前在操作数栈上 */ + usize *stk_pos; /* 在虚拟栈中的位置 */ + usize *use_left; /* 剩余使用次数 */ + usize *at_pos; /* 每个栈位置对应的 node ref */ + usize tracked; /* 当前栈上被跟踪的值个数 */ } cgen_t; static void emit(cgen_t *cg, uint8_t op, uint8_t ty, spl_vm_val_t imm) { @@ -378,6 +385,240 @@ static void cg_store_at(cgen_t *cg, usize addr, uint8_t k) { CG_STORE(cg, k); } +/* ---------- 块内栈化(opt)辅助 ---------- */ + +static uint8_t node_result_kind(cgen_t *cg, usize ref) { + const spl_ir_node_t *n = &vec_at(cg->irf->nodes, ref); + return vm_kind_of(cg->ctx, ir_result_tid(cg->ctx, n)); +} + +static bool node_stackable(cgen_t *cg, const spl_ir_node_t *n) { + switch (n->kind) { + case SPL_IR_ARITH_ADD: + case SPL_IR_ARITH_SUB: + case SPL_IR_ARITH_MUL: + case SPL_IR_ARITH_DIV: + case SPL_IR_ARITH_REM: + case SPL_IR_ARITH_NEG: + case SPL_IR_ARITH_AND: + case SPL_IR_ARITH_OR: + case SPL_IR_ARITH_XOR: + case SPL_IR_ARITH_SHL: + case SPL_IR_ARITH_SHR: + case SPL_IR_ARITH_NOT: + case SPL_IR_CMP_EQ: + case SPL_IR_CMP_NE: + case SPL_IR_CMP_LT: + case SPL_IR_CMP_LE: + case SPL_IR_CMP_GT: + case SPL_IR_CMP_GE: + case SPL_IR_CAST_TRUNC: + case SPL_IR_CAST_ZEXT: + case SPL_IR_CAST_SEXT: + case SPL_IR_CAST_FEXT: + case SPL_IR_CAST_FTRUNC: + case SPL_IR_CAST_BITCAST: + case SPL_IR_CAST_PTR2INT: + case SPL_IR_CAST_INT2PTR: + case SPL_IR_CAST_BOOL2INT: + case SPL_IR_CASE_INT2FLOAT: + case SPL_IR_CASE_FLOAT2INT: + case SPL_IR_TYPE_CONST: { + spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->type_const.tid); + return tn && tn->kind != SPL_TYPE_UNIT; + } + case SPL_IR_TYPE_BITSIZEOF: + case SPL_IR_TYPE_SIZEOF: + case SPL_IR_TYPE_ALIGNOF: + case SPL_IR_TYPE_OFFSETOF: + case SPL_IR_TYPE_FIELD_COUNT: + case SPL_IR_MEM_OFFSET: + case SPL_IR_MEM_FIELD_PTR: + return true; + case SPL_IR_MEM_LOAD: + return !ir_is_aggregate(cg->ctx, n->mem_load.tid); + default: + return false; + } +} + +/* 该节点必须使用槽(直接按槽偏移读写 / 控制转移 / 聚合数据),生成前需 flush。 */ +static bool node_needs_slots(cgen_t *cg, const spl_ir_node_t *n) { + switch (n->kind) { + case SPL_IR_MEM_ALLOCA: + case SPL_IR_MEM_GLOBAL_ALLOC: + case SPL_IR_MEM_COPY: + case SPL_IR_MEM_SET: + case SPL_IR_AGG_CONSTRUCT: + case SPL_IR_AGG_EXTRACT: + case SPL_IR_AGG_INSERT: + case SPL_IR_CONTROL_SELECT: + case SPL_IR_CONTROL_BR: + case SPL_IR_CONTROL_JMP: + case SPL_IR_CONTROL_RET: + case SPL_IR_CONTROL_UNREACHABLE: + case SPL_IR_CONTROL_TRAP: + case SPL_IR_DBG_PANIC: + case SPL_IR_DBG_BREAKPOINT: + return true; + case SPL_IR_MEM_LOAD: + return ir_is_aggregate(cg->ctx, n->mem_load.tid); + case SPL_IR_MEM_STORE: + return ir_is_aggregate(cg->ctx, n->mem_store.tid); + default: + return false; + } +} + +/* 取操作数到 TOS:若在栈上就 PICK,否则从槽 load。j = 本节点已压入的操作数个数。 */ +static void cg_operand(cgen_t *cg, usize ref, uint8_t k, usize j) { + if (cg->opt) { + if (cg->use_left[ref] > 0) + cg->use_left[ref]--; + if (cg->stk_loc[ref]) { + /* 始终复制一份到 TOS,绝不消费栈上的“被跟踪原值”,否则位置模型失效。 */ + usize dist = cg->tracked + j - 1 - cg->stk_pos[ref]; + emit(cg, SPL_PICK, SPL_VOID, dist); + return; + } + } + cg_load_slot(cg, ref, k); +} + +/* 节点结果:若仍会被使用则留在栈上,否则 DROP。 */ +static void cg_result(cgen_t *cg, usize ref, uint8_t k) { + if (cg->opt) { + if (cg->use_left[ref] > 0) { + cg->stk_loc[ref] = 1; + cg->stk_pos[ref] = cg->tracked; + cg->at_pos[cg->tracked] = ref; + cg->tracked++; + } else { + emit(cg, SPL_DROP, SPL_VOID, 0); + } + return; + } + cg_store_slot(cg, ref, k); +} + +/* 把栈上仍存活的值溢出回各自槽(TOS 起),死值 DROP;清空跟踪。 */ +static void cg_flush(cgen_t *cg) { + if (!cg->opt) + return; + while (cg->tracked > 0) { + cg->tracked--; + usize r = cg->at_pos[cg->tracked]; + cg->stk_loc[r] = 0; + if (cg->use_left[r] > 0) { + uint8_t k = node_result_kind(cg, r); + cg_store_slot(cg, r, k); + } else { + emit(cg, SPL_DROP, SPL_VOID, 0); + } + } +} + +/* 统计被引用次数(所有节点载荷中的 node ref)。 */ +static void count_ref(cgen_t *cg, usize r) { + if (r != 0 && r < vec_size(cg->irf->nodes)) + cg->use_left[r]++; +} +static void count_refs_vec(cgen_t *cg, const spl_ir_node_ref_vec_t *v) { + for (usize i = 0; i < vec_size(*v); i++) + count_ref(cg, vec_at(*v, i)); +} +static void count_refs(cgen_t *cg, const spl_ir_node_t *n) { + switch (n->kind) { + case SPL_IR_ARITH_ADD: case SPL_IR_ARITH_SUB: case SPL_IR_ARITH_MUL: + case SPL_IR_ARITH_DIV: case SPL_IR_ARITH_REM: case SPL_IR_ARITH_NEG: + case SPL_IR_ARITH_ABS: case SPL_IR_ARITH_AND: case SPL_IR_ARITH_OR: + case SPL_IR_ARITH_XOR: case SPL_IR_ARITH_SHL: case SPL_IR_ARITH_SHR: + case SPL_IR_ARITH_NOT: + count_ref(cg, n->arith.left); + count_ref(cg, n->arith.right); + break; + case SPL_IR_CMP_EQ: case SPL_IR_CMP_NE: case SPL_IR_CMP_LT: + case SPL_IR_CMP_LE: case SPL_IR_CMP_GT: case SPL_IR_CMP_GE: + count_ref(cg, n->cmp.a); + count_ref(cg, n->cmp.b); + break; + case SPL_IR_CAST_TRUNC: case SPL_IR_CAST_ZEXT: case SPL_IR_CAST_SEXT: + case SPL_IR_CAST_FEXT: case SPL_IR_CAST_FTRUNC: case SPL_IR_CAST_BITCAST: + case SPL_IR_CAST_PTR2INT: case SPL_IR_CAST_INT2PTR: case SPL_IR_CAST_BOOL2INT: + case SPL_IR_CASE_INT2FLOAT: case SPL_IR_CASE_FLOAT2INT: + count_ref(cg, n->cast.val); + break; + case SPL_IR_MEM_ALLOCA: + count_ref(cg, n->mem_alloc.count); + break; + case SPL_IR_MEM_GLOBAL_ALLOC: + count_ref(cg, n->mem_global_alloc.const_node); + break; + case SPL_IR_MEM_LOAD: + count_ref(cg, n->mem_load.ptr); + break; + case SPL_IR_MEM_STORE: + count_ref(cg, n->mem_store.ptr); + count_ref(cg, n->mem_store.val); + break; + case SPL_IR_MEM_OFFSET: + count_ref(cg, n->mem_offset.ptr); + count_ref(cg, n->mem_offset.offset); + break; + case SPL_IR_MEM_FIELD_PTR: + count_ref(cg, n->mem_field_ptr.agg); + break; + case SPL_IR_MEM_COPY: + count_ref(cg, n->mem_copy.dst); + count_ref(cg, n->mem_copy.src); + count_ref(cg, n->mem_copy.size); + break; + case SPL_IR_MEM_SET: + count_ref(cg, n->mem_set.dst); + count_ref(cg, n->mem_set.val); + count_ref(cg, n->mem_set.size); + break; + case SPL_IR_TYPE_OFFSETOF: + count_ref(cg, n->ir_offsetof.field_idx); + break; + case SPL_IR_AGG_CONSTRUCT: + count_refs_vec(cg, &n->agg_construct.fields); + break; + case SPL_IR_AGG_EXTRACT: + count_ref(cg, n->agg_extract.val); + break; + case SPL_IR_AGG_INSERT: + count_ref(cg, n->agg_insert.agg); + count_ref(cg, n->agg_insert.field); + break; + case SPL_IR_CONTROL_SELECT: + count_ref(cg, n->control_select.cond); + count_ref(cg, n->control_select.true_val); + count_ref(cg, n->control_select.false_val); + break; + case SPL_IR_CONTROL_BR: + count_ref(cg, n->control_br.cond); + count_ref(cg, n->control_br.true_label); + count_ref(cg, n->control_br.false_label); + break; + case SPL_IR_CONTROL_JMP: + count_ref(cg, n->control_jmp.label); + break; + case SPL_IR_CONTROL_CALL: + count_ref(cg, n->control_call.func); + count_refs_vec(cg, &n->control_call.params); + break; + case SPL_IR_CONTROL_PARAM: + count_ref(cg, n->control_param.idx); + break; + case SPL_IR_CONTROL_RET: + count_ref(cg, n->control_ret.val); + break; + default: + break; + } +} + typedef struct { bool indirect; usize off; @@ -439,25 +680,25 @@ static void cg_add_fix(cgen_t *cg, usize ins_idx, fix_kind_t kind, spl_ir_node_r static void cg_binop(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { uint8_t k = vm_kind_of(cg->ctx, n->arith.tid); - cg_load_slot(cg, n->arith.left, k); - cg_load_slot(cg, n->arith.right, k); + cg_operand(cg, n->arith.left, k, 0); + cg_operand(cg, n->arith.right, k, 1); CG_OP(cg, op, k); - cg_store_slot(cg, ref, k); + cg_result(cg, ref, k); } static void cg_unop(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { uint8_t k = vm_kind_of(cg->ctx, n->arith.tid); - cg_load_slot(cg, n->arith.left, k); + cg_operand(cg, n->arith.left, k, 0); CG_OP(cg, op, k); - cg_store_slot(cg, ref, k); + cg_result(cg, ref, k); } static void cg_cmp(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { uint8_t k = vm_kind_of(cg->ctx, n->cmp.tid); - cg_load_slot(cg, n->cmp.a, k); - cg_load_slot(cg, n->cmp.b, k); + cg_operand(cg, n->cmp.a, k, 0); + cg_operand(cg, n->cmp.b, k, 1); CG_OP(cg, op, k); - cg_store_slot(cg, ref, SPL_BOOL); + cg_result(cg, ref, SPL_BOOL); } static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) { @@ -479,7 +720,7 @@ static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) { CG_PUSH(cg, SPL_PTR, 0); cg_add_fix(cg, idx, FIX_FNADDR, 0, n->type_const.fn); } - cg_store_slot(cg, ref, SPL_PTR); + cg_result(cg, ref, SPL_PTR); return; } @@ -507,7 +748,7 @@ static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) { break; } CG_PUSH(cg, k, imm); - cg_store_slot(cg, ref, k); + cg_result(cg, ref, k); } static void cg_cast(cgen_t *cg, usize ref, const spl_ir_node_t *n) { @@ -520,7 +761,7 @@ static void cg_cast(cgen_t *cg, usize ref, const spl_ir_node_t *n) { uint8_t fk = vm_kind_of(ctx, n->cast.from_tid); uint8_t tk = vm_kind_of(ctx, n->cast.to_tid); - cg_load_slot(cg, n->cast.val, fk); + cg_operand(cg, n->cast.val, fk, 0); if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_INT) { usize fb = ft->int_type.bits; @@ -533,7 +774,7 @@ static void cg_cast(cgen_t *cg, usize ref, const spl_ir_node_t *n) { emit(cg, SPL_ZEXT, SPL_VOID, 1); } - cg_store_slot(cg, ref, tk); + cg_result(cg, ref, tk); } static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) { @@ -571,9 +812,9 @@ static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) { cg_store_slot(cg, ref, SPL_PTR); } else { uint8_t k = vm_kind_of(ctx, tid); - cg_load_slot(cg, n->mem_load.ptr, SPL_PTR); + cg_operand(cg, n->mem_load.ptr, SPL_PTR, 0); CG_LOAD(cg, k); - cg_store_slot(cg, ref, k); + cg_result(cg, ref, k); } break; } @@ -585,8 +826,8 @@ static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) { ptr_slot(vec_at(cg->frame.slots, n->mem_store.ptr).result_off), tid); } else { uint8_t k = vm_kind_of(ctx, tid); - cg_load_slot(cg, n->mem_store.ptr, SPL_PTR); - cg_load_slot(cg, n->mem_store.val, k); + cg_operand(cg, n->mem_store.ptr, SPL_PTR, 0); + cg_operand(cg, n->mem_store.val, k, 1); CG_STORE(cg, k); } break; @@ -596,24 +837,24 @@ static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) { usize elem_size = ir_type_size(ctx, n->mem_offset.tid); if (elem_size == 0) elem_size = 1; - cg_load_slot(cg, n->mem_offset.ptr, SPL_PTR); - cg_load_slot(cg, n->mem_offset.offset, SPL_U64); + cg_operand(cg, n->mem_offset.ptr, SPL_PTR, 0); + cg_operand(cg, n->mem_offset.offset, SPL_U64, 1); CG_PUSH(cg, SPL_U64, elem_size); CG_OP(cg, SPL_MUL, SPL_U64); CG_OP(cg, SPL_ADD, SPL_PTR); - cg_store_slot(cg, ref, SPL_PTR); + cg_result(cg, ref, SPL_PTR); break; } case SPL_IR_MEM_FIELD_PTR: { spl_type_id_t agg_tid = n->mem_field_ptr.tid; usize off = ir_agg_field_off(ctx, agg_tid, n->mem_field_ptr.field_idx); - cg_load_slot(cg, n->mem_field_ptr.agg, SPL_PTR); + cg_operand(cg, n->mem_field_ptr.agg, SPL_PTR, 0); if (off) { CG_PUSH(cg, SPL_U64, off); CG_OP(cg, SPL_ADD, SPL_PTR); } - cg_store_slot(cg, ref, SPL_PTR); + cg_result(cg, ref, SPL_PTR); break; } @@ -742,7 +983,7 @@ static void cg_typeop(cgen_t *cg, usize ref, const spl_ir_node_t *n) { return; } CG_PUSH(cg, SPL_U64, v); - cg_store_slot(cg, ref, SPL_U64); + cg_result(cg, ref, SPL_U64); } static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { @@ -829,44 +1070,47 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref); spl_type_id_t ptid = ir_result_tid(ctx, pn); uint8_t pk = vm_kind_of(ctx, ptid); - cg_load_slot(cg, pref, pk); + cg_operand(cg, pref, pk, i); } CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat_idx); emit(cg, SPL_NCALL, SPL_VOID, (spl_vm_val_t)nargs); uint8_t rk = vm_kind_of(ctx, n->control_call.tid); if (rk == SPL_VOID) - emit(cg, SPL_DROP, SPL_VOID, 0); /* NCALL 总是 push 一个结果 */ + emit(cg, SPL_DROP, SPL_VOID, 0); /* NCALL always push result */ else - cg_store_slot(cg, ref, rk); + cg_result(cg, ref, rk); } else { spl_type_id_t ret_t = n->control_call.tid; bool ret_is_sret = ir_is_aggregate(ctx, ret_t); usize sret_off = 0; + usize j = 0; if (ret_is_sret) { sret_off = vec_at(cg->frame.slots, ref).data_off; CG_LADDR(cg, sret_off); + j = 1; } for (usize i = 0; i < nargs; ++i) { spl_ir_node_ref_t pref = vec_at(n->control_call.params, i); const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref); spl_type_id_t ptid = ir_result_tid(ctx, pn); uint8_t pk = vm_kind_of(ctx, ptid); - cg_load_slot(cg, pref, pk); + cg_operand(cg, pref, pk, j); + j++; } - cg_load_slot(cg, fref, SPL_PTR); + cg_operand(cg, fref, SPL_PTR, j); spl_vm_val_t actual_nargs = nargs + (ret_is_sret ? 1 : 0); emit(cg, SPL_CALL, SPL_VOID, actual_nargs); if (ret_is_sret) { - /* 结果槽保存 sret 指针,后续 agg_extract 把它当聚合首地址 */ + /* result slot saves sret pointer */ CG_LADDR(cg, sret_off); - cg_store_slot(cg, ref, SPL_PTR); + cg_result(cg, ref, SPL_PTR); } else { uint8_t rk = vm_kind_of(ctx, ret_t); if (rk != SPL_VOID) - cg_store_slot(cg, ref, rk); + cg_result(cg, ref, rk); } } break; @@ -933,10 +1177,10 @@ static void cg_node(cgen_t *cg, usize ref, const spl_ir_node_t *n) { case SPL_IR_ARITH_NOT: { spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid); if (tn && tn->kind == SPL_TYPE_BOOL) { - cg_load_slot(cg, n->arith.left, SPL_BOOL); + cg_operand(cg, n->arith.left, SPL_BOOL, 0); CG_PUSH(cg, SPL_BOOL, 0); CG_OP(cg, SPL_EQ, SPL_BOOL); - cg_store_slot(cg, ref, SPL_BOOL); + cg_result(cg, ref, SPL_BOOL); } else { cg_unop(cg, ref, n, SPL_NOT); } @@ -1098,9 +1342,49 @@ static usize translate_function(spl_ir2vm_t *ctx, spl_ir_func_ref_t fid, fix_vec for (usize i = 0; i < nnodes; ++i) vec_push(cg.node_ip, 0); + unsigned char *leader = NULL; + cg.opt = ctx->opt; + if (ctx->opt) { + cg.stk_loc = (uint8_t *)calloc(nnodes, 1); + cg.stk_pos = (usize *)calloc(nnodes, sizeof(usize)); + cg.use_left = (usize *)calloc(nnodes, sizeof(usize)); + cg.at_pos = (usize *)calloc(nnodes, sizeof(usize)); + leader = (unsigned char *)calloc(nnodes, 1); + cg.tracked = 0; + for (usize i = 1; i < nnodes; ++i) + count_refs(&cg, &vec_at(irf->nodes, i)); + if (nnodes > 1) + leader[1] = 1; + for (usize i = 1; i < nnodes; ++i) { + const spl_ir_node_t *n = &vec_at(irf->nodes, i); + if (n->kind == SPL_IR_CONTROL_BR) { + if (n->control_br.true_label < nnodes) + leader[n->control_br.true_label] = 1; + if (n->control_br.false_label < nnodes) + leader[n->control_br.false_label] = 1; + } else if (n->kind == SPL_IR_CONTROL_JMP) { + if (n->control_jmp.label < nnodes) + leader[n->control_jmp.label] = 1; + } + } + } + for (usize i = 1; i < nnodes; ++i) { + const spl_ir_node_t *n = &vec_at(irf->nodes, i); + if (cg.opt) { + if (leader[i] || node_needs_slots(&cg, n)) + cg_flush(&cg); + } vec_at(cg.node_ip, i) = ip_of(&cg); - cg_node(&cg, i, &vec_at(irf->nodes, i)); + cg_node(&cg, i, n); + } + if (cg.opt) { + cg_flush(&cg); + free(cg.stk_loc); + free(cg.stk_pos); + free(cg.use_left); + free(cg.at_pos); + free(leader); } for (usize i = 0; i < vec_size(local_fixups); ++i) { @@ -1124,12 +1408,13 @@ static usize spl_map_hash(usize k) { return MAP_HASH_INT(k); } static int spl_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); } void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type, - spl_layout_t *layout, const spl_attr_t *attr) { + spl_layout_t *layout, const spl_attr_t *attr, int opt) { Assert(ir != NULL && type != NULL && attr != NULL); ctx->ir = ir; ctx->type = type; ctx->attr = attr; ctx->layout = layout; + ctx->opt = opt; map_init(ctx->extern_native, spl_map_hash, spl_map_cmp); spl_prog_init(&ctx->prog); diff --git a/stage1/spl_ir2vm.h b/stage1/spl_ir2vm.h index b245125..b082adb 100644 --- a/stage1/spl_ir2vm.h +++ b/stage1/spl_ir2vm.h @@ -25,10 +25,11 @@ typedef struct { spl_layout_t *layout; /* 借用 splc0 的 layout(size/align/offset 唯一来源) */ spl_diag_t *diag; + int opt; /* 非 0:块内操作数栈化(表达式临时值留栈,块边界溢出回槽) */ } spl_ir2vm_t; void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type, - spl_layout_t *layout, const spl_attr_t *attr); + spl_layout_t *layout, const spl_attr_t *attr, int opt); void spl_ir2vm_drop(spl_ir2vm_t *ctx); int spl_ir2vm_run_func(spl_ir2vm_t *ctx, spl_ir_func_ref_t ref); diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index d3e70b9..ba42ac5 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -764,8 +764,7 @@ static void sema_collect_signatures(spl_sema_t *sema) { spl_def_node_t *d = &vec_at(sema->type->def_table, i); /* Nested imports share def_table, but each module has its own scope. * Resolve other modules' signatures only when processing their AST. */ - if (d->owner_ast == sema->ast && d->kind == SPL_DEF_FN && - d->state == SPL_DECL_UNRESOLVED) + if (d->owner_ast == sema->ast && d->kind == SPL_DEF_FN && d->state == SPL_DECL_UNRESOLVED) sema_eval_decl(sema, i); } } @@ -830,14 +829,14 @@ static spl_lang_type_id_t sema_infer_type_context(spl_sema_t *sema, spl_ast_node spl_symbol_t symbol; if (!spl_scope_find(sema->scope, n->ident.name, &symbol) || symbol.kind != SPL_SYMBOL_KIND_TYPE) { - spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, - "`%s` is not a type", n->ident.name); + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, "`%s` is not a type", + n->ident.name); return 0; } spl_def_node_t *def = spl_def_node(sema->type, symbol.node); if (!sema_def_is_type(def)) { - spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, - "`%s` is not a type", n->ident.name); + spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, "`%s` is not a type", + n->ident.name); return 0; } n->resolved_def_id = symbol.node; @@ -880,16 +879,15 @@ static spl_lang_type_id_t sema_infer_type_context(spl_sema_t *sema, spl_ast_node spl_lang_type_id_vec_t elements; vec_init(elements); for (usize i = 0; i < vec_size(n->tuple.elems); ++i) { - spl_lang_type_id_t element = - sema_infer_type_context(sema, vec_at(n->tuple.elems, i)); + spl_lang_type_id_t element = sema_infer_type_context(sema, vec_at(n->tuple.elems, i)); if (!element) { vec_free(elements); return 0; } vec_push(elements, element); } - spl_lang_type_id_t result = spl_lang_make_tuple( - sema->type, vec_unsafe_get_data(elements), vec_size(elements)); + spl_lang_type_id_t result = + spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elements), vec_size(elements)); vec_free(elements); n->resolved_lang_tid = result; return result; @@ -2866,6 +2864,7 @@ void spl_sema_dump(spl_sema_t *sema) { printf("Scopes:\n"); for (usize i = 1; i < vec_size(sema->scope->scopes); ++i) { spl_scope_node_t *scope = &vec_at(sema->scope->scopes, i); + Assert(scope != NULL); printf("scope[%zu] parent=%zu\n", i, scope->parent); /* 按符号名排序输出:与哈希表内部布局解耦,保证确定顺序。 */ @@ -2873,6 +2872,7 @@ void spl_sema_dump(spl_sema_t *sema) { spl_sema_sym_t *arr = nsyms ? malloc(nsyms * sizeof(*arr)) : NULL; usize k = 0; map_for(scope->symbols, j) { + Assert(arr != NULL); arr[k].key = unsafe_map_at(scope->symbols, j).key; arr[k].sym = unsafe_map_at(scope->symbols, j).val; k++; @@ -2880,6 +2880,7 @@ void spl_sema_dump(spl_sema_t *sema) { if (arr && nsyms > 1) qsort(arr, nsyms, sizeof(*arr), spl_sema_sym_cmp); for (k = 0; k < nsyms; ++k) { + Assert(arr != NULL); printf(" %s -> def`%s`#%zu\n", arr[k].key, arr[k].sym.name, arr[k].sym.node); } free(arr); diff --git a/stage1/splc0.c b/stage1/splc0.c index faf343c..21691f7 100644 --- a/stage1/splc0.c +++ b/stage1/splc0.c @@ -10,6 +10,9 @@ #include #include +#include "ir_opt.h" +#include "vm_opt.h" + #include "spl_ast.h" #include "spl_ast2ir.h" #include "spl_diag.h" @@ -217,7 +220,7 @@ static spl_ast_t *driver_load(void *user, const char *from_fname, const char *pa } static int compile_spl(const char *src, const char *fname, const char *outpath, int gen_debug, - dump_t dump) { + dump_t dump, int opt) { (void)gen_debug; spl_diag_t diag; @@ -326,6 +329,10 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, rc = 1; goto cleanup; } + /* IR 层优化 pass(默认关闭,--opt 开启)。 */ + if (opt) + spl_ir_opt(&ir_builder.ir, &attr); + if (dump == DUMP_IR) { spl_ir_dump(&ir_builder.ir, &lang_type.ir, &attr); goto cleanup; @@ -334,7 +341,7 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, /* 类型已全部就绪:解析 layout,供 ir2vm 的 size/align/offset 使用。 */ spl_layout_resolve(&layout, &lang_type.ir); - spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, &lang_type.ir, &layout, &attr); + spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, &lang_type.ir, &layout, &attr, opt); ir2vm_ok = 1; spl_diag_set_stage(&diag, SPL_STAGE_IR2VM); ir2vm.diag = &diag; @@ -348,6 +355,10 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, goto cleanup; } + /* ir2vm 之后的字节码优化 pass(默认关闭,--opt 开启)。 */ + if (opt) + spl_prog_opt(&ir2vm.prog); + spl_prog_store_to_file(outpath, &ir2vm.prog); rc = 0; @@ -397,6 +408,11 @@ int main(int argc, char **argv) { LOG_INFO("splc0 --dump dump: lex,ast,sema,ir,vm,none"); return 0; } + int opt = 0; + for (int ai = 1; ai < argc; ai++) + if (strcmp(argv[ai], "--opt") == 0) + opt = 1; + int argi = 1; if (argi >= argc) { LOG_FATAL("Usage: splc0 [--dump ] [out]"); @@ -435,19 +451,26 @@ int main(int argc, char **argv) { return 1; } int gen_debug = 0; - if (strcmp(argv[argi], "-g") == 0) { - gen_debug = 1; - argi++; + while (argi < argc - 1) { + if (strcmp(argv[argi], "-g") == 0) { + gen_debug = 1; + argi++; + } else if (strcmp(argv[argi], "--opt") == 0) { + opt = 1; + argi++; + } else { + break; + } } if (argc < argi + 2) { - LOG_FATAL("Usage: splc0 [-g] or splc0 --dump \n"); + LOG_FATAL("Usage: splc0 [-g] [--opt] or splc0 --dump \n"); return 1; } long len; char *src = read_file(argv[argi], &len); if (!src) return 1; - int rc = compile_spl(src, argv[argi], argv[argi + 1], gen_debug, dump); + int rc = compile_spl(src, argv[argi], argv[argi + 1], gen_debug, dump, opt); free(src); return rc; } diff --git a/stage1/vm_opt.c b/stage1/vm_opt.c new file mode 100644 index 0000000..3c4a55b --- /dev/null +++ b/stage1/vm_opt.c @@ -0,0 +1,165 @@ +/* vm_opt.c - 字节码(VM 层)优化 pass + * + * 从 stage0/spl_mcode.c 迁出:对已生成的 spl_prog_t 做 prog->prog 优化。 + * 默认不启用(由 splc0 --opt 驱动)。 */ + +#include "vm_opt.h" + +#include "../stage0/include/core_map.h" + +#include + +/* 消除“store 后立刻 load 同一槽位”的往返。 + * + * 模式(5 条):laddr X; swap; store k; laddr X; load k + * 变换(3 条):laddr X; pick 1; store k + * [.., v] -> laddr X => [.., v, X] + * -> pick 1 => [.., v, X, v] + * -> store k => [.., v] (存 v 到 X,同时栈上保留 v) + * 与原来 store 后再 load 的效果等价,但去掉 2 条指令与一次内存读。 + * + * 会真的删除指令,因此必须重定位:相对跳转、函数表 address、 + * 以及作为函数指针的 `push ptr `。仅当被删/被改写的指令不是 + * 跳转目标或函数入口时才变换(已收集 mark)。 */ +static usize peep_hash_int(usize k) { return MAP_HASH_INT(k); } +static int peep_cmp_int(usize a, usize b) { return MAP_CMP_INT(a, b); } + +void spl_prog_peephole(spl_prog_t *prog) { + if (!prog) + return; + usize n = vec_size(prog->insns); + if (n < 5) + return; + spl_vm_ins_t *ins = prog->insns.data; + + unsigned char *mark = (unsigned char *)calloc(n, 1); /* 跳转目标/函数入口,受保护 */ + unsigned char *rem = (unsigned char *)calloc(n, 1); + if (!mark || !rem) { + free(mark); + free(rem); + return; + } + + for (usize i = 0; i < n; i++) { + spl_vm_ins_t *x = &ins[i]; + if (x->opcode == SPL_JMP || x->opcode == SPL_BZ || x->opcode == SPL_BNZ) { + isize t = (isize)i + 1 + (isize)x->imm; + if (t >= 0 && (usize)t < n) + mark[(usize)t] = 1; + } + } + vec_for(prog->funcs, fi) { + spl_vm_func_t *f = &vec_at(prog->funcs, fi); + if (f->address < n) + mark[f->address] = 1; + } + + for (usize i = 0; i + 4 < n; i++) { + spl_vm_ins_t *a = &ins[i]; + spl_vm_ins_t *b = &ins[i + 1]; + spl_vm_ins_t *c = &ins[i + 2]; + spl_vm_ins_t *d = &ins[i + 3]; + spl_vm_ins_t *e = &ins[i + 4]; + if (a->opcode == SPL_LADDR && b->opcode == SPL_SWAP && c->opcode == SPL_STORE && + d->opcode == SPL_LADDR && e->opcode == SPL_LOAD && a->imm == d->imm && + c->type == e->type) { + if (mark[i + 1] || mark[i + 3] || mark[i + 4]) + continue; + b->opcode = SPL_PICK; + b->type = SPL_VOID; + b->imm = 1; + rem[i + 3] = 1; + rem[i + 4] = 1; + i += 4; + } + } + + usize kept = 0; + for (usize i = 0; i < n; i++) + if (!rem[i]) + kept++; + if (kept == n) { + free(mark); + free(rem); + return; + } + + spl_vm_ins_t *fresh = (spl_vm_ins_t *)malloc(sizeof(spl_vm_ins_t) * (kept ? kept : 1)); + usize *map = (usize *)malloc(sizeof(usize) * (n + 1)); /* old index -> new index */ + usize *old_of_new = (usize *)malloc(sizeof(usize) * (kept ? kept : 1)); + if (!fresh || !map || !old_of_new) { + free(mark); + free(rem); + free(fresh); + free(map); + free(old_of_new); + return; + } + + usize out = 0; + for (usize i = 0; i < n; i++) { + if (!rem[i]) { + map[i] = out; + old_of_new[out] = i; + fresh[out] = ins[i]; + out++; + } + } + map[n] = kept; + for (usize i = n; i-- > 0;) + if (rem[i]) + map[i] = map[i + 1]; + + /* 函数地址 old->new */ + MAP(usize, usize) addr_map; + map_init(addr_map, peep_hash_int, peep_cmp_int); + vec_for(prog->funcs, fi) { + spl_vm_func_t *f = &vec_at(prog->funcs, fi); + usize old_a = f->address; + if (old_a < n) { + usize new_a = map[old_a]; + map_put(addr_map, old_a, new_a); + f->address = new_a; + } + } + + /* 修正相对跳转与函数指针常量 */ + for (usize j = 0; j < kept; j++) { + spl_vm_ins_t *x = &fresh[j]; + if (x->opcode == SPL_JMP || x->opcode == SPL_BZ || x->opcode == SPL_BNZ) { + isize t = (isize)old_of_new[j] + 1 + (isize)x->imm; + if (t >= 0 && (usize)t <= n) { + usize nt = map[(usize)t]; + x->imm = (spl_vm_val_t)(isize)((isize)nt - (isize)(j + 1)); + } + } else if (x->opcode == SPL_PUSH && x->type == SPL_PTR && x->imm != 0) { + usize nv = 0; + if (map_get(addr_map, (usize)x->imm, &nv)) + x->imm = nv; + } + } + map_free(addr_map); + + /* 指令删除后函数长度变化,重算 ninsns(函数按地址升序排列)。 */ + { + usize nf = vec_size(prog->funcs); + for (usize i = 0; i < nf; i++) { + spl_vm_func_t *f = &vec_at(prog->funcs, i); + usize next = (i + 1 < nf) ? vec_at(prog->funcs, i + 1).address : kept; + f->ninsns = next > f->address ? (spl_vm_val_t)(next - f->address) : 0; + } + } + + free(prog->insns.data); + prog->insns.data = fresh; + prog->insns.size = kept; + prog->insns.cap = kept; + + free(mark); + free(rem); + free(map); + free(old_of_new); +} + +/* 优化 pass 流水线(纯 prog->prog):当前 P1,后续可追加。 */ +void spl_prog_opt(spl_prog_t *prog) { spl_prog_peephole(prog); } diff --git a/stage1/vm_opt.h b/stage1/vm_opt.h new file mode 100644 index 0000000..4708235 --- /dev/null +++ b/stage1/vm_opt.h @@ -0,0 +1,11 @@ +#ifndef __VM_OPT_H__ +#define __VM_OPT_H__ + +/* 字节码(VM 层)优化 pass:输入输出都是 spl_prog_t,纯函数式、可开关。 */ + +#include "../stage0/spl_mcode.h" + +void spl_prog_peephole(spl_prog_t *prog); +void spl_prog_opt(spl_prog_t *prog); + +#endif /* __VM_OPT_H__ */ diff --git a/stage2/ast.spl b/stage2/ast.spl index fb635e8..e90908b 100644 --- a/stage2/ast.spl +++ b/stage2/ast.spl @@ -272,11 +272,8 @@ fn drop(self: *Ast) { } fn node(self: *Ast, ref: usize): *Node { - match Vec.get(&self.nodes, ref) { - .Ok(ptr) => { ret ptr as *Node; }, - .Err(error) => { ret null; }, - } - ret null; + if ref >= self.nodes.len { ret null; } + ret (self.nodes.data as *Node) + ref; } // 追加节点,返回其引用(失败返回 0)。 diff --git a/stage2/ast2ir.spl b/stage2/ast2ir.spl index 6355338..ded4b03 100644 --- a/stage2/ast2ir.spl +++ b/stage2/ast2ir.spl @@ -6,7 +6,7 @@ type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); -type .{ .Map } = @import("utils/map.spl"); +type .{ .Map, .hash_kind_usize } = @import("utils/map.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .hash_usize, .eq_usize } = @import("utils/hash.spl"); @@ -54,8 +54,8 @@ owned: Vec, // ByteBuffer:为 dbg.panic 消息提供稳定存储 // ---- 小工具 ---- fn list_at(v: Vec, i: usize): usize { - match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } } - ret 0; + if i >= v.len { ret 0; } + ret ((v.data as *usize) + i).*; } fn push_u(v: *Vec, x: usize) { @@ -2069,7 +2069,7 @@ fn new(builder: *IrBuilder, sema: *Sema, diag: *Diag): Ast2Ir { .ir = builder, .ast = sema.ast, .def2ir_map = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), - hash_usize, eq_usize), + hash_kind_usize()), .loop_stack = Vec.blank(@sizeof(LoopCtx), @alignof(LoopCtx)), .defer_stack = Vec.blank(@sizeof(usize), @alignof(usize)), .cur_ret_lang = 0, diff --git a/stage2/attr.spl b/stage2/attr.spl index 57bb1c2..a644e6f 100644 --- a/stage2/attr.spl +++ b/stage2/attr.spl @@ -132,11 +132,7 @@ fn drop(self: *Attr) { fn node(self: *Attr, id: usize): *AttrNode { if id == 0 || id >= self.table.len { ret null; } - match Vec.get(&self.table, id) { - .Ok(ptr) => { ret ptr as *AttrNode; }, - .Err(error) => { ret null; }, - } - ret null; + ret (self.table.data as *AttrNode) + id; } fn info_at(self: *Attr, index: usize): *AttrInfo { diff --git a/stage2/def.spl b/stage2/def.spl index 435aa44..0bb6a00 100644 --- a/stage2/def.spl +++ b/stage2/def.spl @@ -87,11 +87,7 @@ fn drop(self: *DefTable) { // id 0 与越界均返回 null(对应 stage1 spl_def_node)。 fn node(self: *DefTable, id: usize): *DefNode { if id == 0 || id >= self.table.len { ret null; } - match Vec.get(&self.table, id) { - .Ok(ptr) => { ret ptr as *DefNode; }, - .Err(error) => { ret null; }, - } - ret null; + ret (self.table.data as *DefNode) + id; } fn count(self: *DefTable): usize { diff --git a/stage2/intrin.spl b/stage2/intrin.spl index cc696b1..c5ddf4b 100644 --- a/stage2/intrin.spl +++ b/stage2/intrin.spl @@ -161,10 +161,7 @@ fn table_count(): usize { fn strip_at(name: ByteView): ByteView { if name.len > 0 && name.ptr[0] == '@' { - match ByteView.slice(name, 1, name.len) { - .Ok(rest) => { ret rest; }, - .Err(error) => { ret name; }, - } + ret ByteView { .ptr = name.ptr + 1, .len = name.len - 1 }; } ret name; } diff --git a/stage2/ir.spl b/stage2/ir.spl index cfc4c68..29f4b8a 100644 --- a/stage2/ir.spl +++ b/stage2/ir.spl @@ -167,26 +167,16 @@ fn drop_body(body: IrBody) { fn drop(self: *Ir) { var i: usize = 0; while i < self.funcs.len { - match Vec.get(&self.funcs, i) { - .Ok(ptr) => { - var f = ptr as *IrFunc; - var j: usize = 0; - while j < f.nodes.len { - match Vec.get(&f.nodes, j) { - .Ok(np) => { - var e = np as *IrEntry; - Vec.drop(&e.attrs); - drop_body(e.body); - }, - .Err(error) => {}, - } - j = j + 1; - } - Vec.drop(&f.attrs); - Vec.drop(&f.nodes); - }, - .Err(error) => {}, + var f = (self.funcs.data as *IrFunc) + i; + var j: usize = 0; + while j < f.nodes.len { + var e = (f.nodes.data as *IrEntry) + j; + Vec.drop(&e.attrs); + drop_body(e.body); + j = j + 1; } + Vec.drop(&f.attrs); + Vec.drop(&f.nodes); i = i + 1; } Vec.drop(&self.funcs); @@ -207,36 +197,22 @@ fn alloc_fn(self: *Ir): usize { fn alloc_node(self: *Ir, fn_id: usize): usize { if fn_id == 0 || fn_id >= self.funcs.len { ret 0; } - match Vec.get(&self.funcs, fn_id) { - .Ok(ptr) => { - var f = ptr as *IrFunc; - var n = new_entry(); - match Vec.push(&f.nodes, &n as *u8) { .Ok => {}, .Err(error) => { ret 0; } } - ret f.nodes.len - 1; - }, - .Err(error) => {}, - } - ret 0; + var f = (self.funcs.data as *IrFunc) + fn_id; + var n = new_entry(); + match Vec.push(&f.nodes, &n as *u8) { .Ok => {}, .Err(error) => { ret 0; } } + ret f.nodes.len - 1; } fn func(self: *Ir, fn_id: usize): *IrFunc { if fn_id == 0 || fn_id >= self.funcs.len { ret null; } - match Vec.get(&self.funcs, fn_id) { - .Ok(ptr) => { ret ptr as *IrFunc; }, - .Err(error) => { ret null; }, - } - ret null; + ret (self.funcs.data as *IrFunc) + fn_id; } fn node(self: *Ir, fn_id: usize, node_id: usize): *IrEntry { var f = func(self, fn_id); if f == null { ret null; } if node_id == 0 || node_id >= f.nodes.len { ret null; } - match Vec.get(&f.nodes, node_id) { - .Ok(ptr) => { ret ptr as *IrEntry; }, - .Err(error) => { ret null; }, - } - ret null; + ret (f.nodes.data as *IrEntry) + node_id; } fn kind_name(kind: IrKind): []u8 { @@ -345,8 +321,8 @@ fn dump_attrs(out: *ByteBuffer, attr: *Attr, ids: Vec): bool { } fn list_at(v: Vec, i: usize): usize { - match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } } - ret 0; + if i >= v.len { ret 0; } + ret ((v.data as *usize) + i).*; } fn dump_body(out: *ByteBuffer, ty: *TypeTable, e: *IrEntry): bool { diff --git a/stage2/ir2vm.spl b/stage2/ir2vm.spl index fb309d5..baae87b 100644 --- a/stage2/ir2vm.spl +++ b/stage2/ir2vm.spl @@ -362,7 +362,7 @@ fn frame_build(fl: *FrameLayout, ctx: *Ir2Vm, fid: usize) { var i: usize = 0; while i < n { var blank: Slot = .{ .result_off = 0, .data_off = 0 }; - match Vec.push(&fl.slots, &blank as *u8) { .Ok => {}, .Err(error) => {} } + ignore_bool(Vec.push_raw(&fl.slots, &blank as *u8)); i = i + 1; } @@ -421,7 +421,17 @@ fixups: *Vec, terminated: bool, fn emit(cg: *Cgen, op: Op, ty: VmKind, imm: usize) { - ignore_usize(Mcode.add_instr(&cg.ctx.prog, op, ty, imm)); + var prog = &cg.ctx.prog; + var i = prog.insns.len; + if i < prog.insns.cap { + var p = (prog.insns.data as *VmIns) + i; + p.opcode = op; + p.ty = ty; + p.imm = imm; + prog.insns.len = i + 1; + ret; + } + ignore_usize(Mcode.add_instr(prog, op, ty, imm)); } fn ip_of(cg: *Cgen): usize { diff --git a/stage2/ir_builder.spl b/stage2/ir_builder.spl index 8ef26f1..a8b282a 100644 --- a/stage2/ir_builder.spl +++ b/stage2/ir_builder.spl @@ -14,8 +14,8 @@ type Ir = @import("./ir.spl"); type .{ .IrKind, .ConstLit, .IrEntry, .IrFunc, .IrBody } = @import("./ir.spl"); fn list_at(v: Vec, i: usize): usize { - match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } } - ret 0; + if i >= v.len { ret 0; } + ret ((v.data as *usize) + i).*; } // ---- builder ---- diff --git a/stage2/lang_type.spl b/stage2/lang_type.spl index d611adc..1695a38 100644 --- a/stage2/lang_type.spl +++ b/stage2/lang_type.spl @@ -9,7 +9,7 @@ type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); -type .{ .Map } = @import("utils/map.spl"); +type .{ .Map, .hash_kind_usize } = @import("utils/map.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .append_usize } = @import("utils/fmt.spl"); @@ -183,7 +183,7 @@ fn new(): LangTypeResult { .ir = ir, .lang_table = lang_table, .fold = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), - hash_usize, eq_usize), + hash_kind_usize()), .defs = defs, .owned_names = Vec.blank(@sizeof(ByteBuffer), @alignof(ByteBuffer)), }; @@ -218,11 +218,7 @@ fn drop(self: *LangType) { // id 0 与越界返回 null(对应 stage1 spl_lang_type_node)。 fn lang_node(self: *LangType, id: usize): *LangEntry { if id == 0 || id >= self.lang_table.len { ret null; } - match Vec.get(&self.lang_table, id) { - .Ok(ptr) => { ret ptr as *LangEntry; }, - .Err(error) => { ret null; }, - } - ret null; + ret (self.lang_table.data as *LangEntry) + id; } fn ir_type(self: *LangType, lang_id: usize): usize { diff --git a/stage2/layout.spl b/stage2/layout.spl index 847238c..959e372 100644 --- a/stage2/layout.spl +++ b/stage2/layout.spl @@ -44,11 +44,7 @@ fn new(): LayoutResult { fn info_at(self: *Layout, id: usize): *LayoutInfo { if id == 0 || id >= self.infos.len { ret null; } - match Vec.get(&self.infos, id) { - .Ok(ptr) => { ret ptr as *LayoutInfo; }, - .Err(error) => { ret null; }, - } - ret null; + ret (self.infos.data as *LayoutInfo) + id; } // 未解析或越界返回 null(对应 stage1 spl_layout_info_of)。 diff --git a/stage2/lexer.spl b/stage2/lexer.spl index 0fdf7e3..ef6dc13 100644 --- a/stage2/lexer.spl +++ b/stage2/lexer.spl @@ -92,11 +92,8 @@ fn has3(self: *Lexer, ch1: u8, ch2: u8): bool { } fn sub(self: *Lexer, start: usize, end: usize): ByteView { - match ByteView.slice(self.src, start, end) { - .Ok(v) => { ret v; }, - .Err(error) => { ret ByteView.empty(); }, - } - ret ByteView.empty(); + if start >= end { ret ByteView.empty(); } + ret ByteView { .ptr = self.src.ptr + start, .len = end - start }; } // 产出 token 并把 pos/col 推进到 end。Vec.push 失败视为致命(同 vec.make_vec 风格)。 diff --git a/stage2/mcode.spl b/stage2/mcode.spl index 654c462..5621a69 100644 --- a/stage2/mcode.spl +++ b/stage2/mcode.spl @@ -265,6 +265,15 @@ fn drop(self: *Prog) { // ---- 构建 ---- fn add_instr(self: *Prog, op: Op, ty: VmKind, imm: usize): usize { + var i = self.insns.len; + if i < self.insns.cap { + var p = (self.insns.data as *VmIns) + i; + p.opcode = op; + p.ty = ty; + p.imm = imm; + self.insns.len = i + 1; + ret i + 1; + } var ins = VmIns { .opcode = op, .ty = ty, .imm = imm }; if !Vec.push_raw(&self.insns, &ins as *u8) { ret 0; } ret self.insns.len; @@ -462,11 +471,8 @@ fn dump(self: *Prog, out: *ByteBuffer): bool { } fn ins_at(self: *Prog, i: usize): VmIns { - match Vec.get(&self.insns, i) { - .Ok(ptr) => { ret (ptr as *VmIns).*; }, - .Err(error) => { ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 }; }, - } - ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 }; + if i >= self.insns.len { ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 }; } + ret ((self.insns.data as *VmIns) + i).*; } fn func_at(self: *Prog, i: usize): *VmFunc { @@ -491,41 +497,43 @@ fn align8(n: usize): usize { ret (n + 7) & (~(7 as usize)); } +// 说明:以下 put_* 直接写入已预留容量的 ByteBuffer 存储(store 已按精确总大小 reserve), +// 跳过 ByteBuffer.append → Vec.append 的校验/拷贝路径。若容量不足会越界,故 store 先校验容量。 + fn put_u8(out: *ByteBuffer, b: u8): bool { - match ByteBuffer.append_byte(out, b) { .Ok => { ret true; }, .Err(error) => { ret false; } } - ret false; + out.storage.data[out.storage.len] = b; + out.storage.len = out.storage.len + 1; + ret true; } +// 直接按小端整型写(x86 小端;VM 的 STORE 用 memcpy,未对齐也安全)。 fn put_u16(out: *ByteBuffer, v: usize): bool { - if !put_u8(out, (v & 255) as u8) { ret false; } - ret put_u8(out, ((v >> 8) & 255) as u8); + var d = out.storage.data + out.storage.len; + (d as *u16).* = v as u16; + out.storage.len = out.storage.len + 2; + ret true; } fn put_u64(out: *ByteBuffer, v: usize): bool { - var i: usize = 0; - while i < 8 { - if !put_u8(out, ((v >> (i * 8)) & 255) as u8) { ret false; } - i = i + 1; - } + var d = out.storage.data + out.storage.len; + (d as *u64).* = v as u64; + out.storage.len = out.storage.len + 8; ret true; } fn put_zeros(out: *ByteBuffer, n: usize): bool { - var i: usize = 0; - while i < n { - if !put_u8(out, 0) { ret false; } - i = i + 1; + if n != 0 { + ignore_ptr(Mem.set((out.storage.data + out.storage.len) as *any, 0, n)); + out.storage.len = out.storage.len + n; } ret true; } fn put_view(out: *ByteBuffer, v: ByteView): bool { if v.len == 0 { ret true; } - match ByteBuffer.append(out, ByteView.as_slice(v)) { - .Ok => { ret true; }, - .Err(error) => { ret false; }, - } - ret false; + Mem.copy((out.storage.data + out.storage.len) as *any, v.ptr as *any, v.len); + out.storage.len = out.storage.len + v.len; + ret true; } // 写入「带结尾 NUL、再按 8 对齐」的名称字段(对应 C 侧 nlen = strlen+1)。 @@ -541,6 +549,41 @@ fn store(self: *Prog, path: ByteView): Status { var out = ByteBuffer.new(); defer { ByteBuffer.drop(&out); } + // 精确预估输出大小并一次性预留,避免大文件逐字节增长导致的重复拷贝。 + var total: usize = 48; + var fi: usize = 0; + while fi < self.funcs.len { + var f = func_at(self, fi); + if f != null { + var nlen = f.name.len + 1; + total = total + 8 + align8(nlen) + 32; + } + fi = fi + 1; + } + total = total + self.insns.len * 12; + fi = 0; + while fi < self.natives.len { + var n = native_at(self, fi); + if n != null { + var nlen = n.name.len + 1; + total = total + 8 + align8(nlen) + 8; + } + fi = fi + 1; + } + fi = 0; + while fi < self.strtab.len { + total = total + 8 + align8(str_at(self, fi).len); + fi = fi + 1; + } + fi = 1; + while fi < self.gdata.len { + var e = gdata_at(self, fi); + if e != null { total = total + 8 + align8(e.storage.len); } + fi = fi + 1; + } + match ByteBuffer.reserve(&out, total) { .Ok => {}, .Err(error) => {} } + if out.storage.cap < total || out.storage.data == null { ret .Err(make(.Io)); } + if !put_view(&out, ByteView.from_slice("SPLBIN")) { ret .Err(make(.Io)); } if !put_zeros(&out, 2) { ret .Err(make(.Io)); } @@ -572,9 +615,11 @@ fn store(self: *Prog, path: ByteView): Status { i = 0; while i < ninsns { var ins = ins_at(self, i); - if !put_u16(&out, @enum2int(ins.opcode) as usize) { ret .Err(make(.Io)); } - if !put_u16(&out, @enum2int(ins.ty) as usize) { ret .Err(make(.Io)); } - if !put_u64(&out, ins.imm) { ret .Err(make(.Io)); } + var d = out.storage.data + out.storage.len; + (d as *u16).* = @enum2int(ins.opcode) as u16; + ((d + 2) as *u16).* = @enum2int(ins.ty) as u16; + ((d + 4) as *u64).* = ins.imm as u64; + out.storage.len = out.storage.len + 12; i = i + 1; } diff --git a/stage2/parser.spl b/stage2/parser.spl index 92aab60..7e2d575 100644 --- a/stage2/parser.spl +++ b/stage2/parser.spl @@ -42,11 +42,8 @@ fn new(ast: *Ast, toks: Vec, diag: *Diag): Parser { // ---- token 访问 ---- fn token_ptr(self: *Parser, index: usize): *Token { - match Vec.get(&self.toks, index) { - .Ok(ptr) => { ret ptr as *Token; }, - .Err(error) => { ret null; }, - } - ret null; + if index >= self.toks.len { ret null; } + ret (self.toks.data as *Token) + index; } fn is_trivia(kind: TokenKind): bool { @@ -61,16 +58,17 @@ fn is_trivia(kind: TokenKind): bool { // 跳过 trivia;返回当前 token(含 EOF)。越界返回 null。 fn peek(self: *Parser): *Token { var n = self.toks.len; + var base = self.toks.data as *Token; var i = self.pos; while i < n { - var t = token_ptr(self, i); - if t == null { break; } + if base == null { break; } + var t = base + i; if !is_trivia(t.kind) { break; } i = i + 1; } self.pos = i; - if i >= n { ret null; } - ret token_ptr(self, i); + if i >= n || base == null { ret null; } + ret base + i; } fn advance(self: *Parser): *Token { diff --git a/stage2/scope.spl b/stage2/scope.spl index 32cb3ca..f28fd94 100644 --- a/stage2/scope.spl +++ b/stage2/scope.spl @@ -7,7 +7,7 @@ type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); -type .{ .Map } = @import("utils/map.spl"); +type .{ .Map, .hash_kind_view } = @import("utils/map.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .hash_view, .eq_view } = @import("utils/hash.spl"); @@ -43,7 +43,7 @@ type ScopeResult = enum { fn new_map(): Map { ret Map.new(@sizeof(ByteView), @alignof(ByteView), @sizeof(Symbol), @alignof(Symbol), - hash_view, eq_view); + hash_kind_view()); } fn new(): ScopeResult { @@ -81,11 +81,7 @@ fn drop(self: *Scope) { // id 0 与越界返回 null。 fn node(self: *Scope, id: usize): *ScopeNode { if id == 0 || id >= self.scopes.len { ret null; } - match Vec.get(&self.scopes, id) { - .Ok(ptr) => { ret ptr as *ScopeNode; }, - .Err(error) => { ret null; }, - } - ret null; + ret (self.scopes.data as *ScopeNode) + id; } // 新作用域 parent = 当前作用域;不自动切换 current(调用方负责,见 sema)。 diff --git a/stage2/sema.spl b/stage2/sema.spl index 150950e..f9a98b4 100644 --- a/stage2/sema.spl +++ b/stage2/sema.spl @@ -9,7 +9,7 @@ type .{ .Error, .Status } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); -type .{ .Map } = @import("utils/map.spl"); +type .{ .Map, .hash_kind_usize } = @import("utils/map.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .append_usize } = @import("utils/fmt.spl"); @@ -69,11 +69,8 @@ type SemaResult = enum { // ---- 小工具 ---- fn list_at(v: Vec, i: usize): usize { - match Vec.get(&v, i) { - .Ok(ptr) => { ret (ptr as *usize).*; }, - .Err(error) => { ret 0; }, - } - ret 0; + if i >= v.len { ret 0; } + ret ((v.data as *usize) + i).*; } fn push_u(v: *Vec, x: usize) { @@ -234,7 +231,7 @@ fn new(ast: *Ast, diag: *Diag): SemaResult { .current_loop_break_tid = 0, .label_stack = Vec.blank(@sizeof(ByteView), @alignof(ByteView)), .ir_to_lang = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), - hash_usize, eq_usize), + hash_kind_usize()), }; ret .Ok(s); } diff --git a/stage2/sys/time.spl b/stage2/sys/time.spl index f55f76e..5eab63b 100644 --- a/stage2/sys/time.spl +++ b/stage2/sys/time.spl @@ -25,6 +25,10 @@ fn steps(): usize { ret vm_timestamp(3); } +fn calls(): usize { + ret vm_timestamp(5); +} + fn now_ns(): usize { ret vm_timestamp(4); } diff --git a/stage2/token.spl b/stage2/token.spl index ed227d4..44b4ff3 100644 --- a/stage2/token.spl +++ b/stage2/token.spl @@ -66,37 +66,65 @@ fn is_trivia(kind: TokenKind): bool { } } +// 先按长度与首字节分派,再做完整比较,避免对每个标识符做全表串比较。 fn keyword_of(text: ByteView): KeywordResult { - if is(text, "any") { ret .Yes(.Any); } - if is(text, "as") { ret .Yes(.As); } - if is(text, "bool") { ret .Yes(.Bool); } - if is(text, "break") { ret .Yes(.Break); } - if is(text, "catch") { ret .Yes(.Catch); } - if is(text, "comptime") { ret .Yes(.Comptime); } - if is(text, "const") { ret .Yes(.Const); } - if is(text, "continue") { ret .Yes(.Continue); } - if is(text, "defer") { ret .Yes(.Defer); } - if is(text, "else") { ret .Yes(.Else); } - if is(text, "enum") { ret .Yes(.Enum); } - if is(text, "errdefer") { ret .Yes(.Errdefer); } - if is(text, "false") { ret .Yes(.False); } - if is(text, "fn") { ret .Yes(.Fn); } - if is(text, "for") { ret .Yes(.For); } - if is(text, "if") { ret .Yes(.If); } - if is(text, "loop") { ret .Yes(.Loop); } - if is(text, "match") { ret .Yes(.Match); } - if is(text, "null") { ret .Yes(.Null); } - if is(text, "ret") { ret .Yes(.Ret); } - if is(text, "shape") { ret .Yes(.Shape); } - if is(text, "struct") { ret .Yes(.Struct); } - if is(text, "true") { ret .Yes(.True); } - if is(text, "try") { ret .Yes(.Try); } - if is(text, "type") { ret .Yes(.Type); } - if is(text, "undefined") { ret .Yes(.Undefined); } - if is(text, "union") { ret .Yes(.Union); } - if is(text, "var") { ret .Yes(.Var); } - if is(text, "while") { ret .Yes(.While); } - if is(text, "_") { ret .Yes(.Underscore); } + var n = text.len; + if n == 0 { ret .No; } + var c0 = text.ptr[0]; + if n == 2 { + if c0 == 'a' && is(text, "as") { ret .Yes(.As); } + if c0 == 'f' && is(text, "fn") { ret .Yes(.Fn); } + if c0 == 'i' && is(text, "if") { ret .Yes(.If); } + ret .No; + } + if n == 3 { + if c0 == 'a' && is(text, "any") { ret .Yes(.Any); } + if c0 == 'f' && is(text, "for") { ret .Yes(.For); } + if c0 == 'r' && is(text, "ret") { ret .Yes(.Ret); } + if c0 == 't' && is(text, "try") { ret .Yes(.Try); } + if c0 == 'v' && is(text, "var") { ret .Yes(.Var); } + ret .No; + } + if n == 4 { + if c0 == 'b' && is(text, "bool") { ret .Yes(.Bool); } + if c0 == 'e' && is(text, "else") { ret .Yes(.Else); } + if c0 == 'e' && is(text, "enum") { ret .Yes(.Enum); } + if c0 == 'l' && is(text, "loop") { ret .Yes(.Loop); } + if c0 == 'n' && is(text, "null") { ret .Yes(.Null); } + if c0 == 't' && is(text, "true") { ret .Yes(.True); } + if c0 == 't' && is(text, "type") { ret .Yes(.Type); } + ret .No; + } + if n == 5 { + if c0 == 'b' && is(text, "break") { ret .Yes(.Break); } + if c0 == 'c' && is(text, "catch") { ret .Yes(.Catch); } + if c0 == 'c' && is(text, "const") { ret .Yes(.Const); } + if c0 == 'd' && is(text, "defer") { ret .Yes(.Defer); } + if c0 == 'f' && is(text, "false") { ret .Yes(.False); } + if c0 == 'm' && is(text, "match") { ret .Yes(.Match); } + if c0 == 's' && is(text, "shape") { ret .Yes(.Shape); } + if c0 == 'u' && is(text, "union") { ret .Yes(.Union); } + if c0 == 'w' && is(text, "while") { ret .Yes(.While); } + ret .No; + } + if n == 6 { + if c0 == 's' && is(text, "struct") { ret .Yes(.Struct); } + ret .No; + } + if n == 8 { + if c0 == 'c' && is(text, "comptime") { ret .Yes(.Comptime); } + if c0 == 'c' && is(text, "continue") { ret .Yes(.Continue); } + if c0 == 'e' && is(text, "errdefer") { ret .Yes(.Errdefer); } + ret .No; + } + if n == 9 { + if c0 == 'u' && is(text, "undefined") { ret .Yes(.Undefined); } + ret .No; + } + if n == 1 { + if c0 == '_' && is(text, "_") { ret .Yes(.Underscore); } + ret .No; + } ret .No; } diff --git a/stage2/type_table.spl b/stage2/type_table.spl index 5adf3f9..d69ed79 100644 --- a/stage2/type_table.spl +++ b/stage2/type_table.spl @@ -9,7 +9,7 @@ type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); -type .{ .Map } = @import("utils/map.spl"); +type .{ .Map, .hash_kind_usize } = @import("utils/map.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .append_usize } = @import("utils/fmt.spl"); @@ -301,11 +301,8 @@ fn usize_at(v: Vec, i: usize): usize { } fn member_at(v: *Vec, i: usize): *Member { - match Vec.get(v, i) { - .Ok(ptr) => { ret ptr as *Member; }, - .Err(error) => { ret null; }, - } - ret null; + if i >= v.len { ret null; } + ret (v.data as *Member) + i; } fn push_member(v: *Vec, name: []u8, type_id: usize) { @@ -323,11 +320,7 @@ fn push_member(v: *Vec, name: []u8, type_id: usize) { // id 0 与越界均返回 null(对应 stage1 spl_type_node)。 fn node(self: *TypeTable, id: usize): *TypeEntry { if id == 0 || id >= self.table.len { ret null; } - match Vec.get(&self.table, id) { - .Ok(ptr) => { ret ptr as *TypeEntry; }, - .Err(error) => { ret null; }, - } - ret null; + ret (self.table.data as *TypeEntry) + id; } // ---- 生命周期 ---- @@ -336,7 +329,7 @@ fn new(): TypeTableResult { var tt = TypeTable { .table = Vec.blank(@sizeof(TypeEntry), @alignof(TypeEntry)), .fold = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), - hash_usize, eq_usize), + hash_kind_usize()), }; var sentinel = TypeEntry { .hash_next = 0, .node = .Error }; match Vec.push(&tt.table, &sentinel as *u8) { diff --git a/stage2/utils/byte_view.spl b/stage2/utils/byte_view.spl index fa365ad..08ab626 100644 --- a/stage2/utils/byte_view.spl +++ b/stage2/utils/byte_view.spl @@ -5,6 +5,8 @@ type .{ .Error, .make } = @import("error.spl"); +#extern(vm) fn vm_bytes_eq(a: *any, alen: usize, b: *any, blen: usize): i32; + type ByteView = @self; ptr: *u8, @@ -62,13 +64,7 @@ fn byte_at(self: ByteView, index: usize): ByteResult { } fn eq(a: ByteView, b: ByteView): bool { - if a.len != b.len { ret false; } - var i: usize = 0; - while i < a.len { - if a.ptr[i] != b.ptr[i] { ret false; } - i = i + 1; - } - ret true; + ret vm_bytes_eq(a.ptr as *any, a.len, b.ptr as *any, b.len) != 0; } // 按无符号字节进行字典序比较,结果只承诺小于、等于或大于零。 diff --git a/stage2/utils/map.spl b/stage2/utils/map.spl index eac66f1..276f048 100644 --- a/stage2/utils/map.spl +++ b/stage2/utils/map.spl @@ -7,9 +7,14 @@ type .{ .Error, .Status, .make } = @import("error.spl"); type .{ .Vec } = @import("vec.spl"); type .{ .ByteView } = @import("byte_view.spl"); -type .{ .hash_usize, .eq_usize, .hash_view, .eq_view } = @import("hash.spl"); -type .{ .checked_add, .checked_mul, .grow_capacity } = @import("memory.spl"); -type .{ .copy } = @import("../sys/mem.spl"); + +#extern(vm) fn vm_map_valid(m: *any): i32; +#extern(vm) fn vm_map_reserve(m: *any, need: usize): i32; +#extern(vm) fn vm_map_put(m: *any, key: *any, val: *any): i32; +#extern(vm) fn vm_map_get(m: *any, key: *any, out: *any): i32; +#extern(vm) fn vm_map_del(m: *any, key: *any): i32; +#extern(vm) fn vm_map_clear(m: *any): void; +#extern(vm) fn vm_map_drop(m: *any): void; // 槽位状态:Empty/Occupied/Deleted(墓碑,仅在扩容重哈希时清除)。 // 负载因子 70/128。 @@ -20,11 +25,6 @@ type SlotState = enum { Deleted, } -fn state_code(state: SlotState): u8 { - var s: SlotState = state; - ret @enum2int(s) as u8; -} - // 查找/删除结果:显式区分命中与缺失,替代 bool 哨兵。 type LookupResult = enum { Found, @@ -39,11 +39,15 @@ states: Vec, size: usize, key_size: usize, val_size: usize, -hash_fn: fn(*u8): usize, -eq_fn: fn(*u8, *u8): bool, +hash_kind: usize, + +// 键解释:0 = usize;1 = ByteView(按内容哈希/比较)。 +fn hash_kind_usize(): usize { ret 0; } +fn hash_kind_view(): usize { ret 1; } +fn hash_kind_constant(): usize { ret 2; } fn blank(key_size: usize, key_align: usize, val_size: usize, val_align: usize, - hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Map { + hash_kind: usize): Map { ret Map { .keys = Vec.blank(key_size, key_align), .vals = Vec.blank(val_size, val_align), @@ -51,23 +55,30 @@ fn blank(key_size: usize, key_align: usize, val_size: usize, val_align: usize, .size = 0, .key_size = key_size, .val_size = val_size, - .hash_fn = hash_fn, - .eq_fn = eq_fn, + .hash_kind = hash_kind, }; } fn new(key_size: usize, key_align: usize, val_size: usize, val_align: usize, - hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Map { - ret blank(key_size, key_align, val_size, val_align, hash_fn, eq_fn); + hash_kind: usize): Map { + ret blank(key_size, key_align, val_size, val_align, hash_kind); } -fn valid(self: Map): bool { - if self.key_size == 0 || self.val_size == 0 { ret false; } - if self.states.len != self.keys.len || self.states.len != self.vals.len { - ret false; - } - if self.size > self.states.len { ret false; } - ret true; +fn status_from_code(code: i32): Status { + if code == 0 { ret .Ok; } + if code == 2 { ret .Err(make(.OutOfRange)); } + if code == 3 { ret .Err(make(.Overflow)); } + if code == 4 { ret .Err(make(.InvalidAlignment)); } + ret .Err(make(.InvalidArgument)); +} + +fn lookup_from_code(code: i32): LookupResult { + if code == 0 { ret .Found; } + ret .NotFound; +} + +fn valid(self: *Map): bool { + ret vm_map_valid(self as *any) != 0; } fn size(self: Map): usize { @@ -85,10 +96,8 @@ fn slot_count(self: Map): usize { fn slot_state(self: Map, index: usize): SlotState { var code = self.states.data[index]; - var occupied: SlotState = .Occupied; - var deleted_state: SlotState = .Deleted; - if code == state_code(occupied) { ret .Occupied; } - if code == state_code(deleted_state) { ret .Deleted; } + if code == 1 { ret .Occupied; } + if code == 2 { ret .Deleted; } ret .Empty; } @@ -109,186 +118,32 @@ fn val_at(self: *Map, index: usize): *u8 { ret self.vals.data + index * self.val_size; } -// 返回占用键的槽位;未找到返回 ~0。容量为 0 时直接未找到。 -fn find_slot(self: *Map, key: *u8): usize { - if self.states.cap == 0 { ret ~(0 as usize); } - var mask = self.states.cap - 1; - var i = self.hash_fn(key) & mask; - var empty: SlotState = .Empty; - var occupied: SlotState = .Occupied; - var probes: usize = 0; - while probes < self.states.cap && self.states.data[i] != state_code(empty) { - if self.states.data[i] == state_code(occupied) && - self.eq_fn(self.keys.data + i * self.key_size, key) { - ret i; - } - i = (i + 1) & mask; - probes = probes + 1; - } - ret ~(0 as usize); -} - -// 要求容量非零且键不存在。优先复用探测链中的第一个墓碑。 -fn place(self: *Map, key: *u8, val: *u8) { - var mask = self.states.cap - 1; - var i = self.hash_fn(key) & mask; - var empty: SlotState = .Empty; - var deleted: SlotState = .Deleted; - var occupied: SlotState = .Occupied; - var first_deleted = ~(0 as usize); - var probes: usize = 0; - while probes < self.states.cap && self.states.data[i] != state_code(empty) { - if self.states.data[i] == state_code(deleted) && first_deleted == ~(0 as usize) { - first_deleted = i; - } - i = (i + 1) & mask; - probes = probes + 1; - } - if first_deleted != ~(0 as usize) { - i = first_deleted; - } - copy((self.keys.data + i * self.key_size) as *any, key as *any, self.key_size); - copy((self.vals.data + i * self.val_size) as *any, val as *any, self.val_size); - self.states.data[i] = state_code(occupied); - self.size = self.size + 1; -} - // 保证至少 need 个槽位。所有检查在旧表改动前完成,失败保持原表不变。 fn reserve(self: *Map, need: usize): Status { - if !valid(self.*) { ret .Err(make(.InvalidArgument)); } - if need <= self.states.cap { ret .Ok; } - - var new_cap = grow_capacity(self.states.cap, 8, need); - - var fresh = self.*; - fresh.keys = Vec.blank(self.key_size, self.keys.elem_align); - fresh.vals = Vec.blank(self.val_size, self.vals.elem_align); - fresh.states = Vec.blank(1, 1); - fresh.size = 0; - - match Vec.reserve(&fresh.keys, new_cap) { - .Ok => {}, - .Err(error) => { drop(&fresh); ret .Err(error); }, - } - match Vec.reserve(&fresh.vals, new_cap) { - .Ok => {}, - .Err(error) => { drop(&fresh); ret .Err(error); }, - } - match Vec.reserve(&fresh.states, new_cap) { - .Ok => {}, - .Err(error) => { drop(&fresh); ret .Err(error); }, - } - fresh.keys.len = new_cap; - fresh.vals.len = new_cap; - fresh.states.len = new_cap; - - var i: usize = 0; - var empty: SlotState = .Empty; - var occupied: SlotState = .Occupied; - while i < new_cap { - fresh.states.data[i] = state_code(empty); - i = i + 1; - } - - i = 0; - while i < self.states.len { - if self.states.data[i] == state_code(occupied) { - place(&fresh, self.keys.data + i * self.key_size, - self.vals.data + i * self.val_size); - } - i = i + 1; - } - - var old_keys = self.keys; - var old_vals = self.vals; - var old_states = self.states; - self.* = fresh; - Vec.drop(&old_keys); - Vec.drop(&old_vals); - Vec.drop(&old_states); - ret .Ok; + ret status_from_code(vm_map_reserve(self as *any, need)); } // 覆盖已存在的键;否则插入并可能扩容。 fn put(self: *Map, key: *u8, val: *u8): Status { - if !valid(self.*) || key == null || val == null { - ret .Err(make(.InvalidArgument)); - } - - var existing = find_slot(self, key); - if existing != ~(0 as usize) { - copy((self.vals.data + existing * self.val_size) as *any, val as *any, self.val_size); - ret .Ok; - } - - if self.states.cap == 0 { - match reserve(self, 8) { - .Ok => {}, - .Err(error) => { ret .Err(error); }, - } - } else { - var next_size: usize = 0; - match checked_add(self.size, 1) { - .Ok(value) => { next_size = value; }, - .Err(error) => { ret .Err(error); }, - } - var scaled: usize = 0; - match checked_mul(next_size, 128) { - .Ok(value) => { scaled = value; }, - .Err(error) => { ret .Err(error); }, - } - if scaled / self.states.cap >= 70 { - var need: usize = 0; - match checked_mul(self.states.cap, 2) { - .Ok(value) => { need = value; }, - .Err(error) => { ret .Err(error); }, - } - match reserve(self, need) { - .Ok => {}, - .Err(error) => { ret .Err(error); }, - } - } - } - - place(self, key, val); - ret .Ok; + ret status_from_code(vm_map_put(self as *any, key as *any, val as *any)); } // 找到键则把值复制到 out 并返回 Found;否则 out 不变并返回 NotFound。 fn get(self: *Map, key: *u8, out: *u8): LookupResult { - if !valid(self.*) || key == null || out == null { ret .NotFound; } - var i = find_slot(self, key); - if i == ~(0 as usize) { ret .NotFound; } - copy(out as *any, (self.vals.data + i * self.val_size) as *any, self.val_size); - ret .Found; + ret lookup_from_code(vm_map_get(self as *any, key as *any, out as *any)); } fn del(self: *Map, key: *u8): LookupResult { - if !valid(self.*) || key == null { ret .NotFound; } - var i = find_slot(self, key); - if i == ~(0 as usize) { ret .NotFound; } - var deleted_state: SlotState = .Deleted; - self.states.data[i] = state_code(deleted_state); - self.size = self.size - 1; - ret .Found; + ret lookup_from_code(vm_map_del(self as *any, key as *any)); } // 清空内容但保留容量。墓碑与负载计数一并复位。 fn clear(self: *Map) { - var i: usize = 0; - var empty: SlotState = .Empty; - while i < self.states.len { - self.states.data[i] = state_code(empty); - i = i + 1; - } - self.size = 0; + vm_map_clear(self as *any); } fn drop(self: *Map) { - Vec.drop(&self.keys); - Vec.drop(&self.vals); - Vec.drop(&self.states); - self.size = 0; + vm_map_drop(self as *any); } fn take(source: *Map): Map { @@ -348,13 +203,13 @@ fn deleted(m: *Map, key: *u8): bool { } fn make_int_map(): Map { - ret new(@sizeof(usize), @alignof(usize), @sizeof(i32), @alignof(i32), hash_usize, eq_usize); + ret new(@sizeof(usize), @alignof(usize), @sizeof(i32), @alignof(i32), hash_kind_usize()); } fn test_put_get_update() { var m = make_int_map(); @assert(size(m) == 0 && capacity(m) == 0, "empty map"); - @assert(valid(m)); + @assert(valid(&m)); var key: usize = 0; var value: i32 = 0; @@ -367,7 +222,7 @@ fn test_put_get_update() { key = 7; value = 70; expect_ok(put(&m, &key as *u8, &value as *u8)); - @assert(size(m) == 1 && valid(m)); + @assert(size(m) == 1 && valid(&m)); out = -1; @assert(found(&m, &key as *u8, &out as *u8) && out == 70, "insert then get"); @@ -463,7 +318,7 @@ fn test_take_and_self_put() { fn test_byte_view_keys() { var m = new(@sizeof(ByteView), @alignof(ByteView), @sizeof(i32), @alignof(i32), - hash_view, eq_view); + hash_kind_view()); defer { drop(&m); } var alpha = ByteView.from_slice("alpha"); diff --git a/stage2/utils/memory.spl b/stage2/utils/memory.spl index 21f85b9..4dc483f 100644 --- a/stage2/utils/memory.spl +++ b/stage2/utils/memory.spl @@ -5,6 +5,7 @@ type .{ .Error, .Status, .make } = @import("error.spl"); #extern(vm) fn vm_memcpy(dst: *any, src: *any, n: usize): *any; +#extern(vm) fn vm_memmove(dst: *any, src: *any, n: usize): *any; fn ignore_ptr(p: *any) {} @@ -73,31 +74,8 @@ fn move(dst: []u8, src: []u8): Status { } if dst_addr == src_addr { ret .Ok; } - // 非重叠且较大时走原生 memcpy(Vec 扩容复制是常见场景)。 - var non_overlap = false; - if dst_addr < src_addr { - if src_addr - dst_addr >= count { non_overlap = true; } - } else { - if dst_addr - src_addr >= count { non_overlap = true; } - } - if non_overlap && count >= 16 { - ignore_ptr(vm_memcpy(dst.ptr as *any, src.ptr as *any, count)); - ret .Ok; - } - - if dst_addr < src_addr { - var i: usize = 0; - while i < count { - dst.ptr[i] = src.ptr[i]; - i = i + 1; - } - } else { - var i = count; - while i > 0 { - i = i - 1; - dst.ptr[i] = src.ptr[i]; - } - } + // 重叠安全,统一走原生 memmove。 + ignore_ptr(vm_memmove(dst.ptr as *any, src.ptr as *any, count)); ret .Ok; } diff --git a/stage2/utils/set.spl b/stage2/utils/set.spl index bb7e114..710a2d2 100644 --- a/stage2/utils/set.spl +++ b/stage2/utils/set.spl @@ -3,7 +3,8 @@ // 开放寻址集合。键按字节复制到集合自己的存储中;集合只释放自身存储, // 不释放键值内部引用的资源。哈希与相等回调的约定和 Map 一致。 type .{ .Status } = @import("error.spl"); -type .{ .Map, .LookupResult } = @import("map.spl"); +type .{ .Map, .LookupResult, .hash_kind_usize, .hash_kind_view, .hash_kind_constant } = + @import("map.spl"); type .{ .ByteView } = @import("byte_view.spl"); type .{ .hash_usize, .eq_usize, .hash_view, .eq_view } = @import("hash.spl"); @@ -11,15 +12,14 @@ type Set = @self; map: Map, -fn new(key_size: usize, key_align: usize, - hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Set { +fn new(key_size: usize, key_align: usize, hash_kind: usize): Set { ret Set { - .map = Map.new(key_size, key_align, 1, 1, hash_fn, eq_fn), + .map = Map.new(key_size, key_align, 1, 1, hash_kind), }; } fn valid(self: Set): bool { - ret Map.valid(self.map) && self.map.val_size == 1; + ret Map.valid(&self.map) && self.map.val_size == 1; } fn size(self: Set): usize { @@ -104,7 +104,7 @@ fn constant_hash(key: *u8): usize { } fn test_insert_find_remove() { - var set = new(@sizeof(usize), @alignof(usize), hash_usize, eq_usize); + var set = new(@sizeof(usize), @alignof(usize), hash_kind_usize()); defer { drop(&set); } @assert(valid(set)); @assert(size(set) == 0 && capacity(set) == 0); @@ -169,7 +169,7 @@ fn test_insert_find_remove() { } fn test_collisions_and_take() { - var set = new(@sizeof(usize), @alignof(usize), constant_hash, eq_usize); + var set = new(@sizeof(usize), @alignof(usize), hash_kind_constant()); defer { drop(&set); } var i: usize = 0; @@ -213,7 +213,7 @@ fn test_collisions_and_take() { } fn test_byte_view_keys() { - var set = new(@sizeof(ByteView), @alignof(ByteView), hash_view, eq_view); + var set = new(@sizeof(ByteView), @alignof(ByteView), hash_kind_view()); defer { drop(&set); } var alpha = ByteView.from_slice("alpha"); diff --git a/stage2/utils/source.spl b/stage2/utils/source.spl index ad1903a..400028e 100644 --- a/stage2/utils/source.spl +++ b/stage2/utils/source.spl @@ -6,7 +6,7 @@ type .{ .Error, .Status, .make } = @import("error.spl"); type .{ .ByteView, .FindResult } = @import("byte_view.spl"); type .{ .Vec } = @import("vec.spl"); -type .{ .Map } = @import("map.spl"); +type .{ .Map, .hash_kind_view } = @import("map.spl"); type .{ .hash_view, .eq_view } = @import("hash.spl"); type Position = struct { @@ -134,7 +134,7 @@ fn set_new(): Sources { ret Sources { .items = Vec.blank(@sizeof(Source), 8), .by_name = Map.blank(@sizeof(ByteView), @alignof(ByteView), @sizeof(usize), - @alignof(usize), hash_view, eq_view), + @alignof(usize), hash_kind_view()), }; } diff --git a/stage2/utils/vec.spl b/stage2/utils/vec.spl index 9c98127..57b8748 100644 --- a/stage2/utils/vec.spl +++ b/stage2/utils/vec.spl @@ -7,6 +7,18 @@ type .{ .Error, .Kind, .Status } = @import("error.spl"); type .{ .SizeResult, .checked_add, .checked_mul, .grow_capacity, .move } = @import("memory.spl"); type .{ .alloc, .copy, .free } = @import("../sys/mem.spl"); +#extern(vm) fn vm_vec_valid(v: *any): i32; +#extern(vm) fn vm_vec_push_raw(v: *any, elem: *any): i32; +#extern(vm) fn vm_vec_push(v: *any, elem: *any): i32; +#extern(vm) fn vm_vec_get(v: *any, index: usize, out: *any): i32; +#extern(vm) fn vm_vec_allocate(out: *any, capacity: usize, elem_size: usize, elem_align: usize): i32; +#extern(vm) fn vm_vec_reserve_raw(v: *any, need: usize): i32; +#extern(vm) fn vm_vec_append(v: *any, elems: *any, count: usize): i32; +#extern(vm) fn vm_vec_set(v: *any, index: usize, elem: *any): i32; +#extern(vm) fn vm_vec_pop(v: *any, out: *any): i32; +#extern(vm) fn vm_vec_clone(out: *any, src: *any): i32; +#extern(vm) fn vm_vec_drop(v: *any): void; + type Vec = @self; raw: *u8, @@ -51,95 +63,41 @@ fn new(elem_size: usize, elem_align: usize): VecResult { // 按指针接收,避免每次调用复制整个 Vec;内联对齐检查,省一次函数调用。 fn valid(self: *Vec): bool { - if self.elem_size == 0 { ret false; } - var a = self.elem_align; - if a == 0 || (a & (a - 1)) != 0 { ret false; } - if self.len > self.cap { ret false; } - if self.cap == 0 { - ret self.raw == null && self.data == null && self.len == 0; - } - if self.raw == null || self.data == null { ret false; } - ret (self.data as usize & (a - 1)) == 0; + ret vm_vec_valid(self as *any) != 0; } fn status_error(kind: Kind): Status { ret .Err(Error.make(kind)); } +// native 错误码 -> Error.Kind(0 ok / 1 InvalidArgument / 2 OutOfRange / 3 Overflow / 4 InvalidAlignment) +fn kind_from_code(code: i32): Kind { + if code == 2 { ret .OutOfRange; } + if code == 3 { ret .Overflow; } + if code == 4 { ret .InvalidAlignment; } + ret .InvalidArgument; +} + +fn status_from_code(code: i32): Status { + if code == 0 { ret .Ok; } + ret status_error(kind_from_code(code)); +} + // 计算元素区字节数。错误时不修改任何 Vec。 fn byte_count(count: usize, elem_size: usize): SizeResult { ret checked_mul(count, elem_size); } fn allocate(capacity: usize, elem_size: usize, elem_align: usize): VecResult { - if elem_size == 0 { ret .Err(Error.make(.InvalidArgument)); } - if !valid_alignment(elem_align) { - ret .Err(Error.make(.InvalidAlignment)); - } - if capacity == 0 { ret .Ok(blank(elem_size, elem_align)); } - - var bytes: usize = 0; - match byte_count(capacity, elem_size) { - .Ok(value) => { bytes = value; }, - .Err(error) => { ret .Err(error); }, - } - - var total: usize = 0; - match checked_add(bytes, elem_align - 1) { - .Ok(value) => { total = value; }, - .Err(error) => { ret .Err(error); }, - } - - var raw = alloc(total) as *u8; - if raw == null { - ret .Err(Error.make(.Overflow)); - } - var address = raw as usize; - var mask = elem_align - 1; - if address > (~(0 as usize)) - mask { - free(raw as *any); - ret .Err(Error.make(.Overflow)); - } - var aligned = (address + mask) & ~mask; - ret .Ok(Vec { - .raw = raw, - .data = aligned as *u8, - .len = 0, - .cap = capacity, - .elem_size = elem_size, - .elem_align = elem_align, - }); + var v: Vec = undefined; + var rc = vm_vec_allocate(&v as *any, capacity, elem_size, elem_align); + if rc == 0 { ret .Ok(v); } + ret .Err(Error.make(kind_from_code(rc))); } // 与 reserve 相同,但假定调用方已校验 self(内部热路径用,省去重复 valid)。 fn reserve_raw(self: *Vec, need: usize): Status { - if need <= self.cap { ret .Ok; } - - var new_cap = grow_capacity(self.cap, 8, need); - - var fresh: Vec = undefined; - match allocate(new_cap, self.elem_size, self.elem_align) { - .Ok(value) => { fresh = value; }, - .Err(error) => { ret .Err(error); }, - } - - var used_bytes: usize = 0; - match byte_count(self.len, self.elem_size) { - .Ok(value) => { used_bytes = value; }, - .Err(error) => { - drop(&fresh); - ret .Err(error); - }, - } - if used_bytes != 0 { - copy(fresh.data as *any, self.data as *any, used_bytes); - } - fresh.len = self.len; - - var old_raw = self.raw; - self.* = fresh; - free(old_raw as *any); - ret .Ok; + ret status_from_code(vm_vec_reserve_raw(self as *any, need)); } // 保证至少可容纳 need 个元素(外部入口,含校验)。 @@ -154,81 +112,30 @@ fn with_capacity(elem_size: usize, elem_align: usize, capacity: usize): VecResul } fn get(self: *Vec, index: usize): PtrResult { - if !valid(self) { ret .Err(Error.make(.InvalidArgument)); } - if index >= self.len { ret .Err(Error.make(.OutOfRange)); } - ret .Ok(self.data + index * self.elem_size); + var out: *u8 = null; + var rc = vm_vec_get(self as *any, index, &out as *any); + if rc == 0 { ret .Ok(out); } + if rc == 2 { ret .Err(Error.make(.OutOfRange)); } + ret .Err(Error.make(.InvalidArgument)); } fn set(self: *Vec, index: usize, elem: *u8): Status { - if !valid(self) || elem == null { ret status_error(.InvalidArgument); } - if index >= self.len { ret status_error(.OutOfRange); } - var dst = self.data + index * self.elem_size; - ret move(dst[0..self.elem_size], elem[0..self.elem_size]); + ret status_from_code(vm_vec_set(self as *any, index, elem as *any)); } // 追加 count 个连续元素。elems 可以指向 self 当前已初始化的元素区。 fn append(self: *Vec, elems: *u8, count: usize): Status { - if !valid(self) { ret status_error(.InvalidArgument); } - if count == 0 { ret .Ok; } - if elems == null { ret status_error(.InvalidArgument); } - - var copy_bytes: usize = 0; - match byte_count(count, self.elem_size) { - .Ok(value) => { copy_bytes = value; }, - .Err(error) => { ret .Err(error); }, - } - var new_len: usize = 0; - match checked_add(self.len, count) { - .Ok(value) => { new_len = value; }, - .Err(error) => { ret .Err(error); }, - } - - var used_bytes: usize = 0; - match byte_count(self.len, self.elem_size) { - .Ok(value) => { used_bytes = value; }, - .Err(error) => { ret .Err(error); }, - } - - var source_inside = false; - var source_offset: usize = 0; - if used_bytes != 0 { - var base = self.data as usize; - var source = elems as usize; - if source >= base && source - base < used_bytes { - source_offset = source - base; - if copy_bytes > used_bytes - source_offset { - ret status_error(.OutOfRange); - } - source_inside = true; - } - } - - match reserve_raw(self, new_len) { - .Ok => {}, - .Err(error) => { ret .Err(error); }, - } - if source_inside { elems = self.data + source_offset; } - - var dst = self.data + used_bytes; - match move(dst[0..copy_bytes], elems[0..copy_bytes]) { - .Ok => {}, - .Err(error) => { ret .Err(error); }, - } - self.len = new_len; - ret .Ok; + ret status_from_code(vm_vec_append(self as *any, elems as *any, count)); } fn push(self: *Vec, elem: *u8): Status { - ret append(self, elem, 1); + ret status_from_code(vm_vec_push(self as *any, elem as *any)); } // 热路径:假定 self 有效且已有容量时直接写入;容量不足才回退到 append。 fn push_raw(self: *Vec, elem: *u8): bool { - if self.len < self.cap { - copy(self.data + self.len * self.elem_size, elem, self.elem_size); - self.len = self.len + 1; - ret true; - } + if elem == null { ret false; } + if vm_vec_push_raw(self as *any, elem as *any) != 0 { ret true; } match append(self, elem, 1) { .Ok => { ret true; }, .Err(error) => { ret false; }, @@ -238,15 +145,7 @@ fn push_raw(self: *Vec, elem: *u8): bool { // 将末元素复制到 out,然后缩短数组。out 可以与元素区重叠。 fn pop(self: *Vec, out: *u8): Status { - if !valid(self) || out == null { ret status_error(.InvalidArgument); } - if self.len == 0 { ret status_error(.OutOfRange); } - var source = self.data + (self.len - 1) * self.elem_size; - match move(out[0..self.elem_size], source[0..self.elem_size]) { - .Ok => {}, - .Err(error) => { ret .Err(error); }, - } - self.len = self.len - 1; - ret .Ok; + ret status_from_code(vm_vec_pop(self as *any, out as *any)); } fn clear(self: *Vec) { @@ -256,31 +155,7 @@ fn clear(self: *Vec) { // 成功时先释放 out 原有存储再提交副本;失败保持 out 不变。 // out 与 src 指向同一个 Vec 也允许。 fn clone(out: *Vec, src: Vec): Status { - if !valid(out) || !valid(&src) { ret status_error(.InvalidArgument); } - if out.elem_size != src.elem_size || out.elem_align != src.elem_align { - ret status_error(.InvalidArgument); - } - - var fresh = blank(src.elem_size, src.elem_align); - match reserve(&fresh, src.len) { - .Ok => {}, - .Err(error) => { ret .Err(error); }, - } - var bytes: usize = 0; - match byte_count(src.len, src.elem_size) { - .Ok(value) => { bytes = value; }, - .Err(error) => { - drop(&fresh); - ret .Err(error); - }, - } - if bytes != 0 { - copy(fresh.data as *any, src.data as *any, bytes); - } - fresh.len = src.len; - drop(out); - out.* = fresh; - ret .Ok; + ret status_from_code(vm_vec_clone(out as *any, &src as *any)); } // 显式转移所有权,返回值必须由接收方最终 drop。 @@ -291,10 +166,7 @@ fn take(source: *Vec): Vec { } fn drop(self: *Vec) { - var elem_size = self.elem_size; - var elem_align = self.elem_align; - free(self.raw as *any); - self.* = blank(elem_size, elem_align); + vm_vec_drop(self as *any); } fn expect_ok(result: Status) {