bug 1397297, make SnowWhite freeing more incremental, r=smaug

--HG--
extra : rebase_source : 0772adabddb6cee33d83184d32c981d3920ea6e6
This commit is contained in:
agashlin@mozilla.com 2018-08-08 09:14:58 +03:00
parent b89a51dc36
commit a03dfcbd42
3 changed files with 80 additions and 12 deletions

View File

@ -129,7 +129,10 @@ public:
AUTO_PROFILER_LABEL("AsyncFreeSnowWhite::Run", GCCC);
TimeStamp start = TimeStamp::Now();
bool hadSnowWhiteObjects = nsCycleCollector_doDeferredDeletion();
// 2 ms budget, given that kICCSliceBudget is only 3 ms
js::SliceBudget budget = js::SliceBudget(js::TimeBudget(2));
bool hadSnowWhiteObjects =
nsCycleCollector_doDeferredDeletionWithBudget(budget);
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_ASYNC_SNOW_WHITE_FREEING,
uint32_t((TimeStamp::Now() - start).ToMilliseconds()));
if (hadSnowWhiteObjects && !mContinuation) {
@ -146,7 +149,7 @@ public:
nsresult Dispatch()
{
nsCOMPtr<nsIRunnable> self(this);
return NS_IdleDispatchToCurrentThread(self.forget(), 2500);
return NS_IdleDispatchToCurrentThread(self.forget(), 500);
}
void Start(bool aContinuation = false, bool aPurge = false)

View File

@ -1353,6 +1353,7 @@ public:
void ForgetSkippable(js::SliceBudget& aBudget, bool aRemoveChildlessNodes,
bool aAsyncSnowWhiteFreeing);
bool FreeSnowWhite(bool aUntilNoSWInPurpleBuffer);
bool FreeSnowWhiteWithBudget(js::SliceBudget& aBudget);
// This method assumes its argument is already canonicalized.
void RemoveObjectFromGraph(void* aPtr);
@ -2715,40 +2716,66 @@ class SnowWhiteKiller : public TraceCallbacks
ObjectsVector;
public:
explicit SnowWhiteKiller(nsCycleCollector* aCollector)
SnowWhiteKiller(nsCycleCollector* aCollector, js::SliceBudget* aBudget)
: mCollector(aCollector)
, mObjects(kSegmentSize)
, mBudget(aBudget)
, mSawSnowWhiteObjects(false)
{
MOZ_ASSERT(mCollector, "Calling SnowWhiteKiller after nsCC went away");
}
explicit SnowWhiteKiller(nsCycleCollector* aCollector)
: SnowWhiteKiller(aCollector, nullptr)
{
}
~SnowWhiteKiller()
{
for (auto iter = mObjects.Iter(); !iter.Done(); iter.Next()) {
SnowWhiteObject& o = iter.Get();
if (!o.mRefCnt->get() && !o.mRefCnt->IsInPurpleBuffer()) {
mCollector->RemoveObjectFromGraph(o.mPointer);
o.mRefCnt->stabilizeForDeletion();
{
JS::AutoEnterCycleCollection autocc(mCollector->Runtime()->Runtime());
o.mParticipant->Trace(o.mPointer, *this, nullptr);
}
o.mParticipant->DeleteCycleCollectable(o.mPointer);
MaybeKillObject(o);
}
}
void
MaybeKillObject(SnowWhiteObject& aObject)
{
if (!aObject.mRefCnt->get() && !aObject.mRefCnt->IsInPurpleBuffer()) {
mCollector->RemoveObjectFromGraph(aObject.mPointer);
aObject.mRefCnt->stabilizeForDeletion();
{
JS::AutoEnterCycleCollection autocc(mCollector->Runtime()->Runtime());
aObject.mParticipant->Trace(aObject.mPointer, *this, nullptr);
}
aObject.mParticipant->DeleteCycleCollectable(aObject.mPointer);
}
}
bool
Visit(nsPurpleBuffer& aBuffer, nsPurpleBufferEntry* aEntry)
{
if (mBudget) {
if (mBudget->isOverBudget()) {
return false;
}
mBudget->step();
}
MOZ_ASSERT(aEntry->mObject, "Null object in purple buffer");
if (!aEntry->mRefCnt->get()) {
mSawSnowWhiteObjects = true;
void* o = aEntry->mObject;
nsCycleCollectionParticipant* cp = aEntry->mParticipant;
ToParticipant(o, &cp);
SnowWhiteObject swo = { o, cp, aEntry->mRefCnt };
mObjects.InfallibleAppend(swo);
if (!mBudget) {
mObjects.InfallibleAppend(swo);
}
aBuffer.Remove(aEntry);
if (mBudget) {
MaybeKillObject(swo);
}
}
return true;
}
@ -2758,6 +2785,11 @@ public:
return !mObjects.IsEmpty();
}
bool SawSnowWhiteObjects() const
{
return mSawSnowWhiteObjects;
}
virtual void Trace(JS::Heap<JS::Value>* aValue, const char* aName,
void* aClosure) const override
{
@ -2817,6 +2849,8 @@ public:
private:
RefPtr<nsCycleCollector> mCollector;
ObjectsVector mObjects;
js::SliceBudget* mBudget;
bool mSawSnowWhiteObjects;
};
class RemoveSkippableVisitor : public SnowWhiteKiller
@ -2925,6 +2959,23 @@ nsCycleCollector::FreeSnowWhite(bool aUntilNoSWInPurpleBuffer)
return hadSnowWhiteObjects;
}
bool
nsCycleCollector::FreeSnowWhiteWithBudget(js::SliceBudget& aBudget)
{
CheckThreadSafety();
if (mFreeingSnowWhite) {
return false;
}
AutoRestore<bool> ar(mFreeingSnowWhite);
mFreeingSnowWhite = true;
SnowWhiteKiller visitor(this, &aBudget);
mPurpleBuf.VisitEntries(visitor);
return visitor.SawSnowWhiteObjects();;
}
void
nsCycleCollector::ForgetSkippable(js::SliceBudget& aBudget,
bool aRemoveChildlessNodes,
@ -4320,6 +4371,19 @@ nsCycleCollector_doDeferredDeletion()
return data->mCollector->FreeSnowWhite(false);
}
bool
nsCycleCollector_doDeferredDeletionWithBudget(js::SliceBudget& aBudget)
{
CollectorData* data = sCollectorData.get();
// We should have started the cycle collector by now.
MOZ_ASSERT(data);
MOZ_ASSERT(data->mCollector);
MOZ_ASSERT(data->mContext);
return data->mCollector->FreeSnowWhiteWithBudget(aBudget);
}
already_AddRefed<nsICycleCollectorLogSink>
nsCycleCollector_createLogSink()
{

View File

@ -43,6 +43,7 @@ void nsCycleCollector_finishAnyCurrentCollection();
void nsCycleCollector_dispatchDeferredDeletion(bool aContinuation = false,
bool aPurge = false);
bool nsCycleCollector_doDeferredDeletion();
bool nsCycleCollector_doDeferredDeletionWithBudget(js::SliceBudget& aBudget);
already_AddRefed<nsICycleCollectorLogSink> nsCycleCollector_createLogSink();