[K/N] Optimize finalizing of simple extra objects

There is no need to delay ExtraObject deletion when it doesn't have
associated object. We can just remove it while iterating on them.
This commit is contained in:
Pavel Kunyavskiy
2021-11-02 12:01:10 +03:00
committed by Space
parent ff3abf9fc0
commit b22dec062c
9 changed files with 72 additions and 39 deletions
@@ -71,9 +71,16 @@ void SweepExtraObjects(typename Traits::ExtraObjectsFactory& objectFactory) noex
auto &extraObject = *it; auto &extraObject = *it;
if (!Traits::IsMarkedByExtraObject(extraObject)) { if (!Traits::IsMarkedByExtraObject(extraObject)) {
extraObject.ClearWeakReferenceCounter(); extraObject.ClearWeakReferenceCounter();
extraObject.DetachAssociatedObject(); if (extraObject.HasAssociatedObject()) {
extraObject.DetachAssociatedObject();
++it;
} else {
extraObject.Uninstall();
objectFactory.EraseAndAdvance(it);
}
} else {
++it;
} }
++it;
} }
} }
@@ -50,6 +50,7 @@ public:
auto& extraObjectData = mm::ExtraObjectData::GetOrInstall(GetObjHeader()); auto& extraObjectData = mm::ExtraObjectData::GetOrInstall(GetObjHeader());
auto *setCounter = extraObjectData.GetOrSetWeakReferenceCounter(GetObjHeader(), counter.GetObjHeader()); auto *setCounter = extraObjectData.GetOrSetWeakReferenceCounter(GetObjHeader(), counter.GetObjHeader());
EXPECT_EQ(setCounter, counter.GetObjHeader()); EXPECT_EQ(setCounter, counter.GetObjHeader());
EXPECT_EQ(extraObjectData.GetBaseObject(), GetObjHeader());
} }
protected: protected:
@@ -340,6 +341,7 @@ TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleCharArrayWithExtraData) {
TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleObjectWithWeakCounter) { TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleObjectWithWeakCounter) {
Object weakCounter; Object weakCounter;
Object object; Object object;
weakCounter->field1 = object.header();
object.InstallWeakCounter(weakCounter); object.InstallWeakCounter(weakCounter);
auto stats = Mark({object}); auto stats = Mark({object});
@@ -352,6 +354,7 @@ TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleObjectWithWeakCounter) {
TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleObjectArrayWithWeakCounter) { TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleObjectArrayWithWeakCounter) {
Object weakCounter; Object weakCounter;
ObjectArray array; ObjectArray array;
weakCounter->field1 = array.header();
array.InstallWeakCounter(weakCounter); array.InstallWeakCounter(weakCounter);
auto stats = Mark({array}); auto stats = Mark({array});
@@ -364,6 +367,7 @@ TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleObjectArrayWithWeakCounter) {
TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleCharArrayWithWeakCounter) { TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleCharArrayWithWeakCounter) {
Object weakCounter; Object weakCounter;
CharArray array; CharArray array;
weakCounter->field1 = array.header();
array.InstallWeakCounter(weakCounter); array.InstallWeakCounter(weakCounter);
auto stats = Mark({array}); auto stats = Mark({array});
@@ -377,6 +381,7 @@ TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleObjectWithInvalidFieldsWithWeakCount
Object weakCounter; Object weakCounter;
Object object; Object object;
object->field1 = kInitializingSingleton; object->field1 = kInitializingSingleton;
weakCounter->field1 = object.header();
object.InstallWeakCounter(weakCounter); object.InstallWeakCounter(weakCounter);
auto stats = Mark({object}); auto stats = Mark({object});
@@ -390,6 +395,7 @@ TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleObjectArrayWithInvalidFieldsWithWeak
Object weakCounter; Object weakCounter;
ObjectArray array; ObjectArray array;
array.elements()[0] = kInitializingSingleton; array.elements()[0] = kInitializingSingleton;
weakCounter->field1 = array.header();
array.InstallWeakCounter(weakCounter); array.InstallWeakCounter(weakCounter);
auto stats = Mark({array}); auto stats = Mark({array});
@@ -405,6 +411,7 @@ TEST_F(MarkAndSweepUtilsMarkTest, MarkSingleCharArrayWithSomeDataWithWeakCounter
array.elements()[0] = 'a'; array.elements()[0] = 'a';
array.elements()[1] = 'b'; array.elements()[1] = 'b';
array.elements()[2] = 'c'; array.elements()[2] = 'c';
weakCounter->field1 = array.header();
array.InstallWeakCounter(weakCounter); array.InstallWeakCounter(weakCounter);
auto stats = Mark({array}); auto stats = Mark({array});
@@ -177,8 +177,7 @@ public:
~MarkAndSweepUtilsSweepTest() override { ~MarkAndSweepUtilsSweepTest() override {
auto deallocExtraObject = [this](ObjHeader* obj) { auto deallocExtraObject = [this](ObjHeader* obj) {
auto *extraObject = mm::ExtraObjectData::Get(obj); auto *extraObject = mm::ExtraObjectData::Get(obj);
EXPECT_NE(extraObject, nullptr); extraObject->Uninstall();
obj->typeInfoOrMeta_ = const_cast<TypeInfo*>(obj->type_info());
extraObjectFactory_.DestroyExtraObjectData(extraObjectFactoryThreadQueue_, *extraObject); extraObjectFactory_.DestroyExtraObjectData(extraObjectFactoryThreadQueue_, *extraObject);
extraObjectFactoryThreadQueue_.Publish(); extraObjectFactoryThreadQueue_.Publish();
}; };
@@ -223,6 +222,14 @@ public:
return objects; return objects;
} }
KStdVector<mm::ExtraObjectData*> AliveExtraObjects() {
KStdVector<mm::ExtraObjectData*> objects;
for (auto &node : extraObjectFactory_.LockForIter()) {
objects.push_back(&node);
}
return objects;
}
Object& AllocateObject(const TypeInfo* typeInfo = typeHolder.typeInfo()) { Object& AllocateObject(const TypeInfo* typeInfo = typeHolder.typeInfo()) {
auto* object = objectFactoryThreadQueue_.CreateObject(typeInfo); auto* object = objectFactoryThreadQueue_.CreateObject(typeInfo);
objectFactoryThreadQueue_.Publish(); objectFactoryThreadQueue_.Publish();
@@ -357,9 +364,9 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectWithExtraData) {
auto finalizers = Sweep(); auto finalizers = Sweep();
EXPECT_THAT(finalizers, testing::UnorderedElementsAre(object.header())); EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
EXPECT_THAT(Alive(), testing::UnorderedElementsAre()); EXPECT_THAT(Alive(), testing::UnorderedElementsAre());
EXPECT_THAT(object.state(), GC::ObjectData::State::kUnmarked); EXPECT_THAT(AliveExtraObjects(), testing::UnorderedElementsAre());
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectArrayWithExtraData) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectArrayWithExtraData) {
@@ -369,9 +376,9 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectArrayWithExtraData) {
auto finalizers = Sweep(); auto finalizers = Sweep();
EXPECT_THAT(finalizers, testing::UnorderedElementsAre(array.header())); EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
EXPECT_THAT(Alive(), testing::UnorderedElementsAre()); EXPECT_THAT(Alive(), testing::UnorderedElementsAre());
EXPECT_THAT(array.state(), GC::ObjectData::State::kUnmarked); EXPECT_THAT(AliveExtraObjects(), testing::UnorderedElementsAre());
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleCharArrayWithExtraData) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleCharArrayWithExtraData) {
@@ -381,14 +388,14 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleCharArrayWithExtraData) {
auto finalizers = Sweep(); auto finalizers = Sweep();
EXPECT_THAT(finalizers, testing::UnorderedElementsAre(array.header())); EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
EXPECT_THAT(Alive(), testing::UnorderedElementsAre()); EXPECT_THAT(Alive(), testing::UnorderedElementsAre());
EXPECT_THAT(array.state(), GC::ObjectData::State::kUnmarked); EXPECT_THAT(AliveExtraObjects(), testing::UnorderedElementsAre());
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectWithExtraData) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectWithExtraData) {
auto& object = AllocateObject(); auto& object = AllocateObject();
InstallExtraData(object.header()); auto& extra = InstallExtraData(object.header());
object.Mark(); object.Mark();
ASSERT_THAT(Alive(), testing::UnorderedElementsAre(object.header())); ASSERT_THAT(Alive(), testing::UnorderedElementsAre(object.header()));
@@ -396,12 +403,12 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectWithExtraData) {
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(AliveExtraObjects(), testing::UnorderedElementsAre(&extra));
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectArrayWithExtraData) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectArrayWithExtraData) {
auto& array = AllocateObjectArray(); auto& array = AllocateObjectArray();
InstallExtraData(array.header()); auto& extra = InstallExtraData(array.header());
array.Mark(); array.Mark();
ASSERT_THAT(Alive(), testing::UnorderedElementsAre(array.header())); ASSERT_THAT(Alive(), testing::UnorderedElementsAre(array.header()));
@@ -409,12 +416,12 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectArrayWithExtraData) {
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(AliveExtraObjects(), testing::UnorderedElementsAre(&extra));
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedCharArrayWithExtraData) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedCharArrayWithExtraData) {
auto& array = AllocateCharArray(); auto& array = AllocateCharArray();
InstallExtraData(array.header()); auto& extra = InstallExtraData(array.header());
array.Mark(); array.Mark();
ASSERT_THAT(Alive(), testing::UnorderedElementsAre(array.header())); ASSERT_THAT(Alive(), testing::UnorderedElementsAre(array.header()));
@@ -422,7 +429,7 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedCharArrayWithExtraData) {
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(AliveExtraObjects(), testing::UnorderedElementsAre(&extra));
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectWithFinalizerHook) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectWithFinalizerHook) {
@@ -457,10 +464,8 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectWithWeakCounter) {
auto finalizers = Sweep(); auto finalizers = Sweep();
EXPECT_THAT(finalizers, testing::UnorderedElementsAre(object.header())); EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
EXPECT_THAT(Alive(), testing::UnorderedElementsAre()); EXPECT_THAT(Alive(), testing::UnorderedElementsAre());
EXPECT_THAT(object.state(), GC::ObjectData::State::kUnmarked);
EXPECT_FALSE(object.HasWeakCounter());
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectArrayWithWeakCounter) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectArrayWithWeakCounter) {
@@ -470,10 +475,8 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleObjectArrayWithWeakCounter) {
auto finalizers = Sweep(); auto finalizers = Sweep();
EXPECT_THAT(finalizers, testing::UnorderedElementsAre(array.header())); EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
EXPECT_THAT(Alive(), testing::UnorderedElementsAre()); EXPECT_THAT(Alive(), testing::UnorderedElementsAre());
EXPECT_THAT(array.state(), GC::ObjectData::State::kUnmarked);
EXPECT_FALSE(array.HasWeakCounter());
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleCharArrayWithWeakCounter) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleCharArrayWithWeakCounter) {
@@ -483,10 +486,8 @@ TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleCharArrayWithWeakCounter) {
auto finalizers = Sweep(); auto finalizers = Sweep();
EXPECT_THAT(finalizers, testing::UnorderedElementsAre(array.header())); EXPECT_THAT(finalizers, testing::UnorderedElementsAre());
EXPECT_THAT(Alive(), testing::UnorderedElementsAre()); EXPECT_THAT(Alive(), testing::UnorderedElementsAre());
EXPECT_THAT(array.state(), GC::ObjectData::State::kUnmarked);
EXPECT_FALSE(array.HasWeakCounter());
} }
TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectWithWeakCounter) { TEST_F(MarkAndSweepUtilsSweepTest, SweepSingleMarkedObjectWithWeakCounter) {
@@ -160,6 +160,11 @@ public:
deletionQueue_ = std::move(remainingDeletions); deletionQueue_ = std::move(remainingDeletions);
} }
// requires LockForIter
void EraseAndAdvance(Iterator &it) {
it.position_ = queue_.erase(it.position_);
}
void ClearForTests() noexcept { void ClearForTests() noexcept {
queue_.clear(); queue_.clear();
deletionQueue_.clear(); deletionQueue_.clear();
@@ -56,20 +56,15 @@ mm::ExtraObjectData& mm::ExtraObjectData::Install(ObjHeader* object) noexcept {
return data; return data;
} }
// static void mm::ExtraObjectData::Uninstall() noexcept {
void mm::ExtraObjectData::Uninstall(ObjHeader* object) noexcept { auto *object = GetBaseObject();
RuntimeAssert(object->has_meta_object(), "Object must have a meta object set"); *const_cast<const TypeInfo**>(&object->typeInfoOrMeta_) = typeInfo_;
RuntimeAssert(!object->has_meta_object(), "Object has metaobject after removing metaobject");
auto& data = ExtraObjectData::FromMetaObjHeader(object->meta_object());
*const_cast<const TypeInfo**>(&object->typeInfoOrMeta_) = data.typeInfo_;
auto *threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
#ifdef KONAN_OBJC_INTEROP #ifdef KONAN_OBJC_INTEROP
Kotlin_ObjCExport_releaseAssociatedObject(data.associatedObject_); Kotlin_ObjCExport_releaseAssociatedObject(associatedObject_);
data.associatedObject_ = nullptr; associatedObject_ = nullptr;
#endif #endif
mm::ExtraObjectDataFactory::Instance().DestroyExtraObjectData(threadData, data);
} }
void mm::ExtraObjectData::DetachAssociatedObject() noexcept { void mm::ExtraObjectData::DetachAssociatedObject() noexcept {
@@ -78,6 +73,15 @@ void mm::ExtraObjectData::DetachAssociatedObject() noexcept {
#endif #endif
} }
bool mm::ExtraObjectData::HasAssociatedObject() noexcept {
#ifdef KONAN_OBJC_INTEROP
return associatedObject_ != nullptr;
#else
return false;
#endif
}
void mm::ExtraObjectData::ClearWeakReferenceCounter() noexcept { void mm::ExtraObjectData::ClearWeakReferenceCounter() noexcept {
if (!HasWeakReferenceCounter()) return; if (!HasWeakReferenceCounter()) return;
@@ -41,11 +41,12 @@ public:
static ExtraObjectData& GetOrInstall(ObjHeader* object) noexcept { return FromMetaObjHeader(object->meta_object()); } static ExtraObjectData& GetOrInstall(ObjHeader* object) noexcept { return FromMetaObjHeader(object->meta_object()); }
static ExtraObjectData& Install(ObjHeader* object) noexcept; static ExtraObjectData& Install(ObjHeader* object) noexcept;
static void Uninstall(ObjHeader* object) noexcept; void Uninstall() noexcept;
#ifdef KONAN_OBJC_INTEROP #ifdef KONAN_OBJC_INTEROP
void** GetAssociatedObjectLocation() noexcept { return &associatedObject_; } void** GetAssociatedObjectLocation() noexcept { return &associatedObject_; }
#endif #endif
bool HasAssociatedObject() noexcept;
void DetachAssociatedObject() noexcept; void DetachAssociatedObject() noexcept;
std::atomic<Flags>& flags() noexcept { return flags_; } std::atomic<Flags>& flags() noexcept { return flags_; }
@@ -53,6 +53,9 @@ public:
size_t GetSizeUnsafe() noexcept { return extraObjects_.GetSizeUnsafe(); } size_t GetSizeUnsafe() noexcept { return extraObjects_.GetSizeUnsafe(); }
// requires LockForIter
void EraseAndAdvance(Iterator &it) { extraObjects_.EraseAndAdvance(it); }
private: private:
Queue extraObjects_; Queue extraObjects_;
}; };
@@ -52,7 +52,8 @@ TEST_F(ExtraObjectDataTest, Install) {
EXPECT_FALSE(extraData.HasWeakReferenceCounter()); EXPECT_FALSE(extraData.HasWeakReferenceCounter());
EXPECT_THAT(extraData.GetBaseObject(), object.header()); EXPECT_THAT(extraData.GetBaseObject(), object.header());
mm::ExtraObjectData::Uninstall(object.header()); extraData.Uninstall();
mm::GlobalData::Instance().threadRegistry().CurrentThreadData()->ClearForTests();
EXPECT_FALSE(object.header()->has_meta_object()); EXPECT_FALSE(object.header()->has_meta_object());
EXPECT_THAT(object.header()->type_info(), typeInfo); EXPECT_THAT(object.header()->type_info(), typeInfo);
+5 -1
View File
@@ -82,7 +82,11 @@ MetaObjHeader* ObjHeader::createMetaObject(ObjHeader* object) {
// static // static
void ObjHeader::destroyMetaObject(ObjHeader* object) { void ObjHeader::destroyMetaObject(ObjHeader* object) {
mm::ExtraObjectData::Uninstall(object); RuntimeAssert(object->has_meta_object(), "Object must have a meta object set");
auto &extraObject = *mm::ExtraObjectData::Get(object);
extraObject.Uninstall();
auto *threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
mm::ExtraObjectDataFactory::Instance().DestroyExtraObjectData(threadData, extraObject);
} }
ALWAYS_INLINE bool isPermanentOrFrozen(const ObjHeader* obj) { ALWAYS_INLINE bool isPermanentOrFrozen(const ObjHeader* obj) {