[K/N] Mark finalizing extra objects to avoid double finalizing

When new mark phase finished before previous finalization is done,
extra objects are still in list, which would be passed to finalize.
This could lead to unpredictable effects.

After this commit such objects are marked by new flag and ignored by
next gc runs.
This commit is contained in:
Pavel Kunyavskiy
2021-12-03 16:31:23 +03:00
committed by Space
parent ebca4d793f
commit 42aaa86f10
3 changed files with 16 additions and 12 deletions
@@ -69,10 +69,11 @@ void SweepExtraObjects(typename Traits::ExtraObjectsFactory& objectFactory) noex
auto iter = objectFactory.LockForIter();
for (auto it = iter.begin(); it != iter.end();) {
auto &extraObject = *it;
if (!Traits::IsMarkedByExtraObject(extraObject)) {
if (!extraObject.getFlag(mm::ExtraObjectData::FLAGS_IN_FINALIZER_QUEUE) && !Traits::IsMarkedByExtraObject(extraObject)) {
extraObject.ClearWeakReferenceCounter();
if (extraObject.HasAssociatedObject()) {
extraObject.DetachAssociatedObject();
extraObject.setFlag(mm::ExtraObjectData::FLAGS_IN_FINALIZER_QUEUE);
++it;
} else {
extraObject.Uninstall();
@@ -23,10 +23,11 @@ namespace mm {
// Optional data that's lazily allocated only for objects that need it.
class ExtraObjectData : private Pinned, public KonanAllocatorAware {
public:
// flags are stored as single atomic uint32, values are bit numbers in that uint32
enum Flags : uint32_t {
FLAGS_NONE = 0,
FLAGS_FROZEN = 1 << 0,
FLAGS_NEVER_FROZEN = 1 << 1,
FLAGS_FROZEN = 0,
FLAGS_NEVER_FROZEN = 1,
FLAGS_IN_FINALIZER_QUEUE = 2,
};
static constexpr unsigned WEAK_REF_TAG = 1;
@@ -49,7 +50,9 @@ public:
bool HasAssociatedObject() noexcept;
void DetachAssociatedObject() noexcept;
std::atomic<Flags>& flags() noexcept { return flags_; }
bool getFlag(Flags value) noexcept { return (flags_.load() & (1u << static_cast<uint32_t>(value))) != 0; }
void setFlag(Flags value) noexcept { flags_.fetch_or(1u << static_cast<uint32_t>(value)); }
bool HasWeakReferenceCounter() noexcept { return hasPointerBits(weakReferenceCounterOrBaseObject_.load(), WEAK_REF_TAG); }
void ClearWeakReferenceCounter() noexcept;
@@ -84,7 +87,7 @@ private:
// Must be first to match `TypeInfo` layout.
const TypeInfo* typeInfo_;
std::atomic<Flags> flags_ = FLAGS_NONE;
std::atomic<uint32_t> flags_ = 0;
#ifdef KONAN_OBJC_INTEROP
void* associatedObject_ = nullptr;
@@ -20,7 +20,7 @@ bool mm::IsFrozen(const ObjHeader* object) noexcept {
}
if (auto* extraObjectData = mm::ExtraObjectData::Get(object)) {
return (extraObjectData->flags() & mm::ExtraObjectData::FLAGS_FROZEN) != 0;
return extraObjectData->getFlag(mm::ExtraObjectData::FLAGS_FROZEN);
}
return false;
}
@@ -48,12 +48,13 @@ ObjHeader* mm::FreezeSubgraph(ObjHeader* root) noexcept {
}
for (auto* object : objects) {
if (auto* extraObjectData = mm::ExtraObjectData::Get(object)) {
if ((extraObjectData->flags() & mm::ExtraObjectData::FLAGS_NEVER_FROZEN) != 0) return object;
if (extraObjectData->getFlag(mm::ExtraObjectData::FLAGS_NEVER_FROZEN)) {
return object;
}
}
}
for (auto* object : objects) {
auto& flags = mm::ExtraObjectData::GetOrInstall(object).flags();
flags = static_cast<mm::ExtraObjectData::Flags>(flags | mm::ExtraObjectData::FLAGS_FROZEN);
mm::ExtraObjectData::GetOrInstall(object).setFlag(mm::ExtraObjectData::FLAGS_FROZEN);
}
return nullptr;
}
@@ -63,7 +64,6 @@ bool mm::EnsureNeverFrozen(ObjHeader* object) noexcept {
return false;
}
auto& flags = mm::ExtraObjectData::GetOrInstall(object).flags();
flags = static_cast<mm::ExtraObjectData::Flags>(flags | mm::ExtraObjectData::FLAGS_NEVER_FROZEN);
mm::ExtraObjectData::GetOrInstall(object).setFlag(mm::ExtraObjectData::FLAGS_NEVER_FROZEN);
return true;
}