mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
bug 1397297, make SnowWhite freeing more incremental, r=smaug
--HG-- extra : rebase_source : 0772adabddb6cee33d83184d32c981d3920ea6e6
This commit is contained in:
parent
b89a51dc36
commit
a03dfcbd42
@ -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)
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user