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