From b35a274e813a2dc5254740212a9a9afe3ec7c494 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 16 Jun 2026 11:25:41 +0200 Subject: [PATCH 01/30] refactor(furlang/ir): rename module to mod Refs: #12 --- furc/include/furc/front/ir_generator.hpp | 4 ++-- furc/include/furc/front/ssa.hpp | 2 +- furc/src/front/ssa.cpp | 2 +- furlang/include/furlang/ir/module.hpp | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/furc/include/furc/front/ir_generator.hpp b/furc/include/furc/front/ir_generator.hpp index ea3adba..ec745cf 100644 --- a/furc/include/furc/front/ir_generator.hpp +++ b/furc/include/furc/front/ir_generator.hpp @@ -22,7 +22,7 @@ public: ir_generator(const ir_generator&) = delete; ir_generator& operator=(const ir_generator&) = delete; public: - furlang::ir::module&& move_module() { return std::move(m_module); } + furlang::ir::mod&& move_module() { return std::move(m_module); } public: void visit(const ast::function_definition_node& funcDef) override; void visit(const ast::return_statement_node& returnStmt) override; @@ -45,7 +45,7 @@ private: furlang::ir::block_index push_block(bool validate = true); private: - furlang::ir::module m_module; + furlang::ir::mod m_module; std::unique_ptr m_currentFunction; std::shared_ptr m_currentBlock; ir_register m_registerCounter = 0; diff --git a/furc/include/furc/front/ssa.hpp b/furc/include/furc/front/ssa.hpp index 0c99b78..8d78683 100644 --- a/furc/include/furc/front/ssa.hpp +++ b/furc/include/furc/front/ssa.hpp @@ -16,7 +16,7 @@ namespace front { class ssa { using block_map_t = std::unordered_map>; public: - static void optimize(furlang::ir::module& mod); + static void optimize(furlang::ir::mod& mod); private: static void optimize(const std::unique_ptr& func); diff --git a/furc/src/front/ssa.cpp b/furc/src/front/ssa.cpp index 8fd8888..5c413ba 100644 --- a/furc/src/front/ssa.cpp +++ b/furc/src/front/ssa.cpp @@ -16,7 +16,7 @@ namespace furc::front { -void ssa::optimize(furlang::ir::module& mod) { +void ssa::optimize(furlang::ir::mod& mod) { for (const auto& func : mod.functions()) { ssa::optimize(func); ssa::constant_propagation(func); diff --git a/furlang/include/furlang/ir/module.hpp b/furlang/include/furlang/ir/module.hpp index 90e2a3f..2940bb8 100644 --- a/furlang/include/furlang/ir/module.hpp +++ b/furlang/include/furlang/ir/module.hpp @@ -12,11 +12,11 @@ namespace ir { /** * @brief IR module */ -class module { +class mod { public: using value_type = std::unique_ptr; /**< Value type. */ public: - module() = default; + mod() = default; public: /** * @brief Pushes and returns a new IR function. @@ -49,4 +49,4 @@ private: } // namespace ir } // namespace furlang -#endif // FURLANG_IR_MODULE_HPP \ No newline at end of file +#endif // FURLANG_IR_MODULE_HPP From 43dac1ec6dda4f9d1a6bcda54ebf63affabf0ad4 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 16 Jun 2026 12:04:02 +0200 Subject: [PATCH 02/30] refactor(furvm): refactor mod Refs: #12 --- furvm/include/furvm/context.hpp | 60 ++++++++++++++------------------ furvm/include/furvm/function.hpp | 19 +++++----- furvm/include/furvm/fwd.hpp | 5 --- furvm/include/furvm/module.hpp | 41 ++++++++++++++++++---- furvm/src/function.cpp | 21 ++++++++--- furvm/src/main.cpp | 2 +- 6 files changed, 90 insertions(+), 58 deletions(-) diff --git a/furvm/include/furvm/context.hpp b/furvm/include/furvm/context.hpp index f9ae6ae..a8397ef 100644 --- a/furvm/include/furvm/context.hpp +++ b/furvm/include/furvm/context.hpp @@ -6,7 +6,10 @@ #include "furvm/module.hpp" #include +#include #include +#include +#include #include namespace furvm { @@ -33,73 +36,64 @@ public: context& operator=(const context&) = delete; public: /** - * @brief Adds a module to this context. + * @brief Emplaces a new module in this context. * * @param args Arguments to forward to module's constructor. * @return An index to the emplaced module. */ - template >> - constexpr const auto& emplace(Args&&... args) { - module_handle id = static_cast(m_modules.size()); - return m_modules.emplace_back(std::make_unique(id, std::forward(args)...)); + template >> + auto& emplace_module(Args&&... args) { + mod_p mod = std::make_shared(std::forward(args)...); + return m_modules.emplace(mod->name(), std::move(mod)).first->second; } /** * @brief Erases a module from this context. * - * @param index Index to the module. - * @return Old value. + * @param name Name of the module to erase. + * @return A shared pointer to the erased module. */ - mod_p erase(module_handle index) { - if (index >= m_modules.size()) return nullptr; - return std::move(m_modules[index]); + template + mod_p erase_module(Name&& name) { + return std::move(m_modules.erase(std::forward(name))->second); } /** * @brief Returns a module of this context. * - * @param index Position of the module. + * @param name Name of the module. * @return The module. */ - constexpr mod_p& operator[](module_handle index) { return m_modules[index]; } + template + constexpr mod_p& module_at(Name&& name) { + return m_modules.at(std::forward(name)); + } /** * @brief Returns a module of this context. * - * @param index Position of the module. + * @param name Name of the module. * @return The module. */ - constexpr const mod_p& operator[](module_handle index) const { return m_modules[index]; } - - /** - * @brief Returns a module of this context. - * - * @param index Position of the module. - * @return The module. - */ - constexpr mod_p& at(module_handle index) { return m_modules.at(index); } - - /** - * @brief Returns a module of this context. - * - * @param index Position of the module. - * @return The module. - */ - constexpr const mod_p& at(module_handle index) const { return m_modules.at(index); } + template + constexpr const mod_p& module_at(Name&& name) const { + return m_modules.at(std::forward(name)); + } /** * @brief Returns how many does this context have modules. * * @return The module count. */ - constexpr size_t size() const { return m_modules.size(); } + constexpr size_t module_count() const { return m_modules.size(); } public: /** * @brief Removes unreferenced things from the thing list. */ void collect(); private: - std::vector m_modules; + std::unordered_map m_modules; + std::vector m_things; std::vector m_executors; @@ -110,4 +104,4 @@ private: } // namespace furvm -#endif // FURVM_CONTEXT_HPP \ No newline at end of file +#endif // FURVM_CONTEXT_HPP diff --git a/furvm/include/furvm/function.hpp b/furvm/include/furvm/function.hpp index 2b3fb93..2831cc1 100644 --- a/furvm/include/furvm/function.hpp +++ b/furvm/include/furvm/function.hpp @@ -6,6 +6,8 @@ #include #include +#include +#include namespace furvm { @@ -46,7 +48,7 @@ public: */ function(funkcja, function_handle id, const native_function& native, const mod_p& mod); - ~function() = default; + ~function(); /** * @brief Move constructor. @@ -120,13 +122,13 @@ public: } /** - * @brief Returns a module of imported function. + * @brief Returns a name of the function's module. * - * @return A handle to the module. + * @return The name. */ - module_handle imported_module() const { + const std::string& imported_module() const { if (m_type != function_t::Import) throw std::runtime_error("function type mismatch"); - return m_value.imp.mod; + return m_value.imp.moduleName; } /** @@ -147,7 +149,7 @@ private: std::size_t position = 0; native_function native; struct { - module_handle mod; + std::string moduleName; function_handle function; } imp; @@ -159,8 +161,9 @@ private: value(const native_function& native) : native(native) {} - value(module_handle mod, function_handle function) - : imp({ mod, function }) {} + template + value(Name&& moduleName, function_handle function) + : imp({ std::forward(moduleName), function }) {} ~value() {} diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index aaa832a..04f5a2f 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -93,11 +93,6 @@ class mod; */ using mod_p = std::shared_ptr; -/** - * @brief Furvm module's index. - */ -using module_handle = std::uint32_t; - // thing.hpp /** diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 709a763..582c38e 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -3,6 +3,7 @@ #include "furvm/fwd.hpp" +#include #include namespace furvm { @@ -16,12 +17,24 @@ public: /** * @brief Construct a new module. * - * @param id Id of this module. + * @param name Name of this module. + * @param args Arguments to forward to bytecode's constructor. + */ + template >> + mod(Name&& name, Args&&... args) + : m_name(std::forward(name)), m_bytecode(std::forward(args)...) {} + + /** + * @brief Construct a new module. + * + * @param name C-string name of this module. * @param args Arguments to forward to bytecode's constructor. */ template >> - mod(module_handle id, Args&&... args) - : m_id(id), m_bytecode(std::forward(args)...) {} + mod(const char* name, Args&&... args) + : m_name(name), m_bytecode(std::forward(args)...) {} ~mod() = default; @@ -39,11 +52,11 @@ public: mod& operator=(const mod&) = delete; public: /** - * @brief Returns an id of this module. + * @brief Returns this module's name. * - * @return The id. + * @return The name. */ - constexpr module_handle id() const { return m_id; } + constexpr const std::string& name() const { return m_name; } /** * @brief Returns a byte from bytecode of this module. @@ -52,6 +65,20 @@ public: * @return The byte. */ constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); } + + /** + * @brief Returns a reference to the module's bytecode. + * + * @return The reference to bytecode. + */ + constexpr bytecode_t& bytecode() { return m_bytecode; } + + /** + * @brief Returns a const reference to the module's bytecode. + * + * @return The reference to bytecode. + */ + constexpr const bytecode_t& bytecode() const { return m_bytecode; } public: /** * @brief Returns a function from this module. @@ -61,7 +88,7 @@ public: */ constexpr const function_p& function_at(function_handle id) const { return m_functions.at(id); } private: - module_handle m_id; + std::string m_name; bytecode_t m_bytecode; std::vector m_functions; }; diff --git a/furvm/src/function.cpp b/furvm/src/function.cpp index ac74dc8..7092a3c 100644 --- a/furvm/src/function.cpp +++ b/furvm/src/function.cpp @@ -1,5 +1,7 @@ #include "furvm/function.hpp" +#include + namespace furvm { function::function(funkcja, function_handle id, std::size_t position, const mod_p& mod) @@ -8,6 +10,17 @@ function::function(funkcja, function_handle id, std::size_t position, const mod_ function::function(funkcja, function_handle id, const native_function& native, const mod_p& mod) : m_id(id), m_type(function_t::Native), m_module(mod), m_value(native) {} +function::~function() { + switch (m_type) { + case function_t::Normal: + case function_t::Native: + default: break; + case function_t::Import: { + m_value.imp.moduleName.~basic_string(); + } break; + } +} + function::function(function&& other) noexcept : m_id(other.m_id), m_type(other.m_type), m_module(std::move(other.m_module)) { switch (m_type) { @@ -18,8 +31,8 @@ function::function(function&& other) noexcept new (&m_value.native) native_function(std::move(other.m_value.native)); } break; case function_t::Import: { - m_value.imp.mod = other.m_value.imp.mod; - m_value.imp.function = other.m_value.imp.function; + m_value.imp.moduleName = std::move(other.m_value.imp.moduleName); + m_value.imp.function = other.m_value.imp.function; } break; } other.m_value.position = 0; @@ -39,8 +52,8 @@ function& function::operator=(function&& other) noexcept { new (&m_value.native) native_function(std::move(other.m_value.native)); } break; case function_t::Import: { - m_value.imp.mod = other.m_value.imp.mod; - m_value.imp.function = other.m_value.imp.function; + m_value.imp.moduleName = std::move(other.m_value.imp.moduleName); + m_value.imp.function = other.m_value.imp.function; } break; } other.m_value.position = 0; diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index 16a07bd..e2287ab 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -24,7 +24,7 @@ static constexpr std::array s_bytecode = { int main(void) { auto context = std::make_shared(); - auto mainModule = context->emplace(s_bytecode.begin(), s_bytecode.end()); + auto mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end()); auto mainFunction = furvm::function::create(mainModule, 0); From 78acfb6ee2e0b49968ab097f54ff76debb4c4fc2 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 16 Jun 2026 12:48:16 +0200 Subject: [PATCH 03/30] refactor(furvm): refactor function Refs: #12 --- furvm/include/furvm/executor.hpp | 5 +- furvm/include/furvm/function.hpp | 83 +++++++++++--------------------- furvm/include/furvm/fwd.hpp | 5 ++ furvm/include/furvm/module.hpp | 46 ++++++++++++++++-- furvm/src/executor.cpp | 11 +++-- furvm/src/function.cpp | 13 ++--- furvm/src/main.cpp | 5 +- furvm/src/serializer.cpp | 7 ++- 8 files changed, 94 insertions(+), 81 deletions(-) diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index a2c264c..3f0a187 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -97,9 +97,10 @@ public: /** * @brief Pushes a new frame. * - * @param function Function. + * @param mod Module. + * @param function Function handle. */ - void push_frame(const function_p& function); + void push_frame(const mod_p& mod, function_handle function); /** * @brief Pops the top frame. diff --git a/furvm/include/furvm/function.hpp b/furvm/include/furvm/function.hpp index 2831cc1..4356a05 100644 --- a/furvm/include/furvm/function.hpp +++ b/furvm/include/furvm/function.hpp @@ -2,7 +2,6 @@ #define FURVM_FUNCTION_HPP #include "furvm/fwd.hpp" -#include "furvm/module.hpp" // IWYU pragma: keep #include #include @@ -20,33 +19,30 @@ enum class function_t : std::uint8_t { using native_function = std::function; class function { -private: - /** - * @brief A private token for the private constructor. - * - * Also `funkcja` in Polish translates to `function` from what I heard. - */ - struct funkcja { - explicit funkcja() = default; - }; public: - /** - * @brief Private constructor. - * - * @param id - * @param position - * @param mod - */ - function(funkcja, function_handle id, std::size_t position, const mod_p& mod); + template + function(Name&& name, bytecode_pos position) + : m_name(std::forward(name)), m_type(function_t::Normal), m_value(position) {} - /** - * @brief Private constructor. - * - * @param id - * @param native - * @param mod - */ - function(funkcja, function_handle id, const native_function& native, const mod_p& mod); + function(const char* name, bytecode_pos position) + : m_name(name), m_type(function_t::Normal), m_value(position) {} + + template + function(Name&& name, const native_function& native) + : m_name(std::forward(name)), m_type(function_t::Native), m_value(native) {} + + function(const char* name, const native_function& native) + : m_name(name), m_type(function_t::Native), m_value(native) {} + + template + function(Name&& name, ModuleName&& moduleName, function_handle function) + : m_name(std::forward(name)), + m_type(function_t::Import), + m_value(std::forward(moduleName), function) {} + + template + function(const char* name, ModuleName&& moduleName, function_handle function) + : m_name(name), m_type(function_t::Import), m_value(std::forward(moduleName), function) {} ~function(); @@ -64,28 +60,11 @@ public: function& operator=(const function&) = delete; public: /** - * @brief Returns a new function. + * @brief Returns a name of this function. * - * @param mod Module. - * @param args Arguments to pass to the function constructor. - * @return The new function. + * @return The name. */ - template >> - static function_p create(const mod_p& mod, Args&&... args) { - function_handle id = mod->m_functions.size(); - - auto func = std::make_shared(funkcja{}, id, std::forward(args)..., mod); - mod->m_functions.emplace(mod->m_functions.begin() + id, func); - return std::move(func); - } -public: - /** - * @brief Returns an id of this function. - * - * @return The id. - */ - constexpr function_handle id() const { return m_id; } + constexpr const std::string& name() const { return m_name; } /** * @brief Returns a type of this function. @@ -93,13 +72,6 @@ public: * @return The type. */ constexpr function_t type() const { return m_type; } - - /** - * @brief Returns a parent module of this function. - * - * @return A shared pointer to the module. - */ - const mod_p& mod() const { return m_module; } public: /** * @brief Returns a value for normal function. @@ -141,9 +113,8 @@ public: return m_value.imp.function; } private: - function_handle m_id; - function_t m_type; - mod_p m_module; + std::string m_name; + function_t m_type; union value { std::size_t position = 0; diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index 04f5a2f..ef8e3f2 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -17,6 +17,11 @@ namespace furvm { */ using byte = std::uint8_t; +/** + * @brief An offset into bytecode. + */ +using bytecode_pos = std::uint64_t; + // constant.hpp /** diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 582c38e..d39e85d 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -1,9 +1,15 @@ #ifndef FURVM_MODULE_HPP #define FURVM_MODULE_HPP +#include "furvm/function.hpp" #include "furvm/fwd.hpp" +#include +#include +#include #include +#include +#include #include namespace furvm { @@ -80,6 +86,17 @@ public: */ constexpr const bytecode_t& bytecode() const { return m_bytecode; } public: + /** + * @brief Returns a function from this module. + * + * @param name Name of the function. + * @return The function. + */ + template + constexpr const function_p& function_at(Name&& name) const { + return m_functions.at(std::forward(name)); + } + /** * @brief Returns a function from this module. * @@ -87,10 +104,33 @@ public: * @return The function. */ constexpr const function_p& function_at(function_handle id) const { return m_functions.at(id); } + + /** + * @brief Returns an id of a function. + * + * @param function Function to get the id of. + * @return The function's id. + */ + function_handle function_id(const function_p& function) const { + if (auto it = std::find(m_functions.begin(), m_functions.end(), function); it != m_functions.end()) + return it - m_functions.begin(); + throw std::runtime_error("function not in the module"); + } + + template + function_handle emplace_function(Args&&... args) { + function_p function = std::make_shared(std::forward(args)...); + m_functionMap.emplace(function->name(), function); + function_handle id = m_functions.size(); + m_functions.emplace_back(std::move(function)); + return id; + } private: - std::string m_name; - bytecode_t m_bytecode; - std::vector m_functions; + std::string m_name; + bytecode_t m_bytecode; + + std::unordered_map m_functionMap; + std::vector m_functions; }; } // namespace furvm diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 6e858bd..563c6b0 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -25,9 +25,10 @@ executor_p executor::create(const context_p& context) { 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() }); +void executor::push_frame(const mod_p& mod, function_handle function) { + const auto& func = mod->function_at(function); + if (func->type() != function_t::Normal) throw std::runtime_error("unexpected function type"); + m_frames.emplace((struct executor::frame){ mod, func->position(), m_stack.size() }); } struct executor::frame executor::pop_frame() { @@ -185,11 +186,11 @@ void executor::step() { const function_p& function = frame.mod->function_at(funcId); switch (function->type()) { - case function_t::Normal: push_frame(function); break; + case function_t::Normal: push_frame(frame.mod, funcId); 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())); + push_frame(frame.mod, function->imported_function()); } break; } } break; diff --git a/furvm/src/function.cpp b/furvm/src/function.cpp index 7092a3c..baf34c8 100644 --- a/furvm/src/function.cpp +++ b/furvm/src/function.cpp @@ -4,12 +4,6 @@ namespace furvm { -function::function(funkcja, function_handle id, std::size_t position, const mod_p& mod) - : m_id(id), m_type(function_t::Normal), m_module(mod), m_value(position) {} - -function::function(funkcja, function_handle id, const native_function& native, const mod_p& mod) - : m_id(id), m_type(function_t::Native), m_module(mod), m_value(native) {} - function::~function() { switch (m_type) { case function_t::Normal: @@ -22,7 +16,7 @@ function::~function() { } function::function(function&& other) noexcept - : m_id(other.m_id), m_type(other.m_type), m_module(std::move(other.m_module)) { + : m_name(std::move(other.m_name)), m_type(other.m_type) { switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; @@ -41,9 +35,8 @@ function::function(function&& other) noexcept function& function::operator=(function&& other) noexcept { if (this == &other) return *this; - m_id = other.m_id; - m_type = other.m_type; - m_module = std::move(other.m_module); + m_name = std::move(other.m_name); + m_type = other.m_type; switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index e2287ab..d3238f7 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -25,14 +25,13 @@ int main(void) { auto context = std::make_shared(); auto mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end()); - - auto mainFunction = furvm::function::create(mainModule, 0); + mainModule->emplace_function("main", 0); std::ofstream file("./test.furm", std::ios::binary); furvm::serializer::serialize_module(file, mainModule); auto executor = furvm::executor::create(context); - executor->push_frame(mainFunction); + executor->push_frame(mainModule, 0); static constexpr std::size_t FPC = 3; // Frames per collection diff --git a/furvm/src/serializer.cpp b/furvm/src/serializer.cpp index 94a8a71..dc76b58 100644 --- a/furvm/src/serializer.cpp +++ b/furvm/src/serializer.cpp @@ -1,6 +1,8 @@ #include "furvm/serializer.hpp" #include "furvm/function.hpp" // IWYU pragma: keep +#include "furvm/fwd.hpp" +#include "furvm/module.hpp" // IWYU pragma: keep #include #include @@ -73,8 +75,9 @@ bool serializer::serialize_module(std::ostream& os, const mod_p& mod) { write_u32(os, VERSION); write_u32(os, mod->m_functions.size()); - for (const auto& func : mod->m_functions) { - write_u16(os, func->id()); + for (function_handle id = 0; id < static_cast(mod->m_functions.size()); ++id) { + const auto& func = mod->m_functions[id]; + write_u16(os, id); write_u8(os, static_cast(func->type())); switch (func->type()) { case function_t::Normal: { From 0dfa8c1c0276519ec88388b23dfa1e426cefcc5a Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 16 Jun 2026 14:45:36 +0200 Subject: [PATCH 04/30] refactor(furvm): refactor executor Refs: #12 --- furvm/include/furvm/context.hpp | 7 ++++++ furvm/include/furvm/executor.hpp | 39 ++++++-------------------------- furvm/src/executor.cpp | 13 ----------- furvm/src/main.cpp | 2 +- 4 files changed, 15 insertions(+), 46 deletions(-) diff --git a/furvm/include/furvm/context.hpp b/furvm/include/furvm/context.hpp index a8397ef..230bfda 100644 --- a/furvm/include/furvm/context.hpp +++ b/furvm/include/furvm/context.hpp @@ -5,6 +5,7 @@ #include "furvm/fwd.hpp" #include "furvm/module.hpp" +#include #include #include #include @@ -86,6 +87,12 @@ public: * @return The module count. */ constexpr size_t module_count() const { return m_modules.size(); } +public: + template >> + auto& emplace_executor(Args&&... args) { + executor_p executor = std::make_shared(std::forward(args)...); + return m_executors.emplace_back(std::move(executor)); + } public: /** * @brief Removes unreferenced things from the thing list. diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 3f0a187..858f48f 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -26,15 +26,6 @@ static inline executor_flags operator~(executor_flags flags) { } class executor { -private: - /** - * @brief A private token for the private constructor. - * - * Also `egzekutor` in Polish translates to `executor` I think. - */ - struct egzekutor { - explicit egzekutor() = default; - }; public: /** * @brief Executor frame. @@ -50,14 +41,14 @@ public: }; public: /** - * @brief Private constructor. + * @brief Returns a new executor. * - * @param id - * @param context + * @param context Context. */ - executor(egzekutor, executor_handle id, const context_p& context); + executor(const context_p& context) + : m_context(context) {} - ~executor(); + ~executor() = default; /** * @brief Move constructor. @@ -72,21 +63,6 @@ public: executor(const executor&) = delete; executor& operator=(const executor&) = delete; public: - /** - * @brief Returns a new executor. - * - * @param context Furvm context. - * @return Shared pointer to the new executor. - */ - static executor_p create(const context_p& context); -public: - /** - * @brief Returns an id of this executor. - * - * @return The id. - */ - executor_handle id() const { return m_id; } - /** * @brief Returns flags of this executor. * @@ -173,9 +149,8 @@ public: */ void step(); private: - executor_handle m_id; - executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization) - context_p m_context; + executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization) + context_p m_context; std::stack m_frames; std::stack m_stack; diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 563c6b0..430cb9d 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -12,19 +12,6 @@ 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(egzekutor{}, context->m_executors.size(), context); - context->m_executors.push_back(ex); - return std::move(ex); -} - void executor::push_frame(const mod_p& mod, function_handle function) { const auto& func = mod->function_at(function); if (func->type() != function_t::Normal) throw std::runtime_error("unexpected function type"); diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index d3238f7..065de61 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -30,7 +30,7 @@ int main(void) { std::ofstream file("./test.furm", std::ios::binary); furvm::serializer::serialize_module(file, mainModule); - auto executor = furvm::executor::create(context); + auto executor = context->emplace_executor(context); executor->push_frame(mainModule, 0); static constexpr std::size_t FPC = 3; // Frames per collection From c9f714642ca058c1932fc585122e45ee56fc5fc4 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 16 Jun 2026 14:59:29 +0200 Subject: [PATCH 05/30] refactor(furvm): refactor thing A pretty sloppy thing class refactor. Refs: #12 --- furvm/include/furvm/thing.hpp | 46 +++-------------------------------- furvm/src/executor.cpp | 3 ++- furvm/src/main.cpp | 3 --- furvm/src/thing.cpp | 39 ++++++++++++----------------- 4 files changed, 21 insertions(+), 70 deletions(-) diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 830e978..7c0ce11 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -53,28 +53,12 @@ public: class thing final { friend class executor; -private: - /** - * @brief A private token for the private constructor. - * - * Also `rzecz` in Polish translates to `thing` I think. - */ - struct rzecz { - explicit rzecz() = default; - }; public: using nref_t = std::size_t; /**< Type of reference count. */ static constexpr thing_handle GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */ public: - /** - * @brief Private constructor. - * - * @param id - * @param type - * @param context - */ - thing(rzecz, thing_handle id, thing_t type, const context_p& context); + thing(const context_p& context, thing_t type); ~thing(); @@ -189,29 +173,6 @@ public: */ friend thing_p operator>=(const thing_p& lhs, const thing_p& rhs); public: - /** - * @brief Returns a new thing. - * - * @param context Furvm context. - * @param args Arguments to forward to the thing constructor. - * @return Shared pointer to the new thing. - */ - template >> - static thing_p create(const context_p& context, Args&&... args) { - thing_handle id = context->m_things.size(); - if (!context->m_deadThings.empty()) { - id = context->m_deadThings.front(); - context->m_deadThings.pop(); - id += 1 << GENERATION_SIZE; - } - thing_handle idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1); - - auto th = std::make_shared(rzecz{}, id, std::forward(args)..., context); - context->m_things.emplace(context->m_things.begin() + idx, th); - return std::move(th); - } - /** * @brief Returns a clone of the thing. * @@ -251,9 +212,8 @@ public: */ constexpr nref_t reference_count() const { return m_refCount; } private: - thing_handle m_id; - thing_t m_type; - context_p m_context; + context_p m_context; + thing_t m_type; nref_t m_refCount = 0; void* m_data = nullptr; diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 430cb9d..9479e6c 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -8,6 +8,7 @@ #include "furvm/thing.hpp" #include +#include #include namespace furvm { @@ -86,7 +87,7 @@ void executor::step() { switch (instr) { case instruction_t::NoOperation: break; case instruction_t::PushB2I: { - auto thing = thing::create(m_context, thing_t::Int32); + auto thing = std::make_shared(m_context, thing_t::Int32); thing->int32() = frame.mod->byte(frame.position++); push_thing(std::move(thing)); } break; diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index 065de61..806fa6d 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -27,9 +27,6 @@ int main(void) { auto mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end()); mainModule->emplace_function("main", 0); - std::ofstream file("./test.furm", std::ios::binary); - furvm::serializer::serialize_module(file, mainModule); - auto executor = context->emplace_executor(context); executor->push_frame(mainModule, 0); diff --git a/furvm/src/thing.cpp b/furvm/src/thing.cpp index a75aa4c..4289e02 100644 --- a/furvm/src/thing.cpp +++ b/furvm/src/thing.cpp @@ -17,8 +17,8 @@ std::size_t thing_type_size(thing_t type) { return 0; } -thing::thing(rzecz, thing_handle id, thing_t type, const context_p& context) - : m_id(id), m_type(type), m_context(context) { +thing::thing(const context_p& context, thing_t type) + : m_context(context), m_type(type) { std::size_t size = thing_type_size(type); std::byte* data = nullptr; if (!m_context->m_deadThingData.empty()) { @@ -56,12 +56,7 @@ thing::~thing() { } thing::thing(thing&& other) noexcept - : m_id(other.m_id), - m_type(other.m_type), - m_context(std::move(other.m_context)), - m_refCount(other.m_refCount), - m_data(other.m_data) { - other.m_id = {}; + : m_context(std::move(other.m_context)), m_type(other.m_type), m_refCount(other.m_refCount), m_data(other.m_data) { other.m_type = {}; other.m_refCount = {}; other.m_data = nullptr; @@ -69,13 +64,11 @@ thing::thing(thing&& other) noexcept thing& thing::operator=(thing&& other) noexcept { if (this == &other) return *this; - m_id = other.m_id; - m_type = other.m_type; m_context = std::move(other.m_context); + m_type = other.m_type; m_refCount = other.m_refCount; m_data = other.m_data; - other.m_id = {}; other.m_type = {}; other.m_refCount = {}; other.m_data = nullptr; @@ -89,7 +82,7 @@ static constexpr std::uint16_t thing_type_pair(thing_t lhs, thing_t rhs) { thing_p operator+(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = lhs->int32() + rhs->int32(); return res; } @@ -100,7 +93,7 @@ thing_p operator+(const thing_p& lhs, const thing_p& rhs) { thing_p operator-(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = lhs->int32() - rhs->int32(); return res; } @@ -111,7 +104,7 @@ thing_p operator-(const thing_p& lhs, const thing_p& rhs) { thing_p operator*(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = lhs->int32() * rhs->int32(); return res; } @@ -122,7 +115,7 @@ thing_p operator*(const thing_p& lhs, const thing_p& rhs) { thing_p operator/(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = lhs->int32() / rhs->int32(); return res; } @@ -133,7 +126,7 @@ thing_p operator/(const thing_p& lhs, const thing_p& rhs) { thing_p operator%(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = lhs->int32() % rhs->int32(); return res; } @@ -144,7 +137,7 @@ thing_p operator%(const thing_p& lhs, const thing_p& rhs) { thing_p operator==(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = static_cast(lhs->int32() == rhs->int32()); return res; } @@ -155,7 +148,7 @@ thing_p operator==(const thing_p& lhs, const thing_p& rhs) { thing_p operator!=(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = static_cast(lhs->int32() != rhs->int32()); return res; } @@ -166,7 +159,7 @@ thing_p operator!=(const thing_p& lhs, const thing_p& rhs) { thing_p operator<(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = static_cast(lhs->int32() < rhs->int32()); return res; } @@ -177,7 +170,7 @@ thing_p operator<(const thing_p& lhs, const thing_p& rhs) { thing_p operator>(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = static_cast(lhs->int32() > rhs->int32()); return res; } @@ -188,7 +181,7 @@ thing_p operator>(const thing_p& lhs, const thing_p& rhs) { thing_p operator<=(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = static_cast(lhs->int32() <= rhs->int32()); return res; } @@ -199,7 +192,7 @@ thing_p operator<=(const thing_p& lhs, const thing_p& rhs) { thing_p operator>=(const thing_p& lhs, const thing_p& rhs) { switch (thing_type_pair(lhs->m_type, rhs->m_type)) { case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = thing::create(lhs->m_context, thing_t::Int32); + auto res = std::make_shared(lhs->m_context, thing_t::Int32); res->int32() = static_cast(lhs->int32() >= rhs->int32()); return res; } @@ -216,7 +209,7 @@ thing_p thing::clone(const thing_p& thing) { } thing_handle idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1); - auto th = std::make_shared(rzecz{}, id, thing->m_type, thing->m_context); + auto th = std::make_shared(thing->m_context, thing->m_type); switch (thing->m_type) { // Primitives default: { From c2b32c96046f0166d814aa8ac2c91267d19b4580 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 16 Jun 2026 16:21:49 +0200 Subject: [PATCH 06/30] refactor(furvm): rename handle suffixes to ids Refs: #12 --- furvm/include/furvm/context.hpp | 6 +++--- furvm/include/furvm/executor.hpp | 2 +- furvm/include/furvm/function.hpp | 12 ++++++------ furvm/include/furvm/fwd.hpp | 6 +++--- furvm/include/furvm/module.hpp | 18 +++--------------- furvm/include/furvm/thing.hpp | 2 +- furvm/src/executor.cpp | 8 ++++---- furvm/src/serializer.cpp | 2 +- furvm/src/thing.cpp | 4 ++-- 9 files changed, 24 insertions(+), 36 deletions(-) diff --git a/furvm/include/furvm/context.hpp b/furvm/include/furvm/context.hpp index 230bfda..ba0f6b8 100644 --- a/furvm/include/furvm/context.hpp +++ b/furvm/include/furvm/context.hpp @@ -104,9 +104,9 @@ private: std::vector m_things; std::vector m_executors; - std::queue m_deadThings; - std::vector m_deadThingData; - furlang::arena m_thingArena; + std::queue m_deadThings; + std::vector m_deadThingData; + furlang::arena m_thingArena; }; } // namespace furvm diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 858f48f..88f69be 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -76,7 +76,7 @@ public: * @param mod Module. * @param function Function handle. */ - void push_frame(const mod_p& mod, function_handle function); + void push_frame(const mod_p& mod, function_id function); /** * @brief Pops the top frame. diff --git a/furvm/include/furvm/function.hpp b/furvm/include/furvm/function.hpp index 4356a05..ca19c01 100644 --- a/furvm/include/furvm/function.hpp +++ b/furvm/include/furvm/function.hpp @@ -35,13 +35,13 @@ public: : m_name(name), m_type(function_t::Native), m_value(native) {} template - function(Name&& name, ModuleName&& moduleName, function_handle function) + function(Name&& name, ModuleName&& moduleName, function_id function) : m_name(std::forward(name)), m_type(function_t::Import), m_value(std::forward(moduleName), function) {} template - function(const char* name, ModuleName&& moduleName, function_handle function) + function(const char* name, ModuleName&& moduleName, function_id function) : m_name(name), m_type(function_t::Import), m_value(std::forward(moduleName), function) {} ~function(); @@ -108,7 +108,7 @@ public: * * @return A handle to the module. */ - function_handle imported_function() const { + function_id imported_function() const { if (m_type != function_t::Import) throw std::runtime_error("function type mismatch"); return m_value.imp.function; } @@ -120,8 +120,8 @@ private: std::size_t position = 0; native_function native; struct { - std::string moduleName; - function_handle function; + std::string moduleName; + function_id function; } imp; value() = default; @@ -133,7 +133,7 @@ private: : native(native) {} template - value(Name&& moduleName, function_handle function) + value(Name&& moduleName, function_id function) : imp({ std::forward(moduleName), function }) {} ~value() {} diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index ef8e3f2..8098d78 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -81,7 +81,7 @@ using function_p = std::shared_ptr; /** * @brief Furvm function's index. */ -using function_handle = std::uint16_t; +using function_id = std::uint16_t; // module.hpp @@ -128,7 +128,7 @@ using thing_p = std::shared_ptr; /** * @brief Furvm thing's index. */ -using thing_handle = std::uint32_t; +using thing_id = std::uint32_t; // executor.hpp @@ -159,7 +159,7 @@ using executor_p = std::shared_ptr; /** * @brief Furvm executor's index. */ -using executor_handle = std::uint32_t; +using executor_id = std::uint32_t; // context.hpp diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index d39e85d..4c394e1 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -103,25 +103,13 @@ public: * @param id Id of the function. * @return The function. */ - constexpr const function_p& function_at(function_handle id) const { return m_functions.at(id); } - - /** - * @brief Returns an id of a function. - * - * @param function Function to get the id of. - * @return The function's id. - */ - function_handle function_id(const function_p& function) const { - if (auto it = std::find(m_functions.begin(), m_functions.end(), function); it != m_functions.end()) - return it - m_functions.begin(); - throw std::runtime_error("function not in the module"); - } + constexpr const function_p& function_at(function_id id) const { return m_functions.at(id); } template - function_handle emplace_function(Args&&... args) { + function_id emplace_function(Args&&... args) { function_p function = std::make_shared(std::forward(args)...); m_functionMap.emplace(function->name(), function); - function_handle id = m_functions.size(); + function_id id = m_functions.size(); m_functions.emplace_back(std::move(function)); return id; } diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 7c0ce11..d85c5fc 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -56,7 +56,7 @@ class thing final { public: using nref_t = std::size_t; /**< Type of reference count. */ - static constexpr thing_handle GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */ + static constexpr thing_id GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */ public: thing(const context_p& context, thing_t type); diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 9479e6c..3514bcd 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -13,7 +13,7 @@ namespace furvm { -void executor::push_frame(const mod_p& mod, function_handle function) { +void executor::push_frame(const mod_p& mod, function_id function) { const auto& func = mod->function_at(function); if (func->type() != function_t::Normal) throw std::runtime_error("unexpected function type"); m_frames.emplace((struct executor::frame){ mod, func->position(), m_stack.size() }); @@ -168,9 +168,9 @@ void executor::step() { store_thing(variable, std::move(pop_thing())); } break; case instruction_t::Call: { - function_handle funcId = static_cast(frame.mod->byte(frame.position)) | - (static_cast(frame.mod->byte(frame.position + 1)) << 8); - frame.position += 2; + function_id funcId = static_cast(frame.mod->byte(frame.position)) | + (static_cast(frame.mod->byte(frame.position + 1)) << 8); + frame.position += 2; const function_p& function = frame.mod->function_at(funcId); switch (function->type()) { diff --git a/furvm/src/serializer.cpp b/furvm/src/serializer.cpp index dc76b58..bac4019 100644 --- a/furvm/src/serializer.cpp +++ b/furvm/src/serializer.cpp @@ -75,7 +75,7 @@ bool serializer::serialize_module(std::ostream& os, const mod_p& mod) { write_u32(os, VERSION); write_u32(os, mod->m_functions.size()); - for (function_handle id = 0; id < static_cast(mod->m_functions.size()); ++id) { + for (function_id id = 0; id < static_cast(mod->m_functions.size()); ++id) { const auto& func = mod->m_functions[id]; write_u16(os, id); write_u8(os, static_cast(func->type())); diff --git a/furvm/src/thing.cpp b/furvm/src/thing.cpp index 4289e02..75cae45 100644 --- a/furvm/src/thing.cpp +++ b/furvm/src/thing.cpp @@ -201,13 +201,13 @@ thing_p operator>=(const thing_p& lhs, const thing_p& rhs) { } thing_p thing::clone(const thing_p& thing) { - thing_handle id = thing->m_context->m_things.size(); + thing_id id = thing->m_context->m_things.size(); if (!thing->m_context->m_deadThings.empty()) { id = thing->m_context->m_deadThings.front(); thing->m_context->m_deadThings.pop(); id += 1 << GENERATION_SIZE; } - thing_handle idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1); + thing_id idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1); auto th = std::make_shared(thing->m_context, thing->m_type); switch (thing->m_type) { From e8ccaa63907e850c63eabbdeac256b5733dcdf81 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 16 Jun 2026 16:47:00 +0200 Subject: [PATCH 07/30] feat(furvm): implement a handle Refs: #12 --- furvm/include/furvm/fwd.hpp | 28 +++++++++ furvm/include/furvm/handle.hpp | 101 +++++++++++++++++++++++++++++++++ furvm/include/furvm/module.hpp | 2 - furvm/src/serializer.cpp | 3 - 4 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 furvm/include/furvm/handle.hpp diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index 8098d78..e5afc2c 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -1,9 +1,12 @@ #ifndef FURVM_FWD_HPP #define FURVM_FWD_HPP +#include "furvm/handle.hpp" + #include // IWYU pragma: export #include // IWYU pragma: export #include +#include /** * @brief Furlang's virtual machine. @@ -83,6 +86,11 @@ using function_p = std::shared_ptr; */ using function_id = std::uint16_t; +/** + * @brief A handle to a furvm function. + */ +using function_h = handle; + // module.hpp /** @@ -98,6 +106,16 @@ class mod; */ using mod_p = std::shared_ptr; +/** + * @brief An alias for a module's identifier. + */ +using mod_id = std::string; + +/** + * @brief A handle to a furvm module. + */ +using mod_h = handle; + // thing.hpp /** @@ -130,6 +148,11 @@ using thing_p = std::shared_ptr; */ using thing_id = std::uint32_t; +/** + * @brief A handle to a furvm's thing. + */ +using thing_h = handle; + // executor.hpp /** @@ -161,6 +184,11 @@ using executor_p = std::shared_ptr; */ using executor_id = std::uint32_t; +/** + * @brief A handle to a furvm's executor. + */ +using executor_h = handle; + // context.hpp /** diff --git a/furvm/include/furvm/handle.hpp b/furvm/include/furvm/handle.hpp new file mode 100644 index 0000000..c1f3503 --- /dev/null +++ b/furvm/include/furvm/handle.hpp @@ -0,0 +1,101 @@ +#ifndef FURVM_HANDLE_HPP +#define FURVM_HANDLE_HPP + +#include + +namespace furvm { + +template +class handle { +public: + using id_type = Id; + + using value_type = T; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; +public: + /** + * @brief Returns a new handle. + * + * @param id Id of the handle. + * @param value Value of the handle. + */ + template + handle(IdF&& id, Value&& value) + : m_id(std::forward(id)), m_value(std::forward(value)) {} +public: + handle& operator=(value_type&& value) noexcept { + m_value = std::move(value); + return *this; + } + + handle& operator=(const value_type& value) noexcept { + m_value = value; + return *this; + } +public: + /** + * @brief Returns the handle's id. + * + * @return The id. + */ + constexpr Id id() const { return m_id; } + + /** + * @brief Returns the handle's pointer. + * + * @return The pointer. + */ + reference value() { return m_value; } + + /** + * @brief Returns the handle's pointer. + * + * @return The pointer. + */ + const_reference value() const { return m_value; } +public: + /** + * @brief Returns the handle's id. + * + * @return The id. + */ + explicit operator Id() const { return m_id; } +public: + /** + * @brief Returns a reference to the handle's value. + * + * @return The value. + */ + reference operator*() { return m_value; } + + /** + * @brief Returns a reference to the handle's value. + * + * @return The value. + */ + const_reference operator*() const { return m_value; } + + /** + * @brief Returns a pointer to the handle's value. + * + * @return The value pointer. + */ + pointer operator->() { return &m_value; } + + /** + * @brief Returns a pointer to the handle's value. + * + * @return The value pointer. + */ + const_pointer operator->() const { return &m_value; } +private: + id_type m_id; + value_type m_value; +}; + +} // namespace furvm + +#endif // FURVM_HANDLE_HPP diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 4c394e1..bfa167d 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -4,9 +4,7 @@ #include "furvm/function.hpp" #include "furvm/fwd.hpp" -#include #include -#include #include #include #include diff --git a/furvm/src/serializer.cpp b/furvm/src/serializer.cpp index bac4019..58ce2d4 100644 --- a/furvm/src/serializer.cpp +++ b/furvm/src/serializer.cpp @@ -4,10 +4,7 @@ #include "furvm/fwd.hpp" #include "furvm/module.hpp" // IWYU pragma: keep -#include -#include #include -#include #include #include From 00bcc0e6a59bc1343ab05ae48a434096b5a427ae Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Wed, 17 Jun 2026 13:59:54 +0200 Subject: [PATCH 08/30] refactor(furvm): use the handle system Refs: #12 --- .clang-tidy | 5 +++-- furvm/include/furvm/context.hpp | 22 +++++++++++-------- furvm/include/furvm/executor.hpp | 15 +++++++++---- furvm/include/furvm/function.hpp | 11 ++++++++-- furvm/include/furvm/module.hpp | 26 +++++++++++----------- furvm/src/context.cpp | 2 +- furvm/src/executor.cpp | 36 +++++++++++++++---------------- furvm/src/function.cpp | 37 ++++++++++++++++++++++++++++++++ furvm/src/main.cpp | 9 ++++---- furvm/src/serializer.cpp | 2 +- 10 files changed, 112 insertions(+), 53 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 88d2f52..1021a8a 100755 --- a/.clang-tidy +++ b/.clang-tidy @@ -28,7 +28,8 @@ Checks: > -cppcoreguidelines-macro-usage, -cppcoreguidelines-owning-memory, -cppcoreguidelines-non-private-member-variables-in-classes, - -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access + -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay WarningsAsErrors: "*" @@ -95,4 +96,4 @@ CheckOptions: - key: readability-identifier-naming.EnumConstantCase value: CamelCase - key: readability-identifier-naming.ScopedEnumConstantCase - value: CamelCase \ No newline at end of file + value: CamelCase diff --git a/furvm/include/furvm/context.hpp b/furvm/include/furvm/context.hpp index ba0f6b8..436ff35 100644 --- a/furvm/include/furvm/context.hpp +++ b/furvm/include/furvm/context.hpp @@ -2,6 +2,7 @@ #define FURVM_CONTEXT_HPP #include "furlang/arena.hpp" +#include "furvm/executor.hpp" #include "furvm/fwd.hpp" #include "furvm/module.hpp" @@ -40,12 +41,13 @@ public: * @brief Emplaces a new module in this context. * * @param args Arguments to forward to module's constructor. - * @return An index to the emplaced module. + * @return A handle to the module. */ template >> - auto& emplace_module(Args&&... args) { - mod_p mod = std::make_shared(std::forward(args)...); - return m_modules.emplace(mod->name(), std::move(mod)).first->second; + mod_h emplace_module(Args&&... args) { + mod_p mod = std::make_shared(std::forward(args)...); + std::string name = mod->name(); + return { name, m_modules[name] = std::move(mod) }; } /** @@ -89,9 +91,11 @@ public: constexpr size_t module_count() const { return m_modules.size(); } public: template >> - auto& emplace_executor(Args&&... args) { - executor_p executor = std::make_shared(std::forward(args)...); - return m_executors.emplace_back(std::move(executor)); + executor_h emplace_executor(Args&&... args) { + executor executor(std::forward(args)...); + executor_id id = m_executors.size(); + m_executors.emplace_back(std::move(executor)); + return { id, m_executors[id] }; } public: /** @@ -101,8 +105,8 @@ public: private: std::unordered_map m_modules; - std::vector m_things; - std::vector m_executors; + std::vector m_things; + std::vector m_executors; std::queue m_deadThings; std::vector m_deadThingData; diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 88f69be..24436fe 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -33,7 +33,7 @@ public: * Call frame. */ struct frame { - mod_p mod; /**< Shared pointer to a module with the bytecode. */ + mod_h mod; /**< Shared pointer to a module with the bytecode. */ std::size_t position; /**< Cursor to a current instruction in the bytecode. */ std::size_t stackBase; /**< Snapshot of the stack size before this frame. */ @@ -60,8 +60,15 @@ public: */ executor& operator=(executor&&) noexcept = default; - executor(const executor&) = delete; - executor& operator=(const executor&) = delete; + /** + * @brief Copy constructor. + */ + executor(const executor&) = default; + + /** + * @brief Copy constructor. + */ + executor& operator=(const executor&) = default; public: /** * @brief Returns flags of this executor. @@ -76,7 +83,7 @@ public: * @param mod Module. * @param function Function handle. */ - void push_frame(const mod_p& mod, function_id function); + void push_frame(const mod_h& mod, const function_h& function); /** * @brief Pops the top frame. diff --git a/furvm/include/furvm/function.hpp b/furvm/include/furvm/function.hpp index ca19c01..e09bacb 100644 --- a/furvm/include/furvm/function.hpp +++ b/furvm/include/furvm/function.hpp @@ -56,8 +56,15 @@ public: */ function& operator=(function&&) noexcept; - function(const function&) = delete; - function& operator=(const function&) = delete; + /** + * @brief Copy constructor. + */ + function(const function&); + + /** + * @brief Copy constructor. + */ + function& operator=(const function&); public: /** * @brief Returns a name of this function. diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index bfa167d..c0d8e9b 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -4,7 +4,7 @@ #include "furvm/function.hpp" #include "furvm/fwd.hpp" -#include +#include #include #include #include @@ -91,8 +91,9 @@ public: * @return The function. */ template - constexpr const function_p& function_at(Name&& name) const { - return m_functions.at(std::forward(name)); + function_h function_at(Name&& name) const { + if (auto it = m_functionMap.find(std::forward(name)); it != m_functionMap.end()) return it->second; + throw std::runtime_error("invalid function"); } /** @@ -101,22 +102,23 @@ public: * @param id Id of the function. * @return The function. */ - constexpr const function_p& function_at(function_id id) const { return m_functions.at(id); } + function_h function_at(function_id id) const { return { id, m_functions.at(id) }; } template - function_id emplace_function(Args&&... args) { - function_p function = std::make_shared(std::forward(args)...); - m_functionMap.emplace(function->name(), function); - function_id id = m_functions.size(); - m_functions.emplace_back(std::move(function)); - return id; + function_h emplace_function(Args&&... args) { + function function(std::forward(args)...); + std::string name = function.name(); + function_id id = m_functions.size(); + function_h handle = { id, m_functions.emplace_back(std::move(function)) }; + m_functionMap.emplace(std::move(name), handle); + return handle; } private: std::string m_name; bytecode_t m_bytecode; - std::unordered_map m_functionMap; - std::vector m_functions; + std::unordered_map m_functionMap; + std::vector m_functions; }; } // namespace furvm diff --git a/furvm/src/context.cpp b/furvm/src/context.cpp index 6dcb1c4..9cb27e7 100644 --- a/furvm/src/context.cpp +++ b/furvm/src/context.cpp @@ -13,4 +13,4 @@ void context::collect() { } } -} // namespace furvm \ No newline at end of file +} // namespace furvm diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 3514bcd..4feb333 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -13,10 +13,9 @@ namespace furvm { -void executor::push_frame(const mod_p& mod, function_id function) { - const auto& func = mod->function_at(function); - if (func->type() != function_t::Normal) throw std::runtime_error("unexpected function type"); - m_frames.emplace((struct executor::frame){ mod, func->position(), m_stack.size() }); +void executor::push_frame(const mod_h& mod, const function_h& function) { + if (function->type() != function_t::Normal) throw std::runtime_error("unexpected function type"); + m_frames.emplace((struct executor::frame){ mod, function->position(), m_stack.size() }); } struct executor::frame executor::pop_frame() { @@ -83,12 +82,12 @@ void executor::step() { struct frame& frame = m_frames.top(); - instruction_t instr = static_cast(frame.mod->byte(frame.position++)); + instruction_t instr = static_cast((*frame.mod)->byte(frame.position++)); switch (instr) { case instruction_t::NoOperation: break; case instruction_t::PushB2I: { auto thing = std::make_shared(m_context, thing_t::Int32); - thing->int32() = frame.mod->byte(frame.position++); + thing->int32() = (*frame.mod)->byte(frame.position++); push_thing(std::move(thing)); } break; case instruction_t::Drop: { @@ -156,37 +155,38 @@ void executor::step() { push_thing(lhs >= rhs); } break; case instruction_t::Load: { - variable_t variable = static_cast(frame.mod->byte(frame.position)) | - (static_cast(frame.mod->byte(frame.position + 1)) << 8); + variable_t variable = static_cast((*frame.mod)->byte(frame.position)) | + (static_cast((*frame.mod)->byte(frame.position + 1)) << 8); frame.position += 2; push_thing(load_thing(variable)); } break; case instruction_t::Store: { - variable_t variable = static_cast(frame.mod->byte(frame.position)) | - (static_cast(frame.mod->byte(frame.position + 1)) << 8); + variable_t variable = static_cast((*frame.mod)->byte(frame.position)) | + (static_cast((*frame.mod)->byte(frame.position + 1)) << 8); frame.position += 2; store_thing(variable, std::move(pop_thing())); } break; case instruction_t::Call: { - function_id funcId = static_cast(frame.mod->byte(frame.position)) | - (static_cast(frame.mod->byte(frame.position + 1)) << 8); + function_id funcId = static_cast((*frame.mod)->byte(frame.position)) | + (static_cast((*frame.mod)->byte(frame.position + 1)) << 8); frame.position += 2; - const function_p& function = frame.mod->function_at(funcId); + const function_h& function = (*frame.mod)->function_at(funcId); switch (function->type()) { - case function_t::Normal: push_frame(frame.mod, funcId); break; + case function_t::Normal: push_frame(frame.mod, 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(frame.mod, function->imported_function()); + // const mod_p& impMod = m_context->m_modules.at(function->imported_module()); + // push_frame(frame.mod, function->imported_function()); + throw std::runtime_error("unimplemented"); } break; } } break; case instruction_t::Jump: { - frame.position += frame.mod->byte(frame.position++); + frame.position += (*frame.mod)->byte(frame.position++); } break; case instruction_t::JumpNotZero: { - byte offset = frame.mod->byte(frame.position++); + byte offset = (*frame.mod)->byte(frame.position++); auto cond = pop_thing(); if (cond->int32() != 0) frame.position += offset; } break; diff --git a/furvm/src/function.cpp b/furvm/src/function.cpp index baf34c8..82df446 100644 --- a/furvm/src/function.cpp +++ b/furvm/src/function.cpp @@ -54,4 +54,41 @@ function& function::operator=(function&& other) noexcept { return *this; } +function::function(const function& other) + : m_name(other.m_name), m_type(other.m_type) { + switch (m_type) { + case function_t::Normal: { + m_value.position = other.m_value.position; + } break; + case function_t::Native: { + new (&m_value.native) native_function(other.m_value.native); + } break; + case function_t::Import: { + m_value.imp.moduleName = other.m_value.imp.moduleName; + m_value.imp.function = other.m_value.imp.function; + } break; + } +} + +function& function::operator=(const function& other) { + if (this == &other) return *this; + + m_name = other.m_name; + m_type = other.m_type; + switch (m_type) { + case function_t::Normal: { + m_value.position = other.m_value.position; + } break; + case function_t::Native: { + new (&m_value.native) native_function(other.m_value.native); + } break; + case function_t::Import: { + m_value.imp.moduleName = other.m_value.imp.moduleName; + m_value.imp.function = other.m_value.imp.function; + } break; + } + + return *this; +} + } // namespace furvm diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index 806fa6d..ebf38e8 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -3,6 +3,7 @@ #include "furvm/context.hpp" #include "furvm/executor.hpp" #include "furvm/function.hpp" +#include "furvm/fwd.hpp" #include "furvm/instruction.hpp" #include "furvm/serializer.hpp" #include "furvm/thing.hpp" @@ -24,11 +25,11 @@ static constexpr std::array s_bytecode = { int main(void) { auto context = std::make_shared(); - auto mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end()); - mainModule->emplace_function("main", 0); + furvm::mod_h mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end()); + furvm::function_h mainFunc = (*mainModule)->emplace_function("main", 0); - auto executor = context->emplace_executor(context); - executor->push_frame(mainModule, 0); + furvm::executor_h executor = context->emplace_executor(context); + executor->push_frame(mainModule, mainFunc); static constexpr std::size_t FPC = 3; // Frames per collection diff --git a/furvm/src/serializer.cpp b/furvm/src/serializer.cpp index 58ce2d4..9825766 100644 --- a/furvm/src/serializer.cpp +++ b/furvm/src/serializer.cpp @@ -73,7 +73,7 @@ bool serializer::serialize_module(std::ostream& os, const mod_p& mod) { write_u32(os, mod->m_functions.size()); for (function_id id = 0; id < static_cast(mod->m_functions.size()); ++id) { - const auto& func = mod->m_functions[id]; + const auto& func = mod->function_at(id); write_u16(os, id); write_u8(os, static_cast(func->type())); switch (func->type()) { From e9b38e95a2dfa33a864b911170f1fd8071a4fb6d Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Wed, 17 Jun 2026 20:19:53 +0200 Subject: [PATCH 09/30] refactor(furvm): integrate handle system into things Sloppy af Refs: #12 --- furvm/include/furvm/context.hpp | 27 +++ furvm/include/furvm/executor.hpp | 18 +- furvm/include/furvm/fwd.hpp | 2 +- furvm/include/furvm/handle.hpp | 19 ++ furvm/include/furvm/thing.hpp | 126 +++---------- furvm/src/executor.cpp | 65 ++++--- furvm/src/thing.cpp | 298 +++++++++++++++---------------- 7 files changed, 253 insertions(+), 302 deletions(-) diff --git a/furvm/include/furvm/context.hpp b/furvm/include/furvm/context.hpp index 436ff35..f2e9298 100644 --- a/furvm/include/furvm/context.hpp +++ b/furvm/include/furvm/context.hpp @@ -5,7 +5,9 @@ #include "furvm/executor.hpp" #include "furvm/fwd.hpp" #include "furvm/module.hpp" +#include "furvm/thing.hpp" +#include #include #include #include @@ -102,6 +104,31 @@ public: * @brief Removes unreferenced things from the thing list. */ void collect(); +public: + thing_h emplace_thing(thing_t type) { + thing_id id = m_things.size(); + if (!m_deadThings.empty()) { + id = m_deadThings.front(); + m_deadThings.pop(); + } + + size_t size = thing_type_size(type); + void* data = nullptr; + for (auto it = m_deadThingData.begin(); it != m_deadThingData.end(); ++it) { + thing_t curType{}; + std::memcpy(&curType, static_cast(*it) - sizeof(curType), sizeof(curType)); + if (thing_type_size(curType) != size) continue; + data = *it; + m_deadThingData.erase(it); + break; + } + if (data == nullptr) data = m_thingArena.allocate(sizeof(thing_t) + size); + memcpy(data, &type, sizeof(type)); + data = static_cast(data) + sizeof(type); + + thing_p thing = std::make_shared(type, data); + return { id, m_things.emplace_back(std::move(thing)) }; + } private: std::unordered_map m_modules; diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 24436fe..b550789 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -37,7 +37,7 @@ public: std::size_t position; /**< Cursor to a current instruction in the bytecode. */ std::size_t stackBase; /**< Snapshot of the stack size before this frame. */ - std::vector variables; /**< Frame variables. */ + std::vector variables; /**< Frame variables. */ }; public: /** @@ -104,28 +104,28 @@ public: * * @param thing The thing to push. */ - void push_thing(const thing_p& thing); + void push_thing(const thing_h& thing); /** * @brief Pushes a thing onto the stack. * * @param thing The thing to push. */ - void push_thing(thing_p&& thing); + void push_thing(thing_h&& thing); /** * @brief Pops a thing from the stack. * * @return The popped thing. */ - thing_p pop_thing(); + thing_h pop_thing(); /** * @brief Returns the top thing on the stack. * * @return The thing. */ - thing_p thing() const; + thing_h thing() const; public: /** * @brief Stores a thing in a variable. @@ -133,7 +133,7 @@ public: * @param variable Variable to store the thing in. * @param thing Thing to store. */ - void store_thing(variable_t variable, const thing_p& thing); + void store_thing(variable_t variable, const thing_h& thing); /** * @brief Stores a thing in a variable. @@ -141,7 +141,7 @@ public: * @param variable Variable to store the thing in. * @param thing Thing to store. */ - void store_thing(variable_t variable, thing_p&& thing); + void store_thing(variable_t variable, thing_h&& thing); /** * @brief Returns a thing stored in a variable. @@ -149,7 +149,7 @@ public: * @param variable Variable where the thing is stored. * @return The thing stored in the variable. */ - thing_p load_thing(variable_t variable) const; + thing_h load_thing(variable_t variable) const; public: /** * @brief Executes next instruction. @@ -160,7 +160,7 @@ private: context_p m_context; std::stack m_frames; - std::stack m_stack; + std::stack m_stack; }; } // namespace furvm diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index e5afc2c..d947449 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -151,7 +151,7 @@ using thing_id = std::uint32_t; /** * @brief A handle to a furvm's thing. */ -using thing_h = handle; +using thing_h = handle; // executor.hpp diff --git a/furvm/include/furvm/handle.hpp b/furvm/include/furvm/handle.hpp index c1f3503..7f10bfc 100644 --- a/furvm/include/furvm/handle.hpp +++ b/furvm/include/furvm/handle.hpp @@ -1,10 +1,26 @@ #ifndef FURVM_HANDLE_HPP #define FURVM_HANDLE_HPP +#include +#include #include namespace furvm { +namespace detail { + +template +struct dead_id { + static constexpr Id value = {}; +}; + +template +struct dead_id>> { + static constexpr Id value = std::numeric_limits::max(); +}; + +} // namespace detail + template class handle { public: @@ -25,6 +41,9 @@ public: template handle(IdF&& id, Value&& value) : m_id(std::forward(id)), m_value(std::forward(value)) {} + + handle() + : m_id(detail::dead_id::value), m_value() {} public: handle& operator=(value_type&& value) noexcept { m_value = std::move(value); diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index d85c5fc..1320a0c 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -1,7 +1,6 @@ #ifndef FURVM_THING_HPP #define FURVM_THING_HPP -#include "furvm/context.hpp" // IWYU pragma: keep #include "furvm/fwd.hpp" namespace furvm { @@ -58,7 +57,9 @@ public: static constexpr thing_id GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */ public: - thing(const context_p& context, thing_t type); + thing(thing_t type); + + thing(thing_t type, void* data); ~thing(); @@ -74,104 +75,6 @@ public: thing(const thing&) = delete; thing& operator=(const thing&) = delete; -public: - /** - * @brief Adds two things together. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator+(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Subtracts two things together. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator-(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Multiplies two things together. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator*(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Divides two things together. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator/(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Modulos two things together. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator%(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Compares two things for equality. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator==(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Compares two things for equality. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator!=(const thing_p& lhs, const thing_p& rhs); - /** - * @brief Compares if the left thing is less than the right thing. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator<(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Compares if the left thing is greater than the right thing. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator>(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Compares if the left thing is less than or equal to the right thing. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator<=(const thing_p& lhs, const thing_p& rhs); - - /** - * @brief Compares if the left thing is greater than or equal to the right thing. - * - * @param lhs Left-hand-side thing. - * @param rhs Right-hand-side thing. - * @return Shared pointer to result thing. - */ - friend thing_p operator>=(const thing_p& lhs, const thing_p& rhs); public: /** * @brief Returns a clone of the thing. @@ -179,7 +82,7 @@ public: * @param thing Thing to clone. * @return Shared pointer to a clone of the thing. */ - static thing_p clone(const thing_p& thing); + static thing_h clone(const context_p& context, const thing_h& thing); public: /** * @brief Returns an int32 value from this thing. @@ -194,6 +97,18 @@ public: * @return The value. */ const std::int32_t& int32() const; +public: + thing_h add(const context_p& context, const thing_h& rhs) const; + thing_h sub(const context_p& context, const thing_h& rhs) const; + thing_h mul(const context_p& context, const thing_h& rhs) const; + thing_h div(const context_p& context, const thing_h& rhs) const; + thing_h mod(const context_p& context, const thing_h& rhs) const; + thing_h equals(const context_p& context, const thing_h& rhs) const; + thing_h not_equals(const context_p& context, const thing_h& rhs) const; + thing_h less_than(const context_p& context, const thing_h& rhs) const; + thing_h greater_than(const context_p& context, const thing_h& rhs) const; + thing_h less_equals(const context_p& context, const thing_h& rhs) const; + thing_h greater_equals(const context_p& context, const thing_h& rhs) const; public: /** * @brief Increments reference count of this thing by one. @@ -212,11 +127,10 @@ public: */ constexpr nref_t reference_count() const { return m_refCount; } private: - context_p m_context; - thing_t m_type; - - nref_t m_refCount = 0; - void* m_data = nullptr; + thing_t m_type; + bool m_ownData = true; + nref_t m_refCount = 0; + void* m_data = nullptr; }; } // namespace furvm diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 4feb333..2f7cf63 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -8,7 +8,6 @@ #include "furvm/thing.hpp" #include -#include #include namespace furvm { @@ -29,50 +28,50 @@ struct executor::frame executor::frame() const { return m_frames.top(); } -void executor::push_thing(const thing_p& thing) { - thing->add_reference(); +void executor::push_thing(const thing_h& thing) { + (*thing)->add_reference(); m_stack.push(thing); } -void executor::push_thing(thing_p&& thing) { - thing->add_reference(); +void executor::push_thing(thing_h&& thing) { + (*thing)->add_reference(); m_stack.push(std::move(thing)); } -thing_p executor::pop_thing() { +thing_h executor::pop_thing() { if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow(); - thing_p top = std::move(m_stack.top()); + thing_h top = std::move(m_stack.top()); m_stack.pop(); - top->remove_reference(); + (*top)->remove_reference(); return top; } -thing_p executor::thing() const { +thing_h executor::thing() const { if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow(); return m_stack.top(); } -void executor::store_thing(variable_t variable, const thing_p& thing) { +void executor::store_thing(variable_t variable, const thing_h& thing) { auto& frame = m_frames.top(); frame.variables.resize(variable + 1); - if (frame.variables[variable] != nullptr) { - frame.variables[variable]->remove_reference(); + if (*frame.variables[variable] != nullptr) { + (*frame.variables[variable])->remove_reference(); } frame.variables[variable] = thing; - thing->add_reference(); + (*thing)->add_reference(); } -void executor::store_thing(variable_t variable, thing_p&& thing) { +void executor::store_thing(variable_t variable, thing_h&& thing) { auto& frame = m_frames.top(); frame.variables.resize(variable + 1); - if (frame.variables[variable] != nullptr) { - frame.variables[variable]->remove_reference(); + if ((*frame.variables[variable]) != nullptr) { + (*frame.variables[variable])->remove_reference(); } - thing->add_reference(); + (*thing)->add_reference(); frame.variables[variable] = std::move(thing); } -thing_p executor::load_thing(variable_t variable) const { +thing_h executor::load_thing(variable_t variable) const { const auto& frame = m_frames.top(); return frame.variables[variable]; } @@ -86,8 +85,8 @@ void executor::step() { switch (instr) { case instruction_t::NoOperation: break; case instruction_t::PushB2I: { - auto thing = std::make_shared(m_context, thing_t::Int32); - thing->int32() = (*frame.mod)->byte(frame.position++); + auto thing = m_context->emplace_thing(thing_t::Int32); + (*thing)->int32() = (*frame.mod)->byte(frame.position++); push_thing(std::move(thing)); } break; case instruction_t::Drop: { @@ -97,62 +96,62 @@ void executor::step() { push_thing(thing()); } break; case instruction_t::Clone: { - push_thing(std::move(thing::clone(thing()))); + push_thing(std::move(thing::clone(m_context, thing()))); } break; case instruction_t::Add: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs + rhs); + push_thing((*lhs)->add(m_context, rhs)); } break; case instruction_t::Sub: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs - rhs); + push_thing((*lhs)->sub(m_context, rhs)); } break; case instruction_t::Mul: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs * rhs); + push_thing((*lhs)->mul(m_context, rhs)); } break; case instruction_t::Div: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs / rhs); + push_thing((*lhs)->div(m_context, rhs)); } break; case instruction_t::Mod: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs % rhs); + push_thing((*lhs)->mod(m_context, rhs)); } break; case instruction_t::Equals: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs == rhs); + push_thing((*lhs)->equals(m_context, rhs)); } break; case instruction_t::NotEquals: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs != rhs); + push_thing((*lhs)->not_equals(m_context, rhs)); } break; case instruction_t::LessThan: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs < rhs); + push_thing((*lhs)->less_than(m_context, rhs)); } break; case instruction_t::GreaterThan: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs > rhs); + push_thing((*lhs)->greater_than(m_context, rhs)); } break; case instruction_t::LessEqual: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs <= rhs); + push_thing((*lhs)->less_equals(m_context, rhs)); } break; case instruction_t::GreaterEqual: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs >= rhs); + push_thing((*lhs)->greater_equals(m_context, rhs)); } break; case instruction_t::Load: { variable_t variable = static_cast((*frame.mod)->byte(frame.position)) | @@ -188,7 +187,7 @@ void executor::step() { case instruction_t::JumpNotZero: { byte offset = (*frame.mod)->byte(frame.position++); auto cond = pop_thing(); - if (cond->int32() != 0) frame.position += offset; + if ((*cond)->int32() != 0) frame.position += offset; } break; case instruction_t::Return: { pop_frame(); diff --git a/furvm/src/thing.cpp b/furvm/src/thing.cpp index 75cae45..8cd4f80 100644 --- a/furvm/src/thing.cpp +++ b/furvm/src/thing.cpp @@ -17,23 +17,10 @@ std::size_t thing_type_size(thing_t type) { return 0; } -thing::thing(const context_p& context, thing_t type) - : m_context(context), m_type(type) { +thing::thing(thing_t type) + : m_type(type) { std::size_t size = thing_type_size(type); - std::byte* data = nullptr; - if (!m_context->m_deadThingData.empty()) { - thing_t itType{}; - for (auto it = m_context->m_deadThingData.rbegin(); it != m_context->m_deadThingData.rend(); ++it) { - std::memcpy(&itType, static_cast(*it) - sizeof(itType), sizeof(itType)); - if (size == thing_type_size(itType)) { - data = static_cast(*it); - m_context->m_deadThingData.erase(std::next(it).base()); - break; - } - } - } - if (data == nullptr) data = m_context->m_thingArena.allocate(sizeof(type) + size); - + byte* data = new byte[size]; if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing"); std::memcpy(data, &type, sizeof(type)); m_data = data + sizeof(type); @@ -45,6 +32,20 @@ thing::thing(const context_p& context, thing_t type) } } +thing::thing(thing_t type, void* data) + : m_type(type), m_ownData(false) { + std::size_t size = thing_type_size(type); + if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing"); + std::memcpy(data, &type, sizeof(type)); + m_data = static_cast(data) + sizeof(type); + + switch (m_type) { + // Primitives are zero-initialized. + default: + case thing_t::Int32: std::memset(m_data, 0, size); + } +} + thing::~thing() { switch (m_type) { // Primitives are not destructed. @@ -52,19 +53,19 @@ thing::~thing() { case thing_t::Int32: break; } - m_context->m_deadThingData.push_back(m_data); + if (m_ownData) delete[] static_cast(m_data); } thing::thing(thing&& other) noexcept - : m_context(std::move(other.m_context)), m_type(other.m_type), m_refCount(other.m_refCount), m_data(other.m_data) { + : m_type(other.m_type), m_refCount(other.m_refCount), m_data(other.m_data) { other.m_type = {}; + other.m_ownData = false; other.m_refCount = {}; other.m_data = nullptr; } thing& thing::operator=(thing&& other) noexcept { if (this == &other) return *this; - m_context = std::move(other.m_context); m_type = other.m_type; m_refCount = other.m_refCount; m_data = other.m_data; @@ -79,145 +80,15 @@ static constexpr std::uint16_t thing_type_pair(thing_t lhs, thing_t rhs) { return (static_cast(lhs) << 8) | static_cast(rhs); } -thing_p operator+(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = lhs->int32() + rhs->int32(); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator-(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = lhs->int32() - rhs->int32(); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator*(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = lhs->int32() * rhs->int32(); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator/(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = lhs->int32() / rhs->int32(); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator%(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = lhs->int32() % rhs->int32(); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator==(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(lhs->int32() == rhs->int32()); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator!=(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(lhs->int32() != rhs->int32()); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator<(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(lhs->int32() < rhs->int32()); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator>(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(lhs->int32() > rhs->int32()); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator<=(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(lhs->int32() <= rhs->int32()); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p operator>=(const thing_p& lhs, const thing_p& rhs) { - switch (thing_type_pair(lhs->m_type, rhs->m_type)) { - case thing_type_pair(thing_t::Int32, thing_t::Int32): { - auto res = std::make_shared(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(lhs->int32() >= rhs->int32()); - return res; - } - default: throw std::runtime_error("unexpected operator"); - } -} - -thing_p thing::clone(const thing_p& thing) { - thing_id id = thing->m_context->m_things.size(); - if (!thing->m_context->m_deadThings.empty()) { - id = thing->m_context->m_deadThings.front(); - thing->m_context->m_deadThings.pop(); - id += 1 << GENERATION_SIZE; - } - thing_id idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1); - - auto th = std::make_shared(thing->m_context, thing->m_type); - switch (thing->m_type) { +thing_h thing::clone(const context_p& context, const thing_h& thing) { + auto th = context->emplace_thing((*thing)->m_type); + switch ((*thing)->m_type) { // Primitives default: { - memcpy(th->m_data, thing->m_data, thing_type_size(thing->m_type)); + memcpy((*th)->m_data, (*thing)->m_data, thing_type_size((*thing)->m_type)); } } - thing->m_context->m_things.emplace(thing->m_context->m_things.begin() + idx, th); return std::move(th); } @@ -231,6 +102,127 @@ const std::int32_t& thing::int32() const { return *static_cast(m_data); } +thing_h thing::add(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = int32() + (*rhs)->int32(); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::sub(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = int32() - (*rhs)->int32(); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::mul(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = int32() * (*rhs)->int32(); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::div(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = int32() / (*rhs)->int32(); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::mod(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = int32() % (*rhs)->int32(); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::equals(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = static_cast(int32() == (*rhs)->int32()); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::not_equals(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = static_cast(int32() != (*rhs)->int32()); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::less_than(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = static_cast(int32() < (*rhs)->int32()); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::greater_than(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = static_cast(int32() > (*rhs)->int32()); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::less_equals(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = static_cast(int32() <= (*rhs)->int32()); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + +thing_h thing::greater_equals(const context_p& context, const thing_h& rhs) const { + switch (thing_type_pair(m_type, (*rhs)->m_type)) { + case thing_type_pair(thing_t::Int32, thing_t::Int32): { + thing_h res = context->emplace_thing(thing_t::Int32); + (*res)->int32() = static_cast(int32() >= (*rhs)->int32()); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + } // namespace furvm // NOLINTEND(cppcoreguidelines-no-malloc) From ec2c81fc569f8935c6ef1c466cb0781b427404cf Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Thu, 18 Jun 2026 23:58:37 +0200 Subject: [PATCH 10/30] refactor(furvm): improve the handle system Absolute slop Refs: #12 --- furlang/include/furlang/arena.hpp | 51 ++++- furvm/include/furvm/context.hpp | 152 +++++-------- furvm/include/furvm/detail/handle.hpp | 24 ++ furvm/include/furvm/executor.hpp | 15 +- furvm/include/furvm/fwd.hpp | 46 ++-- furvm/include/furvm/handle.hpp | 315 ++++++++++++++++++-------- furvm/include/furvm/module.hpp | 83 +++---- furvm/include/furvm/thing.hpp | 213 +++++++++++++---- furvm/src/context.cpp | 10 +- furvm/src/executor.cpp | 69 +++--- furvm/src/main.cpp | 3 +- furvm/src/serializer.cpp | 49 ++-- furvm/src/thing.cpp | 228 ------------------- 13 files changed, 641 insertions(+), 617 deletions(-) create mode 100644 furvm/include/furvm/detail/handle.hpp delete mode 100644 furvm/src/thing.cpp diff --git a/furlang/include/furlang/arena.hpp b/furlang/include/furlang/arena.hpp index ef87d97..58dce98 100644 --- a/furlang/include/furlang/arena.hpp +++ b/furlang/include/furlang/arena.hpp @@ -106,6 +106,55 @@ private: region* m_tail = nullptr; }; +template +class arena_allocator { + template + friend class arena_allocator; +public: + using value_type = T; +public: + explicit arena_allocator(arena& arena) noexcept + : m_arena(&arena) {} + + template + arena_allocator(const arena_allocator& other) noexcept + : m_arena(other.m_arena) {} + + template + arena_allocator& operator=(const arena_allocator& other) noexcept { + if (this == &other) return *this; + m_arena = other.m_arena; + return *this; + } + + template + arena_allocator(arena_allocator&& other) noexcept + : m_arena(std::move(other.m_arena)) {} + + template + arena_allocator& operator=(arena_allocator&& other) noexcept { + if (this == &other) return *this; + m_arena = std::move(other.m_arena); + return *this; + } +public: + [[nodiscard]] T* allocate(std::size_t count = 1) { return m_arena->allocate(count); } + + void deallocate(T* ptr, std::size_t count) noexcept {} +public: + template + bool operator==(const arena_allocator& other) const noexcept { + return m_arena == other.m_arena; + } + + template + bool operator!=(const arena_allocator& other) const noexcept { + return m_arena != other.m_arena; + } +private: + arena* m_arena; +}; + } // namespace furlang -#endif // FURLANG_ARENA_HPP \ No newline at end of file +#endif // FURLANG_ARENA_HPP diff --git a/furvm/include/furvm/context.hpp b/furvm/include/furvm/context.hpp index f2e9298..e1203dd 100644 --- a/furvm/include/furvm/context.hpp +++ b/furvm/include/furvm/context.hpp @@ -4,24 +4,18 @@ #include "furlang/arena.hpp" #include "furvm/executor.hpp" #include "furvm/fwd.hpp" -#include "furvm/module.hpp" -#include "furvm/thing.hpp" +#include "furvm/handle.hpp" +#include "furvm/module.hpp" // IWYU pragma: keep +#include "furvm/thing.hpp" // IWYU pragma: keep -#include -#include -#include -#include -#include -#include +#include #include -#include namespace furvm { class context { public: friend class executor; - friend class thing; public: context(); ~context() = default; @@ -39,105 +33,77 @@ public: context(const context&) = delete; context& operator=(const context&) = delete; public: - /** - * @brief Emplaces a new module in this context. - * - * @param args Arguments to forward to module's constructor. - * @return A handle to the module. - */ - template >> - mod_h emplace_module(Args&&... args) { - mod_p mod = std::make_shared(std::forward(args)...); - std::string name = mod->name(); - return { name, m_modules[name] = std::move(mod) }; + template + auto emplace_module(Args&&... args) { + return m_modules.emplace(std::forward(args)...); } - /** - * @brief Erases a module from this context. - * - * @param name Name of the module to erase. - * @return A shared pointer to the erased module. - */ - template - mod_p erase_module(Name&& name) { - return std::move(m_modules.erase(std::forward(name))->second); + template + auto module_at(Args&&... args) { + return m_modules.at(std::forward(args)...); } - /** - * @brief Returns a module of this context. - * - * @param name Name of the module. - * @return The module. - */ - template - constexpr mod_p& module_at(Name&& name) { - return m_modules.at(std::forward(name)); + template + auto module_at(Args&&... args) const { + return m_modules.at(std::forward(args)...); } - /** - * @brief Returns a module of this context. - * - * @param name Name of the module. - * @return The module. - */ - template - constexpr const mod_p& module_at(Name&& name) const { - return m_modules.at(std::forward(name)); + template + auto erase_module(Args&&... args) { + return m_modules.erase(std::forward(args)...); } - - /** - * @brief Returns how many does this context have modules. - * - * @return The module count. - */ - constexpr size_t module_count() const { return m_modules.size(); } public: - template >> - executor_h emplace_executor(Args&&... args) { - executor executor(std::forward(args)...); - executor_id id = m_executors.size(); - m_executors.emplace_back(std::move(executor)); - return { id, m_executors[id] }; + template + auto emplace_executor(Args&&... args) { + return m_executors.emplace_back(std::forward(args)...); + } + + template + auto executor_at(Args&&... args) { + return m_executors.at(std::forward(args)...); + } + + template + auto executor_at(Args&&... args) const { + return m_executors.at(std::forward(args)...); + } + + template + auto erase_executor(Args&&... args) { + return m_executors.erase(std::forward(args)...); + } +public: + template + auto emplace_thing(Args&&... args) { + return m_things.emplace_back(std::forward(args)...); + } + + template + auto thing_at(Args&&... args) { + return m_things.at(std::forward(args)...); + } + + template + auto thing_at(Args&&... args) const { + return m_things.at(std::forward(args)...); + } + + template + auto erase_thing(Args&&... args) { + return m_things.erase(std::forward(args)...); } public: /** * @brief Removes unreferenced things from the thing list. */ void collect(); -public: - thing_h emplace_thing(thing_t type) { - thing_id id = m_things.size(); - if (!m_deadThings.empty()) { - id = m_deadThings.front(); - m_deadThings.pop(); - } - - size_t size = thing_type_size(type); - void* data = nullptr; - for (auto it = m_deadThingData.begin(); it != m_deadThingData.end(); ++it) { - thing_t curType{}; - std::memcpy(&curType, static_cast(*it) - sizeof(curType), sizeof(curType)); - if (thing_type_size(curType) != size) continue; - data = *it; - m_deadThingData.erase(it); - break; - } - if (data == nullptr) data = m_thingArena.allocate(sizeof(thing_t) + size); - memcpy(data, &type, sizeof(type)); - data = static_cast(data) + sizeof(type); - - thing_p thing = std::make_shared(type, data); - return { id, m_things.emplace_back(std::move(thing)) }; - } private: - std::unordered_map m_modules; + handle_container m_modules; + handle_container m_things; + handle_container m_executors; - std::vector m_things; - std::vector m_executors; - - std::queue m_deadThings; - std::vector m_deadThingData; - furlang::arena m_thingArena; + furlang::arena m_thingArena; + thing_allocator m_thingAllocator; }; } // namespace furvm diff --git a/furvm/include/furvm/detail/handle.hpp b/furvm/include/furvm/detail/handle.hpp new file mode 100644 index 0000000..e426c33 --- /dev/null +++ b/furvm/include/furvm/detail/handle.hpp @@ -0,0 +1,24 @@ +#ifndef FURVM_DETAIL_HANDLE_HPP +#define FURVM_DETAIL_HANDLE_HPP + +#include + +namespace furvm { +namespace detail { + +template +struct header_has_refcount : std::false_type {}; + +template +struct header_has_refcount().acquire()), + decltype(std::declval().release()), + decltype(std::declval().reference_count())>> : std::true_type {}; + +template +static constexpr auto header_has_refcount_v = header_has_refcount
::value; + +} // namespace detail +} // namespace furvm + +#endif // FURVM_DETAIL_HANDLE_HPP diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index b550789..ae60589 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -2,8 +2,11 @@ #define FURVM_EXECUTOR_HPP #include "furvm/fwd.hpp" +#include "furvm/module.hpp" // IWYU pragma: keep +#include "furvm/thing.hpp" // IWYU pragma: keep #include +#include #include namespace furvm { @@ -99,19 +102,17 @@ public: */ frame frame() const; public: - /** - * @brief Pushes a thing onto the stack. - * - * @param thing The thing to push. - */ - void push_thing(const thing_h& thing); + template + void push_thing(HandleFwd&& handle) { + m_stack.emplace(std::forward(handle)); + } /** * @brief Pushes a thing onto the stack. * * @param thing The thing to push. */ - void push_thing(thing_h&& thing); + thing_h push_thing(class thing<>&& thing); /** * @brief Pops a thing from the stack. diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index d947449..6c4c822 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -1,8 +1,6 @@ #ifndef FURVM_FWD_HPP #define FURVM_FWD_HPP -#include "furvm/handle.hpp" - #include // IWYU pragma: export #include // IWYU pragma: export #include @@ -25,6 +23,24 @@ using byte = std::uint8_t; */ using bytecode_pos = std::uint64_t; +/** + * @brief Handle header with reference count. + */ +template +class refcount_header; + +/** + * @brief Generic handle header. + */ +template +class generic_header; + +/** + * @brief Handle. + */ +template +class handle; + // constant.hpp /** @@ -76,11 +92,6 @@ enum class function_t : std::uint8_t; */ class function; -/** - * @brief An alias to a function shared pointer. - */ -using function_p = std::shared_ptr; - /** * @brief Furvm function's index. */ @@ -89,7 +100,7 @@ using function_id = std::uint16_t; /** * @brief A handle to a furvm function. */ -using function_h = handle; +using function_h = handle>; // module.hpp @@ -114,7 +125,7 @@ using mod_id = std::string; /** * @brief A handle to a furvm module. */ -using mod_h = handle; +using mod_h = handle>; // thing.hpp @@ -130,28 +141,27 @@ enum class thing_t : std::uint8_t; */ class bad_thing_access; +template +class thing_allocator; + /** * @class thing * @brief Furvm thing. * * A stack element. Think of it like of a value in C++ or I guess a class in java. */ +template