зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1391423, add a nursery for purple buffer to allow faster addref/release on the main thread, r=mccr8
--HG-- extra : rebase_source : 4dcb8af2d3f2518ab0fd00b65fbf1d0096d8e810
This commit is contained in:
Родитель
f11a1c6fda
Коммит
6e1dc494d2
|
@ -2144,9 +2144,9 @@ NS_INTERFACE_MAP_BEGIN(FragmentOrElement)
|
|||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(FragmentOrElement)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(FragmentOrElement,
|
||||
nsNodeUtils::LastRelease(this))
|
||||
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(FragmentOrElement)
|
||||
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(FragmentOrElement,
|
||||
nsNodeUtils::LastRelease(this))
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -197,6 +197,35 @@
|
|||
|
||||
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();
|
||||
|
||||
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 construction.
|
||||
|
@ -1039,6 +1068,13 @@ public:
|
|||
template<class PurpleVisitor>
|
||||
void VisitEntries(PurpleVisitor& aVisitor)
|
||||
{
|
||||
Maybe<AutoRestore<bool>> ar;
|
||||
if (NS_IsMainThread()) {
|
||||
ar.emplace(gNurseryPurpleBufferEnabled);
|
||||
gNurseryPurpleBufferEnabled = false;
|
||||
ClearNurseryPurpleBuffer();
|
||||
}
|
||||
|
||||
if (mEntries.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1289,6 +1325,7 @@ public:
|
|||
|
||||
void Suspect(void* aPtr, nsCycleCollectionParticipant* aCp,
|
||||
nsCycleCollectingAutoRefCnt* aRefCnt);
|
||||
void SuspectNurseryEntries();
|
||||
uint32_t SuspectedCount();
|
||||
void ForgetSkippable(js::SliceBudget& aBudget, bool aRemoveChildlessNodes,
|
||||
bool aAsyncSnowWhiteFreeing);
|
||||
|
@ -3491,6 +3528,17 @@ nsCycleCollector::Suspect(void* aPtr, nsCycleCollectionParticipant* aParti,
|
|||
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()
|
||||
{
|
||||
|
@ -3893,6 +3941,10 @@ uint32_t
|
|||
nsCycleCollector::SuspectedCount()
|
||||
{
|
||||
CheckThreadSafety();
|
||||
if (NS_IsMainThread()) {
|
||||
return gNurseryPurpleBufferEntryCount + mPurpleBuf.Count();
|
||||
}
|
||||
|
||||
return mPurpleBuf.Count();
|
||||
}
|
||||
|
||||
|
@ -3901,6 +3953,10 @@ nsCycleCollector::Shutdown(bool aDoCollect)
|
|||
{
|
||||
CheckThreadSafety();
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
gNurseryPurpleBufferEnabled = false;
|
||||
}
|
||||
|
||||
// Always delete snow white objects.
|
||||
FreeSnowWhite(true);
|
||||
|
||||
|
@ -4038,6 +4094,30 @@ 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()
|
||||
{
|
||||
|
|
|
@ -190,6 +190,12 @@ do { \
|
|||
class nsCycleCollectingAutoRefCnt
|
||||
{
|
||||
public:
|
||||
|
||||
typedef void (*Suspect)(void* aPtr,
|
||||
nsCycleCollectionParticipant* aCp,
|
||||
nsCycleCollectingAutoRefCnt* aRefCnt,
|
||||
bool* aShouldDelete);
|
||||
|
||||
nsCycleCollectingAutoRefCnt() : mRefCntAndFlags(0) {}
|
||||
|
||||
explicit nsCycleCollectingAutoRefCnt(uintptr_t aValue)
|
||||
|
@ -200,11 +206,13 @@ public:
|
|||
nsCycleCollectingAutoRefCnt(const nsCycleCollectingAutoRefCnt&) = delete;
|
||||
void operator=(const nsCycleCollectingAutoRefCnt&) = delete;
|
||||
|
||||
template<Suspect suspect = NS_CycleCollectorSuspect3>
|
||||
MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports* aOwner)
|
||||
{
|
||||
return incr(aOwner, nullptr);
|
||||
return incr<suspect>(aOwner, nullptr);
|
||||
}
|
||||
|
||||
template<Suspect suspect = NS_CycleCollectorSuspect3>
|
||||
MOZ_ALWAYS_INLINE uintptr_t incr(void* aOwner,
|
||||
nsCycleCollectionParticipant* aCp)
|
||||
{
|
||||
|
@ -216,7 +224,7 @@ public:
|
|||
mRefCntAndFlags |= NS_IN_PURPLE_BUFFER;
|
||||
// Refcount isn't zero, so Suspect won't delete anything.
|
||||
MOZ_ASSERT(get() > 0);
|
||||
NS_CycleCollectorSuspect3(aOwner, aCp, this, nullptr);
|
||||
suspect(aOwner, aCp, this, nullptr);
|
||||
}
|
||||
return NS_REFCOUNT_VALUE(mRefCntAndFlags);
|
||||
}
|
||||
|
@ -228,12 +236,14 @@ public:
|
|||
mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER;
|
||||
}
|
||||
|
||||
template<Suspect suspect = NS_CycleCollectorSuspect3>
|
||||
MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports* aOwner,
|
||||
bool* aShouldDelete = nullptr)
|
||||
{
|
||||
return decr(aOwner, nullptr, aShouldDelete);
|
||||
return decr<suspect>(aOwner, nullptr, aShouldDelete);
|
||||
}
|
||||
|
||||
template<Suspect suspect = NS_CycleCollectorSuspect3>
|
||||
MOZ_ALWAYS_INLINE uintptr_t decr(void* aOwner,
|
||||
nsCycleCollectionParticipant* aCp,
|
||||
bool* aShouldDelete = nullptr)
|
||||
|
@ -244,7 +254,7 @@ public:
|
|||
mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
|
||||
uintptr_t retval = NS_REFCOUNT_VALUE(mRefCntAndFlags);
|
||||
// Suspect may delete 'aOwner' and 'this'!
|
||||
NS_CycleCollectorSuspect3(aOwner, aCp, this, aShouldDelete);
|
||||
suspect(aOwner, aCp, this, aShouldDelete);
|
||||
return retval;
|
||||
}
|
||||
mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
|
||||
|
@ -710,6 +720,18 @@ NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
|||
return count; \
|
||||
}
|
||||
|
||||
#define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(_class) \
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
||||
{ \
|
||||
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
|
||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
||||
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||
nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
|
||||
nsrefcnt count = mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(base); \
|
||||
NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
|
||||
return count; \
|
||||
}
|
||||
|
||||
#define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
|
||||
{ \
|
||||
|
@ -755,6 +777,33 @@ NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \
|
|||
delete this; \
|
||||
}
|
||||
|
||||
// _LAST_RELEASE can be useful when certain resources should be released
|
||||
// as soon as we know the object will be deleted.
|
||||
#define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
|
||||
{ \
|
||||
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
|
||||
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||
bool shouldDelete = false; \
|
||||
nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
|
||||
nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(base, &shouldDelete); \
|
||||
NS_LOG_RELEASE(this, count, #_class); \
|
||||
if (count == 0) { \
|
||||
mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(base); \
|
||||
_last; \
|
||||
mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(base); \
|
||||
if (shouldDelete) { \
|
||||
mRefCnt.stabilizeForDeletion(); \
|
||||
DeleteCycleCollectable(); \
|
||||
} \
|
||||
} \
|
||||
return count; \
|
||||
} \
|
||||
NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \
|
||||
{ \
|
||||
delete this; \
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
|
|
@ -358,6 +358,12 @@ XPCOM_API(void) NS_CycleCollectorSuspect3(void* aPtr,
|
|||
nsCycleCollectingAutoRefCnt* aRefCnt,
|
||||
bool* aShouldDelete);
|
||||
|
||||
XPCOM_API(void)
|
||||
NS_CycleCollectorSuspectUsingNursery(void* aPtr,
|
||||
nsCycleCollectionParticipant* aCp,
|
||||
nsCycleCollectingAutoRefCnt* aRefCnt,
|
||||
bool* aShouldDelete);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче