This repository has been archived on 2024-03-07. You can view files and clone it, but cannot push or open issues/pull-requests.
zarn/src/VM.cpp

157 lines
3.1 KiB
C++
Raw Normal View History

2023-09-17 19:36:58 +00:00
#include "VM.hpp"
#include "src/Program.hpp"
namespace zn
{
/*explicit*/ VM::VM(Program& program)
2023-09-17 19:36:58 +00:00
{
m_pc = 0;
Frame f = {program, {}};
m_frames.push_back(f);
2023-09-17 19:36:58 +00:00
}
/*virtual*/ VM::~VM()
{
}
void VM::execute(Program& program)
{
m_pc = 0;
while (m_pc < program.size())
{
auto instr = program.instr(m_pc);
execute(program, instr.opcode, instr.param);
2023-09-17 19:36:58 +00:00
}
}
void VM::execute(Program& program, Opcode opcode, int param)
2023-09-17 19:36:58 +00:00
{
switch (opcode)
{
case OPCODE_LOAD_CONST: {
push(param);
m_pc++;
} break;
case OPCODE_LOAD_LOCAL: {
auto constant = frame().locals[to_vm_addr(param)];
push(program.add_constant(constant));
m_pc++;
} break;
2023-09-17 19:36:58 +00:00
case OPCODE_POP: {
pop();
m_pc++;
} break;
case OPCODE_CALL_NATIVE: {
std::vector<std::shared_ptr<Constant>> args;
for (int i=0; i<param; i++)
{
size_t addr = pop();
args.insert(std::begin(args),
frame().program.constant(addr));
}
auto fun_ref = m_frames.back().program.constant(pop());
int ref = std::get<int>(*fun_ref->value());
auto fun = std::get<std::shared_ptr<NativeFunction>>
(m_globals[ref]);
assert(fun);
auto result = fun->call(args);
int addr = m_frames.back().program.add_constant(result);
push(addr);
m_pc++;
} break;
2023-09-17 19:36:58 +00:00
default: {
std::cerr << "cannot execute opcode '"
<< OpcodeStr[opcode]
<< "'" << std::endl;
abort();
} break;
}
}
std::string VM::string() const
{
std::stringstream ss;
ss << "======== VM Stack ========\n";
size_t addr = 0;
for (int val: m_stack)
{
ss << addr << " " << val << "\n";
addr++;
}
return ss.str();
}
size_t VM::store_local(int index, std::shared_ptr<Constant> constant)
{
frame().locals.push_back(constant);
size_t addr = frame().locals.size() - 1;
m_addr_mapping[index] = addr;
return addr;
}
std::shared_ptr<Constant> VM::load_local(int index) const
{
size_t addr = to_vm_addr(index);
assert(addr < m_frames.back().locals.size());
return m_frames.back().locals[addr];
}
size_t VM::store_global(global_var_t var)
{
m_globals.push_back(var);
return m_globals.size() - 1;
}
size_t VM::to_vm_addr(int user_addr) const
{
return m_addr_mapping.at(user_addr);
}
int VM::to_user_addr(size_t vm_addr) const
{
for (auto const& entry: m_addr_mapping)
{
if (entry.second == vm_addr)
{
return entry.first;
}
}
std::cerr << "cannot find user addr of '"
<< vm_addr << "'" << std::endl;
abort();
}
Frame& VM::frame()
{
return m_frames.back();
}
2023-09-17 19:36:58 +00:00
void VM::push(int value)
{
m_stack.push_back(value);
}
int VM::pop()
{
assert(m_stack.size() > 0);
int value = m_stack.back();
m_stack.pop_back();
return value;
}
}