/* spl_vm.h - SIR interpreter */ #ifndef __SPL_VM_H__ #define __SPL_VM_H__ #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; uintptr_t saved_ip; spl_vm_val_t nargs; } spl_callframe_t; 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; VEC(uint64_t) self_ns; /* 每函数 time-slice 累加(纳秒) */ uint64_t last_ns; uint64_t total_ns; usize samples; } spl_prof_t; 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 uint64_t steps; // 已执行指令数(供性能分析参考) uint64_t ncalls; // 已执行 CALL/CALLI 次数(供性能分析参考) int exit_code; int trace; /* non-zero to print each instruction */ int debug; /* non-zero to enable canary checks */ int debug_addr; /* non-zero to check for low-address memory access */ int skip_bp; /* non-zero: run_once 忽略下一次断点(continue 越过当前断点指令) */ spl_prof_t *profile; /* native 采样 profiler 状态(spl_prof_t*),NULL = 关闭 */ usize profile_interval; /* 采样间隔(指令数) */ 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; uintptr_t max_call_depth; } config; } spl_vm_t; /* Initialize VM with default sizes (SPL_DEFAULT_STACK_SIZE / * SPL_DEFAULT_CALL_DEPTH) */ void spl_vm_init(spl_vm_t *vm); /* Initialize VM with custom sizes (pass 0 to use defaults) */ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth); /* Free dynamically allocated memory in VM */ 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); /* Enable/disable instruction-level tracing */ void spl_vm_set_trace(spl_vm_t *vm, int enabled); /* Enable/disable debug mode (stack canary protection) */ void spl_vm_set_debug(spl_vm_t *vm, int enabled); int spl_vm_run_once(spl_vm_t *vm); int spl_vm_run_until(spl_vm_t *vm, size_t step); /* 断点:ip 断点 / 函数名断点(CALL/CALLI 目标函数入口)。命中时 run_once 返回 2。 */ void spl_vm_add_breakpoint(spl_vm_t *vm, usize ip); void spl_vm_add_breakpoint_fn(spl_vm_t *vm, const char *name); void spl_vm_clear_breakpoints(spl_vm_t *vm); /* 让 run_once 执行当前指令(忽略一次断点命中);continue 越过当前断点用 */ void spl_vm_skip_breakpoint(spl_vm_t *vm); /* ---- native 采样 profiler ---- * 每隔 interval 条指令记录一次当前调用栈(折叠格式),用于生成火焰图。 * 必须在 prog 加载后调用 enable;dump 输出折叠栈/函数表,再 drop 时释放。 */ void spl_vm_profile_enable(spl_vm_t *vm, usize interval); void spl_vm_profile_dump_folded(spl_vm_t *vm, const char *path); void spl_vm_profile_dump_table(spl_vm_t *vm, const char *path); void spl_vm_dump_instr(spl_vm_t *vm, spl_vm_val_t ip); void spl_vm_stackdump(spl_vm_t *vm, spl_vm_val_t sp); int spl_vm_backtrace(spl_vm_t *vm, spl_vm_val_t fp); #endif /* __SPL_VM_H__ */