From b780d1da4cc66fff4cbca173ebb32263ee907ba6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 1 May 2026 19:54:26 -0400 Subject: [PATCH] refactor focusing on xo-alloc2/ xo-gc/ write-barrier ability to inform allocator of gco->gco mutation, via AAllocator i/face. --- include/xo/alloc2/Allocator.hpp | 2 ++ include/xo/alloc2/Allocator_basic.hpp | 15 ++++++++ include/xo/alloc2/alloc/AAllocator.hpp | 27 +++++++++++++-- include/xo/alloc2/alloc/IAllocator_Any.hpp | 4 +++ include/xo/alloc2/alloc/IAllocator_Xfer.hpp | 4 +++ include/xo/alloc2/alloc/RAllocator.hpp | 21 ++++++++++-- include/xo/alloc2/alloc/RAllocator_aux.hpp | 34 +++++++++++++++++++ include/xo/alloc2/arena/IAllocator_DArena.hpp | 5 +++ include/xo/alloc2/gc/ACollector.hpp | 2 +- include/xo/alloc2/gc/AGCObject.hpp | 2 +- include/xo/alloc2/gc/ICollector_Xfer.hpp | 2 +- include/xo/alloc2/gc/IGCObject_Xfer.hpp | 2 +- include/xo/alloc2/gc/RCollector.hpp | 12 +++---- .../xo/alloc2/visitor/AResourceVisitor.hpp | 2 +- src/alloc2/IAllocator_DArena.cpp | 26 ++++++++++++++ utest/DArenaIterator.test.cpp | 3 +- utest/arena.test.cpp | 4 +-- 17 files changed, 149 insertions(+), 18 deletions(-) create mode 100644 include/xo/alloc2/Allocator_basic.hpp create mode 100644 include/xo/alloc2/alloc/RAllocator_aux.hpp diff --git a/include/xo/alloc2/Allocator.hpp b/include/xo/alloc2/Allocator.hpp index 63ffdb2e..096b7b8d 100644 --- a/include/xo/alloc2/Allocator.hpp +++ b/include/xo/alloc2/Allocator.hpp @@ -10,4 +10,6 @@ #include "alloc/IAllocator_Xfer.hpp" #include "alloc/RAllocator.hpp" +#include "alloc/RAllocator_aux.hpp" + /* end Allocator.hpp */ diff --git a/include/xo/alloc2/Allocator_basic.hpp b/include/xo/alloc2/Allocator_basic.hpp new file mode 100644 index 00000000..df998cd5 --- /dev/null +++ b/include/xo/alloc2/Allocator_basic.hpp @@ -0,0 +1,15 @@ +/** @file Allocator_basic.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include "alloc/AAllocator.hpp" +#include "alloc/IAllocator_Any.hpp" +#include "alloc/IAllocator_Xfer.hpp" +#include "alloc/RAllocator.hpp" + +//#include "alloc/RAllocator_aux.hpp" + +/* end Allocator_basic.hpp */ diff --git a/include/xo/alloc2/alloc/AAllocator.hpp b/include/xo/alloc2/alloc/AAllocator.hpp index 2fd71285..fdf57831 100644 --- a/include/xo/alloc2/alloc/AAllocator.hpp +++ b/include/xo/alloc2/alloc/AAllocator.hpp @@ -20,8 +20,8 @@ namespace xo { using Copaque = const void *; using Opaque = void *; - // see DArena.hpp - struct DArena; + class AGCObject; // see AGCObject.hpp + struct DArena; // see DArena.hpp /** @class AAllocator * @brief Abstract facet for allocation @@ -34,6 +34,7 @@ namespace xo { public: /** @defgroup mm-allocator-type-traits allocator type traits **/ ///@{ + using AGCObject = xo::mm::AGCObject; /** memory size report **/ using MemorySizeInfo = xo::mm::MemorySizeInfo; /** type used for allocation amounts **/ @@ -155,6 +156,28 @@ namespace xo { virtual value_type alloc_copy(Opaque d, value_type src) const = 0; /** reset allocator @p d to empty state. **/ virtual void clear(Opaque d) const = 0; + /** assign helper for allocator that may require a write barrier + * (for example Collector). Using obj here causes + * include cycle, use spelled out form instead; + * + * For: + * obj lhs_ = rhs + * with allocator d, that owns some allocaiton p, would use + * mm.barrier_assign_aux(d, p, + * lhs_.iface(), lhs_.opaque_data_addr(), + * rhs.iface(), rhs.opaque_data()); + * when lhs has known data type: + * DRepr * lhs_ = rhs.data(); + * use + * mm.barrier_assign_aux(d, p, + * nullptr, lhs_.opaque_data_addr(), + * rhs.iface(), rhs.opaque_data()); + * barrier needs to be able to construct complete fop for rhs + * to administrate write barrier. + **/ + virtual void barrier_assign_aux(Opaque d, void * parent, + AGCObject * lhs_iface, void ** lhs_data, + AGCObject * rhs_iface, void * rhs_data) const = 0; ///@} }; /*AAllocator*/ diff --git a/include/xo/alloc2/alloc/IAllocator_Any.hpp b/include/xo/alloc2/alloc/IAllocator_Any.hpp index fa8c14ab..0aafca45 100644 --- a/include/xo/alloc2/alloc/IAllocator_Any.hpp +++ b/include/xo/alloc2/alloc/IAllocator_Any.hpp @@ -60,6 +60,10 @@ namespace xo { [[noreturn]] value_type sub_alloc(Opaque, std::size_t, bool) const override { _fatal(); } [[noreturn]] value_type alloc_copy(Opaque, value_type) const override { _fatal(); } [[noreturn]] void clear(Opaque) const override { _fatal(); } + [[noreturn]] void barrier_assign_aux(Opaque, + void *, + AGCObject *, void **, + AGCObject *, void *) const override { _fatal(); } private: [[noreturn]] static void _fatal(); diff --git a/include/xo/alloc2/alloc/IAllocator_Xfer.hpp b/include/xo/alloc2/alloc/IAllocator_Xfer.hpp index e5b539a1..3343559b 100644 --- a/include/xo/alloc2/alloc/IAllocator_Xfer.hpp +++ b/include/xo/alloc2/alloc/IAllocator_Xfer.hpp @@ -78,6 +78,10 @@ namespace xo { value_type alloc_copy(Opaque d, value_type src) const override { return I::alloc_copy(_dcast(d), src); } void clear(Opaque d) const override { return I::clear(_dcast(d)); } + void barrier_assign_aux(Opaque d, + void * parent, + AGCObject * lhs_iface, void ** lhs_data, + AGCObject * rhs_iface, void * rhs_data) const override { I::barrier_assign_aux(_dcast(d), parent, lhs_iface, lhs_data, rhs_iface, rhs_data); } ///@} private: diff --git a/include/xo/alloc2/alloc/RAllocator.hpp b/include/xo/alloc2/alloc/RAllocator.hpp index 1d04d9cb..e9fa633c 100644 --- a/include/xo/alloc2/alloc/RAllocator.hpp +++ b/include/xo/alloc2/alloc/RAllocator.hpp @@ -5,7 +5,7 @@ #pragma once -#include "AAllocator.hpp" +#include "Allocator_basic.hpp" // omits RAllocator_aux #include "AllocIterator.hpp" #include #include @@ -66,13 +66,30 @@ namespace xo { AllocInfo alloc_info(value_type mem) const noexcept { return O::iface()->alloc_info(O::data(), mem); } range_type alloc_range(DArena & mm) const noexcept { return O::iface()->alloc_range(O::data(), mm); } + bool expand(size_type z) { return O::iface()->expand(O::data(), z); } value_type alloc(typeseq t, size_type z) noexcept { return O::iface()->alloc(O::data(), t, z); } value_type super_alloc(typeseq t, size_type z) noexcept { return O::iface()->super_alloc(O::data(), t, z); } value_type sub_alloc(size_type z, bool complete_flag) noexcept { return O::iface()->sub_alloc(O::data(), z, complete_flag); } value_type alloc_copy(value_type src) noexcept { return O::iface()->alloc_copy(O::data(), src); } - bool expand(size_type z) { return O::iface()->expand(O::data(), z); } + void clear() { O::iface()->clear(O::data()); } + void barrier_assign_aux(void * parent, + AGCObject * lhs_iface, void ** lhs_data, + AGCObject * rhs_iface, void * rhs_data) noexcept { O::iface()->barrier_assign_aux(O::data(), parent, + lhs_iface, lhs_data, + rhs_iface, rhs_data); } + + void barrier_assign(void * parent, + obj * p_lhs, + obj rhs) noexcept; +#ifdef NOT_YET + this->barrier_assign_aux(parent, + p_lhs->iface(), + p_lhs->opaque_data_addr(), + rhs.iface(), + rhs.opaque_data()); +#endif static bool _valid; }; diff --git a/include/xo/alloc2/alloc/RAllocator_aux.hpp b/include/xo/alloc2/alloc/RAllocator_aux.hpp new file mode 100644 index 00000000..2b296a90 --- /dev/null +++ b/include/xo/alloc2/alloc/RAllocator_aux.hpp @@ -0,0 +1,34 @@ +/** @file RAllocator_aux.hpp + * + * Out-of-line definitions for RAllocator template methods + * that depend on RGCObject (avoiding #include cycle in RAllocator.hpp) + * + * Would aspire to Include via user_hpp_includes in Allocator.json5, + * if/when that exists + * + * @author Roland Conybeare + **/ + +#pragma once + +#include "RAllocator.hpp" +#include "GCObject.hpp" + +namespace xo { + namespace mm { + + template + void + RAllocator::barrier_assign(void * parent, + obj * p_lhs, + obj rhs) noexcept + { + (void)parent; + (void)p_lhs; + (void)rhs; + } + + } /*namespace mm*/ +} /*namespace xo*/ + +/* end RAllocator_aux.hpp */ diff --git a/include/xo/alloc2/arena/IAllocator_DArena.hpp b/include/xo/alloc2/arena/IAllocator_DArena.hpp index 81e92211..0512cd57 100644 --- a/include/xo/alloc2/arena/IAllocator_DArena.hpp +++ b/include/xo/alloc2/arena/IAllocator_DArena.hpp @@ -75,6 +75,11 @@ namespace xo { /** allocate copy of @p src in arena @p d. **/ static value_type alloc_copy(DArena & d, value_type src); static void clear(DArena &); + /** perform assignment {*lhs_iface, *lhs_data} = {*rhs_iface, rhs_data} **/ + static void barrier_assign_aux(DArena &, + void * parent, + AGCObject * lhs_iface, void ** lhs_data, + AGCObject * rhs_iface, void * rhs_data); static void destruct_data(DArena &); }; diff --git a/include/xo/alloc2/gc/ACollector.hpp b/include/xo/alloc2/gc/ACollector.hpp index 2765c6b2..2daab3ca 100644 --- a/include/xo/alloc2/gc/ACollector.hpp +++ b/include/xo/alloc2/gc/ACollector.hpp @@ -14,7 +14,7 @@ #pragma once // includes (via {facet_includes}) -#include +#include #include #include #include diff --git a/include/xo/alloc2/gc/AGCObject.hpp b/include/xo/alloc2/gc/AGCObject.hpp index fbb5f613..dc6e79dd 100644 --- a/include/xo/alloc2/gc/AGCObject.hpp +++ b/include/xo/alloc2/gc/AGCObject.hpp @@ -14,7 +14,7 @@ #pragma once // includes (via {facet_includes}) -#include +#include #include #include #include diff --git a/include/xo/alloc2/gc/ICollector_Xfer.hpp b/include/xo/alloc2/gc/ICollector_Xfer.hpp index 50802f9d..77975287 100644 --- a/include/xo/alloc2/gc/ICollector_Xfer.hpp +++ b/include/xo/alloc2/gc/ICollector_Xfer.hpp @@ -13,7 +13,7 @@ #pragma once -#include +#include #include #include diff --git a/include/xo/alloc2/gc/IGCObject_Xfer.hpp b/include/xo/alloc2/gc/IGCObject_Xfer.hpp index c5a0a6b8..bceec9a2 100644 --- a/include/xo/alloc2/gc/IGCObject_Xfer.hpp +++ b/include/xo/alloc2/gc/IGCObject_Xfer.hpp @@ -13,7 +13,7 @@ #pragma once -#include +#include #include #include #include diff --git a/include/xo/alloc2/gc/RCollector.hpp b/include/xo/alloc2/gc/RCollector.hpp index 3f647159..b7c54d44 100644 --- a/include/xo/alloc2/gc/RCollector.hpp +++ b/include/xo/alloc2/gc/RCollector.hpp @@ -52,7 +52,7 @@ public: void * alloc_copy_for(const T * src) noexcept { return O::iface()->alloc_copy(O::data(), (std::byte *)const_cast(src)); } - + /** convenience template for move-constructible T (this is common) **/ template T * std_move_for(T * src) noexcept { @@ -62,28 +62,28 @@ public: } return nullptr; } - + /** forward faceted object pointer in place. Defined in GCObject.hpp to avoid #include cycle **/ template void forward_inplace(obj * p_obj); - + /** another convenience template for forwarding. * Defined in RGCObject.hpp to avoid #include cycle. **/ template void forward_inplace(DRepr ** pp_repr); - + /** convenience template where pointer requires pivot **/ template requires (!std::is_same_v) void forward_pivot_inplace(obj * p_obj); - + /** add root @p p_root **/ template void add_gc_root(obj * p_root) { O::iface()->add_gc_root_poly(O::data(), (obj *)p_root); } - + /** remove root @p p_root **/ template void remove_gc_root(obj * p_root) { diff --git a/include/xo/alloc2/visitor/AResourceVisitor.hpp b/include/xo/alloc2/visitor/AResourceVisitor.hpp index 64d9b136..16a9b0b4 100644 --- a/include/xo/alloc2/visitor/AResourceVisitor.hpp +++ b/include/xo/alloc2/visitor/AResourceVisitor.hpp @@ -14,7 +14,7 @@ #pragma once // includes (via {facet_includes}) -#include "Allocator.hpp" +#include "Allocator_basic.hpp" #include #include #include diff --git a/src/alloc2/IAllocator_DArena.cpp b/src/alloc2/IAllocator_DArena.cpp index bffbd38a..4d9a0a43 100644 --- a/src/alloc2/IAllocator_DArena.cpp +++ b/src/alloc2/IAllocator_DArena.cpp @@ -4,6 +4,7 @@ **/ #include "AllocIterator.hpp" +#include "GCObject.hpp" #include "arena/IAllocator_DArena.hpp" #include "arena/IAllocIterator_DArenaIterator.hpp" // for alloc_range #include @@ -154,6 +155,31 @@ namespace xo { //s.checkpoint_ = s.lo_; } + void + IAllocator_DArena::barrier_assign_aux(DArena & s, + void * parent, + AGCObject * lhs_iface, void ** lhs_data, + AGCObject * rhs_iface, void * rhs_data) + { + (void)s; + (void)parent; + + // usually would expect this to just forward to DArena. + // That's problematic in this case, because DArena is at lower level + // relative to obj; + // recall that DArena is used in the implementation of xo-facet/ + // + // In any case, for DArena no write barrier is applied. + // Instead just perform the fop assignment + + // replacing vtable pointer here + if (lhs_iface) { + ::memcpy((void *)lhs_iface, (void *)rhs_iface, sizeof(AGCObject)); + } + + *lhs_data = rhs_data; + } + void IAllocator_DArena::destruct_data(DArena & s) { diff --git a/utest/DArenaIterator.test.cpp b/utest/DArenaIterator.test.cpp index 7d26e623..2c7503c5 100644 --- a/utest/DArenaIterator.test.cpp +++ b/utest/DArenaIterator.test.cpp @@ -5,7 +5,8 @@ #include "Allocator.hpp" #include "AllocIterator.hpp" -#include "arena/IAllocator_DArena.hpp" +#include "Arena.hpp" +//#include "arena/IAllocator_DArena.hpp" #include "arena/IAllocIterator_DArenaIterator.hpp" #include "padding.hpp" #include diff --git a/utest/arena.test.cpp b/utest/arena.test.cpp index e9358a10..47ff4548 100644 --- a/utest/arena.test.cpp +++ b/utest/arena.test.cpp @@ -4,8 +4,8 @@ **/ #include "xo/alloc2/Allocator.hpp" -#include "xo/alloc2/alloc/IAllocator_Xfer.hpp" -#include "xo/alloc2/arena/IAllocator_DArena.hpp" +#include "xo/alloc2/Arena.hpp" +//#include "xo/alloc2/arena/IAllocator_DArena.hpp" #include "xo/arena/print.hpp" #include "xo/arena/padding.hpp" #include