#include "VM.hpp" #include "Function.hpp" #include "Code.hpp" #include "lib/Opcodes.hpp" namespace jk { /*explicit*/ VM::VM() { } /*virtual*/ VM::~VM() { } void VM::execute(std::shared_ptr program) { Frame frame; frame.program = program; m_frames.push_back(frame); while (m_pc < m_frames.back().program->size()) { Instr instr = m_frames.back().program->get(m_pc); switch (instr.opcode) { case OPCODE_MK_FUNCTION: { auto code = program->constant(pop()); auto function = std::make_shared (code->as_code()->foreign()); auto value = Value::make_function(function); size_t addr = push_heap(value); auto ref = Value::make_ref(addr); push(program->push_constant(ref)); m_pc++; } break; case OPCODE_PUSH_CONST: { push(*instr.param); m_pc++; } break; case OPCODE_LOAD: { auto value = m_frames.back().locals[*instr.param]; push(program->push_constant(value)); m_pc++; } break; case OPCODE_STORE: { auto idx = pop(); m_frames.back().locals[*instr.param] = program->constant(idx); m_pc++; } break; case OPCODE_LOAD_GLOBAL: { auto value = m_globals[*instr.param]; push(program->push_constant(value)); m_pc++; } break; case OPCODE_CALL: { std::vector> args; for (size_t i=0; i<*instr.param; i++) { args.insert(std::begin(args), program->constant(pop())); } auto ref_val = program->constant(pop()); auto ref = ref_val->as_ref(); auto fun_val = heap(ref); auto fun = fun_val->as_function(); auto result = fun->call(args); push(program->push_constant(result)); m_pc++; } break; default: std::cerr << "cannot execute unknown opcode " << OpcodeTypeStr[instr.opcode] << std::endl; abort(); } } } std::string VM::string() const { std::stringstream ss; for (size_t i=0; i value) { m_heap.push_back(value); return m_heap.size() - 1; } std::shared_ptr VM::heap(size_t addr) { assert(addr < m_heap.size()); return m_heap[addr]; } void VM::set_global(size_t addr, std::shared_ptr value) { m_globals[addr] = value; } void VM::push(param_t param) { m_stack.push_back(param); } param_t VM::pop() { auto param = m_stack.back(); m_stack.pop_back(); return param; } }