From c6c68c0d60c92e5fd1e177479520f7fdeaaa0462 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 8 Sep 2023 14:51:48 +0000 Subject: [PATCH] Bug 1843477, add a nursery purple buffer for each cycle collector, r=mccr8 Depends on D187146 Differential Revision: https://phabricator.services.mozilla.com/D187147 --- xpcom/base/nsCycleCollector.cpp | 141 +++++++++++++------------------- xpcom/build/nsXPCOM.h | 6 -- 2 files changed, 59 insertions(+), 88 deletions(-) diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 12e7285c29f0..70681d2e1b88 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -198,33 +198,6 @@ using namespace mozilla; -struct NurseryPurpleBufferEntry { - void* mPtr; - nsCycleCollectionParticipant* mParticipant; - nsCycleCollectingAutoRefCnt* mRefCnt; -}; - -#define NURSERY_PURPLE_BUFFER_SIZE 2048 -bool gNurseryPurpleBufferEnabled = true; -NurseryPurpleBufferEntry gNurseryPurpleBufferEntry[NURSERY_PURPLE_BUFFER_SIZE]; -uint32_t gNurseryPurpleBufferEntryCount = 0; - -void ClearNurseryPurpleBuffer(); - -static void SuspectUsingNurseryPurpleBuffer( - void* aPtr, nsCycleCollectionParticipant* aCp, - nsCycleCollectingAutoRefCnt* aRefCnt) { - MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); - MOZ_ASSERT(gNurseryPurpleBufferEnabled); - if (gNurseryPurpleBufferEntryCount == NURSERY_PURPLE_BUFFER_SIZE) { - ClearNurseryPurpleBuffer(); - } - - gNurseryPurpleBufferEntry[gNurseryPurpleBufferEntryCount] = {aPtr, aCp, - aRefCnt}; - ++gNurseryPurpleBufferEntryCount; -} - // #define COLLECT_TIME_DEBUG // Enable assertions that are useful for diagnosing errors in graph @@ -878,13 +851,26 @@ static nsISupports* CanonicalizeXPCOMParticipant(nsISupports* aIn) { return out; } -struct nsPurpleBufferEntry { - nsPurpleBufferEntry(void* aObject, nsCycleCollectingAutoRefCnt* aRefCnt, - nsCycleCollectionParticipant* aParticipant) +#define NURSERY_PURPLE_BUFFER_SIZE 2048 + +struct NurseryPurpleBufferEntry { + NurseryPurpleBufferEntry() = default; + NurseryPurpleBufferEntry(void* aObject, nsCycleCollectingAutoRefCnt* aRefCnt, + nsCycleCollectionParticipant* aParticipant) : mObject(aObject), mRefCnt(aRefCnt), mParticipant(aParticipant) {} + void* mObject; + nsCycleCollectingAutoRefCnt* mRefCnt; + nsCycleCollectionParticipant* mParticipant; // nullptr for nsISupports +}; + +struct nsPurpleBufferEntry : public NurseryPurpleBufferEntry { + nsPurpleBufferEntry(void* aObject, nsCycleCollectingAutoRefCnt* aRefCnt, + nsCycleCollectionParticipant* aParticipant) + : NurseryPurpleBufferEntry(aObject, aRefCnt, aParticipant) {} + nsPurpleBufferEntry(nsPurpleBufferEntry&& aOther) - : mObject(nullptr), mRefCnt(nullptr), mParticipant(nullptr) { + : NurseryPurpleBufferEntry(nullptr, nullptr, nullptr) { Swap(aOther); } @@ -906,17 +892,13 @@ struct nsPurpleBufferEntry { mRefCnt->RemoveFromPurpleBuffer(); } } - - void* mObject; - nsCycleCollectingAutoRefCnt* mRefCnt; - nsCycleCollectionParticipant* mParticipant; // nullptr for nsISupports }; class nsCycleCollector; struct nsPurpleBuffer { private: - uint32_t mCount; + uint32_t mCount = 0; // Try to match the size of a jemalloc bucket, to minimize slop bytes. // - On 32-bit platforms sizeof(nsPurpleBufferEntry) is 12, so mEntries' @@ -931,8 +913,14 @@ struct nsPurpleBuffer { PurpleBufferVector; PurpleBufferVector mEntries; + NurseryPurpleBufferEntry + mNurseryPurpleBufferEntry[NURSERY_PURPLE_BUFFER_SIZE]; + uint32_t mNurseryPurpleBufferEntryCount = 0; + + bool mNurseryPurpleBufferEnabled = true; + public: - nsPurpleBuffer() : mCount(0) { + explicit nsPurpleBuffer() { static_assert( sizeof(PurpleBufferVector::Segment) == 16372 || // 32-bit sizeof(PurpleBufferVector::Segment) == 32760 || // 64-bit @@ -942,15 +930,14 @@ struct nsPurpleBuffer { ~nsPurpleBuffer() = default; + void DisableNurseryPurpleBuffer() { mNurseryPurpleBufferEnabled = false; } + // This method compacts mEntries. template void VisitEntries(PurpleVisitor& aVisitor) { - Maybe> ar; - if (NS_IsMainThread()) { - ar.emplace(gNurseryPurpleBufferEnabled); - gNurseryPurpleBufferEnabled = false; - ClearNurseryPurpleBuffer(); - } + AutoRestore ar(mNurseryPurpleBufferEnabled); + mNurseryPurpleBufferEnabled = false; + SuspectNurseryEntries(); if (mEntries.IsEmpty()) { return; @@ -1047,19 +1034,46 @@ struct nsPurpleBuffer { MOZ_ALWAYS_INLINE void Put(void* aObject, nsCycleCollectionParticipant* aCp, nsCycleCollectingAutoRefCnt* aRefCnt) { + if (mNurseryPurpleBufferEnabled) { + if (mNurseryPurpleBufferEntryCount == NURSERY_PURPLE_BUFFER_SIZE) { + SuspectNurseryEntries(); + } + + mNurseryPurpleBufferEntry[mNurseryPurpleBufferEntryCount] = { + aObject, aRefCnt, aCp}; + ++mNurseryPurpleBufferEntryCount; + return; + } + + PutToMainBuffer(aObject, aCp, aRefCnt); + } + + private: + MOZ_ALWAYS_INLINE void PutToMainBuffer(void* aObject, + nsCycleCollectionParticipant* aCp, + nsCycleCollectingAutoRefCnt* aRefCnt) { nsPurpleBufferEntry entry(aObject, aRefCnt, aCp); Unused << mEntries.Append(std::move(entry)); MOZ_ASSERT(!entry.mRefCnt, "Move didn't work!"); ++mCount; } + void SuspectNurseryEntries() { + while (mNurseryPurpleBufferEntryCount) { + NurseryPurpleBufferEntry& entry = + mNurseryPurpleBufferEntry[--mNurseryPurpleBufferEntryCount]; + PutToMainBuffer(entry.mObject, entry.mParticipant, entry.mRefCnt); + } + } + + public: void Remove(nsPurpleBufferEntry* aEntry) { MOZ_ASSERT(mCount != 0, "must have entries"); --mCount; aEntry->Clear(); } - uint32_t Count() const { return mCount; } + uint32_t Count() const { return mCount + mNurseryPurpleBufferEntryCount; } size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { return mEntries.SizeOfExcludingThis(aMallocSizeOf); @@ -1176,7 +1190,6 @@ class nsCycleCollector : public nsIMemoryReporter { void Suspect(void* aPtr, nsCycleCollectionParticipant* aCp, nsCycleCollectingAutoRefCnt* aRefCnt); - void SuspectNurseryEntries(); uint32_t SuspectedCount(); void ForgetSkippable(js::SliceBudget& aBudget, bool aRemoveChildlessNodes, bool aAsyncSnowWhiteFreeing); @@ -3286,15 +3299,6 @@ MOZ_ALWAYS_INLINE void nsCycleCollector::Suspect( mPurpleBuf.Put(aPtr, aParti, aRefCnt); } -void nsCycleCollector::SuspectNurseryEntries() { - MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); - while (gNurseryPurpleBufferEntryCount) { - NurseryPurpleBufferEntry& entry = - gNurseryPurpleBufferEntry[--gNurseryPurpleBufferEntryCount]; - mPurpleBuf.Put(entry.mPtr, entry.mParticipant, entry.mRefCnt); - } -} - void nsCycleCollector::CheckThreadSafety() { #ifdef DEBUG MOZ_ASSERT(mEventTarget->IsOnCurrentThread()); @@ -3701,19 +3705,13 @@ void nsCycleCollector::BeginCollection( uint32_t nsCycleCollector::SuspectedCount() { CheckThreadSafety(); - if (NS_IsMainThread()) { - return gNurseryPurpleBufferEntryCount + mPurpleBuf.Count(); - } - return mPurpleBuf.Count(); } void nsCycleCollector::Shutdown(bool aDoCollect) { CheckThreadSafety(); - if (NS_IsMainThread()) { - gNurseryPurpleBufferEnabled = false; - } + mPurpleBuf.DisableNurseryPurpleBuffer(); // Always delete snow white objects. FreeSnowWhite(true); @@ -3852,27 +3850,6 @@ void NS_CycleCollectorSuspect3(void* aPtr, nsCycleCollectionParticipant* aCp, SuspectAfterShutdown(aPtr, aCp, aRefCnt, aShouldDelete); } -void ClearNurseryPurpleBuffer() { - MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); - CollectorData* data = sCollectorData.get(); - MOZ_ASSERT(data); - MOZ_ASSERT(data->mCollector); - data->mCollector->SuspectNurseryEntries(); -} - -void NS_CycleCollectorSuspectUsingNursery(void* aPtr, - nsCycleCollectionParticipant* aCp, - nsCycleCollectingAutoRefCnt* aRefCnt, - bool* aShouldDelete) { - MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); - if (!gNurseryPurpleBufferEnabled) { - NS_CycleCollectorSuspect3(aPtr, aCp, aRefCnt, aShouldDelete); - return; - } - - SuspectUsingNurseryPurpleBuffer(aPtr, aCp, aRefCnt); -} - uint32_t nsCycleCollector_suspectedCount() { CollectorData* data = sCollectorData.get(); diff --git a/xpcom/build/nsXPCOM.h b/xpcom/build/nsXPCOM.h index a000f7b39c2f..8c3d66fd10f8 100644 --- a/xpcom/build/nsXPCOM.h +++ b/xpcom/build/nsXPCOM.h @@ -297,12 +297,6 @@ NS_CycleCollectorSuspect3(void* aPtr, nsCycleCollectionParticipant* aCp, nsCycleCollectingAutoRefCnt* aRefCnt, bool* aShouldDelete); -XPCOM_API(void) -NS_CycleCollectorSuspectUsingNursery(void* aPtr, - nsCycleCollectionParticipant* aCp, - nsCycleCollectingAutoRefCnt* aRefCnt, - bool* aShouldDelete); - #endif /**