thesis-lisp/vm/vmstate.c

428 lines
11 KiB
C
Raw Normal View History

2021-04-07 22:24:33 +03:00
#include "error.h"
#include "op.h"
#include "unit.h"
2021-04-06 17:27:02 +03:00
#include "vmstate.h"
#include "vmval.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
static inline int64_t sximm(uint32_t in) {
if (in & 0x800000) {
return in | 0xFFFFFFFFFF000000;
} else {
return in;
}
}
2021-04-07 22:24:33 +03:00
static int vm_push_context(struct vm_state *vm) {
int res;
if ((res = stack_push(&vm->call_stack, vm->lp)) != 0) {
return res;
2021-04-06 17:27:02 +03:00
}
2021-04-07 22:24:33 +03:00
if ((res = stack_push(&vm->call_stack, vm->fp)) != 0) {
return res;
}
if ((res = stack_push(&vm->call_stack, vm->ip)) != 0) {
return res;
}
return 0;
2021-04-06 17:27:02 +03:00
}
2021-04-07 22:24:33 +03:00
static int vm_pop_context(struct vm_state *vm) {
int res;
if ((res = stack_pop(&vm->call_stack, &vm->ip)) != 0) {
return res;
2021-04-06 17:27:02 +03:00
}
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->call_stack, &vm->fp)) != 0) {
return res;
}
if ((res = stack_pop(&vm->call_stack, &vm->lp)) != 0) {
return res;
}
return 0;
2021-04-06 17:27:02 +03:00
}
2021-04-07 22:24:33 +03:00
int vm_state_init(struct vm_state *vm, size_t stack_size) {
int res;
2021-04-06 17:27:02 +03:00
2021-04-07 22:24:33 +03:00
if ((res = stack_init(&vm->data_stack, stack_size)) != 0) {
return res;
}
if ((res = stack_init(&vm->call_stack, 1024)) != 0) {
return res;
}
2021-04-06 18:22:12 +03:00
2021-04-07 16:19:30 +03:00
vector_init(&vm->units, sizeof(struct vm_unit));
2021-04-06 17:27:02 +03:00
2021-04-07 16:19:30 +03:00
vm->lp = 0;
2021-04-06 17:27:02 +03:00
vm->fp = 0;
vm->ip = 0;
2021-04-07 22:24:33 +03:00
return 0;
}
void vm_state_free(struct vm_state *vm) {
struct vm_unit *unit;
stack_free(&vm->data_stack);
stack_free(&vm->call_stack);
for (size_t i = 0; i < vm->units.size; ++i) {
unit = vector_ref(&vm->units, i);
unit_free(unit);
}
vector_free(&vm->units);
2021-04-06 17:27:02 +03:00
}
2021-04-07 16:19:30 +03:00
struct vm_unit *vm_add_unit(struct vm_state *vm, size_t global_pool_size) {
struct vm_unit *unit = vector_append(&vm->units);
2021-04-07 22:24:33 +03:00
if (!unit) {
return unit;
}
unit->is_loaded = 0;
2021-04-07 16:19:30 +03:00
unit->global_pool = calloc(sizeof(uint64_t), global_pool_size);
unit->global_pool_size = global_pool_size;
vector_init(&unit->ref_table, sizeof(struct vm_ref_entry));
vector_init(&unit->functions, sizeof(struct vm_func_entry));
return unit;
}
// Call an entry from function table of a unit
2021-04-07 22:24:33 +03:00
int vm_call_unit_index(struct vm_state *vm, size_t lib_index, size_t fn_index) {
2021-04-06 18:22:12 +03:00
struct vm_func_entry *func;
2021-04-07 16:19:30 +03:00
struct vm_unit *unit;
2021-04-07 22:24:33 +03:00
int res;
2021-04-07 16:19:30 +03:00
unit = vector_ref(&vm->units, lib_index);
func = vector_ref(&unit->functions, fn_index);
2021-04-06 18:22:12 +03:00
2021-04-07 22:24:33 +03:00
if (func->argc > MAXARG) {
return -ERR_RANGE;
}
if ((res = vm_push_context(vm)) != 0) {
return res;
}
2021-04-07 16:19:30 +03:00
vm->lp = lib_index;
vm->fp = fn_index;
2021-04-06 18:22:12 +03:00
vm->ip = 0;
for (size_t i = 0; i < func->argc; ++i) {
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &func->arg_regs[i])) != 0) {
return res;
}
2021-04-06 18:22:12 +03:00
}
2021-04-07 22:24:33 +03:00
return 0;
2021-04-06 18:22:12 +03:00
}
2021-04-07 22:24:33 +03:00
int vm_call_ref(struct vm_state *vm, struct vm_value *ref) {
if (ref->type != VT_FUNC) {
return -ERR_OPERAND_TYPE;
}
return vm_call_unit_index(vm, ref->v_func.lib_index, ref->v_func.fn_index);
2021-04-07 16:19:30 +03:00
}
2021-04-07 22:24:33 +03:00
static int vm_read_ext_ref(struct vm_state *vm, struct vm_ref_entry *ref, uint64_t *w) {
2021-04-07 16:19:30 +03:00
struct vm_unit *unit;
2021-04-07 22:24:33 +03:00
int res;
2021-04-07 16:19:30 +03:00
unit = vector_ref(&vm->units, ref->unit_index);
if (!unit->is_loaded) {
// Before trying to access target value, eval the unit first
2021-04-07 22:24:33 +03:00
if ((res = vm_eval_unit(vm, ref->unit_index)) != 0) {
return res;
}
2021-04-07 16:19:30 +03:00
}
assert(ref->ref_index < unit->global_pool_size);
2021-04-07 22:24:33 +03:00
if (ref->ref_index >= unit->global_pool_size) {
return -ERR_RANGE;
}
*w = unit->global_pool[ref->ref_index];
return 0;
2021-04-06 18:22:12 +03:00
}
static int vm_eval_debug(struct vm_state *vm, struct vm_func_entry *func, uint32_t arg) {
(void) func;
2021-04-07 16:19:30 +03:00
uint64_t w0;
2021-04-07 22:24:33 +03:00
int res;
switch (arg) {
2021-04-07 16:19:30 +03:00
case 0x01:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
}
2021-04-07 16:19:30 +03:00
printf("trace: ");
vm_print(w0);
printf("\n");
2021-04-07 23:21:02 +03:00
vm_unref(w0);
2021-04-07 16:19:30 +03:00
return 0;
default:
2021-04-07 22:24:33 +03:00
return -ERR_OPCODE_UNDEFINED;
}
}
2021-04-07 16:19:30 +03:00
int vm_eval_step(struct vm_state *vm) {
2021-04-06 17:27:02 +03:00
uint64_t w0, w1;
int64_t sw0, sw1;
2021-04-06 17:27:02 +03:00
ssize_t ii0;
2021-04-07 22:24:33 +03:00
size_t i0;
2021-04-06 17:27:02 +03:00
struct vm_ref_entry *r0;
2021-04-07 23:21:02 +03:00
struct vm_value *v0;
2021-04-07 22:24:33 +03:00
int res;
2021-04-06 17:27:02 +03:00
2021-04-07 16:19:30 +03:00
assert(vm->lp < vm->units.size);
struct vm_unit *unit = vector_ref(&vm->units, vm->lp);
assert(vm->fp < unit->functions.size);
struct vm_func_entry *func = vector_ref(&unit->functions, vm->fp);
uint32_t opcode = func->bytecode[vm->ip++];
2021-04-07 23:21:02 +03:00
printf("%02zx:%02zx:%02zx: %08x\n", vm->lp, vm->fp, vm->ip, opcode);
2021-04-06 17:27:02 +03:00
switch (opcode >> 24) {
case OP_ADD:
2021-04-07 22:24:33 +03:00
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
return res;
}
if ((res = vm_pop_integer(vm, &sw1)) != 0) {
return res;
}
return vm_push_integer(vm, sw0 + sw1);
2021-04-07 23:21:02 +03:00
case OP_SUB:
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
return res;
}
if ((res = vm_pop_integer(vm, &sw1)) != 0) {
return res;
}
return vm_push_integer(vm, sw0 - sw1);
2021-04-07 22:24:33 +03:00
case OP_MUL:
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
return res;
}
if ((res = vm_pop_integer(vm, &sw1)) != 0) {
return res;
}
return vm_push_integer(vm, sw0 * sw1);
2021-04-06 17:27:02 +03:00
case OP_NOT:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
2021-04-06 17:27:02 +03:00
}
2021-04-07 23:21:02 +03:00
res = vm_push_bool(vm, null_q(w0));
vm_unref(w0);
return res;
2021-04-06 18:22:12 +03:00
case OP_EQ:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
2021-04-06 18:22:12 +03:00
}
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w1)) != 0) {
return res;
2021-04-06 18:22:12 +03:00
}
2021-04-07 22:24:33 +03:00
if (ref_q(w0) || ref_q(w1)) {
// TODO what do?
return -ERR_OPERAND_TYPE;
}
2021-04-07 23:21:02 +03:00
res = vm_push_bool(vm, w0 == w1);
vm_unref(w0);
vm_unref(w1);
return res;
2021-04-06 17:27:02 +03:00
//
case OP_LDNIL:
2021-04-07 22:24:33 +03:00
return stack_push(&vm->data_stack, FLAG_REF);
2021-04-06 17:27:02 +03:00
case OP_LDI:
2021-04-07 22:24:33 +03:00
return vm_push_integer(vm, sximm(opcode & 0xFFFFFF));
2021-04-06 17:27:02 +03:00
case OP_CAR:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
}
if (!pair_q(w0)) {
return -ERR_OPERAND_TYPE;
}
2021-04-07 23:21:02 +03:00
vm_ref(getref(w0)->v_cons.fat_ar);
res = stack_push(&vm->data_stack, getref(w0)->v_cons.fat_ar);
vm_unref(w0);
return res;
2021-04-06 17:27:02 +03:00
case OP_CDR:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
}
if (!pair_q(w0)) {
return -ERR_OPERAND_TYPE;
}
2021-04-07 23:21:02 +03:00
vm_ref(getref(w0)->v_cons.fat_dr);
res = stack_push(&vm->data_stack, getref(w0)->v_cons.fat_dr);
vm_unref(w0);
return res;
2021-04-06 17:27:02 +03:00
case OP_CONS:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
}
if ((res = stack_pop(&vm->data_stack, &w1)) != 0) {
return res;
}
2021-04-07 23:21:02 +03:00
v0 = vm_cons(w0, w1);
vm_value_ref(v0);
res = vm_push_ref(vm, v0);
vm_unref(w0);
vm_unref(w1);
return res;
2021-04-06 17:27:02 +03:00
//
2021-04-06 18:22:12 +03:00
case OP_LDARG:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= MAXARG) {
return -ERR_RANGE;
}
2021-04-07 23:21:02 +03:00
w0 = func->arg_regs[i0];
vm_ref(w0);
return stack_push(&vm->data_stack, w0);
case OP_STARG:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= MAXARG) {
return -ERR_RANGE;
}
2021-04-07 23:21:02 +03:00
vm_unref(func->arg_regs[i0]);
2021-04-07 22:24:33 +03:00
return stack_pop(&vm->data_stack, &func->arg_regs[i0]);
2021-04-06 17:27:02 +03:00
case OP_LDG:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= unit->global_pool_size) {
return -ERR_RANGE;
}
2021-04-07 23:21:02 +03:00
w0 = unit->global_pool[i0];
vm_ref(w0);
return stack_push(&vm->data_stack, w0);
2021-04-06 17:27:02 +03:00
case OP_STG:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= unit->global_pool_size) {
return -ERR_RANGE;
}
2021-04-07 23:21:02 +03:00
vm_unref(unit->global_pool[i0]);
2021-04-07 22:24:33 +03:00
return stack_pop(&vm->data_stack, &unit->global_pool[i0]);
2021-04-06 18:22:12 +03:00
case OP_LDF:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= unit->functions.size) {
return -ERR_RANGE;
}
2021-04-07 23:21:02 +03:00
v0 = vm_func(vm->lp, i0);
vm_value_ref(v0);
return vm_push_ref(vm, v0);
2021-04-06 18:22:12 +03:00
case OP_STL:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= func->local_count) {
return -ERR_RANGE;
}
2021-04-07 23:21:02 +03:00
vm_unref(func->local_regs[i0]);
2021-04-07 22:24:33 +03:00
return stack_pop(&vm->data_stack, &func->local_regs[i0]);
2021-04-06 18:22:12 +03:00
case OP_LDL:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= func->local_count) {
return -ERR_RANGE;
}
2021-04-07 23:21:02 +03:00
w0 = func->local_regs[i0];
vm_ref(w0);
return stack_push(&vm->data_stack, w0);
2021-04-06 17:27:02 +03:00
//
2021-04-06 18:22:12 +03:00
case OP_ISZ:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
2021-04-06 17:27:02 +03:00
}
2021-04-07 23:21:02 +03:00
res = vm_push_bool(vm, null_q(w0));
vm_unref(w0);
return res;
2021-04-06 17:27:02 +03:00
//
case OP_XCALL:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= unit->ref_table.size) {
return -ERR_RANGE;
}
2021-04-07 16:19:30 +03:00
r0 = vector_ref(&unit->ref_table, i0);
if (r0->flags & REF_NATIVE) {
int (*func) (struct vm_state *) = (void *) r0->ref_native;
2021-04-07 22:24:33 +03:00
if (!func) {
return -ERR_OPERAND_TYPE;
}
2021-04-06 17:27:02 +03:00
return func(vm);
2021-04-07 16:19:30 +03:00
} else {
2021-04-07 22:24:33 +03:00
if ((res = vm_read_ext_ref(vm, r0, &w0)) != 0) {
return res;
}
if (!func_q(w0)) {
return -ERR_OPERAND_TYPE;
}
return vm_call_ref(vm, getref(w0));
2021-04-06 17:27:02 +03:00
}
2021-04-06 18:22:12 +03:00
case OP_GCALL:
i0 = opcode & 0xFFFFFF;
2021-04-07 22:24:33 +03:00
if (i0 >= unit->global_pool_size) {
return -ERR_RANGE;
}
2021-04-07 16:19:30 +03:00
w0 = unit->global_pool[i0];
2021-04-07 22:24:33 +03:00
if (!func_q(w0)) {
return -ERR_OPERAND_TYPE;
}
return vm_call_ref(vm, getref(w0));
case OP_CALL:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
}
if (!func_q(w0)) {
return -ERR_OPERAND_TYPE;
}
2021-04-07 23:21:02 +03:00
res = vm_call_ref(vm, getref(w0));
vm_unref(w0);
return res;
2021-04-06 17:27:02 +03:00
case OP_BF:
2021-04-07 22:24:33 +03:00
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
}
2021-04-06 17:27:02 +03:00
ii0 = sximm(opcode & 0xFFFFFF);
if (null_q(w0)) {
2021-04-07 22:24:33 +03:00
if (ii0 == 0) {
return -ERR_RANGE;
}
2021-04-06 17:27:02 +03:00
vm->ip += ii0 - 1;
}
2021-04-07 23:21:02 +03:00
vm_unref(w0);
2021-04-06 17:27:02 +03:00
return 0;
case OP_JMP:
ii0 = sximm(opcode & 0xFFFFFF);
2021-04-07 22:24:33 +03:00
if (ii0 == 0) {
return -ERR_RANGE;
}
2021-04-06 17:27:02 +03:00
vm->ip += ii0 - 1;
return 0;
case OP_RET:
2021-04-07 23:21:02 +03:00
// Drop references to arguments
for (size_t i = 0; i < func->argc; ++i) {
vm_unref(func->arg_regs[i]);
}
2021-04-07 22:24:33 +03:00
return vm_pop_context(vm);
//
case OP_DEBUG:
return vm_eval_debug(vm, func, opcode & 0xFFFFFF);
2021-04-06 17:27:02 +03:00
default:
2021-04-07 23:21:02 +03:00
fprintf(stderr, "Undefined opcode: %02x\n", opcode >> 24);
2021-04-07 22:24:33 +03:00
return -ERR_OPCODE_UNDEFINED;
2021-04-06 17:27:02 +03:00
}
}
2021-04-07 16:19:30 +03:00
int vm_eval_unit(struct vm_state *vm, size_t index) {
struct vm_unit *unit;
2021-04-07 22:24:33 +03:00
size_t csp;
int res;
2021-04-07 16:19:30 +03:00
unit = vector_ref(&vm->units, index);
2021-04-07 22:24:33 +03:00
csp = vm->call_stack.sp;
2021-04-07 16:19:30 +03:00
vm_call_unit_index(vm, index, 0);
2021-04-07 22:24:33 +03:00
2021-04-07 16:19:30 +03:00
// Run until return
2021-04-07 22:24:33 +03:00
while (vm->call_stack.sp != csp) {
if ((res = vm_eval_step(vm)) != 0) {
return res;
2021-04-07 16:19:30 +03:00
}
}
unit->is_loaded = 1;
return 0;
2021-04-06 17:27:02 +03:00
}