2023-12-09 17:24:41 +00:00
|
|
|
#include "vm.h"
|
|
|
|
#include "lib/commons.h"
|
2023-12-15 18:30:20 +00:00
|
|
|
#include "lib/mod.h"
|
2023-12-11 17:01:22 +00:00
|
|
|
#include "lib/type.h"
|
2023-12-15 20:32:17 +00:00
|
|
|
#include "lib/tysy.h"
|
2023-12-20 19:54:58 +00:00
|
|
|
#include "program.h"
|
|
|
|
#include "value.h"
|
2023-12-09 17:24:41 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err)
|
2023-12-09 17:24:41 +00:00
|
|
|
{
|
|
|
|
assert(vm);
|
2023-12-17 18:10:17 +00:00
|
|
|
assert(sym);
|
|
|
|
assert(tysy);
|
2023-12-09 17:24:41 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame = NULL;
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_frame_push(vm, NULL);
|
2023-12-11 17:01:22 +00:00
|
|
|
|
2023-12-15 18:30:20 +00:00
|
|
|
vm->tysy = tysy;
|
2023-12-11 17:01:22 +00:00
|
|
|
vm->err = err;
|
2023-12-09 17:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void vm_free(vm_t* vm)
|
|
|
|
{
|
|
|
|
assert(vm);
|
2023-12-17 18:10:17 +00:00
|
|
|
|
|
|
|
while (vm_frame_pop(vm))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
if (vm->top_frame)
|
|
|
|
{
|
|
|
|
vm_frame_free(vm->top_frame);
|
|
|
|
free(vm->top_frame);
|
|
|
|
}
|
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void vm_frame_init(frame_t* frame)
|
|
|
|
{
|
|
|
|
assert(frame);
|
|
|
|
|
|
|
|
frame->pc = 0;
|
|
|
|
frame->bp = 0;
|
|
|
|
frame->sp = 0;
|
|
|
|
|
|
|
|
frame->prev = NULL;
|
2023-12-20 19:54:58 +00:00
|
|
|
frame->program = NULL;
|
2023-12-17 18:10:17 +00:00
|
|
|
frame->locals.cap = 0;
|
|
|
|
frame->locals.size = 0;
|
|
|
|
frame->locals.data = NULL;
|
2023-12-20 19:54:58 +00:00
|
|
|
|
|
|
|
frame->alloc.cap = 0;
|
|
|
|
frame->alloc.size = 0;
|
|
|
|
frame->alloc.data = NULL;
|
2023-12-17 18:10:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void vm_frame_free(frame_t* frame)
|
|
|
|
{
|
|
|
|
for (size_t i=0; i<frame->locals.size; i++)
|
|
|
|
{
|
|
|
|
free(frame->locals.data[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(frame->locals.data);
|
|
|
|
frame->locals.data = NULL;
|
|
|
|
frame->locals.size = 0;
|
|
|
|
frame->locals.cap = 0;
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
//vm_clear_alloc(frame);
|
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
if (frame->prev != NULL)
|
|
|
|
{
|
|
|
|
vm_frame_free((frame_t*) frame->prev);
|
|
|
|
frame->prev = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
void vm_frame_push(vm_t* vm, program_t* program)
|
2023-12-17 18:10:17 +00:00
|
|
|
{
|
|
|
|
assert(vm);
|
|
|
|
|
|
|
|
frame_t* frame = malloc(sizeof(frame_t));
|
|
|
|
vm_frame_init(frame);
|
|
|
|
|
|
|
|
frame->prev = (struct frame*) vm->top_frame;
|
2023-12-20 19:54:58 +00:00
|
|
|
frame->program = program;
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame = frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
int vm_frame_pop(vm_t* vm)
|
|
|
|
{
|
|
|
|
assert(vm);
|
|
|
|
|
|
|
|
if (vm->top_frame)
|
|
|
|
{
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_clear_alloc(vm->top_frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vm->top_frame && vm->top_frame->prev)
|
|
|
|
{
|
|
|
|
frame_t* prev = (frame_t*) vm->top_frame->prev;
|
|
|
|
vm->top_frame->prev = NULL;
|
|
|
|
|
|
|
|
vm_frame_free(vm->top_frame);
|
|
|
|
free(vm->top_frame);
|
|
|
|
|
|
|
|
vm->top_frame = prev;
|
2023-12-17 18:10:17 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
local_t* vm_try_local_load(vm_t* vm, int id)
|
|
|
|
{
|
|
|
|
assert(vm);
|
|
|
|
|
|
|
|
for (size_t i=0; i<vm->top_frame->locals.size; i++)
|
|
|
|
{
|
|
|
|
if (vm->top_frame->locals.data[i]->id == id)
|
|
|
|
{
|
|
|
|
return vm->top_frame->locals.data[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void vm_local_store(vm_t* vm, int id, param_t addr)
|
|
|
|
{
|
|
|
|
assert(vm);
|
|
|
|
local_t* loc = vm_try_local_load(vm, id);
|
|
|
|
|
|
|
|
if (!loc)
|
|
|
|
{
|
|
|
|
if (vm->top_frame->locals.data == NULL)
|
|
|
|
{
|
|
|
|
vm->top_frame->locals.cap = 2;
|
|
|
|
vm->top_frame->locals.data = malloc(sizeof(local_t*)
|
|
|
|
* vm->top_frame->locals.cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vm->top_frame->locals.size >= vm->top_frame->locals.cap)
|
|
|
|
{
|
|
|
|
vm->top_frame->locals.cap *= 2;
|
|
|
|
vm->top_frame->locals.data = realloc(vm->top_frame->locals.data,
|
|
|
|
sizeof(local_t*)
|
|
|
|
* vm->top_frame->locals.cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->top_frame->locals.data[vm->top_frame->locals.size]
|
|
|
|
= malloc(sizeof(local_t));
|
|
|
|
|
|
|
|
vm->top_frame->locals.data[vm->top_frame->locals.size]->id = id;
|
|
|
|
vm->top_frame->locals.data[vm->top_frame->locals.size]->addr = addr;
|
|
|
|
vm->top_frame->locals.size++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
loc->id = id;
|
|
|
|
loc->addr = addr;
|
|
|
|
}
|
2023-12-09 17:24:41 +00:00
|
|
|
}
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
void vm_push_new(vm_t* vm, value_t* value)
|
2023-12-15 18:30:20 +00:00
|
|
|
{
|
|
|
|
assert(value);
|
2023-12-20 19:54:58 +00:00
|
|
|
vm->top_frame->stack[vm->top_frame->sp] = value;
|
2023-12-15 18:30:20 +00:00
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push_alloc(vm->top_frame, value);
|
|
|
|
|
|
|
|
vm->top_frame->sp++;
|
2023-12-15 18:30:20 +00:00
|
|
|
}
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
void vm_push(vm_t* vm, value_t* value)
|
2023-12-15 18:30:20 +00:00
|
|
|
{
|
2023-12-20 19:54:58 +00:00
|
|
|
assert(value);
|
|
|
|
vm->top_frame->stack[vm->top_frame->sp] = value;
|
|
|
|
vm->top_frame->allocated[vm->top_frame->sp] = 0;
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->sp++;
|
2023-12-15 18:30:20 +00:00
|
|
|
}
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* vm_pop(vm_t* vm)
|
2023-12-11 17:01:22 +00:00
|
|
|
{
|
|
|
|
assert(vm);
|
2023-12-20 19:54:58 +00:00
|
|
|
|
|
|
|
if (vm->top_frame->sp == 0)
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1];
|
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->sp--;
|
2023-12-11 17:01:22 +00:00
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
return val;
|
2023-12-11 17:01:22 +00:00
|
|
|
}
|
|
|
|
|
2023-12-09 17:24:41 +00:00
|
|
|
size_t vm_stack_str(vm_t* vm, char* buffer, size_t size)
|
|
|
|
{
|
|
|
|
assert(vm);
|
|
|
|
assert(buffer);
|
|
|
|
|
|
|
|
size_t sz = 0;
|
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
if (vm->top_frame->sp == 0)
|
2023-12-09 17:24:41 +00:00
|
|
|
{
|
2023-12-17 18:10:17 +00:00
|
|
|
sz += snprintf(buffer + sz, size - sz, "** empty **\n");
|
|
|
|
return sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=0; i<vm->top_frame->sp; i++)
|
|
|
|
{
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1 - i];
|
|
|
|
|
|
|
|
sz += snprintf(buffer + sz, size - sz, "| ");
|
|
|
|
value_str(val, buffer + sz, size - sz);
|
|
|
|
sz += snprintf(buffer + sz, size - sz, " |");
|
2023-12-09 17:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return sz;
|
|
|
|
}
|
|
|
|
|
2023-12-11 20:12:02 +00:00
|
|
|
int vm_exec_mod(vm_t* vm, mod_t* mod)
|
2023-12-09 17:24:41 +00:00
|
|
|
{
|
|
|
|
assert(vm);
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc = 0;
|
2023-12-20 19:54:58 +00:00
|
|
|
vm->top_frame->program = &mod->program;
|
2023-12-09 17:24:41 +00:00
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
while (vm->top_frame->pc < vm->top_frame->program->size)
|
2023-12-09 17:24:41 +00:00
|
|
|
{
|
2023-12-20 19:54:58 +00:00
|
|
|
program_t* program = vm->top_frame->program;
|
|
|
|
|
2023-12-11 17:01:22 +00:00
|
|
|
int status = vm_exec_instr(vm,
|
2023-12-20 19:54:58 +00:00
|
|
|
program->ops[vm->top_frame->pc],
|
|
|
|
program->params[vm->top_frame->pc]);
|
2023-12-11 17:01:22 +00:00
|
|
|
|
2023-12-11 20:12:02 +00:00
|
|
|
if (status != 0)
|
2023-12-11 17:01:22 +00:00
|
|
|
{
|
2023-12-11 20:12:02 +00:00
|
|
|
return status;
|
2023-12-11 17:01:22 +00:00
|
|
|
}
|
2023-12-09 17:24:41 +00:00
|
|
|
}
|
2023-12-11 20:12:02 +00:00
|
|
|
|
|
|
|
return 0;
|
2023-12-09 17:24:41 +00:00
|
|
|
}
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
int vm_exec_instr(vm_t* vm, Opcode op, param_t param)
|
2023-12-09 17:24:41 +00:00
|
|
|
{
|
|
|
|
assert(vm);
|
|
|
|
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case OP_PUSH: {
|
2023-12-17 18:10:17 +00:00
|
|
|
if (vm->top_frame->sp + 1 >= RZ_STACK_LIMIT)
|
2023-12-09 17:24:41 +00:00
|
|
|
{
|
|
|
|
fprintf(stderr, "Stack overflow\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* val = (value_t*) vm->top_frame->program->values.data[param];
|
|
|
|
vm_push(vm, val);
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-09 17:24:41 +00:00
|
|
|
} break;
|
|
|
|
|
2023-12-11 17:01:22 +00:00
|
|
|
case OP_ASSERT: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* value = vm_pop(vm);
|
2023-12-11 17:01:22 +00:00
|
|
|
|
|
|
|
if (value->type->kind != TYPE_BOOL)
|
|
|
|
{
|
2023-12-15 20:32:17 +00:00
|
|
|
vm_ensure_type(vm, value, TYPE_BOOL);
|
2023-12-11 17:01:22 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-11 17:01:22 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!value->value.bool)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "\33[31mASSERT\33[0m[:%d] assertion failed\n",
|
|
|
|
value->line);
|
2023-12-11 20:12:02 +00:00
|
|
|
return -1;
|
2023-12-11 17:01:22 +00:00
|
|
|
}
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push(vm, value);
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-11 17:01:22 +00:00
|
|
|
|
|
|
|
} break;
|
|
|
|
|
2023-12-15 18:30:20 +00:00
|
|
|
case OP_NE:
|
|
|
|
case OP_EQ: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* rhs = vm_pop(vm);
|
|
|
|
value_t* lhs = vm_pop(vm);
|
2023-12-15 18:30:20 +00:00
|
|
|
|
|
|
|
int same_type = lhs->type->kind == rhs->type->kind;
|
2023-12-15 18:45:47 +00:00
|
|
|
int eq = value_eq(lhs, rhs);
|
2023-12-15 18:30:20 +00:00
|
|
|
|
|
|
|
value_t* res = tysy_new_bool(vm->tysy,
|
|
|
|
(op == OP_EQ
|
|
|
|
? (same_type && eq)
|
|
|
|
: (!same_type || !eq)),
|
|
|
|
rhs->line);
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push_new(vm, res);
|
2023-12-15 18:30:20 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-15 18:30:20 +00:00
|
|
|
} break;
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
case OP_LT:
|
2023-12-15 20:32:17 +00:00
|
|
|
case OP_LE:
|
|
|
|
case OP_GT:
|
|
|
|
case OP_GE: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* rhs = vm_pop(vm);
|
|
|
|
value_t* lhs = vm_pop(vm);
|
2023-12-15 20:32:17 +00:00
|
|
|
|
|
|
|
vm_ensure_type(vm, lhs, TYPE_NUM);
|
|
|
|
vm_ensure_type(vm, rhs, TYPE_NUM);
|
|
|
|
|
|
|
|
int val = 0;
|
|
|
|
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case OP_LT: val = lhs->value.num < rhs->value.num; break;
|
|
|
|
case OP_LE: val = lhs->value.num <= rhs->value.num; break;
|
|
|
|
case OP_GT: val = lhs->value.num > rhs->value.num; break;
|
|
|
|
case OP_GE: val = lhs->value.num >= rhs->value.num; break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push_new(vm, res);
|
2023-12-15 20:32:17 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-15 20:32:17 +00:00
|
|
|
} break;
|
|
|
|
|
2023-12-15 21:31:01 +00:00
|
|
|
case OP_ADD:
|
|
|
|
case OP_SUB:
|
|
|
|
case OP_MUL:
|
|
|
|
case OP_DIV:
|
|
|
|
case OP_MODULO:
|
|
|
|
case OP_POW: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* rhs = vm_pop(vm);
|
|
|
|
value_t* lhs = vm_pop(vm);
|
2023-12-15 21:31:01 +00:00
|
|
|
|
|
|
|
vm_ensure_type(vm, lhs, TYPE_NUM);
|
|
|
|
vm_ensure_type(vm, rhs, TYPE_NUM);
|
|
|
|
|
|
|
|
double val = 0;
|
|
|
|
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case OP_ADD: val = lhs->value.num + rhs->value.num; break;
|
|
|
|
case OP_SUB: val = lhs->value.num - rhs->value.num; break;
|
|
|
|
case OP_MUL: val = lhs->value.num * rhs->value.num; break;
|
|
|
|
case OP_DIV: val = lhs->value.num / rhs->value.num; break;
|
|
|
|
case OP_MODULO: val = fmod(lhs->value.num, rhs->value.num); break;
|
|
|
|
case OP_POW: val = powf(lhs->value.num, rhs->value.num); break;
|
|
|
|
default: assert(0); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push_new(vm, res);
|
2023-12-16 18:42:26 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-16 18:42:26 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case OP_STRCAT: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* rhs = vm_pop(vm);
|
|
|
|
value_t* lhs = vm_pop(vm);
|
2023-12-16 18:42:26 +00:00
|
|
|
|
|
|
|
vm_ensure_type(vm, lhs, TYPE_STR);
|
|
|
|
vm_ensure_type(vm, rhs, TYPE_STR);
|
|
|
|
|
|
|
|
str_t res;
|
|
|
|
str_init(&res);
|
|
|
|
str_append(&res, lhs->value.str);
|
|
|
|
str_append(&res, rhs->value.str);
|
|
|
|
|
|
|
|
value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line);
|
|
|
|
str_free(&res);
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push_new(vm, value);
|
2023-12-16 18:42:26 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-16 18:42:26 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case OP_STRDUP: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* rhs = vm_pop(vm);
|
|
|
|
value_t* lhs = vm_pop(vm);
|
2023-12-16 18:42:26 +00:00
|
|
|
|
|
|
|
if (lhs->type->kind != TYPE_NUM)
|
|
|
|
{
|
|
|
|
value_t* tmp = lhs;
|
|
|
|
lhs = rhs;
|
|
|
|
rhs = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
vm_ensure_type(vm, lhs, TYPE_NUM);
|
|
|
|
vm_ensure_type(vm, rhs, TYPE_STR);
|
|
|
|
|
|
|
|
str_t res;
|
|
|
|
str_init(&res);
|
|
|
|
|
|
|
|
for (int i=0; i<(int) lhs->value.num; i++)
|
|
|
|
{
|
|
|
|
str_append(&res, rhs->value.str);
|
|
|
|
}
|
|
|
|
|
|
|
|
value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line);
|
|
|
|
str_free(&res);
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push_new(vm, value);
|
2023-12-15 21:31:01 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-16 18:12:20 +00:00
|
|
|
} break;
|
|
|
|
|
2023-12-15 21:31:01 +00:00
|
|
|
case OP_USUB: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* lhs = vm_pop(vm);
|
2023-12-15 21:31:01 +00:00
|
|
|
|
|
|
|
vm_ensure_type(vm, lhs, TYPE_NUM);
|
|
|
|
|
|
|
|
double val = -lhs->value.num;
|
|
|
|
|
|
|
|
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push_new(vm, res);
|
2023-12-15 21:31:01 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-15 21:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
2023-12-16 18:12:20 +00:00
|
|
|
case OP_NOT: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* lhs = vm_pop(vm);
|
2023-12-16 18:12:20 +00:00
|
|
|
vm_ensure_type(vm, lhs, TYPE_BOOL);
|
|
|
|
|
|
|
|
int val = !lhs->value.bool;
|
|
|
|
|
|
|
|
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
2023-12-20 19:54:58 +00:00
|
|
|
vm_push_new(vm, res);
|
2023-12-16 18:12:20 +00:00
|
|
|
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-16 18:12:20 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case OP_BRT:
|
|
|
|
case OP_BRF: {
|
2023-12-20 19:54:58 +00:00
|
|
|
value_t* value = vm_pop(vm);
|
|
|
|
|
2023-12-16 18:12:20 +00:00
|
|
|
vm_ensure_type(vm, value, TYPE_BOOL);
|
|
|
|
|
|
|
|
if (op == OP_BRT && value->value.bool)
|
|
|
|
{
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc = param;
|
2023-12-16 18:12:20 +00:00
|
|
|
}
|
|
|
|
else if (op == OP_BRF && !value->value.bool)
|
|
|
|
{
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc = param;
|
2023-12-16 18:12:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc++;
|
2023-12-16 18:12:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case OP_BR: {
|
2023-12-17 18:10:17 +00:00
|
|
|
vm->top_frame->pc = param;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case OP_LOAD: {
|
|
|
|
local_t* local = vm_try_local_load(vm, param);
|
|
|
|
|
|
|
|
if (!local)
|
|
|
|
{
|
|
|
|
char msg[RZ_STR_LIMIT];
|
|
|
|
|
|
|
|
snprintf(msg, RZ_STR_LIMIT, "Cannot load local variable '%d'.",
|
|
|
|
param);
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
if (vm->top_frame->sp == 0)
|
|
|
|
{
|
|
|
|
err_fatal(vm->err, msg, -1);
|
|
|
|
err_dump(vm->err);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1];
|
|
|
|
int line = val->line;
|
|
|
|
|
|
|
|
err_fatal(vm->err, msg, line);
|
|
|
|
err_dump(vm->err);
|
|
|
|
abort();
|
|
|
|
}
|
2023-12-17 18:10:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vm_push(vm, vm->top_frame->stack[local->addr]);
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->top_frame->pc++;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case OP_STORE: {
|
|
|
|
assert(vm->top_frame->sp > 0);
|
|
|
|
vm_local_store(vm, param, vm->top_frame->sp - 1);
|
|
|
|
vm->top_frame->pc++;
|
2023-12-16 18:12:20 +00:00
|
|
|
} break;
|
|
|
|
|
2023-12-20 19:54:58 +00:00
|
|
|
case OP_CALL: {
|
|
|
|
size_t const ARG_SZ = param;
|
|
|
|
value_t* args[ARG_SZ];
|
|
|
|
|
|
|
|
fun_t* fun = vm_pop(vm)->value.fun;
|
|
|
|
|
|
|
|
for (size_t i=0; i<ARG_SZ; i++)
|
|
|
|
{
|
|
|
|
value_t* val = vm_pop(vm);
|
|
|
|
args[ARG_SZ - 1 - i] = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->top_frame->pc++;
|
|
|
|
vm_frame_push(vm, &fun->program);
|
|
|
|
|
|
|
|
for (size_t i=0; i<ARG_SZ; i++)
|
|
|
|
{
|
|
|
|
value_t* arg = args[i];
|
|
|
|
|
|
|
|
vm_push(vm, arg);
|
|
|
|
vm_local_store(vm, i, vm->top_frame->sp - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case OP_RET: {
|
|
|
|
|
|
|
|
frame_t* frame = (frame_t*) vm->top_frame;
|
|
|
|
frame_t* prev = (frame_t*) vm->top_frame->prev;
|
|
|
|
|
|
|
|
value_t* ret = frame->stack[frame->sp - 1];
|
|
|
|
prev->stack[prev->sp] = ret;
|
|
|
|
prev->sp++;
|
|
|
|
|
|
|
|
for (size_t i=0; i<frame->alloc.size; i++)
|
|
|
|
{
|
|
|
|
if (frame->alloc.data[i] == ret)
|
|
|
|
{
|
|
|
|
frame->alloc.data[i] = NULL;
|
|
|
|
vm_push_alloc(prev, ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vm_frame_pop(vm);
|
|
|
|
} break;
|
|
|
|
|
2023-12-09 17:24:41 +00:00
|
|
|
default: {
|
|
|
|
fprintf(stderr, "Cannot execute unknown opcode '%s'.\n",
|
|
|
|
OpcodeStr[op]);
|
|
|
|
abort();
|
|
|
|
};
|
|
|
|
}
|
2023-12-11 17:01:22 +00:00
|
|
|
|
2023-12-11 20:12:02 +00:00
|
|
|
return 0;
|
2023-12-09 17:24:41 +00:00
|
|
|
}
|
2023-12-15 20:32:17 +00:00
|
|
|
|
|
|
|
void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want)
|
|
|
|
{
|
|
|
|
assert(vm);
|
|
|
|
assert(value);
|
2023-12-20 19:54:58 +00:00
|
|
|
|
2023-12-15 20:32:17 +00:00
|
|
|
TypeKind got = value->type->kind;
|
|
|
|
int line = value->line;
|
|
|
|
|
|
|
|
if (got != want)
|
|
|
|
{
|
|
|
|
char msg[RZ_STR_LIMIT];
|
|
|
|
snprintf(msg, RZ_STR_LIMIT,
|
|
|
|
"type mismatch: %s expected, got %s.",
|
|
|
|
TypeKindStr[want] + strlen("TYPE_"),
|
|
|
|
TypeKindStr[got] + strlen("TYPE_"));
|
|
|
|
|
|
|
|
err_fatal(vm->err, msg, line);
|
2023-12-16 18:42:26 +00:00
|
|
|
err_dump(vm->err);
|
2023-12-15 20:32:17 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-20 19:54:58 +00:00
|
|
|
|
|
|
|
void vm_push_alloc(frame_t* frame, value_t* value)
|
|
|
|
{
|
|
|
|
assert(frame);
|
|
|
|
assert(value);
|
|
|
|
|
|
|
|
if (frame->alloc.cap == 0)
|
|
|
|
{
|
|
|
|
frame->alloc.cap = 2;
|
|
|
|
frame->alloc.data = malloc(sizeof(value_t*) * frame->alloc.cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame->alloc.size >= frame->alloc.cap)
|
|
|
|
{
|
|
|
|
frame->alloc.cap *= 2;
|
|
|
|
frame->alloc.data = realloc(frame->alloc.data,
|
|
|
|
sizeof(value_t*) * frame->alloc.cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
frame->alloc.data[frame->alloc.size] = value;
|
|
|
|
frame->alloc.size++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void vm_clear_alloc(frame_t* frame)
|
|
|
|
{
|
|
|
|
assert(frame);
|
|
|
|
for (size_t i=0; i<frame->alloc.size; i++)
|
|
|
|
{
|
|
|
|
value_t* val = frame->alloc.data[i];
|
|
|
|
|
|
|
|
if (val)
|
|
|
|
{
|
|
|
|
value_free(val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(frame->alloc.data);
|
|
|
|
frame->alloc.data = NULL;
|
|
|
|
}
|