From c0a86ea5529e4bf1c28cc89588e3a369d2e63c2b Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Tue, 22 Sep 2026 23:12:15 +0800 Subject: [PATCH] =?UTF-8?q?stage0=20=E9=87=8D=E6=9E=84vm=E4=BD=BF=E5=85=B6?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E8=87=AA=E5=B7=B1=E7=9A=84=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E7=A9=BA=E9=97=B4=E4=B8=8D=E5=86=8D=E5=85=B1=E7=94=A8=E5=AE=BF?= =?UTF-8?q?=E4=B8=BB=E6=9C=BA=20=E4=BF=AE=E6=94=B9vm=E7=9A=84ABI=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=9B=B8=E5=85=B3nob=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nob.c | 2 +- nob/nob_data.h | 94 +- stage0/spl_asp.h | 38 + stage0/spl_rt.h | 98 ++ stage0/spl_rt_core.h | 691 +++++++++++++ stage0/spl_syscall.c | 1372 ++++++++++--------------- stage0/spl_vm.c | 432 +++++++- stage0/spl_vm.h | 73 +- {stage2/sys => stage0}/spl_vm_embed.h | 59 +- stage0/test_spl_vm.c | 150 ++- stage1/spl_ir2vm.c | 4 + stage2/ir2vm.spl | 12 + stage2/mcode.spl | 59 +- stage2/sys/spl_rt.h | 637 ------------ 14 files changed, 2149 insertions(+), 1572 deletions(-) create mode 100644 stage0/spl_asp.h create mode 100644 stage0/spl_rt.h create mode 100644 stage0/spl_rt_core.h rename {stage2/sys => stage0}/spl_vm_embed.h (56%) delete mode 100644 stage2/sys/spl_rt.h diff --git a/nob.c b/nob.c index e765a1e..36cf8f8 100644 --- a/nob.c +++ b/nob.c @@ -202,7 +202,7 @@ const char *build_target(const char *name) { return target_exe; nob_cc(&cmd); - nob_cmd_append(&cmd, "-I./stage2/sys", "-O2", "-D_CRT_SECURE_NO_WARNINGS"); + nob_cmd_append(&cmd, "-I./stage0", "-O2", "-D_CRT_SECURE_NO_WARNINGS"); nob_cc_inputs(&cmd, target_c); nob_cc_output(&cmd, target_exe); if (!nob_cmd_run(&cmd)) { diff --git a/nob/nob_data.h b/nob/nob_data.h index 229d2c9..bf46024 100644 --- a/nob/nob_data.h +++ b/nob/nob_data.h @@ -3,6 +3,13 @@ /* clang-format off */ #define VM_SRCS "stage0/spl_mcode.c", "stage0/spl_syscall.c", "stage0/spl_vm.c", + +static const char *stage0_headers[] = { + "stage0/spl_asp.h", "stage0/spl_mcode.h", "stage0/spl_syscall.h", + "stage0/spl_vm.h", "stage0/spl_rt_core.h", "stage0/spl_rt.h", + "stage0/spl_vm_embed.h", +}; + static const char *spl_cli_srcs[] = {"stage0/spl_cli.c", VM_SRCS}; static const char *vm_test_srcs[] = {"stage0/test_spl_vm.c", VM_SRCS}; static const char *splc0_srcs[] = { @@ -30,8 +37,8 @@ static const char *splc0_srcs[] = { }; static const char *splc1_crt_deps[] ={ - "stage2/sys/spl_rt.h", - "stage2/sys/spl_vm_embed.h", + "stage0/spl_rt.h", + "stage0/spl_vm_embed.h", // TODO }; @@ -88,10 +95,73 @@ static const char* splc1_deps[] = { }; static const char* splc2_deps[] = { - + /* stage3 */ + "stage3/ast2ir.spl", + "stage3/ast_clone.spl", + "stage3/ctvm.spl", + "stage3/eval.spl", + "stage3/intrin.spl", + "stage3/lang_type.spl", + "stage3/sema.spl", + "stage3/splc2.spl", + "stage3/splrt.spl", + /* stage2 */ + "stage2/sys/exit.spl", + "stage2/sys/file.spl", + "stage2/sys/mem.spl", + "stage2/sys/time.spl", + "stage2/sys/vm.spl", + "stage2/utils/algorithm.spl", + "stage2/utils/arena.spl", + "stage2/utils/ascii.spl", + "stage2/utils/byte_buffer.spl", + "stage2/utils/byte_view.spl", + "stage2/utils/error.spl", + "stage2/utils/fmt.spl", + "stage2/utils/hash.spl", + "stage2/utils/io.spl", + "stage2/utils/json.spl", + "stage2/utils/log.spl", + "stage2/utils/lsp_frame.spl", + "stage2/utils/map.spl", + "stage2/utils/memory.spl", + "stage2/utils/mp.spl", + "stage2/utils/path.spl", + "stage2/utils/profile.spl", + "stage2/utils/set.spl", + "stage2/utils/source.spl", + "stage2/utils/str.spl", + "stage2/utils/utf8.spl", + "stage2/utils/value.spl", + "stage2/utils/vec.spl", + "stage2/ast.spl", + "stage2/ast2ir.spl", + "stage2/attr.spl", + "stage2/def.spl", + "stage2/diag.spl", + "stage2/eval.spl", + "stage2/intrin.spl", + "stage2/ir.spl", + "stage2/ir2c.spl", + "stage2/ir2vm.spl", + "stage2/ir_builder.spl", + "stage2/lang_type.spl", + "stage2/layout.spl", + "stage2/lexer.spl", + "stage2/mcode.spl", + "stage2/parser.spl", + "stage2/scope.spl", + "stage2/sema.spl", + "stage2/splc1.spl", + "stage2/token.spl", + "stage2/type_table.spl", }; -static const char *splc2_crt_deps[] = {}; +static const char *splc2_crt_deps[] = { + "stage0/spl_rt.h", "stage0/spl_rt_core.h", "stage0/spl_asp.h", + "stage0/spl_mcode.h", "stage0/spl_vm.h", "stage0/spl_syscall.h", + "stage0/spl_vm_embed.h", +}; /* clang-format on */ @@ -138,32 +208,32 @@ static build_t targets[] = { BUILD_EXE_WITH_OPTIMIZATION, .exe = {.srcs = spl_cli_srcs, .srcs_count = NOB_ARRAY_LEN(spl_cli_srcs), - .headers = NULL, - .headers_count = 0}, + .headers = stage0_headers, + .headers_count = NOB_ARRAY_LEN(stage0_headers)}, }, { "spl_cli_g", BUILD_EXE, .exe = {.srcs = spl_cli_srcs, .srcs_count = NOB_ARRAY_LEN(spl_cli_srcs), - .headers = NULL, - .headers_count = 0}, + .headers = stage0_headers, + .headers_count = NOB_ARRAY_LEN(stage0_headers)}, }, { "vm_test", BUILD_EXE, .exe = {.srcs = vm_test_srcs, .srcs_count = NOB_ARRAY_LEN(vm_test_srcs), - .headers = NULL, - .headers_count = 0}, + .headers = stage0_headers, + .headers_count = NOB_ARRAY_LEN(stage0_headers)}, }, { "splc0", BUILD_EXE, .exe = {.srcs = splc0_srcs, .srcs_count = NOB_ARRAY_LEN(splc0_srcs), - .headers = NULL, - .headers_count = 0}, + .headers = stage0_headers, + .headers_count = NOB_ARRAY_LEN(stage0_headers)}, }, { "splc1", diff --git a/stage0/spl_asp.h b/stage0/spl_asp.h new file mode 100644 index 0000000..72f16ae --- /dev/null +++ b/stage0/spl_asp.h @@ -0,0 +1,38 @@ +#ifndef __SPL_ASP_H__ +#define __SPL_ASP_H__ + +/* spl_asp.h - 地址空间抽象(Address SPace) + * + * SPL 侧指针语义由 spl_asp_t 统一描述: + * - native(编译器自身):identity,指针就是宿主地址。 + * - VM:句柄/偏移,offset = (handle<<32) | 区内字节偏移,0 为 null。 + * + * runtime(spl_rt_core.h)的解引用/分配一律经此接口,从而同一份 SPL + * 源的 Vec/Map/mem 在两种后端下都自洽。 + */ + +#include +#include + +#ifndef SPL_USIZE_TYPEDEF +#define SPL_USIZE_TYPEDEF +typedef uintptr_t usize; +#endif + +typedef struct spl_asp spl_asp_t; + +struct spl_asp { + void *ctx; + /* offset -> 宿主地址;size>0 时做边界检查;失败返回 NULL。 */ + unsigned char *(*xlate)(void *ctx, uintptr_t off, uintptr_t size); + /* 分配 size 字节,返回 offset(0=失败)。 */ + uintptr_t (*alloc)(void *ctx, uintptr_t size); + /* 重新分配 offset@old,返回新 offset(0=失败)。 */ + uintptr_t (*realloc)(void *ctx, uintptr_t off, uintptr_t size); + /* 释放 offset。 */ + void (*free)(void *ctx, uintptr_t off); + /* 宿主地址 -> offset;size>0 时校验范围。不属于该空间返回 0。 */ + uintptr_t (*to_off)(void *ctx, const void *host, uintptr_t size); +}; + +#endif /* __SPL_ASP_H__ */ diff --git a/stage0/spl_rt.h b/stage0/spl_rt.h new file mode 100644 index 0000000..419329d --- /dev/null +++ b/stage0/spl_rt.h @@ -0,0 +1,98 @@ +#ifndef __SPL_RT_H__ +#define __SPL_RT_H__ + +#include +#include +#include +#include +#include + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define SPL_FN static inline +#elif defined(__GNUC__) || defined(__clang__) +#define SPL_FN static __inline__ +#else +#define SPL_FN static +#endif + +#include +typedef uint8_t u8; +typedef int8_t i8; +typedef uint16_t u16; +typedef int16_t i16; +typedef uint32_t u32; +typedef int32_t i32; +typedef uint64_t u64; +typedef int64_t i64; + +#ifndef SPL_USIZE_TYPEDEF +#define SPL_USIZE_TYPEDEF +typedef u64 usize; +#endif + +#ifndef SPL_ISIZE_TYPEDEF +#define SPL_ISIZE_TYPEDEF +typedef i64 isize; +#endif + +SPL_FN void spl_panic(const char *msg) { + fprintf(stderr, "%s\n", msg ? msg : "panic"); + exit(1); +} +SPL_FN void spl_trap(void) { abort(); } + +#include "spl_rt_core.h" + +SPL_FN void *vm_fopen(void *path, void *mode) { + return (void *)fopen((const char *)path, (const char *)mode); +} +SPL_FN i32 vm_fclose(void *f) { return f ? fclose((FILE *)f) : 0; } +SPL_FN u64 vm_fread(void *buf, u64 sz, u64 n, void *f) { + return f ? (u64)fread(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0; +} +SPL_FN u64 vm_fwrite(void *buf, u64 sz, u64 n, void *f) { + return f ? (u64)fwrite(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0; +} +SPL_FN u64 vm_fsize(void *f) { + long cur, end; + if (!f) + return 0; + cur = ftell((FILE *)f); + if (cur < 0) + return 0; + if (fseek((FILE *)f, 0, SEEK_END) != 0) + return 0; + end = ftell((FILE *)f); + fseek((FILE *)f, cur, SEEK_SET); + return end < 0 ? 0 : (u64)end; +} +SPL_FN void *vm_stdin(void) { return (void *)stdin; } +SPL_FN void *vm_stdout(void) { return (void *)stdout; } +SPL_FN void *vm_stderr(void) { return (void *)stderr; } +SPL_FN i32 vm_putchar(i32 c) { return fputc(c, stdout); } +SPL_FN i32 vm_getchar(void) { return fgetc(stdin); } + +SPL_FN void vm_exit(i32 code) { exit(code); } +SPL_FN u64 vm_timestamp(u64 kind) { + time_t sec = time(NULL); + if (kind == 1) + return (u64)sec; + if (kind == 2) + return 0; + if (kind == 4) + return (u64)sec * 1000000000ull; + return 0; +} + +#define SPL_VM_EMBED_IMPLIMENTATION +#include "spl_vm_embed.h" + +/* 配置层外部函数处理器(native 端)。VM 模式的实现见 spl_syscall.c。 + * native 的 foreign 分发尚未接入(后续),这里先提供可链接入口。 */ +SPL_FN void vm_set_foreign(void *vm, unsigned long long handler, void *ctx) { + (void)vm; + (void)handler; + (void)ctx; +} + +#endif /* __SPL_RT_H__ */ diff --git a/stage0/spl_rt_core.h b/stage0/spl_rt_core.h new file mode 100644 index 0000000..9637ef8 --- /dev/null +++ b/stage0/spl_rt_core.h @@ -0,0 +1,691 @@ +#ifndef __SPL_RT_CORE_H__ +#define __SPL_RT_CORE_H__ + +#include +#include +#include +#include + +#include "spl_asp.h" + +#ifndef SPL_CORE_FN +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define SPL_CORE_FN static inline +#elif defined(__GNUC__) || defined(__clang__) +#define SPL_CORE_FN static __inline__ +#else +#define SPL_CORE_FN static +#endif +#endif + +/* ================================================================ + * 地址空间:identity(native/编译器自身) + * ================================================================ */ + +SPL_CORE_FN unsigned char *spl_asp_id_xlate(void *ctx, uintptr_t off, uintptr_t size) { + (void)ctx; + (void)size; + return (unsigned char *)off; +} +SPL_CORE_FN uintptr_t spl_asp_id_alloc(void *ctx, uintptr_t size) { + (void)ctx; + return (uintptr_t)malloc((size_t)size); +} +SPL_CORE_FN uintptr_t spl_asp_id_realloc(void *ctx, uintptr_t off, uintptr_t size) { + (void)ctx; + return (uintptr_t)realloc((void *)off, (size_t)size); +} +SPL_CORE_FN void spl_asp_id_free(void *ctx, uintptr_t off) { + (void)ctx; + free((void *)off); +} +SPL_CORE_FN uintptr_t spl_asp_id_to_off(void *ctx, const void *host, uintptr_t size) { + (void)ctx; + (void)size; + return (uintptr_t)host; +} + +static const spl_asp_t spl_asp_identity = { + NULL, spl_asp_id_xlate, spl_asp_id_alloc, spl_asp_id_realloc, spl_asp_id_free, + spl_asp_id_to_off, +}; +#define SPL_ASP_ID ((spl_asp_t *)&spl_asp_identity) + +/* 偏移 -> 宿主(不做边界检查)。 */ +SPL_CORE_FN unsigned char *spl_x(spl_asp_t *asp, uintptr_t off) { + return asp->xlate(asp->ctx, off, 0); +} +SPL_CORE_FN void *spl_xp(spl_asp_t *asp, uintptr_t off, uintptr_t size) { + return asp->xlate(asp->ctx, off, size); +} + +/* ---------------- mem ---------------- */ + +SPL_CORE_FN void *spl_alloc_ex(spl_asp_t *asp, uintptr_t sz) { + if (sz == 0) + return NULL; + return (void *)asp->alloc(asp->ctx, sz); +} + +SPL_CORE_FN void spl_free_ex(spl_asp_t *asp, void *p) { + if (p) + asp->free(asp->ctx, (uintptr_t)p); +} + +SPL_CORE_FN void *spl_realloc_ex(spl_asp_t *asp, void *p, uintptr_t sz) { + if (!p) + return spl_alloc_ex(asp, sz); + if (sz == 0) { + asp->free(asp->ctx, (uintptr_t)p); + return NULL; + } + return (void *)asp->realloc(asp->ctx, (uintptr_t)p, sz); +} + +SPL_CORE_FN void *vm_memcpy(void *dst, const void *src, uintptr_t n) { + if (n) + memcpy(dst, src, (size_t)n); + return dst; +} + +SPL_CORE_FN void *vm_memmove(void *dst, const void *src, uintptr_t n) { + if (n) + memmove(dst, src, (size_t)n); + return dst; +} + +SPL_CORE_FN intptr_t vm_memcmp(const void *a, const void *b, uintptr_t n) { + if (n == 0) + return 0; + return (intptr_t)memcmp(a, b, (size_t)n); +} + +SPL_CORE_FN int spl_bytes_eq_ex(spl_asp_t *asp, const void *a, uintptr_t alen, const void *b, + uintptr_t blen) { + (void)asp; + if (alen != blen) + return 0; + if (alen == 0) + return 1; + if (!a || !b) + return 0; + return memcmp(a, b, (size_t)alen) == 0; +} + +/* ---------------- Vec ---------------- */ + +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; + +SPL_CORE_FN int spl_align_ok(uintptr_t a) { return a != 0 && (a & (a - 1)) == 0; } + +SPL_CORE_FN int spl_vec_is_valid(const spl_vec_t *v) { + uintptr_t a; + if (v->elem_size == 0) + return 0; + 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; +} + +SPL_CORE_FN void 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; +} + +SPL_CORE_FN int spl_vec_allocate_ex(spl_asp_t *asp, spl_vec_t *out, uintptr_t capacity, + uintptr_t elem_size, uintptr_t elem_align) { + uintptr_t bytes, mask, addr; + uintptr_t raw; + 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; + bytes = capacity * elem_size; + mask = elem_align - 1; + if (bytes > ~(uintptr_t)0 - mask) + return 3; + raw = asp->alloc(asp->ctx, bytes + mask); + if (!raw) + return 3; + addr = raw; + if (addr > ~(uintptr_t)0 - mask) { + asp->free(asp->ctx, raw); + return 3; + } + out->raw = raw; + out->data = (addr + mask) & ~mask; + out->cap = capacity; + return 0; +} + +SPL_CORE_FN int spl_vec_reserve_raw_ex(spl_asp_t *asp, spl_vec_t *v, uintptr_t need) { + uintptr_t new_cap = 0, used = 0, old; + spl_vec_t fresh; + int rc; + if (need <= v->cap) + return 0; + spl_grow_capacity(v->cap, 8, need, &new_cap); + rc = spl_vec_allocate_ex(asp, &fresh, new_cap, v->elem_size, v->elem_align); + if (rc) + return rc; + if (v->len != 0) { + if (v->len > ~(uintptr_t)0 / v->elem_size) { + asp->free(asp->ctx, fresh.raw); + return 3; + } + used = v->len * v->elem_size; + } + if (used) + memcpy(spl_x(asp, fresh.data), spl_x(asp, v->data), used); + fresh.len = v->len; + old = v->raw; + *v = fresh; + if (old) + asp->free(asp->ctx, old); + return 0; +} + +SPL_CORE_FN void spl_vec_release_ex(spl_asp_t *asp, spl_vec_t *v) { + uintptr_t es = v->elem_size, ea = v->elem_align; + if (v->raw) + asp->free(asp->ctx, v->raw); + v->raw = 0; + v->data = 0; + v->len = 0; + v->cap = 0; + v->elem_size = es; + v->elem_align = ea; +} + +SPL_CORE_FN int spl_vec_valid_ex(const void *vv) { + return vv ? spl_vec_is_valid((const spl_vec_t *)vv) : 0; +} + +SPL_CORE_FN int spl_vec_push_raw_ex(spl_asp_t *asp, void *vv, const void *elem) { + spl_vec_t *v = (spl_vec_t *)vv; + if (!v || !elem) + return 0; + if (v->len < v->cap) { + memcpy(spl_x(asp, v->data + v->len * v->elem_size), elem, v->elem_size); + v->len++; + return 1; + } + return 0; +} + +SPL_CORE_FN int spl_vec_push_ex(spl_asp_t *asp, void *vv, const void *elem) { + spl_vec_t *v = (spl_vec_t *)vv; + int rc; + if (!v || !elem || !spl_vec_is_valid(v)) + return 1; + if (v->len < v->cap) { + memcpy(spl_x(asp, v->data + v->len * v->elem_size), elem, v->elem_size); + v->len++; + return 0; + } + rc = spl_vec_reserve_raw_ex(asp, v, v->len + 1); + if (rc) + return rc; + memmove(spl_x(asp, v->data + v->len * v->elem_size), elem, v->elem_size); + v->len++; + return 0; +} + +SPL_CORE_FN int spl_vec_get_ex(spl_asp_t *asp, const void *vv, uintptr_t index, void **out) { + const spl_vec_t *v = (const spl_vec_t *)vv; + unsigned char *p; + if (!v || !out) + return 1; + if (!spl_vec_is_valid(v)) + return 1; + if (index >= v->len) + return 2; + p = spl_x(asp, v->data) + index * v->elem_size; + *out = (void *)(uintptr_t)asp->to_off(asp->ctx, p, v->elem_size); + return 0; +} + +SPL_CORE_FN int spl_vec_allocate_out_ex(spl_asp_t *asp, void *out, uintptr_t capacity, + uintptr_t elem_size, uintptr_t elem_align) { + if (!out) + return 1; + return spl_vec_allocate_ex(asp, (spl_vec_t *)out, capacity, elem_size, elem_align); +} + +SPL_CORE_FN int spl_vec_reserve_raw_void_ex(spl_asp_t *asp, void *vv, uintptr_t need) { + if (!vv) + return 1; + return spl_vec_reserve_raw_ex(asp, (spl_vec_t *)vv, need); +} + +SPL_CORE_FN int spl_vec_append_ex(spl_asp_t *asp, void *vv, const void *elems, uintptr_t count) { + spl_vec_t *v = (spl_vec_t *)vv; + uintptr_t copy_bytes, new_len, used, source_offset = 0; + int source_inside = 0, rc; + 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; + copy_bytes = count * v->elem_size; + if (v->len > ~(uintptr_t)0 - count) + return 3; + new_len = v->len + count; + used = v->len * v->elem_size; + if (used) { + unsigned char *base = spl_x(asp, v->data); + uintptr_t source = (uintptr_t)elems; + if (source >= (uintptr_t)base && source - (uintptr_t)base < used) { + source_offset = source - (uintptr_t)base; + if (copy_bytes > used - source_offset) + return 2; + source_inside = 1; + } + } + rc = spl_vec_reserve_raw_ex(asp, v, new_len); + if (rc) + return rc; + if (source_inside) + elems = (const void *)(spl_x(asp, v->data) + source_offset); + memmove(spl_x(asp, v->data + used), elems, copy_bytes); + v->len = new_len; + return 0; +} + +SPL_CORE_FN int spl_vec_set_ex(spl_asp_t *asp, void *vv, uintptr_t index, const void *elem) { + spl_vec_t *v = (spl_vec_t *)vv; + if (!v || !elem || !spl_vec_is_valid(v)) + return 1; + if (index >= v->len) + return 2; + memmove(spl_x(asp, v->data + index * v->elem_size), elem, v->elem_size); + return 0; +} + +SPL_CORE_FN int spl_vec_pop_ex(spl_asp_t *asp, void *vv, void *out) { + spl_vec_t *v = (spl_vec_t *)vv; + if (!v || !out || !spl_vec_is_valid(v)) + return 1; + if (v->len == 0) + return 2; + memmove(out, spl_x(asp, v->data + (v->len - 1) * v->elem_size), v->elem_size); + v->len--; + return 0; +} + +SPL_CORE_FN int spl_vec_clone_ex(spl_asp_t *asp, void *outp, const void *srcp) { + spl_vec_t *out = (spl_vec_t *)outp; + const spl_vec_t *src = (const spl_vec_t *)srcp; + spl_vec_t fresh; + uintptr_t bytes; + int rc; + 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; + fresh.raw = 0; + fresh.data = 0; + fresh.len = 0; + fresh.cap = 0; + fresh.elem_size = src->elem_size; + fresh.elem_align = src->elem_align; + rc = spl_vec_reserve_raw_ex(asp, &fresh, src->len); + if (rc) + return rc; + bytes = src->len * src->elem_size; + if (bytes) + memcpy(spl_x(asp, fresh.data), spl_x(asp, src->data), bytes); + fresh.len = src->len; + if (out->raw) + asp->free(asp->ctx, out->raw); + *out = fresh; + return 0; +} + +SPL_CORE_FN int spl_vec_drop_ex(spl_asp_t *asp, void *vv) { + if (vv) + spl_vec_release_ex(asp, (spl_vec_t *)vv); + return 0; +} + +/* ---------------- Map ---------------- */ + +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; + +SPL_CORE_FN 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; +} + +SPL_CORE_FN 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; + uintptr_t i; + for (i = 0; i < len; i++) + h = (h ^ (uintptr_t)p[i]) * prime; + return h; +} + +SPL_CORE_FN uintptr_t spl_hash_bytes_ex(spl_asp_t *asp, const void *data, uintptr_t len) { + return spl_hash_bytes(spl_x(asp, (uintptr_t)data), len); +} + +SPL_CORE_FN uintptr_t spl_map_hash_ex(spl_asp_t *asp, const spl_map_t *m, const void *key) { + const uintptr_t *v; + if (m->hash_kind == 0) + return spl_hash_usize_value(*(const uintptr_t *)key); + if (m->hash_kind == 2) + return 3; + v = (const uintptr_t *)key; + return spl_hash_bytes_ex(asp, (const void *)v[0], v[1]); +} + +SPL_CORE_FN int spl_map_eq_ex(spl_asp_t *asp, const spl_map_t *m, const void *a, const void *b) { + const uintptr_t *x; + const uintptr_t *y; + if (m->hash_kind == 0 || m->hash_kind == 2) + return *(const uintptr_t *)a == *(const uintptr_t *)b; + x = (const uintptr_t *)a; + y = (const uintptr_t *)b; + if (x[1] != y[1]) + return 0; + if (x[1] == 0) + return 1; + return memcmp(spl_x(asp, x[0]), spl_x(asp, y[0]), (size_t)x[1]) == 0; +} + +SPL_CORE_FN 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; +} + +SPL_CORE_FN uintptr_t spl_map_find_slot_ex(spl_asp_t *asp, const spl_map_t *m, const void *key) { + uintptr_t mask, i, probes; + unsigned char *st; + if (m->states.cap == 0) + return ~(uintptr_t)0; + mask = m->states.cap - 1; + i = spl_map_hash_ex(asp, m, key) & mask; + st = spl_x(asp, m->states.data); + probes = 0; + while (probes < m->states.cap && st[i] != 0) { + if (st[i] == 1 && + spl_map_eq_ex(asp, m, spl_x(asp, m->keys.data + i * m->key_size), key)) + return i; + i = (i + 1) & mask; + probes++; + } + return ~(uintptr_t)0; +} + +SPL_CORE_FN void spl_map_place_ex(spl_asp_t *asp, spl_map_t *m, const void *key, const void *val) { + uintptr_t mask = m->states.cap - 1; + uintptr_t i = spl_map_hash_ex(asp, m, key) & mask; + unsigned char *st = spl_x(asp, 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(spl_x(asp, m->keys.data + i * m->key_size), key, m->key_size); + memcpy(spl_x(asp, m->vals.data + i * m->val_size), val, m->val_size); + st[i] = 1; + m->size++; +} + +SPL_CORE_FN int spl_map_reserve_ex(spl_asp_t *asp, spl_map_t *m, uintptr_t need) { + uintptr_t new_cap = 0, i; + spl_map_t fresh; + int rc; + if (!spl_map_valid(m)) + return 1; + if (need <= m->states.cap) + return 0; + spl_grow_capacity(m->states.cap, 8, need, &new_cap); + 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; + rc = spl_vec_reserve_raw_ex(asp, &fresh.keys, new_cap); + if (rc) + goto fail; + rc = spl_vec_reserve_raw_ex(asp, &fresh.vals, new_cap); + if (rc) + goto fail; + rc = spl_vec_reserve_raw_ex(asp, &fresh.states, new_cap); + if (rc) + goto fail; + fresh.keys.len = new_cap; + fresh.vals.len = new_cap; + fresh.states.len = new_cap; + memset(spl_x(asp, fresh.states.data), 0, new_cap); + for (i = 0; i < m->states.len; i++) { + if (spl_x(asp, m->states.data)[i] == 1) + spl_map_place_ex(asp, &fresh, spl_x(asp, m->keys.data + i * m->key_size), + spl_x(asp, m->vals.data + i * m->val_size)); + } + spl_vec_release_ex(asp, &m->keys); + spl_vec_release_ex(asp, &m->vals); + spl_vec_release_ex(asp, &m->states); + *m = fresh; + return 0; +fail: + spl_vec_release_ex(asp, &fresh.keys); + spl_vec_release_ex(asp, &fresh.vals); + spl_vec_release_ex(asp, &fresh.states); + return rc; +} + +SPL_CORE_FN int spl_map_valid_ex(const void *mm) { + return mm ? spl_map_valid((const spl_map_t *)mm) : 0; +} + +SPL_CORE_FN int spl_map_reserve_void_ex(spl_asp_t *asp, void *mm, uintptr_t need) { + if (!mm) + return 1; + return spl_map_reserve_ex(asp, (spl_map_t *)mm, need); +} + +SPL_CORE_FN int spl_map_put_ex(spl_asp_t *asp, void *mm, const void *key, const void *val) { + spl_map_t *m = (spl_map_t *)mm; + uintptr_t existing; + if (!m || !key || !val || !spl_map_valid(m)) + return 1; + existing = spl_map_find_slot_ex(asp, m, key); + if (existing != ~(uintptr_t)0) { + memcpy(spl_x(asp, m->vals.data + existing * m->val_size), val, m->val_size); + return 0; + } + if (m->states.cap == 0) { + int rc = spl_map_reserve_ex(asp, m, 8); + if (rc) + return rc; + } else { + uintptr_t next_size, scaled; + if (m->size > ~(uintptr_t)0 - 1) + return 3; + next_size = m->size + 1; + if (next_size > ~(uintptr_t)0 / 128) + return 3; + scaled = next_size * 128; + if (scaled / m->states.cap >= 70) { + int rc; + if (m->states.cap > ~(uintptr_t)0 / 2) + return 3; + rc = spl_map_reserve_ex(asp, m, m->states.cap * 2); + if (rc) + return rc; + } + } + spl_map_place_ex(asp, m, key, val); + return 0; +} + +SPL_CORE_FN int spl_map_get_ex(spl_asp_t *asp, void *mm, const void *key, void *out) { + spl_map_t *m = (spl_map_t *)mm; + uintptr_t i; + if (!m || !key || !out || !spl_map_valid(m)) + return 1; + i = spl_map_find_slot_ex(asp, m, key); + if (i == ~(uintptr_t)0) + return 1; + memcpy(out, spl_x(asp, m->vals.data + i * m->val_size), m->val_size); + return 0; +} + +SPL_CORE_FN int spl_map_del_ex(spl_asp_t *asp, void *mm, const void *key) { + spl_map_t *m = (spl_map_t *)mm; + uintptr_t i; + if (!m || !key || !spl_map_valid(m)) + return 1; + i = spl_map_find_slot_ex(asp, m, key); + if (i == ~(uintptr_t)0) + return 1; + spl_x(asp, m->states.data)[i] = 2; + m->size--; + return 0; +} + +SPL_CORE_FN int spl_map_clear_ex(spl_asp_t *asp, void *mm) { + spl_map_t *m = (spl_map_t *)mm; + if (!m) + return 0; + if (m->states.data && m->states.len) + memset(spl_x(asp, m->states.data), 0, m->states.len); + m->size = 0; + return 0; +} + +SPL_CORE_FN int spl_map_drop_ex(spl_asp_t *asp, void *mm) { + spl_map_t *m = (spl_map_t *)mm; + if (!m) + return 0; + spl_vec_release_ex(asp, &m->keys); + spl_vec_release_ex(asp, &m->vals); + spl_vec_release_ex(asp, &m->states); + m->size = 0; + return 0; +} + +/* ================================================================ + * 公开 C 符号(identity):供 native 编译器直接调用 + * ================================================================ */ + +SPL_CORE_FN void *vm_alloc(uintptr_t sz) { return spl_alloc_ex(SPL_ASP_ID, sz); } +SPL_CORE_FN void vm_free(void *p) { spl_free_ex(SPL_ASP_ID, p); } +SPL_CORE_FN void *vm_realloc(void *p, uintptr_t sz) { return spl_realloc_ex(SPL_ASP_ID, p, sz); } +SPL_CORE_FN int vm_bytes_eq(const void *a, uintptr_t alen, const void *b, uintptr_t blen) { + return spl_bytes_eq_ex(SPL_ASP_ID, a, alen, b, blen); +} + +SPL_CORE_FN int vm_vec_valid(const void *v) { return spl_vec_valid_ex(v); } +SPL_CORE_FN int vm_vec_push_raw(void *v, const void *e) { + return spl_vec_push_raw_ex(SPL_ASP_ID, v, e); +} +SPL_CORE_FN int vm_vec_push(void *v, const void *e) { return spl_vec_push_ex(SPL_ASP_ID, v, e); } +SPL_CORE_FN int vm_vec_get(const void *v, uintptr_t i, void **o) { + return spl_vec_get_ex(SPL_ASP_ID, v, i, o); +} +SPL_CORE_FN int vm_vec_allocate(void *o, uintptr_t c, uintptr_t es, uintptr_t ea) { + return spl_vec_allocate_out_ex(SPL_ASP_ID, o, c, es, ea); +} +SPL_CORE_FN int vm_vec_reserve_raw(void *v, uintptr_t n) { + return spl_vec_reserve_raw_void_ex(SPL_ASP_ID, v, n); +} +SPL_CORE_FN int vm_vec_append(void *v, const void *e, uintptr_t n) { + return spl_vec_append_ex(SPL_ASP_ID, v, e, n); +} +SPL_CORE_FN int vm_vec_set(void *v, uintptr_t i, const void *e) { + return spl_vec_set_ex(SPL_ASP_ID, v, i, e); +} +SPL_CORE_FN int vm_vec_pop(void *v, void *o) { return spl_vec_pop_ex(SPL_ASP_ID, v, o); } +SPL_CORE_FN int vm_vec_clone(void *o, const void *s) { return spl_vec_clone_ex(SPL_ASP_ID, o, s); } +SPL_CORE_FN int vm_vec_drop(void *v) { return spl_vec_drop_ex(SPL_ASP_ID, v); } + +SPL_CORE_FN int vm_map_valid(const void *m) { return spl_map_valid_ex(m); } +SPL_CORE_FN int vm_map_reserve(void *m, uintptr_t n) { + return spl_map_reserve_void_ex(SPL_ASP_ID, m, n); +} +SPL_CORE_FN int vm_map_put(void *m, const void *k, const void *v) { + return spl_map_put_ex(SPL_ASP_ID, m, k, v); +} +SPL_CORE_FN int vm_map_get(void *m, const void *k, void *o) { + return spl_map_get_ex(SPL_ASP_ID, m, k, o); +} +SPL_CORE_FN int vm_map_del(void *m, const void *k) { return spl_map_del_ex(SPL_ASP_ID, m, k); } +SPL_CORE_FN int vm_map_clear(void *m) { return spl_map_clear_ex(SPL_ASP_ID, m); } +SPL_CORE_FN int vm_map_drop(void *m) { return spl_map_drop_ex(SPL_ASP_ID, m); } + +#endif /* __SPL_RT_CORE_H__ */ diff --git a/stage0/spl_syscall.c b/stage0/spl_syscall.c index a0cf4b2..e8f673e 100644 --- a/stage0/spl_syscall.c +++ b/stage0/spl_syscall.c @@ -1,12 +1,3 @@ -/* spl_syscall.c - built-in syscall implementations + registration - * - * All syscalls validate nargs, cast spl_val_t args to the expected C types, - * execute, and return the result as spl_val_t. - * - * Simple syscalls use the SYSCALL_N macros; complex ones are written - * manually but follow the same template. - */ - #include "spl_syscall.h" #include "include/core_map.h" #include "include/core_vec.h" @@ -18,15 +9,10 @@ #include #include -/* ================================================================= - * Macro templates - * - * Each SYSCALL_N macro: - * 1. Validates nargs (prints error and returns -1 on mismatch) - * 2. Casts args[n] from spl_val_t to the specified C type via - * (type)(uintptr_t) - this handles both integer and pointer types - * 3. Evaluates the expression and returns the result as spl_val_t - * ================================================================= */ +/* VM 偏移 -> 宿主地址;size=0 表示不做边界检查。 */ +#define VM_X(_vm, off) ((void *)spl_vm_xlate((_vm), (spl_vm_val_t)(off), 0)) +#define VM_XN(_vm, off, n) ((void *)spl_vm_xlate((_vm), (spl_vm_val_t)(off), (usize)(n))) +#define VM_ASP(_vm) spl_vm_asp(_vm) #define CHECK_NARGS(fname, expected) \ do { \ @@ -82,9 +68,6 @@ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } -/* syscall / VM 内部统一地址检查宏。 - * 失败时打印 ctx + 地址 + size + ip,置 native_error,return 0。 - * 要求所在函数有可用的 _vm 变量。 */ #define ADDRCHECK(vm, ptr, size, ctx) \ do { \ uintptr_t _acp = (uintptr_t)(ptr); \ @@ -98,7 +81,6 @@ } \ } while (0) -/* syscall 内部:把当前栈和调用栈打印出来,供出错时定位 */ #define SYSCALL_DUMP(vm) \ do { \ fprintf(stderr, " --- syscall dump (sp=%zu fp=%zu cp=%zu ip=%zu) ---\n", (vm)->sp, \ @@ -107,7 +89,6 @@ spl_vm_stackdump((vm), (vm)->sp); \ } while (0) -/* syscall 内部:报告致命错误,dump 后让 VM 停在当前 ip */ #define SYSCALL_FAIL(vm, ...) \ do { \ fprintf(stderr, "syscall error: "); \ @@ -118,153 +99,428 @@ return 0; \ } while (0) +/* ================================================================= + * 从共享核心 spl_rt_core.h 派生的 syscall 包装 + * ================================================================= */ + +#include "spl_rt_core.h" + +#define SPL_WRAP1(name, fn, t1) \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ + CHECK_NARGS(#name, 1); \ + return (spl_vm_val_t)(uintptr_t)fn((t1)(uintptr_t)args[0]); \ + } + +#define SPL_WRAP1_V(name, fn, t1) \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ + CHECK_NARGS(#name, 1); \ + fn((t1)(uintptr_t)args[0]); \ + return 0; \ + } + +#define SPL_WRAP2(name, fn, t1, t2) \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ + CHECK_NARGS(#name, 2); \ + return (spl_vm_val_t)(uintptr_t)fn((t1)(uintptr_t)args[0], (t2)(uintptr_t)args[1]); \ + } + +#define SPL_WRAP3(name, fn, t1, t2, t3) \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ + CHECK_NARGS(#name, 3); \ + return (spl_vm_val_t)(uintptr_t)fn((t1)(uintptr_t)args[0], (t2)(uintptr_t)args[1], \ + (t3)(uintptr_t)args[2]); \ + } + +#define SPL_WRAP4(name, fn, t1, t2, t3, t4) \ + static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ + (void)_vm; \ + CHECK_NARGS(#name, 4); \ + return (spl_vm_val_t)(uintptr_t)fn((t1)(uintptr_t)args[0], (t2)(uintptr_t)args[1], \ + (t3)(uintptr_t)args[2], (t4)(uintptr_t)args[3]); \ + } + /* ================================================================= * OS syscalls * ================================================================= */ -/* vm_exit - terminate process with the given exit code */ SYSCALL_1(vm_exit, int, (exit(a1), (spl_vm_val_t)0)) - -/* vm_putchar - write a single character to stdout */ SYSCALL_1(vm_putchar, int, putchar(a1)) - -/* vm_getchar - read a single character from stdin */ SYSCALL_0(vm_getchar, getchar()) - -/* vm_putint - print an integer to stdout */ SYSCALL_1(vm_putint, int, (fprintf(stdout, "%d", a1), (spl_vm_val_t)0)) -/* vm_putstr - print a string to stdout (no trailing newline) */ -SYSCALL_1(vm_putstr, const char *, (fputs(a1, stdout), (spl_vm_val_t)0)) - -/* vm_fopen - open a file, returns FILE* as spl_val_t */ -SYSCALL_2(vm_fopen, const char *, const char *, (uintptr_t)fopen(a1, a2)) - -/* vm_fclose - close a file, returns 0 on success */ -SYSCALL_1(vm_fclose, FILE *, fclose(a1)) - -/* vm_fread - read from file, returns number of items read */ -SYSCALL_4(vm_fread, void *, size_t, size_t, FILE *, fread(a1, a2, a3, a4)) - -/* vm_fwrite - write to file, returns number of items written */ -SYSCALL_4(vm_fwrite, const void *, size_t, size_t, FILE *, fwrite(a1, a2, a3, a4)) - -/* vm_fsize - get file size in bytes */ -static spl_vm_val_t vm_fsize(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - (void)_vm; - CHECK_NARGS("vm_fsize", 1); - FILE *f = (FILE *)(uintptr_t)args[0]; - long cur = ftell(f); - fseek(f, 0, SEEK_END); - long sz = ftell(f); - fseek(f, cur, SEEK_SET); - return (spl_vm_val_t)(uintptr_t)sz; +/* FILE* 存于 VM 空间,返回其偏移(不透明句柄)。 */ +static spl_vm_val_t vm_file_handle(spl_vm_t *vm, FILE *f) { + spl_vm_val_t off; + FILE **slot; + if (!f) + return 0; + off = (spl_vm_val_t)(uintptr_t)spl_alloc_ex(VM_ASP(vm), sizeof(FILE *)); + if (off == 0) + return 0; + slot = (FILE **)VM_XN(vm, off, sizeof(FILE *)); + if (!slot) + return 0; + *slot = f; + return off; } -SYSCALL_0(vm_stdin, stdin) -SYSCALL_0(vm_stdout, stdout) -SYSCALL_0(vm_stderr, stderr) +static FILE *vm_file_get(spl_vm_t *vm, spl_vm_val_t off) { + FILE **slot = (FILE **)VM_XN(vm, off, sizeof(FILE *)); + return slot ? *slot : NULL; +} + +static spl_vm_val_t vm_putstr(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + const char *s; + CHECK_NARGS("vm_putstr", 1); + s = (const char *)VM_X(_vm, args[0]); + if (s) + fputs(s, stdout); + return 0; +} + +static spl_vm_val_t vm_fopen(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + const char *path, *mode; + CHECK_NARGS("vm_fopen", 2); + path = (const char *)VM_X(_vm, args[0]); + mode = (const char *)VM_X(_vm, args[1]); + return vm_file_handle(_vm, fopen(path, mode)); +} + +static spl_vm_val_t vm_fclose(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + FILE *f; + CHECK_NARGS("vm_fclose", 1); + f = vm_file_get(_vm, args[0]); + return f ? (spl_vm_val_t)fclose(f) : 0; +} + +static spl_vm_val_t vm_fread(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + void *buf; + FILE *f; + CHECK_NARGS("vm_fread", 4); + buf = VM_X(_vm, args[0]); + f = vm_file_get(_vm, args[3]); + if (!buf || !f) + return 0; + return (spl_vm_val_t)fread(buf, (size_t)args[1], (size_t)args[2], f); +} + +static spl_vm_val_t vm_fwrite(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + const void *buf; + FILE *f; + CHECK_NARGS("vm_fwrite", 4); + buf = VM_X(_vm, args[0]); + f = vm_file_get(_vm, args[3]); + if (!buf || !f) + return 0; + return (spl_vm_val_t)fwrite(buf, (size_t)args[1], (size_t)args[2], f); +} + +static spl_vm_val_t vm_fsize(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + FILE *f; + long cur, sz; + CHECK_NARGS("vm_fsize", 1); + f = vm_file_get(_vm, args[0]); + if (!f) + return 0; + cur = ftell(f); + fseek(f, 0, SEEK_END); + sz = ftell(f); + fseek(f, cur, SEEK_SET); + return (spl_vm_val_t)(uintptr_t)(sz < 0 ? 0 : sz); +} + +static spl_vm_val_t vm_std_handle(spl_vm_t *_vm, int which) { + if (_vm->stdio_off[which] == 0) { + FILE *f = which == 0 ? stdin : (which == 1 ? stdout : stderr); + _vm->stdio_off[which] = vm_file_handle(_vm, f); + } + return _vm->stdio_off[which]; +} + +static spl_vm_val_t vm_stdin(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)args; + CHECK_NARGS("vm_stdin", 0); + return vm_std_handle(_vm, 0); +} +static spl_vm_val_t vm_stdout(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)args; + CHECK_NARGS("vm_stdout", 0); + return vm_std_handle(_vm, 1); +} +static spl_vm_val_t vm_stderr(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)args; + CHECK_NARGS("vm_stderr", 0); + return vm_std_handle(_vm, 2); +} -/* vm_read_file - read entire file into a malloc'd, null-terminated buffer */ static spl_vm_val_t vm_read_file(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - (void)_vm; CHECK_NARGS("vm_read_file", 1); - const char *path = (const char *)(uintptr_t)args[0]; + const char *path = (const char *)VM_X(_vm, args[0]); + FILE *f; + long sz; + spl_vm_val_t off; + char *buf; if (path == nullptr) { fprintf(stderr, "filepath can't be null"); return 0; } - FILE *f = fopen(path, "rb"); + f = fopen(path, "rb"); if (!f) { fprintf(stderr, "filepath %s can't be open", path); return 1; } fseek(f, 0, SEEK_END); - long sz = ftell(f); + sz = ftell(f); fseek(f, 0, SEEK_SET); - char *buf = (char *)malloc((size_t)sz + 1); + off = (spl_vm_val_t)(uintptr_t)spl_alloc_ex(VM_ASP(_vm), (uintptr_t)sz + 1); + if (off == 0) { + fclose(f); + return 0; + } + buf = (char *)VM_XN(_vm, off, (uintptr_t)sz + 1); if (!buf) { fclose(f); return 0; } - size_t nread = fread(buf, 1, (size_t)sz, f); + { + size_t nread = fread(buf, 1, (size_t)sz, f); + buf[nread] = '\0'; + } fclose(f); - buf[nread] = '\0'; - return (spl_vm_val_t)(uintptr_t)buf; + return off; } -static spl_vm_val_t vm_alloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { +/* ================================================================= + * mem syscalls —— 使用 spl_rt_core.h 中的实现 + * ================================================================= */ + +static spl_vm_val_t spl_sys_vm_alloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + uintptr_t sz; + spl_vm_val_t p; CHECK_NARGS("vm_alloc", 1); - size_t sz = (size_t)args[0]; + sz = (uintptr_t)args[0]; if (sz == 0) SYSCALL_FAIL(_vm, "vm_alloc: zero size"); - if (sz > (size_t)1 << 32) - SYSCALL_FAIL(_vm, "vm_alloc: size too large (%zu)", sz); - void *p = malloc(sz); - if (!p) - SYSCALL_FAIL(_vm, "vm_alloc: malloc(%zu) failed", sz); - return (spl_vm_val_t)(uintptr_t)p; + if (sz > ((uintptr_t)1 << 32)) + SYSCALL_FAIL(_vm, "vm_alloc: size too large (%zu)", (size_t)sz); + p = (spl_vm_val_t)(uintptr_t)spl_alloc_ex(VM_ASP(_vm), sz); + if (p == 0) + SYSCALL_FAIL(_vm, "vm_alloc: alloc(%zu) failed", (size_t)sz); + return p; } -static spl_vm_val_t vm_free(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - (void)_vm; +static spl_vm_val_t spl_sys_vm_free(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_free", 1); - void *p = (void *)(uintptr_t)args[0]; - if (p) - free(p); + spl_free_ex(VM_ASP(_vm), (void *)(uintptr_t)args[0]); return 0; } -static spl_vm_val_t vm_realloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { +static spl_vm_val_t spl_sys_vm_realloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + uintptr_t sz; + spl_vm_val_t np; CHECK_NARGS("vm_realloc", 2); - void *p = (void *)(uintptr_t)args[0]; - size_t sz = (size_t)args[1]; - if (!p) + sz = (uintptr_t)args[1]; + if (args[0] == 0) SYSCALL_FAIL(_vm, "vm_realloc: NULL ptr"); if (sz == 0) SYSCALL_FAIL(_vm, "vm_realloc: zero size"); - ADDRCHECK(_vm, p, 1, "vm_realloc"); - void *np = realloc(p, sz); - if (!np) - SYSCALL_FAIL(_vm, "vm_realloc: realloc(%p, %zu) failed", p, sz); - return (spl_vm_val_t)(uintptr_t)np; + np = (spl_vm_val_t)(uintptr_t)spl_realloc_ex(VM_ASP(_vm), (void *)(uintptr_t)args[0], sz); + if (np == 0) + SYSCALL_FAIL(_vm, "vm_realloc: realloc failed"); + return np; } -static spl_vm_val_t vm_memcpy(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { +static spl_vm_val_t spl_sys_vm_memcpy(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + void *dst, *src; + uintptr_t n; CHECK_NARGS("vm_memcpy", 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_memcpy(dst)"); - ADDRCHECK(_vm, src, size, "vm_memcpy(src)"); - memcpy(dst, src, size); - return (spl_vm_val_t)(uintptr_t)dst; + n = (uintptr_t)args[2]; + if (n == 0) + return args[0]; + dst = VM_X(_vm, args[0]); + src = VM_X(_vm, args[1]); + if (!dst || !src) + SYSCALL_FAIL(_vm, "vm_memcpy: invalid address"); + vm_memcpy(dst, src, n); + return args[0]; } -static spl_vm_val_t vm_memcmp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - CHECK_NARGS("vm_memcmp", 3); - const void *a = (const void *)(uintptr_t)args[0]; - const void *b = (const void *)(uintptr_t)args[1]; - size_t size = (size_t)args[2]; - if (size == 0) - return 0; - ADDRCHECK(_vm, a, size, "vm_memcmp(a)"); - ADDRCHECK(_vm, b, size, "vm_memcmp(b)"); - return (spl_vm_val_t)memcmp(a, b, size); +static spl_vm_val_t spl_sys_vm_memmove(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + void *dst, *src; + uintptr_t n; + CHECK_NARGS("vm_memmove", 3); + n = (uintptr_t)args[2]; + if (n == 0) + return args[0]; + dst = VM_X(_vm, args[0]); + src = VM_X(_vm, args[1]); + if (!dst || !src) + SYSCALL_FAIL(_vm, "vm_memmove: invalid address"); + vm_memmove(dst, src, n); + return args[0]; } +static spl_vm_val_t spl_sys_vm_memcmp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + const void *a, *b; + uintptr_t n; + CHECK_NARGS("vm_memcmp", 3); + a = VM_X(_vm, args[0]); + b = VM_X(_vm, args[1]); + n = (uintptr_t)args[2]; + if (n && (!a || !b)) + SYSCALL_FAIL(_vm, "vm_memcmp: invalid address"); + return (spl_vm_val_t)(uintptr_t)vm_memcmp(a, b, n); +} + +/* ================================================================= + * Vec syscalls(参数按 VM 偏移解释) + * ================================================================= */ + +#define VM_VEC_BYTES ((uintptr_t)sizeof(spl_vec_t)) +#define VM_MAP_BYTES ((uintptr_t)sizeof(spl_map_t)) + +static spl_vm_val_t spl_sys_vm_vec_valid(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_valid", 1); + return (spl_vm_val_t)(uintptr_t)spl_vec_valid_ex(VM_XN(_vm, args[0], VM_VEC_BYTES)); +} + +static spl_vm_val_t spl_sys_vm_vec_push_raw(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_push_raw", 2); + return (spl_vm_val_t)(uintptr_t)spl_vec_push_raw_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_X(_vm, args[1])); +} + +static spl_vm_val_t spl_sys_vm_vec_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_push", 2); + return (spl_vm_val_t)(uintptr_t)spl_vec_push_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_X(_vm, args[1])); +} + +static spl_vm_val_t spl_sys_vm_vec_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_get", 3); + return (spl_vm_val_t)(uintptr_t)spl_vec_get_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), (uintptr_t)args[1], + (void **)VM_XN(_vm, args[2], sizeof(void *))); +} + +static spl_vm_val_t spl_sys_vm_vec_allocate(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_allocate", 4); + return (spl_vm_val_t)(uintptr_t)spl_vec_allocate_out_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), (uintptr_t)args[1], (uintptr_t)args[2], + (uintptr_t)args[3]); +} + +static spl_vm_val_t spl_sys_vm_vec_reserve_raw(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_reserve_raw", 2); + return (spl_vm_val_t)(uintptr_t)spl_vec_reserve_raw_void_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), (uintptr_t)args[1]); +} + +static spl_vm_val_t spl_sys_vm_vec_append(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_append", 3); + return (spl_vm_val_t)(uintptr_t)spl_vec_append_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_X(_vm, args[1]), (uintptr_t)args[2]); +} + +static spl_vm_val_t spl_sys_vm_vec_set(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_set", 3); + return (spl_vm_val_t)(uintptr_t)spl_vec_set_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), (uintptr_t)args[1], VM_X(_vm, args[2])); +} + +static spl_vm_val_t spl_sys_vm_vec_pop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_pop", 2); + return (spl_vm_val_t)(uintptr_t)spl_vec_pop_ex(VM_ASP(_vm), + VM_XN(_vm, args[0], VM_VEC_BYTES), + VM_X(_vm, args[1])); +} + +static spl_vm_val_t spl_sys_vm_vec_clone(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_clone", 2); + return (spl_vm_val_t)(uintptr_t)spl_vec_clone_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_XN(_vm, args[1], VM_VEC_BYTES)); +} + +static spl_vm_val_t spl_sys_vm_vec_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_vec_drop", 1); + return (spl_vm_val_t)(uintptr_t)spl_vec_drop_ex(VM_ASP(_vm), + VM_XN(_vm, args[0], VM_VEC_BYTES)); +} + +static spl_vm_val_t spl_sys_vm_bytes_eq(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_bytes_eq", 4); + return (spl_vm_val_t)(uintptr_t)spl_bytes_eq_ex(VM_ASP(_vm), VM_X(_vm, args[0]), + (uintptr_t)args[1], VM_X(_vm, args[2]), + (uintptr_t)args[3]); +} + +/* ================================================================= + * Map syscalls + * ================================================================= */ + +static spl_vm_val_t spl_sys_vm_map_valid(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_map_valid", 1); + return (spl_vm_val_t)(uintptr_t)spl_map_valid_ex(VM_XN(_vm, args[0], VM_MAP_BYTES)); +} + +static spl_vm_val_t spl_sys_vm_map_reserve(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_map_reserve", 2); + return (spl_vm_val_t)(uintptr_t)spl_map_reserve_void_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES), (uintptr_t)args[1]); +} + +static spl_vm_val_t spl_sys_vm_map_put(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_map_put", 3); + return (spl_vm_val_t)(uintptr_t)spl_map_put_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES), VM_X(_vm, args[1]), VM_X(_vm, args[2])); +} + +static spl_vm_val_t spl_sys_vm_map_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_map_get", 3); + return (spl_vm_val_t)(uintptr_t)spl_map_get_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES), VM_X(_vm, args[1]), VM_X(_vm, args[2])); +} + +static spl_vm_val_t spl_sys_vm_map_del(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_map_del", 2); + return (spl_vm_val_t)(uintptr_t)spl_map_del_ex( + VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES), VM_X(_vm, args[1])); +} + +static spl_vm_val_t spl_sys_vm_map_clear(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_map_clear", 1); + return (spl_vm_val_t)(uintptr_t)spl_map_clear_ex(VM_ASP(_vm), + VM_XN(_vm, args[0], VM_MAP_BYTES)); +} + +static spl_vm_val_t spl_sys_vm_map_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + CHECK_NARGS("vm_map_drop", 1); + return (spl_vm_val_t)(uintptr_t)spl_map_drop_ex(VM_ASP(_vm), + VM_XN(_vm, args[0], VM_MAP_BYTES)); +} + +/* ================================================================= + * printf / timestamp + * ================================================================= */ + static spl_vm_val_t vm_printf(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - (void)_vm; if (nargs <= 0) return 0; - /* args[0] 是 SPL 的 []u8 format 参数。VM 里 slice 作为参数传递时, - 栈上压的是"指向 slice 结构体的指针",结构为 {ptr:*u8, len:u64} */ - const spl_vm_val_t *fmt_slice = (const spl_vm_val_t *)args[0]; - const char *fmt = (const char *)fmt_slice[0]; - usize fmt_len = (usize)fmt_slice[1]; + const spl_vm_val_t *fmt_slice = + (const spl_vm_val_t *)VM_XN(_vm, args[0], 2 * sizeof(spl_vm_val_t)); + const char *fmt; + usize fmt_len; + if (!fmt_slice) + return 0; + fmt = (const char *)VM_X(_vm, fmt_slice[0]); + fmt_len = (usize)fmt_slice[1]; + if (!fmt && fmt_len) + return 0; if (nargs <= 1) { fwrite(fmt, 1, fmt_len, stdout); @@ -275,7 +531,7 @@ static spl_vm_val_t vm_printf(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { string_builder_t buffer; vec_init(buffer); - int arg_idx = 1; /* 0 是 format */ + int arg_idx = 1; char tmp_buf[32]; for (usize i = 0; i < fmt_len; ++i) { @@ -302,11 +558,13 @@ static spl_vm_val_t vm_printf(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { arg_idx++; break; case 's': { - const spl_vm_val_t *s = (const spl_vm_val_t *)args[arg_idx]; - const char *p = (const char *)s[0]; - usize l = (usize)s[1]; - for (usize j = 0; j < l; ++j) - vec_push(buffer, p[j]); + const spl_vm_val_t *s = + (const spl_vm_val_t *)VM_XN(_vm, args[arg_idx], 2 * sizeof(spl_vm_val_t)); + const char *p = s ? (const char *)VM_X(_vm, s[0]) : NULL; + usize l = s ? (usize)s[1] : 0; + if (p) + for (usize j = 0; j < l; ++j) + vec_push(buffer, p[j]); arg_idx++; break; } @@ -323,15 +581,6 @@ static spl_vm_val_t vm_printf(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { return (spl_vm_val_t)nargs; } -/* 探测接口(syscall 风格,非必选,逐步扩展)。 - * 不假设一定可用:不支持时统一返回 0。 - * case 0 -> 是否存在 time:1 = 存在(则 case 1/2 有效),0 = 不存在 - * case 1 -> 当前秒(time_t) - * case 2 -> 当前纳秒部分(tv_nsec) - * case 3 -> VM 已执行指令数(参考量;解码/执行恒定时可换算时间) - * case 4 -> 完整纳秒时间戳(单次调用,避免 sec/ns 跨秒竞态; - * 纪元纳秒约 1.8e18 < u64 上限,usize 足够,无需 i128) - * 新增探测点先加 case,再在 SPL 侧逐步验证。 */ static spl_vm_val_t vm_timestamp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_timestamp", 1); spl_vm_val_t arg = args[0]; @@ -363,17 +612,42 @@ static spl_vm_val_t vm_timestamp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { } /* ================================================================= - * VM syscalls (for comptime - compile-time code execution) - * - * These let SPL code create isolated sub-VMs, load compiled .sir - * programs into them, push arguments, call functions, and run. + * nested-VM syscalls * ================================================================= */ -/* vm_new - create a new sub-VM instance, returns spl_vm_t* */ +/* ---- 配置层的“外部函数处理器”:把某个 VM 未解析的 native 交给调用者 VM。 + * 这是配置策略,不属于 VM 库 API;VM 本身只有通用 foreign 钩子。 ---- */ +typedef struct { + spl_vm_t *caller; + void *ctx; +} spl_foreign_t; + +static spl_vm_val_t spl_foreign_reenter(spl_vm_t *vm, const spl_vm_call_t *call, void *user) { + spl_foreign_t *f = (spl_foreign_t *)user; + spl_vm_val_t tmp[20]; + spl_vm_call_t c2; + int i; + (void)vm; + if (!f || !f->caller || !call || !call->name) + return 0; + if (call->nargs + 1 > (usize)(sizeof(tmp) / sizeof(tmp[0]))) + return 0; + tmp[0] = (spl_vm_val_t)(uintptr_t)f->ctx; + for (i = 0; i < (int)call->nargs; i++) + tmp[1 + i] = call->args ? call->args[i] : 0; + c2.name = call->name; + c2.args = tmp; + c2.nargs = call->nargs + 1; + c2.ret = 0; + if (spl_vm_invoke(f->caller, &c2) != 0) + return 0; + return c2.ret; +} + static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - (void)_vm; CHECK_NARGS("vm_new", 0); (void)args; + (void)_vm; spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t)); if (!vm) return 0; @@ -381,13 +655,36 @@ static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { return (spl_vm_val_t)(uintptr_t)vm; } -/* vm_drop - destroy a sub-VM and its loaded program */ +/* 配置入口:vm_set_foreign(vm, handler, ctx)。handler=0:把未解析 native 重入 + * 当前调用者(_vm),ctx 透传前置。名与语义由配置层定义;VM 库不认识 foreign handler。 */ +static spl_vm_val_t sc_vm_set_foreign(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + spl_vm_t *vm; + spl_foreign_t *f; + CHECK_NARGS("vm_set_foreign", 3); + vm = (spl_vm_t *)(uintptr_t)args[0]; + if (!vm || !_vm) + return -1; + if (args[1] != 0) /* 仅注册 handler 0(重入调用者) */ + return -1; + if (vm->foreign == spl_foreign_reenter && vm->foreign_ctx) + free(vm->foreign_ctx); + f = (spl_foreign_t *)malloc(sizeof(*f)); + if (!f) + return -1; + f->caller = _vm; + f->ctx = (void *)(uintptr_t)args[2]; + spl_vm_set_foreign(vm, spl_foreign_reenter, f); + return 0; +} + static spl_vm_val_t vm_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_drop", 1); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; if (!vm) return 0; + if (vm->foreign == spl_foreign_reenter && vm->foreign_ctx) + free(vm->foreign_ctx); if (vm->prog) { spl_prog_drop(vm->prog); free(vm->prog); @@ -398,12 +695,10 @@ static spl_vm_val_t vm_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { return 0; } -/* vm_load - load a .sir file, register syscalls, return spl_prog_t* */ static spl_vm_val_t vm_load(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - (void)_vm; CHECK_NARGS("vm_load", 2); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; - const char *path = (const char *)(uintptr_t)args[1]; + const char *path = (const char *)VM_X(_vm, args[1]); if (!vm || !path) return -1; @@ -423,13 +718,10 @@ static spl_vm_val_t vm_load(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { return (spl_vm_val_t)(uintptr_t)prog; } -/* vm_load_from_buffer - 从内存加载字节码(comptime 内嵌 VM 用)。 - * 参数 1 是 slice 结构 { ptr, len } 的地址(聚合参数按指针传递)。 */ static spl_vm_val_t vm_load_from_buffer(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - (void)_vm; CHECK_NARGS("vm_load_from_buffer", 3); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; - const char *buf = (const char *)(uintptr_t)args[1]; + const char *buf = (const char *)VM_XN(_vm, args[1], (usize)args[2]); usize len = (usize)args[2]; spl_prog_t *prog; if (!vm || !buf) @@ -441,7 +733,7 @@ static spl_vm_val_t vm_load_from_buffer(spl_vm_t *_vm, int nargs, spl_vm_val_t * free(prog); return -1; } - spl_syscall_register(prog); + /* 不自动注入任何 native/syscall:解析策略由使用者配置。 */ if (spl_vm_load_prog(vm, prog) != 0) { spl_prog_drop(prog); free(prog); @@ -450,7 +742,6 @@ static spl_vm_val_t vm_load_from_buffer(spl_vm_t *_vm, int nargs, spl_vm_val_t * return 0; } -/* vm_push - push a value onto the sub-VM's stack (for passing arguments) */ static spl_vm_val_t vm_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_push", 2); @@ -466,52 +757,21 @@ static spl_vm_val_t vm_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { return 0; } -/* vm_call - call a function by name with pre-pushed arguments - * - * Args (3): vm, function_name, nargs - * The arguments should already be on the sub-VM's stack via vm_push. - * - * Mirrors the CALL instruction's frame setup: - * - Pushes a sentinel frame (saved_ip=-1) if cp==0 so RET halts properly - * - Pushes the actual call frame - * - Sets fp = sp - nargs (so arg0 = data[fp], arg1 = data[fp+1], ...) - * - Sets ip to the function address - */ static spl_vm_val_t vm_call(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { - (void)_vm; CHECK_NARGS("vm_call", 3); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; - const char *name = (const char *)(uintptr_t)args[1]; + const char *name = (const char *)VM_X(_vm, args[1]); spl_vm_val_t call_nargs = args[2]; if (!vm || !name) return -1; - spl_vm_func_t *func = spl_prog_get_func(vm->prog, name); - if (!func) { - fprintf(stderr, "vm_call: function '%s' not found\n", name); + if (spl_vm_call_entry(vm, name, (int)call_nargs) != 0) { + fprintf(stderr, "vm_call: function '%s' not found or bad ABI\n", name); return -1; } - if (vm->cp >= vm->config.max_call_depth) { - fprintf(stderr, "vm_call: call stack overflow\n"); - return -1; - } - - /* 入口调用:ip 置 -1 作为 sentinel,RET 时 halt 并把返回值写入 exit_code。 - * 实参须已由 vm_push 压栈(sp = nargs)。 */ - vm->ip = (uintptr_t)-1; - vm->cp = 0; - vm->fp = 0; - vm->frames.data[0].saved_sp = vm->sp - call_nargs; - vm->frames.data[0].saved_fp = vm->fp; - vm->frames.data[0].saved_ip = vm->ip; - vm->frames.data[0].nargs = call_nargs; - vm->cp = 1; - vm->ip = (uintptr_t)func->address; - vm->fp = vm->sp - call_nargs; return 0; } -/* vm_run - run a sub-VM to completion, returns exit_code(入口 RET 的值) */ static spl_vm_val_t vm_run(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_run", 1); @@ -519,636 +779,79 @@ static spl_vm_val_t vm_run(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { if (!vm) return -1; spl_vm_run_until(vm, 0); - return (spl_vm_val_t)vm->exit_code; + return (spl_vm_val_t)vm->ret_val; +} + +/* ---- 栈 / 结果 / 内存 访问(不暴露宿主指针) ---- */ + +static spl_vm_val_t sc_vm_ret_val(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_ret_val", 1); + return spl_vm_ret_val((spl_vm_t *)(uintptr_t)args[0]); +} + +static spl_vm_val_t sc_vm_sp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_sp", 1); + return (spl_vm_val_t)spl_vm_sp((spl_vm_t *)(uintptr_t)args[0]); +} + +static spl_vm_val_t sc_vm_fp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_fp", 1); + return (spl_vm_val_t)spl_vm_fp((spl_vm_t *)(uintptr_t)args[0]); +} + +static spl_vm_val_t sc_vm_stack_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_stack_get", 2); + return spl_vm_stack_get((spl_vm_t *)(uintptr_t)args[0], (usize)args[1]); +} + +static spl_vm_val_t sc_vm_stack_set(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_stack_set", 3); + return (spl_vm_val_t)spl_vm_stack_set((spl_vm_t *)(uintptr_t)args[0], (usize)args[1], args[2]); +} + +static spl_vm_val_t sc_vm_mem_alloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + (void)_vm; + CHECK_NARGS("vm_mem_alloc", 2); + return spl_vm_mem_alloc((spl_vm_t *)(uintptr_t)args[0], (usize)args[1]); +} + +static spl_vm_val_t sc_vm_mem_read(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + spl_vm_t *vm; + void *dst; + usize n; + CHECK_NARGS("vm_mem_read", 4); + vm = (spl_vm_t *)(uintptr_t)args[0]; + n = (usize)args[3]; + dst = VM_XN(_vm, args[2], n); + if ((!dst) && n) + return -1; + return (spl_vm_val_t)spl_vm_mem_read(vm, (spl_vm_val_t)args[1], dst, n); +} + +static spl_vm_val_t sc_vm_mem_write(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { + spl_vm_t *vm; + void *src; + usize n; + CHECK_NARGS("vm_mem_write", 4); + vm = (spl_vm_t *)(uintptr_t)args[0]; + n = (usize)args[3]; + src = VM_XN(_vm, args[2], n); + if ((!src) && n) + return -1; + return (spl_vm_val_t)spl_vm_mem_write(vm, (spl_vm_val_t)args[1], src, n); } /* ================================================================= * Registration - * - * Called after loading a .sir file. Matches native declarations in - * 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 */ {"vm_exit", 0, vm_exit}, {"vm_putchar", 0, vm_putchar}, {"vm_getchar", 0, vm_getchar}, @@ -1163,42 +866,55 @@ void spl_syscall_register(spl_prog_t *prog) { {"vm_stdout", 0, vm_stdout}, {"vm_stderr", 0, vm_stderr}, {"vm_read_file", 0, vm_read_file}, - {"vm_alloc", 0, vm_alloc}, - {"vm_free", 0, vm_free}, - {"vm_realloc", 0, vm_realloc}, - {"vm_memcpy", 0, vm_memcpy}, - {"vm_memcmp", 0, vm_memcmp}, + + {"vm_alloc", 0, spl_sys_vm_alloc}, + {"vm_free", 0, spl_sys_vm_free}, + {"vm_realloc", 0, spl_sys_vm_realloc}, + {"vm_memcpy", 0, spl_sys_vm_memcpy}, + {"vm_memmove", 0, spl_sys_vm_memmove}, + {"vm_memcmp", 0, spl_sys_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_vec_valid", 0, spl_sys_vm_vec_valid}, + {"vm_vec_push_raw", 0, spl_sys_vm_vec_push_raw}, + {"vm_vec_push", 0, spl_sys_vm_vec_push}, + {"vm_vec_get", 0, spl_sys_vm_vec_get}, + {"vm_vec_allocate", 0, spl_sys_vm_vec_allocate}, + {"vm_vec_reserve_raw", 0, spl_sys_vm_vec_reserve_raw}, + {"vm_vec_append", 0, spl_sys_vm_vec_append}, + {"vm_vec_set", 0, spl_sys_vm_vec_set}, + {"vm_vec_pop", 0, spl_sys_vm_vec_pop}, + {"vm_vec_clone", 0, spl_sys_vm_vec_clone}, + {"vm_vec_drop", 0, spl_sys_vm_vec_drop}, + {"vm_bytes_eq", 0, spl_sys_vm_bytes_eq}, + + {"vm_map_valid", 0, spl_sys_vm_map_valid}, + {"vm_map_reserve", 0, spl_sys_vm_map_reserve}, + {"vm_map_put", 0, spl_sys_vm_map_put}, + {"vm_map_get", 0, spl_sys_vm_map_get}, + {"vm_map_del", 0, spl_sys_vm_map_del}, + {"vm_map_clear", 0, spl_sys_vm_map_clear}, + {"vm_map_drop", 0, spl_sys_vm_map_drop}, {"vm_timestamp", 0, vm_timestamp}, - /* VM operations (comptime) */ + {"vm_new", 0, vm_new}, + {"vm_set_foreign", 0, sc_vm_set_foreign}, {"vm_drop", 0, vm_drop}, {"vm_load", 0, vm_load}, {"vm_load_from_buffer", 0, vm_load_from_buffer}, {"vm_push", 0, vm_push}, {"vm_call", 0, vm_call}, {"vm_run", 0, vm_run}, + + {"vm_ret_val", 0, sc_vm_ret_val}, + {"vm_sp", 0, sc_vm_sp}, + {"vm_fp", 0, sc_vm_fp}, + {"vm_stack_get", 0, sc_vm_stack_get}, + {"vm_stack_set", 0, sc_vm_stack_set}, + {"vm_mem_alloc", 0, sc_vm_mem_alloc}, + {"vm_mem_read", 0, sc_vm_mem_read}, + {"vm_mem_write", 0, sc_vm_mem_write}, }; int n = (int)(sizeof(table) / sizeof(table[0])); if (!prog) diff --git a/stage0/spl_vm.c b/stage0/spl_vm.c index 828ba6a..7b83848 100644 --- a/stage0/spl_vm.c +++ b/stage0/spl_vm.c @@ -568,6 +568,18 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) { vec_realloc(vm->frames, (usize)vm->config.max_call_depth); vec_init(vm->breakpoints); vec_init(vm->fn_breakpoints); + vec_init(vm->gdata_off); + vec_init(vm->regions); + + /* regions[0] 保留;regions[1] = 栈区。 */ + vec_push(vm->regions, ((spl_vm_region_t){NULL, 0, 0})); + vec_push(vm->regions, ((spl_vm_region_t){ + (unsigned char *)vm->stacks.data, + (usize)vm->config.max_stack_depth * sizeof(spl_vm_val_t), 1})); + vm->stdio_off[0] = vm->stdio_off[1] = vm->stdio_off[2] = 0; + vm->ret_val = 0; + vm->foreign = NULL; + vm->foreign_ctx = NULL; vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0; vm->steps = 0; @@ -593,9 +605,206 @@ void spl_vm_drop(spl_vm_t *vm) { free(vm->fn_breakpoints.data[i]); vec_free(vm->fn_breakpoints); vec_free(vm->breakpoints); + vec_free(vm->gdata_off); + for (usize i = 2; i < vec_size(vm->regions); i++) { + spl_vm_region_t *r = &vec_at(vm->regions, i); + if (r->used && r->base) + free(r->base); + } + vec_free(vm->regions); spl_vm_profile_free(vm); } +/* ================================================================ + * 统一偏移地址空间:offset = (handle<<32) | 区内字节偏移 + * ================================================================ */ + +#define SPL_ASP_HANDLE_OF(off) ((usize)((spl_vm_val_t)(off) >> 32)) +#define SPL_ASP_BYTE_OF(off) ((usize)((spl_vm_val_t)(off) & 0xFFFFFFFFull)) + +static spl_vm_region_t *spl_vm_region_at(spl_vm_t *vm, usize handle) { + if (handle == 0 || handle >= vec_size(vm->regions)) + return NULL; + return &vec_at(vm->regions, handle); +} + +void *spl_vm_xlate(spl_vm_t *vm, spl_vm_val_t off, usize size) { + usize handle, byte; + spl_vm_region_t *r; + if (!vm || off == SPL_OFF_NULL) + return NULL; + handle = SPL_ASP_HANDLE_OF(off); + byte = SPL_ASP_BYTE_OF(off); + r = spl_vm_region_at(vm, handle); + if (!r || !r->used) + return NULL; + if (byte > r->size || (size > 0 && byte + size > r->size)) + return NULL; + return (void *)(r->base + byte); +} + +spl_vm_val_t spl_vm_to_off(spl_vm_t *vm, const void *ptr) { + if (!vm || !ptr) + return SPL_OFF_NULL; + { + unsigned char *p = (unsigned char *)ptr; + usize i; + for (i = 1; i < vec_size(vm->regions); i++) { + spl_vm_region_t *r = &vec_at(vm->regions, i); + if (r->used && r->base && p >= r->base && p < r->base + r->size) + return SPL_ASP_OFF(i, (usize)(p - r->base)); + } + } + return SPL_OFF_NULL; +} + +/* 返回用于存放该偏移的 handle 槽;找不到空闲/空间不足返回 0。 */ +static usize spl_vm_region_new(spl_vm_t *vm, void *base, usize size) { + usize i; + for (i = 2; i < vec_size(vm->regions); i++) { + spl_vm_region_t *r = &vec_at(vm->regions, i); + if (!r->used) { + r->base = (unsigned char *)base; + r->size = size; + r->used = 1; + return i; + } + } + if (vec_size(vm->regions) >= (usize)1 << 32) + return 0; + vec_push(vm->regions, ((spl_vm_region_t){(unsigned char *)base, size, 1})); + return vec_size(vm->regions) - 1; +} + +/* ---- spl_asp_t 实现 ---- */ + +static unsigned char *spl_vm_asp_xlate(void *ctx, uintptr_t off, uintptr_t size) { + return (unsigned char *)spl_vm_xlate((spl_vm_t *)ctx, (spl_vm_val_t)off, (usize)size); +} + +static uintptr_t spl_vm_asp_alloc(void *ctx, uintptr_t size) { + spl_vm_t *vm = (spl_vm_t *)ctx; + void *p; + usize h; + if (size == 0 || size > 0xFFFFFFFFull) + return 0; + p = malloc((size_t)size); + if (!p) + return 0; + h = spl_vm_region_new(vm, p, (usize)size); + if (h == 0) { + free(p); + return 0; + } + return (uintptr_t)SPL_ASP_OFF(h, 0); +} + +static uintptr_t spl_vm_asp_realloc(void *ctx, uintptr_t off, uintptr_t size) { + spl_vm_t *vm = (spl_vm_t *)ctx; + spl_vm_region_t *r; + void *np; + usize h; + if (size == 0 || size > 0xFFFFFFFFull) + return 0; + if (off == 0) + return spl_vm_asp_alloc(ctx, size); + h = SPL_ASP_HANDLE_OF(off); + r = spl_vm_region_at(vm, h); + if (!r || !r->used) + return 0; + np = realloc(r->base, (size_t)size); + if (!np) + return 0; + r->base = (unsigned char *)np; + r->size = (usize)size; + return (uintptr_t)SPL_ASP_OFF(h, SPL_ASP_BYTE_OF(off) & 0); +} + +static void spl_vm_asp_free(void *ctx, uintptr_t off) { + spl_vm_t *vm = (spl_vm_t *)ctx; + usize h; + spl_vm_region_t *r; + if (off == 0 || !vm) + return; + h = SPL_ASP_HANDLE_OF(off); + if (h < 2) /* 0/1 不可释放 */ + return; + r = spl_vm_region_at(vm, h); + if (!r || !r->used) + return; + free(r->base); + r->base = NULL; + r->size = 0; + r->used = 0; +} + +static uintptr_t spl_vm_asp_to_off(void *ctx, const void *host, uintptr_t size) { + (void)size; + return (uintptr_t)spl_vm_to_off((spl_vm_t *)ctx, host); +} + +spl_asp_t *spl_vm_asp(spl_vm_t *vm) { + if (!vm) + return NULL; + vm->asp.ctx = vm; + vm->asp.xlate = spl_vm_asp_xlate; + vm->asp.alloc = spl_vm_asp_alloc; + vm->asp.realloc = spl_vm_asp_realloc; + vm->asp.free = spl_vm_asp_free; + vm->asp.to_off = spl_vm_asp_to_off; + return &vm->asp; +} + +/* ================================================================ + * 动态外部回调 + 栈/结果/内存访问 + * ================================================================ */ + +void spl_vm_set_foreign(spl_vm_t *vm, spl_vm_foreign_fn fn, void *ctx) { + if (!vm) + return; + vm->foreign = fn; + vm->foreign_ctx = ctx; +} + +spl_vm_val_t spl_vm_ret_val(spl_vm_t *vm) { return vm ? vm->ret_val : 0; } + +usize spl_vm_sp(spl_vm_t *vm) { return vm ? (usize)vm->sp : 0; } + +usize spl_vm_fp(spl_vm_t *vm) { return vm ? (usize)vm->fp : 0; } + +spl_vm_val_t spl_vm_stack_get(spl_vm_t *vm, usize index) { + if (!vm || index >= (usize)vm->config.max_stack_depth || !vm->stacks.data) + return 0; + return vm->stacks.data[index]; +} + +int spl_vm_stack_set(spl_vm_t *vm, usize index, spl_vm_val_t val) { + if (!vm || index >= (usize)vm->config.max_stack_depth || !vm->stacks.data) + return -1; + vm->stacks.data[index] = val; + return 0; +} + +spl_vm_val_t spl_vm_mem_alloc(spl_vm_t *vm, usize size) { return spl_vm_asp_alloc(vm, size); } + +int spl_vm_mem_read(spl_vm_t *vm, spl_vm_val_t off, void *dst, usize n) { + void *src = spl_vm_xlate(vm, off, n); + if ((!src || !dst) && n) + return -1; + if (n) + memcpy(dst, src, n); + return 0; +} + +int spl_vm_mem_write(spl_vm_t *vm, spl_vm_val_t off, const void *src, usize n) { + void *dst = spl_vm_xlate(vm, off, n); + if ((!dst || !src) && n) + return -1; + if (n) + memcpy(dst, src, n); + return 0; +} + // FIXME int spl_vm_addr_valid(uintptr_t p, usize size) { if (p == 0) @@ -685,6 +894,35 @@ int spl_vm_load_prog(spl_vm_t *vm, spl_prog_t *prog) { if (!vm || !prog) return -1; vm->prog = prog; + + /* 释放上一次加载的堆分配(保留 regions[0]/[1])。 */ + for (usize i = 2; i < vec_size(vm->regions); i++) { + spl_vm_region_t *r = &vec_at(vm->regions, i); + if (r->used && r->base) + free(r->base); + r->base = NULL; + r->size = 0; + r->used = 0; + } + + /* 把 prog 的常量段搬进本 VM 空间,并记录每个 gdata 的偏移; + * gdata 索引 0 为哨兵,偏移 0(null)。 */ + vm->gdata_off.size = 0; + vec_push(vm->gdata_off, (usize)SPL_OFF_NULL); + for (usize i = 1; i < vec_size(prog->gdata); i++) { + spl_vm_gdata_t *gd = &vec_at(prog->gdata, i); + usize sz = gd->size ? gd->size : 1; + spl_vm_val_t off = spl_vm_asp_alloc(vm, sz); + unsigned char *dst; + if (off == SPL_OFF_NULL) + return -1; + dst = (unsigned char *)spl_vm_xlate(vm, off, sz); + if (!dst) + return -1; + if (gd->data && gd->size) + memcpy(dst, gd->data, gd->size); + vec_push(vm->gdata_off, (usize)off); + } return 0; } @@ -707,21 +945,53 @@ void spl_vm_set_debug(spl_vm_t *vm, int enabled) { #define STACK_CANARY(vm) (vm)->stacks.data[(vm)->fp - 1] +/* 把 C 字符串复制进 VM 空间,返回其偏移。 */ +static spl_vm_val_t spl_vm_marshal_cstr(spl_vm_t *vm, const char *s) { + usize n = s ? strlen(s) + 1 : 1; + spl_vm_val_t off = spl_vm_asp_alloc(vm, n); + unsigned char *d; + if (off == 0) + return 0; + d = (unsigned char *)spl_vm_xlate(vm, off, n); + if (!d) + return 0; + if (s) + memcpy(d, s, n); + else + d[0] = 0; + return off; +} + +/* 把 argv/envp 指针数组整体编组进 VM 空间,返回数组偏移。 */ +static spl_vm_val_t spl_vm_marshal_argv(spl_vm_t *vm, int argc, const char **argv) { + usize bytes = (usize)(argc + 1) * sizeof(spl_vm_val_t); + spl_vm_val_t arr = spl_vm_asp_alloc(vm, bytes); + spl_vm_val_t *slots; + int i; + if (arr == 0) + return 0; + slots = (spl_vm_val_t *)spl_vm_xlate(vm, arr, bytes); + if (!slots) + return 0; + for (i = 0; i < argc; i++) + slots[i] = spl_vm_marshal_cstr(vm, argv ? argv[i] : NULL); + slots[argc] = 0; + return arr; +} + +/* ABI:调用者在实参下方预留 2 个空闲 slot(PAD0/PAD1)。 + * fp 指向 arg0;fp-1 为栈金丝雀槽,fp-2 为空闲槽。 + * saved_sp = fp-2(调用者压参数前的 sp)。 */ +#define SPL_CALL_PADS 2 + static inline int spl_vm_call(spl_vm_t *vm, spl_vm_val_t addr, spl_vm_val_t nargs) { + uintptr_t saved_sp; if (vm->cp >= vm->config.max_call_depth) VM_ERROR("call depth exceeded"); + if (vm->sp < nargs + SPL_CALL_PADS) + VM_ERROR("call: stack underflow (missing pads)"); - 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; - } + saved_sp = vm->sp - nargs - SPL_CALL_PADS; spl_callframe_t *fr = &vm->frames.data[vm->cp]; fr->saved_sp = saved_sp; @@ -736,6 +1006,33 @@ static inline int spl_vm_call(spl_vm_t *vm, spl_vm_val_t addr, spl_vm_val_t narg return 0; } +/* 入口调用:按名字调用顶层函数(同 CALL 的 ABI,实参+2 pads 已由调用方压好)。 */ +int spl_vm_call_entry(spl_vm_t *vm, const char *name, int nargs) { + spl_vm_func_t *func; + if (!vm || !vm->prog || !name) + return -1; + func = spl_prog_get_func(vm->prog, name); + if (!func) + return -1; + if (vm->cp >= vm->config.max_call_depth) + return -1; + if (vm->sp < (usize)nargs + SPL_CALL_PADS) + return -1; + vm->ip = (usize)-1; + vm->cp = 0; + vm->fp = 0; + vm->frames.data[0].saved_sp = vm->sp - (usize)nargs - SPL_CALL_PADS; + vm->frames.data[0].saved_fp = vm->fp; + vm->frames.data[0].saved_ip = vm->ip; + vm->frames.data[0].nargs = (spl_vm_val_t)nargs; + vm->cp = 1; + vm->ip = (usize)func->address; + vm->fp = vm->sp - (usize)nargs; + if (vm->debug && vm->fp > 0) + STACK_CANARY(vm) = SPL_STACK_CANARY; + return 0; +} + int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv, const char **envp) { if (!vm || !vm->prog) { @@ -757,15 +1054,22 @@ int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv, vm->cp = 0; vm->ip = -1; vm->exit_code = 0; + vm->ret_val = 0; + /* ABI:入口也在实参下方预留 2 个空闲 slot。 */ + PUSH(0); + PUSH(0); if (fn->nargs >= 1) { PUSH(argc); } if (fn->nargs >= 2) { - PUSH(argv); + PUSH(spl_vm_marshal_argv(vm, argc, argv)); } if (fn->nargs >= 3) { - PUSH(envp); + int envc = 0; + while (envp && envp[envc]) + envc++; + PUSH(spl_vm_marshal_argv(vm, envc, envp)); } if (fn->nargs >= 4) { printf("the start symbol can't using more than 3 args"); @@ -777,6 +1081,53 @@ int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv, return 0; } +/* 外部 -> VM 的调用:保存外层状态,按当前深度建帧跑到边界,读结果后恢复。 + * 可在 VM 运行中(如外部回调内)安全调用。 */ +int spl_vm_invoke(spl_vm_t *vm, spl_vm_call_t *call) { + spl_vm_func_t *fn; + uintptr_t s_ip, s_fp, s_sp, s_cp; + int s_exit, i, r; + spl_vm_val_t s_ret; + if (!vm || !vm->prog || !call || !call->name) + return -1; + fn = spl_prog_get_func(vm->prog, call->name); + if (!fn) + return -1; + + s_ip = vm->ip; + s_fp = vm->fp; + s_sp = vm->sp; + s_cp = vm->cp; + s_exit = vm->exit_code; + s_ret = vm->ret_val; + + PUSH(0); + PUSH(0); + for (i = 0; i < (int)call->nargs; i++) + PUSH(call->args ? call->args[i] : 0); + /* sentinel:本次调用的 RET 视为边界(与入口调用一致)。 */ + vm->ip = (spl_vm_val_t)-1; + if (spl_vm_call(vm, fn->address, (spl_vm_val_t)call->nargs) != 0) { + vm->ip = s_ip; + vm->fp = s_fp; + vm->sp = s_sp; + vm->cp = s_cp; + vm->exit_code = s_exit; + vm->ret_val = s_ret; + return -1; + } + r = spl_vm_run_until(vm, 0); + call->ret = vm->ret_val; + + vm->ip = s_ip; + vm->fp = s_fp; + vm->sp = s_sp; + vm->cp = s_cp; + vm->exit_code = s_exit; + vm->ret_val = s_ret; + return r < 0 ? -1 : 0; +} + /* ================================================================ * spl_vm_run_once - execute one instruction * @@ -817,7 +1168,7 @@ static uint64_t prof_now_ns(void) { } static void spl_vm_sample(spl_vm_t *vm) { - spl_prof_t *p = (spl_prof_t *)vm->profile; + spl_prof_t *p = vm->profile; spl_prog_t *prog = vm->prog; if (!p || !prog) return; @@ -862,7 +1213,7 @@ static void spl_vm_sample(spl_vm_t *vm) { usize old = 0; if (map_get(p->stacks, buf, &old)) { - map_put(p->stacks, buf, old + 1); + map_put(p->stacks, strdup(buf), old + 1); } else { map_put(p->stacks, strdup(buf), (usize)1); } @@ -1250,6 +1601,8 @@ L_SPL_RET: intptr_t _saved_ip = vm->frames.data[vm->cp].saved_ip; /* entry return -> halt */ if (_saved_ip < 0) { + PUSH(_retval); + vm->ret_val = _retval; vm->exit_code = (int)_retval; return 1; } @@ -1263,6 +1616,7 @@ L_SPL_RET: } L_SPL_HALT: + vm->ret_val = ins->imm; if (ins->imm) vm->exit_code = (int)ins->imm; return 1; @@ -1281,7 +1635,8 @@ L_SPL_ALLOC: } L_SPL_LADDR: - PUSH((spl_vm_val_t)((char *)(vm->stacks.data + vm->fp) + ins->imm)); + PUSH(SPL_ASP_OFF(SPL_ASP_HANDLE_STACK, + (spl_vm_val_t)vm->fp * sizeof(spl_vm_val_t) + ins->imm)); DISPATCH(); L_SPL_GADDR: @@ -1289,20 +1644,22 @@ 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"); - spl_vm_gdata_t *gd = &vec_at(prog->gdata, _idx); - if (!gd->data) - VM_ERROR("GADDR: null gdata entry"); - PUSH((spl_vm_val_t)(uintptr_t)gd->data); + if (_idx >= vec_size(vm->gdata_off)) + VM_ERROR("GADDR: global data not mapped"); + PUSH((spl_vm_val_t)vec_at(vm->gdata_off, _idx)); DISPATCH(); } /* ========== Indirect Memory (load/store with types) ========== */ L_SPL_LOAD: { - void *_addr = (void *)POP(); - CHECK_ADDR(_addr, "LOAD"); + spl_vm_val_t _off = POP(); + void *_addr; spl_vm_val_t _v = 0; usize _sz = spl_type_size(ins->type); + _addr = spl_vm_xlate(vm, _off, _sz); + if (!_addr) + VM_ERROR("LOAD: invalid address"); memcpy(&_v, _addr, _sz); /* Sign-extend signed integer types smaller than 64 bits */ if (_sz > 0 && _sz < sizeof(spl_vm_val_t) && spl_is_signed(ins->type)) { @@ -1315,8 +1672,13 @@ L_SPL_LOAD: L_SPL_STORE: { spl_vm_val_t _v = POP(); - void *_addr = (void *)POP(); - CHECK_ADDR(_addr, "STORE"); + spl_vm_val_t _off = POP(); + void *_addr = spl_vm_xlate(vm, _off, spl_type_size(ins->type)); + if (!_addr) { + fprintf(stderr, "vm: STORE bad off=%zu sz=%d\n", (size_t)_off, (int)spl_type_size(ins->type)); + spl_vm_backtrace(vm, vm->fp); + VM_ERROR("STORE: invalid address"); + } memcpy(_addr, &_v, spl_type_size(ins->type)); DISPATCH(); } @@ -1374,13 +1736,23 @@ L_SPL_NCALL: if (_nat_idx >= vec_size(prog->natives)) VM_ERROR("NCALL: native index out of range"); _nat = &vec_at(prog->natives, _nat_idx); - if (!_nat->impl_fn) { + spl_vm_val_t *_arg_base = vm->stacks.data + vm->sp - _nargs; + spl_vm_val_t _result; + if (_nat->impl_fn) { + _result = _nat->impl_fn(vm, _nargs, _arg_base); + } else if (vm->foreign) { + /* 线 1 动态:交给按名的外部函数处理器。 */ + spl_vm_call_t _call; + _call.name = _nat->name ? _nat->name : ""; + _call.args = _arg_base; + _call.nargs = (usize)_nargs; + _call.ret = 0; + _result = vm->foreign(vm, &_call, vm->foreign_ctx); + } else { snprintf(vm->error_msg, sizeof(vm->error_msg), "NCALL: NULL native function pointer expect %s", _nat->name); VM_ERROR(vm->error_msg); } - spl_vm_val_t *_arg_base = vm->stacks.data + vm->sp - _nargs; - spl_vm_val_t _result = _nat->impl_fn(vm, _nargs, _arg_base); if (vm->exit_code) { snprintf(vm->error_msg, sizeof(vm->error_msg), "NCALL %s failed (ip=%zd)", _nat->name ? _nat->name : "?", vm->ip - 1); @@ -1442,7 +1814,11 @@ L_default: return -1; } -int spl_vm_run_once(spl_vm_t *vm) { return vm_loop(vm, 1); } +int spl_vm_run_once(spl_vm_t *vm) { + if (!vm) + return -1; + return vm_loop(vm, 1); +} int spl_vm_run_until(spl_vm_t *vm, size_t step) { if (!vm) diff --git a/stage0/spl_vm.h b/stage0/spl_vm.h index a4b3cbe..eeab3a8 100644 --- a/stage0/spl_vm.h +++ b/stage0/spl_vm.h @@ -5,11 +5,25 @@ #include "include/core_map.h" #include "include/core_vec.h" +#include "spl_asp.h" #include "spl_mcode.h" #include #define SPL_STACK_CANARY ((spl_vm_val_t)0xDEADBEEFCAFEBABEull) +/* 统一偏移地址空间:SPL 侧指针一律是句柄/偏移,0 保留为 null。 + * offset = (handle<<32) | 区内字节偏移;handle 1 = 栈,handle>=2 = 堆分配。 */ +#define SPL_OFF_NULL ((spl_vm_val_t)0) +#define SPL_ASP_HANDLE_STACK ((spl_vm_val_t)1) +#define SPL_ASP_OFF(handle, byte) ((((spl_vm_val_t)(handle)) << 32) | (spl_vm_val_t)(byte)) + +typedef struct { + unsigned char *base; + usize size; + int used; +} spl_vm_region_t; +typedef VEC(spl_vm_region_t) spl_vm_region_vec_t; + typedef struct { uintptr_t saved_sp; uintptr_t saved_fp; @@ -20,6 +34,18 @@ typedef struct { typedef VEC(spl_vm_val_t) spl_stack_vec_t; typedef VEC(spl_callframe_t) spl_frame_vec_t; +/* 一次调用描述(VM <-> 外部两侧统一形状)。 */ +typedef struct { + const char *name; + const spl_vm_val_t *args; + usize nargs; + spl_vm_val_t ret; +} spl_vm_call_t; + +/* 线 1 动态形态:VM 调“外部(非 VM)函数”的按名处理器。 + * 当 NCALL 的 native 无 impl_fn 时调用;返回被调函数的返回值。 */ +typedef spl_vm_val_t (*spl_vm_foreign_fn)(spl_vm_t *vm, const spl_vm_call_t *call, void *ctx); + typedef struct { MAP(const char *, usize) stacks; VEC(usize) self_samples; @@ -32,11 +58,11 @@ typedef struct { typedef struct spl_vm { spl_stack_vec_t stacks; spl_frame_vec_t frames; - uintptr_t gp; // global pointer - uintptr_t sp; // stack pointer - uintptr_t fp; // frame pointer - uintptr_t cp; // call pointer - uintptr_t ip; // instr pointer + uintptr_t gp; // global pointer + uintptr_t sp; // stack pointer + uintptr_t fp; // frame pointer + uintptr_t cp; // call pointer + uintptr_t ip; // instr pointer uint64_t steps; // 已执行指令数(供性能分析参考) uint64_t ncalls; // 已执行 CALL/CALLI 次数(供性能分析参考) int exit_code; @@ -49,6 +75,14 @@ typedef struct spl_vm { VEC(usize) breakpoints; /* ip 断点(执行到该指令前暂停,run_once 返回 2) */ VEC(char *) fn_breakpoints; /* 函数名断点(CALL/CALLI 目标函数入口暂停) */ spl_prog_t *prog; + /* 统一偏移地址空间:regions[1]=栈,regions[i>=2]=堆分配。 */ + spl_vm_region_vec_t regions; + VEC(usize) gdata_off; /* prog->gdata[i] 在本 VM 空间内的偏移 */ + spl_asp_t asp; /* 本 VM 的地址空间描述符(按值持有,避免共享静态) */ + spl_vm_val_t stdio_off[3]; /* stdin/stdout/stderr 的 VM 句柄(懒建) */ + spl_vm_val_t ret_val; /* 最近一次完成的调用返回值(64 位) */ + spl_vm_foreign_fn foreign; /* 线 1 动态处理器(可为 NULL) */ + void *foreign_ctx; char error_msg[1024]; struct { uintptr_t max_stack_depth; @@ -68,6 +102,35 @@ void spl_vm_drop(spl_vm_t *vm); int spl_vm_addr_valid(uintptr_t p, usize size); +/* 偏移地址空间:偏移 -> 宿主地址;越界/ null 返回 NULL。 */ +void *spl_vm_xlate(spl_vm_t *vm, spl_vm_val_t off, usize size); +/* 宿主地址 -> 偏移;不属于本 VM 地址空间返回 0。 */ +spl_vm_val_t spl_vm_to_off(spl_vm_t *vm, const void *ptr); +/* 本 VM 的地址空间描述符(供 runtime 解引用)。 */ +spl_asp_t *spl_vm_asp(spl_vm_t *vm); + +/* ---- 线 1:VM -> 外部函数 ---- */ +/* 安装“外部函数”按名处理器(NCALL 的 native 无 impl_fn 时使用)。 */ +void spl_vm_set_foreign(spl_vm_t *vm, spl_vm_foreign_fn fn, void *ctx); + +/* ---- 线 2:外部 -> VM 函数 ---- */ +/* 按 call->name 调用 VM 内函数(call->args/nargs 为实参),结果写入 call->ret。 + * 可在 VM 运行中重入调用。返回 0 成功,-1 失败。 */ +int spl_vm_invoke(spl_vm_t *vm, spl_vm_call_t *call); + +/* 入口调用:调用方先按 ABI 压 2 个 pad 再压实参。 */ +int spl_vm_call_entry(spl_vm_t *vm, const char *name, int nargs); + +/* ---- 栈 / 结果 / 内存 访问(不暴露宿主指针) ---- */ +spl_vm_val_t spl_vm_ret_val(spl_vm_t *vm); +usize spl_vm_sp(spl_vm_t *vm); +usize spl_vm_fp(spl_vm_t *vm); +spl_vm_val_t spl_vm_stack_get(spl_vm_t *vm, usize index); +int spl_vm_stack_set(spl_vm_t *vm, usize index, spl_vm_val_t val); +spl_vm_val_t spl_vm_mem_alloc(spl_vm_t *vm, usize size); +int spl_vm_mem_read(spl_vm_t *vm, spl_vm_val_t off, void *dst, usize n); +int spl_vm_mem_write(spl_vm_t *vm, spl_vm_val_t off, const void *src, usize n); + int spl_vm_load_prog(spl_vm_t *vm, spl_prog_t *prog); int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv, const char **envp); diff --git a/stage2/sys/spl_vm_embed.h b/stage0/spl_vm_embed.h similarity index 56% rename from stage2/sys/spl_vm_embed.h rename to stage0/spl_vm_embed.h index d026fdf..3054ca1 100644 --- a/stage2/sys/spl_vm_embed.h +++ b/stage0/spl_vm_embed.h @@ -1,7 +1,7 @@ -/* spl_vm_embed.h - 原生编译器内嵌 VM(comptime 执行)。 +/* spl_vm_embed.h - 裸机内嵌 VM(装载/运行,不含任何内置 native/syscall)。 * * 单 TU 合并式:定义 SPL_VM_EMBED_IMPLIMENTATION 后 include 本头,会把 stage0 的 - * spl_mcode.c / spl_syscall.c / spl_vm.c 一并纳入当前翻译单元(不单独编译/链接)。 + * spl_mcode.c / spl_vm.c 一并纳入当前翻译单元(不单独编译/链接)。 */ #ifndef __SPL_VM_EMBED_H__ @@ -13,14 +13,17 @@ int vm_load_from_buffer(void *vm, const void *buf, unsigned long long len); void vm_push(void *vm, unsigned long long val); int vm_call(void *vm, const char *name, unsigned long long nargs); int vm_run(void *vm); +unsigned long long vm_ret_val(void *vm); +unsigned long long vm_mem_alloc(void *vm, unsigned long long size); +int vm_mem_read(void *vm, unsigned long long off, void *dst, unsigned long long n); +int vm_mem_write(void *vm, unsigned long long off, const void *src, unsigned long long n); #ifdef SPL_VM_EMBED_IMPLIMENTATION -#include "../../stage0/spl_mcode.h" -void spl_syscall_register(spl_prog_t *prog) { (void)prog; /* stub */ } - -#include "../../stage0/spl_mcode.c" -#include "../../stage0/spl_vm.c" +/* 裸机内嵌 VM:只提供装载/运行 VM 的能力,不内置任何 native/syscall。 + * 外部函数解析与注册属于配置端(调用方自行处理)。 */ +#include "spl_mcode.c" +#include "spl_vm.c" void *vm_new(void) { spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t)); @@ -55,7 +58,6 @@ int vm_load_from_buffer(void *p, const void *buf, unsigned long long len) { free(prog); return -1; } - spl_syscall_register(prog); if (spl_vm_load_prog(vm, prog) != 0) { spl_prog_drop(prog); free(prog); @@ -75,26 +77,10 @@ void vm_push(void *p, unsigned long long val) { int vm_call(void *p, const char *name, unsigned long long nargs) { spl_vm_t *vm = (spl_vm_t *)p; - spl_vm_func_t *func; if (!vm || !name) return -1; - func = spl_prog_get_func(vm->prog, name); - if (!func) - return -1; - if (vm->cp >= vm->config.max_call_depth) - return -1; - /* 入口调用:ip=-1 作 sentinel;实参由 vm_push 压栈。 */ - vm->ip = (usize)-1; - vm->cp = 0; - vm->fp = 0; - vm->frames.data[0].saved_sp = vm->sp - (usize)nargs; - vm->frames.data[0].saved_fp = vm->fp; - vm->frames.data[0].saved_ip = vm->ip; - vm->frames.data[0].nargs = (spl_vm_val_t)nargs; - vm->cp = 1; - vm->ip = (usize)func->address; - vm->fp = vm->sp - (usize)nargs; - return 0; + /* 入口调用:调用方需先按 ABI 压 2 个 pad 再压实参。 */ + return spl_vm_call_entry(vm, name, (int)nargs); } int vm_run(void *p) { @@ -104,6 +90,27 @@ int vm_run(void *p) { spl_vm_run_until(vm, 0); return (int)vm->exit_code; } + +unsigned long long vm_ret_val(void *p) { + spl_vm_t *vm = (spl_vm_t *)p; + return vm ? (unsigned long long)vm->ret_val : 0; +} + +unsigned long long vm_mem_alloc(void *p, unsigned long long size) { + spl_vm_t *vm = (spl_vm_t *)p; + return (unsigned long long)spl_vm_mem_alloc(vm, (usize)size); +} + +int vm_mem_read(void *p, unsigned long long off, void *dst, unsigned long long n) { + spl_vm_t *vm = (spl_vm_t *)p; + return spl_vm_mem_read(vm, (spl_vm_val_t)off, dst, (usize)n); +} + +int vm_mem_write(void *p, unsigned long long off, const void *src, unsigned long long n) { + spl_vm_t *vm = (spl_vm_t *)p; + return spl_vm_mem_write(vm, (spl_vm_val_t)off, src, (usize)n); +} + #endif /* SPL_VM_EMBED_IMPLIMENTATION */ #endif /* __SPL_VM_EMBED_H__ */ diff --git a/stage0/test_spl_vm.c b/stage0/test_spl_vm.c index b70f8bb..c0231be 100644 --- a/stage0/test_spl_vm.c +++ b/stage0/test_spl_vm.c @@ -6,6 +6,7 @@ #include "include/acutest.h" #include "spl_mcode.h" +#include "spl_syscall.h" #include "spl_vm.h" #include @@ -159,7 +160,8 @@ static int run_with_natives(const spl_vm_ins_t *instns, int ninsns, spl_vm_nativ * Native function for NCALL tests * ================================================================ */ -static spl_vm_val_t native_add_impl(int nargs, spl_vm_val_t *args) { +static spl_vm_val_t native_add_impl(spl_vm_t *vm, int nargs, spl_vm_val_t *args) { + (void)vm; return (nargs >= 2) ? args[0] + args[1] : 0; } @@ -479,7 +481,8 @@ void test_call_add(void) { spl_vm_ins_t add_insns[] = {ins(SPL_LADDR, SPL_VOID, 0), ins(SPL_LOAD, SPL_I64, 0), ins(SPL_LADDR, SPL_VOID, 8), ins(SPL_LOAD, SPL_I64, 0), ins(SPL_ADD, SPL_I64, 0), ins(SPL_RET, SPL_I64, 0)}; - spl_vm_ins_t main_insns[] = {ins(SPL_PUSH, SPL_I32, 10), ins(SPL_PUSH, SPL_I32, 20), + spl_vm_ins_t main_insns[] = {ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_PUSH, SPL_VOID, 0), + ins(SPL_PUSH, SPL_I32, 10), ins(SPL_PUSH, SPL_I32, 20), ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_CALL, SPL_VOID, 2), ins(SPL_RET, SPL_I64, 0)}; @@ -586,11 +589,12 @@ void test_calli(void) { spl_vm_ins_t add_insns[] = {ins(SPL_LADDR, SPL_VOID, 0), ins(SPL_LOAD, SPL_I64, 0), ins(SPL_LADDR, SPL_VOID, 8), ins(SPL_LOAD, SPL_I64, 0), ins(SPL_ADD, SPL_I64, 0), ins(SPL_RET, SPL_I64, 0)}; - spl_vm_ins_t main_insns[] = {ins(SPL_PUSH, SPL_I32, 10), ins(SPL_PUSH, SPL_I32, 20), + spl_vm_ins_t main_insns[] = {ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_PUSH, SPL_VOID, 0), + ins(SPL_PUSH, SPL_I32, 10), ins(SPL_PUSH, SPL_I32, 20), ins(SPL_PUSH, SPL_VOID, 2), ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_CALLI, SPL_VOID, 0), ins(SPL_RET, SPL_I64, 0)}; - int ninsns_t = 6 + 6; + int ninsns_t = 6 + 8; size_t nlen0 = strlen("add") + 1; size_t npad0 = ((nlen0 + 7) / 8) * 8 - nlen0; size_t nlen1 = strlen("main") + 1; @@ -627,7 +631,7 @@ void test_calli(void) { p += npad1; LE64(p, 0); LE64(p, 0); - LE64(p, 6); + LE64(p, 8); LE64(p, 6); for (int i = 0; i < 6; i++) { @@ -637,7 +641,7 @@ void test_calli(void) { *p++ = (unsigned char)(add_insns[i].type >> 8); LE64(p, add_insns[i].imm); } - for (int i = 0; i < 6; i++) { + for (int i = 0; i < 8; i++) { *p++ = (unsigned char)(main_insns[i].opcode); *p++ = (unsigned char)(main_insns[i].opcode >> 8); *p++ = (unsigned char)(main_insns[i].type); @@ -669,8 +673,9 @@ void test_calli(void) { * ================================================================ */ void test_gaddr_ld32(void) { - /* Load program, add global data, GADDR + LD32 to read it back */ - spl_vm_ins_t p[] = {ins(SPL_GADDR, SPL_VOID, 0), ins(SPL_LOAD, SPL_U32, 0), + /* Load program, add global data, GADDR + LD32 to read it back. + * gdata 索引 0 为哨兵;首次 add_data 得到索引 1。 */ + spl_vm_ins_t p[] = {ins(SPL_GADDR, SPL_VOID, 1), ins(SPL_LOAD, SPL_U32, 0), ins(SPL_RET, SPL_U32, 0)}; size_t len; unsigned char *bin = build_binary("main", 0, p, 3, &len); @@ -697,8 +702,8 @@ void test_gaddr_ld32(void) { } void test_gaddr_multi(void) { - /* Two global data entries: read second one via GADDR 1 */ - spl_vm_ins_t p[] = {ins(SPL_GADDR, SPL_VOID, 1), ins(SPL_LOAD, SPL_U32, 0), + /* Two global data entries: read second one via GADDR 2 (0 为哨兵) */ + spl_vm_ins_t p[] = {ins(SPL_GADDR, SPL_VOID, 2), ins(SPL_LOAD, SPL_U32, 0), ins(SPL_RET, SPL_U32, 0)}; size_t len; unsigned char *bin = build_binary("main", 0, p, 3, &len); @@ -818,6 +823,127 @@ void test_empty(void) { TEST_CHECK(spl_prog_load_from_file("nonexistent_file_xyz.bin", NULL) != 0); } +/* ================================================================ + * 动态回调 / 重入 / 栈访问 API + * ================================================================ */ + +static spl_vm_val_t foreign_add_cb(spl_vm_t *vm, const spl_vm_call_t *call, void *ctx) { + (void)vm; + (void)ctx; + if (!call || call->nargs < 2) + return 0; + return call->args[0] + call->args[1]; +} + +/* 线 1 动态:NCALL 的 native 无 impl_fn 时走 vm->foreign。 */ +void test_foreign_fallback(void) { + spl_vm_ins_t p[] = {ins(SPL_PUSH, SPL_I32, 30), ins(SPL_PUSH, SPL_I32, 12), + ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_NCALL, SPL_I32, 2), + ins(SPL_RET, SPL_I32, 0)}; + size_t len; + unsigned char *bin = build_binary("main", 0, p, 5, &len); + spl_prog_t prog; + spl_vm_t vm; + spl_vm_native_t nat[] = {{"host_add", 0, NULL}}; + int rc = -1; + + spl_vm_init(&vm); + if (write_temp(bin, len) == 0 && spl_prog_load_from_file(TMPFILE, &prog) == 0) { + for (int i = 0; i < 1; i++) + spl_prog_add_native(&prog, &nat[i]); + if (spl_vm_load_prog(&vm, &prog) == 0) { + spl_vm_set_foreign(&vm, foreign_add_cb, NULL); + if (spl_vm_prepare(&vm, "main", 0, NULL, NULL) == 0) { + int ret = spl_vm_run_until(&vm, 0); + if (ret == 1) + rc = (int)vm.ret_val; + } + } + } + spl_vm_drop(&vm); + remove(TMPFILE); + free(bin); + TEST_CHECK(rc == 42); +} + +/* 线 2:外部 -> VM 调用。 */ +void test_invoke(void) { + spl_vm_ins_t add_insns[] = {ins(SPL_LADDR, SPL_VOID, 0), ins(SPL_LOAD, SPL_I64, 0), + ins(SPL_LADDR, SPL_VOID, 8), ins(SPL_LOAD, SPL_I64, 0), + ins(SPL_ADD, SPL_I64, 0), ins(SPL_RET, SPL_I64, 0)}; + size_t len; + unsigned char *bin = build_binary("add", 2, add_insns, 6, &len); + spl_prog_t prog; + spl_vm_t vm; + spl_vm_val_t args[2]; + spl_vm_call_t call; + int ok = 0; + + spl_vm_init(&vm); + if (write_temp(bin, len) == 0 && spl_prog_load_from_file(TMPFILE, &prog) == 0) { + if (spl_vm_load_prog(&vm, &prog) == 0) { + args[0] = 40; + args[1] = 2; + call.name = "add"; + call.args = args; + call.nargs = 2; + call.ret = 0; + ok = (spl_vm_invoke(&vm, &call) == 0) && (call.ret == 42); + } + } + spl_vm_drop(&vm); + remove(TMPFILE); + free(bin); + TEST_CHECK(ok); +} + +/* 栈 / 结果访问 API 不依赖宿主指针。 */ +void test_stack_api(void) { + spl_vm_t vm; + spl_vm_init(&vm); + TEST_CHECK(spl_vm_stack_set(&vm, 0, 123) == 0); + TEST_CHECK(spl_vm_stack_get(&vm, 0) == 123); + TEST_CHECK(spl_vm_sp(&vm) == 0); + TEST_CHECK(spl_vm_fp(&vm) == 0); + TEST_CHECK(spl_vm_stack_get(&vm, (usize)-1) == 0); + spl_vm_drop(&vm); +} + +/* syscall 注册 + 内存 API:NCALL vm_alloc 得到 VM 偏移,并经 mem_read/write 往返。 */ +void test_syscall_registration(void) { + spl_vm_ins_t p[] = {ins(SPL_PUSH, SPL_I64, 16), ins(SPL_PUSH, SPL_VOID, 0), + ins(SPL_NCALL, SPL_I64, 1), ins(SPL_RET, SPL_I64, 0)}; + size_t len; + unsigned char *bin = build_binary("main", 0, p, 4, &len); + spl_prog_t prog; + spl_vm_t vm; + spl_vm_native_t nat[] = {{"vm_alloc", 0, NULL}}; + spl_vm_val_t off = 0; + int ok = 0; + char w[4] = {1, 2, 3, 0}; + char r[4] = {0}; + + spl_vm_init(&vm); + if (write_temp(bin, len) == 0 && spl_prog_load_from_file(TMPFILE, &prog) == 0) { + for (int i = 0; i < 1; i++) + spl_prog_add_native(&prog, &nat[i]); + spl_syscall_register(&prog); + if (spl_vm_load_prog(&vm, &prog) == 0 && spl_vm_prepare(&vm, "main", 0, NULL, NULL) == 0) { + if (spl_vm_run_until(&vm, 0) == 1) { + off = vm.ret_val; + if (off != 0 && spl_vm_mem_write(&vm, off, w, 4) == 0 && + spl_vm_mem_read(&vm, off, r, 4) == 0 && memcmp(w, r, 4) == 0) + ok = 1; + } + } + } + spl_vm_drop(&vm); + remove(TMPFILE); + free(bin); + TEST_CHECK(off != 0); + TEST_CHECK(ok); +} + /* ================================================================ * Test list * ================================================================ */ @@ -872,6 +998,10 @@ TEST_LIST = { {"ld_st64", test_ld_st64}, {"many_ops", test_many_ops}, {"halt", test_halt}, + {"foreign_fallback", test_foreign_fallback}, + {"invoke", test_invoke}, + {"stack_api", test_stack_api}, + {"syscall_registration", test_syscall_registration}, {"bad_magic", test_bad_magic}, {"empty", test_empty}, {NULL, NULL}, diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index ec4d4c4..05084c0 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -1086,6 +1086,10 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { usize sret_off = 0; usize j = 0; + /* ABI:实参下方预留 2 个空闲 slot(PAD0/PAD1)。 */ + CG_PUSH(cg, SPL_U64, 0); + CG_PUSH(cg, SPL_U64, 0); + if (ret_is_sret) { sret_off = vec_at(cg->frame.slots, ref).data_off; CG_LADDR(cg, sret_off); diff --git a/stage2/ir2vm.spl b/stage2/ir2vm.spl index baae87b..992e675 100644 --- a/stage2/ir2vm.spl +++ b/stage2/ir2vm.spl @@ -952,6 +952,9 @@ fn cg_control(cg: *Cgen, ref: usize, n: *IrEntry) { cg_store_slot(cg, ref, rk); } } else { + /* ABI:实参下方预留 2 个空闲 slot(PAD0/PAD1)。 */ + cg_push(cg, .U64, 0); + cg_push(cg, .U64, 0); var ret_t = cl.tid; var ret_is_sret = ir_is_aggregate(ctx, ret_t); var sret_off: usize = 0; @@ -1327,6 +1330,15 @@ fn dump(ctx: *Ir2Vm, out: *ByteBuffer): bool { ret Mcode.dump(&ctx.prog, out); } +// 序列化到内存 ByteBuffer(不落盘),供内嵌 VM 直接加载。 +fn encode(ctx: *Ir2Vm, out: *ByteBuffer): bool { + match Mcode.encode(&ctx.prog, out) { + .Ok => { ret true; }, + .Err(error) => { ret false; }, + } + ret false; +} + // 把翻译结果写成 .sir(二进制)。 fn store(ctx: *Ir2Vm, path: ByteView): bool { match Mcode.store(&ctx.prog, path) { diff --git a/stage2/mcode.spl b/stage2/mcode.spl index 5621a69..372ae8e 100644 --- a/stage2/mcode.spl +++ b/stage2/mcode.spl @@ -545,10 +545,8 @@ fn put_name_field(out: *ByteBuffer, name: ByteView): bool { ret put_zeros(out, align8(nlen) - nlen); } -fn store(self: *Prog, path: ByteView): Status { - var out = ByteBuffer.new(); - defer { ByteBuffer.drop(&out); } - +// 把 prog 序列化为二进制写入 out(不落盘,供内嵌 VM 直接用)。 +fn encode(self: *Prog, out: *ByteBuffer): Status { // 精确预估输出大小并一次性预留,避免大文件逐字节增长导致的重复拷贝。 var total: usize = 48; var fi: usize = 0; @@ -581,11 +579,11 @@ fn store(self: *Prog, path: ByteView): Status { if e != null { total = total + 8 + align8(e.storage.len); } fi = fi + 1; } - match ByteBuffer.reserve(&out, total) { .Ok => {}, .Err(error) => {} } + 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)); } + if !put_view(out, ByteView.from_slice("SPLBIN")) { ret .Err(make(.Io)); } + if !put_zeros(out, 2) { ret .Err(make(.Io)); } var nfuncs = self.funcs.len; var ninsns = self.insns.len; @@ -594,21 +592,21 @@ fn store(self: *Prog, path: ByteView): Status { var ndata: usize = 0; if self.gdata.len > 0 { ndata = self.gdata.len - 1; } - if !put_u64(&out, nfuncs) { ret .Err(make(.Io)); } - if !put_u64(&out, ninsns) { ret .Err(make(.Io)); } - if !put_u64(&out, nnatives) { ret .Err(make(.Io)); } - if !put_u64(&out, nstrs) { ret .Err(make(.Io)); } - if !put_u64(&out, ndata) { ret .Err(make(.Io)); } + if !put_u64(out, nfuncs) { ret .Err(make(.Io)); } + if !put_u64(out, ninsns) { ret .Err(make(.Io)); } + if !put_u64(out, nnatives) { ret .Err(make(.Io)); } + if !put_u64(out, nstrs) { ret .Err(make(.Io)); } + if !put_u64(out, ndata) { ret .Err(make(.Io)); } var i: usize = 0; while i < nfuncs { var f = func_at(self, i); if f == null { ret .Err(make(.Io)); } - if !put_name_field(&out, f.name) { ret .Err(make(.Io)); } - if !put_u64(&out, f.idx_of_strtab) { ret .Err(make(.Io)); } - if !put_u64(&out, f.nargs) { ret .Err(make(.Io)); } - if !put_u64(&out, f.ninsns) { ret .Err(make(.Io)); } - if !put_u64(&out, f.address) { ret .Err(make(.Io)); } + if !put_name_field(out, f.name) { ret .Err(make(.Io)); } + if !put_u64(out, f.idx_of_strtab) { ret .Err(make(.Io)); } + if !put_u64(out, f.nargs) { ret .Err(make(.Io)); } + if !put_u64(out, f.ninsns) { ret .Err(make(.Io)); } + if !put_u64(out, f.address) { ret .Err(make(.Io)); } i = i + 1; } @@ -627,17 +625,17 @@ fn store(self: *Prog, path: ByteView): Status { while i < nnatives { var n = native_at(self, i); if n == null { ret .Err(make(.Io)); } - if !put_name_field(&out, n.name) { ret .Err(make(.Io)); } - if !put_u64(&out, n.idx_of_strtab) { ret .Err(make(.Io)); } + if !put_name_field(out, n.name) { ret .Err(make(.Io)); } + if !put_u64(out, n.idx_of_strtab) { ret .Err(make(.Io)); } i = i + 1; } i = 0; while i < nstrs { var s = str_at(self, i); - if !put_u64(&out, s.len) { ret .Err(make(.Io)); } - if !put_view(&out, s) { ret .Err(make(.Io)); } - if !put_zeros(&out, align8(s.len) - s.len) { ret .Err(make(.Io)); } + if !put_u64(out, s.len) { ret .Err(make(.Io)); } + if !put_view(out, s) { ret .Err(make(.Io)); } + if !put_zeros(out, align8(s.len) - s.len) { ret .Err(make(.Io)); } i = i + 1; } @@ -646,11 +644,22 @@ fn store(self: *Prog, path: ByteView): Status { var e = gdata_at(self, i); if e == null { ret .Err(make(.Io)); } var dsize = e.storage.len; - if !put_u64(&out, dsize) { ret .Err(make(.Io)); } - if !put_view(&out, ByteView.from_slice(ByteBuffer.as_slice(e.*))) { ret .Err(make(.Io)); } - if !put_zeros(&out, align8(dsize) - dsize) { ret .Err(make(.Io)); } + if !put_u64(out, dsize) { ret .Err(make(.Io)); } + if !put_view(out, ByteView.from_slice(ByteBuffer.as_slice(e.*))) { ret .Err(make(.Io)); } + if !put_zeros(out, align8(dsize) - dsize) { ret .Err(make(.Io)); } i = i + 1; } + ret .Ok; +} + +fn store(self: *Prog, path: ByteView): Status { + var out = ByteBuffer.new(); + defer { ByteBuffer.drop(&out); } + + match encode(self, &out) { + .Ok => {}, + .Err(error) => { ret .Err(error); }, + } var f = open_cstr(path, ByteView.from_slice("wb")); if !File.valid(&f) { ret .Err(make(.Io)); } diff --git a/stage2/sys/spl_rt.h b/stage2/sys/spl_rt.h deleted file mode 100644 index 6c7e0ab..0000000 --- a/stage2/sys/spl_rt.h +++ /dev/null @@ -1,637 +0,0 @@ -/* spl_rt.h - SPL native runtime (header-only, C89-friendly) - * - * 提供 ir2c 生成代码所需的所有 `#extern(vm)` 符号,以及 SPL 基础类型别名。 - * 目标:生成代码可用 C89 语法通过(不依赖 stdint/stdbool)。 - */ - -#ifndef __SPL_RT_H__ -#define __SPL_RT_H__ - -#include -#include -#include -#include -#include - -/* 语义清晰的 inline:C99 用 static inline,GNU 用 __inline__,C89 退化为 static */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#define SPL_INLINE static inline -#elif defined(__GNUC__) || defined(__clang__) -#define SPL_INLINE static __inline__ -#else -#define SPL_INLINE static -#endif - -/* ---- SPL 基础类型别名 ---- */ -typedef unsigned char u8; -typedef signed char i8; -typedef unsigned short u16; -typedef signed short i16; -typedef unsigned int u32; -typedef signed int i32; -typedef unsigned long long u64; -typedef signed long long i64; - -#ifndef SPL_USIZE_TYPEDEF -#define SPL_USIZE_TYPEDEF -typedef u64 usize; -#endif - -#ifndef SPL_ISIZE_TYPEDEF -#define SPL_ISIZE_TYPEDEF -typedef i64 isize; -#endif -/* 注:不定义 bool/true/false,避免与 C23 关键字冲突;生成代码用 u8 表示布尔。 */ - -/* ---- panic / trap ---- */ -SPL_INLINE void spl_panic(const char *msg) { - fprintf(stderr, "%s\n", msg ? msg : "panic"); - exit(1); -} -SPL_INLINE void spl_trap(void) { abort(); } - -/* ---- mem ---- */ -SPL_INLINE void *vm_alloc(u64 sz) { - if (sz == 0) - return NULL; - return malloc((size_t)sz); -} -SPL_INLINE void vm_free(void *p) { - if (p) - free(p); -} -SPL_INLINE void *vm_realloc(void *p, u64 sz) { - if (!p) - return vm_alloc(sz); - if (sz == 0) { - free(p); - return NULL; - } - return realloc(p, (size_t)sz); -} -SPL_INLINE void *vm_memcpy(void *dst, const void *src, u64 n) { - if (n) - memcpy(dst, src, (size_t)n); - return dst; -} -SPL_INLINE void *vm_memmove(void *dst, const void *src, u64 n) { - if (n) - memmove(dst, src, (size_t)n); - return dst; -} -SPL_INLINE i64 vm_memcmp(const void *a, const void *b, u64 n) { - if (n == 0) - return 0; - return (i64)memcmp(a, b, (size_t)n); -} -SPL_INLINE i32 vm_bytes_eq(const void *a, u64 alen, const void *b, u64 blen) { - if (alen != blen) - return 0; - if (alen == 0) - return 1; - if (!a || !b) - return 0; - return memcmp(a, b, (size_t)alen) == 0; -} - -/* ---- Vec ---- */ -typedef struct { - usize raw; - usize data; - usize len; - usize cap; - usize elem_size; - usize elem_align; -} spl_vec_t; - -SPL_INLINE int spl_vec_is_valid(const spl_vec_t *v) { - usize a; - if (v->elem_size == 0) - return 0; - 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; -} - -SPL_INLINE int spl_align_ok(usize a) { return a != 0 && (a & (a - 1)) == 0; } - -SPL_INLINE void spl_grow(usize current, usize need, usize *out) { - usize cap = current < 8 ? 8 : current; - usize limit = ~(usize)0; - while (cap < need) { - if (cap > limit / 2) { - cap = need; - break; - } - cap = cap * 2; - } - *out = cap; -} - -SPL_INLINE int spl_vec_allocate(spl_vec_t *out, usize capacity, usize elem_size, usize elem_align) { - usize bytes, mask, addr; - void *raw; - 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 > ~(usize)0 / elem_size) - return 3; - bytes = capacity * elem_size; - mask = elem_align - 1; - if (bytes > ~(usize)0 - mask) - return 3; - raw = malloc(bytes + mask); - if (!raw) - return 3; - addr = (usize)raw; - if (addr > ~(usize)0 - mask) { - free(raw); - return 3; - } - out->raw = addr; - out->data = (addr + mask) & ~mask; - out->cap = capacity; - return 0; -} - -SPL_INLINE int spl_vec_reserve_raw(spl_vec_t *v, usize need) { - usize new_cap = 0, used = 0, old; - spl_vec_t fresh; - int rc; - if (need <= v->cap) - return 0; - spl_grow(v->cap, need, &new_cap); - rc = spl_vec_allocate(&fresh, new_cap, v->elem_size, v->elem_align); - if (rc) - return rc; - if (v->len != 0) { - if (v->len > ~(usize)0 / v->elem_size) { - free((void *)fresh.raw); - return 3; - } - used = v->len * v->elem_size; - } - if (used) - memcpy((void *)fresh.data, (void *)v->data, used); - fresh.len = v->len; - old = v->raw; - *v = fresh; - if (old) - free((void *)old); - return 0; -} - -SPL_INLINE void spl_vec_release(spl_vec_t *v) { - usize es = v->elem_size, 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; -} - -SPL_INLINE i32 vm_vec_valid(void *vv) { - const spl_vec_t *v = (const spl_vec_t *)vv; - return v ? spl_vec_is_valid(v) : 0; -} -SPL_INLINE i32 vm_vec_push_raw(void *vv, const void *elem) { - spl_vec_t *v = (spl_vec_t *)vv; - 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; -} -SPL_INLINE i32 vm_vec_get(void *vv, u64 index, void **out) { - const spl_vec_t *v = (const spl_vec_t *)vv; - if (!v || !out) - return 1; - if (!spl_vec_is_valid(v)) - return 1; - if (index >= v->len) - return 2; - *out = (void *)(v->data + index * v->elem_size); - return 0; -} -SPL_INLINE i32 vm_vec_push(void *vv, const void *elem) { - spl_vec_t *v = (spl_vec_t *)vv; - int rc; - 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; - } - 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; -} -SPL_INLINE i32 vm_vec_allocate(void *out, u64 capacity, u64 elem_size, u64 elem_align) { - return spl_vec_allocate((spl_vec_t *)out, capacity, elem_size, elem_align); -} -SPL_INLINE i32 vm_vec_reserve_raw(void *vv, u64 need) { - spl_vec_t *v = (spl_vec_t *)vv; - if (!v) - return 1; - return spl_vec_reserve_raw(v, need); -} -SPL_INLINE i32 vm_vec_append(void *vv, const void *elems, u64 count) { - spl_vec_t *v = (spl_vec_t *)vv; - usize copy_bytes, new_len, used, source_offset = 0; - int source_inside = 0, rc; - if (!v || !spl_vec_is_valid(v)) - return 1; - if (count == 0) - return 0; - if (!elems) - return 1; - if (count > ~(usize)0 / v->elem_size) - return 3; - copy_bytes = count * v->elem_size; - if (v->len > ~(usize)0 - count) - return 3; - new_len = v->len + count; - used = v->len * v->elem_size; - if (used) { - usize base = v->data; - usize source = (usize)elems; - if (source >= base && source - base < used) { - source_offset = source - base; - if (copy_bytes > used - source_offset) - return 2; - source_inside = 1; - } - } - 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; -} -SPL_INLINE i32 vm_vec_set(void *vv, u64 index, const void *elem) { - spl_vec_t *v = (spl_vec_t *)vv; - 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; -} -SPL_INLINE i32 vm_vec_pop(void *vv, void *out) { - spl_vec_t *v = (spl_vec_t *)vv; - 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; -} -SPL_INLINE i32 vm_vec_clone(void *outp, const void *srcp) { - spl_vec_t *out = (spl_vec_t *)outp; - const spl_vec_t *src = (const spl_vec_t *)srcp; - spl_vec_t fresh; - usize bytes; - int rc; - 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; - fresh.raw = 0; - fresh.data = 0; - fresh.len = 0; - fresh.cap = 0; - fresh.elem_size = src->elem_size; - fresh.elem_align = src->elem_align; - rc = spl_vec_reserve_raw(&fresh, src->len); - if (rc) - return rc; - bytes = src->len * src->elem_size; - if (bytes) - memcpy((void *)fresh.data, (void *)src->data, bytes); - fresh.len = src->len; - if (out->raw) - free((void *)out->raw); - *out = fresh; - return 0; -} -SPL_INLINE void vm_vec_drop(void *vv) { - spl_vec_t *v = (spl_vec_t *)vv; - if (v) - spl_vec_release(v); -} - -/* ---- Map ---- */ -typedef struct { - spl_vec_t keys; - spl_vec_t vals; - spl_vec_t states; - usize size; - usize key_size; - usize val_size; - usize hash_kind; -} spl_map_t; - -SPL_INLINE usize spl_hash_usize_value(usize value) { - usize prime = 1099511628211ull; - usize 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; -} -SPL_INLINE usize spl_hash_bytes(const void *data, usize len) { - const unsigned char *p = (const unsigned char *)data; - usize h = 14695981039346656037ull; - usize prime = 1099511628211ull; - usize i; - for (i = 0; i < len; i++) - h = (h ^ (usize)p[i]) * prime; - return h; -} -SPL_INLINE usize spl_map_hash(const spl_map_t *m, const void *key) { - const usize *v; - if (m->hash_kind == 0) - return spl_hash_usize_value(*(const usize *)key); - if (m->hash_kind == 2) - return 3; - v = (const usize *)key; - return spl_hash_bytes((const void *)v[0], v[1]); -} -SPL_INLINE int spl_map_eq(const spl_map_t *m, const void *a, const void *b) { - const usize *x; - const usize *y; - if (m->hash_kind == 0 || m->hash_kind == 2) - return *(const usize *)a == *(const usize *)b; - x = (const usize *)a; - y = (const usize *)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; -} -SPL_INLINE 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; -} -SPL_INLINE usize spl_map_find_slot(const spl_map_t *m, const void *key) { - usize mask, i, probes; - unsigned char *st; - if (m->states.cap == 0) - return ~(usize)0; - mask = m->states.cap - 1; - i = spl_map_hash(m, key) & mask; - st = (unsigned char *)m->states.data; - 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 ~(usize)0; -} -SPL_INLINE void spl_map_place(spl_map_t *m, const void *key, const void *val) { - usize mask, i, first_deleted, probes; - unsigned char *st; - mask = m->states.cap - 1; - i = spl_map_hash(m, key) & mask; - st = (unsigned char *)m->states.data; - first_deleted = ~(usize)0; - probes = 0; - while (probes < m->states.cap && st[i] != 0) { - if (st[i] == 2 && first_deleted == ~(usize)0) - first_deleted = i; - i = (i + 1) & mask; - probes++; - } - if (first_deleted != ~(usize)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++; -} -SPL_INLINE int spl_map_reserve(spl_map_t *m, usize need) { - usize new_cap = 0, i; - spl_map_t fresh; - int rc; - if (!spl_map_valid(m)) - return 1; - if (need <= m->states.cap) - return 0; - spl_grow(m->states.cap, need, &new_cap); - 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; - 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 (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; -} -SPL_INLINE i32 vm_map_valid(void *mm) { - const spl_map_t *m = (const spl_map_t *)mm; - return m ? spl_map_valid(m) : 0; -} -SPL_INLINE i32 vm_map_reserve(void *mm, u64 need) { - spl_map_t *m = (spl_map_t *)mm; - if (!m) - return 1; - return spl_map_reserve(m, need); -} -SPL_INLINE i32 vm_map_put(void *mm, const void *key, const void *val) { - spl_map_t *m = (spl_map_t *)mm; - usize existing; - if (!m || !key || !val || !spl_map_valid(m)) - return 1; - existing = spl_map_find_slot(m, key); - if (existing != ~(usize)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 { - usize next_size, scaled; - if (m->size > ~(usize)0 - 1) - return 3; - next_size = m->size + 1; - if (next_size > ~(usize)0 / 128) - return 3; - scaled = next_size * 128; - if (scaled / m->states.cap >= 70) { - int rc; - if (m->states.cap > ~(usize)0 / 2) - return 3; - rc = spl_map_reserve(m, m->states.cap * 2); - if (rc) - return rc; - } - } - spl_map_place(m, key, val); - return 0; -} -SPL_INLINE i32 vm_map_get(void *mm, const void *key, void *out) { - spl_map_t *m = (spl_map_t *)mm; - usize i; - if (!m || !key || !out || !spl_map_valid(m)) - return 1; - i = spl_map_find_slot(m, key); - if (i == ~(usize)0) - return 1; - memcpy(out, (void *)(m->vals.data + i * m->val_size), m->val_size); - return 0; -} -SPL_INLINE i32 vm_map_del(void *mm, const void *key) { - spl_map_t *m = (spl_map_t *)mm; - usize i; - if (!m || !key || !spl_map_valid(m)) - return 1; - i = spl_map_find_slot(m, key); - if (i == ~(usize)0) - return 1; - ((unsigned char *)m->states.data)[i] = 2; - m->size--; - return 0; -} -SPL_INLINE void vm_map_clear(void *mm) { - spl_map_t *m = (spl_map_t *)mm; - if (!m) - return; - if (m->states.data && m->states.len) - memset((void *)m->states.data, 0, m->states.len); - m->size = 0; -} -SPL_INLINE void vm_map_drop(void *mm) { - spl_map_t *m = (spl_map_t *)mm; - if (!m) - return; - spl_vec_release(&m->keys); - spl_vec_release(&m->vals); - spl_vec_release(&m->states); - m->size = 0; -} - -/* ---- file ---- */ -SPL_INLINE void *vm_fopen(void *path, void *mode) { - return (void *)fopen((const char *)path, (const char *)mode); -} -SPL_INLINE i32 vm_fclose(void *f) { return f ? fclose((FILE *)f) : 0; } -SPL_INLINE u64 vm_fread(void *buf, u64 sz, u64 n, void *f) { - return f ? (u64)fread(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0; -} -SPL_INLINE u64 vm_fwrite(void *buf, u64 sz, u64 n, void *f) { - return f ? (u64)fwrite(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0; -} -SPL_INLINE u64 vm_fsize(void *f) { - long cur, end; - if (!f) - return 0; - cur = ftell((FILE *)f); - if (cur < 0) - return 0; - if (fseek((FILE *)f, 0, SEEK_END) != 0) - return 0; - end = ftell((FILE *)f); - fseek((FILE *)f, cur, SEEK_SET); - return end < 0 ? 0 : (u64)end; -} -SPL_INLINE void *vm_stdin(void) { return (void *)stdin; } -SPL_INLINE void *vm_stdout(void) { return (void *)stdout; } -SPL_INLINE void *vm_stderr(void) { return (void *)stderr; } -SPL_INLINE i32 vm_putchar(i32 c) { return fputc(c, stdout); } -SPL_INLINE i32 vm_getchar(void) { return fgetc(stdin); } - -/* ---- misc ---- */ -SPL_INLINE void vm_exit(i32 code) { exit(code); } -SPL_INLINE u64 vm_timestamp(u64 kind) { - time_t sec = time(NULL); - if (kind == 1) - return (u64)sec; - if (kind == 2) - return 0; - if (kind == 4) - return (u64)sec * 1000000000ull; - return 0; -} - -/* ---- 内嵌 VM(comptime):实现在 spl_vm_embed.c,链接 stage0 VM ---- */ -#define SPL_VM_EMBED_IMPLIMENTATION -#include "spl_vm_embed.h" - -#endif /* __SPL_RT_H__ */