/* 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" #include "spl_mcode.h" #include "spl_vm.h" #include #include #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 * ================================================================= */ #define CHECK_NARGS(fname, expected) \ do { \ if (nargs != (expected)) { \ fprintf(stderr, fname ": expected " #expected " args, got %d\n", nargs); \ return -1; \ } \ } while (0) #define SYSCALL_0(name, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 0); \ (void)args; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_1(name, t1, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 1); \ t1 a1 = (t1)(uintptr_t)args[0]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_2(name, t1, t2, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 2); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_3(name, t1, t2, t3, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 3); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ t3 a3 = (t3)(uintptr_t)args[2]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_4(name, t1, t2, t3, t4, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 4); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ t3 a3 = (t3)(uintptr_t)args[2]; \ t4 a4 = (t4)(uintptr_t)args[3]; \ 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); \ usize _acs = (usize)(size); \ if (!spl_vm_addr_valid(_acp, _acs)) { \ fprintf(stderr, "%s: invalid address %p size=%zu (ip=%zu fp=%zu sp=%zu)\n", (ctx), \ (void *)_acp, _acs, (vm)->ip, (vm)->fp, (vm)->sp); \ spl_vm_backtrace((vm), (vm)->fp); \ (vm)->exit_code = 2; \ return 0; \ } \ } while (0) /* syscall 内部:把当前栈和调用栈打印出来,供出错时定位 */ #define SYSCALL_DUMP(vm) \ do { \ fprintf(stderr, " --- syscall dump (sp=%zu fp=%zu cp=%zu ip=%zu) ---\n", (vm)->sp, \ (vm)->fp, (vm)->cp, (vm)->ip); \ spl_vm_backtrace((vm), (vm)->fp); \ spl_vm_stackdump((vm), (vm)->sp); \ } while (0) /* syscall 内部:报告致命错误,dump 后让 VM 停在当前 ip */ #define SYSCALL_FAIL(vm, ...) \ do { \ fprintf(stderr, "syscall error: "); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ SYSCALL_DUMP(vm); \ (vm)->exit_code = 1; \ return 0; \ } while (0) /* ================================================================= * 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; } SYSCALL_0(vm_stdin, stdin) SYSCALL_0(vm_stdout, stdout) SYSCALL_0(vm_stderr, stderr) /* 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]; if (path == nullptr) { fprintf(stderr, "filepath can't be null"); return 0; } FILE *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); fseek(f, 0, SEEK_SET); char *buf = (char *)malloc((size_t)sz + 1); if (!buf) { fclose(f); return 0; } size_t nread = fread(buf, 1, (size_t)sz, f); fclose(f); buf[nread] = '\0'; return (spl_vm_val_t)(uintptr_t)buf; } static spl_vm_val_t vm_alloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_alloc", 1); size_t sz = (size_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; } static spl_vm_val_t vm_free(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_free", 1); void *p = (void *)(uintptr_t)args[0]; if (p) free(p); return 0; } static spl_vm_val_t vm_realloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_realloc", 2); void *p = (void *)(uintptr_t)args[0]; size_t sz = (size_t)args[1]; if (!p) 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; } static spl_vm_val_t vm_memcpy(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { 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; } 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 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]; if (nargs <= 1) { fwrite(fmt, 1, fmt_len, stdout); return (spl_vm_val_t)nargs; } typedef VEC(char) string_builder_t; string_builder_t buffer; vec_init(buffer); int arg_idx = 1; /* 0 是 format */ char tmp_buf[32]; for (usize i = 0; i < fmt_len; ++i) { if (fmt[i] != '%') { vec_push(buffer, fmt[i]); continue; } if (++i >= fmt_len) break; if (arg_idx >= nargs) break; switch (fmt[i]) { case 'd': { memset(tmp_buf, 0, sizeof(tmp_buf)); snprintf(tmp_buf, sizeof(tmp_buf), "%zd", (isize)args[arg_idx]); for (usize j = 0; tmp_buf[j] != '\0'; ++j) vec_push(buffer, tmp_buf[j]); arg_idx++; break; } case 'c': vec_push(buffer, (char)args[arg_idx]); 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]); arg_idx++; break; } default: vec_push(buffer, '%'); vec_push(buffer, fmt[i]); break; } } if (vec_size(buffer) > 0) fwrite(buffer.data, 1, vec_size(buffer), stdout); vec_free(buffer); 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]; struct timespec ts; int has_time = (timespec_get(&ts, TIME_UTC) == TIME_UTC); switch (arg) { case 0: return has_time ? 1 : 0; case 1: return has_time ? (spl_vm_val_t)ts.tv_sec : 0; case 2: return has_time ? (spl_vm_val_t)ts.tv_nsec : 0; case 3: if (!_vm) return 0; return (spl_vm_val_t)_vm->steps; case 5: if (!_vm) return 0; return (spl_vm_val_t)_vm->ncalls; case 4: return has_time ? (spl_vm_val_t)((unsigned long long)ts.tv_sec * 1000000000ull + (unsigned long long)ts.tv_nsec) : 0; default: fprintf(stderr, "vm_timestamp: invalid arg %zu\n", (size_t)arg); return 0; } } /* ================================================================= * 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. * ================================================================= */ /* vm_new - create a new sub-VM instance, returns spl_vm_t* */ 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; spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t)); if (!vm) return 0; spl_vm_init(vm); return (spl_vm_val_t)(uintptr_t)vm; } /* vm_drop - destroy a sub-VM and its loaded program */ 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->prog) { spl_prog_drop(vm->prog); free(vm->prog); vm->prog = NULL; } spl_vm_drop(vm); free(vm); 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]; if (!vm || !path) return -1; spl_prog_t *prog = (spl_prog_t *)malloc(sizeof(spl_prog_t)); if (!prog) return -1; if (spl_prog_load_from_file(path, prog) != 0) { free(prog); return -1; } spl_syscall_register(prog); if (spl_vm_load_prog(vm, prog) != 0) { spl_prog_drop(prog); free(prog); return -1; } 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]; usize len = (usize)args[2]; spl_prog_t *prog; if (!vm || !buf) return -1; prog = (spl_prog_t *)malloc(sizeof(spl_prog_t)); if (!prog) return -1; if (spl_prog_load_from_buffer(buf, len, prog) != 0) { free(prog); return -1; } spl_syscall_register(prog); if (spl_vm_load_prog(vm, prog) != 0) { spl_prog_drop(prog); free(prog); return -1; } 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); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; spl_vm_val_t val = args[1]; if (!vm) return -1; if (vm->sp >= vm->config.max_stack_depth) { fprintf(stderr, "vm_push: stack overflow\n"); return -1; } vm->stacks.data[vm->sp++] = val; 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]; 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); 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); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; if (!vm) return -1; spl_vm_run_until(vm, 0); return (spl_vm_val_t)vm->exit_code; } /* ================================================================= * 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}, {"vm_putint", 0, vm_putint}, {"vm_putstr", 0, vm_putstr}, {"vm_fopen", 0, vm_fopen}, {"vm_fclose", 0, vm_fclose}, {"vm_fread", 0, vm_fread}, {"vm_fwrite", 0, vm_fwrite}, {"vm_fsize", 0, vm_fsize}, {"vm_stdin", 0, vm_stdin}, {"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_printf", 0, vm_printf}, {"vm_vec_valid", 0, vm_vec_valid}, {"vm_vec_push_raw", 0, vm_vec_push_raw}, {"vm_vec_push", 0, vm_vec_push}, {"vm_vec_get", 0, vm_vec_get}, {"vm_vec_allocate", 0, vm_vec_allocate}, {"vm_vec_reserve_raw", 0, vm_vec_reserve_raw}, {"vm_vec_append", 0, vm_vec_append}, {"vm_vec_set", 0, vm_vec_set}, {"vm_vec_pop", 0, vm_vec_pop}, {"vm_vec_clone", 0, vm_vec_clone}, {"vm_vec_drop", 0, vm_vec_drop}, {"vm_memmove", 0, vm_memmove}, {"vm_bytes_eq", 0, vm_bytes_eq}, {"vm_map_valid", 0, vm_map_valid}, {"vm_map_reserve", 0, vm_map_reserve}, {"vm_map_put", 0, vm_map_put}, {"vm_map_get", 0, vm_map_get}, {"vm_map_del", 0, vm_map_del}, {"vm_map_clear", 0, vm_map_clear}, {"vm_map_drop", 0, vm_map_drop}, {"vm_timestamp", 0, vm_timestamp}, /* VM operations (comptime) */ {"vm_new", 0, vm_new}, {"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}, }; int n = (int)(sizeof(table) / sizeof(table[0])); if (!prog) return; vec_for(prog->natives, i) { spl_vm_native_t *nat = &vec_at(prog->natives, i); if (!nat->name || nat->impl_fn) continue; for (int j = 0; j < n; j++) { if (strcmp(nat->name, table[j].name) == 0) { nat->impl_fn = table[j].impl_fn; break; } } } }