142 lines
4.3 KiB
C++
142 lines
4.3 KiB
C++
#include "furvm/executor.hpp"
|
|
|
|
#include "furvm/context.hpp" // IWYU pragma: keep
|
|
#include "furvm/exceptions.hpp"
|
|
#include "furvm/function.hpp" // IWYU pragma: keep
|
|
#include "furvm/instruction.hpp"
|
|
#include "furvm/thing.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
namespace furvm {
|
|
|
|
executor::executor(egzekutor, executor_handle id, const context_p& context)
|
|
: m_id(id), m_context(context) {}
|
|
|
|
executor::~executor() {
|
|
m_context->m_executors[m_id] = nullptr;
|
|
}
|
|
|
|
executor_p executor::create(const context_p& context) {
|
|
auto ex = std::make_shared<executor>(egzekutor{}, context->m_executors.size(), context);
|
|
context->m_executors.push_back(ex);
|
|
return std::move(ex);
|
|
}
|
|
|
|
void executor::push_frame(const function_p& function) {
|
|
if (function->type() != function_t::Normal) return;
|
|
m_frames.emplace((struct executor::frame){ function->mod(), function->position(), m_stack.size() });
|
|
}
|
|
|
|
struct executor::frame executor::pop_frame() {
|
|
if (m_frames.empty()) throw stack_underflow();
|
|
struct executor::frame frame = m_frames.top();
|
|
m_frames.pop();
|
|
return frame;
|
|
}
|
|
|
|
struct executor::frame executor::frame() const {
|
|
return m_frames.top();
|
|
}
|
|
|
|
void executor::push_thing(const thing_p& thing) {
|
|
thing->add_reference();
|
|
m_stack.push(thing);
|
|
}
|
|
|
|
void executor::push_thing(thing_p&& thing) {
|
|
thing->add_reference();
|
|
m_stack.push(std::move(thing));
|
|
}
|
|
|
|
thing_p executor::pop_thing() {
|
|
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
|
|
thing_p top = std::move(m_stack.top());
|
|
m_stack.pop();
|
|
top->remove_reference();
|
|
return top;
|
|
}
|
|
|
|
thing_p executor::thing() const {
|
|
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
|
|
return m_stack.top();
|
|
}
|
|
|
|
void executor::step() {
|
|
if ((m_flags & executor_flags::Suspended) == executor_flags::Suspended) return;
|
|
|
|
struct frame& frame = m_frames.top();
|
|
|
|
instruction_t instr = static_cast<instruction_t>(frame.mod->byte(frame.position++));
|
|
switch (instr) {
|
|
case instruction_t::NoOperation: break;
|
|
case instruction_t::PushB2I: {
|
|
auto thing = thing::create(m_context, thing_t::Int32);
|
|
thing->int32() = frame.mod->byte(frame.position++);
|
|
push_thing(std::move(thing));
|
|
} break;
|
|
case instruction_t::Drop: {
|
|
pop_thing();
|
|
} break;
|
|
case instruction_t::Duplicate: {
|
|
push_thing(thing());
|
|
} break;
|
|
case instruction_t::Clone: {
|
|
push_thing(std::move(thing::clone(thing())));
|
|
} break;
|
|
case instruction_t::Add: {
|
|
auto rhs = pop_thing();
|
|
auto lhs = pop_thing();
|
|
push_thing(lhs + rhs);
|
|
} break;
|
|
case instruction_t::Sub: {
|
|
auto rhs = pop_thing();
|
|
auto lhs = pop_thing();
|
|
push_thing(lhs - rhs);
|
|
} break;
|
|
case instruction_t::Mul: {
|
|
auto rhs = pop_thing();
|
|
auto lhs = pop_thing();
|
|
push_thing(lhs * rhs);
|
|
} break;
|
|
case instruction_t::Div: {
|
|
auto rhs = pop_thing();
|
|
auto lhs = pop_thing();
|
|
push_thing(lhs / rhs);
|
|
} break;
|
|
case instruction_t::Mod: {
|
|
auto rhs = pop_thing();
|
|
auto lhs = pop_thing();
|
|
push_thing(lhs % rhs);
|
|
} break;
|
|
case instruction_t::Call: {
|
|
function_handle funcId = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
|
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
|
frame.position += 2;
|
|
|
|
const function_p& function = frame.mod->function_at(funcId);
|
|
switch (function->type()) {
|
|
case function_t::Normal: push_frame(function); break;
|
|
case function_t::Native: function->native()(*this); break;
|
|
case function_t::Import: {
|
|
const mod_p& impMod = m_context->m_modules.at(function->imported_module());
|
|
push_frame(impMod->function_at(function->imported_function()));
|
|
} break;
|
|
}
|
|
} break;
|
|
case instruction_t::Return: {
|
|
pop_frame();
|
|
if (m_frames.empty()) m_flags = m_flags | executor_flags::Done;
|
|
} break;
|
|
case instruction_t::ReturnValue: {
|
|
auto value = pop_thing();
|
|
pop_frame();
|
|
push_thing(std::move(value));
|
|
} break;
|
|
case instruction_t::PushConstant: throw std::runtime_error("unimplemented");
|
|
default: throw std::runtime_error("unknown instruction");
|
|
}
|
|
}
|
|
|
|
} // namespace furvm
|