xo-gc: bugfixes. xo-gc utests pass.

This commit is contained in:
Roland Conybeare 2026-04-25 15:50:08 -04:00
commit 866ab0503d
5 changed files with 209 additions and 122 deletions

View file

@ -4,9 +4,11 @@
**/
#include "MutationLogEntry.hpp"
#include <xo/gc/GCObjectStore.hpp>
#include "GCObjectStore.hpp"
#include "MutationLogStatistics.hpp"
namespace xo {
using xo::mm::MutationLogStatistics;
using xo::reflect::typeseq;
namespace mm {
@ -19,39 +21,110 @@ namespace xo {
snap_{snap}
{}
bool
MutationLogEntry::check_forward_inplace(GCObjectStore * gcos,
MutationLogStatistics * p_counters) noexcept
{
/** Several cases here based on state of {mlog entry, parent}.
*
* 1. gc already updated P->P', C->C',
* still have snap->P, snap->C
* update P'->C', snap->P', snap->C'
* 2. gc already updated P->C to P->C'.
* still have snap->C. mlog entry is current.
* update snap->C to snap->C'
* 3. gc has not updated P->C,
* but it has (independently) evacuated C to C'.
* still have snap->C, P->C. mlog entry is current.
* update P->C' and snap->C'
* 4. gc has not moved P or C. mlog entry is up to date.
* no update. P,C may yet be rescued, or may be garbage.
* 5. P->D, D not in {C,C'}
* mlog entry has been superseded.
* Be careful of confusing this case with 1..4
**/
// if either of {parent, snapshot} has been forwarded,
// update with destination.
//
// Don't do this with child, since child might now point
// outside gc-owned space
bool upd_flag = this->check_forward_parent_inplace(gcos, p_counters);
AllocInfo snap_info = gcos->alloc_info((std::byte *)snap_.data_);
if (snap_info.is_forwarding_tseq()) {
void * snap_from = snap_.data_;
void * snap_to = *(void **)snap_.data_;
if (snap_from == *p_data_) {
// parent still refers to forwarding pointer, needs fix
*p_data_ = snap_to;
// also fix snapshot
this->snap_.reset_opaque(snap_to);
upd_flag = true;
} else if (snap_to == *p_data_) {
// parent updated, but snapshot stale
this->snap_.reset_opaque(snap_to);
upd_flag = true;
} else {
// superseded mlog entry
}
}
return upd_flag;
}
bool
MutationLogEntry::check_forward_parent_inplace(GCObjectStore * gcos,
MutationLogStatistics * p_counters) noexcept
{
AllocInfo parent_info = gcos->alloc_info((std::byte *)parent_);
if (parent_info.is_forwarding_tseq()) {
void * parent_to = *(void **)parent_;
std::size_t offset
= (std::byte *)p_data_ - (std::byte *)parent_;
void ** p_data_to = (void **)((std::byte *)parent_to + offset);
this->parent_ = parent_to;
this->p_data_ = p_data_to;
++(p_counters->n_live_parent_);
return true;
} else {
return false;
}
}
bool
MutationLogEntry::refresh_snapshot(Generation parent_gen,
GCObjectStore * gcos) noexcept
{
scope log(XO_DEBUG(gcos->config().debug_flag_));
void * child_data = *p_data_;
// note: never the same child_info as computed at the top of
// MutationLogEntry._preserve_child_of_live_parent()
// Child pointer was either forwarding pointer or moved.
// In either case must pickup info for new location.
//
AllocInfo child_info = gcos->alloc_info((std::byte*)child_data);
if (child_info.is_forwarding_tseq()) {
// code salvaged from MutationLogStore._check_keep_mutation_aux()
// as reminder. But if caller is gc will have to know this anyway,
// so it can move child
// if (info.is_forwarding_tseq()) {
// child_data = *(void **)child_data;
// info = gcos->alloc_info((std::byte *)child_data);
//}
assert(false); // for now assuming caller forward child
}
Generation child_gen_to
= gcos->generation_of(Role::to_space(), child_data);
if (child_gen_to.is_sentinel()) {
// child no longer points to gc-owned space.
// 1. may not have an alloc header (could be a static global for example),
// so AllocInfo not available
// 2. doesn't need a mutation log entry since this gc can't move destination
log && log("child not in to-space");
// unreachable, since:
// 1. not in from-space, if it were forwarded,
// caller would already have forwarded this mlog entry.
// 2. caller already confirmed mlog entry current.
// 3. would not create mlog entry for non-gc-owned child
// in any case, would be legal to discard mlog entry here.
assert(false);
snap_.data_ = nullptr; // hygiene
@ -66,6 +139,12 @@ namespace xo {
> config.promotion_threshold(child_gen_to)));
if (need_mlog_entry) {
AllocInfo child_info = gcos->alloc_info((std::byte*)child_data);
assert(!child_info.is_forwarding_tseq());
log && log("need mlog entry", xtag("tseq", child_info.tseq()));
AGCObject * iface = gcos->lookup_type(typeseq(child_info.tseq()));
if (iface) {
@ -74,11 +153,17 @@ namespace xo {
// snapshot updated, keep mlog entry
return true;
} else {
log && log("facet install error!");
// facet install error
assert(false);
return false;
}
} else {
log && log("retire mlog entry");
// retire this entry.
return false;
}