From 9b280fab2286023383a8105b2765bfa6f4b8b126 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sun, 12 Jul 2026 00:03:39 +0200 Subject: [PATCH] refactor(furvm): improve references Closes: #53 --- furvm/include/furvm/module.hpp | 14 ++--- furvm/include/furvm/thing.hpp | 102 +++++++++++++++++++++++---------- furvm/src/executor.cpp | 6 +- furvm/src/main.cpp | 1 + furvm/src/module.cpp | 3 +- 5 files changed, 84 insertions(+), 42 deletions(-) diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index b950176..8f1045c 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -18,10 +18,6 @@ namespace furvm { struct mod_type { - struct ptr { - mod_type_id typeId; - }; - struct array { mod_type_id typeId; std::size_t size; @@ -42,6 +38,7 @@ struct mod_type { U32, U64, Ptr, + Ref, Array, Import, @@ -49,16 +46,14 @@ struct mod_type { } type; union value { std::nullptr_t null = nullptr; - ptr ptr; + mod_type_id typeRef; array array; imprt imprt; value() = default; value(mod_type_id id) - : ptr({}) { - ptr.typeId = id; - } + : typeRef(id) {} value(mod_type_id id, std::size_t size) : array({}) { @@ -84,6 +79,9 @@ struct mod_type { mod_type(enum type type) : type(type) {} + mod_type(enum type type, mod_type_id typeRef) + : type(type), value(typeRef) {} + mod_type(mod_type_id id, std::size_t size) : type(Array), value(id, size) {} diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 1c3256b..6a96483 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -30,10 +30,6 @@ struct thing_type { using u32 = std::uint32_t; using u64 = std::uint64_t; - struct ptr { - thing_type* type; - }; - struct array { thing_type* type; std::size_t size; @@ -49,21 +45,20 @@ struct thing_type { U32, U64, Ptr, + Ref, Array, Count, } type; union value { std::nullptr_t null = nullptr; - ptr ptr; + thing_type* typeRef; array array; value() = default; value(thing_type* type) - : ptr({}) { - ptr.type = type; - } + : typeRef(type) {} value(thing_type* type, std::size_t size) : array({}) { @@ -87,7 +82,8 @@ struct thing_type { case U16: case U32: case U64: return true; - case Ptr: return *value.ptr.type == *other.value.ptr.type; + case Ptr: + case Ref: return *value.typeRef == *other.value.typeRef; case Array: return *value.array.type == *other.value.array.type && value.array.size == other.value.array.size; case Count: break; } @@ -107,6 +103,7 @@ struct thing_type { case U32: case U64: return true; case Ptr: + case Ref: case Array: return false; case Count: break; } @@ -124,6 +121,7 @@ struct thing_type { case thing_type::U32: return sizeof(u32); case thing_type::U64: return sizeof(u64); case Ptr: + case Ref: case Array: return 0; case Count: break; } @@ -145,7 +143,8 @@ struct thing_type_hash { case thing_type::U16: case thing_type::U32: case thing_type::U64: return seed; - case thing_type::Ptr: return furlang::utility::hash_combine(seed, thing_type_hash{}(*type.value.ptr.type)); + case thing_type::Ptr: + case thing_type::Ref: return furlang::utility::hash_combine(seed, thing_type_hash{}(*type.value.typeRef)); case thing_type::Array: seed = furlang::utility::hash_combine(seed, thing_type_hash{}(*type.value.array.type)); seed = furlang::utility::hash_combine(seed, @@ -171,6 +170,16 @@ public: return ptr; } + thing_type* insert(const thing_type& type) { + if (auto it = m_typeMap.find(type); it != m_typeMap.end()) return m_map[it->second]; + + thing_type_id id = m_counter++; + thing_type* ptr = m_arena.allocate(type); + m_map[id] = ptr; + m_typeMap[type] = id; + return ptr; + } + thing_type* at(thing_type_id id) const { if (auto it = m_map.find(id); it != m_map.end()) return it->second; return nullptr; @@ -204,6 +213,7 @@ public: */ thing(const thing_type& type, const allocator_type& allocator = {}) : m_type(type), m_size(compute_size(type)), m_allocator(allocator) { + if (m_type.type == thing_type::Ref) return; // TODO: Account for alignment m_data = m_allocator.allocate(m_size); std::memset(m_data, 0, m_size); @@ -213,7 +223,7 @@ public: * @brief Destructs a thing. */ ~thing() { - if (m_data != nullptr && m_size > 0) m_allocator.deallocate(m_data, m_size); + if (m_type.type != thing_type::Ref && m_data != nullptr && m_size > 0) m_allocator.deallocate(m_data, m_size); } /** @@ -249,8 +259,6 @@ public: * @return A clone of this thing. */ thing clone() const { - if (m_size == 0) return reference(); - thing res(m_type, m_allocator); switch (m_type.type) { case thing_type::S8: @@ -263,17 +271,37 @@ public: case thing_type::U64: case thing_type::Ptr: std::memcpy(res.m_data, m_data, m_size); return std::move(res); case thing_type::Array: copy_list(m_type, res.get(), get()); return std::move(res); + case thing_type::Ref: throw std::runtime_error("cannot clone references"); case thing_type::Count: break; } throw std::runtime_error("unreachable"); } public: /** - * @brief Returns the thing's type reference. + * @brief Returns the thing's type. * - * @return The type reference. + * @return The type. */ - constexpr auto type() const { return m_type; } + constexpr thing_type type() const { return m_type; } + + /** + * @brief Returns the thing's true type. + * + * If the thing is a reference, returns the referenced type. + * + * @return The true type. + */ + constexpr thing_type true_type() const { return (m_type.type == thing_type::Ref) ? *m_type.value.typeRef : m_type; } + + /** + * @brief Checks if the thing is of a specified type. + * + * Compares the true type. + * + * @param type Type to compare. + * @return true if the types match. + */ + constexpr bool is(enum thing_type::type type) const { return true_type().type == type; } public: /** * @brief Returns a raw data pointer. @@ -418,12 +446,8 @@ public: } } - thing reference() const { return { m_type, m_data, m_allocator }; } - - constexpr bool is_reference() const { return m_size == 0; } - void resize(thing_type::u64 newSize) { - if (m_type.type != thing_type::Array) throw bad_thing_access(); + if (!is(thing_type::Array)) throw bad_thing_access(); if (m_type.value.array.size > 0) throw std::runtime_error("cannot resize a static array"); auto& array = get(); @@ -439,29 +463,45 @@ public: } thing at(thing_type::u64 index) const { - if (m_type.type != thing_type::Array) throw bad_thing_access(); + if (!is(thing_type::Array)) throw bad_thing_access(); std::size_t elementSize = compute_size_na(*m_type.value.array.type); if (m_type.value.array.size == 0) { auto& array = get(); if (index < 0 || index >= array.dynamic.size) throw std::out_of_range("index out of range"); - return { *m_type.value.array.type, array.dynamic.data + (index * elementSize), m_allocator }; + thing ref = { { thing_type::Ref, m_type.value.array.type }, m_allocator }; + ref.m_data = array.dynamic.data + (index * elementSize); + return ref; } std::byte* data = reinterpret_cast(m_data)->flat; if (index < 0 || index >= m_type.value.array.size) throw std::out_of_range("index out of range"); - return { *m_type.value.array.type, data + (index * elementSize), m_allocator }; + thing ref = { { thing_type::Ref, m_type.value.array.type }, m_allocator }; + ref.m_data = data + (index * elementSize); + return ref; } thing_type::u64 length() const { - if (m_type.type != thing_type::Array) throw bad_thing_access(); - return m_type.value.array.size == 0 ? get().dynamic.size : m_type.value.array.size; + if (!is(thing_type::Array)) throw bad_thing_access(); + return true_type().value.array.size == 0 ? get().dynamic.size : true_type().value.array.size; } template >> T cast_to() const { return visit_primitive([](auto value) { return static_cast(value); }); } + + /** + * @brief Changes reference thing's referenced thing. + * + * Yes. + * + * @param thing Thing. + */ + void reference(const thing& thing) { + if (m_type.type != thing_type::Ref || *m_type.value.typeRef != thing.type()) throw bad_thing_access(); + m_data = thing.m_data; + } private: static void copy_list(const thing_type& arrayType, array& dst, const array& src) { if (arrayType.type != thing_type::Array || arrayType.value.array.type == nullptr) @@ -497,7 +537,8 @@ private: case thing_type::U16: case thing_type::U32: case thing_type::U64: - case thing_type::Ptr: std::memcpy(dst.flat, src.flat, size); return; + case thing_type::Ptr: + case thing_type::Ref: std::memcpy(dst.flat, src.flat, size); return; case thing_type::Array: for (std::size_t i = 0; i < size; ++i) { copy_list(*innerType.value.array.type, @@ -521,6 +562,7 @@ private: case thing_type::U32: return sizeof(thing_type::u32); case thing_type::U64: return sizeof(thing_type::u64); case thing_type::Ptr: return sizeof(void*); + case thing_type::Ref: return compute_size_na(*type.value.typeRef); case thing_type::Array: return type.value.array.size == 0 ? sizeof(array) : compute_size_na(*type.value.array.type) * type.value.array.size; @@ -532,9 +574,6 @@ private: // NOTE: Align to 4 bytes static std::size_t compute_size(const thing_type& type) { return (compute_size_na(type) + 3) & ~3; } -private: - thing(const thing_type& type, std::byte* data, const allocator_type& allocator = {}) - : m_type(type), m_size(0), m_data(data), m_allocator(allocator) {} private: template decltype(auto) visit_primitive(Func&& func) const { @@ -629,7 +668,7 @@ private: thing_type::U64, }; - enum thing_type::type resultType = promotions[m_type.type + (rhs.m_type.type * 8)]; + enum thing_type::type resultType = promotions[true_type().type + (rhs.true_type().type * 8)]; thing res = { thing_type{ resultType }, m_allocator }; switch (resultType) { @@ -658,6 +697,7 @@ private: res.get() = Op{}(cast_to(), rhs.cast_to()); return res; case thing_type::Ptr: // TODO: Pointer arithmetics + case thing_type::Ref: case thing_type::Array: case thing_type::Count: break; } diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index ed40b88..4c1c6b4 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -29,7 +29,7 @@ thing_type executor::thing_type_impl(mod_h mod, mod_type type) const { case thing_type::U16: case thing_type::U32: case thing_type::U64: return { static_cast(type.type) }; - case thing_type::Ptr: return { thing_type::Ptr, thing_type(mod, *mod->type_at(type.value.ptr.typeId)) }; + case thing_type::Ptr: return { thing_type::Ptr, thing_type(mod, *mod->type_at(type.value.typeRef)) }; case thing_type::Array: { return { static_cast(type.type), { thing_type(mod, *mod->type_at(type.value.array.typeId)), type.value.array.size } }; @@ -165,7 +165,9 @@ void executor::step() { } break; case instruction_t::Reference: { auto thing = pop_thing(); - push_thing(std::move(thing->reference())); + push_thing({ (struct thing_type){ thing_type::Ref, m_context->thing_type_store().insert(thing->type()) }, + m_context->thing_alloc() }) + ->reference(*thing); } break; case instruction_t::Add: { auto rhs = pop_thing(); diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index f86259a..596c45b 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -58,6 +58,7 @@ int main(int argc, char** argv) { 0, 0, 0, + static_cast(furvm::instruction_t::Reference), static_cast(furvm::instruction_t::Lengthof), static_cast(furvm::instruction_t::Call), 1, diff --git a/furvm/src/module.cpp b/furvm/src/module.cpp index d0fbdd9..3ac33c2 100644 --- a/furvm/src/module.cpp +++ b/furvm/src/module.cpp @@ -34,7 +34,8 @@ std::ostream& mod::serialize(std::ostream& os) const { case mod_type::U16: case mod_type::U32: case mod_type::U64: break; - case mod_type::Ptr: detail::serialize(os, type.value.ptr.typeId); break; + case mod_type::Ptr: + case mod_type::Ref: detail::serialize(os, type.value.typeRef); break; case mod_type::Array: { detail::serialize(os, type.value.array.typeId); detail::serialize(os, type.value.array.size);