stage2 大量优化代码使其自举编译时间大幅缩短
This commit is contained in:
1 parent
e02b0c633a
commit
846f441e3a
38 files changed
+2418
-835
No files matched your search
+292
-202
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user