Compare commits
9 Commits
29dd9abb3f
...
ed84a65757
| Author | SHA1 | Date | |
|---|---|---|---|
|
ed84a65757
|
|||
|
26efd110f1
|
|||
|
dd96f95d77
|
|||
|
70cbb003f2
|
|||
|
665982049d
|
|||
|
195d154474
|
|||
|
26d935e22a
|
|||
|
a4966a057c
|
|||
|
b3ce4fa0ed
|
@@ -36,4 +36,24 @@ public:
|
|||||||
void execute(context& ctx, const command_info& info) override;
|
void execute(context& ctx, const command_info& info) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class continue_command final : public command {
|
||||||
|
public:
|
||||||
|
void execute(context& ctx, const command_info& info) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class next_command final : public command {
|
||||||
|
public:
|
||||||
|
void execute(context& ctx, const command_info& info) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class break_command final : public command {
|
||||||
|
public:
|
||||||
|
void execute(context& ctx, const command_info& info) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class info_command final : public command {
|
||||||
|
public:
|
||||||
|
void execute(context& ctx, const command_info& info) override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // COMMAND_HPP
|
#endif // COMMAND_HPP
|
||||||
|
|||||||
@@ -13,8 +13,14 @@ struct context {
|
|||||||
furvm::function_h mainFunction;
|
furvm::function_h mainFunction;
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
bool halt = true;
|
||||||
|
|
||||||
|
void kill() const;
|
||||||
|
void init();
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
void print_instruction() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTEXT_HPP
|
#endif // CONTEXT_HPP
|
||||||
|
|||||||
+137
-1
@@ -1,9 +1,16 @@
|
|||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
|
|
||||||
|
#include "furvm/executor.hpp"
|
||||||
|
#include "furvm/function.hpp"
|
||||||
|
#include "furvm/instruction.hpp"
|
||||||
|
#include "furvm/module.hpp"
|
||||||
|
#include "furvm/thing.hpp"
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
command_info command::parse(std::string_view line) {
|
command_info command::parse(std::string_view line) {
|
||||||
@@ -50,6 +57,135 @@ void quit_command::execute(context& ctx, const command_info& info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void run_command::execute(context& ctx, const command_info& info) {
|
void run_command::execute(context& ctx, const command_info& info) {
|
||||||
|
if (!ctx.executor->done()) {
|
||||||
|
std::cout << "A program is currently running, do you want to kill it? (y/N) ";
|
||||||
|
std::string answer;
|
||||||
|
if (!std::getline(std::cin, answer)) {
|
||||||
|
ctx.running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (answer != "y" && answer != "Y" && answer != "yes") return;
|
||||||
|
ctx.kill();
|
||||||
|
}
|
||||||
|
std::cout << "Running the program\n";
|
||||||
ctx.run();
|
ctx.run();
|
||||||
std::cout << "Execution finished\n";
|
}
|
||||||
|
|
||||||
|
void continue_command::execute(context& ctx, const command_info& info) {
|
||||||
|
ctx.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void next_command::execute(context& ctx, const command_info& info) {
|
||||||
|
if (ctx.executor->done()) {
|
||||||
|
std::cout << "No program's currently running\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.executor->unsuspend();
|
||||||
|
ctx.executor->step();
|
||||||
|
ctx.print_instruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_type(const furvm::thing_type& type) {
|
||||||
|
switch (type.type) {
|
||||||
|
case furvm::thing_type::S8: std::cout << "s8"; break;
|
||||||
|
case furvm::thing_type::S16: std::cout << "s16"; break;
|
||||||
|
case furvm::thing_type::S32: std::cout << "s32"; break;
|
||||||
|
case furvm::thing_type::S64: std::cout << "s64"; break;
|
||||||
|
case furvm::thing_type::U8: std::cout << "u8"; break;
|
||||||
|
case furvm::thing_type::U16: std::cout << "u16"; break;
|
||||||
|
case furvm::thing_type::U32: std::cout << "u32"; break;
|
||||||
|
case furvm::thing_type::U64: std::cout << "u64"; break;
|
||||||
|
case furvm::thing_type::Ptr: std::cout << "ptr"; break;
|
||||||
|
case furvm::thing_type::Ref: std::cout << "ref"; break;
|
||||||
|
case furvm::thing_type::Array:
|
||||||
|
std::cout << "array(";
|
||||||
|
print_type(*type.value.array.type);
|
||||||
|
std::cout << ", ";
|
||||||
|
if (type.value.array.size == 0)
|
||||||
|
std::cout << "dynamic";
|
||||||
|
else
|
||||||
|
std::cout << type.value.array.size;
|
||||||
|
std::cout << ")";
|
||||||
|
break;
|
||||||
|
case furvm::thing_type::Count: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_thing(const furvm::thing<>& thing) {
|
||||||
|
std::cout << '(';
|
||||||
|
print_type(thing.type());
|
||||||
|
std::cout << ") ";
|
||||||
|
switch (thing.type().type) {
|
||||||
|
case furvm::thing_type::S8: std::cout << std::to_string(thing.get<furvm::thing_type::s8>()); break;
|
||||||
|
case furvm::thing_type::S16: std::cout << thing.get<furvm::thing_type::s16>(); break;
|
||||||
|
case furvm::thing_type::S32: std::cout << thing.get<furvm::thing_type::s32>(); break;
|
||||||
|
case furvm::thing_type::S64: std::cout << thing.get<furvm::thing_type::s64>(); break;
|
||||||
|
case furvm::thing_type::U8: std::cout << std::to_string(thing.get<furvm::thing_type::u8>()); break;
|
||||||
|
case furvm::thing_type::U16: std::cout << thing.get<furvm::thing_type::u16>(); break;
|
||||||
|
case furvm::thing_type::U32: std::cout << thing.get<furvm::thing_type::u32>(); break;
|
||||||
|
case furvm::thing_type::U64: std::cout << thing.get<furvm::thing_type::u64>(); break;
|
||||||
|
case furvm::thing_type::Ptr: std::cout << thing.get<const void*>(); break;
|
||||||
|
case furvm::thing_type::Array: {
|
||||||
|
if (thing.type().value.array.size == 0) std::cout << thing.length();
|
||||||
|
std::cout << "{ ";
|
||||||
|
for (std::size_t i = 0; i < thing.length(); ++i) {
|
||||||
|
if (i > 0) std::cout << ", ";
|
||||||
|
print_thing(thing.at(i));
|
||||||
|
}
|
||||||
|
std::cout << " }";
|
||||||
|
} break;
|
||||||
|
case furvm::thing_type::Ref:
|
||||||
|
case furvm::thing_type::Count: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void breakpoint_hit(furvm::executor& executor, void* data) {
|
||||||
|
std::cout << "Breakpoint hit\n";
|
||||||
|
context* ctx = reinterpret_cast<context*>(data);
|
||||||
|
ctx->halt = true;
|
||||||
|
|
||||||
|
ctx->print_instruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void break_command::execute(context& ctx, const command_info& info) {
|
||||||
|
if (info.args.empty()) {
|
||||||
|
std::cerr << "Usage: " << info.commandName << " <function name>\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t count = 0;
|
||||||
|
for (const auto& [id, sigPair] : ctx.mod->function_map()) {
|
||||||
|
if (sigPair.first != info.args[0]) continue;
|
||||||
|
const auto& func = ctx.mod->function_at(id);
|
||||||
|
if (func->type() != furvm::function_t::Normal) continue;
|
||||||
|
count += 1;
|
||||||
|
ctx.mod->set_breakpoint(func->position(), furvm::breakpoint{ breakpoint_hit, &ctx });
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
std::cerr << "No function \"" << info.args[0] << "\" found!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::cout << "Breakpoint set in " << count << " places\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void info_command::execute(context& ctx, const command_info& info) {
|
||||||
|
if (info.args.empty()) {
|
||||||
|
std::cout << "Possible arguments:\n";
|
||||||
|
std::cout << "- variables\n";
|
||||||
|
} else if (info.args[0] == "variables") {
|
||||||
|
if (ctx.executor->frames().empty()) {
|
||||||
|
std::cerr << "Not running\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::cout << "Variables:\n";
|
||||||
|
const auto& frame = ctx.executor->top_frame();
|
||||||
|
for (std::size_t i = 0; i < frame.variables.size(); ++i) {
|
||||||
|
// TODO: Add debug information to modules
|
||||||
|
std::cout << "- %" << i << " = ";
|
||||||
|
print_thing(frame.variables[i]);
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cerr << "Unexpected argument \"" << info.args[0] << "\"\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+129
-3
@@ -1,9 +1,135 @@
|
|||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
|
|
||||||
|
#include <furvm/executor.hpp>
|
||||||
|
#include <furvm/instruction.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
void context::kill() const {
|
||||||
|
while (!executor->done())
|
||||||
|
executor->pop_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void context::init() {
|
||||||
|
kill();
|
||||||
|
executor->push_frame(mod, *mainFunction);
|
||||||
|
executor->clear_flags();
|
||||||
|
}
|
||||||
|
|
||||||
void context::run() {
|
void context::run() {
|
||||||
if ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done)
|
if (executor->done()) init();
|
||||||
executor->push_frame(mod, *mainFunction);
|
executor->unsuspend();
|
||||||
while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
|
||||||
|
halt = false;
|
||||||
|
while (!executor->done() && !halt)
|
||||||
executor->step();
|
executor->step();
|
||||||
|
if (executor->done()) {
|
||||||
|
std::cout << "Execution finished\n";
|
||||||
|
halt = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void context::print_instruction() const {
|
||||||
|
static const char* s_instrNames[furvm::instruction::Count] = {
|
||||||
|
// NoOperation
|
||||||
|
"nop",
|
||||||
|
// PushS8
|
||||||
|
"push $s8",
|
||||||
|
// PushU8
|
||||||
|
"push $u8",
|
||||||
|
// PushS16
|
||||||
|
"push $s16",
|
||||||
|
// PushU16
|
||||||
|
"push $U16",
|
||||||
|
// PushS32
|
||||||
|
"push $S32",
|
||||||
|
// PushU32
|
||||||
|
"push $U32",
|
||||||
|
// PushConstant
|
||||||
|
"push",
|
||||||
|
// Array
|
||||||
|
"array",
|
||||||
|
// Get
|
||||||
|
"get",
|
||||||
|
// Set
|
||||||
|
"set",
|
||||||
|
// Drop
|
||||||
|
"drop",
|
||||||
|
// Duplicate
|
||||||
|
"dup",
|
||||||
|
// Swap
|
||||||
|
"swap",
|
||||||
|
// Clone
|
||||||
|
"clone",
|
||||||
|
// Reference
|
||||||
|
"ref",
|
||||||
|
// Add
|
||||||
|
"add",
|
||||||
|
// Sub
|
||||||
|
"sub",
|
||||||
|
// Mul
|
||||||
|
"mul",
|
||||||
|
// Div
|
||||||
|
"div",
|
||||||
|
// Mod
|
||||||
|
"mod",
|
||||||
|
// Equals
|
||||||
|
"eq",
|
||||||
|
// NotEquals
|
||||||
|
"ne",
|
||||||
|
// LessThan
|
||||||
|
"lt",
|
||||||
|
// GreaterThan
|
||||||
|
"gt",
|
||||||
|
// LessEqual
|
||||||
|
"le",
|
||||||
|
// GreaterEqual
|
||||||
|
"ge",
|
||||||
|
// Pointerof
|
||||||
|
"pointerof",
|
||||||
|
// Sizeof
|
||||||
|
"sizeof",
|
||||||
|
// Lengthof
|
||||||
|
"lenof",
|
||||||
|
// Load
|
||||||
|
"load",
|
||||||
|
// Store
|
||||||
|
"store",
|
||||||
|
// LoadGlobal
|
||||||
|
"loadg",
|
||||||
|
// StoreGlobal
|
||||||
|
"storeg",
|
||||||
|
// Call
|
||||||
|
"call",
|
||||||
|
// Jump
|
||||||
|
"jmp",
|
||||||
|
// JumpNotZero
|
||||||
|
"jnz",
|
||||||
|
// Return
|
||||||
|
"ret",
|
||||||
|
};
|
||||||
|
|
||||||
|
furvm::instruction instr{};
|
||||||
|
instr.read(mod->bytecode_view().subview(executor->top_frame().position));
|
||||||
|
std::cout << s_instrNames[instr.type];
|
||||||
|
if (instr.arg.type != furvm::instruction_argument_t::None) {
|
||||||
|
std::cout << ' ';
|
||||||
|
switch (instr.arg.type) {
|
||||||
|
case furvm::instruction_argument::S8: std::cout << std::to_string(instr.arg.s8); break;
|
||||||
|
case furvm::instruction_argument::U8: std::cout << std::to_string(instr.arg.u8); break;
|
||||||
|
case furvm::instruction_argument::S16: std::cout << instr.arg.s16; break;
|
||||||
|
case furvm::instruction_argument::U16: std::cout << instr.arg.u16; break;
|
||||||
|
case furvm::instruction_argument::S32: std::cout << instr.arg.s32; break;
|
||||||
|
case furvm::instruction_argument::U32: std::cout << instr.arg.u32; break;
|
||||||
|
case furvm::instruction_argument::None:
|
||||||
|
case furvm::instruction_argument::Count: break;
|
||||||
|
case furvm::instruction_argument::Constant: throw std::runtime_error("unimplemented");
|
||||||
|
case furvm::instruction_argument::Type: std::cout << "$__t" << instr.arg.u32; break;
|
||||||
|
case furvm::instruction_argument::Variable: std::cout << "%" << instr.arg.u16; break;
|
||||||
|
case furvm::instruction_argument::GlobalVariable: std::cout << "%__g" << instr.arg.u16; break;
|
||||||
|
case furvm::instruction_argument::Function: std::cout << "<a function>"; break;
|
||||||
|
case furvm::instruction_argument::Offset: std::cout << std::to_string(instr.arg.s8); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
|||||||
+5
-1
@@ -43,8 +43,12 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::unordered_map<std::string_view, command*> s_commands;
|
static std::unordered_map<std::string_view, command*> s_commands;
|
||||||
s_commands["quit"] = s_commands["q"] = new quit_command();
|
s_commands["exit"] = s_commands["quit"] = s_commands["q"] = new quit_command();
|
||||||
s_commands["run"] = s_commands["r"] = new run_command();
|
s_commands["run"] = s_commands["r"] = new run_command();
|
||||||
|
s_commands["continue"] = s_commands["c"] = new continue_command();
|
||||||
|
s_commands["next"] = s_commands["n"] = new next_command();
|
||||||
|
s_commands["break"] = s_commands["b"] = new break_command();
|
||||||
|
s_commands["info"] = s_commands["i"] = new info_command();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::ifstream file(argv[1], std::ios::binary | std::ios::in);
|
std::ifstream file(argv[1], std::ios::binary | std::ios::in);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
@@ -15,6 +14,8 @@ namespace furvm {
|
|||||||
enum class executor_flags : std::uint32_t {
|
enum class executor_flags : std::uint32_t {
|
||||||
Suspended = (1 << 0), /**< Execution suspended. */
|
Suspended = (1 << 0), /**< Execution suspended. */
|
||||||
Done = (1 << 1), /**< Execution is finished. */
|
Done = (1 << 1), /**< Execution is finished. */
|
||||||
|
|
||||||
|
JustHit = (1 << 16), /**< Executor just hit a breakpoint. */
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline executor_flags operator|(executor_flags lhs, executor_flags rhs) {
|
static inline executor_flags operator|(executor_flags lhs, executor_flags rhs) {
|
||||||
@@ -29,13 +30,15 @@ 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:
|
||||||
|
static constexpr executor_flags STATE_FLAGS = executor_flags::JustHit;
|
||||||
|
|
||||||
|
using new_frame_callback = std::function<void(executor&)>;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Executor frame.
|
* @brief Executor frame.
|
||||||
@@ -84,6 +87,17 @@ public:
|
|||||||
* @return The flags.
|
* @return The flags.
|
||||||
*/
|
*/
|
||||||
executor_flags flags() const { return m_flags; }
|
executor_flags flags() const { return m_flags; }
|
||||||
|
|
||||||
|
bool done() const { return (m_flags & executor_flags::Done) == executor_flags::Done; }
|
||||||
|
|
||||||
|
bool suspended() const { return (m_flags & executor_flags::Suspended) == executor_flags::Suspended; }
|
||||||
|
|
||||||
|
void unsuspend() { m_flags = m_flags & ~executor_flags::Suspended; }
|
||||||
|
|
||||||
|
void clear_flags() {
|
||||||
|
m_flags = m_flags & STATE_FLAGS;
|
||||||
|
m_flags = m_frames.empty() ? executor_flags::Done : furvm::executor_flags{ 0 };
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Pushes a new frame.
|
* @brief Pushes a new frame.
|
||||||
@@ -174,13 +188,13 @@ private:
|
|||||||
private:
|
private:
|
||||||
static bool compare_thing_types(const thing_type& lhs, const thing_type& rhs);
|
static bool compare_thing_types(const thing_type& lhs, const thing_type& rhs);
|
||||||
private:
|
private:
|
||||||
executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization)
|
executor_flags m_flags = executor_flags::Done;
|
||||||
context* m_context;
|
context* m_context;
|
||||||
|
|
||||||
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 = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -104,6 +104,13 @@ void executor::push_frame(const mod_h& mod, function function) {
|
|||||||
default: throw std::runtime_error("unexpected function type");
|
default: throw std::runtime_error("unexpected function type");
|
||||||
}
|
}
|
||||||
if (m_newFrameCb) m_newFrameCb(*this);
|
if (m_newFrameCb) m_newFrameCb(*this);
|
||||||
|
|
||||||
|
if (!m_frames.empty()) {
|
||||||
|
m_flags = m_flags & ~executor_flags::Done;
|
||||||
|
} else {
|
||||||
|
m_flags = m_flags | executor_flags::Done;
|
||||||
|
}
|
||||||
|
m_flags = m_flags & ~executor_flags::JustHit;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct executor::frame executor::pop_frame() {
|
struct executor::frame executor::pop_frame() {
|
||||||
@@ -117,6 +124,14 @@ struct executor::frame executor::pop_frame() {
|
|||||||
}
|
}
|
||||||
if (m_stack.size() != frame.stackBase) throw std::runtime_error("unexhausted stack");
|
if (m_stack.size() != frame.stackBase) throw std::runtime_error("unexhausted stack");
|
||||||
if (returnValue.has_value()) push_thing(std::move(returnValue.value()));
|
if (returnValue.has_value()) push_thing(std::move(returnValue.value()));
|
||||||
|
|
||||||
|
if (!m_frames.empty()) {
|
||||||
|
m_flags = m_flags & ~executor_flags::Done;
|
||||||
|
} else {
|
||||||
|
m_flags = m_flags | executor_flags::Done;
|
||||||
|
}
|
||||||
|
m_flags = m_flags & ~executor_flags::JustHit;
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +191,14 @@ void executor::step() {
|
|||||||
|
|
||||||
struct frame& frame = m_frames.top();
|
struct frame& frame = m_frames.top();
|
||||||
|
|
||||||
|
if ((m_flags & executor_flags::JustHit) != executor_flags::JustHit && frame.mod->has_breakpoint(frame.position)) {
|
||||||
|
m_flags = m_flags | executor_flags::Suspended | executor_flags::JustHit;
|
||||||
|
const auto& bp = frame.mod->breakpoint_at(frame.position);
|
||||||
|
bp.callback(*this, bp.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_flags = m_flags & ~executor_flags::JustHit;
|
||||||
|
|
||||||
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