lang/vm.c

94 lines
2.0 KiB
C

#include "vm.h"
#include "runtime.h"
#include "util.h"
#define INIT_STACK_CAP 256
typedef struct Stack {
Value *mem;
size_t len, cap;
} Stack;
static Stack stack_make(void);
static void stack_term(Stack *s);
static void stack_fit(Stack *s, size_t idx);
static Stack stack_make(void) {
Stack s;
s.mem = xmalloc(sizeof(Value) * INIT_STACK_CAP);
s.cap = INIT_STACK_CAP;
s.len = 0;
return s;
}
static void stack_term(Stack *s) {
free(s->mem);
}
static void stack_fit(Stack *s, size_t idx) {
size_t size = idx+1;
if (size > s->cap) {
s->mem = xrealloc(s->mem, sizeof(Value) * (size + (s->cap *= 2)));
}
}
static Value *irparam_to_val(Stack *s, IRParam *v) {
if (v->kind == IRParamLiteral)
return &v->Literal;
else if (v->kind == IRParamAddr)
return &s->mem[v->Addr];
else
ASSERT_UNREACHED();
}
void run(const IRToks *ir, const BuiltinFunc *builtin_funcs) {
Stack s = stack_make();
for (size_t i = 0; i < ir->len;) {
IRTok *instr = &ir->toks[i];
switch (instr->instr) {
case IRSet:
case IRNeg:
stack_fit(&s, instr->Unary.addr);
s.mem[instr->Unary.addr] = eval_unary(instr->instr, irparam_to_val(&s, &instr->Unary.val));
break;
case IRAdd:
case IRSub:
case IRDiv:
case IRMul:
stack_fit(&s, instr->Arith.addr);
s.mem[instr->Arith.addr] = eval_arith(instr->instr,
irparam_to_val(&s, &instr->Arith.lhs),
irparam_to_val(&s, &instr->Arith.rhs)
);
break;
case IRJmp:
i = instr->Jmp.iaddr;
continue;
case IRJnz:
if (is_nonzero(irparam_to_val(&s, &instr->CJmp.condition))) {
i = instr->Jmp.iaddr;
continue;
}
break;
case IRCallInternal: {
const BuiltinFunc *f = &builtin_funcs[instr->CallI.fid];
Value *args = xmalloc(sizeof(Value) * f->n_args);
for (size_t i = 0; i < f->n_args; i++)
args[i] = *irparam_to_val(&s, &instr->CallI.args[i]);
stack_fit(&s, instr->CallI.ret_addr);
s.mem[instr->CallI.ret_addr] = f->func(args);
free(args);
break;
}
default:
ASSERT_UNREACHED();
}
i++;
}
stack_term(&s);
}