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:
Olli Pettay 2017-08-22 00:01:47 +03:00
Родитель f11a1c6fda
Коммит 6e1dc494d2
4 изменённых файлов: 142 добавлений и 7 удалений

Просмотреть файл

@ -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
/**