xo-gc: + execute_gc() scaffold

This commit is contained in:
Roland Conybeare 2026-01-03 00:19:26 -05:00
commit e0cb07c9f5
9 changed files with 112 additions and 6 deletions

View file

@ -221,6 +221,22 @@ namespace xo {
**/
bool install_type(const AGCObject & meta) noexcept;
/** add GC root at @p root_addr, with type @p typeseq **/
void add_gc_root(typeseq tseq, Opaque * root_addr) noexcept;
/** Request immediate collection.
* 1. if collection is enabled, immediately collect all generations
* up to (but not including) g
* 2. may nevertheless escalate to older generations,
* depending on collector state.
* 3. if collection is currently disabled,
* collection will trigger the next time gc is enabled.
**/
void request_gc(generation upto) noexcept;
/** Execute gc immediately, for all generations < @p upto **/
void execute_gc(generation upto) noexcept;
// ----- allocation -----
/** simple allocation. allocate @p z bytes of memory
@ -269,6 +285,12 @@ namespace xo {
/** discard all allocated memory **/
void clear() noexcept;
private:
/** swap from- and to- roles for all generations < @p upto **/
void swap_roles(generation upto) noexcept;
/** copy roots + everything reachable from them, to to-space **/
void copy_roots(generation upto) noexcept;
public:
/** garbage collector configuration **/
CollectorConfig config_;
@ -281,6 +303,11 @@ namespace xo {
**/
DArena object_types_;
/** gc disabled whenever gc_blocked_ > 0 **/
uint32_t gc_blocked_ = 0;
/** if > 0: need gc for all generations < gc_pending_upto_ **/
generation gc_pending_upto_;
/** collector-managed memory here.
* - space_[1] is from-space
* - space_[0] is to-space

View file

@ -59,6 +59,16 @@ namespace xo {
virtual bool install_type(Opaque d, const AGCObject & iface) = 0;
virtual void add_gc_root(Opaque d, int32_t tseq, Opaque * root) = 0;
/** Request immediate collection.
* 1. if collection is enabled, immediately collect all generations
* up to (but not including) g
* 2. may nevertheless escalate to older generations,
* depending on collector state.
* 3. if collection is currently disabled,
* collection will trigger the next time gc is enabled.
**/
virtual void request_gc(Opaque d, generation upto) = 0;
/** evacuate @p *lhs, that refers to state with interface @p lhs_iface,
* to collector @p d's to-space. Replace *lhs_data with forwarding pointer
*

View file

@ -39,6 +39,7 @@ namespace xo {
// non-const methods
[[noreturn]] bool install_type(Opaque, const AGCObject &) noexcept override { _fatal(); }
[[noreturn]] void add_gc_root(Opaque, int32_t, Opaque *) override { _fatal(); }
[[noreturn]] void request_gc(Opaque, generation) override { _fatal(); }
[[noreturn]] void forward_inplace(Opaque, AGCObject *, void **) override { _fatal(); }
private:

View file

@ -45,6 +45,7 @@ namespace xo {
static bool install_type(DX1Collector & d, const AGCObject & iface);
static void add_gc_root(DX1Collector & d, int32_t tseq, Opaque * root);
static void request_gc(DX1Collector & d, generation upto);
static void forward_inplace(DX1Collector & d, AGCObject * lhs_iface, void ** lhs_data);
static int32_t s_typeseq;

View file

@ -53,7 +53,11 @@ namespace xo {
void add_gc_root(Opaque d, int32_t tseq, Opaque * root) override {
I::add_gc_root(_dcast(d), tseq, root);
}
void forward_inplace(Opaque d, AGCObject * lhs_iface, void ** lhs_data) override {
void request_gc(Opaque d, generation upto) override {
I::request_gc(_dcast(d), upto);
}
void forward_inplace(Opaque d,
AGCObject * lhs_iface, void ** lhs_data) override {
I::forward_inplace(_dcast(d), lhs_iface, lhs_data);
}

View file

@ -31,7 +31,7 @@ namespace xo {
bool install_type(const AGCObject & iface) { return O::iface()->install_type(O::data(), iface); }
void add_gc_root(int32_t tseq, Opaque * root) { O::iface()->add_gc_root(O::data(), tseq, root); }
void request_gc(generation g) { O::iface()->request_gc(O::data(), g); }
void forward_inplace(AGCObject * lhs_iface, void ** lhs_data) { O::iface()->forward_inplace(O::data(), lhs_iface, lhs_data); }
static bool _valid;

View file

@ -228,6 +228,65 @@ namespace xo {
return true;
}
void
DX1Collector::add_gc_root(typeseq tseq,
Opaque * root) noexcept
{
(void)tseq;
(void)root;
}
void
DX1Collector::request_gc(generation upto) noexcept
{
if (gc_blocked_ > 0) {
if (gc_pending_upto_ < upto) {
this->gc_pending_upto_ = upto;
}
/* intend collecting later */
} else {
this->execute_gc(upto);
}
}
void
DX1Collector::execute_gc(generation upto) noexcept
{
scope log(XO_DEBUG(true), xtag("upto", upto));
//auto t0 = std::chrono::steady_clock::now();
log && log("step 0a : [STUB] snapshot alloc state");
log && log("step 0b : [STUB] scan for object statistics");
log && log("step 1 : swap from/to roles");
this->swap_roles(upto);
log && log("step 2a : copy roots");
this->copy_roots(upto);
log && log("step 2b : [STUB] copy pinned");
log && log("step 3a : [STUB] run destructors");
log && log("step 3b : [STUB] keep reachable weak pointers");
log && log("step 4 : [STUB] cleanup");
}
void
DX1Collector::swap_roles(generation upto) noexcept
{
for (generation g = generation{0}; g < upto; ++g) {
std::swap(space_[role::to_space()][g], space_[role::from_space()][g]);
}
}
void
DX1Collector::copy_roots(generation upto) noexcept
{
scope log(XO_DEBUG(true), "STUB", xtag("upto", upto));
}
auto
DX1Collector::alloc(typeseq t, size_type z) noexcept -> value_type
{

View file

@ -65,11 +65,14 @@ namespace xo {
int32_t tseq,
Opaque * root)
{
(void)d;
(void)tseq;
(void)root;
d.add_gc_root(typeseq(tseq), root);
}
assert(false);
void
ICollector_DX1Collector::request_gc(DX1Collector & d,
generation upto)
{
d.request_gc(upto);
}
void

View file

@ -194,6 +194,7 @@ namespace ut {
}
/* no GC roots, so GC is trivial */
c_o.request_gc(generation{1});
} catch (std::exception & ex) {
std::cerr << "caught exception: " << ex.what() << std::endl;
REQUIRE(false);