aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/openvic-simulation/vm/AsmBuilder.hpp91
-rw-r--r--src/openvic-simulation/vm/Module.hpp95
-rw-r--r--src/openvic-simulation/vm/Reader.hpp80
-rw-r--r--src/openvic-simulation/vm/RuntimeFiber.cpp65
-rw-r--r--src/openvic-simulation/vm/RuntimeFiber.hpp96
-rw-r--r--src/openvic-simulation/vm/RuntimeProcess.hpp57
-rw-r--r--src/openvic-simulation/vm/Stacktrace.hpp65
-rw-r--r--src/openvic-simulation/vm/VirtualMachine.hpp43
-rw-r--r--src/openvic-simulation/vm/Writer.hpp70
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>;
+}