diff --git a/xo-gc/include/xo/gc/DX1Collector.hpp b/xo-gc/include/xo/gc/DX1Collector.hpp index 2c149855..c72b802e 100644 --- a/xo-gc/include/xo/gc/DX1Collector.hpp +++ b/xo-gc/include/xo/gc/DX1Collector.hpp @@ -99,8 +99,17 @@ namespace xo { std::uint32_t n_to_ = 0; /** counts forwarding object encountered in to-space scan. Fatal if non-zero **/ std::uint32_t n_fwd_ = 0; - /** counts missing GCObject interface. Fatal if non-zero **/ + /** counts missing GCObject interface. Fatal if non-zero **/ std::uint32_t n_no_iface_ = 0; + /** live mlog entry refers to to-space, as expected **/ + std::uint32_t n_mlog_vital_ = 0; + /** stale mlog entry. not troubling to verify these **/ + std::uint32_t n_mlog_stale_ = 0; + /** live mlog entry refers to from-space. Fatal if non-zero **/ + std::uint32_t n_mlog_from_ = 0; + /** live mlog entry refers to either some other generation or outside gc-space. Fatal if non-zero **/ + std::uint32_t n_mlog_wild_ = 0; + }; // ----- DX1Collector ----- diff --git a/xo-gc/src/gc/DX1Collector.cpp b/xo-gc/src/gc/DX1Collector.cpp index af861f11..bdb73ff1 100644 --- a/xo-gc/src/gc/DX1Collector.cpp +++ b/xo-gc/src/gc/DX1Collector.cpp @@ -424,7 +424,7 @@ namespace xo { // child pointer validity. // // Nested control reenters - // X1Collector::forward_inplace() + // X1Collector::forward_inplace() -> _verify_aux() // gco.forward_children(self); } else { @@ -434,6 +434,49 @@ namespace xo { } } } + + // 4. scan mutation logs + for (Generation g(0); g + 1 < config_.n_generation_; ++g) { + const DArena * space = this->get_space(role::to_space(), g); + const DArena * from = this->get_space(role::from_space(), g); + + // mutation log for generation g records *incoming* pointers + // from more senior generations; includes objects from *this* + // generation that are older (track since source promotes before + // destination) + // + for (const MutationLogEntry & mrecd : *(mlog_[role::to_space()][g])) { + // mutation log entries are only valid until the next assignment + // at the source location. Superseded entry may now point + // somewhere else. The snapshot member must however point + // to this generation, since that's preserved as long as the + // log entry survives. + + void * orig_data = mrecd.snap().data(); + void * curr_data = *mrecd.p_data(); + + if (orig_data == curr_data) { + // live mlog entry must point to to-space + + if (space->contains_allocated(orig_data)) { + ++verify_stats_.n_mlog_vital_; + } else if (from->contains(curr_data)) { + // verify failure. + ++verify_stats_.n_mlog_from_; + } else { + // verify failure. + ++verify_stats_.n_mlog_wild_; + } + } else { + // requirements on superseded log entry: + // - snapshot refers to to-space + // + // no requirements on current data, entry is superseded anyway + // + ++verify_stats_.n_mlog_stale_; + } + } + } } // restore run state at end of verify cycle @@ -574,7 +617,11 @@ namespace xo { xtag("n-from", verify_stats_.n_from_), xtag("n-to", verify_stats_.n_to_), xtag("n-fwd", verify_stats_.n_fwd_), - xtag("n-no-iface", verify_stats_.n_no_iface_)); + xtag("n-no-iface", verify_stats_.n_no_iface_), + xtag("n-mlog-vital", verify_stats_.n_mlog_vital_), + xtag("n-mlog-stale", verify_stats_.n_mlog_stale_), + xtag("n-mlog-from", verify_stats_.n_mlog_from_), + xtag("n-mlog-wild", verify_stats_.n_mlog_wild_)); assert(ok); } @@ -1230,8 +1277,8 @@ namespace xo { if (src_g < dest_g) { // young-to-old pointers don't need to be remembered, - // since a GC cycle that collects the old generation is guarnatted - // to also collect the young generation. + // since a GC cycle that collects an (old) generation is guarnatted + // to also collect all younger generations. return; }