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()) {