Bug 716014, use compartment gc more often, r=billm

--HG--
extra : rebase_source : cf20b7aca16349e4007da24cfb5b19ab7a16cad8
This commit is contained in:
Olli Pettay 2012-05-05 11:55:30 +03:00
Родитель 80c977488b
Коммит d7fa29d6cf
5 изменённых файлов: 95 добавлений и 14 удалений

Просмотреть файл

@ -966,7 +966,7 @@ nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener *aListener,
}
#endif
nsJSContext::GarbageCollectNow(js::gcreason::DOM_UTILS);
nsJSContext::GarbageCollectNow(js::gcreason::DOM_UTILS, nsGCNormal, true);
nsJSContext::CycleCollectNow(aListener, aExtraForgetSkippableCalls);
return NS_OK;

Просмотреть файл

@ -134,6 +134,10 @@ static PRLogModuleInfo* gJSDiagnostics;
// doing the first GC.
#define NS_FIRST_GC_DELAY 10000 // ms
#define NS_FULL_GC_DELAY 30000 // ms
#define NS_MAX_COMPARTMENT_GC_COUNT 10
// Maximum amount of time that should elapse between incremental GC slices
#define NS_INTERSLICE_GC_DELAY 100 // ms
@ -159,6 +163,7 @@ static PRLogModuleInfo* gJSDiagnostics;
static nsITimer *sGCTimer;
static nsITimer *sShrinkGCBuffersTimer;
static nsITimer *sCCTimer;
static nsITimer *sFullGCTimer;
static PRTime sLastCCEndTime;
@ -178,6 +183,7 @@ static bool sLoadingInProgress;
static PRUint32 sCCollectedWaitingForGC;
static bool sPostGCEventsToConsole;
static bool sDisableExplicitCompartmentGC;
static PRUint32 sCCTimerFireCount = 0;
static PRUint32 sMinForgetSkippableTime = PR_UINT32_MAX;
static PRUint32 sMaxForgetSkippableTime = 0;
@ -185,7 +191,9 @@ static PRUint32 sTotalForgetSkippableTime = 0;
static PRUint32 sRemovedPurples = 0;
static PRUint32 sForgetSkippableBeforeCC = 0;
static PRUint32 sPreviousSuspectedCount = 0;
static PRUint32 sCompartmentGCCount = NS_MAX_COMPARTMENT_GC_COUNT;
static bool sContextDeleted = false;
static bool sDidRunInitialGC = false;
static PRUint32 sCleanupsSinceLastGC = PR_UINT32_MAX;
static bool sNeedsFullCC = false;
@ -229,7 +237,8 @@ nsMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
if (sGCOnMemoryPressure) {
nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking);
nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking,
true);
nsJSContext::CycleCollectNow();
}
return NS_OK;
@ -929,6 +938,8 @@ static const char js_pccounts_content_str[] = JS_OPTIONS_DOT_STR "pccounts.con
static const char js_pccounts_chrome_str[] = JS_OPTIONS_DOT_STR "pccounts.chrome";
static const char js_jit_hardening_str[] = JS_OPTIONS_DOT_STR "jit_hardening";
static const char js_memlog_option_str[] = JS_OPTIONS_DOT_STR "mem.log";
static const char js_disable_explicit_compartment_gc[] =
JS_OPTIONS_DOT_STR "disable_explicit_compartment_gc";
int
nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
@ -938,6 +949,8 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
PRUint32 newDefaultJSOptions = oldDefaultJSOptions;
sPostGCEventsToConsole = Preferences::GetBool(js_memlog_option_str);
sDisableExplicitCompartmentGC =
Preferences::GetBool(js_disable_explicit_compartment_gc);
bool strict = Preferences::GetBool(js_strict_option_str);
if (strict)
@ -1115,6 +1128,7 @@ nsJSContext::DestroyJSContext()
js_options_dot_str, this);
if (mGCOnDestruction) {
sContextDeleted = true;
PokeGC(js::gcreason::NSJSCONTEXT_DESTROY);
}
@ -2849,6 +2863,11 @@ nsJSContext::ScriptEvaluated(bool aTerminated)
if (aTerminated) {
mOperationCallbackTime = 0;
mModalStateTime = 0;
JSObject* global = GetNativeGlobal();
if (global) {
js::PrepareCompartmentForGC(js::GetObjectCompartment(global));
}
}
}
@ -2916,9 +2935,20 @@ nsJSContext::ScriptExecuted()
return NS_OK;
}
void
FullGCTimerFired(nsITimer* aTimer, void* aClosure)
{
NS_RELEASE(sFullGCTimer);
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
nsGCNormal, true);
}
//static
void
nsJSContext::GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind)
nsJSContext::GarbageCollectNow(js::gcreason::Reason aReason, PRUint32 aGckind,
bool aGlobal)
{
NS_TIME_FUNCTION_MIN(1.0);
SAMPLE_LABEL("GC", "GarbageCollectNow");
@ -2935,9 +2965,36 @@ nsJSContext::GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind)
sPendingLoadCount = 0;
sLoadingInProgress = false;
if (nsContentUtils::XPConnect()) {
nsContentUtils::XPConnect()->GarbageCollect(reason, gckind);
if (!nsContentUtils::XPConnect()) {
return;
}
// Use compartment GC when we're not asked to do a shrinking GC nor
// global GC and compartment GC has been called less than
// NS_MAX_COMPARTMENT_GC_COUNT times after the previous global GC. If a top
// level browsing context has been deleted, we do a global GC.
if (sDidRunInitialGC &&
!sDisableExplicitCompartmentGC &&
aGckind != nsGCShrinking && !aGlobal &&
!sContextDeleted && sCompartmentGCCount < NS_MAX_COMPARTMENT_GC_COUNT) {
if (!sFullGCTimer) {
CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer);
}
if (sFullGCTimer) {
sFullGCTimer->Cancel();
js::gcreason::Reason reason = js::gcreason::FULL_GC_TIMER;
sFullGCTimer->InitWithFuncCallback(FullGCTimerFired,
reinterpret_cast<void *>(reason),
NS_FULL_GC_DELAY,
nsITimer::TYPE_ONE_SHOT);
}
if (js::IsGCScheduled(nsJSRuntime::sRuntime)) {
js::IncrementalGC(nsJSRuntime::sRuntime, aReason);
}
return;
}
nsContentUtils::XPConnect()->GarbageCollect(aReason, aGckind);
}
//static
@ -2963,7 +3020,7 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
if (sCCLockedOut) {
// We're in the middle of an incremental GC; finish it first
nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal, true);
}
SAMPLE_LABEL("GC", "CycleCollectNow");
@ -3100,7 +3157,8 @@ GCTimerFired(nsITimer *aTimer, void *aClosure)
NS_RELEASE(sGCTimer);
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason), nsGCIncremental);
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
nsGCNormal, false);
}
void
@ -3156,7 +3214,7 @@ CCTimerFired(nsITimer *aTimer, void *aClosure)
}
// Finish the current incremental GC
nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal, true);
}
++sCCTimerFireCount;
@ -3309,6 +3367,15 @@ nsJSContext::KillGCTimer()
}
}
void
nsJSContext::KillFullGCTimer()
{
if (sFullGCTimer) {
sFullGCTimer->Cancel();
NS_RELEASE(sFullGCTimer);
}
}
//static
void
nsJSContext::KillShrinkGCBuffersTimer()
@ -3336,6 +3403,8 @@ nsJSContext::KillCCTimer()
void
nsJSContext::GC(js::gcreason::Reason aReason)
{
// Force full gc.
sCompartmentGCCount = NS_MAX_COMPARTMENT_GC_COUNT;
PokeGC(aReason);
}
@ -3419,6 +3488,7 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
sCleanupsSinceLastGC = 0;
if (aDesc.isCompartment) {
++sCompartmentGCCount;
// If this is a compartment GC, restart it. We still want
// a full GC to happen. Compartment GCs usually happen as a
// result of last-ditch or MaybeGC. In both cases it is
@ -3431,6 +3501,11 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
nsJSContext::MaybePokeCC();
if (!aDesc.isCompartment) {
sDidRunInitialGC = true;
sContextDeleted = false;
sCompartmentGCCount = 0;
nsJSContext::KillFullGCTimer();
// Avoid shrinking during heavy activity, which is suggested by
// compartment GC.
nsJSContext::PokeShrinkGCBuffers();
@ -3530,7 +3605,7 @@ void
nsJSRuntime::Startup()
{
// initialize all our statics, so that we can restart XPCOM
sGCTimer = sCCTimer = nsnull;
sGCTimer = sFullGCTimer = sCCTimer = nsnull;
sCCLockedOut = false;
sCCLockedOutTime = 0;
sLastCCEndTime = 0;
@ -3538,6 +3613,7 @@ nsJSRuntime::Startup()
sLoadingInProgress = false;
sCCollectedWaitingForGC = 0;
sPostGCEventsToConsole = false;
sDisableExplicitCompartmentGC = false;
sNeedsFullCC = false;
gNameSpaceManager = nsnull;
sRuntimeService = nsnull;
@ -3829,6 +3905,7 @@ nsJSRuntime::Shutdown()
nsJSContext::KillGCTimer();
nsJSContext::KillShrinkGCBuffersTimer();
nsJSContext::KillCCTimer();
nsJSContext::KillFullGCTimer();
NS_IF_RELEASE(gNameSpaceManager);

Просмотреть файл

@ -184,7 +184,9 @@ public:
static void LoadStart();
static void LoadEnd();
static void GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind = nsGCNormal);
static void GarbageCollectNow(js::gcreason::Reason reason,
PRUint32 aGckind,
bool aGlobal);
static void ShrinkGCBuffersNow();
// If aExtraForgetSkippableCalls is -1, forgetSkippable won't be
// called even if the previous collection was GC.
@ -199,6 +201,7 @@ public:
static void MaybePokeCC();
static void KillCCTimer();
static void KillFullGCTimer();
virtual void GC(js::gcreason::Reason aReason);

Просмотреть файл

@ -791,14 +791,14 @@ ContentChild::GetIndexedDBPath()
bool
ContentChild::RecvGarbageCollect()
{
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC, nsGCNormal, true);
return true;
}
bool
ContentChild::RecvCycleCollect()
{
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC, nsGCNormal, true);
nsJSContext::CycleCollectNow();
return true;
}

Просмотреть файл

@ -629,7 +629,8 @@ SizeOfJSContext();
D(DOM_IPC) \
D(DOM_WORKER) \
D(INTER_SLICE_GC) \
D(REFRESH_FRAME)
D(REFRESH_FRAME) \
D(FULL_GC_TIMER)
namespace gcreason {