diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 6edb88a..45add42 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -7,7 +7,6 @@ #include #include -#include #include namespace furvm { @@ -29,13 +28,13 @@ static inline executor_flags operator~(executor_flags flags) { return executor_flags(~static_cast(flags)); } -using executor_callback = std::function; - class executor { friend class context; private: executor(context* context) : m_context(context) {} +public: + using new_frame_callback = std::function; public: /** * @brief Executor frame. @@ -180,7 +179,7 @@ private: std::stack m_frames; std::stack> m_stack; - executor_callback m_newFrameCb = nullptr; + new_frame_callback m_newFrameCb = nullptr; }; } // namespace furvm diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 1b95081..2f1faf8 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -145,6 +145,11 @@ struct mod_type { } }; +struct breakpoint { + std::function callback; + void* data; +}; + class mod { friend class function; friend class serializer; @@ -379,6 +384,15 @@ public: if (var >= m_globalVariables.size()) throw std::runtime_error("invalid slot"); return m_globalVariables[var]; } +public: + template >> + void set_breakpoint(bytecode_pos pos, Fwd&& breakpoint) { + m_breakpoints[pos] = std::forward(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: /** * @brief Prints the module in a bytecode form to an output stream. @@ -410,6 +424,8 @@ private: std::vector> m_globalVariables; std::unordered_map m_nativeFunctions; + + std::unordered_map m_breakpoints; }; } // namespace furvm diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index e3e42be..1a4a6a5 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -176,6 +176,13 @@ void executor::step() { 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{}; frame.position += instr.read(frame.mod->bytecode_view().subview(frame.position)); switch (instr.type) {