From 99593c4d724d7a0d78b608fa29c2bfe71ec12e0c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 3 Apr 2026 15:53:25 -0400 Subject: [PATCH] xo-gc: refactor: move forward_inplace_aux() to GCObjectStore --- include/xo/gc/DX1Collector.hpp | 3 +- include/xo/gc/GCObjectStore.hpp | 12 ++ src/gc/DX1Collector.cpp | 23 ++-- src/gc/GCObjectStore.cpp | 187 ++++++++++++++++++++++++++++++++ 4 files changed, 217 insertions(+), 8 deletions(-) diff --git a/include/xo/gc/DX1Collector.hpp b/include/xo/gc/DX1Collector.hpp index b3d1ba7..c41284a 100644 --- a/include/xo/gc/DX1Collector.hpp +++ b/include/xo/gc/DX1Collector.hpp @@ -392,7 +392,8 @@ namespace xo { /** Evacuate object at @p *lhs_data to to-space. * Replace original with forwarding pointer to new location **/ - void _forward_inplace_aux(AGCObject * lhs_iface, void ** lhs_data); + void _forward_inplace_aux(AGCObject * lhs_iface, void ** lhs_data, Generation upto); + /** Verify that pointer {@p iface, @p data} is valid: * destination either in to-space, or somewhere outside this collector **/ diff --git a/include/xo/gc/GCObjectStore.hpp b/include/xo/gc/GCObjectStore.hpp index 7cb4e71..147cec6 100644 --- a/include/xo/gc/GCObjectStore.hpp +++ b/include/xo/gc/GCObjectStore.hpp @@ -135,6 +135,18 @@ namespace xo { void * gco_data, Generation upto) const noexcept; + /** Evacuate object at @p *lhs_data to to-space, during collection phase + * acting on generations g in [0 ,.., upto). + * Need @p gc to pass to invoke AGCObject methods shallow_copy() and + * forward_children() + * + * Replace original with forwarding pointer to new location + **/ + void _forward_inplace_aux(DX1Collector * gc, + AGCObject * lhs_iface, + void ** lhs_data, + Generation upto); + /** For each generation g in [0 ,.., upto) * swap arenas assigned to {to-space, from-space}. * Invoked once at the beginning of each gc cycle. diff --git a/src/gc/DX1Collector.cpp b/src/gc/DX1Collector.cpp index fc4acdc..39525b3 100644 --- a/src/gc/DX1Collector.cpp +++ b/src/gc/DX1Collector.cpp @@ -1094,9 +1094,11 @@ namespace xo { DX1Collector::forward_inplace(AGCObject * lhs_iface, void ** lhs_data) { + Generation upto = runstate_.gc_upto(); + if (runstate_.is_running()) { // called during collection phase - this->_forward_inplace_aux(lhs_iface, lhs_data); + this->_forward_inplace_aux(lhs_iface, lhs_data, upto); } else if (runstate_.is_verify()) { // called during verify_ok this->_verify_aux(lhs_iface, *lhs_data); @@ -1108,8 +1110,14 @@ namespace xo { void DX1Collector::_forward_inplace_aux(AGCObject * lhs_iface, - void ** lhs_data) + void ** lhs_data, + Generation upto) { + // upto == runstate_.gc_upto() + + gco_store_._forward_inplace_aux(this, lhs_iface, lhs_data, upto); + +#ifdef MARKED scope log(XO_DEBUG(config_.debug_flag_), xtag("lhs_data", lhs_data), xtag("*lhs_data", lhs_data ? *lhs_data : nullptr)); @@ -1137,7 +1145,7 @@ namespace xo { if (!object_data) { /* trivial to forward nullptr */ return; - } else if (!this->contains(role::from_space(), object_data)) { + } else if (!gco_store_.contains(role::from_space(), object_data)) { /* *lhs_data either: * 1. already in to-space * 2. not in GC-allocated space at all @@ -1162,7 +1170,7 @@ namespace xo { * allocated object data. * Only using this to get alloc header **/ - DArena * some_arena = this->from_space(Generation(0)); + DArena * some_arena = gco_store_.from_space(Generation(0)); DArena::header_type * p_header = some_arena->obj2hdr(object_data); @@ -1192,7 +1200,7 @@ namespace xo { */ assert(alloc_z >= sizeof(uintptr_t)); - if (this->is_forwarding_header(alloc_hdr)) { + if (gco_store_.is_forwarding_header(alloc_hdr)) { /* *lhs_data already refers to a forwarding pointer */ /* @@ -1245,7 +1253,7 @@ namespace xo { xtag("tname", TypeRegistry::id2name(typeseq(info.tseq()))), xtag("age", info.age()), xtag("size", info.size())); } - } else if (this->check_move_policy(alloc_hdr, object_data)) { + } else if (gco_store_._check_move_policy(alloc_hdr, object_data, upto)) { /* copy object *lhs + replace with forwarding pointer */ log && log("forward object now"); @@ -1289,7 +1297,8 @@ namespace xo { * e.g. incremental collection + object is tenured */ } - } /*_forward_inplace*/ +#endif + } /*_forward_inplace_aux*/ void DX1Collector::_verify_aux(AGCObject * iface, void * data) diff --git a/src/gc/GCObjectStore.cpp b/src/gc/GCObjectStore.cpp index 13475dd..118530d 100644 --- a/src/gc/GCObjectStore.cpp +++ b/src/gc/GCObjectStore.cpp @@ -4,6 +4,7 @@ **/ #include "GCObjectStore.hpp" +#include "X1Collector.hpp" #include #include @@ -371,6 +372,192 @@ namespace xo { return (g < upto); } + void + GCObjectStore::_forward_inplace_aux(DX1Collector * gc, + AGCObject * lhs_iface, + void ** lhs_data, + Generation upto) + { + // upto == runstate_.gc_upto() + + scope log(XO_DEBUG(config_.debug_flag_), + xtag("lhs_data", lhs_data), + xtag("*lhs_data", lhs_data ? *lhs_data : nullptr)); + + /* coordinates with DX1Collector::_deep_move() */ + + /* + * lhs obj + * | +---------+ +---+-+----+ + * \--->| .iface | | T |G|size| header + * +---------+ object_data +---+-+----+ + * | .data x----------------->| alloc | + * +---------+ | data | + * | for | + * | instance | + * | ... | + * +----------+ + */ + + void * object_data = (std::byte *)*lhs_data; + + if (!object_data) { + /* trivial to forward nullptr */ + return; + } else if (!this->contains(role::from_space(), object_data)) { + /* *lhs_data either: + * 1. already in to-space + * 2. not in GC-allocated space at all + * (small number of niche examples of this) + * + * It's important we recognize case (2) up front. + * Since not allocated from GC, they don't have + * an alloc-header. + */ + log && log("disposition: not in from-space. Don't forward, but check children"); + + obj gco(lhs_iface, object_data); + gco.forward_children(gc->ref()); + + return; + } + + log && log("disposition: in from-space"); + + /** NOTE: for form's sake: + * lookup actual arena that + * allocated object data. + * Only using this to get alloc header + **/ + DArena * some_arena = this->from_space(Generation(0)); + + DArena::header_type * p_header + = some_arena->obj2hdr(object_data); + + DArena::header_type alloc_hdr = *p_header; + + /* recover allocation size */ + std::size_t alloc_z = some_arena->config_.header_.size_with_padding(alloc_hdr); + + if (log) { + log(xtag("some_arena.lo", some_arena->lo_), + xtag("p_header", p_header), + xtag("alloc_z", alloc_z)); + + AllocInfo info = this->alloc_info((std::byte *)object_data); + log(xtag("tseq", info.tseq()), + xtag("tname", TypeRegistry::id2name(typeseq(info.tseq()))), + xtag("is_forwarding_tseq", info.is_forwarding_tseq()), + xtag("age", info.age()), + xtag("size", info.size())); + } + + /* need to be able to fit forwarding pointer + * in place of forwarded object. + * + * This is guaranteed anyway, by alignment rules + */ + assert(alloc_z >= sizeof(uintptr_t)); + + if (this->is_forwarding_header(alloc_hdr)) { + /* *lhs_data already refers to a forwarding pointer */ + + /* + * lhs obj (from-space) + * | +---------+ +---+-+----+ + * \--->| .iface | |FWD|G|size| alloc_hdr + * +---------+ object_data +---+-+----+ + * | .data x----------------->| x--------\ + * +---------+ | | | dest + * | | | + * +----------+ | + * | + * (to-space) | + * +---+-+----+ | + * |TSQ|G|size| | + * +---+-+----+ | + * | | <-/ + * | | + * | | + * +----------+ + */ + void * dest = *(void**)object_data; + + *lhs_data = dest; + /* + * lhs obj + * | +---------+ + * \--->| .iface | + * +---------+ + * | .data x------------\ + * +---------+ | + * | dest + * | + * | + * | (to-space) + * | +---+-+----+ + * | |TSQ|G|size| + * | +---+-+----+ + * \---> | | + * | | + * | | + * +----------+ + */ + + if (log) { + log("lhs_data already forwarded", xtag("dest", dest)); + + AllocInfo info = this->alloc_info((std::byte *)dest); + log(xtag("tseq", info.tseq()), + xtag("tname", TypeRegistry::id2name(typeseq(info.tseq()))), + xtag("age", info.age()), xtag("size", info.size())); + } + } else if (this->_check_move_policy(alloc_hdr, object_data, upto)) { + /* copy object *lhs + replace with forwarding pointer */ + + log && log("forward object now"); + + /* + * lhs obj (from-space) + * | +---------+ +---+-+----+ + * \--->| .iface | |TSQ|G|size| alloc_hdr + * +---------+ object_data +---+-+----+ + * | .data x----------------> | | + * +---------+ | | + * | | + * +----------+ + */ + + *lhs_data = this->_shallow_move(gc->ref(), lhs_iface, *lhs_data); + + /* + * lhs obj (from-space) + * | +---------+ +---+-+----+ + * \--->| .iface | |FWD|G|SIZE| + * +---------+ +---+-+----+ + * | .data x------------\ | x--------\ + * +---------+ | | | | + * | | | | + * dest | +----------+ | + * | | + * | (to-space) | + * | +---+-+----+ | + * | |TSQ|G|size| | + * | +---+-+----+ | + * \---> | | <-/ + * | | + * | | + * +----------+ + */ + } else { + log && log("object not eligible/required to forward"); + + /* object doesn't need to move. + * e.g. incremental collection + object is tenured + */ + } + } /*_forward_inplace_aux*/ + void GCObjectStore::swap_roles(Generation upto) noexcept {