feat(furvm): add breakpoints
This commit is contained in:
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
@@ -29,13 +28,13 @@ static inline executor_flags operator~(executor_flags flags) {
|
|||||||
return executor_flags(~static_cast<std::uint32_t>(flags));
|
return executor_flags(~static_cast<std::uint32_t>(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
using executor_callback = std::function<void(executor&)>;
|
|
||||||
|
|
||||||
class executor {
|
class executor {
|
||||||
friend class context;
|
friend class context;
|
||||||
private:
|
private:
|
||||||
executor(context* context)
|
executor(context* context)
|
||||||
: m_context(context) {}
|
: m_context(context) {}
|
||||||
|
public:
|
||||||
|
using new_frame_callback = std::function<void(executor&)>;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Executor frame.
|
* @brief Executor frame.
|
||||||
@@ -180,7 +179,7 @@ private:
|
|||||||
std::stack<frame> m_frames;
|
std::stack<frame> m_frames;
|
||||||
std::stack<thing<>> m_stack;
|
std::stack<thing<>> m_stack;
|
||||||
|
|
||||||
executor_callback m_newFrameCb = nullptr;
|
new_frame_callback m_newFrameCb = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
@@ -145,6 +145,11 @@ struct mod_type {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct breakpoint {
|
||||||
|
std::function<void(executor&, void*)> callback;
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
class mod {
|
class mod {
|
||||||
friend class function;
|
friend class function;
|
||||||
friend class serializer;
|
friend class serializer;
|
||||||
@@ -379,6 +384,15 @@ public:
|
|||||||
if (var >= m_globalVariables.size()) throw std::runtime_error("invalid slot");
|
if (var >= m_globalVariables.size()) throw std::runtime_error("invalid slot");
|
||||||
return m_globalVariables[var];
|
return m_globalVariables[var];
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
template <typename Fwd, typename = std::enable_if_t<std::is_constructible_v<breakpoint, Fwd>>>
|
||||||
|
void set_breakpoint(bytecode_pos pos, Fwd&& breakpoint) {
|
||||||
|
m_breakpoints[pos] = std::forward<Fwd>(breakpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_breakpoint(bytecode_pos pos) const { return m_breakpoints.find(pos) != m_breakpoints.end(); }
|
||||||
|
|
||||||
|
const breakpoint& breakpoint_at(bytecode_pos pos) const { return m_breakpoints.at(pos); }
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Prints the module in a bytecode form to an output stream.
|
* @brief Prints the module in a bytecode form to an output stream.
|
||||||
@@ -410,6 +424,8 @@ private:
|
|||||||
std::vector<thing<>> m_globalVariables;
|
std::vector<thing<>> m_globalVariables;
|
||||||
|
|
||||||
std::unordered_map<std::string, native_function> m_nativeFunctions;
|
std::unordered_map<std::string, native_function> m_nativeFunctions;
|
||||||
|
|
||||||
|
std::unordered_map<bytecode_pos, breakpoint> m_breakpoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|||||||
@@ -176,6 +176,13 @@ void executor::step() {
|
|||||||
|
|
||||||
struct frame& frame = m_frames.top();
|
struct frame& frame = m_frames.top();
|
||||||
|
|
||||||
|
if (frame.mod->has_breakpoint(frame.position)) {
|
||||||
|
m_flags = m_flags | executor_flags::Suspended;
|
||||||
|
const auto& bp = frame.mod->breakpoint_at(frame.position);
|
||||||
|
bp.callback(*this, bp.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
instruction instr{};
|
instruction instr{};
|
||||||
frame.position += instr.read(frame.mod->bytecode_view().subview(frame.position));
|
frame.position += instr.read(frame.mod->bytecode_view().subview(frame.position));
|
||||||
switch (instr.type) {
|
switch (instr.type) {
|
||||||
|
|||||||
Reference in New Issue
Block a user