diff options
author | Spartan322 <Megacake1234@gmail.com> | 2024-07-24 04:02:24 +0200 |
---|---|---|
committer | Spartan322 <Megacake1234@gmail.com> | 2024-08-03 23:57:07 +0200 |
commit | 972ed9d7921637d4ac290dae214942dbe9bc05c3 (patch) | |
tree | caecd46664be8ba9edcc9c525e86f145e407bb8b | |
parent | bfea50b4188f18c68289e2b8cd915220393de8d4 (diff) |
Add simple RAII VM types
-rw-r--r-- | src/openvic-simulation/vm/AsmBuilder.hpp | 91 | ||||
-rw-r--r-- | src/openvic-simulation/vm/Module.hpp | 95 | ||||
-rw-r--r-- | src/openvic-simulation/vm/Reader.hpp | 80 | ||||
-rw-r--r-- | src/openvic-simulation/vm/RuntimeFiber.cpp | 65 | ||||
-rw-r--r-- | src/openvic-simulation/vm/RuntimeFiber.hpp | 96 | ||||
-rw-r--r-- | src/openvic-simulation/vm/RuntimeProcess.hpp | 57 | ||||
-rw-r--r-- | src/openvic-simulation/vm/Stacktrace.hpp | 65 | ||||
-rw-r--r-- | src/openvic-simulation/vm/VirtualMachine.hpp | 43 | ||||
-rw-r--r-- | src/openvic-simulation/vm/Writer.hpp | 70 |
9 files changed, 662 insertions, 0 deletions
diff --git a/src/openvic-simulation/vm/AsmBuilder.hpp b/src/openvic-simulation/vm/AsmBuilder.hpp new file mode 100644 index 0000000..31fe0aa --- /dev/null +++ b/src/openvic-simulation/vm/AsmBuilder.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include <lauf/asm/builder.h> +#include <lauf/asm/module.h> + +namespace OpenVic::Vm { + struct AsmBuilder { + AsmBuilder(lauf_asm_build_options options) : _handle(lauf_asm_create_builder(options)) {} + + AsmBuilder(AsmBuilder&&) = default; + AsmBuilder& operator=(AsmBuilder&&) = default; + + AsmBuilder(AsmBuilder const&) = delete; + AsmBuilder& operator=(AsmBuilder const&) = delete; + + ~AsmBuilder() { + lauf_asm_destroy_builder(_handle); + } + + lauf_asm_builder* handle() { + return _handle; + } + + const lauf_asm_builder* handle() const { + return _handle; + } + + operator lauf_asm_builder*() { + return _handle; + } + + operator const lauf_asm_builder*() const { + return _handle; + } + + struct CodeBuilder { + CodeBuilder(CodeBuilder const&) = delete; + CodeBuilder& operator=(CodeBuilder const&) = delete; + + ~CodeBuilder() { + if (!has_finished()) { + finish(); + } + } + + operator lauf_asm_builder*() { + return _builder.handle(); + } + + operator const lauf_asm_builder*() const { + return _builder.handle(); + } + + bool finish() { + return _has_finished = lauf_asm_build_finish(_builder.handle()); + } + + bool has_finished() const { + return _has_finished; + } + + bool is_well_formed() const { + return _is_well_formed; + } + + void build_function(lauf_asm_function* fn) { + lauf_asm_build(_builder.handle(), _module, fn); + } + + void build_chunk(lauf_asm_chunk* chunk, lauf_asm_signature sig) { + lauf_asm_build_chunk(_builder.handle(), _module, chunk, sig); + } + + private: + friend struct AsmBuilder; + CodeBuilder(AsmBuilder& builder, lauf_asm_module* module) : _builder(builder), _module(module) {} + + bool _has_finished; + bool _is_well_formed; + AsmBuilder& _builder; + lauf_asm_module* _module; + }; + + CodeBuilder code(lauf_asm_module* module) { + return CodeBuilder(*this, module); + } + + private: + lauf_asm_builder* _handle; + }; +} diff --git a/src/openvic-simulation/vm/Module.hpp b/src/openvic-simulation/vm/Module.hpp new file mode 100644 index 0000000..d8a7c6e --- /dev/null +++ b/src/openvic-simulation/vm/Module.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include <memory> +#include <span> +#include <type_traits> + +#include <range/v3/view/enumerate.hpp> + +#include <lauf/asm/module.h> +#include <lauf/asm/program.h> +#include <lauf/asm/type.h> + +namespace OpenVic::Vm { + template<typename T> + concept Arithmetic = std::is_arithmetic_v<T>; + + struct Module { + Module(const char* module_name) : _handle(lauf_asm_create_module(module_name)) {} + + Module(Module&&) = default; + Module& operator=(Module&&) = default; + + Module(Module const&) = delete; + Module& operator=(Module const&) = delete; + + ~Module() { + lauf_asm_destroy_module(_handle); + } + + lauf_asm_module* handle() { + return _handle; + } + + const lauf_asm_module* handle() const { + return _handle; + } + + operator lauf_asm_module*() { + return _handle; + } + + operator const lauf_asm_module*() const { + return _handle; + } + + const char* name() const { + return lauf_asm_module_name(_handle); + } + + const char* debug_path() const { + return lauf_asm_module_debug_path(_handle); + } + + void debug_path(const char* path) { + lauf_asm_set_module_debug_path(_handle, path); + } + + lauf_asm_function* add_function(const char* name, lauf_asm_signature sig) { + return lauf_asm_add_function(_handle, name, sig); + } + + const lauf_asm_function* find_function_by_name(const char* name) const { + return lauf_asm_find_function_by_name(_handle, name); + } + + lauf_asm_global* add_global(lauf_asm_global_permissions perms) { + return lauf_asm_add_global(_handle, perms); + } + + lauf_asm_program create_program(const lauf_asm_function* entry) const { + return lauf_asm_create_program(_handle, entry); + } + + void define_data(lauf_asm_global* global, lauf_asm_layout layout, const void* data) { + lauf_asm_define_data_global(_handle, global, layout, data); + } + + template<Arithmetic T> + void define_data_type(lauf_asm_global* global, const T* data = nullptr) { + define_data(global, { sizeof(T), alignof(T) }, static_cast<const void*>(data)); + } + + static std::unique_ptr<const lauf_asm_module* const[]> make_list(std::span<Module> mods) { + auto result = new const lauf_asm_module*[mods.size()]; + auto span = std::span<const lauf_asm_module*> { result, mods.size() }; + for (auto [count, element] : span | ranges::views::enumerate) { + element = mods[count].handle(); + } + return std::unique_ptr<const lauf_asm_module* const[]>(result); + } + + private: + lauf_asm_module* _handle; + }; +} diff --git a/src/openvic-simulation/vm/Reader.hpp b/src/openvic-simulation/vm/Reader.hpp new file mode 100644 index 0000000..e75042f --- /dev/null +++ b/src/openvic-simulation/vm/Reader.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include <string_view> + +#include <lauf/reader.h> + +namespace OpenVic::Vm { + template<typename Tag> + struct BasicReader { + BasicReader(BasicReader&&) = default; + BasicReader& operator=(BasicReader&&) = default; + + BasicReader(BasicReader const&) = delete; + BasicReader& operator=(BasicReader const&) = delete; + + ~BasicReader() { + if (_handle == nullptr) { + return; + } + lauf_destroy_reader(_handle); + } + + lauf_reader* handle() { + return _handle; + } + + const lauf_reader* handle() const { + return _handle; + } + + operator lauf_reader*() { + return _handle; + } + + operator const lauf_reader*() const { + return _handle; + } + + void set_path(const char* path) { + lauf_reader_set_path(_handle, path); + } + + struct StringTag; + struct FileTag; + struct StdinTag; + + protected: + BasicReader(lauf_reader* reader) : _handle(reader) {} + + private: + lauf_reader* _handle; + }; + + template<> + struct BasicReader<BasicReader<void>::StringTag> : BasicReader<void> { + using BasicReader<void>::BasicReader; + BasicReader(const char* cstr) : BasicReader(lauf_create_cstring_reader(cstr)) {} + BasicReader(std::string_view view) : BasicReader(lauf_create_string_reader(view.data(), view.size())) {} + }; + + template<> + struct BasicReader<BasicReader<void>::FileTag> : BasicReader<void> { + using BasicReader<void>::BasicReader; + BasicReader(const char* path) : BasicReader(lauf_create_file_reader(path)) {} + + bool is_valid() { + return handle() != nullptr; + } + }; + + template<> + struct BasicReader<BasicReader<void>::StdinTag> : BasicReader<void> { + using BasicReader<void>::BasicReader; + BasicReader() : BasicReader(lauf_create_stdin_reader()) {} + }; + + using StringReader = BasicReader<BasicReader<void>::StringTag>; + using FileReader = BasicReader<BasicReader<void>::FileTag>; + using CinReader = BasicReader<BasicReader<void>::StdinTag>; +} diff --git a/src/openvic-simulation/vm/RuntimeFiber.cpp b/src/openvic-simulation/vm/RuntimeFiber.cpp new file mode 100644 index 0000000..838f9da --- /dev/null +++ b/src/openvic-simulation/vm/RuntimeFiber.cpp @@ -0,0 +1,65 @@ +#include "RuntimeFiber.hpp" + +#include <cassert> +#include <optional> + +#include "RuntimeProcess.hpp" // IWYU pragma: keep +#include "Stacktrace.hpp" +#include <lauf/runtime/process.h> +#include <lauf/runtime/stacktrace.h> + +using namespace OpenVic::Vm; + +const lauf_runtime_value* RuntimeFiberRef::get_vstack_base() const { + assert(is_valid()); + return lauf_runtime_get_vstack_base(_handle); +} + +RuntimeFiber::~RuntimeFiber() { + destroy(); +} + +std::optional<Stacktrace> RuntimeFiber::get_stacktrace() const { + assert(is_valid()); + auto result = lauf_runtime_get_stacktrace(*_process, _handle); + if (result == nullptr) { + return std::nullopt; + } + return std::make_optional<Stacktrace>(result); +} + +std::optional<RuntimeFiberRef> RuntimeFiber::get_parent() { + assert(is_valid()); + auto result = lauf_runtime_get_fiber_parent(*_process, _handle); + if (result == nullptr) { + return std::nullopt; + } + return result; +} + +const lauf_runtime_value* RuntimeFiber::get_vstack_ptr() const { + assert(is_valid()); + return lauf_runtime_get_vstack_ptr(*_process, _handle); +} + +bool RuntimeFiber::resume( + const lauf_runtime_value* input, size_t input_count, lauf_runtime_value* output, size_t output_count +) { + assert(is_valid()); + return lauf_runtime_resume(*_process, _handle, input, input_count, output, output_count); +} + +bool RuntimeFiber::resume_until_completion( + const lauf_runtime_value* input, size_t input_count, lauf_runtime_value* output, size_t output_count +) { + assert(is_valid()); + return lauf_runtime_resume_until_completion(*_process, _handle, input, input_count, output, output_count); +} + +void RuntimeFiber::destroy() { + if (!is_valid()) { + return; + } + lauf_runtime_destroy_fiber(*_process, _handle); + _handle = nullptr; +} diff --git a/src/openvic-simulation/vm/RuntimeFiber.hpp b/src/openvic-simulation/vm/RuntimeFiber.hpp new file mode 100644 index 0000000..2c4d21d --- /dev/null +++ b/src/openvic-simulation/vm/RuntimeFiber.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include <cassert> +#include <optional> + +#include "vm/Stacktrace.hpp" +#include <lauf/runtime/process.h> +#include <lauf/runtime/value.h> + +namespace OpenVic::Vm { + struct RuntimeProcess; + + struct RuntimeFiber; + + struct RuntimeFiberRef { + RuntimeFiberRef(lauf_runtime_fiber* fiber) : _handle(fiber) {} + + lauf_runtime_fiber* handle() { + return _handle; + } + + const lauf_runtime_fiber* handle() const { + return _handle; + } + + operator lauf_runtime_fiber*() { + return _handle; + } + + operator const lauf_runtime_fiber*() const { + return _handle; + } + + lauf_runtime_address lauf_handle() const { + assert(is_valid()); + return lauf_runtime_get_fiber_handle(_handle); + } + + lauf_runtime_fiber_status status() const { + assert(is_valid()); + return lauf_runtime_get_fiber_status(_handle); + } + + const lauf_runtime_value* get_vstack_base() const; + + RuntimeFiberRef iterate_next() { + assert(is_valid()); + return lauf_runtime_iterate_fibers_next(_handle); + } + + bool is_valid() const { + return _handle != nullptr; + } + + protected: + lauf_runtime_fiber* _handle; + }; + + struct RuntimeFiber : RuntimeFiberRef { + RuntimeFiber(RuntimeFiber&&) = default; + RuntimeFiber& operator=(RuntimeFiber&&) = default; + + RuntimeFiber(RuntimeFiber const&) = delete; + RuntimeFiber& operator=(RuntimeFiber const&) = delete; + + ~RuntimeFiber(); + + RuntimeFiberRef& as_ref() { + return *this; + } + + RuntimeFiberRef const& as_ref() const { + return *this; + } + + std::optional<Stacktrace> get_stacktrace() const; + + std::optional<RuntimeFiberRef> get_parent(); + + const lauf_runtime_value* get_vstack_ptr() const; + + bool resume(const lauf_runtime_value* input, size_t input_count, lauf_runtime_value* output, size_t output_count); + bool resume_until_completion( + const lauf_runtime_value* input, size_t input_count, lauf_runtime_value* output, size_t output_count + ); + + void destroy(); + + private: + friend RuntimeFiberRef; + friend struct RuntimeProcess; + RuntimeFiber(RuntimeProcess* process, lauf_runtime_fiber* fiber) : RuntimeFiberRef(fiber), _process(process) {} + + RuntimeProcess* _process; + }; +} diff --git a/src/openvic-simulation/vm/RuntimeProcess.hpp b/src/openvic-simulation/vm/RuntimeProcess.hpp new file mode 100644 index 0000000..be183e6 --- /dev/null +++ b/src/openvic-simulation/vm/RuntimeProcess.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "vm/RuntimeFiber.hpp" +#include "vm/Stacktrace.hpp" +#include <lauf/runtime/memory.h> +#include <lauf/runtime/process.h> +#include <lauf/runtime/stacktrace.h> + +namespace OpenVic::Vm { + struct VirtualMachine; + + struct RuntimeProcess { + RuntimeProcess(RuntimeProcess&&) = default; + RuntimeProcess& operator=(RuntimeProcess&&) = default; + + RuntimeProcess(RuntimeProcess const&) = delete; + RuntimeProcess& operator=(RuntimeProcess const&) = delete; + + ~RuntimeProcess() { + lauf_runtime_destroy_process(_handle); + } + + lauf_runtime_process* handle() { + return _handle; + } + + const lauf_runtime_process* handle() const { + return _handle; + } + + operator lauf_runtime_process*() { + return _handle; + } + + operator const lauf_runtime_process*() const { + return _handle; + } + + RuntimeFiber create_fiber(const lauf_asm_function* fn) { + return RuntimeFiber(this, lauf_runtime_create_fiber(*this, fn)); + } + + RuntimeFiberRef get_current_fiber() { + return lauf_runtime_get_current_fiber(_handle); + } + + RuntimeFiberRef get_fiber_ptr(lauf_runtime_address addr) { + return lauf_runtime_get_fiber_ptr(_handle, addr); + } + + private: + friend struct VirtualMachine; + RuntimeProcess(lauf_runtime_process* process) : _handle(process) {} + + lauf_runtime_process* _handle; + }; +} diff --git a/src/openvic-simulation/vm/Stacktrace.hpp b/src/openvic-simulation/vm/Stacktrace.hpp new file mode 100644 index 0000000..016443a --- /dev/null +++ b/src/openvic-simulation/vm/Stacktrace.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include <optional> + +#include <lauf/runtime/stacktrace.h> + +namespace OpenVic::Vm { + struct RuntimeFiber; + + struct StacktraceRef { + lauf_runtime_stacktrace* handle() { + return _handle; + } + + const lauf_runtime_stacktrace* handle() const { + return _handle; + } + + operator lauf_runtime_stacktrace*() { + return _handle; + } + + operator const lauf_runtime_stacktrace*() const { + return _handle; + } + + std::optional<StacktraceRef> get_parent() { + auto result = lauf_runtime_stacktrace_parent(_handle); + if (result == nullptr) { + return std::nullopt; + } + return StacktraceRef(result); + } + + protected: + friend struct RuntimeFiber; + StacktraceRef(lauf_runtime_stacktrace* stacktrace) : _handle(stacktrace) {} + + lauf_runtime_stacktrace* _handle; + }; + + struct Stacktrace : StacktraceRef { + Stacktrace(Stacktrace&&) = default; + Stacktrace& operator=(Stacktrace&&) = default; + + StacktraceRef& as_ref() { + return *this; + } + + StacktraceRef const& as_ref() const { + return *this; + } + + Stacktrace(Stacktrace const&) = delete; + Stacktrace& operator=(Stacktrace const&) = delete; + + ~Stacktrace() { + lauf_runtime_destroy_stacktrace(_handle); + } + + private: + friend struct RuntimeFiber; + Stacktrace(lauf_runtime_stacktrace* stacktrace) : StacktraceRef(stacktrace) {} + }; +} diff --git a/src/openvic-simulation/vm/VirtualMachine.hpp b/src/openvic-simulation/vm/VirtualMachine.hpp new file mode 100644 index 0000000..1c130b2 --- /dev/null +++ b/src/openvic-simulation/vm/VirtualMachine.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "RuntimeProcess.hpp" +#include <lauf/vm.h> + +namespace OpenVic::Vm { + struct VirtualMachine { + VirtualMachine(lauf_vm_options options) : _handle(lauf_create_vm(options)) {} + + VirtualMachine(VirtualMachine&&) = default; + VirtualMachine& operator=(VirtualMachine&&) = default; + + VirtualMachine(VirtualMachine const&) = delete; + VirtualMachine& operator=(VirtualMachine const&) = delete; + + ~VirtualMachine() { + lauf_destroy_vm(_handle); + } + + lauf_vm* handle() { + return _handle; + } + + const lauf_vm* handle() const { + return _handle; + } + + operator lauf_vm*() { + return _handle; + } + + operator const lauf_vm*() const { + return _handle; + } + + RuntimeProcess start_process(const lauf_asm_program* program) { + return RuntimeProcess(lauf_vm_start_process(_handle, program)); + } + + private: + lauf_vm* _handle; + }; +} diff --git a/src/openvic-simulation/vm/Writer.hpp b/src/openvic-simulation/vm/Writer.hpp new file mode 100644 index 0000000..2a7696b --- /dev/null +++ b/src/openvic-simulation/vm/Writer.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include <lauf/writer.h> + +namespace OpenVic::Vm { + template<typename Tag> + struct BasicWriter { + BasicWriter(BasicWriter&&) = default; + BasicWriter& operator=(BasicWriter&&) = default; + + BasicWriter(BasicWriter const&) = delete; + BasicWriter& operator=(BasicWriter const&) = delete; + + ~BasicWriter() { + lauf_destroy_writer(_handle); + } + + lauf_writer* handle() { + return _handle; + } + + const lauf_writer* handle() const { + return _handle; + } + + operator lauf_writer*() { + return _handle; + } + + operator const lauf_writer*() const { + return _handle; + } + + struct StringTag; + struct FileTag; + struct StdoutTag; + + protected: + BasicWriter(lauf_writer* writer) : _handle(writer) {} + + private: + lauf_writer* _handle; + }; + + template<> + struct BasicWriter<BasicWriter<void>::StringTag> : BasicWriter<void> { + using BasicWriter<void>::BasicWriter; + BasicWriter() : BasicWriter(lauf_create_string_writer()) {} + + const char* c_str() { + return lauf_writer_get_string(*this); + } + }; + + template<> + struct BasicWriter<BasicWriter<void>::FileTag> : BasicWriter<void> { + using BasicWriter<void>::BasicWriter; + BasicWriter(const char* path) : BasicWriter(lauf_create_file_writer(path)) {} + }; + + template<> + struct BasicWriter<BasicWriter<void>::StdoutTag> : BasicWriter<void> { + using BasicWriter<void>::BasicWriter; + BasicWriter() : BasicWriter(lauf_create_stdout_writer()) {} + }; + + using StringWriter = BasicWriter<BasicWriter<void>::StringTag>; + using FileWriter = BasicWriter<BasicWriter<void>::FileTag>; + using CoutWriter = BasicWriter<BasicWriter<void>::StdoutTag>; +} |