diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index adc4957..709a763 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -9,6 +9,7 @@ namespace furvm { class mod { friend class function; + friend class serializer; public: using bytecode_t = std::vector; /**< An alias to a vector of bytes. */ public: @@ -67,4 +68,4 @@ private: } // namespace furvm -#endif // FURVM_MODULE_HPP \ No newline at end of file +#endif // FURVM_MODULE_HPP diff --git a/furvm/include/furvm/serializer.hpp b/furvm/include/furvm/serializer.hpp new file mode 100644 index 0000000..276dd43 --- /dev/null +++ b/furvm/include/furvm/serializer.hpp @@ -0,0 +1,20 @@ +#ifndef FURVM_SERIALIZER_HPP +#define FURVM_SERIALIZER_HPP + +#include "furvm/fwd.hpp" + +#include + +namespace furvm { + +class serializer { +public: + static constexpr byte MODULE_MAGIC[4] = { 'F', 'u', 'r', 'M' }; + static constexpr std::uint32_t VERSION = 0; +public: + static bool serialize_module(std::ostream& os, const mod_p& mod); +}; + +} // namespace furvm + +#endif // FURVM_SERIALIZER_HPP diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index 87ebe72..16a07bd 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -4,10 +4,12 @@ #include "furvm/executor.hpp" #include "furvm/function.hpp" #include "furvm/instruction.hpp" +#include "furvm/serializer.hpp" #include "furvm/thing.hpp" #include #include +#include #include #include @@ -16,16 +18,9 @@ static constexpr std::array s_bytecode = { 67, furvm::byte(furvm::instruction_t::Clone), furvm::byte(furvm::instruction_t::Add), - furvm::byte(furvm::instruction_t::Call), - 1, - 0, furvm::byte(furvm::instruction_t::Return), }; -void print(furvm::executor& exec) { - std::cout << exec.pop_thing()->int32() << '\n'; -} - int main(void) { auto context = std::make_shared(); @@ -33,7 +28,8 @@ int main(void) { auto mainFunction = furvm::function::create(mainModule, 0); - auto printFunction = furvm::function::create(mainModule, print); + std::ofstream file("./test.furm", std::ios::binary); + furvm::serializer::serialize_module(file, mainModule); auto executor = furvm::executor::create(context); executor->push_frame(mainFunction); diff --git a/furvm/src/serializer.cpp b/furvm/src/serializer.cpp new file mode 100644 index 0000000..94a8a71 --- /dev/null +++ b/furvm/src/serializer.cpp @@ -0,0 +1,101 @@ +#include "furvm/serializer.hpp" + +#include "furvm/function.hpp" // IWYU pragma: keep + +#include +#include +#include +#include +#include +#include + +namespace furvm { + +template +static inline void write_raw(std::ostream& os, const T& value) { + os.write(reinterpret_cast(&value), sizeof(T)); +} + +template +static inline void read_raw(std::istream& is, T& value) { + is.read(reinterpret_cast(&value), sizeof(T)); +} + +static inline void write_u64(std::ostream& os, std::uint64_t value) { + os.put(static_cast((value >> 0ULL) & 0xFF)); + os.put(static_cast((value >> 8ULL) & 0xFF)); + os.put(static_cast((value >> 16ULL) & 0xFF)); + os.put(static_cast((value >> 24ULL) & 0xFF)); + os.put(static_cast((value >> 32ULL) & 0xFF)); + os.put(static_cast((value >> 40ULL) & 0xFF)); + os.put(static_cast((value >> 48ULL) & 0xFF)); + os.put(static_cast((value >> 56ULL) & 0xFF)); +} + +static inline void read_u64(std::istream& is, std::uint64_t& value) { + value = (static_cast(is.get()) << 0) | (static_cast(is.get()) << 8) | + (static_cast(is.get()) << 16) | (static_cast(is.get()) << 24) | + (static_cast(is.get()) << 32) | (static_cast(is.get()) << 40) | + (static_cast(is.get()) << 48) | (static_cast(is.get()) << 56); +} + +static inline void write_u32(std::ostream& os, std::uint32_t value) { + os.put(static_cast((value >> 0ULL) & 0xFF)); + os.put(static_cast((value >> 8ULL) & 0xFF)); + os.put(static_cast((value >> 16ULL) & 0xFF)); + os.put(static_cast((value >> 24ULL) & 0xFF)); +} + +static inline void read_u32(std::istream& is, std::uint32_t& value) { + value = static_cast(is.get() << 0) | static_cast(is.get() << 8) | + static_cast(is.get() << 16) | static_cast(is.get() << 24); +} + +static inline void write_u16(std::ostream& os, std::uint16_t value) { + os.put(static_cast((value >> 0ULL) & 0xFF)); + os.put(static_cast((value >> 8ULL) & 0xFF)); +} + +static inline void read_u16(std::istream& is, std::uint16_t& value) { + value = static_cast(is.get() << 0) | static_cast(is.get() << 8); +} + +static inline void write_u8(std::ostream& os, std::uint8_t value) { + os.put(static_cast((value >> 0ULL) & 0xFF)); +} + +static inline void read_u8(std::istream& is, std::uint8_t& value) { + value = static_cast(is.get() << 0); +} + +bool serializer::serialize_module(std::ostream& os, const mod_p& mod) { + os.write(reinterpret_cast(MODULE_MAGIC), sizeof(MODULE_MAGIC)); + write_u32(os, VERSION); + + write_u32(os, mod->m_functions.size()); + for (const auto& func : mod->m_functions) { + write_u16(os, func->id()); + write_u8(os, static_cast(func->type())); + switch (func->type()) { + case function_t::Normal: { + write_u64(os, func->position()); + } break; + case function_t::Native: { + // TODO: Replace with a reference to the function's name from constant pool + throw std::runtime_error("cannot serialize native functions yet"); + } break; + case function_t::Import: { + // TODO: Replace with a reference to the module's and function's name from constant pool + throw std::runtime_error("cannot serialize import functions yet"); + } break; + } + } + + write_u64(os, mod->m_bytecode.size()); + os.write(reinterpret_cast(mod->m_bytecode.data()), + static_cast(mod->m_bytecode.size())); + + return false; +} + +} // namespace furvm