зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 6 changesets (bug 1661293) for causing Bug 1758370 CLOSED TREE
Backed out changeset 8f4d646a4bf6 (bug 1661293) Backed out changeset ec817d9e8a17 (bug 1661293) Backed out changeset efd35f1d9bd5 (bug 1661293) Backed out changeset 00d93cc6125f (bug 1661293) Backed out changeset 77b0b0003ca0 (bug 1661293) Backed out changeset 04443fa474ac (bug 1661293)
This commit is contained in:
Родитель
7b8f0188b8
Коммит
61cd14ddcd
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "CCGCScheduler.h"
|
||||
|
||||
#include "js/GCAPI.h"
|
||||
#include "mozilla/StaticPrefs_javascript.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/ProfilerMarkers.h"
|
||||
|
@ -110,7 +109,7 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
void CCGCScheduler::NoteGCBegin(JS::GCReason aReason) {
|
||||
void CCGCScheduler::NoteGCBegin() {
|
||||
// Treat all GC as incremental here; non-incremental GC will just appear to
|
||||
// be one slice.
|
||||
mInIncrementalGC = true;
|
||||
|
@ -123,20 +122,10 @@ void CCGCScheduler::NoteGCBegin(JS::GCReason aReason) {
|
|||
if (child) {
|
||||
child->StartedGC();
|
||||
}
|
||||
|
||||
// The reason might have come from mMajorReason, mEagerMajorGCReason, or
|
||||
// in the case of an internally-generated GC, it might come from the
|
||||
// internal logic (and be passed in here). It's easier to manage a single
|
||||
// reason state variable, so merge all sources into mMajorGCReason.
|
||||
MOZ_ASSERT(aReason != JS::GCReason::NO_REASON);
|
||||
mMajorGCReason = aReason;
|
||||
mEagerMajorGCReason = JS::GCReason::NO_REASON;
|
||||
}
|
||||
|
||||
void CCGCScheduler::NoteGCEnd() {
|
||||
mMajorGCReason = JS::GCReason::NO_REASON;
|
||||
mEagerMajorGCReason = JS::GCReason::NO_REASON;
|
||||
mEagerMinorGCReason = JS::GCReason::NO_REASON;
|
||||
|
||||
mInIncrementalGC = false;
|
||||
mCCBlockStart = TimeStamp();
|
||||
|
@ -216,7 +205,6 @@ void CCGCScheduler::NoteCCEnd(TimeStamp aWhen) {
|
|||
void CCGCScheduler::NoteWontGC() {
|
||||
mReadyForMajorGC = !mAskParentBeforeMajorGC;
|
||||
mMajorGCReason = JS::GCReason::NO_REASON;
|
||||
mEagerMajorGCReason = JS::GCReason::NO_REASON;
|
||||
mWantAtLeastRegularGC = false;
|
||||
// Don't clear the WantFullGC state, we will do a full GC the next time a
|
||||
// GC happens for any other reason.
|
||||
|
@ -225,17 +213,10 @@ void CCGCScheduler::NoteWontGC() {
|
|||
bool CCGCScheduler::GCRunnerFired(TimeStamp aDeadline) {
|
||||
MOZ_ASSERT(!mDidShutdown, "GCRunner still alive during shutdown");
|
||||
|
||||
GCRunnerStep step = GetNextGCRunnerAction(aDeadline);
|
||||
GCRunnerStep step = GetNextGCRunnerAction();
|
||||
switch (step.mAction) {
|
||||
case GCRunnerAction::None:
|
||||
KillGCRunner();
|
||||
return false;
|
||||
|
||||
case GCRunnerAction::MinorGC:
|
||||
JS::MaybeRunNurseryCollection(CycleCollectedJSRuntime::Get()->Runtime(),
|
||||
step.mReason);
|
||||
NoteMinorGCEnd();
|
||||
return HasMoreIdleGCRunnerWork();
|
||||
MOZ_CRASH("Unexpected GCRunnerAction");
|
||||
|
||||
case GCRunnerAction::WaitToMajorGC: {
|
||||
MOZ_ASSERT(!mHaveAskedParent, "GCRunner alive after asking the parent");
|
||||
|
@ -465,9 +446,6 @@ void CCGCScheduler::PokeFullGC() {
|
|||
|
||||
void CCGCScheduler::PokeGC(JS::GCReason aReason, JSObject* aObj,
|
||||
TimeDuration aDelay) {
|
||||
MOZ_ASSERT(aReason != JS::GCReason::NO_REASON);
|
||||
MOZ_ASSERT(aReason != JS::GCReason::EAGER_NURSERY_COLLECTION);
|
||||
|
||||
if (mDidShutdown) {
|
||||
return;
|
||||
}
|
||||
|
@ -480,7 +458,7 @@ void CCGCScheduler::PokeGC(JS::GCReason aReason, JSObject* aObj,
|
|||
}
|
||||
|
||||
if (mGCRunner || mHaveAskedParent) {
|
||||
// There's already a GC runner, or there will be, so just return.
|
||||
// There's already a GC runner, there or will be, so just return.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -505,24 +483,6 @@ void CCGCScheduler::PokeGC(JS::GCReason aReason, JSObject* aObj,
|
|||
EnsureGCRunner(delay);
|
||||
}
|
||||
|
||||
void CCGCScheduler::PokeMinorGC(JS::GCReason aReason) {
|
||||
MOZ_ASSERT(aReason != JS::GCReason::NO_REASON);
|
||||
|
||||
if (mDidShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetWantEagerMinorGC(aReason);
|
||||
|
||||
if (mGCRunner || mHaveAskedParent || mCCRunner) {
|
||||
// There's already a runner, or there will be, so just return.
|
||||
return;
|
||||
}
|
||||
|
||||
// Immediately start looking for idle time to run the minor GC.
|
||||
EnsureGCRunner(0);
|
||||
}
|
||||
|
||||
void CCGCScheduler::EnsureGCRunner(TimeDuration aDelay) {
|
||||
if (mGCRunner) {
|
||||
return;
|
||||
|
@ -828,10 +788,6 @@ CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline, TimeStamp aNow,
|
|||
return {CCRunnerAction::StopRunning, Yield};
|
||||
}
|
||||
|
||||
if (mEagerMinorGCReason != JS::GCReason::NO_REASON && !aDeadline.IsNull()) {
|
||||
return {CCRunnerAction::MinorGC, Continue, mEagerMinorGCReason};
|
||||
}
|
||||
|
||||
switch (mCCRunnerState) {
|
||||
// ReducePurple: a GC ran (or we otherwise decided to try CC'ing). Wait
|
||||
// for some amount of time (kCCDelay, or less if incremental GC blocked
|
||||
|
@ -916,7 +872,7 @@ CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline, TimeStamp aNow,
|
|||
// CycleCollecting: continue running slices until done.
|
||||
case CCRunnerState::CycleCollecting: {
|
||||
CCRunnerStep step{CCRunnerAction::CycleCollect, Yield};
|
||||
step.mParam.mCCReason = mCCReason;
|
||||
step.mCCReason = mCCReason;
|
||||
mCCReason = CCReason::SLICE; // Set reason for following slices.
|
||||
return step;
|
||||
}
|
||||
|
@ -926,33 +882,18 @@ CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline, TimeStamp aNow,
|
|||
};
|
||||
}
|
||||
|
||||
GCRunnerStep CCGCScheduler::GetNextGCRunnerAction(TimeStamp aDeadline) const {
|
||||
GCRunnerStep CCGCScheduler::GetNextGCRunnerAction() const {
|
||||
MOZ_ASSERT(mMajorGCReason != JS::GCReason::NO_REASON);
|
||||
|
||||
if (InIncrementalGC()) {
|
||||
MOZ_ASSERT(mMajorGCReason != JS::GCReason::NO_REASON);
|
||||
return {GCRunnerAction::GCSlice, mMajorGCReason};
|
||||
}
|
||||
|
||||
// Service a non-eager GC request first, even if it requires waiting.
|
||||
if (mMajorGCReason != JS::GCReason::NO_REASON) {
|
||||
return {mReadyForMajorGC ? GCRunnerAction::StartMajorGC
|
||||
: GCRunnerAction::WaitToMajorGC,
|
||||
mMajorGCReason};
|
||||
if (mReadyForMajorGC) {
|
||||
return {GCRunnerAction::StartMajorGC, mMajorGCReason};
|
||||
}
|
||||
|
||||
// Now for eager requests, which are ignored unless we're idle.
|
||||
if (!aDeadline.IsNull()) {
|
||||
if (mEagerMajorGCReason != JS::GCReason::NO_REASON) {
|
||||
return {mReadyForMajorGC ? GCRunnerAction::StartMajorGC
|
||||
: GCRunnerAction::WaitToMajorGC,
|
||||
mEagerMajorGCReason};
|
||||
}
|
||||
|
||||
if (mEagerMinorGCReason != JS::GCReason::NO_REASON) {
|
||||
return {GCRunnerAction::MinorGC, mEagerMinorGCReason};
|
||||
}
|
||||
}
|
||||
|
||||
return {GCRunnerAction::None, JS::GCReason::NO_REASON};
|
||||
return {GCRunnerAction::WaitToMajorGC, mMajorGCReason};
|
||||
}
|
||||
|
||||
js::SliceBudget CCGCScheduler::ComputeForgetSkippableBudget(
|
||||
|
|
|
@ -63,7 +63,6 @@ static const uint32_t kCCPurpleLimit = 200;
|
|||
|
||||
// Actions performed by the GCRunner state machine.
|
||||
enum class GCRunnerAction {
|
||||
MinorGC, // Run a minor GC (nursery collection)
|
||||
WaitToMajorGC, // We want to start a new major GC
|
||||
StartMajorGC, // The parent says we may begin our major GC
|
||||
GCSlice, // Run a single slice of a major GC
|
||||
|
@ -75,24 +74,12 @@ struct GCRunnerStep {
|
|||
JS::GCReason mReason;
|
||||
};
|
||||
|
||||
// Actions that are output from the CCRunner state machine.
|
||||
enum class CCRunnerAction {
|
||||
// Do nothing.
|
||||
None,
|
||||
|
||||
// We crossed an eager minor GC threshold in the middle of an incremental CC,
|
||||
// and we have some idle time.
|
||||
MinorGC,
|
||||
|
||||
// Various cleanup actions.
|
||||
ForgetSkippable,
|
||||
CleanupContentUnbinder,
|
||||
CleanupDeferred,
|
||||
|
||||
// Do the actual cycle collection (build the graph etc).
|
||||
CycleCollect,
|
||||
|
||||
// All done.
|
||||
StopRunning
|
||||
};
|
||||
|
||||
|
@ -104,30 +91,20 @@ enum CCRunnerForgetSkippableRemoveChildless {
|
|||
};
|
||||
|
||||
struct CCRunnerStep {
|
||||
// The action the scheduler is instructing the caller to perform.
|
||||
// The action to scheduler is instructing the caller to perform.
|
||||
CCRunnerAction mAction;
|
||||
|
||||
// Whether to stop processing actions for this invocation of the timer
|
||||
// callback.
|
||||
CCRunnerYield mYield;
|
||||
|
||||
union ActionData {
|
||||
// If the action is ForgetSkippable, then whether to remove childless nodes
|
||||
// or not.
|
||||
CCRunnerForgetSkippableRemoveChildless mRemoveChildless;
|
||||
// If the action is ForgetSkippable, then whether to remove childless nodes
|
||||
// or not. (ForgetSkippable is the only action requiring a parameter; if
|
||||
// that changes, this will become a union.)
|
||||
CCRunnerForgetSkippableRemoveChildless mRemoveChildless;
|
||||
|
||||
// If the action is CycleCollect, the reason for the collection.
|
||||
CCReason mCCReason;
|
||||
|
||||
// If the action is MinorGC, the reason for the GC.
|
||||
JS::GCReason mReason;
|
||||
|
||||
MOZ_IMPLICIT ActionData(CCRunnerForgetSkippableRemoveChildless v)
|
||||
: mRemoveChildless(v) {}
|
||||
MOZ_IMPLICIT ActionData(CCReason v) : mCCReason(v) {}
|
||||
MOZ_IMPLICIT ActionData(JS::GCReason v) : mReason(v) {}
|
||||
ActionData() = default;
|
||||
} mParam;
|
||||
// If the action is CycleCollect, the reason for the collection.
|
||||
CCReason mCCReason;
|
||||
};
|
||||
|
||||
class CCGCScheduler {
|
||||
|
@ -168,7 +145,6 @@ class CCGCScheduler {
|
|||
void PokeShrinkingGC();
|
||||
void PokeFullGC();
|
||||
void MaybePokeCC(TimeStamp aNow, uint32_t aSuspectedCCObjects);
|
||||
void PokeMinorGC(JS::GCReason aReason);
|
||||
|
||||
void UserIsInactive();
|
||||
void UserIsActive();
|
||||
|
@ -239,12 +215,6 @@ class CCGCScheduler {
|
|||
}
|
||||
}
|
||||
|
||||
void SetWantEagerMinorGC(JS::GCReason aReason) {
|
||||
if (mEagerMinorGCReason == JS::GCReason::NO_REASON) {
|
||||
mEagerMinorGCReason = aReason;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the current runner does a cycle collection, and trigger a GC
|
||||
// after it finishes.
|
||||
void EnsureCCThenGC(CCReason aReason) {
|
||||
|
@ -265,7 +235,7 @@ class CCGCScheduler {
|
|||
}
|
||||
|
||||
// Starting a major GC (incremental or non-incremental).
|
||||
void NoteGCBegin(JS::GCReason aReason);
|
||||
void NoteGCBegin();
|
||||
|
||||
// Major GC completed.
|
||||
void NoteGCEnd();
|
||||
|
@ -273,8 +243,6 @@ class CCGCScheduler {
|
|||
// A timer fired, but then decided not to run a GC.
|
||||
void NoteWontGC();
|
||||
|
||||
void NoteMinorGCEnd() { mEagerMinorGCReason = JS::GCReason::NO_REASON; }
|
||||
|
||||
// This is invoked when we reach the actual cycle collection portion of the
|
||||
// overall cycle collection.
|
||||
void NoteCCBegin(CCReason aReason, TimeStamp aWhen);
|
||||
|
@ -456,13 +424,7 @@ class CCGCScheduler {
|
|||
mCCReason = CCReason::NO_REASON;
|
||||
}
|
||||
|
||||
bool HasMoreIdleGCRunnerWork() const {
|
||||
return mMajorGCReason != JS::GCReason::NO_REASON ||
|
||||
mEagerMajorGCReason != JS::GCReason::NO_REASON ||
|
||||
mEagerMinorGCReason != JS::GCReason::NO_REASON;
|
||||
}
|
||||
|
||||
GCRunnerStep GetNextGCRunnerAction(TimeStamp aDeadline) const;
|
||||
GCRunnerStep GetNextGCRunnerAction() const;
|
||||
|
||||
CCRunnerStep AdvanceCCRunner(TimeStamp aDeadline, TimeStamp aNow,
|
||||
uint32_t aSuspectedCCObjects);
|
||||
|
@ -534,8 +496,6 @@ class CCGCScheduler {
|
|||
|
||||
mozilla::CCReason mCCReason = mozilla::CCReason::NO_REASON;
|
||||
JS::GCReason mMajorGCReason = JS::GCReason::NO_REASON;
|
||||
JS::GCReason mEagerMajorGCReason = JS::GCReason::NO_REASON;
|
||||
JS::GCReason mEagerMinorGCReason = JS::GCReason::NO_REASON;
|
||||
|
||||
bool mIsCompactingOnUserInactive = false;
|
||||
bool mIsCollectingCycles = false;
|
||||
|
|
|
@ -1547,15 +1547,9 @@ bool CCGCScheduler::CCRunnerFired(TimeStamp aDeadline) {
|
|||
case CCRunnerAction::None:
|
||||
break;
|
||||
|
||||
case CCRunnerAction::MinorGC:
|
||||
JS::MaybeRunNurseryCollection(CycleCollectedJSRuntime::Get()->Runtime(),
|
||||
step.mParam.mReason);
|
||||
sScheduler.NoteMinorGCEnd();
|
||||
break;
|
||||
|
||||
case CCRunnerAction::ForgetSkippable:
|
||||
// 'Forget skippable' only, then end this invocation.
|
||||
FireForgetSkippable(bool(step.mParam.mRemoveChildless), aDeadline);
|
||||
FireForgetSkippable(bool(step.mRemoveChildless), aDeadline);
|
||||
break;
|
||||
|
||||
case CCRunnerAction::CleanupContentUnbinder:
|
||||
|
@ -1570,7 +1564,7 @@ bool CCGCScheduler::CCRunnerFired(TimeStamp aDeadline) {
|
|||
|
||||
case CCRunnerAction::CycleCollect:
|
||||
// Cycle collection slice.
|
||||
nsJSContext::RunCycleCollectorSlice(step.mParam.mCCReason, aDeadline);
|
||||
nsJSContext::RunCycleCollectorSlice(step.mCCReason, aDeadline);
|
||||
break;
|
||||
|
||||
case CCRunnerAction::StopRunning:
|
||||
|
@ -1656,23 +1650,6 @@ void nsJSContext::PokeGC(JS::GCReason aReason, JSObject* aObj,
|
|||
}
|
||||
|
||||
// static
|
||||
void nsJSContext::MaybePokeGC() {
|
||||
if (sShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSRuntime* rt = CycleCollectedJSRuntime::Get()->Runtime();
|
||||
JS::GCReason reason = JS::WantEagerMinorGC(rt);
|
||||
if (reason != JS::GCReason::NO_REASON) {
|
||||
MOZ_ASSERT(reason == JS::GCReason::EAGER_NURSERY_COLLECTION);
|
||||
sScheduler.PokeMinorGC(reason);
|
||||
}
|
||||
reason = JS::WantEagerMajorGC(rt);
|
||||
if (reason != JS::GCReason::NO_REASON) {
|
||||
PokeGC(reason, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void nsJSContext::DoLowMemoryGC() {
|
||||
if (sShuttingDown) {
|
||||
return;
|
||||
|
@ -1715,7 +1692,7 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
|
|||
switch (aProgress) {
|
||||
case JS::GC_CYCLE_BEGIN: {
|
||||
// Prevent cycle collections and shrinking during incremental GC.
|
||||
sScheduler.NoteGCBegin(aDesc.reason_);
|
||||
sScheduler.NoteGCBegin();
|
||||
sCurrentGCStartTime = TimeStamp::Now();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -103,15 +103,10 @@ class nsJSContext : public nsIScriptContext {
|
|||
static void MaybeRunNextCollectorSlice(nsIDocShell* aDocShell,
|
||||
JS::GCReason aReason);
|
||||
|
||||
// The GC should run soon, in the zone of aObj if given. If aObj is
|
||||
// nullptr, collect all Zones.
|
||||
// The GC should probably run soon, in the zone of object aObj (if given).
|
||||
static void PokeGC(JS::GCReason aReason, JSObject* aObj,
|
||||
mozilla::TimeDuration aDelay = 0);
|
||||
|
||||
// If usage is nearing a threshold, request idle-only GC work. (This is called
|
||||
// when a collection would be relatively convenient.)
|
||||
static void MaybePokeGC();
|
||||
|
||||
// Immediately perform a non-incremental shrinking GC and CC.
|
||||
static void DoLowMemoryGC();
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ void TestGC::Run(int aNumSlices) {
|
|||
CCReason neededCCAtStartOfGC =
|
||||
mScheduler.IsCCNeeded(Now(), SuspectedCCObjects());
|
||||
|
||||
mScheduler.NoteGCBegin(JS::GCReason::API);
|
||||
mScheduler.NoteGCBegin();
|
||||
|
||||
for (int slice = 0; slice < aNumSlices; slice++) {
|
||||
EXPECT_TRUE(mScheduler.InIncrementalGC());
|
||||
|
@ -125,7 +125,7 @@ void TestCC::TimerFires(int aNumSlices) {
|
|||
mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
|
||||
// Should first see a series of ForgetSkippable actions.
|
||||
if (step.mAction != CCRunnerAction::ForgetSkippable ||
|
||||
step.mParam.mRemoveChildless != KeepChildless) {
|
||||
step.mRemoveChildless != KeepChildless) {
|
||||
break;
|
||||
}
|
||||
EXPECT_EQ(step.mYield, Yield);
|
||||
|
@ -138,7 +138,7 @@ void TestCC::TimerFires(int aNumSlices) {
|
|||
mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
|
||||
}
|
||||
EXPECT_EQ(step.mAction, CCRunnerAction::ForgetSkippable);
|
||||
EXPECT_EQ(step.mParam.mRemoveChildless, RemoveChildless);
|
||||
EXPECT_EQ(step.mRemoveChildless, RemoveChildless);
|
||||
ForgetSkippable();
|
||||
|
||||
TimeStamp idleDeadline = Now() + kOneSecond;
|
||||
|
|
|
@ -416,8 +416,8 @@ typedef enum JSGCParamKey {
|
|||
JSGC_MINOR_GC_NUMBER = 45,
|
||||
|
||||
/**
|
||||
* JS::MaybeRunNurseryCollection will collect the nursery if it hasn't been
|
||||
* collected in this many milliseconds.
|
||||
* JS::RunIdleTimeGCTask will collect the nursery if it hasn't been collected
|
||||
* in this many milliseconds.
|
||||
*
|
||||
* Default: 5000
|
||||
* Pref: None
|
||||
|
@ -551,7 +551,7 @@ namespace JS {
|
|||
D(OUT_OF_NURSERY, 10) \
|
||||
D(EVICT_NURSERY, 11) \
|
||||
D(SHARED_MEMORY_LIMIT, 13) \
|
||||
D(EAGER_NURSERY_COLLECTION, 14) \
|
||||
D(IDLE_TIME_COLLECTION, 14) \
|
||||
D(BG_TASK_FINISHED, 15) \
|
||||
D(ABORT_GC, 16) \
|
||||
D(FULL_WHOLE_CELL_BUFFER, 17) \
|
||||
|
@ -1237,12 +1237,9 @@ JS_GetExternalStringCallbacks(JSString* str);
|
|||
|
||||
namespace JS {
|
||||
|
||||
extern JS_PUBLIC_API GCReason WantEagerMinorGC(JSRuntime* rt);
|
||||
extern JS_PUBLIC_API bool IsIdleGCTaskNeeded(JSRuntime* rt);
|
||||
|
||||
extern JS_PUBLIC_API GCReason WantEagerMajorGC(JSRuntime* rt);
|
||||
|
||||
extern JS_PUBLIC_API void MaybeRunNurseryCollection(JSRuntime* rt,
|
||||
JS::GCReason reason);
|
||||
extern JS_PUBLIC_API void RunIdleTimeGCTask(JSRuntime* rt);
|
||||
|
||||
extern JS_PUBLIC_API void SetHostCleanupFinalizationRegistryCallback(
|
||||
JSContext* cx, JSHostCleanupFinalizationRegistryCallback cb, void* data);
|
||||
|
|
|
@ -1651,31 +1651,28 @@ void GCRuntime::maybeGC() {
|
|||
}
|
||||
#endif
|
||||
|
||||
(void)gcIfRequestedImpl(/* eagerOk = */ true);
|
||||
}
|
||||
|
||||
JS::GCReason GCRuntime::wantMajorGC(bool eagerOk) {
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
||||
|
||||
if (majorGCRequested()) {
|
||||
return majorGCTriggerReason;
|
||||
if (gcIfRequested()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isIncrementalGCInProgress() || !eagerOk) {
|
||||
return JS::GCReason::NO_REASON;
|
||||
if (isIncrementalGCInProgress()) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::GCReason reason = JS::GCReason::NO_REASON;
|
||||
bool scheduledZones = false;
|
||||
for (ZonesIter zone(this, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (checkEagerAllocTrigger(zone->gcHeapSize, zone->gcHeapThreshold) ||
|
||||
checkEagerAllocTrigger(zone->mallocHeapSize,
|
||||
zone->mallocHeapThreshold)) {
|
||||
zone->scheduleGC();
|
||||
reason = JS::GCReason::EAGER_ALLOC_TRIGGER;
|
||||
scheduledZones = true;
|
||||
}
|
||||
}
|
||||
|
||||
return reason;
|
||||
if (scheduledZones) {
|
||||
SliceBudget budget = defaultBudget(JS::GCReason::EAGER_ALLOC_TRIGGER, 0);
|
||||
startGC(JS::GCOptions::Normal, JS::GCReason::EAGER_ALLOC_TRIGGER, budget);
|
||||
}
|
||||
}
|
||||
|
||||
bool GCRuntime::checkEagerAllocTrigger(const HeapSize& size,
|
||||
|
@ -4181,25 +4178,24 @@ void GCRuntime::startBackgroundFreeAfterMinorGC() {
|
|||
startBackgroundFree();
|
||||
}
|
||||
|
||||
bool GCRuntime::gcIfRequestedImpl(bool eagerOk) {
|
||||
bool GCRuntime::gcIfRequested() {
|
||||
// This method returns whether a major GC was performed.
|
||||
|
||||
if (nursery().minorGCRequested()) {
|
||||
minorGC(nursery().minorGCTriggerReason());
|
||||
}
|
||||
|
||||
JS::GCReason reason = wantMajorGC(eagerOk);
|
||||
if (reason == JS::GCReason::NO_REASON) {
|
||||
return false;
|
||||
if (majorGCRequested()) {
|
||||
SliceBudget budget = defaultBudget(majorGCTriggerReason, 0);
|
||||
if (!isIncrementalGCInProgress()) {
|
||||
startGC(JS::GCOptions::Normal, majorGCTriggerReason, budget);
|
||||
} else {
|
||||
gcSlice(majorGCTriggerReason, budget);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SliceBudget budget = defaultBudget(reason, 0);
|
||||
if (!isIncrementalGCInProgress()) {
|
||||
startGC(JS::GCOptions::Normal, reason, budget);
|
||||
} else {
|
||||
gcSlice(reason, budget);
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void js::gc::FinishGC(JSContext* cx, JS::GCReason reason) {
|
||||
|
|
|
@ -330,27 +330,11 @@ class GCRuntime {
|
|||
// The return value indicates if we were able to do the GC.
|
||||
bool triggerZoneGC(Zone* zone, JS::GCReason reason, size_t usedBytes,
|
||||
size_t thresholdBytes);
|
||||
|
||||
void maybeGC();
|
||||
|
||||
// Return whether we want to run a major GC. If eagerOk is true, include eager
|
||||
// triggers (eg EAGER_ALLOC_TRIGGER) in this determination, and schedule all
|
||||
// zones that exceed the eager thresholds.
|
||||
JS::GCReason wantMajorGC(bool eagerOk);
|
||||
bool checkEagerAllocTrigger(const HeapSize& size,
|
||||
const HeapThreshold& threshold);
|
||||
|
||||
// Do a minor GC if requested, followed by a major GC if requested. The return
|
||||
// value indicates whether a major GC was performed.
|
||||
bool gcIfRequested() { return gcIfRequestedImpl(false); }
|
||||
|
||||
// Internal function to do a GC if previously requested. But if not and
|
||||
// eagerOk, do an eager GC for all Zones that have exceeded the eager
|
||||
// thresholds.
|
||||
//
|
||||
// Return whether a major GC was performed or started.
|
||||
bool gcIfRequestedImpl(bool eagerOk);
|
||||
|
||||
// The return value indicates whether a major GC was performed.
|
||||
bool gcIfRequested();
|
||||
void gc(JS::GCOptions options, JS::GCReason reason);
|
||||
void startGC(JS::GCOptions options, JS::GCReason reason,
|
||||
const SliceBudget& budget);
|
||||
|
|
|
@ -1287,22 +1287,15 @@ JS_PUBLIC_API void JS_RemoveExtraGCRootsTracer(JSContext* cx,
|
|||
return cx->runtime()->gc.removeBlackRootsTracer(traceOp, data);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::GCReason JS::WantEagerMinorGC(JSRuntime* rt) {
|
||||
if (rt->gc.nursery().shouldCollect()) {
|
||||
return JS::GCReason::EAGER_NURSERY_COLLECTION;
|
||||
}
|
||||
return JS::GCReason::NO_REASON;
|
||||
JS_PUBLIC_API bool JS::IsIdleGCTaskNeeded(JSRuntime* rt) {
|
||||
// Currently, we only collect nursery during idle time.
|
||||
return rt->gc.nursery().shouldCollect();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::GCReason JS::WantEagerMajorGC(JSRuntime* rt) {
|
||||
return rt->gc.wantMajorGC(true);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void JS::MaybeRunNurseryCollection(JSRuntime* rt,
|
||||
JS::GCReason reason) {
|
||||
JS_PUBLIC_API void JS::RunIdleTimeGCTask(JSRuntime* rt) {
|
||||
gc::GCRuntime& gc = rt->gc;
|
||||
if (gc.nursery().shouldCollect()) {
|
||||
gc.minorGC(reason);
|
||||
gc.minorGC(JS::GCReason::IDLE_TIME_COLLECTION);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "nsCCUncollectableMarker.h"
|
||||
#include "nsCycleCollectionNoteRootCallback.h"
|
||||
#include "nsCycleCollector.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/ArrayBuffer.h"
|
||||
#include "js/ContextOptions.h"
|
||||
|
@ -1491,8 +1490,6 @@ void XPCJSContext::AfterProcessTask(uint32_t aNewRecursionDepth) {
|
|||
SetPendingException(nullptr);
|
||||
}
|
||||
|
||||
void XPCJSContext::MaybePokeGC() { nsJSContext::MaybePokeGC(); }
|
||||
|
||||
bool XPCJSContext::IsSystemCaller() const {
|
||||
return nsContentUtils::IsSystemCaller(Context());
|
||||
}
|
||||
|
|
|
@ -337,10 +337,6 @@ class XPCJSContext final : public mozilla::CycleCollectedJSContext,
|
|||
virtual void BeforeProcessTask(bool aMightBlock) override;
|
||||
virtual void AfterProcessTask(uint32_t aNewRecursionDepth) override;
|
||||
|
||||
// Relay to the CCGCScheduler instead of queuing up an idle runnable
|
||||
// (as is done for workers in CycleCollectedJSContext).
|
||||
virtual void MaybePokeGC() override;
|
||||
|
||||
~XPCJSContext();
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
|
|
@ -467,7 +467,7 @@ void CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth) {
|
|||
|
||||
// This should be a fast test so that it won't affect the next task
|
||||
// processing.
|
||||
MaybePokeGC();
|
||||
IsIdleGCTaskNeeded();
|
||||
}
|
||||
|
||||
void CycleCollectedJSContext::AfterProcessMicrotasks() {
|
||||
|
@ -493,9 +493,7 @@ void CycleCollectedJSContext::AfterProcessMicrotasks() {
|
|||
JS::ClearKeptObjects(mJSContext);
|
||||
}
|
||||
|
||||
void CycleCollectedJSContext::MaybePokeGC() {
|
||||
// Worker-compatible check to see if we want to do an idle-time minor
|
||||
// GC.
|
||||
void CycleCollectedJSContext::IsIdleGCTaskNeeded() const {
|
||||
class IdleTimeGCTaskRunnable : public mozilla::IdleRunnable {
|
||||
public:
|
||||
using mozilla::IdleRunnable::IdleRunnable;
|
||||
|
|
|
@ -210,9 +210,8 @@ class CycleCollectedJSContext : dom::PerThreadAtomCache, private JS::JobQueue {
|
|||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
virtual void AfterProcessTask(uint32_t aRecursionDepth);
|
||||
|
||||
// Check whether any eager thresholds have been reached, which would mean
|
||||
// an idle GC task (minor or major) would be useful.
|
||||
virtual void MaybePokeGC();
|
||||
// Check whether we need an idle GC task.
|
||||
void IsIdleGCTaskNeeded() const;
|
||||
|
||||
uint32_t RecursionDepth() const;
|
||||
|
||||
|
|
|
@ -368,15 +368,14 @@ class CycleCollectedJSRuntime {
|
|||
|
||||
void RunIdleTimeGCTask() {
|
||||
if (HasPendingIdleGCTask()) {
|
||||
JS::MaybeRunNurseryCollection(Runtime(),
|
||||
JS::GCReason::EAGER_NURSERY_COLLECTION);
|
||||
JS::RunIdleTimeGCTask(Runtime());
|
||||
ClearPendingIdleGCTask();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsIdleGCTaskNeeded() {
|
||||
return !HasPendingIdleGCTask() && Runtime() &&
|
||||
JS::WantEagerMinorGC(Runtime()) != JS::GCReason::NO_REASON;
|
||||
JS::IsIdleGCTaskNeeded(Runtime());
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
Загрузка…
Ссылка в новой задаче