xo-alloc: check_write_barrier to verify mutation log
This commit is contained in:
parent
e5c3d4c714
commit
3c27dfbf59
5 changed files with 133 additions and 4 deletions
|
|
@ -177,7 +177,6 @@ namespace xo {
|
|||
virtual std::byte * alloc(std::size_t z) final override;
|
||||
virtual bool check_owned(IObject * src) const final override;
|
||||
|
||||
|
||||
ArenaAlloc & operator=(const ArenaAlloc &) = delete;
|
||||
ArenaAlloc & operator=(ArenaAlloc &&) = delete;
|
||||
|
||||
|
|
|
|||
|
|
@ -337,6 +337,12 @@ namespace xo {
|
|||
* - incr GC -> if not tenured
|
||||
**/
|
||||
virtual bool check_move(IObject * src) const final override;
|
||||
/** if src is cross-generational (or cross-checkpoint), verify that it
|
||||
* is recorded in mutation log,
|
||||
* given an object @p parent that contains object pointer @p lhs
|
||||
**/
|
||||
virtual bool check_write_barrier(IObject * parent, IObject ** lhs, bool may_throw) const final;
|
||||
|
||||
virtual std::byte * alloc(std::size_t z) final override;
|
||||
virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override;
|
||||
|
||||
|
|
@ -447,7 +453,15 @@ namespace xo {
|
|||
std::vector<IObject**> gc_root_v_;
|
||||
|
||||
/** log cross-generational and cross-checkpoint mutations.
|
||||
* These need to be adjusted on next incremental collection
|
||||
* These need to be adjusted on next incremental collection.
|
||||
*
|
||||
* mutation_log_[tospace] accumulates {xgen,xckp} pointers until
|
||||
* the next GC.
|
||||
*
|
||||
* See GC aux functions
|
||||
* @ref incremental_gc_forward_mlog
|
||||
* @ref full_gc_forward_mlog
|
||||
*
|
||||
**/
|
||||
std::array<up<MutationLog>, role2int(role::N)> mutation_log_;
|
||||
/** temporary mutation log (for deferred entries) **/
|
||||
|
|
|
|||
|
|
@ -41,6 +41,13 @@ namespace xo {
|
|||
return generation::tenured;
|
||||
}
|
||||
|
||||
const char * genresult2str(generation_result x);
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & os, generation_result x) {
|
||||
os << genresult2str(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
} /*namespace gc*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -587,6 +587,104 @@ namespace xo {
|
|||
|| (this->tospace_generation_of(src) != gc::generation_result::tenured));
|
||||
}
|
||||
|
||||
bool
|
||||
GC::check_write_barrier(IObject * parent,
|
||||
IObject ** lhs,
|
||||
bool may_throw_flag) const
|
||||
{
|
||||
if (!this->contains(parent)) {
|
||||
if (may_throw_flag) {
|
||||
throw std::runtime_error(tostr("GC::check_write_barrier",
|
||||
": expected parent object P in GC to-space",
|
||||
xtag("P", parent)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t parent_z = parent->_shallow_size();
|
||||
|
||||
std::byte * parent_addr = reinterpret_cast<std::byte *>(parent);
|
||||
std::byte * lhs_addr = reinterpret_cast<std::byte *>(lhs);
|
||||
|
||||
if ((lhs_addr < parent_addr) || (parent_addr + parent_z < lhs_addr)) {
|
||||
if (may_throw_flag) {
|
||||
throw std::runtime_error
|
||||
(tostr("GC::check_write_barrier",
|
||||
": expected lhs address L within address extent z of parent P",
|
||||
xtag("P", parent), xtag("z", parent_z),
|
||||
xtag("P+z", parent_addr + parent_z),
|
||||
xtag("L", lhs)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IObject * rhs = *lhs;
|
||||
|
||||
auto parent_gen = tospace_generation_of(parent);
|
||||
auto rhs_gen = tospace_generation_of(rhs);
|
||||
|
||||
switch(parent_gen) {
|
||||
case generation_result::nursery:
|
||||
if (is_before_checkpoint(parent)) {
|
||||
switch(rhs_gen) {
|
||||
case generation_result::nursery:
|
||||
if (is_before_checkpoint(rhs)) {
|
||||
/* no mlog entry needed */
|
||||
return true;
|
||||
} else {
|
||||
/* need to check mlog */
|
||||
;
|
||||
}
|
||||
break;
|
||||
case generation_result::tenured:
|
||||
/* no mlog entry needed */
|
||||
return true;
|
||||
case generation_result::not_found:
|
||||
/* possible non-gc rhs */
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
/* no mlog entry needed */
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case generation_result::tenured:
|
||||
switch(rhs_gen) {
|
||||
case generation_result::nursery:
|
||||
/* need to check mlog */
|
||||
break;
|
||||
case generation_result::tenured:
|
||||
/* no mlog entry needed */
|
||||
return true;
|
||||
case generation_result::not_found:
|
||||
/* possible non-gc rhs */
|
||||
return true;
|
||||
}
|
||||
case generation_result::not_found:
|
||||
/* already excluded -> impossible */
|
||||
assert(false && "already verified parent owned by GC");
|
||||
}
|
||||
|
||||
/* control here -> expect mutation log entry.
|
||||
* search mutation log + verify such entry exists
|
||||
*/
|
||||
for (MutationLogEntry & mlog : *(mutation_log_[role2int(role::to_space)])) {
|
||||
if ((mlog.parent() == parent) && (mlog.lhs() == lhs)) {
|
||||
return true;
|
||||
}
|
||||
mlog.lhs();
|
||||
}
|
||||
|
||||
if (may_throw_flag) {
|
||||
throw std::runtime_error
|
||||
(tostr("GC::check_write_barrier",
|
||||
": expected mlog entry for xgen pointer L->C within parent P",
|
||||
xtag("P", parent), xtag("L", lhs), xtag("C", rhs),
|
||||
xtag("gen(P)", parent_gen), xtag("gen(C)", rhs_gen)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GC::swap_nursery()
|
||||
{
|
||||
|
|
@ -1126,9 +1224,11 @@ namespace xo {
|
|||
scope log(XO_DEBUG(config_.debug_flag_));
|
||||
|
||||
if (upto == generation::tenured) {
|
||||
this->full_gc_forward_mlog(&object_statistics_sae_[gen2int(generation::tenured)]);
|
||||
this->full_gc_forward_mlog
|
||||
(&object_statistics_sae_[gen2int(generation::tenured)]);
|
||||
} else {
|
||||
this->incremental_gc_forward_mlog(&object_statistics_sae_[gen2int(generation::nursery)]);
|
||||
this->incremental_gc_forward_mlog
|
||||
(&object_statistics_sae_[gen2int(generation::nursery)]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,15 @@ namespace xo {
|
|||
return "?generation";
|
||||
}
|
||||
|
||||
const char * genresult2str(generation_result x) {
|
||||
switch (x) {
|
||||
case generation_result::nursery: return "nursery";
|
||||
case generation_result::tenured: return "tenured";
|
||||
case generation_result::not_found: return "not-found";
|
||||
}
|
||||
return "?generation_result";
|
||||
}
|
||||
|
||||
} /*namespace gc*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue