Bug 1052793 - Do per-zone GC for CC_WAITING triggers. r=smaug

This commit is contained in:
Andrew McCreight 2014-12-13 21:17:35 -08:00
parent 23622ce32a
commit 87c4bbdc6b
4 changed files with 50 additions and 1 deletions

View File

@ -185,6 +185,7 @@ static uint32_t sForgetSkippableBeforeCC = 0;
static uint32_t sPreviousSuspectedCount = 0; static uint32_t sPreviousSuspectedCount = 0;
static uint32_t sCleanupsSinceLastGC = UINT32_MAX; static uint32_t sCleanupsSinceLastGC = UINT32_MAX;
static bool sNeedsFullCC = false; static bool sNeedsFullCC = false;
static bool sNeedsFullGC = false;
static bool sNeedsGCAfterCC = false; static bool sNeedsGCAfterCC = false;
static bool sIncrementalCC = false; static bool sIncrementalCC = false;
static bool sDidPaintAfterPreviousICCSlice = false; static bool sDidPaintAfterPreviousICCSlice = false;
@ -1462,7 +1463,13 @@ nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
return; return;
} }
JS::PrepareForFullGC(sRuntime); if (sNeedsFullGC || aReason != JS::gcreason::CC_WAITING) {
sNeedsFullGC = false;
JS::PrepareForFullGC(sRuntime);
} else {
CycleCollectedJSRuntime::Get()->PrepareWaitingZonesForGC();
}
if (aIncremental == IncrementalGC) { if (aIncremental == IncrementalGC) {
MOZ_ASSERT(aShrinking == NonShrinkingGC); MOZ_ASSERT(aShrinking == NonShrinkingGC);
JS::IncrementalGC(sRuntime, aReason, aSliceMillis); JS::IncrementalGC(sRuntime, aReason, aSliceMillis);
@ -2149,6 +2156,8 @@ nsJSContext::RunNextCollectorTimer()
void void
nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay) nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay)
{ {
sNeedsFullGC = sNeedsFullGC || aReason != JS::gcreason::CC_WAITING;
if (sGCTimer || sInterSliceGCTimer || sShuttingDown) { if (sGCTimer || sInterSliceGCTimer || sShuttingDown) {
// There's already a timer for GC'ing, just return // There's already a timer for GC'ing, just return
return; return;
@ -2458,6 +2467,7 @@ mozilla::dom::StartupJSEnvironment()
sLikelyShortLivingObjectsNeedingGC = 0; sLikelyShortLivingObjectsNeedingGC = 0;
sPostGCEventsToConsole = false; sPostGCEventsToConsole = false;
sNeedsFullCC = false; sNeedsFullCC = false;
sNeedsFullGC = false;
sNeedsGCAfterCC = false; sNeedsGCAfterCC = false;
gNameSpaceManager = nullptr; gNameSpaceManager = nullptr;
sRuntimeService = nullptr; sRuntimeService = nullptr;

View File

@ -1260,6 +1260,7 @@ CycleCollectedJSRuntime::OnGC(JSGCStatus aStatus)
switch (aStatus) { switch (aStatus) {
case JSGC_BEGIN: case JSGC_BEGIN:
nsCycleCollector_prepareForGarbageCollection(); nsCycleCollector_prepareForGarbageCollection();
mZonesWaitingForGC.Clear();
break; break;
case JSGC_END: { case JSGC_END: {
#ifdef MOZ_CRASHREPORTER #ifdef MOZ_CRASHREPORTER
@ -1298,3 +1299,21 @@ CycleCollectedJSRuntime::OnLargeAllocationFailure()
CustomLargeAllocationFailureCallback(); CustomLargeAllocationFailureCallback();
AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reported); AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reported);
} }
static PLDHashOperator
PrepareWaitingZoneForGC(nsPtrHashKey<JS::Zone>* aZoneEntry, void*)
{
JS::PrepareZoneForGC(aZoneEntry->GetKey());
return PL_DHASH_NEXT;
}
void
CycleCollectedJSRuntime::PrepareWaitingZonesForGC()
{
if (mZonesWaitingForGC.Count() == 0) {
JS::PrepareForFullGC(Runtime());
} else {
mZonesWaitingForGC.EnumerateEntries(PrepareWaitingZoneForGC, nullptr);
mZonesWaitingForGC.Clear();
}
}

View File

@ -15,6 +15,7 @@
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
#include "nsHashKeys.h" #include "nsHashKeys.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "nsTHashtable.h"
class nsCycleCollectionNoteRootCallback; class nsCycleCollectionNoteRootCallback;
class nsIException; class nsIException;
@ -291,6 +292,18 @@ public:
// isn't one. // isn't one.
static CycleCollectedJSRuntime* Get(); static CycleCollectedJSRuntime* Get();
// Add aZone to the set of zones waiting for a GC.
void AddZoneWaitingForGC(JS::Zone* aZone)
{
mZonesWaitingForGC.PutEntry(aZone);
}
// Prepare any zones for GC that have been passed to AddZoneWaitingForGC()
// since the last GC or since the last call to PrepareWaitingZonesForGC(),
// whichever was most recent. If there were no such zones, prepare for a
// full GC.
void PrepareWaitingZonesForGC();
private: private:
JSGCThingParticipant mGCThingCycleCollectorGlobal; JSGCThingParticipant mGCThingCycleCollectorGlobal;
@ -313,6 +326,8 @@ private:
OOMState mOutOfMemoryState; OOMState mOutOfMemoryState;
OOMState mLargeAllocationFailureState; OOMState mLargeAllocationFailureState;
nsTHashtable<nsPtrHashKey<JS::Zone>> mZonesWaitingForGC;
}; };
MOZ_FINISH_NESTED_ENUM_CLASS(CycleCollectedJSRuntime::OOMState) MOZ_FINISH_NESTED_ENUM_CLASS(CycleCollectedJSRuntime::OOMState)

View File

@ -3213,9 +3213,14 @@ nsCycleCollector::CollectWhite()
if (pinfo->mColor == white && pinfo->mParticipant) { if (pinfo->mColor == white && pinfo->mParticipant) {
if (pinfo->IsGrayJS()) { if (pinfo->IsGrayJS()) {
++numWhiteGCed; ++numWhiteGCed;
JS::Zone* zone;
if (MOZ_UNLIKELY(pinfo->mParticipant == zoneParticipant)) { if (MOZ_UNLIKELY(pinfo->mParticipant == zoneParticipant)) {
++numWhiteJSZones; ++numWhiteJSZones;
zone = static_cast<JS::Zone*>(pinfo->mPointer);
} else {
zone = JS::GetTenuredGCThingZone(pinfo->mPointer);
} }
mJSRuntime->AddZoneWaitingForGC(zone);
} else { } else {
whiteNodes.InfallibleAppend(pinfo); whiteNodes.InfallibleAppend(pinfo);
pinfo->mParticipant->Root(pinfo->mPointer); pinfo->mParticipant->Root(pinfo->mPointer);