[K/N] Simplify ObjectFactory ^KT-51436
Merge-request: KT-MR-5958 Merged-by: Alexander Shabalin <Alexander.Shabalin@jetbrains.com>
This commit is contained in:
committed by
Space
parent
4873f18067
commit
421ad77740
@@ -42,7 +42,7 @@ struct MarkTraits {
|
||||
}
|
||||
|
||||
static void enqueue(MarkQueue& queue, ObjHeader* object) noexcept {
|
||||
auto& objectData = mm::ObjectFactory<gc::ConcurrentMarkAndSweep>::NodeRef::From(object).GCObjectData();
|
||||
auto& objectData = mm::ObjectFactory<gc::ConcurrentMarkAndSweep>::NodeRef::From(object).ObjectData();
|
||||
if (objectData.color() == gc::ConcurrentMarkAndSweep::ObjectData::Color::kBlack) return;
|
||||
objectData.setColor(gc::ConcurrentMarkAndSweep::ObjectData::Color::kBlack);
|
||||
queue.push_back(object);
|
||||
@@ -56,12 +56,12 @@ struct SweepTraits {
|
||||
static bool IsMarkedByExtraObject(mm::ExtraObjectData &object) noexcept {
|
||||
auto *baseObject = object.GetBaseObject();
|
||||
if (!baseObject->heap()) return true;
|
||||
auto& objectData = mm::ObjectFactory<gc::ConcurrentMarkAndSweep>::NodeRef::From(baseObject).GCObjectData();
|
||||
auto& objectData = mm::ObjectFactory<gc::ConcurrentMarkAndSweep>::NodeRef::From(baseObject).ObjectData();
|
||||
return objectData.color() == gc::ConcurrentMarkAndSweep::ObjectData::Color::kBlack;
|
||||
}
|
||||
|
||||
static bool TryResetMark(ObjectFactory::NodeRef node) noexcept {
|
||||
auto& objectData = node.GCObjectData();
|
||||
auto& objectData = node.ObjectData();
|
||||
if (objectData.color() == gc::ConcurrentMarkAndSweep::ObjectData::Color::kWhite) return false;
|
||||
objectData.setColor(gc::ConcurrentMarkAndSweep::ObjectData::Color::kWhite);
|
||||
return true;
|
||||
|
||||
@@ -190,10 +190,10 @@ test_support::Object<Payload>& AllocateObjectWithFinalizer(mm::ThreadData& threa
|
||||
KStdVector<ObjHeader*> Alive(mm::ThreadData& threadData) {
|
||||
KStdVector<ObjHeader*> objects;
|
||||
for (auto node : threadData.gc().impl().objectFactoryThreadQueue()) {
|
||||
objects.push_back(node.IsArray() ? node.GetArrayHeader()->obj() : node.GetObjHeader());
|
||||
objects.push_back(node.GetObjHeader());
|
||||
}
|
||||
for (auto node : mm::GlobalData::Instance().gc().impl().objectFactory().LockForIter()) {
|
||||
objects.push_back(node.IsArray() ? node.GetArrayHeader()->obj() : node.GetObjHeader());
|
||||
objects.push_back(node.GetObjHeader());
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
@@ -202,7 +202,7 @@ using Color = gc::ConcurrentMarkAndSweep::ObjectData::Color;
|
||||
|
||||
Color GetColor(ObjHeader* objHeader) {
|
||||
auto nodeRef = mm::ObjectFactory<gc::ConcurrentMarkAndSweep>::NodeRef::From(objHeader);
|
||||
return nodeRef.GCObjectData().color();
|
||||
return nodeRef.ObjectData().color();
|
||||
}
|
||||
|
||||
WeakCounter& InstallWeakCounter(mm::ThreadData& threadData, ObjHeader* objHeader, ObjHeader** location) {
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
Impl(GC& gc, mm::ThreadData& threadData) noexcept :
|
||||
gcScheduler_(gc.impl_->gcScheduler().NewThreadData()),
|
||||
gc_(gc.impl_->gc(), threadData, gcScheduler_),
|
||||
objectFactoryThreadQueue_(gc.impl_->objectFactory(), gc_) {}
|
||||
objectFactoryThreadQueue_(gc.impl_->objectFactory(), gc_.CreateAllocator()) {}
|
||||
|
||||
GCSchedulerThreadData& gcScheduler() noexcept { return gcScheduler_; }
|
||||
GCImpl::ThreadData& gc() noexcept { return gc_; }
|
||||
|
||||
@@ -91,7 +91,7 @@ typename Traits::ObjectFactory::FinalizerQueue Sweep(typename Traits::ObjectFact
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
auto* objHeader = it->IsArray() ? it->GetArrayHeader()->obj() : it->GetObjHeader();
|
||||
auto* objHeader = it->GetObjHeader();
|
||||
if (HasFinalizers(objHeader)) {
|
||||
objectFactoryIter.MoveAndAdvance(finalizerQueue, it);
|
||||
} else {
|
||||
|
||||
@@ -44,7 +44,7 @@ test_support::TypeInfoHolder typeHolder{test_support::TypeInfoHolder::ObjectBuil
|
||||
test_support::TypeInfoHolder typeHolderWithFinalizer{test_support::TypeInfoHolder::ObjectBuilder<Payload>().addFlag(TF_HAS_FINALIZER)};
|
||||
test_support::TypeInfoHolder typeHolderWeakCounter{test_support::TypeInfoHolder::ObjectBuilder<WeakCounterPayload>()};
|
||||
|
||||
struct GC {
|
||||
struct ObjectFactoryTraits {
|
||||
struct ObjectData {
|
||||
enum class State {
|
||||
kUnmarked,
|
||||
@@ -55,15 +55,9 @@ struct GC {
|
||||
};
|
||||
|
||||
using Allocator = gc::AlignedAllocator;
|
||||
|
||||
struct ThreadData {
|
||||
void SafePointAllocation(size_t) {}
|
||||
void OnOOM(size_t) {}
|
||||
Allocator CreateAllocator() { return Allocator(); }
|
||||
};
|
||||
};
|
||||
|
||||
using ObjectFactory = mm::ObjectFactory<GC>;
|
||||
using ObjectFactory = mm::ObjectFactory<ObjectFactoryTraits>;
|
||||
using ExtraObjectsDataFactory = mm::ExtraObjectDataFactory;
|
||||
|
||||
class Object : public test_support::Object<Payload> {
|
||||
@@ -82,12 +76,12 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mark() { objectData().state = GC::ObjectData::State::kMarked; }
|
||||
void Mark() { objectData().state = ObjectFactoryTraits::ObjectData::State::kMarked; }
|
||||
|
||||
GC::ObjectData::State state() { return objectData().state; }
|
||||
ObjectFactoryTraits::ObjectData::State state() { return objectData().state; }
|
||||
|
||||
private:
|
||||
GC::ObjectData& objectData() { return ObjectFactory::NodeRef::From(header()).GCObjectData(); }
|
||||
ObjectFactoryTraits::ObjectData& objectData() { return ObjectFactory::NodeRef::From(header()).ObjectData(); }
|
||||
};
|
||||
|
||||
class ObjectArray : public test_support::ObjectArray<3> {
|
||||
@@ -107,12 +101,12 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mark() { objectData().state = GC::ObjectData::State::kMarked; }
|
||||
void Mark() { objectData().state = ObjectFactoryTraits::ObjectData::State::kMarked; }
|
||||
|
||||
GC::ObjectData::State state() { return objectData().state; }
|
||||
ObjectFactoryTraits::ObjectData::State state() { return objectData().state; }
|
||||
|
||||
private:
|
||||
GC::ObjectData& objectData() { return ObjectFactory::NodeRef::From(header()).GCObjectData(); }
|
||||
ObjectFactoryTraits::ObjectData& objectData() { return ObjectFactory::NodeRef::From(header()).ObjectData(); }
|
||||
};
|
||||
|
||||
class CharArray : public test_support::CharArray<3> {
|
||||
@@ -132,22 +126,22 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mark() { objectData().state = GC::ObjectData::State::kMarked; }
|
||||
void Mark() { objectData().state = ObjectFactoryTraits::ObjectData::State::kMarked; }
|
||||
|
||||
GC::ObjectData::State state() { return objectData().state; }
|
||||
ObjectFactoryTraits::ObjectData::State state() { return objectData().state; }
|
||||
|
||||
private:
|
||||
GC::ObjectData& objectData() { return ObjectFactory::NodeRef::From(header()).GCObjectData(); }
|
||||
ObjectFactoryTraits::ObjectData& objectData() { return ObjectFactory::NodeRef::From(header()).ObjectData(); }
|
||||
};
|
||||
|
||||
using WeakCounter = test_support::Object<WeakCounterPayload>;
|
||||
|
||||
void MarkWeakCounter(WeakCounter& counter) {
|
||||
ObjectFactory::NodeRef::From(counter.header()).GCObjectData().state = GC::ObjectData::State::kMarked;
|
||||
ObjectFactory::NodeRef::From(counter.header()).ObjectData().state = ObjectFactoryTraits::ObjectData::State::kMarked;
|
||||
}
|
||||
|
||||
GC::ObjectData::State GetWeakCounterState(WeakCounter& counter) {
|
||||
return ObjectFactory::NodeRef::From(counter.header()).GCObjectData().state;
|
||||
ObjectFactoryTraits::ObjectData::State GetWeakCounterState(WeakCounter& counter) {
|
||||
return ObjectFactory::NodeRef::From(counter.header()).ObjectData().state;
|
||||
}
|
||||
|
||||
struct SweepTraits {
|
||||
@@ -155,19 +149,19 @@ struct SweepTraits {
|
||||
using ExtraObjectsFactory = mm::ExtraObjectDataFactory;
|
||||
|
||||
static bool IsMarkedByExtraObject(mm::ExtraObjectData &object) noexcept {
|
||||
auto& objectData = ObjectFactory::NodeRef::From(object.GetBaseObject()).GCObjectData();
|
||||
return objectData.state != GC::ObjectData::State::kUnmarked;
|
||||
auto& objectData = ObjectFactory::NodeRef::From(object.GetBaseObject()).ObjectData();
|
||||
return objectData.state != ObjectFactoryTraits::ObjectData::State::kUnmarked;
|
||||
}
|
||||
|
||||
static bool TryResetMark(ObjectFactory::NodeRef node) {
|
||||
GC::ObjectData& objectData = node.GCObjectData();
|
||||
ObjectFactoryTraits::ObjectData& objectData = node.ObjectData();
|
||||
switch (objectData.state) {
|
||||
case GC::ObjectData::State::kUnmarked:
|
||||
case ObjectFactoryTraits::ObjectData::State::kUnmarked:
|
||||
return false;
|
||||
case GC::ObjectData::State::kMarked:
|
||||
objectData.state = GC::ObjectData::State::kMarkReset;
|
||||
case ObjectFactoryTraits::ObjectData::State::kMarked:
|
||||
objectData.state = ObjectFactoryTraits::ObjectData::State::kMarkReset;
|
||||
return true;
|
||||
case GC::ObjectData::State::kMarkReset:
|
||||
case ObjectFactoryTraits::ObjectData::State::kMarkReset:
|
||||
RuntimeFail("Trying to reset mark twice.");
|
||||
}
|
||||
}
|
||||
@@ -184,7 +178,7 @@ public:
|
||||
};
|
||||
for (auto& finalizerQueue : finalizers_) {
|
||||
for (auto node : finalizerQueue.IterForTests()) {
|
||||
auto *object = node->IsArray() ? node->GetArrayHeader()->obj() : node->GetObjHeader();
|
||||
auto *object = node->GetObjHeader();
|
||||
if (object->has_meta_object()) {
|
||||
deallocExtraObject(object);
|
||||
}
|
||||
@@ -195,7 +189,7 @@ public:
|
||||
// TODO: Figure out a better way to clear up the stuff.
|
||||
EXPECT_CALL(finalizerHook(), Call(testing::_)).Times(testing::AnyNumber());
|
||||
for (auto node : objectFactory_.LockForIter()) {
|
||||
auto* obj = node->IsArray() ? node->GetArrayHeader()->obj() : node->GetObjHeader();
|
||||
auto* obj = node->GetObjHeader();
|
||||
if (auto* extraObject = mm::ExtraObjectData::Get(obj)) {
|
||||
extraObject->ClearWeakReferenceCounter();
|
||||
deallocExtraObject(obj);
|
||||
@@ -209,7 +203,7 @@ public:
|
||||
auto finalizers = gc::Sweep<SweepTraits>(objectFactory_);
|
||||
KStdVector<ObjHeader*> objects;
|
||||
for (auto node : finalizers.IterForTests()) {
|
||||
objects.push_back(node.IsArray() ? node.GetArrayHeader()->obj() : node.GetObjHeader());
|
||||
objects.push_back(node.GetObjHeader());
|
||||
}
|
||||
finalizers_.push_back(std::move(finalizers));
|
||||
return objects;
|
||||
@@ -218,7 +212,7 @@ public:
|
||||
KStdVector<ObjHeader*> Alive() {
|
||||
KStdVector<ObjHeader*> objects;
|
||||
for (auto node : objectFactory_.LockForIter()) {
|
||||
objects.push_back(node.IsArray() ? node.GetArrayHeader()->obj() : node.GetObjHeader());
|
||||
objects.push_back(node.GetObjHeader());
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
@@ -273,9 +267,8 @@ private:
|
||||
// TODO: Provide a common base class for all unit tests that require memory initializtion.
|
||||
kotlin::ScopedMemoryInit memoryInit;
|
||||
FinalizerHooksTestSupport finalizerHooks_;
|
||||
GC::ThreadData gcThreadData_;
|
||||
ObjectFactory objectFactory_;
|
||||
ObjectFactory::ThreadQueue objectFactoryThreadQueue_{objectFactory_, gcThreadData_};
|
||||
ObjectFactory::ThreadQueue objectFactoryThreadQueue_{objectFactory_, gc::AlignedAllocator()};
|
||||
ExtraObjectsDataFactory extraObjectFactory_;
|
||||
ExtraObjectsDataFactory::ThreadQueue extraObjectFactoryThreadQueue_{extraObjectFactory_};
|
||||
KStdVector<ObjectFactory::FinalizerQueue> finalizers_;
|
||||
@@ -331,7 +324,7 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObject) {
|
||||
|
||||
EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(Alive(), testing::UnorderedElementsAre(object.header()));
|
||||
EXPECT_THAT(object.state(), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(object.state(), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
}
|
||||
|
||||
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectArray) {
|
||||
@@ -343,7 +336,7 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectArray) {
|
||||
|
||||
EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(Alive(), testing::UnorderedElementsAre(array.header()));
|
||||
EXPECT_THAT(array.state(), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(array.state(), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
}
|
||||
|
||||
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedCharArray) {
|
||||
@@ -355,7 +348,7 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedCharArray) {
|
||||
|
||||
EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(Alive(), testing::UnorderedElementsAre(array.header()));
|
||||
EXPECT_THAT(array.state(), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(array.state(), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
}
|
||||
|
||||
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectWithExtraData) {
|
||||
@@ -441,7 +434,7 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectWithFinalizerHook) {
|
||||
|
||||
EXPECT_THAT(finalizers, testing::UnorderedElementsAre(object.header()));
|
||||
EXPECT_THAT(Alive(), testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(object.state(), GC::ObjectData::State::kUnmarked);
|
||||
EXPECT_THAT(object.state(), ObjectFactoryTraits::ObjectData::State::kUnmarked);
|
||||
|
||||
EXPECT_CALL(finalizerHook(), Call(object.header()));
|
||||
}
|
||||
@@ -455,7 +448,7 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectWithFinalizerHook) {
|
||||
|
||||
EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(Alive(), testing::UnorderedElementsAre(object.header()));
|
||||
EXPECT_THAT(object.state(), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(object.state(), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
}
|
||||
|
||||
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectWithWeakCounter) {
|
||||
@@ -502,8 +495,8 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectWithWeakCounter) {
|
||||
|
||||
EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(Alive(), testing::UnorderedElementsAre(object.header(), weakCounter.header()));
|
||||
EXPECT_THAT(object.state(), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(GetWeakCounterState(weakCounter), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(object.state(), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(GetWeakCounterState(weakCounter), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
EXPECT_TRUE(object.HasWeakCounter());
|
||||
EXPECT_NE(weakCounter->referred, nullptr);
|
||||
}
|
||||
@@ -519,8 +512,8 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectArrayWithWeakCounter)
|
||||
|
||||
EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(Alive(), testing::UnorderedElementsAre(array.header(), weakCounter.header()));
|
||||
EXPECT_THAT(array.state(), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(GetWeakCounterState(weakCounter), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(array.state(), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(GetWeakCounterState(weakCounter), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
EXPECT_TRUE(array.HasWeakCounter());
|
||||
EXPECT_NE(weakCounter->referred, nullptr);
|
||||
}
|
||||
@@ -536,8 +529,8 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedCharArrayWithWeakCounter) {
|
||||
|
||||
EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(Alive(), testing::UnorderedElementsAre(array.header(), weakCounter.header()));
|
||||
EXPECT_THAT(array.state(), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(GetWeakCounterState(weakCounter), GC::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(array.state(), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
EXPECT_THAT(GetWeakCounterState(weakCounter), ObjectFactoryTraits::ObjectData::State::kMarkReset);
|
||||
EXPECT_TRUE(array.HasWeakCounter());
|
||||
EXPECT_NE(weakCounter->referred, nullptr);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
Impl(GC& gc, mm::ThreadData& threadData) noexcept :
|
||||
gcScheduler_(gc.impl_->gcScheduler().NewThreadData()),
|
||||
gc_(gc.impl_->gc(), threadData, gcScheduler_),
|
||||
objectFactoryThreadQueue_(gc.impl_->objectFactory(), gc_) {}
|
||||
objectFactoryThreadQueue_(gc.impl_->objectFactory(), gc_.CreateAllocator()) {}
|
||||
|
||||
GCSchedulerThreadData& gcScheduler() noexcept { return gcScheduler_; }
|
||||
GCImpl::ThreadData& gc() noexcept { return gc_; }
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
Impl(GC& gc, mm::ThreadData& threadData) noexcept :
|
||||
gcScheduler_(gc.impl_->gcScheduler().NewThreadData()),
|
||||
gc_(gc.impl_->gc(), threadData, gcScheduler_),
|
||||
objectFactoryThreadQueue_(gc.impl_->objectFactory(), gc_) {}
|
||||
objectFactoryThreadQueue_(gc.impl_->objectFactory(), gc_.CreateAllocator()) {}
|
||||
|
||||
GCSchedulerThreadData& gcScheduler() noexcept { return gcScheduler_; }
|
||||
GCImpl::ThreadData& gc() noexcept { return gc_; }
|
||||
|
||||
@@ -40,7 +40,7 @@ struct MarkTraits {
|
||||
}
|
||||
|
||||
static void enqueue(MarkQueue& queue, ObjHeader* object) noexcept {
|
||||
auto& objectData = mm::ObjectFactory<gc::SameThreadMarkAndSweep>::NodeRef::From(object).GCObjectData();
|
||||
auto& objectData = mm::ObjectFactory<gc::SameThreadMarkAndSweep>::NodeRef::From(object).ObjectData();
|
||||
if (objectData.color() == gc::SameThreadMarkAndSweep::ObjectData::Color::kBlack) return;
|
||||
objectData.setColor(gc::SameThreadMarkAndSweep::ObjectData::Color::kBlack);
|
||||
queue.push_back(object);
|
||||
@@ -54,12 +54,12 @@ struct SweepTraits {
|
||||
static bool IsMarkedByExtraObject(mm::ExtraObjectData &object) noexcept {
|
||||
auto *baseObject = object.GetBaseObject();
|
||||
if (!baseObject->heap()) return true;
|
||||
auto& objectData = mm::ObjectFactory<gc::SameThreadMarkAndSweep>::NodeRef::From(baseObject).GCObjectData();
|
||||
auto& objectData = mm::ObjectFactory<gc::SameThreadMarkAndSweep>::NodeRef::From(baseObject).ObjectData();
|
||||
return objectData.color() == gc::SameThreadMarkAndSweep::ObjectData::Color::kBlack;
|
||||
}
|
||||
|
||||
static bool TryResetMark(ObjectFactory::NodeRef node) noexcept {
|
||||
auto& objectData = node.GCObjectData();
|
||||
auto& objectData = node.ObjectData();
|
||||
if (objectData.color() == gc::SameThreadMarkAndSweep::ObjectData::Color::kWhite) return false;
|
||||
objectData.setColor(gc::SameThreadMarkAndSweep::ObjectData::Color::kWhite);
|
||||
return true;
|
||||
|
||||
@@ -190,10 +190,10 @@ test_support::Object<Payload>& AllocateObjectWithFinalizer(mm::ThreadData& threa
|
||||
KStdVector<ObjHeader*> Alive(mm::ThreadData& threadData) {
|
||||
KStdVector<ObjHeader*> objects;
|
||||
for (auto node : threadData.gc().impl().objectFactoryThreadQueue()) {
|
||||
objects.push_back(node.IsArray() ? node.GetArrayHeader()->obj() : node.GetObjHeader());
|
||||
objects.push_back(node.GetObjHeader());
|
||||
}
|
||||
for (auto node : mm::GlobalData::Instance().gc().impl().objectFactory().LockForIter()) {
|
||||
objects.push_back(node.IsArray() ? node.GetArrayHeader()->obj() : node.GetObjHeader());
|
||||
objects.push_back(node.GetObjHeader());
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
@@ -202,7 +202,7 @@ using Color = gc::SameThreadMarkAndSweep::ObjectData::Color;
|
||||
|
||||
Color GetColor(ObjHeader* objHeader) {
|
||||
auto nodeRef = mm::ObjectFactory<gc::SameThreadMarkAndSweep>::NodeRef::From(objHeader);
|
||||
return nodeRef.GCObjectData().color();
|
||||
return nodeRef.ObjectData().color();
|
||||
}
|
||||
|
||||
WeakCounter& InstallWeakCounter(mm::ThreadData& threadData, ObjHeader* objHeader, ObjHeader** location) {
|
||||
|
||||
@@ -93,6 +93,7 @@ struct ObjHeader {
|
||||
}
|
||||
|
||||
// Unsafe cast to ArrayHeader. Use carefully!
|
||||
// TODO: RuntimeAssert on type_info()->IsArray()?
|
||||
ArrayHeader* array() { return reinterpret_cast<ArrayHeader*>(this); }
|
||||
const ArrayHeader* array() const { return reinterpret_cast<const ArrayHeader*>(this); }
|
||||
|
||||
|
||||
@@ -427,21 +427,20 @@ private:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename GC>
|
||||
template <typename Traits>
|
||||
class ObjectFactory : private Pinned {
|
||||
using GCObjectData = typename GC::ObjectData;
|
||||
using GCThreadData = typename GC::ThreadData;
|
||||
using Allocator = typename GC::Allocator;
|
||||
using ObjectData = typename Traits::ObjectData;
|
||||
using Allocator = typename Traits::Allocator;
|
||||
|
||||
struct HeapObjHeader {
|
||||
GCObjectData gcData;
|
||||
ObjectData gcData;
|
||||
alignas(kObjectAlignment) ObjHeader object;
|
||||
};
|
||||
|
||||
// Needs to be kept compatible with `HeapObjHeader` just like `ArrayHeader` is compatible
|
||||
// with `ObjHeader`: the former can always be casted to the other.
|
||||
struct HeapArrayHeader {
|
||||
GCObjectData gcData;
|
||||
ObjectData gcData;
|
||||
alignas(kObjectAlignment) ArrayHeader array;
|
||||
};
|
||||
|
||||
@@ -470,29 +469,14 @@ public:
|
||||
|
||||
NodeRef* operator->() noexcept { return this; }
|
||||
|
||||
GCObjectData& GCObjectData() noexcept {
|
||||
ObjectData& ObjectData() noexcept {
|
||||
// `HeapArrayHeader` and `HeapObjHeader` are kept compatible, so the former can
|
||||
// be always casted to the other.
|
||||
return static_cast<HeapObjHeader*>(node_.Data())->gcData;
|
||||
}
|
||||
|
||||
bool IsArray() const noexcept {
|
||||
// `HeapArrayHeader` and `HeapObjHeader` are kept compatible, so the former can
|
||||
// be always casted to the other.
|
||||
auto* object = &static_cast<HeapObjHeader*>(node_.Data())->object;
|
||||
return object->type_info()->IsArray();
|
||||
}
|
||||
|
||||
ObjHeader* GetObjHeader() noexcept {
|
||||
auto* object = &static_cast<HeapObjHeader*>(node_.Data())->object;
|
||||
RuntimeAssert(!object->type_info()->IsArray(), "Must not be an array");
|
||||
return object;
|
||||
}
|
||||
|
||||
ArrayHeader* GetArrayHeader() noexcept {
|
||||
auto* array = &static_cast<HeapArrayHeader*>(node_.Data())->array;
|
||||
RuntimeAssert(array->type_info()->IsArray(), "Must be an array");
|
||||
return array;
|
||||
return &static_cast<HeapObjHeader*>(node_.Data())->object;
|
||||
}
|
||||
|
||||
bool operator==(const NodeRef& rhs) const noexcept { return &node_ == &rhs.node_; }
|
||||
@@ -526,7 +510,7 @@ public:
|
||||
typename Storage::Producer::Iterator iterator_;
|
||||
};
|
||||
|
||||
ThreadQueue(ObjectFactory& owner, GCThreadData& gc) noexcept : producer_(owner.storage_, gc.CreateAllocator()) {}
|
||||
ThreadQueue(ObjectFactory& owner, Allocator allocator) noexcept : producer_(owner.storage_, std::move(allocator)) {}
|
||||
|
||||
static size_t ObjectAllocatedSize(const TypeInfo* typeInfo) noexcept {
|
||||
RuntimeAssert(!typeInfo->IsArray(), "Must not be an array");
|
||||
@@ -648,7 +632,7 @@ public:
|
||||
// TODO: Consider running it in the destructor instead.
|
||||
void Finalize() noexcept {
|
||||
for (auto node : Iterable(*this)) {
|
||||
RunFinalizers(node->IsArray() ? node->GetArrayHeader()->obj() : node->GetObjHeader());
|
||||
RunFinalizers(node->GetObjHeader());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -828,25 +828,16 @@ MockAllocator::~MockAllocator() {
|
||||
// static
|
||||
MockAllocator* GlobalMockAllocator::instance_ = nullptr;
|
||||
|
||||
class GC {
|
||||
class ObjectFactoryTraits {
|
||||
public:
|
||||
struct ObjectData {
|
||||
uint32_t flags = 42;
|
||||
};
|
||||
|
||||
using Allocator = GlobalMockAllocator;
|
||||
|
||||
class ThreadData {
|
||||
public:
|
||||
void SafePointAllocation(size_t size) noexcept {}
|
||||
|
||||
void OnOOM(size_t size) noexcept {}
|
||||
|
||||
Allocator CreateAllocator() noexcept { return Allocator(); }
|
||||
};
|
||||
};
|
||||
|
||||
using ObjectFactory = mm::ObjectFactory<GC>;
|
||||
using ObjectFactory = mm::ObjectFactory<ObjectFactoryTraits>;
|
||||
|
||||
struct Payload {
|
||||
ObjHeader* field1;
|
||||
@@ -864,9 +855,8 @@ TEST(ObjectFactoryTest, CreateObject) {
|
||||
testing::StrictMock<MockAllocator> allocator;
|
||||
|
||||
test_support::TypeInfoHolder type{test_support::TypeInfoHolder::ObjectBuilder<Payload>()};
|
||||
GC::ThreadData gc;
|
||||
ObjectFactory objectFactory;
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, gc);
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, GlobalMockAllocator());
|
||||
|
||||
size_t allocSize = 0;
|
||||
void* allocAddress = nullptr;
|
||||
@@ -880,13 +870,13 @@ TEST(ObjectFactoryTest, CreateObject) {
|
||||
EXPECT_THAT(allocSize, testing::Gt<size_t>(type.typeInfo()->instanceSize_));
|
||||
EXPECT_THAT(allocAddress, testing::Ne(nullptr));
|
||||
EXPECT_THAT(mm::GetAllocatedHeapSize(object), allocSize);
|
||||
EXPECT_THAT(object->type_info(), type.typeInfo());
|
||||
|
||||
threadQueue.Publish();
|
||||
|
||||
auto node = ObjectFactory::NodeRef::From(object);
|
||||
EXPECT_FALSE(node.IsArray());
|
||||
EXPECT_THAT(node.GetObjHeader(), object);
|
||||
EXPECT_THAT(node.GCObjectData().flags, 42);
|
||||
EXPECT_THAT(node.ObjectData().flags, 42);
|
||||
|
||||
auto iter = objectFactory.LockForIter();
|
||||
auto it = iter.begin();
|
||||
@@ -900,9 +890,8 @@ TEST(ObjectFactoryTest, CreateObject) {
|
||||
TEST(ObjectFactoryTest, CreateObjectArray) {
|
||||
testing::StrictMock<MockAllocator> allocator;
|
||||
|
||||
GC::ThreadData gc;
|
||||
ObjectFactory objectFactory;
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, gc);
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, GlobalMockAllocator());
|
||||
|
||||
size_t allocSize = 0;
|
||||
void* allocAddress = nullptr;
|
||||
@@ -916,13 +905,13 @@ TEST(ObjectFactoryTest, CreateObjectArray) {
|
||||
EXPECT_THAT(allocSize, testing::Gt<size_t>(-theArrayTypeInfo->instanceSize_ * 3));
|
||||
EXPECT_THAT(allocAddress, testing::Ne(nullptr));
|
||||
EXPECT_THAT(mm::GetAllocatedHeapSize(array->obj()), allocSize);
|
||||
EXPECT_THAT(array->type_info(), theArrayTypeInfo);
|
||||
|
||||
threadQueue.Publish();
|
||||
|
||||
auto node = ObjectFactory::NodeRef::From(array);
|
||||
EXPECT_TRUE(node.IsArray());
|
||||
EXPECT_THAT(node.GetArrayHeader(), array);
|
||||
EXPECT_THAT(node.GCObjectData().flags, 42);
|
||||
EXPECT_THAT(node.GetObjHeader()->array(), array);
|
||||
EXPECT_THAT(node.ObjectData().flags, 42);
|
||||
|
||||
auto iter = objectFactory.LockForIter();
|
||||
auto it = iter.begin();
|
||||
@@ -936,9 +925,8 @@ TEST(ObjectFactoryTest, CreateObjectArray) {
|
||||
TEST(ObjectFactoryTest, CreateCharArray) {
|
||||
testing::StrictMock<MockAllocator> allocator;
|
||||
|
||||
GC::ThreadData gc;
|
||||
ObjectFactory objectFactory;
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, gc);
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, GlobalMockAllocator());
|
||||
|
||||
size_t allocSize = 0;
|
||||
void* allocAddress = nullptr;
|
||||
@@ -952,13 +940,13 @@ TEST(ObjectFactoryTest, CreateCharArray) {
|
||||
EXPECT_THAT(allocSize, testing::Gt<size_t>(-theCharArrayTypeInfo->instanceSize_ * 3));
|
||||
EXPECT_THAT(allocAddress, testing::Ne(nullptr));
|
||||
EXPECT_THAT(mm::GetAllocatedHeapSize(array->obj()), allocSize);
|
||||
EXPECT_THAT(array->type_info(), theCharArrayTypeInfo);
|
||||
|
||||
threadQueue.Publish();
|
||||
|
||||
auto node = ObjectFactory::NodeRef::From(array);
|
||||
EXPECT_TRUE(node.IsArray());
|
||||
EXPECT_THAT(node.GetArrayHeader(), array);
|
||||
EXPECT_THAT(node.GCObjectData().flags, 42);
|
||||
EXPECT_THAT(node.GetObjHeader()->array(), array);
|
||||
EXPECT_THAT(node.ObjectData().flags, 42);
|
||||
|
||||
auto iter = objectFactory.LockForIter();
|
||||
auto it = iter.begin();
|
||||
@@ -973,9 +961,8 @@ TEST(ObjectFactoryTest, Erase) {
|
||||
testing::StrictMock<MockAllocator> allocator;
|
||||
|
||||
test_support::TypeInfoHolder objectType{test_support::TypeInfoHolder::ObjectBuilder<Payload>()};
|
||||
GC::ThreadData gc;
|
||||
ObjectFactory objectFactory;
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, gc);
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, GlobalMockAllocator());
|
||||
|
||||
EXPECT_CALL(allocator, Alloc(_, _)).Times(20);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
@@ -989,7 +976,7 @@ TEST(ObjectFactoryTest, Erase) {
|
||||
{
|
||||
auto iter = objectFactory.LockForIter();
|
||||
for (auto it = iter.begin(); it != iter.end();) {
|
||||
if (it->IsArray()) {
|
||||
if (it->GetObjHeader()->type_info()->IsArray()) {
|
||||
EXPECT_CALL(allocator, Free(_));
|
||||
iter.EraseAndAdvance(it);
|
||||
testing::Mock::VerifyAndClearExpectations(&allocator);
|
||||
@@ -1003,7 +990,7 @@ TEST(ObjectFactoryTest, Erase) {
|
||||
auto iter = objectFactory.LockForIter();
|
||||
int count = 0;
|
||||
for (auto it = iter.begin(); it != iter.end(); ++it, ++count) {
|
||||
EXPECT_FALSE(it->IsArray());
|
||||
EXPECT_FALSE(it->GetObjHeader()->type_info()->IsArray());
|
||||
}
|
||||
EXPECT_THAT(count, 10);
|
||||
}
|
||||
@@ -1014,9 +1001,8 @@ TEST(ObjectFactoryTest, Move) {
|
||||
testing::StrictMock<MockAllocator> allocator;
|
||||
|
||||
test_support::TypeInfoHolder objectType{test_support::TypeInfoHolder::ObjectBuilder<Payload>()};
|
||||
GC::ThreadData gc;
|
||||
ObjectFactory objectFactory;
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, gc);
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, GlobalMockAllocator());
|
||||
ObjectFactory::FinalizerQueue finalizerQueue;
|
||||
|
||||
EXPECT_CALL(allocator, Alloc(_, _)).Times(20);
|
||||
@@ -1031,7 +1017,7 @@ TEST(ObjectFactoryTest, Move) {
|
||||
{
|
||||
auto iter = objectFactory.LockForIter();
|
||||
for (auto it = iter.begin(); it != iter.end();) {
|
||||
if (it->IsArray()) {
|
||||
if (it->GetObjHeader()->type_info()->IsArray()) {
|
||||
iter.MoveAndAdvance(finalizerQueue, it);
|
||||
} else {
|
||||
++it;
|
||||
@@ -1043,7 +1029,7 @@ TEST(ObjectFactoryTest, Move) {
|
||||
auto iter = objectFactory.LockForIter();
|
||||
int count = 0;
|
||||
for (auto it = iter.begin(); it != iter.end(); ++it, ++count) {
|
||||
EXPECT_FALSE(it->IsArray());
|
||||
EXPECT_FALSE(it->GetObjHeader()->type_info()->IsArray());
|
||||
}
|
||||
EXPECT_THAT(count, 10);
|
||||
}
|
||||
@@ -1052,7 +1038,7 @@ TEST(ObjectFactoryTest, Move) {
|
||||
int count = 0;
|
||||
auto iter = finalizerQueue.IterForTests();
|
||||
for (auto it = iter.begin(); it != iter.end(); ++it, ++count) {
|
||||
EXPECT_TRUE(it->IsArray());
|
||||
EXPECT_TRUE(it->GetObjHeader()->type_info()->IsArray());
|
||||
}
|
||||
EXPECT_THAT(count, 10);
|
||||
}
|
||||
@@ -1066,9 +1052,8 @@ TEST(ObjectFactoryTest, RunFinalizers) {
|
||||
FinalizerHooksTestSupport finalizerHooks;
|
||||
|
||||
test_support::TypeInfoHolder objectType{test_support::TypeInfoHolder::ObjectBuilder<Payload>().addFlag(TF_HAS_FINALIZER)};
|
||||
GC::ThreadData gc;
|
||||
ObjectFactory objectFactory;
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, gc);
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, GlobalMockAllocator());
|
||||
ObjectFactory::FinalizerQueue finalizerQueue;
|
||||
|
||||
KStdVector<ObjHeader*> objects;
|
||||
@@ -1111,8 +1096,7 @@ TEST(ObjectFactoryTest, ConcurrentPublish) {
|
||||
EXPECT_CALL(allocator, Alloc(_, _)).Times(kThreadCount);
|
||||
for (int i = 0; i < kThreadCount; ++i) {
|
||||
threads.emplace_back([&type, &objectFactory, &canStart, &readyCount, &expected, &expectedMutex]() {
|
||||
GC::ThreadData gc;
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, gc);
|
||||
ObjectFactory::ThreadQueue threadQueue(objectFactory, GlobalMockAllocator());
|
||||
auto* object = threadQueue.CreateObject(type.typeInfo());
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(expectedMutex);
|
||||
|
||||
Reference in New Issue
Block a user