From 540b43d971d0a8fee350bbce514ea212f5d6a3fb Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 1 Dec 2025 01:20:49 -0500 Subject: [PATCH] xo-alloc + xo-allocutil: refactor to shrink dep surface area --- CMakeLists.txt | 1 + xo-alloc/include/xo/alloc/ArenaAlloc.hpp | 4 +- xo-alloc/include/xo/alloc/Forwarding1.hpp | 10 +- xo-alloc/include/xo/alloc/GC.hpp | 37 ++-- xo-alloc/include/xo/alloc/Object.hpp | 171 +++--------------- xo-alloc/src/alloc/ArenaAlloc.cpp | 2 +- xo-alloc/src/alloc/Blob.cpp | 2 +- xo-alloc/src/alloc/CMakeLists.txt | 2 +- xo-alloc/src/alloc/Forwarding1.cpp | 21 ++- xo-alloc/src/alloc/GC.cpp | 41 +++-- xo-alloc/src/alloc/IAlloc.cpp | 74 -------- xo-alloc/src/alloc/Object.cpp | 20 +- xo-allocutil/CMakeLists.txt | 43 +++++ xo-allocutil/cmake/xo-bootstrap-macros.cmake | 14 ++ .../cmake/xo_allocutilConfig.cmake.in | 6 + .../include/xo/allocutil}/IAlloc.hpp | 57 ++++-- xo-allocutil/include/xo/allocutil/IObject.hpp | 97 ++++++++++ .../xo/allocutil/gc_allocator_traits.hpp | 75 ++++++++ xo-allocutil/include/xo/allocutil/gc_ptr.hpp | 77 ++++++++ xo-imgui/example/ex2/imgui_ex2.cpp | 3 +- xo-imgui/example/ex4/AppState.cpp | 3 +- .../xo/interpreter/BuiltinPrimitives.hpp | 2 +- .../include/xo/interpreter/GlobalEnv.hpp | 2 +- .../include/xo/interpreter/LocalEnv.hpp | 2 +- xo-interpreter/utest/LocalEnv.test.cpp | 4 +- xo-object/include/xo/object/CVector.hpp | 2 +- xo-object/include/xo/object/Integer.hpp | 2 +- xo-object/include/xo/object/List.hpp | 6 +- xo-object/include/xo/object/String.hpp | 2 +- xo-object/src/object/Integer.cpp | 2 +- xo-object/src/object/List.cpp | 4 +- xo-object/utest/GC.test.cpp | 8 +- xo-object/utest/List.test.cpp | 4 +- xo-object/utest/String.test.cpp | 2 +- 34 files changed, 479 insertions(+), 323 deletions(-) delete mode 100644 xo-alloc/src/alloc/IAlloc.cpp create mode 100644 xo-allocutil/CMakeLists.txt create mode 100644 xo-allocutil/cmake/xo-bootstrap-macros.cmake create mode 100644 xo-allocutil/cmake/xo_allocutilConfig.cmake.in rename {xo-alloc/include/xo/alloc => xo-allocutil/include/xo/allocutil}/IAlloc.hpp (70%) create mode 100644 xo-allocutil/include/xo/allocutil/IObject.hpp create mode 100644 xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp create mode 100644 xo-allocutil/include/xo/allocutil/gc_ptr.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b554c34..53c40f2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ add_subdirectory(xo-unit) add_subdirectory(xo-pyunit) add_subdirectory(xo-callback) # +add_subdirectory(xo-allocutil) add_subdirectory(xo-alloc) add_subdirectory(xo-object) # diff --git a/xo-alloc/include/xo/alloc/ArenaAlloc.hpp b/xo-alloc/include/xo/alloc/ArenaAlloc.hpp index d9731761..1f48121b 100644 --- a/xo-alloc/include/xo/alloc/ArenaAlloc.hpp +++ b/xo-alloc/include/xo/alloc/ArenaAlloc.hpp @@ -5,7 +5,7 @@ #pragma once -#include "IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" #include "ObjectStatistics.hpp" namespace xo { @@ -175,8 +175,8 @@ namespace xo { virtual void clear() final override; virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; + virtual bool check_owned(IObject * src) const final override; - virtual bool check_owned(Object * src) const final override; ArenaAlloc & operator=(const ArenaAlloc &) = delete; ArenaAlloc & operator=(ArenaAlloc &&) = delete; diff --git a/xo-alloc/include/xo/alloc/Forwarding1.hpp b/xo-alloc/include/xo/alloc/Forwarding1.hpp index 8999849a..90ff0198 100644 --- a/xo-alloc/include/xo/alloc/Forwarding1.hpp +++ b/xo-alloc/include/xo/alloc/Forwarding1.hpp @@ -19,18 +19,18 @@ namespace xo { **/ class Forwarding1 : public Object { public: - explicit Forwarding1(gp dest); + explicit Forwarding1(gp dest); // inherited from Object.. virtual TaggedPtr self_tp() const final override; virtual void display(std::ostream & os) const final override; virtual bool _is_forwarded() const final override { return true; } - virtual Object * _offset_destination(Object * src) const final override; - virtual Object * _destination() final override; + virtual IObject * _offset_destination(IObject * src) const final override; + virtual IObject * _destination() final override; /** required by Object i/face, but never called on Forwarding1 **/ virtual std::size_t _shallow_size() const final override; /** required by Object i/face, but never called on Forwarding1 **/ - virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; + virtual IObject * _shallow_copy(gc::IAlloc * mm) const final override; /** required by Object i/face, but never called on Forwarding1 **/ virtual std::size_t _forward_children(gc::IAlloc * mm) final override; @@ -47,7 +47,7 @@ namespace xo { * UB revealed when GC traverses a pointer that relies on the 2nd * vtable to index virtual methods. **/ - gp dest_; + gp dest_; }; } /*namespace obj*/ diff --git a/xo-alloc/include/xo/alloc/GC.hpp b/xo-alloc/include/xo/alloc/GC.hpp index 6146cba9..aeb918c9 100644 --- a/xo-alloc/include/xo/alloc/GC.hpp +++ b/xo-alloc/include/xo/alloc/GC.hpp @@ -88,29 +88,30 @@ namespace xo { class MutationLogEntry { public: - MutationLogEntry(Object * parent, Object ** lhs) : parent_{parent}, lhs_{lhs} {} + MutationLogEntry(IObject * parent, IObject ** lhs) + : parent_{parent}, lhs_{lhs} {} - Object * parent() const { return parent_; } - Object ** lhs() const { return lhs_; } + IObject * parent() const { return parent_; } + IObject ** lhs() const { return lhs_; } - Object * child() const { return *lhs_; } + IObject * child() const { return *lhs_; } bool is_child_forwarded() const; bool is_parent_forwarded() const; - Object * parent_destination() const; + IObject * parent_destination() const; /** Flag obsolete mutation. * Future proofing, never happens for regular objects **/ bool is_dead() const { return false; } - MutationLogEntry update_parent_moved(Object * parent_to) const; - void fixup_parent_child_moved(Object * child_to) { *lhs_ = child_to; } + MutationLogEntry update_parent_moved(IObject * parent_to) const; + void fixup_parent_child_moved(IObject * child_to) { *lhs_ = child_to; } private: - Object * parent_; - Object ** lhs_; + IObject * parent_ = nullptr; + IObject ** lhs_ = nullptr; }; using MutationLog = std::vector; @@ -235,15 +236,15 @@ namespace xo { /** add gc root at address @p addr . Gc will keep alive anything reachable * from @c *addr **/ - void add_gc_root(Object ** addr); + void add_gc_root(IObject ** addr); /** reverse the effect of previous call to @ref add_gc_root **/ - void remove_gc_root(Object ** addr); + void remove_gc_root(IObject ** addr); /** convenience wrapper **/ template - void add_gc_root_dwim(gp * p) { this->add_gc_root(reinterpret_cast(p->ptr_address())); } + void add_gc_root_dwim(gp * p) { this->add_gc_root(reinterpret_cast(p->ptr_address())); } template - void remove_gc_root_dwim(gp * p) { this->remove_gc_root(reinterpret_cast(p->ptr_address())); } + void remove_gc_root_dwim(gp * p) { this->remove_gc_root(reinterpret_cast(p->ptr_address())); } /** may optionally use this to observe GC copy phase. * Will be invoked once _per surviving object_, so not cheap. @@ -308,17 +309,17 @@ namespace xo { * @param lhs. address of a member variable within the allocation of @p parent. * @param rhs. new target for @p *lhs **/ - virtual void assign_member(Object * parent, Object ** lhs, Object* rhs) final override; + virtual void assign_member(IObject * parent, IObject ** lhs, IObject* rhs) final override; /** during GC check for source objects owned by GC. * See Object::_shallow_move. **/ - virtual bool check_owned(Object * src) const final override; + virtual bool check_owned(IObject * src) const final override; /** queries during GC to determine if object at address @p src should move: * - full GC -> always * - incr GC -> if not tenured **/ - virtual bool check_move(Object * src) const final override; + virtual bool check_move(IObject * src) const final override; virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; @@ -349,7 +350,7 @@ namespace xo { /** scan to-space for object statistics before GC */ void capture_object_statistics(generation upto, capture_phase phase); /** copy object **/ - void copy_object(Object ** addr, generation upto, ObjectStatistics * object_stats); + void copy_object(IObject ** addr, generation upto, ObjectStatistics * object_stats); /** copy everything reachable from global gc roots **/ void copy_globals(generation g); /** review mutation log; may discover+rescue reachable objects. @@ -426,7 +427,7 @@ namespace xo { * Application can introduce new root object pointers at any time provided GC not running, * but cannot withdraw them. **/ - std::vector gc_root_v_; + std::vector gc_root_v_; /** log cross-generational and cross-checkpoint mutations. * These need to be adjusted on next incremental collection diff --git a/xo-alloc/include/xo/alloc/Object.hpp b/xo-alloc/include/xo/alloc/Object.hpp index c8772db9..2468c8bc 100644 --- a/xo-alloc/include/xo/alloc/Object.hpp +++ b/xo-alloc/include/xo/alloc/Object.hpp @@ -7,6 +7,8 @@ #include "xo/reflect/TaggedPtr.hpp" #include "IAlloc.hpp" +#include "xo/allocutil/IObject.hpp" +#include "xo/allocutil/gc_ptr.hpp" #include #include @@ -16,71 +18,6 @@ namespace xo { class ObjectStatistics; }; - template - class gc_ptr; - - template - using gp = gc_ptr; - - /** wrapper for a pointer to garbage-collector-eligible T. - * Application code will usually use the alias template gp - **/ - template - class gc_ptr { - public: - using element_type = T; - - public: - gc_ptr() = default; - gc_ptr(T * p) : ptr_{p} {} - gc_ptr(const gc_ptr & x) : ptr_{x.ptr_} {} - - /** create from gc_ptr to some related type @tparam S **/ - template - gc_ptr(const gc_ptr & x) : ptr_{x.ptr()} {} - - /** runtime downcast. shorthand for dynamic_cast **/ - template - static gc_ptr from(const gc_ptr & x) { return gc_ptr{dynamic_cast(x.ptr())}; } - - /** convenience for static asserts **/ - static constexpr bool is_gc_ptr = true; - /** see also: xo/refcnt/Refcounted.hpp **/ - static constexpr bool is_rc_ptr = false; - - static bool is_eq(gc_ptr x1, gc_ptr x2) { - std::uintptr_t u1 = reinterpret_cast(x1.ptr()); - std::uintptr_t u2 = reinterpret_cast(x2.ptr()); - - // multiple inheritance shenanigans. - // (allow interface pointers separated by one pointer) - - if (u1 >= u2) - return (u1 <= u2 + sizeof(std::uintptr_t)); - else - return (u2 <= u1 + sizeof(std::uintptr_t)); - } - - /** (for consistency's sake) **/ - T * get() const { return ptr_; } - - T * ptr() const { return ptr_; } - T ** ptr_address() { return &ptr_; } - - bool is_null() const { return ptr_ == nullptr; } - void make_null() { ptr_ = nullptr; } - - void assign_ptr(T * x) { ptr_ = x; } - - gc_ptr & operator=(const gc_ptr & x) { ptr_ = x.ptr(); return *this; } - - T * operator->() const { return ptr_; } - T & operator*() const { return *ptr_; } - - private: - T * ptr_ = nullptr; - }; - /** Root class for all xo GC-collectable objects. * * Design note: @@ -92,11 +29,15 @@ namespace xo { * Would be feasible to relax the must-inherit-from-Object constraint * by having GC use its own wrapper, at cost of an extra layer of indirection **/ - class Object { + class Object : public IObject { public: using TaggedPtr = xo::reflect::TaggedPtr; public: + static gp from(gp x) { + return dynamic_cast(x.ptr()); + } + virtual ~Object() = default; /** memory allocator for objects. Likely this will be a GC instance, @@ -111,7 +52,7 @@ namespace xo { * add mutation log entry **/ template - static void assign_member(gp parent, gp * lhs, gp rhs); + static void assign_member(gp parent, gp * lhs, gp rhs); /** use from GC aux functions **/ static gc::GC * _gc() { return reinterpret_cast(mm); } @@ -125,11 +66,11 @@ namespace xo { * @p src. source object to be forwarded * @p gc. garbage collector */ - static Object * _forward(Object * src, gc::IAlloc * gc); + static IObject * _forward(IObject * src, gc::IAlloc * gc); template static void _forward_inplace(T ** src_addr, gc::IAlloc * gc) { - Object * fwd = _forward(*src_addr, gc); + IObject * fwd = _forward(*src_addr, gc); *src_addr = reinterpret_cast(fwd); } @@ -160,12 +101,12 @@ namespace xo { * @param gc garbage collector * @param stats per-object-type GC statistics **/ - static Object * _deep_move(Object * src, gc::GC * gc, gc::ObjectStatistics * stats); + static IObject * _deep_move(IObject * src, gc::GC * gc, gc::ObjectStatistics * stats); /** copy @p src to to-space. Overwrite original with forwarding pointer to new location. * return the new location **/ - static Object * _shallow_move(Object * src, gc::IAlloc * gc); + static IObject * _shallow_move(IObject * src, gc::IAlloc * gc); // Reflection support @@ -176,89 +117,25 @@ namespace xo { /** print on stream @p os **/ virtual void display(std::ostream & os) const = 0; - // GC support + // Inherited from IObject.. - /** true iff this object represents a forwarding pointer. - * Forwarding pointers are exclusively created by the garbage collector; - * forwarding pointers (and only forwarding pointers) return true here. - **/ - virtual bool _is_forwarded() const { return false; } + //virtual bool _is_forwarded() const override { return false; } + //virtual IObject * _offset_destination(IObject * src) const override { return src; }; + virtual void _forward_to(IObject * dest) override; + //virtual IObject * _destination() override { return nullptr; } - /** offset for uncommon situation where pointer address is offset from object - * base address - **/ - virtual Object * _offset_destination(Object * src) const { return src; }; - - /** replace this object with a forwarding pointer referring to @p dest. - **/ - virtual void _forward_to(Object * dest); - - /** if this object represents a forwarding pointer, return its new location. - * forwarding pointers belong to the garbage collector implementation. - * (if you have to ask -- no, your class is not a forwarding pointer) - * all other objects return nullptr here. - **/ - virtual Object * _destination() { return nullptr; } - - /** return amount of storage (including padding) consumed by this object, - * excluding immediate Object-pointer children - **/ - virtual std::size_t _shallow_size() const = 0; - - /** if subject is allocated by GC: - * - create copy C in to-space - * - destination C will be nursery|tenured depending on location of this. - * else - * - return this to disengage from GC - * - * Require: @ref mm is an instance of @ref gc::GC - **/ - virtual Object * _shallow_copy(gc::IAlloc * gc) const = 0; - - /** update child pointers that refer to forwarding pointers, - * replacing them with the correct destination. - * See @ref Object::deep_move - * - * this gray object, located in to-space. - * fwd1 forwarding objects. - * Located in from-space. Invalid at end of GC cycle. - * p1,p2 source pointers. - * D1,D2 already-forwarded objects. located in to-space. - * - * before: - * this fwd1 - * +----+ +-+ - * | p1 ----->|x|-------> D1 - * | | +-+ - * | | - * | p2 ----------------> D2 - * +----+ - * - * after: - * this - * +----+ - * | p1 ----------------> D1 - * | | - * | | - * | p2 ----------------> D2 - * +----+ - * - * this is now white - * - * @return shallow size of *this. Must exactly match the amount of memory in to-space - * allocated by @ref _shallow_move - * - **/ - virtual std::size_t _forward_children(gc::IAlloc * gc) = 0; + virtual std::size_t _shallow_size() const override = 0; + virtual IObject * _shallow_copy(gc::IAlloc * gc) const override = 0; + virtual std::size_t _forward_children(gc::IAlloc * gc) override = 0; }; template void - Object::assign_member(gp parent, gp * lhs, gp rhs) + Object::assign_member(gp parent, gp * lhs, gp rhs) { - Object::mm->assign_member(parent.ptr(), - reinterpret_cast(lhs->ptr_address()), - rhs.ptr()); + Object::mm->assign_member(reinterpret_cast(parent.ptr()), + reinterpret_cast(lhs->ptr_address()), + reinterpret_cast(rhs.ptr())); } std::ostream & diff --git a/xo-alloc/src/alloc/ArenaAlloc.cpp b/xo-alloc/src/alloc/ArenaAlloc.cpp index 15078a0e..886b6a70 100644 --- a/xo-alloc/src/alloc/ArenaAlloc.cpp +++ b/xo-alloc/src/alloc/ArenaAlloc.cpp @@ -357,7 +357,7 @@ namespace xo { } bool - ArenaAlloc::check_owned(Object * src) const + ArenaAlloc::check_owned(IObject * src) const { byte * addr = reinterpret_cast(src); diff --git a/xo-alloc/src/alloc/Blob.cpp b/xo-alloc/src/alloc/Blob.cpp index 97932844..83e4121b 100644 --- a/xo-alloc/src/alloc/Blob.cpp +++ b/xo-alloc/src/alloc/Blob.cpp @@ -5,7 +5,7 @@ #include "Blob.hpp" #include "xo/reflect/Reflect.hpp" -#include "xo/alloc/IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" namespace xo { using xo::reflect::Reflect; diff --git a/xo-alloc/src/alloc/CMakeLists.txt b/xo-alloc/src/alloc/CMakeLists.txt index 4a9d1db4..67e9759b 100644 --- a/xo-alloc/src/alloc/CMakeLists.txt +++ b/xo-alloc/src/alloc/CMakeLists.txt @@ -2,7 +2,6 @@ set(SELF_LIB xo_alloc) set(SELF_SRCS - IAlloc.cpp ArenaAlloc.cpp ListAlloc.cpp GC.cpp @@ -15,6 +14,7 @@ set(SELF_SRCS ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +xo_headeronly_dependency(${SELF_LIB} xo_allocutil) # xo-unit used for time measurement xo_headeronly_dependency(${SELF_LIB} xo_unit) xo_dependency(${SELF_LIB} indentlog) diff --git a/xo-alloc/src/alloc/Forwarding1.cpp b/xo-alloc/src/alloc/Forwarding1.cpp index f94bf4f1..a42a3f57 100644 --- a/xo-alloc/src/alloc/Forwarding1.cpp +++ b/xo-alloc/src/alloc/Forwarding1.cpp @@ -13,7 +13,7 @@ namespace xo { using xo::reflect::TaggedPtr; namespace obj { - Forwarding1::Forwarding1(gp dest) + Forwarding1::Forwarding1(gp dest) : dest_{dest} {} @@ -26,18 +26,21 @@ namespace xo { void Forwarding1::display(std::ostream & os) const { - os << "self_tp().td()->short_name()) << ">"; + os << "self_tp().td()->short_name()) + << ">"; } - Object * - Forwarding1::_offset_destination(Object * src) const + IObject * + Forwarding1::_offset_destination(IObject * src) const { - intptr_t offset = src - static_cast(this); + intptr_t offset = src - static_cast(this); return dest_.ptr() + offset; } - Object * + IObject * Forwarding1::_destination() { return dest_.ptr(); } @@ -51,8 +54,10 @@ namespace xo { // LCOV_EXCL_STOP // LCOV_EXCL_START - Object * + IObject * Forwarding1::_shallow_copy(gc::IAlloc *) const { + /* forwarding objects are never copied */ + assert(false); return nullptr; } @@ -61,6 +66,8 @@ namespace xo { // LCOV_EXCL_START std::size_t Forwarding1::_forward_children(gc::IAlloc *) { + /* forwarding objects are never traced */ + assert(false); return 0; } diff --git a/xo-alloc/src/alloc/GC.cpp b/xo-alloc/src/alloc/GC.cpp index 3e636cad..ca2506d9 100644 --- a/xo-alloc/src/alloc/GC.cpp +++ b/xo-alloc/src/alloc/GC.cpp @@ -27,7 +27,7 @@ namespace xo { return parent_->_is_forwarded(); } - Object * + IObject * MutationLogEntry::parent_destination() const { //const bool c_debug_flag = true; @@ -45,7 +45,7 @@ namespace xo { } MutationLogEntry - MutationLogEntry::update_parent_moved(Object * parent_to) const + MutationLogEntry::update_parent_moved(IObject * parent_to) const { std::byte * parent_from = reinterpret_cast(parent_); std::byte * lhs_from = reinterpret_cast(lhs_); @@ -55,7 +55,7 @@ namespace xo { std::byte * lhs_to = reinterpret_cast(parent_to) + offset; return MutationLogEntry(parent_to, - reinterpret_cast(lhs_to)); + reinterpret_cast(lhs_to)); } GC::GC(const Config & config) @@ -395,13 +395,13 @@ namespace xo { } void - GC::add_gc_root(Object ** addr) + GC::add_gc_root(IObject ** addr) { gc_root_v_.push_back(addr); } void - GC::remove_gc_root(Object ** addr) + GC::remove_gc_root(IObject ** addr) { /* Multithreaded GC not supported */ @@ -450,7 +450,9 @@ namespace xo { std::byte * GC::alloc_gc_copy(std::size_t z, const void * src) { - scope log(XO_DEBUG(config_.debug_flag_), xtag("z", z), xtag("+pad", IAlloc::alloc_padding(z))); + scope log(XO_DEBUG(config_.debug_flag_), + xtag("z", z), + xtag("+pad", IAlloc::alloc_padding(z))); generation_result src_gr = this->fromspace_generation_of(src); @@ -483,7 +485,8 @@ namespace xo { gc_copy_cbset_.invoke(&GcCopyCallback::notify_gc_copy, z, src, retval, generation::nursery, generation::tenured); - this->gc_statistics_.total_promoted_ += IAlloc::with_padding(z); + this->gc_statistics_.total_promoted_ + += IAlloc::with_padding(z); } else { log && log("nursery"); @@ -509,7 +512,7 @@ namespace xo { } void - GC::assign_member(Object * parent, Object ** lhs, Object * rhs) + GC::assign_member(IObject * parent, IObject ** lhs, IObject * rhs) { ++gc_statistics_.n_mutation_; @@ -566,13 +569,13 @@ namespace xo { } bool - GC::check_owned(Object * src) const + GC::check_owned(IObject * src) const { return this->fromspace_contains(src); } bool - GC::check_move(Object * src) const + GC::check_move(IObject * src) const { return (this->runstate().full_move() || (this->tospace_generation_of(src) != gc::generation_result::tenured)); @@ -682,7 +685,9 @@ namespace xo { } void - GC::copy_object(Object ** pp_object, generation upto, ObjectStatistics * object_stats) + GC::copy_object(IObject ** pp_object, + generation upto, + ObjectStatistics * object_stats) { void * object_address = *pp_object; @@ -707,7 +712,7 @@ namespace xo { scope log(XO_DEBUG(config_.debug_flag_), xtag("roots", gc_root_v_.size())); - for (Object ** pp_root : gc_root_v_) { + for (IObject ** pp_root : gc_root_v_) { this->copy_object(pp_root, upto, &object_statistics_sae_[gen2int(upto)]); } @@ -778,7 +783,7 @@ namespace xo { // obsolete mutation -- no longer belongs to parent, discard } else { // note: child obtained (as it must be) by reading from parent's memory _now_. - Object * child_from = from_entry.child(); + IObject * child_from = from_entry.child(); if (child_from) { if (!child_from->_is_forwarded()) { @@ -813,7 +818,7 @@ namespace xo { // P->C, C moved to C' // Includes cases (a),(c) from above - Object * child_to = child_from->_destination(); + IObject * child_to = child_from->_destination(); from_entry.fixup_parent_child_moved(child_to); @@ -843,7 +848,7 @@ namespace xo { // follows that loc(P') = T // already have P'->C' when parent moved separately - Object * parent_to = from_entry.parent_destination(); + IObject * parent_to = from_entry.parent_destination(); log && log(xtag("parent_to", (void*)parent_to)); @@ -851,7 +856,7 @@ namespace xo { MutationLogEntry to_entry = from_entry.update_parent_moved(parent_to); - Object * child_to = to_entry.child(); // after moving + IObject * child_to = to_entry.child(); // after moving if (tospace_generation_of(child_to) == generation_result::nursery) { if (to_entry.is_dead()) { @@ -954,7 +959,7 @@ namespace xo { log && (i_from % 10000 == 0) && log(xtag("i_from", i_from)); if (from_entry.is_parent_forwarded()) { - Object * parent_to = from_entry.parent_destination(); + IObject * parent_to = from_entry.parent_destination(); log && log(xtag("parent_to", (void*)parent_to)); @@ -964,7 +969,7 @@ namespace xo { // note: child obtained (as it must be) by reading from prarent's memory _now_. // Since parent has moved, child has too - Object * child_to = to_entry.child(); // after moveing + IObject * child_to = to_entry.child(); // after moveing if (tospace_generation_of(parent_to) == generation_result::tenured) { diff --git a/xo-alloc/src/alloc/IAlloc.cpp b/xo-alloc/src/alloc/IAlloc.cpp deleted file mode 100644 index 9754fb47..00000000 --- a/xo-alloc/src/alloc/IAlloc.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* @file IAlloc.cpp - * - * author: Roland Conybeare, Aug 2025 - */ - -#include "IAlloc.hpp" -#include -#include - -namespace xo { - namespace gc { - - std::uint32_t - IAlloc::alloc_padding(std::size_t z) - { - /* word size for alignment */ - constexpr uint32_t c_bpw = sizeof(std::uintptr_t); - - /* round up to multiple of c_bpw, but map 0 -> 0 - * (table assuming c_bpw==8) - * - * z%c_bpw dz - * ------------ - * 0 0 - * 1 7 - * 2 6 - * .. .. - * 7 1 - */ - std::uint32_t dz = (c_bpw - (z % c_bpw)) % c_bpw; - z += dz; - - assert(z % c_bpw == 0ul); - - return dz; - } - - std::size_t - IAlloc::with_padding(std::size_t z) - { - return z + alloc_padding(z); - } - - void - IAlloc::assign_member(Object * /*parent*/, Object ** lhs, Object * rhs) - { - *lhs = rhs; - } - - bool - IAlloc::check_owned(Object * /*obj*/) const - { - return false; - } - - bool - IAlloc::check_move(Object * /*obj*/) const - { - return false; - } - - // LCOV_EXCL_START - std::byte * - IAlloc::alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) - { - assert(false); - return nullptr; - } - // LCOV_EXCL_STOP - - } /*namespace gc*/ -} /*namespace xo*/ - -/* end IAlloc.cpp */ diff --git a/xo-alloc/src/alloc/Object.cpp b/xo-alloc/src/alloc/Object.cpp index dbb86ae2..82583a0a 100644 --- a/xo-alloc/src/alloc/Object.cpp +++ b/xo-alloc/src/alloc/Object.cpp @@ -23,8 +23,8 @@ namespace xo { gc::IAlloc * Object::mm = nullptr; - Object * - Object::_forward(Object * src, gc::IAlloc * gc) + IObject * + Object::_forward(IObject * src, gc::IAlloc * gc) { if (!src) return src; @@ -43,15 +43,15 @@ namespace xo { } } - Object * - Object::_deep_move(Object * from_src, gc::GC * gc, gc::ObjectStatistics * /*stats*/) + IObject * + Object::_deep_move(IObject * from_src, gc::GC * gc, gc::ObjectStatistics * /*stats*/) { using gc::generation; if (!from_src) return nullptr; - Object * retval = from_src->_destination(); + IObject * retval = from_src->_destination(); if (retval) return retval; @@ -124,7 +124,7 @@ namespace xo { std::array gray_lo_v = { gc->free_ptr(generation::nursery), gc->free_ptr(generation::tenured) }; - Object * to_src = Object::_shallow_move(from_src, gc); + IObject * to_src = Object::_shallow_move(from_src, gc); std::size_t fixup_work = 0; do { @@ -158,15 +158,15 @@ namespace xo { return to_src; } /*deep_move*/ - Object * - Object::_shallow_move(Object * src, gc::IAlloc * gc) + IObject * + Object::_shallow_move(IObject * src, gc::IAlloc * gc) { /* filter for source objects that are owned by GC. * Care required though -- during GC from/to spaces have been swapped already */ if (gc->check_owned(src)) { - Object * dest = src->_shallow_copy(gc); + IObject * dest = src->_shallow_copy(gc); if (dest != src) src->_forward_to(dest); @@ -178,7 +178,7 @@ namespace xo { } void - Object::_forward_to(Object * dest) + Object::_forward_to(IObject * dest) { char * mem = reinterpret_cast(this); diff --git a/xo-allocutil/CMakeLists.txt b/xo-allocutil/CMakeLists.txt new file mode 100644 index 00000000..83f0a59f --- /dev/null +++ b/xo-allocutil/CMakeLists.txt @@ -0,0 +1,43 @@ +# xo-allocutil/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(xo_allocutil VERSION 0.1) +enable_language(CXX) + +# common XO macros (see github:Rconybea/xo-cmake) +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings + +set(PROJECT_CXX_FLAGS "") +add_definitions(${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- +# output targets + +#add_subdirectory(utest) + +# ---------------------------------------------------------------- +# header-only library + +set(SELF_LIB xo_allocutil) +xo_add_headeronly_library(${SELF_LIB}) + +# ---------------------------------------------------------------- +# +xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets) +# (note: ..Targets from xo_install_library2()) +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) + +# ---------------------------------------------------------------- +# input dependencies + +# NOTE: dependency set here must be kept consistent with allocutil/cmake/xo_allocutilConfig.cmake.in + +# xo-allocutil is also header-only +#xo_headeronly_dependency(${SELF_LIB} randomgen) diff --git a/xo-allocutil/cmake/xo-bootstrap-macros.cmake b/xo-allocutil/cmake/xo-bootstrap-macros.cmake new file mode 100644 index 00000000..694d9b5c --- /dev/null +++ b/xo-allocutil/cmake/xo-bootstrap-macros.cmake @@ -0,0 +1,14 @@ +if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "prefix")) + # default to typical install location for xo-project-macros + set(CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/cmake) +endif() + +if (NOT XO_SUBMODULE_BUILD) + message("-- CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") + message("-- CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") +endif() + +# needs to have been installed somewhere on CMAKE_MODULE_PATH, +# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) +# +include(xo_macros/xo_cxx) diff --git a/xo-allocutil/cmake/xo_allocutilConfig.cmake.in b/xo-allocutil/cmake/xo_allocutilConfig.cmake.in new file mode 100644 index 00000000..00b2de9b --- /dev/null +++ b/xo-allocutil/cmake/xo_allocutilConfig.cmake.in @@ -0,0 +1,6 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +#find_dependency(randomgen) +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/xo-alloc/include/xo/alloc/IAlloc.hpp b/xo-allocutil/include/xo/allocutil/IAlloc.hpp similarity index 70% rename from xo-alloc/include/xo/alloc/IAlloc.hpp rename to xo-allocutil/include/xo/allocutil/IAlloc.hpp index 3b36dc98..f2e6de31 100644 --- a/xo-alloc/include/xo/alloc/IAlloc.hpp +++ b/xo-allocutil/include/xo/allocutil/IAlloc.hpp @@ -1,7 +1,7 @@ -/* file IAlloc.hpp +/** @file IAlloc.hpp * - * author: Roland Conybeare, Jul 2025 - */ + * @author: Roland Conybeare, Jul 2025 + **/ #pragma once @@ -12,11 +12,11 @@ namespace xo { template using up = std::unique_ptr; - class Object; + class IObject; namespace gc { /** @class IAllocator - * @brief arena allocation interface with limited garbage collector support + * @brief Abstract API for allocation interface * * Garbage collector support methods: * - checkpoint() @@ -30,12 +30,30 @@ namespace xo { public: virtual ~IAlloc() {} - /** compute padding to add to an allocation of size z to bring it up to - * a multiple of word size (8 bytes on x86_64) - **/ - static std::uint32_t alloc_padding(std::size_t z); - /** z + alloc_padding(z) **/ - static std::size_t with_padding(std::size_t z); + static inline std::uint32_t alloc_padding(std::size_t z) { + /* word size for alignment */ + constexpr uint32_t c_bpw = sizeof(std::uintptr_t); + + /* round up to multiple of c_bpw, but map 0 -> 0 + * (table assuming c_bpw==8) + * + * z%c_bpw dz + * ------------ + * 0 0 + * 1 7 + * 2 6 + * .. .. + * 7 1 + */ + std::uint32_t dz = (c_bpw - (z % c_bpw)) % c_bpw; + z += dz; + + return dz; + } + + static inline std::size_t with_padding(std::size_t z) { + return z + alloc_padding(z); + } /** optional name for this allocator; labelling for diagnostics **/ virtual const std::string & name() const = 0; @@ -81,23 +99,30 @@ namespace xo { /** true iff this allocator owns object at address @p src. * Use to assist Object::_shallow_move **/ - virtual bool check_owned(Object * src) const; + virtual bool check_owned(IObject * /*src*/) const { return false; } /** true iff object at address @p src must move as part of * in-progress collection phase **/ - virtual bool check_move(Object * src) const; - /** perform assignment + virtual bool check_move(IObject * /*src*/) const { return false; } + /** write barrier for collector. perform assignment * @code * *lhs = rhs * @endcode * plus additional book keeping if needed (e.g. in @ref GC) * Default implementation just does the assignment. **/ - virtual void assign_member(Object * parent, Object ** lhs, Object * rhs); + virtual void assign_member(IObject * /*parent*/, + IObject ** lhs, + IObject * rhs) { *lhs = rhs; } /** allocate @p z bytes for copy of object at @p src. * Only used in @ref GC. Default implementation asserts and returns nullptr **/ - virtual std::byte * alloc_gc_copy(std::size_t z, const void * src); + virtual std::byte * alloc_gc_copy(std::size_t /*z*/, const void * /*src*/) { + // LCOV_EXCL_START + //assert(false); + return nullptr; + // LCOV_EXCL_STOP + } }; } /*namespace gc*/ diff --git a/xo-allocutil/include/xo/allocutil/IObject.hpp b/xo-allocutil/include/xo/allocutil/IObject.hpp new file mode 100644 index 00000000..c4b15800 --- /dev/null +++ b/xo-allocutil/include/xo/allocutil/IObject.hpp @@ -0,0 +1,97 @@ +/** @file IObject.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace gc { class IAlloc; } + + /** @class IObject + * @brief Base interface for GC interaction + * + * Classes that can be collected inherit this api + * indirectly via xo::Object (see xo/alloc/Object.hpp) + **/ + class IObject { + public: + /** true iff this object represents a forwarding pointer. + * Forwarding pointers are exclusively created by the garbage collector; + * forwarding pointers (and only forwarding pointers) return true here. + **/ + virtual bool _is_forwarded() const { return false; } + + /** offset for uncommon situation where pointer address is offset from object + * base address + **/ + virtual IObject * _offset_destination(IObject * src) const { return src; }; + + /** replace this object with a forwarding pointer referring to @p dest. + **/ + virtual void _forward_to(IObject * dest) = 0; + + /** if this object represents a forwarding pointer, return its new location. + * forwarding pointers belong to the garbage collector implementation. + * (if you have to ask -- no, your class is not a forwarding pointer) + * all other objects return nullptr here. + **/ + virtual IObject * _destination() { return nullptr; } + + /** return amount of storage (including padding) consumed by this object, + * excluding immediate Object-pointer children + **/ + virtual std::size_t _shallow_size() const = 0; + + /** if subject is allocated by GC: + * - create copy C in to-space + * - destination C will be nursery|tenured depending on location of this. + * else + * - return this to disengage from GC + * + * Require: @ref mm is an instance of @ref gc::GC + **/ + virtual IObject * _shallow_copy(gc::IAlloc * gc) const = 0; + + /** update child pointers that refer to forwarding pointers, + * replacing them with the correct destination. + * See @ref Object::deep_move + * + * this gray object, located in to-space. + * fwd1 forwarding objects. + * Located in from-space. Invalid at end of GC cycle. + * p1,p2 source pointers. + * D1,D2 already-forwarded objects. located in to-space. + * + * before: + * this fwd1 + * +----+ +-+ + * | p1 ----->|x|-------> D1 + * | | +-+ + * | | + * | p2 ----------------> D2 + * +----+ + * + * after: + * this + * +----+ + * | p1 ----------------> D1 + * | | + * | | + * | p2 ----------------> D2 + * +----+ + * + * this is now white + * + * @return shallow size of *this. Must exactly match the amount of memory in to-space + * allocated by @ref _shallow_move + * + **/ + virtual std::size_t _forward_children(gc::IAlloc * gc) = 0; + }; +} + +/* end IObject.hpp */ diff --git a/xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp b/xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp new file mode 100644 index 00000000..b2fc4168 --- /dev/null +++ b/xo-allocutil/include/xo/allocutil/gc_allocator_traits.hpp @@ -0,0 +1,75 @@ +/** @file gc_allocator_traits.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace gc { + /** Extended version of + * std::allocator_traits + * Introduces additional i/face methods + * for garbage-collector-enabled allocators + * + * allocator A can identify itself as a copying collector: + * 1. provide A::object_interface + * A::object_interface = xo::Object + * 2. provide A::is_incremental_collector + * A::is_incremental_collector = std::true_type + * Collectible objects must: + * 2a. inherit A::object_interface + * 2b. implement A::object_interface::_shallow_size() + * 2c. implement A::object_interface::_shallow_copy(alloc) + * 2d. implement A::object_interface::_forward_children(alloc) + **/ + template + struct gc_allocator_traits : std::allocator_traits { + using super = std::allocator_traits; + using pointer = typename super::pointer; + using value_type = typename super::value_type; + + // default: allocator A fallback to standard non-gc allocator behavior + template + struct is_incremental_collector : std::false_type {}; + + // opt-in: A provides nested type 'is_incremental_collector': + // struct A { + // using is_incremental_collector = std::true_type; + // }; + template + struct is_incremental_collector> : + A::is_incremental_collector {}; + + // default: empty object interface. + // classes that want to conditionally support GC + // (e.g. see xo::tree::RedBlackTree, xo::tree::Node + // in xo-ordinal-tree) + // can inherit + // gc_allocator_traits::template object_interface + // + template + struct object_interface {}; + + // specialization when A provides gc_object_interface + template + struct object_interface> + : A::gc_object_interface {}; + + /** true iff this allocator advertises itself as an incremental collector + * allocator will include: + * + * struct GC { + * using is_incremental_collector = std::true_type; + * }; + **/ + static inline constexpr bool is_incremental_collector_v = is_incremental_collector::value; + + }; + } /*namespace gc*/ +} /*namespace xo*/ + +/* end gc_allocator_traits.hpp */ diff --git a/xo-allocutil/include/xo/allocutil/gc_ptr.hpp b/xo-allocutil/include/xo/allocutil/gc_ptr.hpp new file mode 100644 index 00000000..bb4225ae --- /dev/null +++ b/xo-allocutil/include/xo/allocutil/gc_ptr.hpp @@ -0,0 +1,77 @@ +/** @file gc_ptr.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include + +namespace xo { + template + class gc_ptr; + + template + using gp = gc_ptr; + + /** wrapper for a pointer to garbage-collector-eligible T. + * Application code will usually use the alias template gp + **/ + template + class gc_ptr { + public: + using element_type = T; + + public: + gc_ptr() = default; + gc_ptr(T * p) : ptr_{p} {} + gc_ptr(const gc_ptr & x) : ptr_{x.ptr_} {} + + /** create from gc_ptr to some related type @tparam S **/ + template + gc_ptr(const gc_ptr & x) : ptr_{x.ptr()} {} + + /** runtime downcast. shorthand for dynamic_cast **/ + template + static gc_ptr from(const gc_ptr & x) { return gc_ptr{dynamic_cast(x.ptr())}; } + + /** convenience for static asserts **/ + static constexpr bool is_gc_ptr = true; + /** see also: xo/refcnt/Refcounted.hpp **/ + static constexpr bool is_rc_ptr = false; + + static bool is_eq(gc_ptr x1, gc_ptr x2) { + std::uintptr_t u1 = reinterpret_cast(x1.ptr()); + std::uintptr_t u2 = reinterpret_cast(x2.ptr()); + + // multiple inheritance shenanigans. + // (allow interface pointers separated by one pointer) + + if (u1 >= u2) + return (u1 <= u2 + sizeof(std::uintptr_t)); + else + return (u2 <= u1 + sizeof(std::uintptr_t)); + } + + /** (for consistency's sake) **/ + T * get() const { return ptr_; } + + T * ptr() const { return ptr_; } + T ** ptr_address() { return &ptr_; } + + bool is_null() const { return ptr_ == nullptr; } + void make_null() { ptr_ = nullptr; } + + void assign_ptr(T * x) { ptr_ = x; } + + gc_ptr & operator=(const gc_ptr & x) { ptr_ = x.ptr(); return *this; } + + T * operator->() const { return ptr_; } + T & operator*() const { return *ptr_; } + + private: + T * ptr_ = nullptr; + }; +} /*namespace xo*/ + +/* end gc_ptr.hpp */ diff --git a/xo-imgui/example/ex2/imgui_ex2.cpp b/xo-imgui/example/ex2/imgui_ex2.cpp index 3da0c883..90694618 100644 --- a/xo-imgui/example/ex2/imgui_ex2.cpp +++ b/xo-imgui/example/ex2/imgui_ex2.cpp @@ -263,6 +263,7 @@ GcStateDescription::GcStateDescription(const GcGenerationDescription & nursery, using xo::gp; using xo::up; +using xo::IObject; using xo::Object; using xo::obj::List; using xo::obj::Integer; @@ -342,7 +343,7 @@ AppState::AppState() Object::mm = gc_.get(); for (auto & x: gc_root_v_) - gc_->add_gc_root(x.ptr_address()); + gc_->add_gc_root(reinterpret_cast(x.ptr_address())); gc_->disable_gc(); } diff --git a/xo-imgui/example/ex4/AppState.cpp b/xo-imgui/example/ex4/AppState.cpp index 1d145667..11c43ff2 100644 --- a/xo-imgui/example/ex4/AppState.cpp +++ b/xo-imgui/example/ex4/AppState.cpp @@ -4,6 +4,7 @@ #include "xo/object/Integer.hpp" #include "xo/object/List.hpp" +using xo::IObject; using xo::obj::Integer; using xo::obj::List; using xo::gp; @@ -22,7 +23,7 @@ AppState::AppState() Object::mm = gc_.get(); for (auto & x: gc_root_v_) - gc_->add_gc_root(x.ptr_address()); + gc_->add_gc_root(reinterpret_cast(x.ptr_address())); gc_->disable_gc(); } diff --git a/xo-interpreter/include/xo/interpreter/BuiltinPrimitives.hpp b/xo-interpreter/include/xo/interpreter/BuiltinPrimitives.hpp index e19fc61e..39995b23 100644 --- a/xo-interpreter/include/xo/interpreter/BuiltinPrimitives.hpp +++ b/xo-interpreter/include/xo/interpreter/BuiltinPrimitives.hpp @@ -4,7 +4,7 @@ **/ #include "xo/object/ObjectConverter.hpp" -#include "xo/alloc/IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" #include "Primitive.hpp" #include "GlobalEnv.hpp" diff --git a/xo-interpreter/include/xo/interpreter/GlobalEnv.hpp b/xo-interpreter/include/xo/interpreter/GlobalEnv.hpp index bf43a755..50e765ba 100644 --- a/xo-interpreter/include/xo/interpreter/GlobalEnv.hpp +++ b/xo-interpreter/include/xo/interpreter/GlobalEnv.hpp @@ -3,7 +3,7 @@ #pragma once #include "Env.hpp" -#include "xo/alloc/IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" #include "xo/expression/GlobalSymtab.hpp" namespace xo { diff --git a/xo-interpreter/include/xo/interpreter/LocalEnv.hpp b/xo-interpreter/include/xo/interpreter/LocalEnv.hpp index be6e2f0a..9745a854 100644 --- a/xo-interpreter/include/xo/interpreter/LocalEnv.hpp +++ b/xo-interpreter/include/xo/interpreter/LocalEnv.hpp @@ -2,7 +2,7 @@ #include "Env.hpp" #include "CVector.hpp" -#include "xo/alloc/IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" #include "xo/expression/LocalSymtab.hpp" #include #include diff --git a/xo-interpreter/utest/LocalEnv.test.cpp b/xo-interpreter/utest/LocalEnv.test.cpp index 657f1293..084d5a4d 100644 --- a/xo-interpreter/utest/LocalEnv.test.cpp +++ b/xo-interpreter/utest/LocalEnv.test.cpp @@ -91,12 +91,12 @@ namespace xo { std::size_t n = tc.contents_.size(); gp x = Integer::make(gc.get(), 42); - gc->add_gc_root(reinterpret_cast(&x)); + gc->add_gc_root(reinterpret_cast(&x)); REQUIRE(gc->tospace_generation_of(x.ptr()) == generation_result::nursery); gp frame = LocalEnv::make(gc.get(), nullptr /*parent*/, nullptr /*symtab*/, n); LocalEnv ** frame_pp = frame.ptr_address(); - gc->add_gc_root(reinterpret_cast(frame_pp)); + gc->add_gc_root(reinterpret_cast(frame_pp)); /* verifying allocated in N1 */ REQUIRE(gc->tospace_generation_of(frame.ptr()) == generation_result::nursery); diff --git a/xo-object/include/xo/object/CVector.hpp b/xo-object/include/xo/object/CVector.hpp index d8c27e60..58828add 100644 --- a/xo-object/include/xo/object/CVector.hpp +++ b/xo-object/include/xo/object/CVector.hpp @@ -5,7 +5,7 @@ #pragma once -#include "xo/alloc/IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" #include namespace xo { diff --git a/xo-object/include/xo/object/Integer.hpp b/xo-object/include/xo/object/Integer.hpp index 2efec19d..ad88b0ad 100644 --- a/xo-object/include/xo/object/Integer.hpp +++ b/xo-object/include/xo/object/Integer.hpp @@ -23,7 +23,7 @@ namespace xo { /** create instance holding integer value @p x **/ static gp make(IAlloc * mm, int_type x); /** downcast from @p x iff x is actually an Integer. Otherwise nullptr **/ - static gp from(gp x); + static gp from(gp x); int_type value() const { return value_; } diff --git a/xo-object/include/xo/object/List.hpp b/xo-object/include/xo/object/List.hpp index 787940c6..71fe095f 100644 --- a/xo-object/include/xo/object/List.hpp +++ b/xo-object/include/xo/object/List.hpp @@ -18,7 +18,7 @@ namespace xo { static gp nil; /** @return non-null iff @p x is actually a List cell (or nil) **/ - static gp from(gp x); + static gp from(gp x); /** @return list with first element @p car, and tail @p cdr **/ static gp cons(gp car, gp cdr); @@ -44,7 +44,7 @@ namespace xo { /** @return first element in list; synonym for @ref head **/ gp car() const { return head_; } /** @return remainder of list after first element; synonym for @ref rest **/ - gp cdr() const { return rest_; } + gp cdr() const { return rest_; } /** @return number of top-level elements in this list **/ std::size_t size() const; @@ -58,7 +58,7 @@ namespace xo { virtual TaggedPtr self_tp() const final override; virtual void display(std::ostream & os) const final override; virtual std::size_t _shallow_size() const final override; - virtual Object * _shallow_copy(gc::IAlloc * gc) const final override; + virtual IObject * _shallow_copy(gc::IAlloc * gc) const final override; virtual std::size_t _forward_children(gc::IAlloc * gc) final override; private: diff --git a/xo-object/include/xo/object/String.hpp b/xo-object/include/xo/object/String.hpp index e778d2f8..5c06da69 100644 --- a/xo-object/include/xo/object/String.hpp +++ b/xo-object/include/xo/object/String.hpp @@ -5,7 +5,7 @@ #include "xo/alloc/Object.hpp" #include "ObjectConversion.hpp" -#include "xo/alloc/IAlloc.hpp" +#include "xo/allocutil/IAlloc.hpp" #include "xo/indentlog/print/tag.hpp" namespace xo { diff --git a/xo-object/src/object/Integer.cpp b/xo-object/src/object/Integer.cpp index 5aee03f6..82e755c9 100644 --- a/xo-object/src/object/Integer.cpp +++ b/xo-object/src/object/Integer.cpp @@ -23,7 +23,7 @@ namespace xo { } gp - Integer::from(gp x) { + Integer::from(gp x) { return gp::from(x); } diff --git a/xo-object/src/object/List.cpp b/xo-object/src/object/List.cpp index 78ce7db2..e8e700f2 100644 --- a/xo-object/src/object/List.cpp +++ b/xo-object/src/object/List.cpp @@ -21,7 +21,7 @@ namespace xo { List::nil = new List(nullptr, nullptr); gp - List::from(gp x) { + List::from(gp x) { return dynamic_cast(x.ptr()); } @@ -99,7 +99,7 @@ namespace xo { return sizeof(List); } - Object * + IObject * List::_shallow_copy(gc::IAlloc * gc) const { assert(!(this->is_nil())); diff --git a/xo-object/utest/GC.test.cpp b/xo-object/utest/GC.test.cpp index 9c312683..015d7eb8 100644 --- a/xo-object/utest/GC.test.cpp +++ b/xo-object/utest/GC.test.cpp @@ -59,10 +59,10 @@ namespace xo { Object::mm = gc.get(); gp l = List::list(Integer::make(gc.get(), 1)); - gc->add_gc_root(reinterpret_cast(l.ptr_address())); + gc->add_gc_root(reinterpret_cast(l.ptr_address())); gp l2 = List::list(Integer::make(gc.get(), 10)); - gc->add_gc_root(reinterpret_cast(l2.ptr_address())); + gc->add_gc_root(reinterpret_cast(l2.ptr_address())); { REQUIRE(l->size() == 1); @@ -447,7 +447,7 @@ namespace xo { REQUIRE(root_v_.size() == r_); for (auto & root : root_v_) - gc->add_gc_root(root.ptr_address()); + gc->add_gc_root(reinterpret_cast(root.ptr_address())); } void RandomMutationModel::generate_random_mutations(xoshiro256ss * p_rgen) @@ -495,7 +495,7 @@ namespace xo { if (w2_.at(j)->_is_forwarded()) { /* w2[i] survived GC */ - w2_[j] = w2_[j]->_destination(); + w2_[j] = Object::from(w2_[j]->_destination()); REQUIRE(w2_[j].ptr()); } else { /* w2[j] is garbage, replace */ diff --git a/xo-object/utest/List.test.cpp b/xo-object/utest/List.test.cpp index 7aaf4f9d..f2c75de7 100644 --- a/xo-object/utest/List.test.cpp +++ b/xo-object/utest/List.test.cpp @@ -124,7 +124,7 @@ namespace xo { REQUIRE(l1->size() == v.size()); root_v[i] = l1; - gc->add_gc_root(reinterpret_cast(root_v[i].ptr_address())); + gc->add_gc_root(reinterpret_cast(root_v[i].ptr_address())); REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0); REQUIRE(gc->allocated() == expected_alloc_z); @@ -285,7 +285,7 @@ namespace xo { //REQUIRE(l1->size() == v.size()); // lwill loop forever root_v[i] = l1; - gc->add_gc_root(reinterpret_cast(root_v[i].ptr_address())); + gc->add_gc_root(reinterpret_cast(root_v[i].ptr_address())); REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0); REQUIRE(gc->allocated() == expected_alloc_z); diff --git a/xo-object/utest/String.test.cpp b/xo-object/utest/String.test.cpp index 17253553..15b90748 100644 --- a/xo-object/utest/String.test.cpp +++ b/xo-object/utest/String.test.cpp @@ -145,7 +145,7 @@ namespace xo { xtag("alloc_z", alloc_z)); log && log(xtag("expected_alloc_z", expected_alloc_z)); - gc->add_gc_root(reinterpret_cast(sv[i].ptr_address())); + gc->add_gc_root(reinterpret_cast(sv[i].ptr_address())); REQUIRE(gc->allocated() % sizeof(std::uintptr_t) == 0); REQUIRE(gc->allocated() == expected_alloc_z);