diff --git a/idl/GCObject.json5 b/idl/GCObject.json5 index f86e6ca..cd320d0 100644 --- a/idl/GCObject.json5 +++ b/idl/GCObject.json5 @@ -48,6 +48,11 @@ doc: ["fomo collector type"], definition: "xo::mm::AGCObjectVisitor", }, + { + name: "VisitReason", + doc: ["hint arg when navigating object graph"], + definition: "xo::mm::VisitReason", + }, ], const_methods: [ // size_type shallow_size() const noexcept @@ -77,7 +82,7 @@ noexcept: true, attributes: [], }, - // size_type visit_gco_children(obj) noexcept + // size_type visit_gco_children(VisitReason reason, obj) noexcept { name: "visit_gco_children", doc: [ @@ -87,6 +92,7 @@ ], return_type: "void", args: [ + {type: "VisitReason", name: "reason"}, {type: "obj", name: "fn"}, ], const: true, diff --git a/idl/GCObjectVisitor.json5 b/idl/GCObjectVisitor.json5 index 854287e..fe6fbb1 100644 --- a/idl/GCObjectVisitor.json5 +++ b/idl/GCObjectVisitor.json5 @@ -6,6 +6,7 @@ includes: [ "", "", + "", "", ], // extra includes in GCObject.hpp, if any @@ -85,12 +86,13 @@ noexcept: false, attributes: [], }, - // void visit_child(AGCObject * iface, void ** pp_data) noexcept; + // void visit_child(VisitReason reason, AGCObject * iface, void ** pp_data) noexcept; { name: "visit_child", doc: ["visit child of a gc-aware object. May update child in-place!"], return_type: "void", args:[ + {type: "VisitReason", name: "reason"}, {type: "AGCObject *", name: "iface"}, {type: "void **", name: "pp_data"}, ], @@ -121,20 +123,20 @@ " (for historical reasons - coul d be in RGCObject_aux.hpp?)", " **/", "template ", - "void visit_child(xo::facet::obj * p_obj);", + "void visit_child(VisitReason reason, xo::facet::obj * p_obj);", "", "/** visit typed child data pointer in place.", " Defined in RGCObject.hpp to avoid #include cycle", " **/", "template ", - "void visit_child(DRepr ** pp_data);", + "void visit_child(VisitReason reason, DRepr ** pp_data);", "", "/** visit faceted object pointer stored using some facet", " other than AGCObject", " **/", "template ", "requires (!std::is_same_v)", - "void visit_poly_child(obj * p_pivot);", + "void visit_poly_child(VisitReason reason, obj * p_pivot);", "", ] } diff --git a/include/xo/alloc2/VisitReason.hpp b/include/xo/alloc2/VisitReason.hpp new file mode 100644 index 0000000..569b02d --- /dev/null +++ b/include/xo/alloc2/VisitReason.hpp @@ -0,0 +1,51 @@ +/** @file VisitReason.hpp + * + * @author Roland Conybeare, Apr 2026 + **/ + +#pragma once + +namespace xo { + namespace mm { + + /** @brief tag when navigating object graph + * + * Used with + * @ref DX1Collector::visit_child + * @ref GCObject::visit_gco_children + **/ + class VisitReason { + public: + enum class code { + invalid = -1, + + /** color not needed **/ + unspecified, + + /** Forward child pointers inplace for GC. + * See @ref GCObjectStore::forward_inplace_aux + **/ + forward, + /** verify GC store consistency + * See @ref DX1Collector::_verify_aux + **/ + verify, + + N, + }; + + explicit VisitReason(code x) : code_{x} {} + + static VisitReason unspecified() { return VisitReason(code::unspecified); } + static VisitReason forward() { return VisitReason(code::forward); } + static VisitReason verify() { return VisitReason(code::verify); } + + code code() const noexcept { return code_; } + + enum code code_; + }; + + } /*namespace mm*/ +} /*namespace xo*/ + +/* end VisitReason.hpp */ diff --git a/include/xo/alloc2/gc/AGCObject.hpp b/include/xo/alloc2/gc/AGCObject.hpp index 6ed3ee7..fbb5f61 100644 --- a/include/xo/alloc2/gc/AGCObject.hpp +++ b/include/xo/alloc2/gc/AGCObject.hpp @@ -51,6 +51,8 @@ public: using ACollector = xo::mm::ACollector; /** fomo collector type **/ using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + /** hint arg when navigating object graph **/ + using VisitReason = xo::mm::VisitReason; ///@} /** @defgroup mm-gcobject-methods **/ @@ -73,7 +75,7 @@ Arguably abusing the word 'visitor' here **/ /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. Context: provides address of data pointer so it can be updated in place when @p fn invokes garbage collector reentry point **/ - virtual void visit_gco_children(Opaque data, obj fn) const noexcept = 0; + virtual void visit_gco_children(Opaque data, VisitReason reason, obj fn) const noexcept = 0; ///@} }; /*AGCObject*/ diff --git a/include/xo/alloc2/gc/AGCObjectVisitor.hpp b/include/xo/alloc2/gc/AGCObjectVisitor.hpp index a9d0093..86cd9b9 100644 --- a/include/xo/alloc2/gc/AGCObjectVisitor.hpp +++ b/include/xo/alloc2/gc/AGCObjectVisitor.hpp @@ -16,6 +16,7 @@ // includes (via {facet_includes}) #include #include +#include #include #include #include @@ -71,7 +72,7 @@ Source must be owned by this collector. Increments object age **/ virtual void * alloc_copy(Opaque data, std::byte * src) const = 0; /** visit child of a gc-aware object. May update child in-place! **/ - virtual void visit_child(Opaque data, AGCObject * iface, void ** pp_data) const noexcept = 0; + virtual void visit_child(Opaque data, VisitReason reason, AGCObject * iface, void ** pp_data) const noexcept = 0; ///@} }; /*AGCObjectVisitor*/ diff --git a/include/xo/alloc2/gc/IGCObjectVisitor_Any.hpp b/include/xo/alloc2/gc/IGCObjectVisitor_Any.hpp index 53515e2..8dbece0 100644 --- a/include/xo/alloc2/gc/IGCObjectVisitor_Any.hpp +++ b/include/xo/alloc2/gc/IGCObjectVisitor_Any.hpp @@ -63,7 +63,7 @@ namespace mm { // nonconst methods [[noreturn]] void * alloc_copy(Opaque, std::byte *) const override; - [[noreturn]] void visit_child(Opaque, AGCObject *, void **) const noexcept override; + [[noreturn]] void visit_child(Opaque, VisitReason, AGCObject *, void **) const noexcept override; ///@} diff --git a/include/xo/alloc2/gc/IGCObjectVisitor_Xfer.hpp b/include/xo/alloc2/gc/IGCObjectVisitor_Xfer.hpp index 00ad359..0cc6087 100644 --- a/include/xo/alloc2/gc/IGCObjectVisitor_Xfer.hpp +++ b/include/xo/alloc2/gc/IGCObjectVisitor_Xfer.hpp @@ -15,6 +15,7 @@ #include #include +#include #include namespace xo { @@ -56,8 +57,8 @@ namespace mm { void * alloc_copy(Opaque data, std::byte * src) const override { return I::alloc_copy(_dcast(data), src); } - void visit_child(Opaque data, AGCObject * iface, void ** pp_data) const noexcept override { - return I::visit_child(_dcast(data), iface, pp_data); + void visit_child(Opaque data, VisitReason reason, AGCObject * iface, void ** pp_data) const noexcept override { + return I::visit_child(_dcast(data), reason, iface, pp_data); } ///@} diff --git a/include/xo/alloc2/gc/IGCObject_Any.hpp b/include/xo/alloc2/gc/IGCObject_Any.hpp index 6297477..f9ff5f8 100644 --- a/include/xo/alloc2/gc/IGCObject_Any.hpp +++ b/include/xo/alloc2/gc/IGCObject_Any.hpp @@ -48,6 +48,7 @@ namespace mm { using AAllocator = AGCObject::AAllocator; using ACollector = AGCObject::ACollector; using AGCObjectVisitor = AGCObject::AGCObjectVisitor; + using VisitReason = AGCObject::VisitReason; ///@} /** @defgroup mm-gcobject-any-methods **/ @@ -65,7 +66,7 @@ namespace mm { // nonconst methods [[noreturn]] Opaque gco_shallow_move(Opaque, obj) const noexcept override; - [[noreturn]] void visit_gco_children(Opaque, obj) const noexcept override; + [[noreturn]] void visit_gco_children(Opaque, VisitReason, obj) const noexcept override; ///@} diff --git a/include/xo/alloc2/gc/IGCObject_Xfer.hpp b/include/xo/alloc2/gc/IGCObject_Xfer.hpp index 633c103..c5a0a6b 100644 --- a/include/xo/alloc2/gc/IGCObject_Xfer.hpp +++ b/include/xo/alloc2/gc/IGCObject_Xfer.hpp @@ -36,6 +36,7 @@ namespace mm { using AAllocator = AGCObject::AAllocator; using ACollector = AGCObject::ACollector; using AGCObjectVisitor = AGCObject::AGCObjectVisitor; + using VisitReason = AGCObject::VisitReason; ///@} /** @defgroup mm-gcobject-xfer-methods **/ @@ -56,8 +57,8 @@ namespace mm { Opaque gco_shallow_move(Opaque data, obj gc) const noexcept override { return I::gco_shallow_move(_dcast(data), gc); } - void visit_gco_children(Opaque data, obj fn) const noexcept override { - return I::visit_gco_children(_dcast(data), fn); + void visit_gco_children(Opaque data, VisitReason reason, obj fn) const noexcept override { + return I::visit_gco_children(_dcast(data), reason, fn); } ///@} diff --git a/include/xo/alloc2/gc/RCollector_aux.hpp b/include/xo/alloc2/gc/RCollector_aux.hpp index 83bc631..e964a93 100644 --- a/include/xo/alloc2/gc/RCollector_aux.hpp +++ b/include/xo/alloc2/gc/RCollector_aux.hpp @@ -24,32 +24,33 @@ namespace xo { template template void - RGCObjectVisitor::visit_child(xo::facet::obj * p_obj) + RGCObjectVisitor::visit_child(VisitReason reason, + xo::facet::obj * p_obj) { - this->visit_child(p_obj->iface(), (void **)&(p_obj->data_)); + this->visit_child(reason, p_obj->iface(), (void **)&(p_obj->data_)); } template template void - RGCObjectVisitor::visit_child(DRepr ** p_repr) + RGCObjectVisitor::visit_child(VisitReason reason, DRepr ** p_repr) { // fetch static interface for DRepr (strip const: FacetImplementation specializations use non-const DRepr) auto iface = xo::facet::impl_for>(); - this->visit_child(&iface, (void **)p_repr); + this->visit_child(reason, &iface, (void **)p_repr); } template template requires (!std::is_same_v) void - RGCObjectVisitor::visit_poly_child(obj * p_objs) + RGCObjectVisitor::visit_poly_child(VisitReason reason, obj * p_objs) { if (*p_objs) { auto e = xo::facet::FacetRegistry::instance().variant(*p_objs); - this->visit_child(e.iface(), (void **)&(p_objs->data_)); + this->visit_child(reason, e.iface(), (void **)&(p_objs->data_)); } } diff --git a/include/xo/alloc2/gc/RGCObject.hpp b/include/xo/alloc2/gc/RGCObject.hpp index 1d62559..5b40155 100644 --- a/include/xo/alloc2/gc/RGCObject.hpp +++ b/include/xo/alloc2/gc/RGCObject.hpp @@ -35,6 +35,7 @@ public: using AAllocator = AGCObject::AAllocator; using ACollector = AGCObject::ACollector; using AGCObjectVisitor = AGCObject::AGCObjectVisitor; + using VisitReason = AGCObject::VisitReason; ///@} /** @defgroup mm-gcobject-router-ctors **/ @@ -61,8 +62,8 @@ public: Opaque gco_shallow_move(obj gc) noexcept { return O::iface()->gco_shallow_move(O::data(), gc); } - void visit_gco_children(obj fn) noexcept { - return O::iface()->visit_gco_children(O::data(), fn); + void visit_gco_children(VisitReason reason, obj fn) noexcept { + return O::iface()->visit_gco_children(O::data(), reason, fn); } ///@} diff --git a/include/xo/alloc2/gc/RGCObjectVisitor.hpp b/include/xo/alloc2/gc/RGCObjectVisitor.hpp index 8b7ab26..4972593 100644 --- a/include/xo/alloc2/gc/RGCObjectVisitor.hpp +++ b/include/xo/alloc2/gc/RGCObjectVisitor.hpp @@ -67,20 +67,20 @@ public: (for historical reasons - coul d be in RGCObject_aux.hpp?) **/ template - void visit_child(xo::facet::obj * p_obj); + void visit_child(VisitReason reason, xo::facet::obj * p_obj); /** visit typed child data pointer in place. Defined in RGCObject.hpp to avoid #include cycle **/ template - void visit_child(DRepr ** pp_data); + void visit_child(VisitReason reason, DRepr ** pp_data); /** visit faceted object pointer stored using some facet other than AGCObject **/ template requires (!std::is_same_v) - void visit_poly_child(obj * p_pivot); + void visit_poly_child(VisitReason reason, obj * p_pivot); // builtin methods @@ -99,8 +99,8 @@ public: void * alloc_copy(std::byte * src) { return O::iface()->alloc_copy(O::data(), src); } - void visit_child(AGCObject * iface, void ** pp_data) noexcept { - return O::iface()->visit_child(O::data(), iface, pp_data); + void visit_child(VisitReason reason, AGCObject * iface, void ** pp_data) noexcept { + return O::iface()->visit_child(O::data(), reason, iface, pp_data); } ///@} diff --git a/include/xo/alloc2/role.hpp b/include/xo/alloc2/role.hpp index d2b7c2f..9b068a1 100644 --- a/include/xo/alloc2/role.hpp +++ b/include/xo/alloc2/role.hpp @@ -12,6 +12,8 @@ namespace xo { namespace mm { static constexpr uint32_t c_n_role = 2; + /** @brief identify GC half-spaces + **/ class Role { public: using value_type = std::uint32_t; diff --git a/src/alloc2/IGCObject_Any.cpp b/src/alloc2/IGCObject_Any.cpp index 914123d..4e729e0 100644 --- a/src/alloc2/IGCObject_Any.cpp +++ b/src/alloc2/IGCObject_Any.cpp @@ -42,7 +42,7 @@ IGCObject_Any::gco_shallow_move(Opaque, obj) const noexcept } auto -IGCObject_Any::visit_gco_children(Opaque, obj) const noexcept -> void +IGCObject_Any::visit_gco_children(Opaque, VisitReason, obj) const noexcept -> void { _fatal(); } diff --git a/src/alloc2/facet/IGCObjectVisitor_Any.cpp b/src/alloc2/facet/IGCObjectVisitor_Any.cpp index 0946acd..934aa94 100644 --- a/src/alloc2/facet/IGCObjectVisitor_Any.cpp +++ b/src/alloc2/facet/IGCObjectVisitor_Any.cpp @@ -42,7 +42,7 @@ IGCObjectVisitor_Any::alloc_copy(Opaque, std::byte *) const -> void * } auto -IGCObjectVisitor_Any::visit_child(Opaque, AGCObject *, void **) const noexcept -> void +IGCObjectVisitor_Any::visit_child(Opaque, VisitReason, AGCObject *, void **) const noexcept -> void { _fatal(); }