diff --git a/xo-gc/CMakeLists.txt b/xo-gc/CMakeLists.txt index aa0df8ef..7a74f5c7 100644 --- a/xo-gc/CMakeLists.txt +++ b/xo-gc/CMakeLists.txt @@ -27,9 +27,9 @@ xo_add_genfacetimpl( # note: manual target; generated code committed to git xo_add_genfacetimpl( - TARGET xo-gc-facetimpl-gcobjectvisitor-x1collector + TARGET xo-gc-facetimpl-gcobjectvisitor-gcobjectstorevisitor FACET_PKG xo_alloc2 - INPUT idl/IGCObjectVisitor_DX1Collector.json5 + INPUT idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5 ) # ---------------------------------------------------------------- diff --git a/xo-gc/idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5 b/xo-gc/idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5 new file mode 100644 index 00000000..d393ba47 --- /dev/null +++ b/xo-gc/idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5 @@ -0,0 +1,28 @@ +{ + mode: "implementation", + output_cpp_dir: "src/gc/facet", + output_hpp_dir: "include/xo/gc", + output_impl_subdir: "detail", + includes: [ +// "", +// "" + ], + local_types: [ +// { +// name: "typeseq", +// doc: ["identifies a c++ type"], +// definition: "xo::reflect::typeseq" +// }, + ], + namespace1: "xo", + namespace2: "mm", + facet_idl: "idl/GCObjectVisitor.json5", + brief: "provide AGCObjectVisitor interface for DGCObjectStoreVisitor", + using_doxygen: true, + repr: "DGCObjectStoreVisitor", + doc: [ + "Implement AGCObjectVisitor for DGCObjectStoreVisitor.", + "Visit a gc-aware object. Either evacuate+forward (for gc cycle),", + "or check consistency (for verify_ok)", + ], +} diff --git a/xo-gc/include/xo/gc/DGCObjectStoreVisitor.hpp b/xo-gc/include/xo/gc/DGCObjectStoreVisitor.hpp new file mode 100644 index 00000000..7ba65dad --- /dev/null +++ b/xo-gc/include/xo/gc/DGCObjectStoreVisitor.hpp @@ -0,0 +1,49 @@ +/** @file DGCObjectStoreVisitor.hpp + * + * @author Roland Conybeare, Apr 2026 + **/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace xo { + namespace mm { + + class GCObjectStore; // see GCObjectStore.hpp + class AGCObject; // see AGCObject.hpp + + /** @brief visitor shim for GCObjectStore + * + * For a GC cycle, remembers which generations + * are being collected + **/ + class DGCObjectStoreVisitor { + public: + DGCObjectStoreVisitor(GCObjectStore * gcos, Generation upto); + + template + obj ref() { return obj(this); } + + Generation generation_of(Role r, const void * addr) const noexcept; + AllocInfo alloc_info(void * mem) const noexcept; + + void visit_child(VisitReason reason, AGCObject * lhs_iface, void ** lhs_data); + std::byte * alloc_copy(void * src) noexcept; + + private: + /** object storage **/ + GCObjectStore * p_gco_store_ = nullptr; + /** collecting generations up to this bound **/ + Generation upto_; + }; + + } /*namespace mm*/ +} /*namespace xo*/ + +/* end DGCObjectVisitor.hpp */ diff --git a/xo-gc/include/xo/gc/GCObjectStore.hpp b/xo-gc/include/xo/gc/GCObjectStore.hpp index ba925f9b..76b15977 100644 --- a/xo-gc/include/xo/gc/GCObjectStore.hpp +++ b/xo-gc/include/xo/gc/GCObjectStore.hpp @@ -134,7 +134,7 @@ namespace xo { * to call AGCObject visitor method (forward_children()) on each * object stored here. **/ - void verify_ok(obj gc) noexcept; + void verify_ok() noexcept; /** Register object type with this collector. * Provides shallow copy and pointer forwarding for instances of this @@ -156,8 +156,7 @@ namespace xo { * * Require: runstate_.is_running() **/ - void * deep_move_root(obj gc, - const AGCObject * root_iface, + void * deep_move_root(const AGCObject * root_iface, void ** root_data, Generation upto); @@ -170,15 +169,16 @@ namespace xo { void * from_src, Generation upto); -#ifdef NOT_YET /** Target for GCObjectVisitor facet * During gc phase (@p reason is 'forward') * 1. evacuate object at @p *lhs_data to to-space. * 2. replace @p *lhs_data with forwarding pointer * to new location. **/ - void visit_child(VisitReason reason, AGCObject * lhs_iface, void ** lhs_data); -#endif + void visit_child_aux(VisitReason reason, + AGCObject * lhs_iface, + void ** lhs_data, + Generation upto); /** Evacuate object at @p *lhs_data to to-space, during collection phase * acting on generations g in [0 ,.., upto). diff --git a/xo-gc/include/xo/gc/GCObjectStoreVisitor.hpp b/xo-gc/include/xo/gc/GCObjectStoreVisitor.hpp new file mode 100644 index 00000000..37fa95b4 --- /dev/null +++ b/xo-gc/include/xo/gc/GCObjectStoreVisitor.hpp @@ -0,0 +1,11 @@ +/** @file GCObjectStoreVisitor.hpp +* + * @author Roland Conybeare, Apr 2026 + **/ + +#pragma once + +#include "DGCObjectStoreVisitor.hpp" +#include "detail/IGCObjectVisitor_DGCObjectStoreVisitor.hpp" + +/* end GCObjectStoreVisitor.hpp */ diff --git a/xo-gc/include/xo/gc/X1Collector.hpp b/xo-gc/include/xo/gc/X1Collector.hpp index c35f5251..38999844 100644 --- a/xo-gc/include/xo/gc/X1Collector.hpp +++ b/xo-gc/include/xo/gc/X1Collector.hpp @@ -8,6 +8,5 @@ #include "DX1Collector.hpp" #include "detail/ICollector_DX1Collector.hpp" #include "detail/IAllocator_DX1Collector.hpp" -#include "detail/IGCObjectVisitor_DX1Collector.hpp" /* end X1Collector.hpp */ diff --git a/xo-gc/include/xo/gc/detail/IGCObjectVisitor_DX1Collector.hpp b/xo-gc/include/xo/gc/detail/IGCObjectVisitor_DGCObjectStoreVisitor.hpp similarity index 53% rename from xo-gc/include/xo/gc/detail/IGCObjectVisitor_DX1Collector.hpp rename to xo-gc/include/xo/gc/detail/IGCObjectVisitor_DGCObjectStoreVisitor.hpp index 5c18c8eb..de14f5b0 100644 --- a/xo-gc/include/xo/gc/detail/IGCObjectVisitor_DX1Collector.hpp +++ b/xo-gc/include/xo/gc/detail/IGCObjectVisitor_DGCObjectStoreVisitor.hpp @@ -1,64 +1,64 @@ -/** @file IGCObjectVisitor_DX1Collector.hpp +/** @file IGCObjectVisitor_DGCObjectStoreVisitor.hpp * * Generated automagically from ingredients: * 1. code generator: * [xo-facet/codegen/genfacet] * arguments: - * --input [idl/IGCObjectVisitor_DX1Collector.json5] + * --input [idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5] * 2. jinja2 template for abstract facet .hpp file: * [iface_facet_repr.hpp.j2] * 3. idl for facet methods - * [idl/IGCObjectVisitor_DX1Collector.json5] + * [idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5] **/ #pragma once #include "GCObjectVisitor.hpp" -#include "DX1Collector.hpp" +#include "DGCObjectStoreVisitor.hpp" -namespace xo { namespace mm { class IGCObjectVisitor_DX1Collector; } } +namespace xo { namespace mm { class IGCObjectVisitor_DGCObjectStoreVisitor; } } namespace xo { namespace facet { template <> struct FacetImplementation + xo::mm::DGCObjectStoreVisitor> { using ImplType = xo::mm::IGCObjectVisitor_Xfer - ; + ; }; } } namespace xo { namespace mm { - /** @class IGCObjectVisitor_DX1Collector + /** @class IGCObjectVisitor_DGCObjectStoreVisitor **/ - class IGCObjectVisitor_DX1Collector { + class IGCObjectVisitor_DGCObjectStoreVisitor { public: - /** @defgroup mm-gcobjectvisitor-dx1collector-type-traits **/ + /** @defgroup mm-gcobjectvisitor-dgcobjectstorevisitor-type-traits **/ ///@{ using Copaque = xo::mm::AGCObjectVisitor::Copaque; using Opaque = xo::mm::AGCObjectVisitor::Opaque; ///@} - /** @defgroup mm-gcobjectvisitor-dx1collector-methods **/ + /** @defgroup mm-gcobjectvisitor-dgcobjectstorevisitor-methods **/ ///@{ // const methods /** allocation metadata for gc-aware data at address @p gco. @p gco must be the result of a call to collector's alloc() function **/ - static AllocInfo alloc_info(const DX1Collector & self, void * addr); + static AllocInfo alloc_info(const DGCObjectStoreVisitor & self, void * addr); /** generation to which pointer @p addr belongs, given role @p r; sentinel if @p addr is not owned by collector **/ - static Generation generation_of(const DX1Collector & self, Role r, const void * addr) noexcept; + static Generation generation_of(const DGCObjectStoreVisitor & self, Role r, const void * addr) noexcept; // non-const methods /** allocate copy of source object at address @p src. Source must be owned by this collector. Increments object age **/ - static void * alloc_copy(DX1Collector & self, std::byte * src); + static void * alloc_copy(DGCObjectStoreVisitor & self, std::byte * src); /** visit child of a gc-aware object. May update child in-place! **/ - static void visit_child(DX1Collector & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept; + static void visit_child(DGCObjectStoreVisitor & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept; ///@} }; diff --git a/xo-gc/src/gc/CMakeLists.txt b/xo-gc/src/gc/CMakeLists.txt index 7cbce173..0dcfa2e3 100644 --- a/xo-gc/src/gc/CMakeLists.txt +++ b/xo-gc/src/gc/CMakeLists.txt @@ -12,10 +12,12 @@ set(SELF_SRCS X1CollectorConfig.cpp DX1Collector.cpp facet/ICollector_DX1Collector.cpp - facet/IGCObjectVisitor_DX1Collector.cpp DX1CollectorIterator.cpp + DGCObjectStoreVisitor.cpp + facet/IGCObjectVisitor_DGCObjectStoreVisitor.cpp + GCObjectStoreConfig.cpp GCObjectStore.cpp diff --git a/xo-gc/utest/DMockCollector.cpp b/xo-gc/src/gc/DGCObjectStoreVisitor.cpp similarity index 56% rename from xo-gc/utest/DMockCollector.cpp rename to xo-gc/src/gc/DGCObjectStoreVisitor.cpp index 833d32b2..9c2618d2 100644 --- a/xo-gc/utest/DMockCollector.cpp +++ b/xo-gc/src/gc/DGCObjectStoreVisitor.cpp @@ -1,27 +1,34 @@ -/** @file DMockCollector.cpp +/** @file DGCObjectStoreVisitor.cpp * * @author Roland Conybeare, Apr 2026 **/ -#include "MockCollector.hpp" +#include "GCObjectStoreVisitor.hpp" +#include "GCObjectStore.hpp" namespace xo { namespace mm { + DGCObjectStoreVisitor::DGCObjectStoreVisitor(GCObjectStore * gcos, + Generation upto) + : p_gco_store_{gcos}, upto_{upto} + {} + Generation - DMockCollector::generation_of(Role r, const void * addr) const noexcept + DGCObjectStoreVisitor::generation_of(Role r, const void * addr) const noexcept { return p_gco_store_->generation_of(r, addr); } AllocInfo - DMockCollector::alloc_info(void * mem) const noexcept + DGCObjectStoreVisitor::alloc_info(void * mem) const noexcept { return p_gco_store_->alloc_info((std::byte *)mem); } void - DMockCollector::visit_child(VisitReason reason, AGCObject * lhs_iface, void ** lhs_data) + DGCObjectStoreVisitor::visit_child(VisitReason reason, + AGCObject * lhs_iface, void ** lhs_data) { switch (reason.code()) { case VisitReason::code::forward: @@ -37,11 +44,11 @@ namespace xo { } std::byte * - DMockCollector::alloc_copy(void * src) noexcept { + DGCObjectStoreVisitor::alloc_copy(void * src) noexcept { return p_gco_store_->new_space()->alloc_copy((std::byte *)src); } } /*namespace mm*/ } /*namespace xo*/ -/* end DMockCollector.cpp */ +/* end DGCObjectVisitor.cpp */ diff --git a/xo-gc/src/gc/DX1Collector.cpp b/xo-gc/src/gc/DX1Collector.cpp index cf079781..d8f4021f 100644 --- a/xo-gc/src/gc/DX1Collector.cpp +++ b/xo-gc/src/gc/DX1Collector.cpp @@ -4,6 +4,7 @@ **/ #include "X1Collector.hpp" +#include "GCObjectStoreVisitor.hpp" #include #include @@ -13,7 +14,6 @@ #include #include -#include #include #include #include "object_age.hpp" @@ -383,7 +383,8 @@ namespace xo { // Add run state so DX1Collector can recognize forward_inplace() // calls made for the purpose of checking child pointers. - auto self = this->ref(); + DGCObjectStoreVisitor visitor(&gco_store_, + Generation{0} /*not used for verify*/); GCRunState saved_runstate = runstate_; { @@ -404,8 +405,7 @@ namespace xo { // - X1Collector::forward_inplace() -> _verify_aux() // - gco.visit_gco_children(VisitReason::verify(), self); - + gco.visit_gco_children(VisitReason::verify(), visitor.ref()); } X1VerifyStats post = verify_stats_; @@ -417,7 +417,7 @@ namespace xo { } // 3. scan to-space for each generation - gco_store_.verify_ok(this->ref()); + gco_store_.verify_ok(); // 4. scan mutation logs mlog_store_.verify_ok(&gco_store_, @@ -483,7 +483,7 @@ namespace xo { //auto t0 = std::chrono::steady_clock::now(); log && log("memory"); - auto visitor = [&log](const MemorySizeInfo & info) { + auto resource_visitor = [&log](const MemorySizeInfo & info) { log && log(xtag("resource", info.resource_name_), xtag("used", info.used_), xtag("alloc", info.allocated_), @@ -492,7 +492,7 @@ namespace xo { xtag("lo", info.lo_), xtag("hi", info.hi_)); }; - this->visit_pools(visitor); + this->visit_pools(resource_visitor); if (config_.sanitize_flag_) { log && log("step 0a : verify"); @@ -500,6 +500,8 @@ namespace xo { } + DGCObjectStoreVisitor gco_visitor(&gco_store_, upto); + log && log("step 0b : update run state"); this->runstate_ = GCRunState::gc_upto(upto); @@ -519,7 +521,7 @@ namespace xo { log && log("step 2b : [STUB] copy pinned"); log && log("step 3 : [STUB] forward mutation log"); - mlog_store_.forward_mutation_log(this->ref(), upto); + mlog_store_.forward_mutation_log(gco_visitor.ref(), upto); log && log("step 4a : [STUB] run destructors"); log && log("step 4b : [STUB] keep reachable weak pointers"); @@ -576,8 +578,7 @@ namespace xo { xtag("slot.root()", slot.root()), xtag("slot.root()->data_", slot.root()->data_)); - void * root_to = gco_store_.deep_move_root(this->ref(), - slot.root()->iface(), + void * root_to = gco_store_.deep_move_root(slot.root()->iface(), (void **)&(slot.root()->data_), upto); slot.root()->reset_opaque(root_to); @@ -594,24 +595,9 @@ namespace xo { // MAYBE: adapter distinct from DX1Collector that supports GCObjectVisitor facet, // calls DX1Collector::_verify_aux() - switch (reason.code()) { - case VisitReason::code::forward: - { - Generation upto = runstate_.gc_upto(); + Generation upto = runstate_.gc_upto(); - // called during collection phase - gco_store_.forward_inplace_aux - (this->ref(), lhs_iface, lhs_data, upto); - break; - } - case VisitReason::code::verify: - // called during verify_ok - gco_store_.verify_aux(lhs_iface, *lhs_data); - break; - default: - // should be unreachable - assert(false); - } + gco_store_.visit_child_aux(reason, lhs_iface, lhs_data, upto); } auto diff --git a/xo-gc/src/gc/GCObjectStore.cpp b/xo-gc/src/gc/GCObjectStore.cpp index b76801d2..18188a4c 100644 --- a/xo-gc/src/gc/GCObjectStore.cpp +++ b/xo-gc/src/gc/GCObjectStore.cpp @@ -4,6 +4,7 @@ **/ #include "GCObjectStore.hpp" +#include "GCObjectStoreVisitor.hpp" #include "X1VerifyStats.hpp" #include @@ -475,35 +476,33 @@ namespace xo { return (g < upto); } -#ifdef NOT_YET void - GCObjectStore::visit_child(VisitReason reason, - AGCObject * lhs_iface, - void ** lhs_data) + GCObjectStore::visit_child_aux(VisitReason reason, + AGCObject * lhs_iface, + void ** lhs_data, + Generation upto) { - // MAYBE: adapter distinct from DX1Collector that supports GCObjectVisitor facet, - // calls DX1Collector::_verify_aux() - switch (reason.code()) { case VisitReason::code::forward: { - Generation upto = runstate_.gc_upto(); + DGCObjectStoreVisitor gcos_visitor(this, upto); + auto gcos_visitor_obj + = obj(&gcos_visitor); // called during collection phase this->forward_inplace_aux - (this->ref(), lhs_iface, lhs_data, upto); + (gcos_visitor_obj, lhs_iface, lhs_data, upto); break; } case VisitReason::code::verify: // called during verify_ok - gco_store_.verify_aux(lhs_iface, *lhs_data); + this->verify_aux(lhs_iface, *lhs_data); break; default: // should be unreachable assert(false); } } -#endif void GCObjectStore::forward_inplace_aux(obj gc, @@ -768,8 +767,11 @@ namespace xo { } void - GCObjectStore::verify_ok(obj gc) noexcept + GCObjectStore::verify_ok() noexcept { + Generation unused_gen; + DGCObjectStoreVisitor visitor{this, unused_gen}; + for (Generation g(0); g < config_.n_generation_; ++g) { const DArena * space = this->get_space(Role::to_space(), g); @@ -789,7 +791,7 @@ namespace xo { // assembled fop for gc-aware object obj gco(iface, const_cast(data)); - gco.visit_gco_children(VisitReason::verify(), gc); + gco.visit_gco_children(VisitReason::verify(), visitor.ref()); } else { ++(p_verify_stats_->n_no_iface_); continue; @@ -830,8 +832,7 @@ namespace xo { } void * - GCObjectStore::deep_move_root(obj gc, - const AGCObject * root_iface, + GCObjectStore::deep_move_root(const AGCObject * root_iface, void ** root_data, Generation upto) { @@ -849,8 +850,10 @@ namespace xo { bool src_in_from_space = this->contains(Role::from_space(), *root_data); + DGCObjectStoreVisitor visitor(this, upto); + if (src_in_from_space) { - *root_data = this->_deep_move_gc_owned(gc, *root_data, upto); + *root_data = this->_deep_move_gc_owned(visitor.ref(), *root_data, upto); } else { // we aren't moving from_src, it's not gc-owned. // However we are moving all its gc-owned children @@ -860,7 +863,7 @@ namespace xo { auto root = obj(root_iface, *root_data); - root.visit_gco_children(VisitReason::forward(), gc); + root.visit_gco_children(VisitReason::forward(), visitor.ref()); // For each generation g: // traverse objects newer than gray_lo_v[g], to make sure children @@ -868,7 +871,7 @@ namespace xo { // Remember that forwarding may promote objects to older generation, // so need multiple passes // - this->_forward_children_until_fixpoint(gc, upto, gray_lo_v); + this->_forward_children_until_fixpoint(visitor.ref(), upto, gray_lo_v); // reminder: *root_data preserved diff --git a/xo-gc/src/gc/SetupGc.cpp b/xo-gc/src/gc/SetupGc.cpp index fa0ea721..dc5fad04 100644 --- a/xo-gc/src/gc/SetupGc.cpp +++ b/xo-gc/src/gc/SetupGc.cpp @@ -5,6 +5,7 @@ #include "SetupGc.hpp" #include "X1Collector.hpp" +#include "GCObjectStoreVisitor.hpp" #include #include @@ -24,9 +25,11 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); - FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); log && log(xtag("DX1Collector.tseq", typeseq::id())); + log && log(xtag("DGCObjectStoreVisitor.tseq", typeseq::id())); log && log(xtag("ACollector.tseq", typeseq::id())); log && log(xtag("AGCObjectVisitor.tseq", typeseq::id())); diff --git a/xo-gc/src/gc/facet/IGCObjectVisitor_DGCObjectStoreVisitor.cpp b/xo-gc/src/gc/facet/IGCObjectVisitor_DGCObjectStoreVisitor.cpp new file mode 100644 index 00000000..b0306f3a --- /dev/null +++ b/xo-gc/src/gc/facet/IGCObjectVisitor_DGCObjectStoreVisitor.cpp @@ -0,0 +1,44 @@ +/** @file IGCObjectVisitor_DGCObjectStoreVisitor.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5] +**/ + +#include "detail/IGCObjectVisitor_DGCObjectStoreVisitor.hpp" + +namespace xo { + namespace mm { + auto + IGCObjectVisitor_DGCObjectStoreVisitor::alloc_info(const DGCObjectStoreVisitor & self, void * addr) -> AllocInfo + { + return self.alloc_info(addr); + } + + auto + IGCObjectVisitor_DGCObjectStoreVisitor::generation_of(const DGCObjectStoreVisitor & self, Role r, const void * addr) noexcept -> Generation + { + return self.generation_of(r, addr); + } + + auto + IGCObjectVisitor_DGCObjectStoreVisitor::alloc_copy(DGCObjectStoreVisitor & self, std::byte * src) -> void * + { + return self.alloc_copy(src); + } + auto + IGCObjectVisitor_DGCObjectStoreVisitor::visit_child(DGCObjectStoreVisitor & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept -> void + { + self.visit_child(reason, iface, pp_data); + } + + } /*namespace mm*/ +} /*namespace xo*/ + +/* end IGCObjectVisitor_DGCObjectStoreVisitor.cpp */ diff --git a/xo-gc/src/gc/facet/IGCObjectVisitor_DX1Collector.cpp b/xo-gc/src/gc/facet/IGCObjectVisitor_DX1Collector.cpp deleted file mode 100644 index 17f364ed..00000000 --- a/xo-gc/src/gc/facet/IGCObjectVisitor_DX1Collector.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** @file IGCObjectVisitor_DX1Collector.cpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/IGCObjectVisitor_DX1Collector.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/IGCObjectVisitor_DX1Collector.json5] -**/ - -#include "detail/IGCObjectVisitor_DX1Collector.hpp" - -namespace xo { - namespace mm { - auto - IGCObjectVisitor_DX1Collector::alloc_info(const DX1Collector & self, void * addr) -> AllocInfo - { - return self.alloc_info(addr); - } - - auto - IGCObjectVisitor_DX1Collector::generation_of(const DX1Collector & self, Role r, const void * addr) noexcept -> Generation - { - return self.generation_of(r, addr); - } - - auto - IGCObjectVisitor_DX1Collector::alloc_copy(DX1Collector & self, std::byte * src) -> void * - { - return self.alloc_copy(src); - } - auto - IGCObjectVisitor_DX1Collector::visit_child(DX1Collector & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept -> void - { - self.visit_child(reason, iface, pp_data); - } - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end IGCObjectVisitor_DX1Collector.cpp */ diff --git a/xo-gc/utest/CMakeLists.txt b/xo-gc/utest/CMakeLists.txt index 599e1ea1..8f9b9503 100644 --- a/xo-gc/utest/CMakeLists.txt +++ b/xo-gc/utest/CMakeLists.txt @@ -10,20 +10,10 @@ set(UTEST_SRCS GCObjectStore.test.cpp Object2.test.cpp - DMockCollector.cpp - IGCObjectVisitor_DMockCollector.cpp - init_gc_utest.cpp random_allocs.cpp ) -# mock collector for unit test -xo_add_genfacetimpl( - TARGET xo-gc-facetimpl-gcobjectvisitor-mockcollector - FACET_PKG xo_alloc2 - INPUT idl/IGCObjectVisitor_DMockCollector.json5 -) - if (ENABLE_TESTING) xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) xo_headeronly_dependency(${UTEST_EXE} randomgen) diff --git a/xo-gc/utest/DMockCollector.hpp b/xo-gc/utest/DMockCollector.hpp deleted file mode 100644 index 3297f8fa..00000000 --- a/xo-gc/utest/DMockCollector.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/** @file DMockCollector.hpp - * - * @author Roland Conybeare, Apr 2026 - **/ - -#pragma once - -#include -#include - -namespace xo { - namespace mm { - - /** @brief Mock Collector - * - * Intended to help unit test a GCObjectSotre instance. - * Mock a Collector in collection phase for generations 0 <= g < @ref upto_. - **/ - class DMockCollector { - public: - explicit DMockCollector(GCObjectStore * gcos, Generation upto) : p_gco_store_{gcos}, upto_{upto} {} - - template - obj ref() { return obj(this); } - - Generation generation_of(Role r, const void * addr) const noexcept; - AllocInfo alloc_info(void * mem) const noexcept; - - void visit_child(VisitReason reason, AGCObject * lhs_iface, void ** lhs_data); - std::byte * alloc_copy(void * src) noexcept; - - private: - GCObjectStore * p_gco_store_ = nullptr; - Generation upto_; - }; - - } /*namespace mm*/ -} /*namespaace xo*/ - -/* end DMockCollector.hpp */ diff --git a/xo-gc/utest/GCObjectStore.test.cpp b/xo-gc/utest/GCObjectStore.test.cpp index d258dba2..8e1ae05c 100644 --- a/xo-gc/utest/GCObjectStore.test.cpp +++ b/xo-gc/utest/GCObjectStore.test.cpp @@ -5,8 +5,6 @@ #include #include -#include "MockCollector.hpp" - #include #include #include @@ -27,7 +25,6 @@ namespace ut { using xo::scm::DList; using xo::scm::DInteger; using xo::scm::DBoolean; - using xo::mm::DMockCollector; using xo::mm::GCObjectStoreConfig; using xo::mm::GCObjectStore; using xo::mm::X1VerifyStats; @@ -395,7 +392,6 @@ namespace ut { const GCObjectStore & gcos) { Generation g0{0}; - //Generation g1{1}; Generation gn{tc.n_gen_}; @@ -413,6 +409,13 @@ namespace ut { } } + /** Generate two copies of a random object graph for test case @p tc. + * Store first graph in @p *p_x1_v, allocating + * entirely from @p p_gcos new-space. + * Store second graph in @p *p_x2_v, allocating + * entirely from @p p_arena2. + * Use random number generator @p_rgen + **/ void gcos_construct_ab_object_graphs(const Testcase & tc, GCObjectStore * p_gcos, @@ -444,24 +447,26 @@ namespace ut { // typeseq::id())); } + /** Invoke built-in consistency verification for @p *p_gcos. + **/ void - gcos_verify_consistency(obj mock_gc_visitor, - GCObjectStore * p_gcos, - const X1VerifyStats & verify_stats) + gcos_verify_consistency(GCObjectStore * p_gcos) { // traverses stored objects, updates counters // in verify_stats (= gco.p_verify_stats_, via ctor) // - p_gcos->verify_ok(mock_gc_visitor); + p_gcos->verify_ok(); - INFO(tostr(xtag("n_gc_root", verify_stats.n_gc_root_), - xtag("n_ext", verify_stats.n_ext_), - xtag("n_from", verify_stats.n_from_), - xtag("n_to", verify_stats.n_to_), - xtag("n_fwd", verify_stats.n_fwd_), - xtag("n_no_iface", verify_stats.n_no_iface_))); + X1VerifyStats * verify_stats = p_gcos->verify_stats(); - REQUIRE(verify_stats.is_ok()); + INFO(tostr(xtag("n_gc_root", verify_stats->n_gc_root_), + xtag("n_ext", verify_stats->n_ext_), + xtag("n_from", verify_stats->n_from_), + xtag("n_to", verify_stats->n_to_), + xtag("n_fwd", verify_stats->n_fwd_), + xtag("n_no_iface", verify_stats->n_no_iface_))); + + REQUIRE(verify_stats->is_ok()); } void @@ -635,7 +640,7 @@ namespace ut { void gcos_move_roots_and_verify(const Testcase & tc, GCObjectStore * p_gcos, - obj mock_gc_visitor, + Generation upto, const std::vector & x1_v, const std::vector & x2_v, bool debug_flag) @@ -690,9 +695,9 @@ namespace ut { obj x1_gco = x1.gco_; // modifies x1.gco_ in place - auto x1p_data = p_gcos->deep_move_root(mock_gc_visitor, - x1p_iface, (void **)&(x1.gco_.data_), - g1); + auto x1p_data + = p_gcos->deep_move_root(x1p_iface, (void **)&(x1.gco_.data_), upto); + REQUIRE(x1p_data); REQUIRE(x1p_data == x1.gco_.data_); @@ -713,8 +718,7 @@ namespace ut { // but will fail since type isn't registered auto x1p_data - = p_gcos->deep_move_root(mock_gc_visitor, - x1.gco_.iface(), + = p_gcos->deep_move_root(x1.gco_.iface(), (void **)&(x1.gco_.data_), g1); @@ -812,10 +816,6 @@ namespace ut { Generation g1{1}; Generation gn{tc.n_gen_}; - // scaffold mock collector doing incremental collection - DMockCollector mock_gc(&gcos, g1); - auto mock_gc_visitor = mock_gc.ref(); - REQUIRE(gcos.is_type_installed(typeseq::id()) == false); REQUIRE(gcos.is_type_installed(typeseq::id()) == false); @@ -836,9 +836,7 @@ namespace ut { log1 && log1("verify before any gcos side effects"); - gcos_verify_consistency(mock_gc_visitor, - &gcos, - verify_stats); + gcos_verify_consistency(&gcos); // someday: print the graph. Need a cycle-detecting printer @@ -851,7 +849,7 @@ namespace ut { gcos_verify_gen0_fromspace_only_allocated(tc, gcos, x1_v); - gcos_move_roots_and_verify(tc, &gcos, mock_gc_visitor, x1_v, x2_v, tc.debug_flag_); + gcos_move_roots_and_verify(tc, &gcos, g1, x1_v, x2_v, tc.debug_flag_); // Things to test: // - deep_move_interior() // used from MutationLogStore @@ -870,7 +868,7 @@ namespace ut { // traverses stored objects, updates counters // in verify_stats (= gco.p_verify_stats_, via ctor) // - gcos.verify_ok(mock_gc_visitor); + gcos.verify_ok(); INFO(tostr(xtag("n_gc_root", verify_stats.n_gc_root_), xtag("n_ext", verify_stats.n_ext_), diff --git a/xo-gc/utest/IGCObjectVisitor_DMockCollector.cpp b/xo-gc/utest/IGCObjectVisitor_DMockCollector.cpp deleted file mode 100644 index 34a0c155..00000000 --- a/xo-gc/utest/IGCObjectVisitor_DMockCollector.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** @file IGCObjectVisitor_DMockCollector.cpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/IGCObjectVisitor_DMockCollector.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/IGCObjectVisitor_DMockCollector.json5] -**/ - -#include "./IGCObjectVisitor_DMockCollector.hpp" - -namespace xo { - namespace mm { - auto - IGCObjectVisitor_DMockCollector::alloc_info(const DMockCollector & self, void * addr) -> AllocInfo - { - return self.alloc_info(addr); - } - - auto - IGCObjectVisitor_DMockCollector::generation_of(const DMockCollector & self, Role r, const void * addr) noexcept -> Generation - { - return self.generation_of(r, addr); - } - - auto - IGCObjectVisitor_DMockCollector::alloc_copy(DMockCollector & self, std::byte * src) -> void * - { - return self.alloc_copy(src); - } - auto - IGCObjectVisitor_DMockCollector::visit_child(DMockCollector & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept -> void - { - self.visit_child(reason, iface, pp_data); - } - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end IGCObjectVisitor_DMockCollector.cpp */ diff --git a/xo-gc/utest/IGCObjectVisitor_DMockCollector.hpp b/xo-gc/utest/IGCObjectVisitor_DMockCollector.hpp deleted file mode 100644 index 359972ba..00000000 --- a/xo-gc/utest/IGCObjectVisitor_DMockCollector.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/** @file IGCObjectVisitor_DMockCollector.hpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/IGCObjectVisitor_DMockCollector.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_repr.hpp.j2] - * 3. idl for facet methods - * [idl/IGCObjectVisitor_DMockCollector.json5] - **/ - -#pragma once - -#include "GCObjectVisitor.hpp" -#include "DMockCollector.hpp" - -namespace xo { namespace mm { class IGCObjectVisitor_DMockCollector; } } - -namespace xo { - namespace facet { - template <> - struct FacetImplementation - { - using ImplType = xo::mm::IGCObjectVisitor_Xfer - ; - }; - } -} - -namespace xo { - namespace mm { - /** @class IGCObjectVisitor_DMockCollector - **/ - class IGCObjectVisitor_DMockCollector { - public: - /** @defgroup mm-gcobjectvisitor-dmockcollector-type-traits **/ - ///@{ - using Copaque = xo::mm::AGCObjectVisitor::Copaque; - using Opaque = xo::mm::AGCObjectVisitor::Opaque; - ///@} - /** @defgroup mm-gcobjectvisitor-dmockcollector-methods **/ - ///@{ - // const methods - /** allocation metadata for gc-aware data at address @p gco. -@p gco must be the result of a call to collector's alloc() function **/ - static AllocInfo alloc_info(const DMockCollector & self, void * addr); - /** generation to which pointer @p addr belongs, given role @p r; -sentinel if @p addr is not owned by collector **/ - static Generation generation_of(const DMockCollector & self, Role r, const void * addr) noexcept; - - // non-const methods - /** allocate copy of source object at address @p src. -Source must be owned by this collector. -Increments object age **/ - static void * alloc_copy(DMockCollector & self, std::byte * src); - /** visit child of a gc-aware object. May update child in-place! **/ - static void visit_child(DMockCollector & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept; - ///@} - }; - - } /*namespace mm*/ -} /*namespace xo*/ - -/* end */ \ No newline at end of file diff --git a/xo-gc/utest/MockCollector.hpp b/xo-gc/utest/MockCollector.hpp deleted file mode 100644 index 4e3f3d1b..00000000 --- a/xo-gc/utest/MockCollector.hpp +++ /dev/null @@ -1,13 +0,0 @@ -/** @file MockCollector.hpp - * - * @author Roland Conybeare, Apr 2026 - **/ - -#pragma once - -#include "DMockCollector.hpp" -#include "IGCObjectVisitor_DMockCollector.hpp" -//#include "ICollector_DMockCollector.hpp" -//#include "IAllocator_DMockCollector.hpp" - -/* end MockCollector.hpp */ diff --git a/xo-gc/utest/init_gc_utest.cpp b/xo-gc/utest/init_gc_utest.cpp index c708c561..5f1958cf 100644 --- a/xo-gc/utest/init_gc_utest.cpp +++ b/xo-gc/utest/init_gc_utest.cpp @@ -4,7 +4,7 @@ **/ #include "init_gc_utest.hpp" -#include "MockCollector.hpp" +//#include "MockCollector.hpp" #include #include #include @@ -19,9 +19,9 @@ namespace xo { { scope log(XO_DEBUG(false)); - FacetRegistry::register_impl(); + //FacetRegistry::register_impl(); - log && log(xtag("DMockCollector.tseq", typeseq::id())); + //log && log(xtag("DMockCollector.tseq", typeseq::id())); return true; }