Bug 1089582 - Only perform a minor GC when a store buffer is full r=terrence

This commit is contained in:
Jon Coppeard 2014-10-28 10:18:40 +00:00
parent 2051dac10e
commit dde7851d32
3 changed files with 59 additions and 35 deletions

View File

@ -277,7 +277,7 @@ class GCRuntime
void minorGC(JS::gcreason::Reason reason);
void minorGC(JSContext *cx, JS::gcreason::Reason reason);
void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) { minorGC(reason); }
void gcIfNeeded(JSContext *cx);
bool gcIfNeeded(JSContext *cx = nullptr);
void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
void gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
void gcFinalSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
@ -326,6 +326,10 @@ class GCRuntime
allocTask.cancel(GCParallelTask::CancelAndWait);
}
#ifdef JSGC_GENERATIONAL
void requestMinorGC(JS::gcreason::Reason reason);
#endif
#ifdef DEBUG
bool onBackgroundThread() { return helperState.onBackgroundThread(); }
@ -436,7 +440,7 @@ class GCRuntime
bool areGrayBitsValid() { return grayBitsValid; }
void setGrayBitsInvalid() { grayBitsValid = false; }
bool isGcNeeded() { return isNeeded; }
bool isGcNeeded() { return minorGCRequested || majorGCRequested; }
double computeHeapGrowthFactor(size_t lastBytes);
size_t computeTriggerBytes(double growthFactor, size_t lastBytes);
@ -498,7 +502,7 @@ class GCRuntime
void startBackgroundAllocTaskIfIdle();
bool initZeal();
void requestInterrupt(JS::gcreason::Reason reason);
void requestMajorGC(JS::gcreason::Reason reason);
void collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
JS::gcreason::Reason reason);
bool gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
@ -631,12 +635,13 @@ class GCRuntime
*/
bool grayBitsValid;
/*
* These flags must be kept separate so that a thread requesting a
* compartment GC doesn't cancel another thread's concurrent request for a
* full GC.
*/
volatile uintptr_t isNeeded;
volatile uintptr_t majorGCRequested;
JS::gcreason::Reason majorGCTriggerReason;
#ifdef JSGC_GENERATIONAL
bool minorGCRequested;
JS::gcreason::Reason minorGCTriggerReason;
#endif
/* Incremented at the start of every major GC. */
uint64_t majorGCNumber;
@ -659,9 +664,6 @@ class GCRuntime
/* The invocation kind of the current GC, taken from the first slice. */
JSGCInvocationKind invocationKind;
/* The reason that an interrupt-triggered GC should be called. */
JS::gcreason::Reason triggerReason;
/*
* If this is 0, all cross-compartment proxies must be registered in the
* wrapper map. This checking must be disabled temporarily while creating

View File

@ -303,7 +303,7 @@ void
StoreBuffer::setAboutToOverflow()
{
aboutToOverflow_ = true;
runtime_->requestInterrupt(JSRuntime::RequestInterruptMainThread);
runtime_->gc.requestMinorGC(JS::gcreason::FULL_STORE_BUFFER);
}
bool

View File

@ -1181,13 +1181,17 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
decommitThreshold(32 * 1024 * 1024),
cleanUpEverything(false),
grayBitsValid(false),
isNeeded(0),
majorGCRequested(0),
majorGCTriggerReason(JS::gcreason::NO_REASON),
#ifdef JSGC_GENERATIONAL
minorGCRequested(false),
minorGCTriggerReason(JS::gcreason::NO_REASON),
#endif
majorGCNumber(0),
jitReleaseNumber(0),
number(0),
startNumber(0),
isFull(false),
triggerReason(JS::gcreason::NO_REASON),
#ifdef DEBUG
disableStrictProxyCheckingCount(0),
#endif
@ -2946,13 +2950,25 @@ js::MarkCompartmentActive(InterpreterFrame *fp)
}
void
GCRuntime::requestInterrupt(JS::gcreason::Reason reason)
GCRuntime::requestMajorGC(JS::gcreason::Reason reason)
{
if (isNeeded)
if (majorGCRequested)
return;
isNeeded = true;
triggerReason = reason;
majorGCRequested = true;
majorGCTriggerReason = reason;
rt->requestInterrupt(JSRuntime::RequestInterruptMainThread);
}
void
GCRuntime::requestMinorGC(JS::gcreason::Reason reason)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
if (minorGCRequested)
return;
minorGCRequested = true;
minorGCTriggerReason = reason;
rt->requestInterrupt(JSRuntime::RequestInterruptMainThread);
}
@ -2981,7 +2997,7 @@ GCRuntime::triggerGC(JS::gcreason::Reason reason)
return false;
JS::PrepareForFullGC(rt);
requestInterrupt(reason);
requestMajorGC(reason);
return true;
}
@ -3023,7 +3039,7 @@ GCRuntime::triggerZoneGC(Zone *zone, JS::gcreason::Reason reason)
}
PrepareZoneForGC(zone);
requestInterrupt(reason);
requestMajorGC(reason);
return true;
}
@ -3040,10 +3056,8 @@ GCRuntime::maybeGC(Zone *zone)
}
#endif
if (isNeeded) {
gcSlice(GC_NORMAL, JS::gcreason::MAYBEGC);
if (gcIfNeeded())
return true;
}
double factor = schedulingState.inHighFrequencyGCMode() ? 0.85 : 0.9;
if (zone->usage.gcBytes() > 1024 * 1024 &&
@ -5798,7 +5812,7 @@ GCRuntime::gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
AutoTraceSession session(rt, MajorCollecting);
isNeeded = false;
majorGCRequested = false;
interFrameGC = true;
number++;
@ -6134,6 +6148,7 @@ void
GCRuntime::minorGC(JS::gcreason::Reason reason)
{
#ifdef JSGC_GENERATIONAL
minorGCRequested = false;
TraceLogger *logger = TraceLoggerForMainThread(rt);
AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC);
nursery.collect(rt, reason, nullptr);
@ -6147,6 +6162,7 @@ GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason)
// Alternate to the runtime-taking form above which allows marking type
// objects as needing pretenuring.
#ifdef JSGC_GENERATIONAL
minorGCRequested = false;
TraceLogger *logger = TraceLoggerForMainThread(rt);
AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC);
Nursery::TypeObjectList pretenureTypes;
@ -6185,20 +6201,26 @@ GCRuntime::enableGenerationalGC()
#endif
}
void
GCRuntime::gcIfNeeded(JSContext *cx)
bool
GCRuntime::gcIfNeeded(JSContext *cx /* = nullptr */)
{
// This method returns whether a major GC was performed.
#ifdef JSGC_GENERATIONAL
/*
* In case of store buffer overflow perform minor GC first so that the
* correct reason is seen in the logs.
*/
if (storeBuffer.isAboutToOverflow())
minorGC(cx, JS::gcreason::FULL_STORE_BUFFER);
if (minorGCRequested) {
if (cx)
minorGC(cx, minorGCTriggerReason);
else
minorGC(minorGCTriggerReason);
}
#endif
if (isNeeded)
gcSlice(GC_NORMAL, rt->gc.triggerReason, 0);
if (majorGCRequested) {
gcSlice(GC_NORMAL, rt->gc.majorGCTriggerReason);
return true;
}
return false;
}
AutoFinishGC::AutoFinishGC(JSRuntime *rt)