2023-09-17 19:36:58 +00:00
|
|
|
#include "VM.hpp"
|
|
|
|
#include "src/Program.hpp"
|
|
|
|
|
|
|
|
namespace zn
|
|
|
|
{
|
2023-09-18 15:33:04 +00:00
|
|
|
/*explicit*/ VM::VM(Program& program)
|
2023-09-17 19:36:58 +00:00
|
|
|
{
|
2023-09-18 15:33:04 +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);
|
2023-09-18 15:33:04 +00:00
|
|
|
execute(program, instr.opcode, instr.param);
|
2023-09-17 19:36:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-18 15:33:04 +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;
|
|
|
|
|
2023-09-18 15:33:04 +00:00
|
|
|
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;
|
|
|
|
|
2023-09-18 15:33:04 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2023-09-18 15:33:04 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|