xo-interpreter2 stack: + reason arg to visit_gco_children()

Helps streamline DX1Collector in xo-gc/.
Want both forward and verify entry points for the same
representation.
This commit is contained in:
Roland Conybeare 2026-04-10 01:10:03 -04:00
commit 5a0314d8d6
15 changed files with 97 additions and 28 deletions

View file

@ -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 */

View file

@ -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<AGCObjectVisitor> fn) const noexcept = 0;
virtual void visit_gco_children(Opaque data, VisitReason reason, obj<AGCObjectVisitor> fn) const noexcept = 0;
///@}
}; /*AGCObject*/

View file

@ -16,6 +16,7 @@
// includes (via {facet_includes})
#include <xo/alloc2/Generation.hpp>
#include <xo/alloc2/role.hpp>
#include <xo/alloc2/VisitReason.hpp>
#include <xo/arena/AllocInfo.hpp>
#include <xo/facet/obj.hpp>
#include <xo/facet/facet_implementation.hpp>
@ -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*/

View file

@ -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;
///@}

View file

@ -15,6 +15,7 @@
#include <xo/alloc2/Generation.hpp>
#include <xo/alloc2/role.hpp>
#include <xo/alloc2/VisitReason.hpp>
#include <xo/arena/AllocInfo.hpp>
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);
}
///@}

View file

@ -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<AGCObjectVisitor>) const noexcept override;
[[noreturn]] void visit_gco_children(Opaque, obj<AGCObjectVisitor>) const noexcept override;
[[noreturn]] void visit_gco_children(Opaque, VisitReason, obj<AGCObjectVisitor>) const noexcept override;
///@}

View file

@ -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<AGCObjectVisitor> gc) const noexcept override {
return I::gco_shallow_move(_dcast(data), gc);
}
void visit_gco_children(Opaque data, obj<AGCObjectVisitor> fn) const noexcept override {
return I::visit_gco_children(_dcast(data), fn);
void visit_gco_children(Opaque data, VisitReason reason, obj<AGCObjectVisitor> fn) const noexcept override {
return I::visit_gco_children(_dcast(data), reason, fn);
}
///@}

View file

@ -24,32 +24,33 @@ namespace xo {
template <typename Object>
template <typename DRepr>
void
RGCObjectVisitor<Object>::visit_child(xo::facet::obj<AGCObject,DRepr> * p_obj)
RGCObjectVisitor<Object>::visit_child(VisitReason reason,
xo::facet::obj<AGCObject,DRepr> * p_obj)
{
this->visit_child(p_obj->iface(), (void **)&(p_obj->data_));
this->visit_child(reason, p_obj->iface(), (void **)&(p_obj->data_));
}
template <typename Object>
template <typename DRepr>
void
RGCObjectVisitor<Object>::visit_child(DRepr ** p_repr)
RGCObjectVisitor<Object>::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<AGCObject, std::remove_const_t<DRepr>>();
this->visit_child(&iface, (void **)p_repr);
this->visit_child(reason, &iface, (void **)p_repr);
}
template <typename Object>
template <typename AFacet, typename DRepr>
requires (!std::is_same_v<AFacet, AGCObject>)
void
RGCObjectVisitor<Object>::visit_poly_child(obj<AFacet, DRepr> * p_objs)
RGCObjectVisitor<Object>::visit_poly_child(VisitReason reason, obj<AFacet, DRepr> * p_objs)
{
if (*p_objs) {
auto e = xo::facet::FacetRegistry::instance().variant<AGCObject,AFacet>(*p_objs);
this->visit_child(e.iface(), (void **)&(p_objs->data_));
this->visit_child(reason, e.iface(), (void **)&(p_objs->data_));
}
}

View file

@ -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<AGCObjectVisitor> gc) noexcept {
return O::iface()->gco_shallow_move(O::data(), gc);
}
void visit_gco_children(obj<AGCObjectVisitor> fn) noexcept {
return O::iface()->visit_gco_children(O::data(), fn);
void visit_gco_children(VisitReason reason, obj<AGCObjectVisitor> fn) noexcept {
return O::iface()->visit_gco_children(O::data(), reason, fn);
}
///@}

View file

@ -67,20 +67,20 @@ public:
(for historical reasons - coul d be in RGCObject_aux.hpp?)
**/
template <typename DRepr>
void visit_child(xo::facet::obj<AGCObject,DRepr> * p_obj);
void visit_child(VisitReason reason, xo::facet::obj<AGCObject,DRepr> * p_obj);
/** visit typed child data pointer in place.
Defined in RGCObject.hpp to avoid #include cycle
**/
template <typename DRepr>
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 <typename AFacet, typename DRepr>
requires (!std::is_same_v<AFacet, AGCObject>)
void visit_poly_child(obj<AFacet,DRepr> * p_pivot);
void visit_poly_child(VisitReason reason, obj<AFacet,DRepr> * 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);
}
///@}

View file

@ -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;