stage0 重构vm使其依赖自己的地址空间不再共用宿主机 修改vm的ABI 修正相关nob构建问题
This commit is contained in:
1 parent
fae017b52d
commit
c0a86ea552
14 files changed
+2149
-1572
No files matched your search
+404
-28
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user