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
|
|
|
}
|
|
|
|
|
2021-04-07 01:05:41 +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;
|
2021-04-07 01:05:41 +03:00
|
|
|
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;
|
2021-04-07 01:05:41 +03:00
|
|
|
default:
|
2021-04-07 22:24:33 +03:00
|
|
|
return -ERR_OPCODE_UNDEFINED;
|
2021-04-07 01:05:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2021-04-07 00:03:42 +03:00
|
|
|
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) {
|
2021-04-07 00:03:42 +03:00
|
|
|
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);
|
2021-04-07 00:03:42 +03:00
|
|
|
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:
|
2021-04-07 00:03:42 +03:00
|
|
|
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:
|
2021-04-07 00:03:42 +03:00
|
|
|
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));
|
2021-04-07 00:03:42 +03:00
|
|
|
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);
|
2021-04-07 01:05:41 +03:00
|
|
|
//
|
|
|
|
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
|
|
|
}
|