2021-12-21 01:18:22 +01:00
|
|
|
#include "vm.h"
|
2021-12-22 17:23:24 +01:00
|
|
|
|
|
|
|
#include "runtime.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
2021-12-29 21:42:43 +01:00
|
|
|
#define INIT_STACK_CAP 128
|
2021-12-22 17:23:24 +01:00
|
|
|
|
|
|
|
typedef struct Stack {
|
|
|
|
Value *mem;
|
2021-12-29 21:42:43 +01:00
|
|
|
bool *holds_value;
|
2021-12-22 17:23:24 +01:00
|
|
|
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);
|
2021-12-29 21:42:43 +01:00
|
|
|
static void stack_assign(Stack *s, size_t idx, const Value *v);
|
2021-12-22 17:23:24 +01:00
|
|
|
|
|
|
|
static Stack stack_make(void) {
|
|
|
|
Stack s;
|
|
|
|
s.mem = xmalloc(sizeof(Value) * INIT_STACK_CAP);
|
2021-12-29 21:42:43 +01:00
|
|
|
s.holds_value = xmalloc(sizeof(bool) * INIT_STACK_CAP);
|
2021-12-22 17:23:24 +01:00
|
|
|
s.cap = INIT_STACK_CAP;
|
|
|
|
s.len = 0;
|
2021-12-29 21:42:43 +01:00
|
|
|
for (size_t i = 0; i < s.cap; i++)
|
|
|
|
s.holds_value[i] = false;
|
2021-12-22 17:23:24 +01:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stack_term(Stack *s) {
|
2021-12-29 21:42:43 +01:00
|
|
|
/* free any dynamically allocated objects still alive */
|
|
|
|
for (size_t i = 0; i < s->cap; i++) {
|
|
|
|
if (s->holds_value[i])
|
|
|
|
free_value(&s->mem[i], false);
|
|
|
|
}
|
|
|
|
/* free the stack memory itself */
|
2021-12-22 17:23:24 +01:00
|
|
|
free(s->mem);
|
2021-12-29 21:42:43 +01:00
|
|
|
free(s->holds_value);
|
2021-12-22 17:23:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void stack_fit(Stack *s, size_t idx) {
|
|
|
|
size_t size = idx+1;
|
|
|
|
if (size > s->cap) {
|
2021-12-29 21:42:43 +01:00
|
|
|
size_t new_cap = size + s->cap * 2;
|
|
|
|
s->mem = xrealloc(s->mem, sizeof(Value) * new_cap);
|
|
|
|
s->holds_value = xrealloc(s->holds_value, sizeof(bool) * new_cap);
|
|
|
|
for (size_t i = s->cap; i < new_cap; i++)
|
|
|
|
s->holds_value[i] = false;
|
|
|
|
s->cap = new_cap;
|
2021-12-22 17:23:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2021-12-29 21:42:43 +01:00
|
|
|
static void stack_assign(Stack *s, size_t idx, const Value *v) {
|
|
|
|
stack_fit(s, idx);
|
|
|
|
if (s->holds_value[idx])
|
|
|
|
free_value(&s->mem[idx], false); /* free any overwritten heap-allocated values */
|
|
|
|
s->mem[idx] = *v;
|
|
|
|
s->holds_value[idx] = true;
|
|
|
|
}
|
|
|
|
|
2021-12-29 13:27:58 +01:00
|
|
|
void run(IRList *ir, const BuiltinFunc *builtin_funcs) {
|
2021-12-23 17:00:57 +01:00
|
|
|
/* so we don't have to call malloc on every function call */
|
|
|
|
size_t fn_args_cap = 16;
|
|
|
|
Value *fn_args = xmalloc(sizeof(Value) * fn_args_cap);
|
|
|
|
|
2021-12-29 13:27:58 +01:00
|
|
|
/* so we can use index-based addressing */
|
|
|
|
irlist_update_index(ir);
|
|
|
|
|
2021-12-22 17:23:24 +01:00
|
|
|
Stack s = stack_make();
|
2021-12-29 13:27:58 +01:00
|
|
|
for (IRItem *i = ir->begin; i;) {
|
|
|
|
IRTok *instr = &i->tok;
|
2021-12-23 15:56:12 +01:00
|
|
|
err_ln = instr->ln;
|
|
|
|
err_col = instr->col;
|
2021-12-22 17:23:24 +01:00
|
|
|
switch (instr->instr) {
|
|
|
|
case IRSet:
|
|
|
|
case IRNeg:
|
2021-12-29 21:42:43 +01:00
|
|
|
case IRNot: {
|
|
|
|
Value res;
|
|
|
|
TRY_ELSE(res = eval_unary(instr->instr, irparam_to_val(&s, &instr->Unary.val)),
|
2021-12-23 17:00:57 +01:00
|
|
|
{free(fn_args); stack_term(&s);});
|
2021-12-29 21:42:43 +01:00
|
|
|
stack_assign(&s, instr->Unary.addr, &res);
|
2021-12-22 17:23:24 +01:00
|
|
|
break;
|
2021-12-29 21:42:43 +01:00
|
|
|
}
|
|
|
|
case IRAddrOf: {
|
2021-12-28 13:39:12 +01:00
|
|
|
if (instr->Unary.val.kind != IRParamAddr) {
|
2021-12-30 18:07:59 +01:00
|
|
|
set_err("Unable to take the address of a literal");
|
2021-12-30 17:59:28 +01:00
|
|
|
free(fn_args);
|
|
|
|
stack_term(&s);
|
2021-12-28 13:39:12 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
Value *v = &s.mem[instr->Unary.val.Addr];
|
2021-12-29 21:42:43 +01:00
|
|
|
Value res = {
|
2021-12-28 13:55:01 +01:00
|
|
|
.type = TypePtr,
|
2021-12-28 13:39:12 +01:00
|
|
|
.Ptr = {
|
2021-12-28 13:55:01 +01:00
|
|
|
.type = v->type,
|
2021-12-28 17:53:27 +01:00
|
|
|
.val = &v->Void,
|
2021-12-28 13:39:12 +01:00
|
|
|
},
|
|
|
|
};
|
2021-12-29 21:42:43 +01:00
|
|
|
stack_assign(&s, instr->Unary.addr, &res);
|
2021-12-28 13:39:12 +01:00
|
|
|
break;
|
2021-12-29 21:42:43 +01:00
|
|
|
}
|
2021-12-22 17:23:24 +01:00
|
|
|
case IRAdd:
|
|
|
|
case IRSub:
|
|
|
|
case IRDiv:
|
|
|
|
case IRMul:
|
2021-12-23 21:06:49 +01:00
|
|
|
case IREq:
|
2021-12-26 12:19:54 +01:00
|
|
|
case IRNeq:
|
2021-12-23 21:06:49 +01:00
|
|
|
case IRLt:
|
|
|
|
case IRLe:
|
2021-12-23 21:42:09 +01:00
|
|
|
case IRAnd:
|
2021-12-29 21:42:43 +01:00
|
|
|
case IROr: {
|
|
|
|
Value res;
|
|
|
|
TRY_ELSE(res = eval_binary(instr->instr,
|
2021-12-23 20:10:02 +01:00
|
|
|
irparam_to_val(&s, &instr->Binary.lhs),
|
|
|
|
irparam_to_val(&s, &instr->Binary.rhs)),
|
2021-12-23 17:00:57 +01:00
|
|
|
{free(fn_args); stack_term(&s);});
|
2021-12-29 21:42:43 +01:00
|
|
|
stack_assign(&s, instr->Binary.addr, &res);
|
2021-12-22 17:23:24 +01:00
|
|
|
break;
|
2021-12-29 21:42:43 +01:00
|
|
|
}
|
2021-12-22 17:23:24 +01:00
|
|
|
case IRJmp:
|
2021-12-29 21:42:43 +01:00
|
|
|
if (instr->Jmp.iaddr < ir->len)
|
|
|
|
i = ir->index[instr->Jmp.iaddr];
|
|
|
|
else
|
|
|
|
i = NULL;
|
2021-12-22 17:23:24 +01:00
|
|
|
continue;
|
|
|
|
case IRJnz:
|
|
|
|
if (is_nonzero(irparam_to_val(&s, &instr->CJmp.condition))) {
|
2021-12-29 21:42:43 +01:00
|
|
|
if (instr->Jmp.iaddr < ir->len)
|
|
|
|
i = ir->index[instr->CJmp.iaddr];
|
|
|
|
else
|
|
|
|
i = NULL;
|
2021-12-22 17:23:24 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IRCallInternal: {
|
|
|
|
const BuiltinFunc *f = &builtin_funcs[instr->CallI.fid];
|
2021-12-28 13:39:12 +01:00
|
|
|
size_t n_args = instr->CallI.n_args;
|
2021-12-23 17:00:57 +01:00
|
|
|
/* make sure enough space for our arguments is allocated */
|
2021-12-28 13:39:12 +01:00
|
|
|
if (n_args > fn_args_cap)
|
|
|
|
fn_args = xrealloc(fn_args, sizeof(Value) * (fn_args_cap = n_args));
|
2021-12-23 17:00:57 +01:00
|
|
|
/* copy arguments into buffer */
|
2021-12-28 13:39:12 +01:00
|
|
|
for (size_t i = 0; i < n_args; i++)
|
2021-12-23 17:00:57 +01:00
|
|
|
fn_args[i] = *irparam_to_val(&s, &instr->CallI.args[i]);
|
2021-12-22 17:23:24 +01:00
|
|
|
|
2021-12-28 13:39:12 +01:00
|
|
|
if (f->returns) {
|
2021-12-29 21:42:43 +01:00
|
|
|
Value res;
|
2021-12-28 13:39:12 +01:00
|
|
|
if (f->kind == FuncVarArgs) {
|
|
|
|
size_t min_args = f->VarArgs.min_args;
|
2021-12-29 21:42:43 +01:00
|
|
|
TRY_ELSE(res = f->VarArgs.WithRet.func(n_args - min_args, fn_args),
|
2021-12-28 13:39:12 +01:00
|
|
|
{free(fn_args); stack_term(&s);});
|
|
|
|
} else if (f->kind == FuncFixedArgs) {
|
2021-12-29 21:42:43 +01:00
|
|
|
TRY_ELSE(res = f->FixedArgs.WithRet.func(fn_args),
|
2021-12-28 13:39:12 +01:00
|
|
|
{free(fn_args); stack_term(&s);});
|
|
|
|
} else
|
|
|
|
ASSERT_UNREACHED();
|
2021-12-29 21:42:43 +01:00
|
|
|
stack_assign(&s, instr->CallI.ret_addr, &res);
|
2021-12-28 13:39:12 +01:00
|
|
|
} else {
|
|
|
|
if (f->kind == FuncVarArgs) {
|
|
|
|
size_t min_args = f->VarArgs.min_args;
|
|
|
|
TRY_ELSE(f->VarArgs.NoRet.func(n_args - min_args, fn_args),
|
|
|
|
{free(fn_args); stack_term(&s);});
|
|
|
|
} else if (f->kind == FuncFixedArgs) {
|
|
|
|
TRY_ELSE(f->FixedArgs.NoRet.func(fn_args),
|
|
|
|
{free(fn_args); stack_term(&s);});
|
|
|
|
} else
|
|
|
|
ASSERT_UNREACHED();
|
|
|
|
}
|
2021-12-22 17:23:24 +01:00
|
|
|
break;
|
|
|
|
}
|
2021-12-30 17:59:28 +01:00
|
|
|
case IRArrMake: {
|
|
|
|
size_t arr_len = instr->ArrMake.len, arr_cap = instr->ArrMake.cap;
|
|
|
|
Value arr = {
|
|
|
|
.type = TypeArr,
|
|
|
|
.Arr = {
|
|
|
|
.type = TypeVoid,
|
|
|
|
.is_string = false,
|
|
|
|
.dynamically_allocated = true,
|
|
|
|
.vals = NULL,
|
|
|
|
.len = arr_len,
|
|
|
|
.cap = arr_len ? arr_cap : 0,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
if (arr_len) {
|
|
|
|
Type arr_ty = irparam_to_val(&s, &instr->ArrMake.vals[0])->type;
|
|
|
|
void *arr_vals = xmalloc(type_size[arr_ty] * arr_cap);
|
|
|
|
for (size_t j = 0; j < arr_len; j++) {
|
|
|
|
Value *v = irparam_to_val(&s, &instr->ArrMake.vals[j]);
|
|
|
|
if (v->type != arr_ty) {
|
2021-12-30 18:07:59 +01:00
|
|
|
set_err("Type of array item %zu (%s) differs from array type (%s)", j, type_str[v->type], type_str[arr_ty]);
|
2021-12-30 17:59:28 +01:00
|
|
|
free(arr_vals);
|
|
|
|
free(fn_args);
|
|
|
|
stack_term(&s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memcpy((uint8_t*)arr_vals + type_size[arr_ty] * j, &v->Void, type_size[arr_ty]);
|
|
|
|
}
|
|
|
|
arr.Arr.type = arr_ty;
|
|
|
|
arr.Arr.vals = arr_vals;
|
|
|
|
}
|
|
|
|
stack_assign(&s, instr->ArrMake.arr_addr, &arr);
|
|
|
|
break;
|
|
|
|
}
|
2021-12-22 17:23:24 +01:00
|
|
|
default:
|
|
|
|
ASSERT_UNREACHED();
|
|
|
|
}
|
|
|
|
|
2021-12-29 13:27:58 +01:00
|
|
|
i = i->next;
|
2021-12-22 17:23:24 +01:00
|
|
|
}
|
|
|
|
stack_term(&s);
|
2021-12-23 17:00:57 +01:00
|
|
|
free(fn_args);
|
2021-12-22 17:23:24 +01:00
|
|
|
}
|