mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1089582 - Only perform a minor GC when a store buffer is full r=terrence
This commit is contained in:
parent
f7b0f5750e
commit
a16b40ad8c
@ -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
|
||||
|
@ -303,7 +303,7 @@ void
|
||||
StoreBuffer::setAboutToOverflow()
|
||||
{
|
||||
aboutToOverflow_ = true;
|
||||
runtime_->requestInterrupt(JSRuntime::RequestInterruptMainThread);
|
||||
runtime_->gc.requestMinorGC(JS::gcreason::FULL_STORE_BUFFER);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user