xo-gc: use DArenaVector for DX1Collector.object_types_
Original implementation predated DArenaVector, using it is more natural
This commit is contained in:
parent
c5da97dea0
commit
890fd0fe1a
3 changed files with 92 additions and 32 deletions
|
|
@ -80,6 +80,49 @@ namespace xo {
|
|||
obj<AGCObject> * root_ = nullptr;
|
||||
};
|
||||
|
||||
/** @brief Object Interface
|
||||
*
|
||||
* GC-object interface for a particular type.
|
||||
* X1 maintains a table of these (X1Collector::object_types_)
|
||||
* indexed by typeseq.
|
||||
*
|
||||
* Using a wrapper here for searchability
|
||||
**/
|
||||
struct ObjectTypeSlot {
|
||||
ObjectTypeSlot() {}
|
||||
explicit ObjectTypeSlot(AGCObject * iface) {
|
||||
this->store_iface(iface);
|
||||
}
|
||||
|
||||
/** true iff this slot is empty **/
|
||||
bool is_null() const noexcept {
|
||||
return this->iface()->_has_null_vptr();
|
||||
}
|
||||
|
||||
bool is_occupied() const noexcept {
|
||||
return !this->is_null();
|
||||
}
|
||||
|
||||
AGCObject * iface() const noexcept {
|
||||
return std::launder((AGCObject *)&iface_[0]);
|
||||
}
|
||||
|
||||
/** Store interface pointer @p iface.
|
||||
* We just want the vtable here
|
||||
**/
|
||||
void store_iface(const AGCObject * iface) {
|
||||
::memcpy((void*)&(this->iface_[0]), (void*)iface, sizeof(AGCObject));
|
||||
}
|
||||
|
||||
private:
|
||||
/** runtime interface for this object.
|
||||
* We might prefer to declare this as AGCObject, but that's prohibited
|
||||
* since AGCObject has abstract methods.
|
||||
* Main downside of this form is it makes the data unintelligible to debugger.
|
||||
**/
|
||||
alignas(AGCObject) std::byte iface_[sizeof(AGCObject)];
|
||||
};
|
||||
|
||||
/** @brief info collected during a @ref DX1Collector::verify_ok call
|
||||
*
|
||||
**/
|
||||
|
|
@ -119,6 +162,7 @@ namespace xo {
|
|||
struct DX1Collector {
|
||||
public:
|
||||
using RootSet = DArenaVector<GCRoot>;
|
||||
using ObjectTypeTable = DArenaVector<ObjectTypeSlot>;
|
||||
/* TODO: AllocIterator pointing to free pointer instead of std::byte* */
|
||||
using GCMoveCheckpoint = std::array<std::byte *, c_max_generation>;
|
||||
using MutationLog = DArenaVector<MutationLogEntry>;
|
||||
|
|
@ -142,7 +186,7 @@ namespace xo {
|
|||
|
||||
std::string_view name() const noexcept { return config_.name_; }
|
||||
GCRunState runstate() const noexcept { return runstate_; }
|
||||
const DArena * get_object_types() const noexcept { return &object_types_; }
|
||||
const ObjectTypeTable * get_object_types() const noexcept { return &object_types_; }
|
||||
const RootSet * get_root_set() const noexcept { return &root_set_; }
|
||||
const DArena * get_space(role r, Generation g) const noexcept { return space_[r][g]; }
|
||||
DArena * get_space(role r, Generation g) noexcept { return space_[r][g]; }
|
||||
|
|
@ -409,7 +453,7 @@ namespace xo {
|
|||
/** (ab)using arena to get an extensible array of object types.
|
||||
* For each type need to store one (8-byte) IGCObject_Any instance,
|
||||
**/
|
||||
DArena object_types_;
|
||||
ObjectTypeTable object_types_;
|
||||
|
||||
/** gc disabled whenever gc_blocked_ > 0 **/
|
||||
uint32_t gc_blocked_ = 0;
|
||||
|
|
|
|||
|
|
@ -82,10 +82,10 @@ namespace xo {
|
|||
* likely << .size/8
|
||||
*/
|
||||
this->object_types_
|
||||
= DArena::map(ArenaConfig{.name_ = "x1-object-types",
|
||||
.size_ = cfg.object_types_z_,
|
||||
.hugepage_z_ = page_z,
|
||||
.store_header_flag_ = false});
|
||||
= ObjectTypeTable::map(ArenaConfig{.name_ = "x1-object-types",
|
||||
.size_ = cfg.object_types_z_,
|
||||
.hugepage_z_ = page_z,
|
||||
.store_header_flag_ = false});
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -242,7 +242,7 @@ namespace xo {
|
|||
accumulate_total_aux(const DX1Collector & d,
|
||||
size_t (DArena::* get_stat_fn)() const) noexcept
|
||||
{
|
||||
size_t z1 = (d.object_types_.*get_stat_fn)();
|
||||
size_t z1 = (d.object_types_.store()->*get_stat_fn)();
|
||||
size_t z2 = (d.root_set_.store()->*get_stat_fn)();
|
||||
|
||||
size_t z3 = 0;
|
||||
|
|
@ -424,14 +424,14 @@ namespace xo {
|
|||
bool
|
||||
DX1Collector::is_type_installed(typeseq tseq) const noexcept
|
||||
{
|
||||
if (object_types_.committed() < sizeof(AGCObject) * (tseq.seqno() + 1))
|
||||
if (tseq.is_sentinel()
|
||||
|| static_cast<ObjectTypeTable::size_type>(tseq.seqno()) > object_types_.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AGCObject * v = reinterpret_cast<AGCObject *>(object_types_.lo_);
|
||||
const ObjectTypeSlot & slot = object_types_[tseq.seqno()];
|
||||
|
||||
void * vtable = *(void **)&(v[tseq.seqno()]);
|
||||
|
||||
return (vtable != nullptr);
|
||||
return slot.is_occupied();
|
||||
}
|
||||
|
||||
AllocInfo
|
||||
|
|
@ -600,24 +600,34 @@ namespace xo {
|
|||
{
|
||||
scope log(XO_DEBUG(false));
|
||||
|
||||
AGCObject * v = reinterpret_cast<AGCObject *>(object_types_.lo_);
|
||||
if (tseq.is_sentinel()
|
||||
|| static_cast<ObjectTypeTable::size_type>(tseq.seqno()) > object_types_.size()) {
|
||||
|
||||
const AGCObject * target = &(v[tseq.seqno()]);
|
||||
log.retroactively_enable("out-of-bounds",
|
||||
xtag("tseq", tseq), xtag("tname", TypeRegistry::id2name(tseq)));
|
||||
|
||||
if (reinterpret_cast<const std::byte *>(target) >= object_types_.limit_) {
|
||||
log.retroactively_enable(xtag("tseq", tseq), xtag("tname", TypeRegistry::id2name(tseq)));
|
||||
|
||||
log(xtag("types.allocated", object_types_.allocated()),
|
||||
xtag("types.committed", object_types_.committed()),
|
||||
xtag("types.lo", object_types_.lo_),
|
||||
xtag("types.limit", object_types_.limit_),
|
||||
xtag("types.hi", object_types_.hi_));
|
||||
log(xtag("types.size", object_types_.size()),
|
||||
xtag("types.allocated", object_types_.store()->allocated()),
|
||||
xtag("types.committed", object_types_.store()->committed()),
|
||||
xtag("types.lo", object_types_.store()->lo_),
|
||||
xtag("types.limit", object_types_.store()->limit_),
|
||||
xtag("types.hi", object_types_.store()->hi_));
|
||||
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return target;
|
||||
const ObjectTypeSlot & slot = object_types_[tseq.seqno()];
|
||||
|
||||
if (slot.is_null()) {
|
||||
log.retroactively_enable("null-vtable",
|
||||
xtag("tseq", tseq), xtag("tname", TypeRegistry::id2name(tseq)));
|
||||
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return slot.iface();
|
||||
}
|
||||
|
||||
/* editor bait: register_type */
|
||||
|
|
@ -626,14 +636,20 @@ namespace xo {
|
|||
{
|
||||
typeseq tseq = meta._typeseq();
|
||||
|
||||
bool ok = object_types_.expand(sizeof(AGCObject) * (tseq.seqno() + 1));
|
||||
if (!ok)
|
||||
return false;
|
||||
assert(tseq.seqno() > 0);
|
||||
|
||||
AGCObject * v = reinterpret_cast<AGCObject *>(object_types_.lo_);
|
||||
auto ix = static_cast<ObjectTypeTable::size_type>(tseq.seqno());
|
||||
|
||||
/* explicitly copying vtable pointer here */
|
||||
std::memcpy((void*)&(v[tseq.seqno()]), (void*)&meta, sizeof(AGCObject));
|
||||
if (ix >= object_types_.size()) {
|
||||
if (!object_types_.resize(std::max(2 * object_types_.size(), ix + 1)))
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(ix < object_types_.size());
|
||||
|
||||
ObjectTypeSlot & slot = object_types_[ix];
|
||||
|
||||
slot.store_iface(&meta);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,11 +133,11 @@ namespace ut {
|
|||
{
|
||||
REQUIRE(gc.name() == "x1_test");
|
||||
|
||||
const DArena * otypes = gc.get_object_types();
|
||||
const DX1Collector::ObjectTypeTable * otypes = gc.get_object_types();
|
||||
|
||||
REQUIRE(otypes != nullptr);
|
||||
REQUIRE(otypes->reserved() >= cfg.object_types_z_);
|
||||
REQUIRE(otypes->reserved() < cfg.object_types_z_ + otypes->page_z_);
|
||||
REQUIRE(otypes->store()->reserved() >= cfg.object_types_z_);
|
||||
REQUIRE(otypes->store()->reserved() < cfg.object_types_z_ + otypes->store()->page_z_);
|
||||
|
||||
const DX1Collector::RootSet * roots = gc.get_root_set();
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ namespace ut {
|
|||
REQUIRE(to_2 == nullptr);
|
||||
|
||||
REQUIRE(gc.reserved()
|
||||
== otypes->reserved() + roots->store()->reserved() + 4 * from_0->reserved());
|
||||
== otypes->store()->reserved() + roots->store()->reserved() + 4 * from_0->reserved());
|
||||
|
||||
log && log(xtag("from_0", from_0->lo_), xtag("to_0", to_0->lo_));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue