зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1296484 - Automatically CycleCollect if COMPARTMENT_REVIVED GC ends mostly gray; r=mccr8,r=jonco
--HG-- extra : rebase_source : d8df564fb782c4d8cfa4a5b153e5cda00e6343a2
This commit is contained in:
Родитель
ac99e35d5f
Коммит
d00af19508
|
@ -386,6 +386,16 @@ using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress pro
|
|||
extern JS_PUBLIC_API(GCNurseryCollectionCallback)
|
||||
SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback);
|
||||
|
||||
typedef void
|
||||
(* DoCycleCollectionCallback)(JSContext* cx);
|
||||
|
||||
/**
|
||||
* The purge gray callback is called after any COMPARTMENT_REVIVED GC in which
|
||||
* the majority of compartments have been marked gray.
|
||||
*/
|
||||
extern JS_PUBLIC_API(DoCycleCollectionCallback)
|
||||
SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback);
|
||||
|
||||
/**
|
||||
* Incremental GC defaults to enabled, but may be disabled for testing or in
|
||||
* embeddings that have not yet implemented barriers on their native classes.
|
||||
|
|
|
@ -778,6 +778,8 @@ class GCRuntime
|
|||
JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
|
||||
JS::GCNurseryCollectionCallback setNurseryCollectionCallback(
|
||||
JS::GCNurseryCollectionCallback callback);
|
||||
JS::DoCycleCollectionCallback setDoCycleCollectionCallback(JS::DoCycleCollectionCallback callback);
|
||||
void callDoCycleCollectionCallback(JSContext* cx);
|
||||
|
||||
void setFullCompartmentChecks(bool enable);
|
||||
|
||||
|
@ -947,6 +949,7 @@ class GCRuntime
|
|||
void traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark,
|
||||
AutoLockForExclusiveAccess& lock);
|
||||
void bufferGrayRoots();
|
||||
void maybeDoCycleCollection();
|
||||
void markCompartments();
|
||||
IncrementalProgress drainMarkStack(SliceBudget& sliceBudget, gcstats::Phase phase);
|
||||
template <class CompartmentIterT> void markWeakReferences(gcstats::Phase phase);
|
||||
|
@ -1309,6 +1312,7 @@ class GCRuntime
|
|||
bool fullCompartmentChecks;
|
||||
|
||||
Callback<JSGCCallback> gcCallback;
|
||||
Callback<JS::DoCycleCollectionCallback> gcDoCycleCollectionCallback;
|
||||
Callback<JSObjectsTenuredCallback> tenuredCallback;
|
||||
CallbackVector<JSFinalizeCallback> finalizeCallbacks;
|
||||
CallbackVector<JSWeakPointerZoneGroupCallback> updateWeakPointerZoneGroupCallbacks;
|
||||
|
|
|
@ -1482,6 +1482,21 @@ GCRuntime::setNurseryCollectionCallback(JS::GCNurseryCollectionCallback callback
|
|||
return stats.setNurseryCollectionCallback(callback);
|
||||
}
|
||||
|
||||
JS::DoCycleCollectionCallback
|
||||
GCRuntime::setDoCycleCollectionCallback(JS::DoCycleCollectionCallback callback)
|
||||
{
|
||||
auto prior = gcDoCycleCollectionCallback;
|
||||
gcDoCycleCollectionCallback = Callback<JS::DoCycleCollectionCallback>(callback, nullptr);
|
||||
return prior.op;
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::callDoCycleCollectionCallback(JSContext* cx)
|
||||
{
|
||||
if (gcDoCycleCollectionCallback.op)
|
||||
gcDoCycleCollectionCallback.op(cx);
|
||||
}
|
||||
|
||||
bool
|
||||
GCRuntime::addRoot(Value* vp, const char* name)
|
||||
{
|
||||
|
@ -6163,6 +6178,31 @@ GCRuntime::scanZonesBeforeGC()
|
|||
return zoneStats;
|
||||
}
|
||||
|
||||
// The GC can only clean up scheduledForDestruction compartments that were
|
||||
// marked live by a barrier (e.g. by RemapWrappers from a navigation event).
|
||||
// It is also common to have compartments held live because they are part of a
|
||||
// cycle in gecko, e.g. involving the HTMLDocument wrapper. In this case, we
|
||||
// need to run the CycleCollector in order to remove these edges before the
|
||||
// compartment can be freed.
|
||||
void
|
||||
GCRuntime::maybeDoCycleCollection()
|
||||
{
|
||||
const static double ExcessiveGrayCompartments = 0.8;
|
||||
const static size_t LimitGrayCompartments = 200;
|
||||
|
||||
size_t compartmentsTotal = 0;
|
||||
size_t compartmentsGray = 0;
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
++compartmentsTotal;
|
||||
GlobalObject* global = c->unsafeUnbarrieredMaybeGlobal();
|
||||
if (global && global->asTenured().isMarked(GRAY))
|
||||
++compartmentsGray;
|
||||
}
|
||||
double grayFraction = double(compartmentsGray) / double(compartmentsTotal);
|
||||
if (grayFraction > ExcessiveGrayCompartments || compartmentsGray > LimitGrayCompartments)
|
||||
callDoCycleCollectionCallback(rt->contextFromMainThread());
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::checkCanCallAPI()
|
||||
{
|
||||
|
@ -6243,6 +6283,9 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
|
|||
repeat = (poked && cleanUpEverything) || wasReset || repeatForDeadZone;
|
||||
} while (repeat);
|
||||
|
||||
if (reason == JS::gcreason::COMPARTMENT_REVIVED)
|
||||
maybeDoCycleCollection();
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (shouldCompact() && rt->hasZealMode(ZealMode::CheckHeapOnMovingGC)) {
|
||||
gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_TRACE_HEAP);
|
||||
|
@ -7206,6 +7249,12 @@ JS::SetGCSliceCallback(JSContext* cx, GCSliceCallback callback)
|
|||
return cx->gc.setSliceCallback(callback);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::DoCycleCollectionCallback)
|
||||
JS::SetDoCycleCollectionCallback(JSContext* cx, JS::DoCycleCollectionCallback callback)
|
||||
{
|
||||
return cx->gc.setDoCycleCollectionCallback(callback);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::GCNurseryCollectionCallback)
|
||||
JS::SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback)
|
||||
{
|
||||
|
|
|
@ -720,6 +720,21 @@ XPCJSRuntime::GCSliceCallback(JSContext* cx,
|
|||
(*self->mPrevGCSliceCallback)(cx, progress, desc);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::DoCycleCollectionCallback(JSContext* cx)
|
||||
{
|
||||
XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
// The GC has detected that a CC at this point would collect a tremendous
|
||||
// amount of garbage that is being revivified unnecessarily.
|
||||
nsJSContext::CycleCollectNow();
|
||||
|
||||
if (self->mPrevDoCycleCollectionCallback)
|
||||
(*self->mPrevDoCycleCollectionCallback)(cx);
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::CustomGCCallback(JSGCStatus status)
|
||||
{
|
||||
|
@ -3502,6 +3517,8 @@ XPCJSRuntime::Initialize()
|
|||
JS_SetSizeOfIncludingThisCompartmentCallback(cx, CompartmentSizeOfIncludingThisCallback);
|
||||
JS_SetCompartmentNameCallback(cx, CompartmentNameCallback);
|
||||
mPrevGCSliceCallback = JS::SetGCSliceCallback(cx, GCSliceCallback);
|
||||
mPrevDoCycleCollectionCallback = JS::SetDoCycleCollectionCallback(cx,
|
||||
DoCycleCollectionCallback);
|
||||
JS_AddFinalizeCallback(cx, FinalizeCallback, nullptr);
|
||||
JS_AddWeakPointerZoneGroupCallback(cx, WeakPointerZoneGroupCallback, this);
|
||||
JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this);
|
||||
|
|
|
@ -551,6 +551,7 @@ public:
|
|||
static void GCSliceCallback(JSContext* cx,
|
||||
JS::GCProgress progress,
|
||||
const JS::GCDescription& desc);
|
||||
static void DoCycleCollectionCallback(JSContext* cx);
|
||||
static void FinalizeCallback(JSFreeOp* fop,
|
||||
JSFinalizeStatus status,
|
||||
bool isCompartmentGC,
|
||||
|
@ -628,6 +629,7 @@ private:
|
|||
nsTArray<xpcGCCallback> extraGCCallbacks;
|
||||
RefPtr<WatchdogManager> mWatchdogManager;
|
||||
JS::GCSliceCallback mPrevGCSliceCallback;
|
||||
JS::DoCycleCollectionCallback mPrevDoCycleCollectionCallback;
|
||||
JS::PersistentRootedObject mUnprivilegedJunkScope;
|
||||
JS::PersistentRootedObject mPrivilegedJunkScope;
|
||||
JS::PersistentRootedObject mCompilationScope;
|
||||
|
|
Загрузка…
Ссылка в новой задаче