diff --git a/idl/GCObject.json5 b/idl/GCObject.json5 index 2b0b669..234b3d0 100644 --- a/idl/GCObject.json5 +++ b/idl/GCObject.json5 @@ -6,6 +6,7 @@ includes: [ "", "", + "", "", "", ], @@ -42,6 +43,11 @@ doc: ["fomo collector type"], definition: "xo::mm::ACollector", }, + { + name: "AGCObjectVisitor", + doc: ["fomo collector type"], + definition: "xo::mm::AGCObjectVisitor", + }, ], const_methods: [ // size_type shallow_size() const noexcept @@ -68,13 +74,17 @@ noexcept: true, attributes: [], }, - // size_type forward_children(obj) noexcept + // size_type visit_gco_children(obj) noexcept { - name: "forward_children", - doc: ["during GC: forward immdiate children"], + name: "visit_gco_children", + doc: [ + "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" + ], return_type: "void", args: [ - {type: "obj", name: "gc"}, + {type: "obj", name: "fn"}, ], const: true, noexcept: true, diff --git a/idl/GCObjectVisitor.json5 b/idl/GCObjectVisitor.json5 index b465842..2e8344d 100644 --- a/idl/GCObjectVisitor.json5 +++ b/idl/GCObjectVisitor.json5 @@ -71,5 +71,26 @@ attributes: [], }, ], - router_facet_explicit_content: [] + router_facet_explicit_content: [ + "", + "/** visit forward faceted object child pointer in place.", + " Defined in RGCObject.hpp to avoid #include cycle", + " **/", + "template ", + "void visit_child(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);", + "", + "/** visit faceted object pointer stored using some facet", + " other than AGCObject", + " **/", + "template ", + "requires (!std::is_same_v)", + "void visit_poly_child(obj * p_pivot);", + "", + ] } diff --git a/include/xo/alloc2/gc/AGCObject.hpp b/include/xo/alloc2/gc/AGCObject.hpp index b5b9fb0..3c0fed0 100644 --- a/include/xo/alloc2/gc/AGCObject.hpp +++ b/include/xo/alloc2/gc/AGCObject.hpp @@ -16,6 +16,7 @@ // includes (via {facet_includes}) #include #include +#include #include #include #include @@ -48,6 +49,8 @@ public: using AAllocator = xo::mm::AAllocator; /** fomo collector type **/ using ACollector = xo::mm::ACollector; + /** fomo collector type **/ + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; ///@} /** @defgroup mm-gcobject-methods **/ @@ -66,8 +69,10 @@ public: // nonconst methods /** move instance using allocator **/ virtual Opaque shallow_move(Opaque data, obj gc) const noexcept = 0; - /** during GC: forward immdiate children **/ - virtual void forward_children(Opaque data, obj gc) const noexcept = 0; + /** 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; ///@} }; /*AGCObject*/ diff --git a/include/xo/alloc2/gc/IGCObject_Any.hpp b/include/xo/alloc2/gc/IGCObject_Any.hpp index 34f0bca..7f12f82 100644 --- a/include/xo/alloc2/gc/IGCObject_Any.hpp +++ b/include/xo/alloc2/gc/IGCObject_Any.hpp @@ -47,6 +47,7 @@ namespace mm { using size_type = AGCObject::size_type; using AAllocator = AGCObject::AAllocator; using ACollector = AGCObject::ACollector; + using AGCObjectVisitor = AGCObject::AGCObjectVisitor; ///@} /** @defgroup mm-gcobject-any-methods **/ @@ -64,7 +65,7 @@ namespace mm { // nonconst methods [[noreturn]] Opaque shallow_move(Opaque, obj) const noexcept override; - [[noreturn]] void forward_children(Opaque, obj) const noexcept override; + [[noreturn]] void visit_gco_children(Opaque, obj) const noexcept override; ///@} diff --git a/include/xo/alloc2/gc/IGCObject_Xfer.hpp b/include/xo/alloc2/gc/IGCObject_Xfer.hpp index d69184c..361bc51 100644 --- a/include/xo/alloc2/gc/IGCObject_Xfer.hpp +++ b/include/xo/alloc2/gc/IGCObject_Xfer.hpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ namespace mm { using size_type = AGCObject::size_type; using AAllocator = AGCObject::AAllocator; using ACollector = AGCObject::ACollector; + using AGCObjectVisitor = AGCObject::AGCObjectVisitor; ///@} /** @defgroup mm-gcobject-xfer-methods **/ @@ -54,8 +56,8 @@ namespace mm { Opaque shallow_move(Opaque data, obj gc) const noexcept override { return I::shallow_move(_dcast(data), gc); } - void forward_children(Opaque data, obj gc) const noexcept override { - return I::forward_children(_dcast(data), gc); + void visit_gco_children(Opaque data, obj fn) const noexcept override { + return I::visit_gco_children(_dcast(data), fn); } ///@} diff --git a/include/xo/alloc2/gc/RCollector_aux.hpp b/include/xo/alloc2/gc/RCollector_aux.hpp index 529f69d..83bc631 100644 --- a/include/xo/alloc2/gc/RCollector_aux.hpp +++ b/include/xo/alloc2/gc/RCollector_aux.hpp @@ -17,6 +17,46 @@ namespace xo { class ACollector; class AGCObject; + /** defined here to avoid #include cycle, since + * template obj awkward to make available + * in RCollector.hpp + **/ + template + template + void + RGCObjectVisitor::visit_child(xo::facet::obj * p_obj) + { + this->visit_child(p_obj->iface(), (void **)&(p_obj->data_)); + } + + template + template + void + RGCObjectVisitor::visit_child(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); + } + + template + template + requires (!std::is_same_v) + void + RGCObjectVisitor::visit_poly_child(obj * p_objs) + { + if (*p_objs) { + auto e = xo::facet::FacetRegistry::instance().variant(*p_objs); + + this->visit_child(e.iface(), (void **)&(p_objs->data_)); + } + } + + // ----- DEPRECATED ----- + // + // Moving these methods to RGCObjectVisitor + /** defined here to avoid #include cycle, since * template obj awkward to make available * in RCollector.hpp @@ -52,6 +92,8 @@ namespace xo { } } + // ----- mm_do_assign ----- + /** gc-aware assignment; engage special book-keeping for cross-gen pointers **/ inline void mm_do_assign(obj & gc, void * parent, diff --git a/include/xo/alloc2/gc/RGCObject.hpp b/include/xo/alloc2/gc/RGCObject.hpp index a0de103..5ac4c48 100644 --- a/include/xo/alloc2/gc/RGCObject.hpp +++ b/include/xo/alloc2/gc/RGCObject.hpp @@ -34,6 +34,7 @@ public: using size_type = AGCObject::size_type; using AAllocator = AGCObject::AAllocator; using ACollector = AGCObject::ACollector; + using AGCObjectVisitor = AGCObject::AGCObjectVisitor; ///@} /** @defgroup mm-gcobject-router-ctors **/ @@ -60,8 +61,8 @@ public: Opaque shallow_move(obj gc) noexcept { return O::iface()->shallow_move(O::data(), gc); } - void forward_children(obj gc) noexcept { - return O::iface()->forward_children(O::data(), gc); + void visit_gco_children(obj fn) noexcept { + return O::iface()->visit_gco_children(O::data(), fn); } ///@} diff --git a/include/xo/alloc2/gc/RGCObjectVisitor.hpp b/include/xo/alloc2/gc/RGCObjectVisitor.hpp index 800d197..7fbf907 100644 --- a/include/xo/alloc2/gc/RGCObjectVisitor.hpp +++ b/include/xo/alloc2/gc/RGCObjectVisitor.hpp @@ -46,6 +46,26 @@ public: ///@{ // explicit injected content + + /** visit forward faceted object child pointer in place. + Defined in RGCObject.hpp to avoid #include cycle + **/ + template + void visit_child(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); + + /** visit faceted object pointer stored using some facet + other than AGCObject + **/ + template + requires (!std::is_same_v) + void visit_poly_child(obj * p_pivot); + // builtin methods typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); } diff --git a/src/alloc2/IGCObject_Any.cpp b/src/alloc2/IGCObject_Any.cpp index a441524..7df0548 100644 --- a/src/alloc2/IGCObject_Any.cpp +++ b/src/alloc2/IGCObject_Any.cpp @@ -42,7 +42,7 @@ IGCObject_Any::shallow_move(Opaque, obj) const noexcept -> Opaque } auto -IGCObject_Any::forward_children(Opaque, obj) const noexcept -> void +IGCObject_Any::visit_gco_children(Opaque, obj) const noexcept -> void { _fatal(); }