Files
spl/stage0/spl_vm.h
T

168 lines
7.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 <stdint.h>
#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);
/* 本次调用实参在 VM 栈中的起始下标(外部处理器可按需用 stack_get 逐个读取,
* 无需在 C 侧了解参数类型/元数上限)。失败返回 (usize)-1。 */
usize spl_vm_call_arg_base(spl_vm_t *vm, const spl_vm_call_t *call);
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__ */