diff --git a/include/xo/gc/DX1Collector.hpp b/include/xo/gc/DX1Collector.hpp index 5eafa80..98fc254 100644 --- a/include/xo/gc/DX1Collector.hpp +++ b/include/xo/gc/DX1Collector.hpp @@ -274,20 +274,13 @@ namespace xo { /** Execute gc immediately, for all generations < @p upto **/ void execute_gc(Generation upto) noexcept; -#ifdef OBSOLETE // replaced by visit_child() - /** Evacuate object at @p *lhs_data to to-space. - * Replace original with forwarding pointer to new location - **/ - void forward_inplace(AGCObject * lhs_iface, void ** lhs_data); -#endif - /** Supports GCObjectVisitor facet. - * During gc phase: + * During gc phase (@p reason is 'forward') * 1. evacuate object at @p *lhs_data to to-space. * 2. replace @p *lhs_data with forwarding pointer * to new location. **/ - void visit_child(AGCObject * lhs_iface, void ** lhs_data); + void visit_child(VisitReason reason, AGCObject * lhs_iface, void ** lhs_data); // ----- allocation ----- diff --git a/include/xo/gc/detail/IGCObjectVisitor_DX1Collector.hpp b/include/xo/gc/detail/IGCObjectVisitor_DX1Collector.hpp index 95534db..5c18c8e 100644 --- a/include/xo/gc/detail/IGCObjectVisitor_DX1Collector.hpp +++ b/include/xo/gc/detail/IGCObjectVisitor_DX1Collector.hpp @@ -58,7 +58,7 @@ Source must be owned by this collector. Increments object age **/ static void * alloc_copy(DX1Collector & self, std::byte * src); /** visit child of a gc-aware object. May update child in-place! **/ - static void visit_child(DX1Collector & self, AGCObject * iface, void ** pp_data) noexcept; + static void visit_child(DX1Collector & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept; ///@} }; diff --git a/src/gc/DX1Collector.cpp b/src/gc/DX1Collector.cpp index 1faebdc..63b6ef5 100644 --- a/src/gc/DX1Collector.cpp +++ b/src/gc/DX1Collector.cpp @@ -404,7 +404,7 @@ namespace xo { // - X1Collector::forward_inplace() -> _verify_aux() // - gco.visit_gco_children(self); + gco.visit_gco_children(VisitReason::verify(), self); } @@ -585,21 +585,28 @@ namespace xo { } void - DX1Collector::visit_child(AGCObject * lhs_iface, + DX1Collector::visit_child(VisitReason reason, + AGCObject * lhs_iface, void ** lhs_data) { // MAYBE: adapter distinct from DX1Collector that supports GCObjectVisitor facet, // calls DX1Collector::_verify_aux() - if (runstate_.is_running()) { + switch (reason.code()) { + case VisitReason::code::forward: + { Generation upto = runstate_.gc_upto(); // called during collection phase - gco_store_.forward_inplace_aux(this->ref(), lhs_iface, lhs_data, upto); - } else if (runstate_.is_verify()) { + gco_store_.forward_inplace_aux + (this->ref(), lhs_iface, lhs_data, upto); + break; + } + case VisitReason::code::verify: // called during verify_ok this->_verify_aux(lhs_iface, *lhs_data); - } else { + break; + default: // should be unreachable assert(false); } diff --git a/src/gc/GCObjectStore.cpp b/src/gc/GCObjectStore.cpp index 9ff067d..1f54a4c 100644 --- a/src/gc/GCObjectStore.cpp +++ b/src/gc/GCObjectStore.cpp @@ -501,7 +501,7 @@ namespace xo { log && log("disposition: not in from-space. Don't forward, but check children"); obj gco(lhs_iface, object_data); - gco.visit_gco_children(gc); + gco.visit_gco_children(VisitReason::forward(), gc); return; } @@ -714,7 +714,7 @@ namespace xo { // Nested control reenters // X1Collector::forward_inplace() -> _verify_aux() // - gco.visit_gco_children(gc); + gco.visit_gco_children(VisitReason::forward(), gc); } else { ++(p_verify_stats->n_no_iface_); continue; @@ -783,7 +783,7 @@ namespace xo { GCMoveCheckpoint gray_lo_v = this->snap_move_checkpoint(upto); - from_src.visit_gco_children(gc); + from_src.visit_gco_children(VisitReason::forward(), gc); // For each generation g: // traverse objects newer than gray_lo_v[g], to make sure children @@ -1013,7 +1013,7 @@ namespace xo { assert(iface->_has_null_vptr() == false); - iface->visit_gco_children(src, gc); + iface->visit_gco_children(src, VisitReason::forward(), gc); gray_lo_v[g] = ((std::byte *)src) + z; diff --git a/src/gc/facet/IGCObjectVisitor_DX1Collector.cpp b/src/gc/facet/IGCObjectVisitor_DX1Collector.cpp index 7a00a1f..17f364e 100644 --- a/src/gc/facet/IGCObjectVisitor_DX1Collector.cpp +++ b/src/gc/facet/IGCObjectVisitor_DX1Collector.cpp @@ -33,9 +33,9 @@ namespace xo { return self.alloc_copy(src); } auto - IGCObjectVisitor_DX1Collector::visit_child(DX1Collector & self, AGCObject * iface, void ** pp_data) noexcept -> void + IGCObjectVisitor_DX1Collector::visit_child(DX1Collector & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept -> void { - self.visit_child(iface, pp_data); + self.visit_child(reason, iface, pp_data); } } /*namespace mm*/ diff --git a/utest/DMockCollector.cpp b/utest/DMockCollector.cpp index 69f9050..6b6e920 100644 --- a/utest/DMockCollector.cpp +++ b/utest/DMockCollector.cpp @@ -21,9 +21,12 @@ namespace xo { } void - DMockCollector::visit_child(AGCObject * lhs_iface, void ** lhs_data) + DMockCollector::visit_child(VisitReason reason, AGCObject * lhs_iface, void ** lhs_data) { - p_gco_store_->forward_inplace_aux(this->ref(), lhs_iface, lhs_data, upto_); + (void)reason; + + p_gco_store_->forward_inplace_aux + (this->ref(), lhs_iface, lhs_data, upto_); } std::byte * diff --git a/utest/DMockCollector.hpp b/utest/DMockCollector.hpp index ca1c0df..3297f8f 100644 --- a/utest/DMockCollector.hpp +++ b/utest/DMockCollector.hpp @@ -26,7 +26,7 @@ namespace xo { Generation generation_of(Role r, const void * addr) const noexcept; AllocInfo alloc_info(void * mem) const noexcept; - void visit_child(AGCObject * lhs_iface, void ** lhs_data); + void visit_child(VisitReason reason, AGCObject * lhs_iface, void ** lhs_data); std::byte * alloc_copy(void * src) noexcept; private: diff --git a/utest/GCObjectStore.test.cpp b/utest/GCObjectStore.test.cpp index 552ad28..7576656 100644 --- a/utest/GCObjectStore.test.cpp +++ b/utest/GCObjectStore.test.cpp @@ -295,9 +295,10 @@ namespace ut { * 2. arena2 doesn't have concept of installed types. * It doesn't have or require any builtin ability to traverse an object model **/ - DArena arena2 = DArena::map(ArenaConfig().with_name("arena2-reference") - .with_size(tc.gc_size_ * tc.n_gen_) - .with_store_header_flag(true)); + DArena arena2 + = DArena::map(ArenaConfig().with_name("arena2-reference") + .with_size(tc.gc_size_ * tc.n_gen_) + .with_store_header_flag(true)); // object type storage will be empty unless we install a type. GCObjectStore gcos(gcos_config); @@ -325,7 +326,7 @@ namespace ut { } } - // verify basic arena partitioning + // verify basic arena partitioning + sizing { REQUIRE(g0 != g1); REQUIRE(gcos.new_space()); @@ -371,7 +372,7 @@ namespace ut { } } - // allocator + // allocator api auto alloc = obj(gcos.new_space()); // create object(s). @@ -420,6 +421,7 @@ namespace ut { REQUIRE(gcos.header2size(obj_info.header()) == obj_info.size()); REQUIRE(gcos.header2age(obj_info.header()) == object_age{0}); REQUIRE(gcos.header2tseq(obj_info.header()) == obj_info.tseq()); + REQUIRE(gcos.is_forwarding_header(obj_info.header()) == false); } // new objects appear in to-space for generation 0 @@ -441,6 +443,7 @@ namespace ut { for (size_t i = 0, n = x1_v.size(); i < n; ++i) { const auto & x1 = x1_v.at(i); + REQUIRE(gcos.contains(Role::from_space(), x1.gco_.data())); REQUIRE(gcos.contains_allocated(Role::from_space(), x1.gco_.data())); AllocInfo obj_info = gcos.alloc_info((std::byte *)x1.gco_.data()); REQUIRE(obj_info.size() >= x1.alloc_z_); @@ -578,7 +581,8 @@ namespace ut { // can still try to move something. // but will fail since type isn't registered - auto x1p_data = gcos.deep_move_root(mock_gc_visitor, x1.gco_, g1); + auto x1p_data + = gcos.deep_move_root(mock_gc_visitor, x1.gco_, g1); // control here under normal GC use // would represent a configuration fail @@ -590,10 +594,23 @@ namespace ut { // Things to test: // - deep_move_interior() // used from MutationLogStore // - forward_inplace_aux() // used from DX1Collector.visit_child - // - cleanup_phase() // used from DX1Collector._cleanup_phase // - report_object_types + // - report_object_ages() + bool sanitize_flag = true; + + // swaps to- and from- spaces again + // Now from-space will be empty, all live objects in to-space + + gcos.cleanup_phase(g1, sanitize_flag); + +#ifdef NOT_YET + gcos.verify_ok(xxx objectvisitor, + xxx &verify_stats); +#endif + + // - verify_ok } } diff --git a/utest/IGCObjectVisitor_DMockCollector.cpp b/utest/IGCObjectVisitor_DMockCollector.cpp index f447287..34a0c15 100644 --- a/utest/IGCObjectVisitor_DMockCollector.cpp +++ b/utest/IGCObjectVisitor_DMockCollector.cpp @@ -33,9 +33,9 @@ namespace xo { return self.alloc_copy(src); } auto - IGCObjectVisitor_DMockCollector::visit_child(DMockCollector & self, AGCObject * iface, void ** pp_data) noexcept -> void + IGCObjectVisitor_DMockCollector::visit_child(DMockCollector & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept -> void { - self.visit_child(iface, pp_data); + self.visit_child(reason, iface, pp_data); } } /*namespace mm*/ diff --git a/utest/IGCObjectVisitor_DMockCollector.hpp b/utest/IGCObjectVisitor_DMockCollector.hpp index ac9db2b..359972b 100644 --- a/utest/IGCObjectVisitor_DMockCollector.hpp +++ b/utest/IGCObjectVisitor_DMockCollector.hpp @@ -58,7 +58,7 @@ Source must be owned by this collector. Increments object age **/ static void * alloc_copy(DMockCollector & self, std::byte * src); /** visit child of a gc-aware object. May update child in-place! **/ - static void visit_child(DMockCollector & self, AGCObject * iface, void ** pp_data) noexcept; + static void visit_child(DMockCollector & self, VisitReason reason, AGCObject * iface, void ** pp_data) noexcept; ///@} };