From 7ec7124d0136200f3f463fc9877dedaa3a117145 Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Tue, 19 Nov 2019 19:56:18 -0800 Subject: [PATCH] Implement CALLONJUMP and SJUMP instructions Add support for scenario functions (functions which clear the call stack upon entry and never return). --- instructions.c | 4 ++-- vm.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/instructions.c b/instructions.c index c4b6c90..410fd28 100644 --- a/instructions.c +++ b/instructions.c @@ -146,8 +146,8 @@ const struct instruction instructions[NR_OPCODES] = { OP(FUNC, 1, INSTR_FUN), OP(_EOF, 1, INSTR_FILE), OP(CALLSYS, 1, INSTR_INT), - OP(SJUMP, 0), // TODO - OP(CALLONJUMP, 0), // TODO + JMP(SJUMP, 0), + OP(CALLONJUMP, 0), OP(SWAP, 0), OP(SH_STRUCTREF, 1, INSTR_INT), OP(S_LENGTH, 0), diff --git a/vm.c b/vm.c index 28bdf90..2225585 100644 --- a/vm.c +++ b/vm.c @@ -253,6 +253,49 @@ union vm_value vm_copy(union vm_value v, enum ain_data_type type) } } +static int get_function_by_name(const char *name) +{ + for (int i = 0; i < ain->nr_functions; i++) { + if (!strcmp(name, ain->functions[i].name)) + return i; + } + return -1; +} + +static int alloc_scenario_page(const char *fname) +{ + int fno, slot; + struct ain_function *f; + + if ((fno = get_function_by_name(fname)) < 0) + VM_ERROR("Invalid scenario function: %s", fname); + f = &ain->functions[fno]; + + slot = heap_alloc_slot(VM_PAGE); + heap[slot].page = alloc_page(LOCAL_PAGE, fno, f->nr_vars); + for (int i = 0; i < f->nr_vars; i++) { + heap[slot].page->values[i] = variable_initval(f->vars[i].data_type); + } + return slot; +} + +static void scenario_call(int slot) +{ + int fno = heap[slot].page->index; + // flush call stack + for (int i = call_stack_ptr - 1; i >= 0; i--) { + heap_unref(call_stack[i].page_slot); + } + call_stack[0] = (struct function_call) { + .fno = fno, + .return_address = VM_RETURN, + .page_slot = slot, + .struct_page = -1 + }; + call_stack_ptr = 1; + instr_ptr = ain->functions[fno].address; +} + /* * System 4 calling convention: * - caller pushes arguments, in order @@ -572,6 +615,17 @@ static void execute_instruction(int16_t opcode) case CALLSYS: system_call(get_argument(0)); break; + case CALLONJUMP: + slot = stack_pop().i; + // XXX: I am GUESSING that the VM pre-allocates the scenario function's + // local page here. It certainly pushes what appears to be a page + // index to the stack. + stack_push(alloc_scenario_page(heap[slot].s->text)); + heap_unref(slot); + break; + case SJUMP: + scenario_call(stack_pop().i); + break; case JUMP: // ADDR instr_ptr = get_argument(0); break;