stage2 大量优化代码使其自举编译时间大幅缩短

This commit is contained in:
zzy committed 2026-09-20 09:33:20 +08:00
1 parent e02b0c633a
commit 846f441e3a
38 files changed
+2418 -835

No files matched your search

+292 -202
View File
@@ -11,6 +11,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
static void spl_vm_profile_free(spl_vm_t *vm);
@@ -67,7 +68,7 @@ static int spl_type_size(spl_vm_kind_t t) {
case SPL_USIZE:
case SPL_PTR:
return sizeof(void *);
case SPL_TYPE_COUNT:
default:
return 0;
}
return 0;
@@ -570,6 +571,7 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) {
vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0;
vm->steps = 0;
vm->ncalls = 0;
vm->profile = NULL;
vm->profile_interval = 0;
vm->prog = NULL;
@@ -708,22 +710,29 @@ void spl_vm_set_debug(spl_vm_t *vm, int enabled) {
static inline int spl_vm_call(spl_vm_t *vm, spl_vm_val_t addr, spl_vm_val_t nargs) {
if (vm->cp >= vm->config.max_call_depth)
VM_ERROR("call depth exceeded");
// spl_vm_stackdump(vm, vm->sp);
PUSH(SPL_STACK_CANARY);
/* Shift args right by 1 to create gap for canary at fp-1 */
for (usize i = vm->sp; i >= vm->sp - nargs; --i) {
vm->stacks.data[i] = vm->stacks.data[i - 1];
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;
}
vm->frames.data[vm->cp].saved_sp = vm->sp - nargs - 1;
vm->frames.data[vm->cp].saved_fp = vm->fp;
vm->frames.data[vm->cp].saved_ip = vm->ip;
vm->frames.data[vm->cp].nargs = nargs;
spl_callframe_t *fr = &vm->frames.data[vm->cp];
fr->saved_sp = saved_sp;
fr->saved_fp = vm->fp;
fr->saved_ip = vm->ip;
fr->nargs = nargs;
vm->cp++;
vm->ip = addr;
vm->fp = vm->sp - nargs;
if (vm->fp > 0)
if (vm->debug && vm->fp > 0)
STACK_CANARY(vm) = SPL_STACK_CANARY;
// spl_vm_stackdump(vm, vm->sp);
return 0;
}
@@ -800,6 +809,13 @@ static int func_index_by_ip(spl_prog_t *prog, spl_vm_val_t ip) {
return -1;
}
static uint64_t prof_now_ns(void) {
struct timespec ts;
if (timespec_get(&ts, TIME_UTC) != TIME_UTC)
return 0;
return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec;
}
static void spl_vm_sample(spl_vm_t *vm) {
spl_prof_t *p = (spl_prof_t *)vm->profile;
spl_prog_t *prog = vm->prog;
@@ -823,6 +839,17 @@ static void spl_vm_sample(spl_vm_t *vm) {
}
}
int leaf = func_index_by_ip(prog, vm->ip > 0 ? vm->ip - 1 : 0);
/* time-slice:把两次采样之间的时间记到当前活跃函数(leaf)。 */
uint64_t now = prof_now_ns();
if (p->last_ns != 0 && now > p->last_ns) {
uint64_t d = now - p->last_ns;
p->total_ns += d;
if (leaf >= 0 && (usize)leaf < vec_size(p->self_ns))
p->self_ns.data[leaf] += d;
}
p->last_ns = now;
const char *ln = leaf >= 0 ? vec_at(prog->funcs, (usize)leaf).name : "?";
size_t ll = strlen(ln);
if (len + ll + 1 < sizeof(buf)) {
@@ -853,10 +880,13 @@ void spl_vm_profile_enable(spl_vm_t *vm, usize interval) {
memset(p, 0, sizeof(*p));
map_init(p->stacks, MAP_HASH_STR, MAP_CMP_STR);
vec_init(p->self_samples);
vec_init(p->self_ns);
if (vm->prog) {
usize n = vec_size(vm->prog->funcs);
for (usize i = 0; i < n; i++)
for (usize i = 0; i < n; i++) {
vec_push(p->self_samples, (usize)0);
vec_push(p->self_ns, (uint64_t)0);
}
}
vm->profile = p;
vm->profile_interval = interval ? interval : 100000;
@@ -869,6 +899,7 @@ static void spl_vm_profile_free(spl_vm_t *vm) {
map_for(p->stacks, i) { free((void *)p->stacks.data[i].key); }
map_free(p->stacks);
vec_free(p->self_samples);
vec_free(p->self_ns);
free(p);
vm->profile = NULL;
}
@@ -891,20 +922,67 @@ void spl_vm_profile_dump_table(spl_vm_t *vm, const char *path) {
FILE *f = fopen(path, "wb");
if (!f)
return;
fprintf(f, "samples=%zu interval=%zu\n", p->samples, vm->profile_interval);
fprintf(f, "func\tself_samples\tpercent\n");
fprintf(f, "samples=%zu interval=%zu total_ns=%llu\n", p->samples, vm->profile_interval,
(unsigned long long)p->total_ns);
fprintf(f, "func\tself_samples\tpct_samples\tself_ns\tpct_ns\tns_per_step\n");
for (usize i = 0; i < vec_size(vm->prog->funcs); i++) {
usize c = i < vec_size(p->self_samples) ? p->self_samples.data[i] : 0;
if (c == 0)
continue;
uint64_t t = i < vec_size(p->self_ns) ? p->self_ns.data[i] : 0;
spl_vm_func_t *fn = &vec_at(vm->prog->funcs, i);
fprintf(f, "%s\t%zu\t%.2f\n", fn->name, c,
p->samples ? (100.0 * (double)c / (double)p->samples) : 0.0);
double ps = p->samples ? (100.0 * (double)c / (double)p->samples) : 0.0;
double pt = p->total_ns ? (100.0 * (double)t / (double)p->total_ns) : 0.0;
double nps = c ? ((double)t / (double)c) : 0.0;
fprintf(f, "%s\t%zu\t%.2f\t%llu\t%.2f\t%.1f\n", fn->name, c, ps, (unsigned long long)t, pt,
nps);
}
fclose(f);
}
int spl_vm_run_once(spl_vm_t *vm) {
/* 单步执行核心(static,便于内联进热循环)。 */
/* computed-goto 调度:每个 opcode 直接跳到对应标签;limit=SIZE_MAX 表示不限步。 */
#define DT(op) [op] = &&L_##op
#define FETCH() \
do { \
if (vm->ip >= (spl_vm_val_t)vec_size(prog->insns)) { \
fprintf(stderr, "vm: ip=%zd out of bounds\n", vm->ip); \
vm->exit_code = 1; \
return -1; \
} \
ins = &vec_at(prog->insns, vm->ip); \
vm->ip++; \
vm->steps++; \
if (vm->profile && vm->profile_interval && (vm->steps % vm->profile_interval) == 0) \
spl_vm_sample(vm); \
if (vm->trace) { \
fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1, \
spl_vm_opcode_name(ins->opcode), spl_vm_type_kind_name(ins->type), ins->imm, \
vm->sp, vm->fp); \
} \
} while (0)
#define DISPATCH() \
do { \
if (vm->debug && vm->fp > 0 && STACK_CANARY(vm) != SPL_STACK_CANARY) { \
snprintf(vm->error_msg, sizeof(vm->error_msg), \
"STACK CANARY CORRUPTED at ip=%zd, fp=%zd\n", vm->ip - 1, vm->fp); \
VM_ERROR(vm->error_msg); \
} \
if (limit && --limit == 0) \
return 0; \
if (ip_breakpoint_hit(vm)) { \
if (vm->skip_bp) \
vm->skip_bp = 0; \
else \
return 2; \
} \
FETCH(); \
goto *vm_dispatch[ins->opcode]; \
} while (0)
static int vm_loop(spl_vm_t *vm, size_t limit) {
const spl_vm_ins_t *ins;
spl_prog_t *prog;
@@ -912,73 +990,78 @@ int spl_vm_run_once(spl_vm_t *vm) {
return -1;
prog = vm->prog;
if (vm->ip >= vec_size(prog->insns)) {
fprintf(stderr, "vm: ip=%zd out of bounds\n", vm->ip);
vm->exit_code = 1;
return -1;
}
static void *vm_dispatch[SPL_OPCODE_COUNT] = {
DT(SPL_PUSH), DT(SPL_DUP), DT(SPL_DROP),
DT(SPL_SWAP), DT(SPL_PICK), DT(SPL_ROT),
DT(SPL_ADD), DT(SPL_SUB), DT(SPL_MUL),
DT(SPL_DIV_S), DT(SPL_DIV_U), DT(SPL_REM_S),
DT(SPL_REM_U), DT(SPL_NEG), DT(SPL_AND),
DT(SPL_OR), DT(SPL_XOR), DT(SPL_NOT),
DT(SPL_SHL), DT(SPL_SHR_U), DT(SPL_SHR_S),
DT(SPL_EQ), DT(SPL_NE), DT(SPL_SLT),
DT(SPL_SLE), DT(SPL_ULT), DT(SPL_ULE),
DT(SPL_SGT), DT(SPL_SGE), DT(SPL_UGT),
DT(SPL_UGE), DT(SPL_TRUNC), DT(SPL_SEXT),
DT(SPL_ZEXT), DT(SPL_JMP), DT(SPL_BZ),
DT(SPL_BNZ), DT(SPL_HALT), DT(SPL_CALL),
DT(SPL_CALLI), DT(SPL_RET), DT(SPL_ALLOC),
DT(SPL_LADDR), DT(SPL_GADDR), DT(SPL_LOAD),
DT(SPL_STORE), DT(SPL_NCALL), DT(SPL_NLIB),
DT(SPL_BK), DT(SPL_DBG), [SPL_ERROR] = &&L_default,
};
/* 断点:即将执行的指令命中 ip 断点 -> 暂停(返回 2)。
* skip_bp 置位时执行当前指令(continue 越过当前断点)。 */
if (limit == 0)
return 0;
if (ip_breakpoint_hit(vm)) {
if (vm->skip_bp) {
if (vm->skip_bp)
vm->skip_bp = 0;
} else {
else
return 2;
}
}
FETCH();
goto *vm_dispatch[ins->opcode];
ins = &vec_at(prog->insns, vm->ip);
vm->ip++;
vm->steps++;
if (vm->profile && vm->profile_interval && (vm->steps % vm->profile_interval) == 0)
spl_vm_sample(vm);
/* ========== Stack ========== */
L_SPL_PUSH:
PUSH(ins->imm);
DISPATCH();
if (vm->trace) {
fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1,
spl_vm_opcode_name(ins->opcode), spl_vm_type_kind_name(ins->type), ins->imm, vm->sp,
vm->fp);
}
switch (ins->opcode) {
/* ========== Stack ========== */
case SPL_PUSH:
PUSH(ins->imm);
break;
case SPL_DUP: {
L_SPL_DUP:
{
if (vm->sp < 1)
VM_ERROR("DUP: stack underflow");
spl_vm_val_t _v = vm->stacks.data[vm->sp - 1];
PUSH(_v);
break;
DISPATCH();
}
case SPL_DROP:
if (vm->sp < 1)
VM_ERROR("DROP: stack underflow");
vm->sp--;
break;
L_SPL_DROP:
if (vm->sp < 1)
VM_ERROR("DROP: stack underflow");
vm->sp--;
DISPATCH();
case SPL_SWAP: {
L_SPL_SWAP:
{
if (vm->sp < 2)
VM_ERROR("SWAP: stack underflow");
spl_vm_val_t _t = vm->stacks.data[vm->sp - 1];
vm->stacks.data[vm->sp - 1] = vm->stacks.data[vm->sp - 2];
vm->stacks.data[vm->sp - 2] = _t;
break;
DISPATCH();
}
case SPL_PICK: {
L_SPL_PICK:
{
isize _idx = ins->imm;
if ((usize)_idx >= vm->sp)
VM_ERROR("PICK: index out of range");
PUSH(vm->stacks.data[vm->sp - 1 - _idx]);
break;
DISPATCH();
}
case SPL_ROT: {
L_SPL_ROT:
{
if (vm->sp < 3)
VM_ERROR("ROT: stack underflow");
spl_vm_val_t _a = vm->stacks.data[vm->sp - 3];
@@ -987,34 +1070,35 @@ int spl_vm_run_once(spl_vm_t *vm) {
vm->stacks.data[vm->sp - 3] = _b;
vm->stacks.data[vm->sp - 2] = _c;
vm->stacks.data[vm->sp - 1] = _a;
break;
DISPATCH();
}
/* ========== Arithmetic ========== */
case SPL_ADD:
ARITH_BINOP(+);
break;
case SPL_SUB:
ARITH_BINOP(-);
break;
case SPL_MUL:
ARITH_BINOP(*);
break;
/* ========== Arithmetic ========== */
L_SPL_ADD:
ARITH_BINOP(+);
DISPATCH();
L_SPL_SUB:
ARITH_BINOP(-);
DISPATCH();
L_SPL_MUL:
ARITH_BINOP(*);
DISPATCH();
case SPL_DIV_S:
DIV_REM_S(/);
break;
case SPL_DIV_U:
DIV_REM_U(/);
break;
case SPL_REM_S:
DIV_REM_S(%);
break;
case SPL_REM_U:
DIV_REM_U(%);
break;
L_SPL_DIV_S:
DIV_REM_S(/);
DISPATCH();
L_SPL_DIV_U:
DIV_REM_U(/);
DISPATCH();
L_SPL_REM_S:
DIV_REM_S(%);
DISPATCH();
L_SPL_REM_U:
DIV_REM_U(%);
DISPATCH();
case SPL_NEG: {
L_SPL_NEG:
{
spl_vm_val_t _a = POP();
if (spl_is_float((spl_vm_kind_t)ins->type)) {
double _d;
@@ -1032,115 +1116,129 @@ int spl_vm_run_once(spl_vm_t *vm) {
} else {
PUSH(-(int64_t)_a);
}
break;
DISPATCH();
}
/* ========== Bitwise ========== */
case SPL_AND: {
/* ========== Bitwise ========== */
L_SPL_AND:
{
spl_vm_val_t _b = POP(), _a = POP();
PUSH(_a & _b);
break;
DISPATCH();
}
case SPL_OR: {
L_SPL_OR:
{
spl_vm_val_t _b = POP(), _a = POP();
PUSH(_a | _b);
break;
DISPATCH();
}
case SPL_XOR: {
L_SPL_XOR:
{
spl_vm_val_t _b = POP(), _a = POP();
PUSH(_a ^ _b);
break;
DISPATCH();
}
case SPL_NOT: {
L_SPL_NOT:
{
PUSH(~POP());
break;
DISPATCH();
}
case SPL_SHL: {
L_SPL_SHL:
{
int _s = (int)(POP() & 63);
PUSH(POP() << _s);
break;
DISPATCH();
}
case SPL_SHR_U: {
L_SPL_SHR_U:
{
int _s = (int)(POP() & 63);
PUSH(POP() >> _s);
break;
DISPATCH();
}
case SPL_SHR_S: {
L_SPL_SHR_S:
{
int _s = (int)(POP() & 63);
PUSH(POP() >> _s);
break;
DISPATCH();
}
/* ========== Comparison ========== */
case SPL_EQ:
CMP_ALL(==);
break;
case SPL_NE:
CMP_ALL(!=);
break;
case SPL_SLT:
CMP_S(<);
break;
case SPL_SLE:
CMP_S(<=);
break;
case SPL_SGT:
CMP_S(>);
break;
case SPL_SGE:
CMP_S(>=);
break;
case SPL_ULT:
CMP_U(<);
break;
case SPL_ULE:
CMP_U(<=);
break;
case SPL_UGT:
CMP_U(>);
break;
case SPL_UGE:
CMP_U(>=);
break;
/* ========== Comparison ========== */
L_SPL_EQ:
CMP_ALL(==);
DISPATCH();
L_SPL_NE:
CMP_ALL(!=);
DISPATCH();
L_SPL_SLT:
CMP_S(<);
DISPATCH();
L_SPL_SLE:
CMP_S(<=);
DISPATCH();
L_SPL_SGT:
CMP_S(>);
DISPATCH();
L_SPL_SGE:
CMP_S(>=);
DISPATCH();
L_SPL_ULT:
CMP_U(<);
DISPATCH();
L_SPL_ULE:
CMP_U(<=);
DISPATCH();
L_SPL_UGT:
CMP_U(>);
DISPATCH();
L_SPL_UGE:
CMP_U(>=);
DISPATCH();
/* ========== Control Flow (relative offset) ========== */
case SPL_JMP:
vm->ip = vm->ip + ins->imm;
break;
/* ========== Control Flow (relative offset) ========== */
L_SPL_JMP:
vm->ip = vm->ip + ins->imm;
DISPATCH();
case SPL_BZ: {
L_SPL_BZ:
{
if (POP() == 0)
vm->ip = vm->ip + ins->imm;
break;
DISPATCH();
}
case SPL_BNZ: {
L_SPL_BNZ:
{
if (POP() != 0)
vm->ip = vm->ip + ins->imm;
break;
DISPATCH();
}
case SPL_CALL: {
L_SPL_CALL:
{
spl_vm_val_t _nargs = ins->imm;
spl_vm_val_t _addr = POP();
vm->ncalls++;
int _hit = fn_breakpoint_hit(vm, _addr);
spl_vm_call(vm, _addr, _nargs);
if (_hit)
return 2; /* 已进入函数,暂停在函数入口 */
break;
DISPATCH();
}
case SPL_CALLI: {
L_SPL_CALLI:
{
spl_vm_val_t _addr = POP();
spl_vm_val_t _nargs = POP();
vm->ncalls++;
int _hit = fn_breakpoint_hit(vm, _addr);
spl_vm_call(vm, _addr, _nargs);
if (_hit)
return 2;
break;
DISPATCH();
}
case SPL_RET: {
L_SPL_RET:
{
spl_vm_val_t _retval = 0;
if (ins->type != SPL_VOID)
_retval = POP();
@@ -1161,16 +1259,17 @@ int spl_vm_run_once(spl_vm_t *vm) {
if (ins->type != SPL_VOID)
PUSH(_retval);
// spl_vm_stackdump(vm, vm->sp);
break;
DISPATCH();
}
case SPL_HALT:
if (ins->imm)
vm->exit_code = (int)ins->imm;
return 1;
L_SPL_HALT:
if (ins->imm)
vm->exit_code = (int)ins->imm;
return 1;
/* ========== Stack / Frame Local Memory ========== */
case SPL_ALLOC: {
/* ========== Stack / Frame Local Memory ========== */
L_SPL_ALLOC:
{
spl_vm_val_t _k = ins->imm;
uintptr_t _new_sp = vm->sp + _k;
if (_new_sp > vm->config.max_stack_depth)
@@ -1178,14 +1277,15 @@ int spl_vm_run_once(spl_vm_t *vm) {
for (uintptr_t _i = vm->sp; _i < _new_sp; _i++)
vm->stacks.data[_i] = 0;
vm->sp = _new_sp;
break;
DISPATCH();
}
case SPL_LADDR:
PUSH((spl_vm_val_t)((char *)(vm->stacks.data + vm->fp) + ins->imm));
break;
L_SPL_LADDR:
PUSH((spl_vm_val_t)((char *)(vm->stacks.data + vm->fp) + ins->imm));
DISPATCH();
case SPL_GADDR: {
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");
@@ -1193,11 +1293,12 @@ int spl_vm_run_once(spl_vm_t *vm) {
if (!gd->data)
VM_ERROR("GADDR: null gdata entry");
PUSH((spl_vm_val_t)(uintptr_t)gd->data);
break;
DISPATCH();
}
/* ========== Indirect Memory (load/store with types) ========== */
case SPL_LOAD: {
/* ========== Indirect Memory (load/store with types) ========== */
L_SPL_LOAD:
{
void *_addr = (void *)POP();
CHECK_ADDR(_addr, "LOAD");
spl_vm_val_t _v = 0;
@@ -1209,18 +1310,20 @@ int spl_vm_run_once(spl_vm_t *vm) {
_v = (spl_vm_val_t)(((isize)(_v << _shift)) >> _shift);
}
PUSH(_v);
break;
DISPATCH();
}
case SPL_STORE: {
L_SPL_STORE:
{
spl_vm_val_t _v = POP();
void *_addr = (void *)POP();
CHECK_ADDR(_addr, "STORE");
memcpy(_addr, &_v, spl_type_size(ins->type));
break;
DISPATCH();
}
/* ========== Type Conversion ========== */
case SPL_TRUNC: {
/* ========== Type Conversion ========== */
L_SPL_TRUNC:
{
spl_vm_val_t _v = POP();
intptr_t _bits = ins->imm;
if (_bits < 1 || _bits > 64)
@@ -1230,10 +1333,11 @@ int spl_vm_run_once(spl_vm_t *vm) {
_v &= _mask;
}
PUSH(_v);
break;
DISPATCH();
}
case SPL_SEXT: {
L_SPL_SEXT:
{
spl_vm_val_t _v = POP();
intptr_t _bits = ins->imm;
if (_bits < 1 || _bits > 64)
@@ -1246,10 +1350,11 @@ int spl_vm_run_once(spl_vm_t *vm) {
_v |= ~_mask;
}
PUSH(_v);
break;
DISPATCH();
}
case SPL_ZEXT: {
L_SPL_ZEXT:
{
spl_vm_val_t _v = POP();
intptr_t _bits = ins->imm;
if (_bits < 1 || _bits > 64)
@@ -1257,11 +1362,12 @@ int spl_vm_run_once(spl_vm_t *vm) {
if (_bits < 64)
_v &= ((spl_vm_val_t)1 << _bits) - 1;
PUSH(_v);
break;
DISPATCH();
}
/* ========== Native Interface ========== */
case SPL_NCALL: {
/* ========== Native Interface ========== */
L_SPL_NCALL:
{
intptr_t _nargs = ins->imm;
spl_vm_val_t _nat_idx = POP();
spl_vm_native_t *_nat;
@@ -1287,10 +1393,11 @@ int spl_vm_run_once(spl_vm_t *vm) {
}
vm->sp -= _nargs;
PUSH(_result);
break;
DISPATCH();
}
case SPL_NLIB: {
L_SPL_NLIB:
{
spl_vm_val_t _si = ins->imm;
const char *_lib;
if (_si >= vec_size(prog->strtab) || !vec_at(prog->strtab, _si))
@@ -1303,11 +1410,12 @@ int spl_vm_run_once(spl_vm_t *vm) {
} else {
PUSH(_handle);
}
break;
DISPATCH();
}
/* ========== Debug ========== */
case SPL_DBG: {
/* ========== Debug ========== */
L_SPL_DBG:
{
fprintf(stderr, "---DGB: current ip %zu---\n", vm->ip);
spl_vm_dump_instr(vm, vm->ip - 6);
spl_vm_dump_instr(vm, vm->ip - 5);
@@ -1320,44 +1428,26 @@ int spl_vm_run_once(spl_vm_t *vm) {
spl_vm_backtrace(vm, vm->fp);
spl_vm_stackdump(vm, vm->sp);
fprintf(stderr, "---DGB END ---\n");
break;
DISPATCH();
}
case SPL_BK: {
L_SPL_BK:
{
return 2; /* breakpoint: pause execution */
}
default:
fprintf(stderr, "vm: unknown opcode %d at ip=%zd\n", ins->opcode, vm->ip - 1);
vm->exit_code = 1;
return -1;
}
/* canary check in debug mode (canary is at fp-1, invisible to compiled code) */
if (vm->debug && vm->fp > 0) {
if (STACK_CANARY(vm) != SPL_STACK_CANARY) {
snprintf(vm->error_msg, sizeof(vm->error_msg),
"STACK CANARY CORRUPTED at ip=%zd, fp=%zd\n", vm->ip - 1, vm->fp);
VM_ERROR(vm->error_msg);
}
}
return 0;
L_default:
fprintf(stderr, "vm: unknown opcode %d at ip=%zd\n", ins->opcode, vm->ip - 1);
vm->exit_code = 1;
return -1;
}
int spl_vm_run_once(spl_vm_t *vm) { return vm_loop(vm, 1); }
int spl_vm_run_until(spl_vm_t *vm, size_t step) {
size_t _count = 0;
int _ret;
if (!vm)
return -1;
while (1) {
if (step > 0 && _count >= step)
return 0;
_ret = spl_vm_run_once(vm);
if (_ret != 0)
return _ret;
_count++;
}
return vm_loop(vm, step ? step : (size_t)-1);
}
static const char *func_name_by_ip(spl_prog_t *prog, spl_vm_val_t ip) {