diff --git a/include/xo/alloc2/alloc/AAllocator.hpp b/include/xo/alloc2/alloc/AAllocator.hpp index 74c1c6b..2fd7128 100644 --- a/include/xo/alloc2/alloc/AAllocator.hpp +++ b/include/xo/alloc2/alloc/AAllocator.hpp @@ -8,7 +8,6 @@ #include #include #include "AllocInfo.hpp" -//#include "AllocIterator.hpp" #include "AllocRange.hpp" #include "typeseq.hpp" #include diff --git a/include/xo/alloc2/gc/ACollector.hpp b/include/xo/alloc2/gc/ACollector.hpp index 72d3802..32ee2b2 100644 --- a/include/xo/alloc2/gc/ACollector.hpp +++ b/include/xo/alloc2/gc/ACollector.hpp @@ -76,6 +76,15 @@ namespace xo { **/ virtual void request_gc(Opaque d, generation upto) = 0; + /** Assign pointer @p p_lhs to destination @p rhs, within parent allocation @p parent + * + * Require: gc not in progress + **/ + virtual void assign_member(Opaque d, + void * parent, + obj * p_lhs, + obj & rhs) = 0; + /** evacuate @p *lhs, that refers to state with interface @p lhs_iface, * to collector @p d's to-space. Replace *lhs_data with forwarding pointer * diff --git a/include/xo/alloc2/gc/AGCObject.hpp b/include/xo/alloc2/gc/AGCObject.hpp index c420f0f..1037f25 100644 --- a/include/xo/alloc2/gc/AGCObject.hpp +++ b/include/xo/alloc2/gc/AGCObject.hpp @@ -53,6 +53,11 @@ public: /** @defgroup mm-gcobject-methods **/ ///@{ // const methods + /** An uninitialized AGCObject instance will have zero vtable pointer (per {linux,osx} abi). + * Use case for this is narrow. We go to some lengths to avoid null vtable pointers. For example + * obj will have non-null vtable (via IFacet_Any) with all methods terminating. + **/ + bool _has_null_vptr() const noexcept { return *reinterpret_cast(this) == nullptr; } /** RTTI: unique id# for actual runtime data representation **/ virtual typeseq _typeseq() const noexcept = 0; /** destroy instance @p d; calls c++ dtor only for actual runtime type; does not recover memory **/ diff --git a/include/xo/alloc2/gc/ICollector_Any.hpp b/include/xo/alloc2/gc/ICollector_Any.hpp index 555adc6..dbff110 100644 --- a/include/xo/alloc2/gc/ICollector_Any.hpp +++ b/include/xo/alloc2/gc/ICollector_Any.hpp @@ -41,6 +41,8 @@ namespace xo { [[noreturn]] void add_gc_root_poly(Opaque, obj *) override { _fatal(); } [[noreturn]] void remove_gc_root_poly(Opaque, obj *) override { _fatal(); } [[noreturn]] void request_gc(Opaque, generation) override { _fatal(); } + [[noreturn]] void assign_member(Opaque, void *, + obj *, obj &) override { _fatal(); } [[noreturn]] void forward_inplace(Opaque, AGCObject *, void **) override { _fatal(); } private: diff --git a/include/xo/alloc2/gc/ICollector_Xfer.hpp b/include/xo/alloc2/gc/ICollector_Xfer.hpp index 4100c8c..dbb6655 100644 --- a/include/xo/alloc2/gc/ICollector_Xfer.hpp +++ b/include/xo/alloc2/gc/ICollector_Xfer.hpp @@ -59,6 +59,10 @@ namespace xo { void request_gc(Opaque d, generation upto) override { I::request_gc(_dcast(d), upto); } + void assign_member(Opaque d, void * parent, + obj * p_lhs, obj & rhs) override { + I::assign_member(_dcast(d), parent, p_lhs, rhs); + } void forward_inplace(Opaque d, AGCObject * lhs_iface, void ** lhs_data) override { I::forward_inplace(_dcast(d), lhs_iface, lhs_data); diff --git a/include/xo/alloc2/gc/RCollector.hpp b/include/xo/alloc2/gc/RCollector.hpp index b9d3e3e..f62c02f 100644 --- a/include/xo/alloc2/gc/RCollector.hpp +++ b/include/xo/alloc2/gc/RCollector.hpp @@ -51,6 +51,11 @@ namespace xo { void add_gc_root_poly(obj * p_root) { O::iface()->add_gc_root_poly(O::data(), p_root); } void remove_gc_root_poly(obj * p_root) { O::iface()->remove_gc_root_poly(O::data(), p_root); } void request_gc(generation g) { O::iface()->request_gc(O::data(), g); } + + void assign_member(void * parent, + obj * p_lhs, + obj & rhs) { O::iface()->assign_member(O::data(), parent, p_lhs, rhs); } + void forward_inplace(AGCObject * lhs_iface, void ** lhs_data) { O::iface()->forward_inplace(O::data(), lhs_iface, lhs_data); } /** add root @p p_root **/ diff --git a/include/xo/alloc2/gc/RCollector_aux.hpp b/include/xo/alloc2/gc/RCollector_aux.hpp index 5e56035..4fc59b9 100644 --- a/include/xo/alloc2/gc/RCollector_aux.hpp +++ b/include/xo/alloc2/gc/RCollector_aux.hpp @@ -43,9 +43,27 @@ namespace xo { void RCollector::forward_pivot_inplace(obj * p_objs) { - auto e = xo::facet::FacetRegistry::instance().variant(*p_objs); - this->forward_inplace(e.iface(), (void **)&(p_objs->data_)); + if (*p_objs) { + auto e = xo::facet::FacetRegistry::instance().variant(*p_objs); + this->forward_inplace(e.iface(), (void **)&(p_objs->data_)); + } } + + /** gc-aware assignment; engage special book-keeping for cross-gen pointers **/ + inline void mm_do_assign(obj & gc, + void * parent, + obj * p_lhs, + obj & rhs) + { + if (gc.data()) { + gc.assign_member(parent, p_lhs, rhs); + } else { + // assume null collector downstream from allocator that does not provide collection. + // In that no additional assignment work. + + *p_lhs = rhs; + } + }; } } diff --git a/include/xo/alloc2/generation.hpp b/include/xo/alloc2/generation.hpp index 12b36d0..08c8532 100644 --- a/include/xo/alloc2/generation.hpp +++ b/include/xo/alloc2/generation.hpp @@ -23,6 +23,9 @@ namespace xo { explicit constexpr generation(value_type x) : value_{x} {} static generation nursery() { return generation{0}; } + static generation sentinel() { return generation(c_max_generation); } + + bool is_sentinel() const noexcept { return value_ == c_max_generation; } constexpr operator value_type() const { return value_; } @@ -30,6 +33,19 @@ namespace xo { std::uint32_t value_ = 0; }; + + inline bool operator==(generation lhs, generation rhs) { + return lhs.value_ == rhs.value_; + } + + inline bool operator<(generation lhs, generation rhs) { + return lhs.value_ < rhs.value_; + } + + inline bool operator>(generation lhs, generation rhs) { + return lhs.value_ > rhs.value_; + } + } } diff --git a/include/xo/alloc2/visitor/AResourceVisitor.hpp b/include/xo/alloc2/visitor/AResourceVisitor.hpp index c8ab374..64d9b13 100644 --- a/include/xo/alloc2/visitor/AResourceVisitor.hpp +++ b/include/xo/alloc2/visitor/AResourceVisitor.hpp @@ -46,6 +46,11 @@ public: /** @defgroup mm-resourcevisitor-methods **/ ///@{ // const methods + /** An uninitialized AResourceVisitor instance will have zero vtable pointer (per {linux,osx} abi). + * Use case for this is narrow. We go to some lengths to avoid null vtable pointers. For example + * obj will have non-null vtable (via IFacet_Any) with all methods terminating. + **/ + bool _has_null_vptr() const noexcept { return *reinterpret_cast(this) == nullptr; } /** RTTI: unique id# for actual runtime data representation **/ virtual typeseq _typeseq() const noexcept = 0; /** destroy instance @p d; calls c++ dtor only for actual runtime type; does not recover memory **/