From e0cb07c9f5fd6f33f573fc7a63fc64c3dec615a4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 3 Jan 2026 00:19:26 -0500 Subject: [PATCH] xo-gc: + execute_gc() scaffold --- xo-gc/include/xo/gc/DX1Collector.hpp | 27 +++++++++ xo-gc/include/xo/gc/detail/ACollector.hpp | 10 ++++ xo-gc/include/xo/gc/detail/ICollector_Any.hpp | 1 + .../xo/gc/detail/ICollector_DX1Collector.hpp | 1 + .../include/xo/gc/detail/ICollector_Xfer.hpp | 6 +- xo-gc/include/xo/gc/detail/RCollector.hpp | 2 +- xo-gc/src/gc/DX1Collector.cpp | 59 +++++++++++++++++++ xo-gc/src/gc/ICollector_DX1Collector.cpp | 11 ++-- xo-object2/utest/X1Collector.test.cpp | 1 + 9 files changed, 112 insertions(+), 6 deletions(-) diff --git a/xo-gc/include/xo/gc/DX1Collector.hpp b/xo-gc/include/xo/gc/DX1Collector.hpp index 9c7c69da..c14d96e0 100644 --- a/xo-gc/include/xo/gc/DX1Collector.hpp +++ b/xo-gc/include/xo/gc/DX1Collector.hpp @@ -221,6 +221,22 @@ namespace xo { **/ bool install_type(const AGCObject & meta) noexcept; + /** add GC root at @p root_addr, with type @p typeseq **/ + void add_gc_root(typeseq tseq, Opaque * root_addr) noexcept; + + /** Request immediate collection. + * 1. if collection is enabled, immediately collect all generations + * up to (but not including) g + * 2. may nevertheless escalate to older generations, + * depending on collector state. + * 3. if collection is currently disabled, + * collection will trigger the next time gc is enabled. + **/ + void request_gc(generation upto) noexcept; + + /** Execute gc immediately, for all generations < @p upto **/ + void execute_gc(generation upto) noexcept; + // ----- allocation ----- /** simple allocation. allocate @p z bytes of memory @@ -269,6 +285,12 @@ namespace xo { /** discard all allocated memory **/ void clear() noexcept; + private: + /** swap from- and to- roles for all generations < @p upto **/ + void swap_roles(generation upto) noexcept; + /** copy roots + everything reachable from them, to to-space **/ + void copy_roots(generation upto) noexcept; + public: /** garbage collector configuration **/ CollectorConfig config_; @@ -281,6 +303,11 @@ namespace xo { **/ DArena object_types_; + /** gc disabled whenever gc_blocked_ > 0 **/ + uint32_t gc_blocked_ = 0; + /** if > 0: need gc for all generations < gc_pending_upto_ **/ + generation gc_pending_upto_; + /** collector-managed memory here. * - space_[1] is from-space * - space_[0] is to-space diff --git a/xo-gc/include/xo/gc/detail/ACollector.hpp b/xo-gc/include/xo/gc/detail/ACollector.hpp index 69f10085..9c738a60 100644 --- a/xo-gc/include/xo/gc/detail/ACollector.hpp +++ b/xo-gc/include/xo/gc/detail/ACollector.hpp @@ -59,6 +59,16 @@ namespace xo { virtual bool install_type(Opaque d, const AGCObject & iface) = 0; virtual void add_gc_root(Opaque d, int32_t tseq, Opaque * root) = 0; + /** Request immediate collection. + * 1. if collection is enabled, immediately collect all generations + * up to (but not including) g + * 2. may nevertheless escalate to older generations, + * depending on collector state. + * 3. if collection is currently disabled, + * collection will trigger the next time gc is enabled. + **/ + virtual void request_gc(Opaque d, generation upto) = 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/xo-gc/include/xo/gc/detail/ICollector_Any.hpp b/xo-gc/include/xo/gc/detail/ICollector_Any.hpp index 3b0b10a0..76d46959 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_Any.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_Any.hpp @@ -39,6 +39,7 @@ namespace xo { // non-const methods [[noreturn]] bool install_type(Opaque, const AGCObject &) noexcept override { _fatal(); } [[noreturn]] void add_gc_root(Opaque, int32_t, Opaque *) override { _fatal(); } + [[noreturn]] void request_gc(Opaque, generation) override { _fatal(); } [[noreturn]] void forward_inplace(Opaque, AGCObject *, void **) override { _fatal(); } private: diff --git a/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp b/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp index 233eeba0..82330435 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp @@ -45,6 +45,7 @@ namespace xo { static bool install_type(DX1Collector & d, const AGCObject & iface); static void add_gc_root(DX1Collector & d, int32_t tseq, Opaque * root); + static void request_gc(DX1Collector & d, generation upto); static void forward_inplace(DX1Collector & d, AGCObject * lhs_iface, void ** lhs_data); static int32_t s_typeseq; diff --git a/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp b/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp index 352dc82f..00599bd5 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp @@ -53,7 +53,11 @@ namespace xo { void add_gc_root(Opaque d, int32_t tseq, Opaque * root) override { I::add_gc_root(_dcast(d), tseq, root); } - void forward_inplace(Opaque d, AGCObject * lhs_iface, void ** lhs_data) override { + void request_gc(Opaque d, generation upto) override { + I::request_gc(_dcast(d), upto); + } + void forward_inplace(Opaque d, + AGCObject * lhs_iface, void ** lhs_data) override { I::forward_inplace(_dcast(d), lhs_iface, lhs_data); } diff --git a/xo-gc/include/xo/gc/detail/RCollector.hpp b/xo-gc/include/xo/gc/detail/RCollector.hpp index bd28dc66..9af508d8 100644 --- a/xo-gc/include/xo/gc/detail/RCollector.hpp +++ b/xo-gc/include/xo/gc/detail/RCollector.hpp @@ -31,7 +31,7 @@ namespace xo { bool install_type(const AGCObject & iface) { return O::iface()->install_type(O::data(), iface); } void add_gc_root(int32_t tseq, Opaque * root) { O::iface()->add_gc_root(O::data(), tseq, root); } - + void request_gc(generation g) { O::iface()->request_gc(O::data(), g); } void forward_inplace(AGCObject * lhs_iface, void ** lhs_data) { O::iface()->forward_inplace(O::data(), lhs_iface, lhs_data); } static bool _valid; diff --git a/xo-gc/src/gc/DX1Collector.cpp b/xo-gc/src/gc/DX1Collector.cpp index d9e7e283..45da4f69 100644 --- a/xo-gc/src/gc/DX1Collector.cpp +++ b/xo-gc/src/gc/DX1Collector.cpp @@ -228,6 +228,65 @@ namespace xo { return true; } + void + DX1Collector::add_gc_root(typeseq tseq, + Opaque * root) noexcept + { + (void)tseq; + (void)root; + } + + void + DX1Collector::request_gc(generation upto) noexcept + { + if (gc_blocked_ > 0) { + if (gc_pending_upto_ < upto) { + this->gc_pending_upto_ = upto; + } + + /* intend collecting later */ + } else { + this->execute_gc(upto); + } + } + + void + DX1Collector::execute_gc(generation upto) noexcept + { + scope log(XO_DEBUG(true), xtag("upto", upto)); + + //auto t0 = std::chrono::steady_clock::now(); + + log && log("step 0a : [STUB] snapshot alloc state"); + + log && log("step 0b : [STUB] scan for object statistics"); + + log && log("step 1 : swap from/to roles"); + this->swap_roles(upto); + + log && log("step 2a : copy roots"); + this->copy_roots(upto); + + log && log("step 2b : [STUB] copy pinned"); + log && log("step 3a : [STUB] run destructors"); + log && log("step 3b : [STUB] keep reachable weak pointers"); + log && log("step 4 : [STUB] cleanup"); + } + + void + DX1Collector::swap_roles(generation upto) noexcept + { + for (generation g = generation{0}; g < upto; ++g) { + std::swap(space_[role::to_space()][g], space_[role::from_space()][g]); + } + } + + void + DX1Collector::copy_roots(generation upto) noexcept + { + scope log(XO_DEBUG(true), "STUB", xtag("upto", upto)); + } + auto DX1Collector::alloc(typeseq t, size_type z) noexcept -> value_type { diff --git a/xo-gc/src/gc/ICollector_DX1Collector.cpp b/xo-gc/src/gc/ICollector_DX1Collector.cpp index 82e5e937..2f049046 100644 --- a/xo-gc/src/gc/ICollector_DX1Collector.cpp +++ b/xo-gc/src/gc/ICollector_DX1Collector.cpp @@ -65,11 +65,14 @@ namespace xo { int32_t tseq, Opaque * root) { - (void)d; - (void)tseq; - (void)root; + d.add_gc_root(typeseq(tseq), root); + } - assert(false); + void + ICollector_DX1Collector::request_gc(DX1Collector & d, + generation upto) + { + d.request_gc(upto); } void diff --git a/xo-object2/utest/X1Collector.test.cpp b/xo-object2/utest/X1Collector.test.cpp index 2afe158d..720711a9 100644 --- a/xo-object2/utest/X1Collector.test.cpp +++ b/xo-object2/utest/X1Collector.test.cpp @@ -194,6 +194,7 @@ namespace ut { } /* no GC roots, so GC is trivial */ + c_o.request_gc(generation{1}); } catch (std::exception & ex) { std::cerr << "caught exception: " << ex.what() << std::endl; REQUIRE(false);