xo-gc: refactor: demote GCObjectVisitor to GCObjectStore
No longer needed by DX1Collector Also retires utest/MockCollector
This commit is contained in:
parent
d1e2ae38f3
commit
9e74e35c68
21 changed files with 242 additions and 331 deletions
|
|
@ -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
|
||||
)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
|
|
|||
28
idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5
Normal file
28
idl/IGCObjectVisitor_DGCObjectStoreVisitor.json5
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
mode: "implementation",
|
||||
output_cpp_dir: "src/gc/facet",
|
||||
output_hpp_dir: "include/xo/gc",
|
||||
output_impl_subdir: "detail",
|
||||
includes: [
|
||||
// "<xo/alloc2/GCObject.hpp>",
|
||||
// "<xo/alloc2/Allocator.hpp>"
|
||||
],
|
||||
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)",
|
||||
],
|
||||
}
|
||||
49
include/xo/gc/DGCObjectStoreVisitor.hpp
Normal file
49
include/xo/gc/DGCObjectStoreVisitor.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/** @file DGCObjectStoreVisitor.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Apr 2026
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xo/alloc2/GCObjectVisitor.hpp>
|
||||
#include <xo/alloc2/VisitReason.hpp>
|
||||
#include <xo/alloc2/Generation.hpp>
|
||||
#include <xo/alloc2/role.hpp>
|
||||
#include <xo/arena/AllocInfo.hpp>
|
||||
#include <xo/facet/obj.hpp>
|
||||
|
||||
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 <typename AFacet = AGCObjectVisitor>
|
||||
obj<AFacet,DGCObjectStoreVisitor> ref() { return obj<AFacet,DGCObjectStoreVisitor>(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 */
|
||||
|
|
@ -134,7 +134,7 @@ namespace xo {
|
|||
* to call AGCObject visitor method (forward_children()) on each
|
||||
* object stored here.
|
||||
**/
|
||||
void verify_ok(obj<AGCObjectVisitor> 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<AGCObjectVisitor> 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).
|
||||
|
|
|
|||
11
include/xo/gc/GCObjectStoreVisitor.hpp
Normal file
11
include/xo/gc/GCObjectStoreVisitor.hpp
Normal file
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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::AGCObjectVisitor,
|
||||
xo::mm::DX1Collector>
|
||||
xo::mm::DGCObjectStoreVisitor>
|
||||
{
|
||||
using ImplType = xo::mm::IGCObjectVisitor_Xfer
|
||||
<xo::mm::DX1Collector,
|
||||
xo::mm::IGCObjectVisitor_DX1Collector>;
|
||||
<xo::mm::DGCObjectStoreVisitor,
|
||||
xo::mm::IGCObjectVisitor_DGCObjectStoreVisitor>;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
///@}
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
**/
|
||||
|
||||
#include "X1Collector.hpp"
|
||||
#include "GCObjectStoreVisitor.hpp"
|
||||
#include <xo/gc/DX1CollectorIterator.hpp>
|
||||
|
||||
#include <xo/object2/Dictionary.hpp>
|
||||
|
|
@ -13,7 +14,6 @@
|
|||
#include <xo/stringtable2/String.hpp>
|
||||
|
||||
#include <xo/alloc2/GCObject.hpp>
|
||||
#include <xo/alloc2/GCObjectVisitor.hpp>
|
||||
#include <xo/alloc2/Allocator.hpp>
|
||||
#include <xo/alloc2/Arena.hpp>
|
||||
#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<AGCObjectVisitor>();
|
||||
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<AGCObjectVisitor>());
|
||||
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<AGCObjectVisitor>(), 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<AGCObjectVisitor>(),
|
||||
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<AGCObjectVisitor>(), 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
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
**/
|
||||
|
||||
#include "GCObjectStore.hpp"
|
||||
#include "GCObjectStoreVisitor.hpp"
|
||||
#include "X1VerifyStats.hpp"
|
||||
|
||||
#include <xo/object2/Dictionary.hpp>
|
||||
|
|
@ -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<AGCObjectVisitor,DGCObjectStoreVisitor>(&gcos_visitor);
|
||||
|
||||
// called during collection phase
|
||||
this->forward_inplace_aux
|
||||
(this->ref<AGCObjectVisitor>(), 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<AGCObjectVisitor> gc,
|
||||
|
|
@ -768,8 +767,11 @@ namespace xo {
|
|||
}
|
||||
|
||||
void
|
||||
GCObjectStore::verify_ok(obj<AGCObjectVisitor> 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<AGCObject> gco(iface, const_cast<void *>(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<AGCObjectVisitor> 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<AGCObject>(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
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "SetupGc.hpp"
|
||||
#include "X1Collector.hpp"
|
||||
#include "GCObjectStoreVisitor.hpp"
|
||||
#include <xo/facet/FacetRegistry.hpp>
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
|
||||
|
|
@ -24,9 +25,11 @@ namespace xo {
|
|||
|
||||
FacetRegistry::register_impl<AAllocator, DX1Collector>();
|
||||
FacetRegistry::register_impl<ACollector, DX1Collector>();
|
||||
FacetRegistry::register_impl<AGCObjectVisitor, DX1Collector>();
|
||||
|
||||
FacetRegistry::register_impl<AGCObjectVisitor, DGCObjectStoreVisitor>();
|
||||
|
||||
log && log(xtag("DX1Collector.tseq", typeseq::id<DX1Collector>()));
|
||||
log && log(xtag("DGCObjectStoreVisitor.tseq", typeseq::id<DGCObjectStoreVisitor>()));
|
||||
|
||||
log && log(xtag("ACollector.tseq", typeseq::id<ACollector>()));
|
||||
log && log(xtag("AGCObjectVisitor.tseq", typeseq::id<AGCObjectVisitor>()));
|
||||
|
|
|
|||
44
src/gc/facet/IGCObjectVisitor_DGCObjectStoreVisitor.cpp
Normal file
44
src/gc/facet/IGCObjectVisitor_DGCObjectStoreVisitor.cpp
Normal file
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
/** @file DMockCollector.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Apr 2026
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xo/gc/GCObjectStore.hpp>
|
||||
#include <xo/arena/AllocInfo.hpp>
|
||||
|
||||
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 <typename AFacet>
|
||||
obj<AFacet,DMockCollector> ref() { return obj<AFacet,DMockCollector>(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 */
|
||||
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
#include <xo/gc/GCObjectStore.hpp>
|
||||
#include <xo/gc/X1VerifyStats.hpp>
|
||||
#include "MockCollector.hpp"
|
||||
|
||||
#include <xo/object2/ListOps.hpp>
|
||||
#include <xo/object2/List.hpp>
|
||||
#include <xo/object2/Integer.hpp>
|
||||
|
|
@ -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<DBoolean>()));
|
||||
}
|
||||
|
||||
/** Invoke built-in consistency verification for @p *p_gcos.
|
||||
**/
|
||||
void
|
||||
gcos_verify_consistency(obj<AGCObjectVisitor> 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<AGCObjectVisitor> mock_gc_visitor,
|
||||
Generation upto,
|
||||
const std::vector<Recd> & x1_v,
|
||||
const std::vector<Recd> & x2_v,
|
||||
bool debug_flag)
|
||||
|
|
@ -690,9 +695,9 @@ namespace ut {
|
|||
obj<AGCObject> 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<AGCObjectVisitor>();
|
||||
|
||||
REQUIRE(gcos.is_type_installed(typeseq::id<DList>()) == false);
|
||||
REQUIRE(gcos.is_type_installed(typeseq::id<DBoolean>()) == 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_),
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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<xo::mm::AGCObjectVisitor,
|
||||
xo::mm::DMockCollector>
|
||||
{
|
||||
using ImplType = xo::mm::IGCObjectVisitor_Xfer
|
||||
<xo::mm::DMockCollector,
|
||||
xo::mm::IGCObjectVisitor_DMockCollector>;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
**/
|
||||
|
||||
#include "init_gc_utest.hpp"
|
||||
#include "MockCollector.hpp"
|
||||
//#include "MockCollector.hpp"
|
||||
#include <xo/gc/init_gc.hpp>
|
||||
#include <xo/facet/FacetRegistry.hpp>
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
|
|
@ -19,9 +19,9 @@ namespace xo {
|
|||
{
|
||||
scope log(XO_DEBUG(false));
|
||||
|
||||
FacetRegistry::register_impl<AGCObjectVisitor, DMockCollector>();
|
||||
//FacetRegistry::register_impl<AGCObjectVisitor, DMockCollector>();
|
||||
|
||||
log && log(xtag("DMockCollector.tseq", typeseq::id<DMockCollector>()));
|
||||
//log && log(xtag("DMockCollector.tseq", typeseq::id<DMockCollector>()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue