diff --git a/furc/src/back/furvm.cpp b/furc/src/back/furvm.cpp index 2c3de20..0f7c9a0 100644 --- a/furc/src/back/furvm.cpp +++ b/furc/src/back/furvm.cpp @@ -2,6 +2,7 @@ #include "furlang/ir/function.hpp" #include "furlang/ir/instruction.hpp" +#include "furvm/function.hpp" #include "furvm/fwd.hpp" #include @@ -20,12 +21,14 @@ furvm::mod furvm_generator::generate(furlang::ir::mod& mod) { } void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::function& function) { + furvm::function_sig signature; // TODO: Complete + switch (function.type()) { case furlang::ir::function_t::Normal: { if (function.access() == furlang::ir::function_access_t::Public) - mod.emplace_function_named(function.name(), function.param_count(), mod.bytecode().size()).dispatch(); + mod.emplace_function(function.name(), std::move(signature), mod.bytecode().size()).dispatch(); else - mod.emplace_function(function.param_count(), mod.bytecode().size()).dispatch(); + mod.emplace_function(std::move(signature), mod.bytecode().size()).dispatch(); function_context ctx; for (furlang::ir::block_index idx = 0; idx < function.blocks().size(); ++idx) { @@ -48,9 +51,9 @@ void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::func } break; case furlang::ir::function_t::Native: { if (function.access() == furlang::ir::function_access_t::Public) - mod.emplace_function_named(function.name(), function.param_count(), function.name()).dispatch(); + mod.emplace_function(function.name(), std::move(signature), function.name()).dispatch(); else - mod.emplace_function(function.param_count(), function.name()).dispatch(); + mod.emplace_function(std::move(signature), function.name()).dispatch(); } break; } } @@ -150,7 +153,7 @@ void furvm_generator::generate_instruction(furvm::mod& mod, const auto& call = dynamic_cast(instr); // TODO: Implement a queue for unknown functions - furvm::function_id func = mod.function_at(call.name()).id(); + furvm::function_id func = mod.function_at(call.name(), furvm::function_sig{}).id(); // TODO: Complete mod.bytecode().push_back(static_cast(furvm::instruction_t::Call)); mod.bytecode().push_back((func >> 0) & 0xFF); mod.bytecode().push_back((func >> 8) & 0xFF); diff --git a/furc/src/main.cpp b/furc/src/main.cpp index f5ce2a4..84f97ed 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -71,7 +71,7 @@ int main(void) { [](furvm::executor& executor) { std::cout << executor.load_thing(0)->integer() << '\n'; }); furvm::executor_h executor = context->emplace_executor(context); - executor->push_frame(furvmMod, *furvmMod->function_at("main")); + executor->push_frame(furvmMod, *furvmMod->function_at("main", furvm::function_sig{})); std::cout << "--- Interpreting:\n"; diff --git a/furvm/include/furvm/detail/handle.hpp b/furvm/include/furvm/detail/handle.hpp index 25f5641..c9c9e2a 100644 --- a/furvm/include/furvm/detail/handle.hpp +++ b/furvm/include/furvm/detail/handle.hpp @@ -1,6 +1,7 @@ #ifndef FURVM_DETAIL_HANDLE_HPP #define FURVM_DETAIL_HANDLE_HPP +#include #include namespace furvm { @@ -27,6 +28,11 @@ struct header_has_refcount static constexpr auto header_has_refcount_v = header_has_refcount
::value; +template > +struct handle_hash { + std::size_t operator()(const Handle& handle) const { return IdHash{}(handle.id()); } +}; + } // namespace detail } // namespace furvm diff --git a/furvm/include/furvm/function.hpp b/furvm/include/furvm/function.hpp index caf4b50..8fdd194 100644 --- a/furvm/include/furvm/function.hpp +++ b/furvm/include/furvm/function.hpp @@ -1,6 +1,7 @@ #ifndef FURVM_FUNCTION_HPP #define FURVM_FUNCTION_HPP +#include "furlang/utility/hash.hpp" #include "furvm/fwd.hpp" #include "furvm/handle.hpp" // IWYU pragma: keep @@ -9,6 +10,7 @@ #include #include #include +#include namespace furvm { @@ -31,26 +33,43 @@ struct import_function { function_id function; }; +/** + * @brief Function signature. + */ +struct function_sig { + std::vector params; + + bool operator==(const function_sig& rhs) const { return params == rhs.params; } + + bool operator!=(const function_sig& rhs) const { return !this->operator==(rhs); } +}; + class function { public: /** * @brief Constructs a normal function. * - * @param paramCount Paremeter count. + * @param signature Function's signature. * @param position Offset in bytecode of the function. */ - function(std::uint32_t paramCount, bytecode_pos position) - : m_type(function_t::Normal), m_paramCount(paramCount), m_value(position) {} + template >> + function(SigFwd&& signature, bytecode_pos position) + : m_type(function_t::Normal), m_signature(std::forward(signature)), m_value(position) {} /** * @brief Constructs a native function. * - * @param paramCount Paremeter count. + * @param signature Function's signature. * @param native Native function tag. */ - template >> - function(std::uint32_t paramCount, Native&& native) - : m_type(function_t::Native), m_paramCount(paramCount), m_value(std::forward(native)) {} + template && + std::is_constructible_v>> + function(SigFwd&& signature, Native&& native) + : m_type(function_t::Native), + m_signature(std::forward(signature)), + m_value(std::forward(native)) {} /** * @brief Constructs an import function. @@ -60,7 +79,7 @@ public: */ template >> function(ModFwd&& mod, function_id function) - : m_type(function_t::Import), m_paramCount(0), m_value(import_function{ std::forward(mod), function }) {} + : m_type(function_t::Import), m_signature(), m_value(import_function{ std::forward(mod), function }) {} /** * @brief Constructs an import function. @@ -103,11 +122,11 @@ public: constexpr function_t type() const { return m_type; } /** - * @brief Returns this function's parameter count. + * @brief Returns this function's signature. * - * @return The parameter count. + * @return The signature. */ - constexpr std::uint32_t param_count() const { return m_paramCount; } + function_sig signature() const { return m_signature; } public: /** * @brief Returns normal function's value. @@ -139,8 +158,8 @@ public: return m_value.imp; } private: - function_t m_type; - std::uint32_t m_paramCount; + function_t m_type; + function_sig m_signature; union value { std::size_t position = 0; @@ -168,6 +187,16 @@ private: } m_value; }; +namespace detail { + +struct function_sig_hash { + std::size_t operator()(const function_sig& signature) const { + return furlang::utility::vector_hash>{}(signature.params); + } +}; + +} // namespace detail + } // namespace furvm #endif // FURVM_FUNCTION_HPP diff --git a/furvm/include/furvm/handle.hpp b/furvm/include/furvm/handle.hpp index 7016d17..c08653b 100644 --- a/furvm/include/furvm/handle.hpp +++ b/furvm/include/furvm/handle.hpp @@ -237,6 +237,10 @@ public: * @brief Invalidates the handle without releasing. */ void dispatch() { m_value = nullptr; } +public: + bool operator==(const handle& rhs) const { return m_value == rhs.m_value; } + + bool operator!=(const handle& rhs) const { return !this->operator==(rhs); } private: pair_type* m_value = nullptr; }; diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index c2d766e..976dc73 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -1,6 +1,7 @@ #ifndef FURVM_MODULE_HPP #define FURVM_MODULE_HPP +#include "furlang/utility/hash.hpp" #include "furvm/function.hpp" #include "furvm/fwd.hpp" #include "furvm/handle.hpp" @@ -90,7 +91,6 @@ public: } else { function = std::move(m_functions.emplace(std::forward(args)...)); } - m_functionMap[function.id()] = ""; return std::move(function); } @@ -99,22 +99,23 @@ public: * * Emplaces the function in module's function container and name to function map. * + * @param name Name of the function. * @param args Arguments forwarded into the container's emplace_back function. * @return A handle to the emplaced function. */ template >> - function_h emplace_function_named(NameFwd&& name, Args&&... args) { + function_h emplace_function(NameFwd&& name, Args&&... args) { function_h function; if constexpr (std::is_constructible_v) { function = std::move(m_functions.emplace_back(std::forward(args)...)); } else { function = std::move(m_functions.emplace(std::forward(args)...)); } - std::string nameInst = std::forward(name); - m_functionNames[nameInst] = function.id(); - m_functionMap[function.id()] = nameInst; + auto pair = std::make_pair(std::forward(name), function->signature()); + m_functionMap[function.id()] = pair; + m_functionSigs[std::move(pair)] = function.id(); return std::move(function); } @@ -140,20 +141,13 @@ public: * @param name Name of the function. * @return A handle to the function. */ - template >> - auto function_at(NameFwd&& name) { - return function_at(m_functionNames.at(std::forward(name))); - } - - /** - * @brief Returns a function from the module. - * - * @param name Name of the function. - * @return A handle to the function. - */ - template >> - auto function_at(NameFwd&& name) const { - return function_at(m_functionNames.at(std::forward(name))); + template && + std::is_constructible_v>> + auto function_at(NameFwd&& name, SigFwd&& signature) { + return function_at( + m_functionSigs.at(std::make_pair<>(std::forward(name), std::forward(signature)))); } /** @@ -161,7 +155,13 @@ public: * * @param id Identifier of the function. */ - void erase_function(function_id id) { m_functions.erase(id); } + void erase_function(function_id id) { + m_functions.erase(id); + if (auto it = m_functionMap.find(id); it != m_functionMap.end()) { + m_functionSigs.erase(it->second); + m_functionMap.erase(it); + } + } public: template void set_native_function(NameFwd&& name, Func&& func) { @@ -238,9 +238,12 @@ public: private: bytecode_t m_bytecode; - std::unordered_map m_functionNames; - std::unordered_map m_functionMap; - handle_container m_functions; + using pair_type = std::pair; + using pair_hash = + furlang::utility::pair_hash, detail::function_sig_hash>; + std::unordered_map m_functionSigs; + std::unordered_map m_functionMap; + handle_container m_functions; handle_container m_types; diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 9c79263..c74cb57 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -22,8 +22,8 @@ void executor::push_frame(const mod_h& mod, function function) { } std::vector args; - args.reserve(function.param_count()); - for (size_t i = 0; i < function.param_count(); ++i) + args.reserve(function.signature().params.size()); + while (args.size() < args.capacity()) args.push_back(pop_thing()); switch (function.type()) { diff --git a/furvm/src/function.cpp b/furvm/src/function.cpp index f1f18fb..c8eaae6 100644 --- a/furvm/src/function.cpp +++ b/furvm/src/function.cpp @@ -7,7 +7,7 @@ namespace furvm { function::function(const mod_h& mod, const function_h& function) - : m_type(function_t::Import), m_paramCount(0), m_value(import_function{ mod.id(), function.id() }) {} + : m_type(function_t::Import), m_value(import_function{ mod.id(), function.id() }) {} function::~function() { switch (m_type) { @@ -23,7 +23,7 @@ function::~function() { } function::function(function&& other) noexcept - : m_type(other.m_type), m_paramCount(other.m_paramCount) { + : m_type(other.m_type), m_signature(std::move(other.m_signature)) { switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; @@ -42,8 +42,8 @@ function::function(function&& other) noexcept function& function::operator=(function&& other) noexcept { if (this == &other) return *this; - m_type = other.m_type; - m_paramCount = other.m_paramCount; + m_type = other.m_type; + m_signature = other.m_signature; switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; @@ -62,7 +62,7 @@ function& function::operator=(function&& other) noexcept { } function::function(const function& other) - : m_type(other.m_type), m_paramCount(other.m_paramCount) { + : m_type(other.m_type), m_signature(other.m_signature) { switch (m_type) { case function_t::Normal: { m_value.position = other.m_value.position; @@ -80,8 +80,8 @@ function::function(const function& other) function& function::operator=(const function& other) { if (this == &other) return *this; - m_type = other.m_type; - m_paramCount = other.m_paramCount; + m_type = other.m_type; + m_signature = other.m_signature; 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 6fdae55..d773cb0 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -58,10 +58,10 @@ int main(int argc, char** argv) { static_cast(furvm::instruction_t::Return), }; - furvm::mod_h mod = context->emplace("main", s_bytecode, s_bytecode + sizeof(s_bytecode)); - mod->emplace_type(std::make_shared(context->at("core")->type_at(2), 10)).dispatch(); - auto mainFunc = mod->emplace_function_named("main", 0, 0); - mod->emplace_function(1, "print").dispatch(); + furvm::mod_h mod = context->emplace("main", s_bytecode, s_bytecode + sizeof(s_bytecode)); + furvm::type_h intType = mod->emplace_type(std::make_shared(context->at("core")->type_at(2), 10)); + auto mainFunc = mod->emplace_function("main", furvm::function_sig{}, 0); + mod->emplace_function(furvm::function_sig{ { intType } }, "print").dispatch(); #endif mod->set_native_function("print", [](furvm::executor& executor) { print_thing(*executor.load_thing(0)); }); diff --git a/furvm/src/module.cpp b/furvm/src/module.cpp index dea96be..d367e73 100644 --- a/furvm/src/module.cpp +++ b/furvm/src/module.cpp @@ -1,6 +1,7 @@ #include "furvm/module.hpp" #include "furvm/detail/serialization.hpp" +#include "furvm/function.hpp" #include "furvm/fwd.hpp" #include "furvm/type.hpp" @@ -17,34 +18,6 @@ std::ostream& mod::serialize(std::ostream& os) const { os.write(MAGIC, sizeof(MAGIC)); detail::serialize(os, std::uint32_t(0)); // version - function_id funcCount = m_functions.cend() - m_functions.cbegin(); - detail::serialize(os, funcCount); - for (function_id id = 0; id < funcCount; ++id) { - if (!m_functions.contains(id)) { - detail::serialize(os, ""); - detail::serialize(os, 0); - detail::serialize(os, std::uint8_t(0xFF)); // null function - continue; - } - - function_h func = m_functions.at(id); - detail::serialize(os, m_functionMap.at(func.id())); - detail::serialize(os, func->param_count()); - detail::serialize(os, std::uint8_t(func->type())); - switch (func->type()) { - case function_t::Normal: { - detail::serialize(os, func->position()); - } break; - case function_t::Native: { - detail::serialize(os, func->native()); - } break; - case function_t::Import: { - detail::serialize(os, func->imp().mod); - detail::serialize(os, func->imp().function); - } break; - } - } - type_id typeCount = type_id(m_types.cend() - m_types.cbegin()); detail::serialize(os, typeCount); for (type_id id = 0; id < typeCount; ++id) { @@ -67,6 +40,45 @@ std::ostream& mod::serialize(std::ostream& os) const { } } + function_id funcCount = m_functions.cend() - m_functions.cbegin(); + detail::serialize(os, funcCount); + for (function_id id = 0; id < funcCount; ++id) { + if (!m_functions.contains(id)) { + detail::serialize(os, ""); + detail::serialize(os, 0); + detail::serialize(os, std::uint8_t(0xFF)); // null function + continue; + } + + // Function name + function_h func = m_functions.at(id); + if (auto it = m_functionMap.find(func.id()); it != m_functionMap.end()) { + detail::serialize(os, it->second.first); + } else { + detail::serialize(os, ""); + } + + // Function signature + detail::serialize(os, func->signature().params.size()); + for (std::uint32_t i = 0; i < func->signature().params.size(); ++i) + detail::serialize(os, func->signature().params[i].id()); + + // Function body/value + detail::serialize(os, std::uint8_t(func->type())); + switch (func->type()) { + case function_t::Normal: { + detail::serialize(os, func->position()); + } break; + case function_t::Native: { + detail::serialize(os, func->native()); + } break; + case function_t::Import: { + detail::serialize(os, func->imp().mod); + detail::serialize(os, func->imp().function); + } break; + } + } + detail::serialize(os, std::uint64_t(m_bytecode.size())); return os.write(reinterpret_cast(m_bytecode.data()), static_cast(m_bytecode.size())); } @@ -81,45 +93,6 @@ mod mod::load(std::istream& is) { mod mod; - function_id functionCount = 0; - detail::load(is, functionCount); - for (function_id id = 0; id < functionCount; ++id) { - std::string name; - detail::load(is, name); - std::uint32_t paramCount = 0; - detail::load(is, paramCount); - std::uint8_t type = 0; - detail::load(is, type); - if (type == 0xFF) continue; - - switch ((function_t)type) { - case function_t::Normal: { - decltype(std::declval().position()) offset = 0; - detail::load(is, offset); - if (name.empty()) - mod.emplace_function_named(std::move(name), id, paramCount, offset).dispatch(); - else - mod.emplace_function(id, paramCount, offset).dispatch(); - } break; - case function_t::Native: { - std::string native; - detail::load(is, native); - if (name.empty()) - mod.emplace_function_named(std::move(name), id, paramCount, std::move(native)).dispatch(); - else - mod.emplace_function(id, paramCount, std::move(native)).dispatch(); - } break; - case function_t::Import: { - std::string modName; - detail::load(is, modName); - function_id function = 0; - detail::load(is, function); - mod.emplace_function(id, std::move(modName), function).dispatch(); - } break; - default: throw std::runtime_error("unknown function type"); - } - } - type_id typeCount = 0; detail::load(is, typeCount); for (type_id id = 0; id < typeCount; ++id) { @@ -151,6 +124,54 @@ mod mod::load(std::istream& is) { } } + function_id functionCount = 0; + detail::load(is, functionCount); + for (function_id id = 0; id < functionCount; ++id) { + std::string name; + detail::load(is, name); + + function_sig signature; + std::uint32_t paramCount = 0; + detail::load(is, paramCount); + signature.params.reserve(paramCount); + while (signature.params.size() < paramCount) { + thing_id param{ 0 }; + detail::load(is, param); + signature.params.emplace_back(mod.type_at(param)); + } + + std::uint8_t type = 0; + detail::load(is, type); + if (type == 0xFF) continue; + + switch ((function_t)type) { + case function_t::Normal: { + decltype(std::declval().position()) offset = 0; + detail::load(is, offset); + if (name.empty()) + mod.emplace_function(std::move(name), id, std::move(signature), offset).dispatch(); + else + mod.emplace_function(id, std::move(signature), offset).dispatch(); + } break; + case function_t::Native: { + std::string native; + detail::load(is, native); + if (name.empty()) + mod.emplace_function(std::move(name), id, std::move(signature), std::move(native)).dispatch(); + else + mod.emplace_function(id, std::move(signature), std::move(native)).dispatch(); + } break; + case function_t::Import: { + std::string modName; + detail::load(is, modName); + function_id function = 0; + detail::load(is, function); + mod.emplace_function(id, std::move(modName), function).dispatch(); + } break; + default: throw std::runtime_error("unknown function type"); + } + } + std::uint64_t bytecodeLength = 0; detail::load(is, bytecodeLength); mod.bytecode().resize(bytecodeLength);