xo-gc xo-object2: gc bugfixes and logging [WORKING]
This commit is contained in:
parent
84adc35aec
commit
c739fba5eb
4 changed files with 135 additions and 20 deletions
|
|
@ -293,6 +293,9 @@ namespace xo {
|
|||
log && log("step 1 : swap from/to roles");
|
||||
this->swap_roles(upto);
|
||||
|
||||
log && log(xtag("from_0", get_space(role::from_space(), generation{0})->lo_),
|
||||
xtag("to_0", get_space(role::to_space(), generation{0})->lo_));
|
||||
|
||||
log && log("step 2a : copy roots");
|
||||
this->copy_roots(upto);
|
||||
|
||||
|
|
@ -305,7 +308,11 @@ namespace xo {
|
|||
void
|
||||
DX1Collector::swap_roles(generation upto) noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(true), xtag("upto", upto));
|
||||
|
||||
for (generation g = generation{0}; g < upto; ++g) {
|
||||
log && log("swap roles", xtag("g", g));
|
||||
|
||||
std::swap(space_[role::to_space()][g], space_[role::from_space()][g]);
|
||||
}
|
||||
}
|
||||
|
|
@ -345,6 +352,7 @@ namespace xo {
|
|||
*
|
||||
* Coordinates with forward_inplace()
|
||||
*/
|
||||
log && log("disposition: already forwarded");
|
||||
|
||||
return *(void **)from_src;
|
||||
}
|
||||
|
|
@ -353,6 +361,8 @@ namespace xo {
|
|||
|
||||
if (!this->check_move_policy(hdr, from_src)) {
|
||||
/* object at from_src in generation that is not being collected */
|
||||
log && log("disposition: not moving from_src");
|
||||
|
||||
return from_src;
|
||||
}
|
||||
|
||||
|
|
@ -418,6 +428,8 @@ namespace xo {
|
|||
*
|
||||
**/
|
||||
|
||||
log && log("disposition: move subtree");
|
||||
|
||||
/* TODO: AllocIterator pointing to free pointer */
|
||||
std::array<std::byte *, c_max_generation> gray_lo_v;
|
||||
{
|
||||
|
|
@ -462,16 +474,24 @@ namespace xo {
|
|||
}
|
||||
} while (fixup_work > 0);
|
||||
|
||||
log && log(xtag("to_dest", to_dest));
|
||||
|
||||
return to_dest;
|
||||
}
|
||||
|
||||
void
|
||||
DX1Collector::copy_roots(generation upto) noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
for (obj<AGCObject> ** p_root = (obj<AGCObject> **)roots_.lo_;
|
||||
p_root < (obj<AGCObject> **)roots_.free_; ++p_root)
|
||||
{
|
||||
log && log("copy root", xtag("**p_root.data.pre", (**p_root).data_));
|
||||
|
||||
(*p_root)->reset_opaque(this->deep_move((*p_root)->data_, upto));
|
||||
|
||||
log && log(xtag("**p_root.data.post", (**p_root).data_));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -479,6 +499,10 @@ namespace xo {
|
|||
DX1Collector::forward_inplace(AGCObject * lhs_iface,
|
||||
void ** lhs_data)
|
||||
{
|
||||
scope log(XO_DEBUG(config_.debug_flag_),
|
||||
xtag("lhs_data", lhs_data),
|
||||
xtag("*lhs_data", *lhs_data));
|
||||
|
||||
/* coordinates with DX1Collector::_deep_move() */
|
||||
|
||||
(void)lhs_iface;
|
||||
|
|
@ -497,28 +521,31 @@ namespace xo {
|
|||
* +----------+
|
||||
*/
|
||||
|
||||
void * object_data = (std::byte *)lhs_data;
|
||||
void * object_data = (std::byte *)*lhs_data;
|
||||
|
||||
if (!this->contains(role::from_space(), object_data)) {
|
||||
/* *lhs isn't in GC-allocated space.
|
||||
/* *lhs_data either:
|
||||
* 1. already in to-space
|
||||
* 2. not in GC-allocated space at all
|
||||
* (small number of niche examples of this)
|
||||
*
|
||||
* This happens for a modest number of global
|
||||
* constants, for example DBoolean {true, false}.
|
||||
*
|
||||
* It's important we recognize these up front.
|
||||
* 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");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
log && log("disposition: in from-space");
|
||||
|
||||
/** NOTE: for form's sake:
|
||||
* better to lookup actual arena that
|
||||
* lookup actual arena that
|
||||
* allocated object data.
|
||||
* Only using this to get alloc header
|
||||
*
|
||||
**/
|
||||
DArena * some_arena = this->to_space(generation(0));
|
||||
DArena * some_arena = this->from_space(generation(0));
|
||||
|
||||
DArena::header_type * p_header
|
||||
= some_arena->obj2hdr(object_data);
|
||||
|
|
@ -528,37 +555,96 @@ namespace xo {
|
|||
/* recover allocation size */
|
||||
std::size_t alloc_z = some_arena->config_.header_.size_with_padding(alloc_hdr);
|
||||
|
||||
log && log(xtag("some_arena.lo", some_arena->lo_),
|
||||
xtag("p_header", p_header),
|
||||
xtag("alloc_z", alloc_z));
|
||||
|
||||
/* 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));
|
||||
assert(alloc_z >= sizeof(uintptr_t));
|
||||
|
||||
if (this->is_forwarding_header(alloc_hdr)) {
|
||||
/* *lhs already refers to a forwarding pointer */
|
||||
/* *lhs_data already refers to a forwarding pointer */
|
||||
|
||||
/*
|
||||
* lhs obj<AGCObject>
|
||||
* lhs obj<AGCObject> (from-space)
|
||||
* | +---------+ +---+-+----+
|
||||
* \--->| .iface | |FWD|G|size| alloc_hdr
|
||||
* +---------+ object_data +---+-+----+
|
||||
* | .data x----------------->| x-------->
|
||||
* +---------+ | | dest
|
||||
* | .data x----------------->| x--------\
|
||||
* +---------+ | | | dest
|
||||
* | | |
|
||||
* +----------+ |
|
||||
* |
|
||||
* (to-space) |
|
||||
* +---+-+----+ |
|
||||
* |FWD|G|size|<--/
|
||||
* +---+-+----+
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* +----------+
|
||||
*/
|
||||
void * dest = *(void**)object_data;
|
||||
|
||||
/* update *lhs in-place */
|
||||
*lhs_data = dest;
|
||||
/*
|
||||
* lhs obj<AGCObject>
|
||||
* | +---------+
|
||||
* \--->| .iface |
|
||||
* +---------+
|
||||
* | .data x------------\
|
||||
* +---------+ |
|
||||
* | dest
|
||||
* |
|
||||
* |
|
||||
* | (to-space)
|
||||
* | +---+-+----+
|
||||
* \---->|FWD|G|size|
|
||||
* +---+-+----+
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* +----------+
|
||||
*/
|
||||
} else if (this->check_move_policy(alloc_hdr, object_data)) {
|
||||
/* copy object *lhs + replace with forwarding pointer */
|
||||
|
||||
/* which arena are we writing to? need allocator interface */
|
||||
/*
|
||||
* lhs obj<AGCObject> (from-space)
|
||||
* | +---------+ +---+-+----+
|
||||
* \--->| .iface | |FWD|G|size| alloc_hdr
|
||||
* +---------+ object_data +---+-+----+
|
||||
* | .data x----------------->| |
|
||||
* +---------+ | |
|
||||
* | |
|
||||
* +----------+
|
||||
*/
|
||||
|
||||
*lhs_data = this->shallow_move(lhs_iface, *lhs_data);
|
||||
|
||||
/*
|
||||
* lhs obj<AGCObject> (from-space)
|
||||
* | +---------+ +---+-+----+
|
||||
* \--->| .iface | |FWD|G|SIZE|
|
||||
* +---------+ +---+-+----+
|
||||
* | .data x------------\ | x--------\
|
||||
* +---------+ | | | |
|
||||
* | | | |
|
||||
* dest | +----------+ |
|
||||
* | |
|
||||
* | (to-space) |
|
||||
* | +---+-+----+ |
|
||||
* \---->|FWD|G|size|<--/
|
||||
* +---+-+----+
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* +----------+
|
||||
*/
|
||||
} else {
|
||||
/* object doesn't need to move.
|
||||
* e.g. incremental collection + object is tenured
|
||||
|
|
@ -569,11 +655,15 @@ namespace xo {
|
|||
void *
|
||||
DX1Collector::shallow_move(const AGCObject * iface, void * from_src)
|
||||
{
|
||||
scope log(XO_DEBUG(config_.debug_flag_));
|
||||
|
||||
AllocInfo info = this->alloc_info((std::byte *)from_src);
|
||||
obj<AAllocator, DX1Collector> alloc(this);
|
||||
|
||||
void * to_dest = iface->shallow_copy(from_src, alloc);
|
||||
|
||||
log && log(xtag("from_src", from_src), xtag("to_dest", to_dest));
|
||||
|
||||
if(to_dest == from_src) {
|
||||
assert(false);
|
||||
} else {
|
||||
|
|
@ -699,7 +789,7 @@ namespace xo {
|
|||
DX1Collector::reverse_roles(generation g) noexcept {
|
||||
assert(g < config_.n_generation_);
|
||||
|
||||
std::swap(space_[0][g], space_[1][g]);
|
||||
std::swap(space_[role::from_space()][g], space_[role::to_space()][g]);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace xo {
|
|||
bool
|
||||
DList::is_empty() const noexcept
|
||||
{
|
||||
return this != &s_null;
|
||||
return this == &s_null;
|
||||
}
|
||||
|
||||
auto
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
**/
|
||||
|
||||
#include "IGCObject_DList.hpp"
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
|
||||
namespace xo {
|
||||
using xo::mm::AGCObject;
|
||||
|
|
@ -36,6 +37,8 @@ namespace xo {
|
|||
IGCObject_DList::forward_children(DList & src,
|
||||
obj<ACollector> gc) noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
gc.forward_inplace(src.head_.iface(), (void **)&(src.head_.data_));
|
||||
|
||||
auto iface = xo::facet::impl_for<AGCObject, DList>();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
#include <xo/alloc2/AllocInfo.hpp>
|
||||
#include <xo/alloc2/padding.hpp>
|
||||
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
#include <xo/indentlog/print/tag.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace ut {
|
||||
|
|
@ -39,6 +42,8 @@ namespace ut {
|
|||
using xo::mm::padding;
|
||||
using xo::facet::with_facet;
|
||||
using xo::facet::typeseq;
|
||||
using xo::scope;
|
||||
using xo::xtag;
|
||||
|
||||
namespace {
|
||||
struct testcase_x1 {
|
||||
|
|
@ -69,6 +74,9 @@ namespace ut {
|
|||
|
||||
TEST_CASE("x1", "[gc][x1]")
|
||||
{
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag));
|
||||
|
||||
for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) {
|
||||
try {
|
||||
const testcase_x1 & tc = s_testcase_v[i_tc];
|
||||
|
|
@ -82,6 +90,7 @@ namespace ut {
|
|||
.gc_trigger_v_{{
|
||||
tc.incr_gc_threshold_,
|
||||
tc.full_gc_threshold_}},
|
||||
.debug_flag_ = c_debug_flag,
|
||||
};
|
||||
|
||||
DX1Collector gc(cfg);
|
||||
|
|
@ -140,6 +149,8 @@ namespace ut {
|
|||
|
||||
REQUIRE(gc.reserved_total()
|
||||
== otypes->reserved() + roots->reserved() + 4 * from_0->reserved());
|
||||
|
||||
log && log(xtag("from_0", from_0->lo_), xtag("to_0", to_0->lo_));
|
||||
}
|
||||
|
||||
/* attempt allocation */
|
||||
|
|
@ -197,11 +208,22 @@ namespace ut {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* no GC roots, so GC is trivial */
|
||||
c_o.request_gc(generation{1});
|
||||
|
||||
log && log(xtag("l0_o.data()", l0_o.data()));
|
||||
log && log(xtag("l0_o.data()->head_.data()", l0_o.data()->head_.data()));
|
||||
log && log(xtag("x0_o.data()", x0_o.data()));
|
||||
|
||||
REQUIRE(!gc.contains(role::from_space(), x0_o.data()));
|
||||
REQUIRE(gc.contains(role::to_space(), x0_o.data()));
|
||||
REQUIRE(x0_o.data()->value() == 3.1415927);
|
||||
REQUIRE(!gc.contains(role::from_space(), l0_o.data()));
|
||||
REQUIRE(gc.contains(role::to_space(), l0_o.data()));
|
||||
REQUIRE(l0_o.data()->is_empty() == false);
|
||||
|
||||
REQUIRE((void*)l0_o.data()->head_.data() == (void*)x0_o.data());
|
||||
|
||||
} catch (std::exception & ex) {
|
||||
std::cerr << "caught exception: " << ex.what() << std::endl;
|
||||
REQUIRE(false);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue