зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
299b5e79f7
|
@ -10381,7 +10381,7 @@ nsresult nsDocShell::DoChannelLoad(nsIChannel* aChannel,
|
||||||
// We're about to load a new page and it may take time before necko
|
// We're about to load a new page and it may take time before necko
|
||||||
// gives back any data, so main thread might have a chance to process a
|
// gives back any data, so main thread might have a chance to process a
|
||||||
// collector slice
|
// collector slice
|
||||||
nsJSContext::MaybeRunNextCollectorSlice(this, JS::gcreason::DOCSHELL);
|
nsJSContext::MaybeRunNextCollectorSlice(this, JS::GCReason::DOCSHELL);
|
||||||
|
|
||||||
// Success. Keep the initial ClientSource if it exists.
|
// Success. Keep the initial ClientSource if it exists.
|
||||||
cleanupInitialClient.release();
|
cleanupInitialClient.release();
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
/* static */ void FuzzingFunctions::GarbageCollect(const GlobalObject&) {
|
/* static */ void FuzzingFunctions::GarbageCollect(const GlobalObject&) {
|
||||||
nsJSContext::GarbageCollectNow(JS::gcreason::COMPONENT_UTILS,
|
nsJSContext::GarbageCollectNow(JS::GCReason::COMPONENT_UTILS,
|
||||||
nsJSContext::NonIncrementalGC,
|
nsJSContext::NonIncrementalGC,
|
||||||
nsJSContext::NonShrinkingGC);
|
nsJSContext::NonShrinkingGC);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1037,7 +1037,7 @@ NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener* aListener) {
|
nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener* aListener) {
|
||||||
AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC);
|
AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC);
|
||||||
|
|
||||||
nsJSContext::GarbageCollectNow(JS::gcreason::DOM_UTILS);
|
nsJSContext::GarbageCollectNow(JS::GCReason::DOM_UTILS);
|
||||||
nsJSContext::CycleCollectNow(aListener);
|
nsJSContext::CycleCollectNow(aListener);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -1051,7 +1051,7 @@ nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener* aListener) {
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::RunNextCollectorTimer() {
|
nsDOMWindowUtils::RunNextCollectorTimer() {
|
||||||
nsJSContext::RunNextCollectorTimer(JS::gcreason::DOM_WINDOW_UTILS);
|
nsJSContext::RunNextCollectorTimer(JS::GCReason::DOM_WINDOW_UTILS);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6006,10 +6006,11 @@ bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
|
||||||
nsJSUtils::ExecutionContext exec(aes.cx(), global);
|
nsJSUtils::ExecutionContext exec(aes.cx(), global);
|
||||||
rv = exec.Compile(options, handler->GetHandlerText());
|
rv = exec.Compile(options, handler->GetHandlerText());
|
||||||
|
|
||||||
if (rv == NS_OK) {
|
JS::Rooted<JSScript*> script(aes.cx(), exec.MaybeGetScript());
|
||||||
|
if (script) {
|
||||||
LoadedScript* initiatingScript = handler->GetInitiatingScript();
|
LoadedScript* initiatingScript = handler->GetInitiatingScript();
|
||||||
if (initiatingScript) {
|
if (initiatingScript) {
|
||||||
initiatingScript->AssociateWithScript(exec.GetScript());
|
initiatingScript->AssociateWithScript(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = exec.ExecScript();
|
rv = exec.ExecScript();
|
||||||
|
|
|
@ -2495,7 +2495,7 @@ void nsGlobalWindowOuter::DetachFromDocShell() {
|
||||||
// When we're about to destroy a top level content window
|
// When we're about to destroy a top level content window
|
||||||
// (for example a tab), we trigger a full GC by passing null as the last
|
// (for example a tab), we trigger a full GC by passing null as the last
|
||||||
// param. We also trigger a full GC for chrome windows.
|
// param. We also trigger a full GC for chrome windows.
|
||||||
nsJSContext::PokeGC(JS::gcreason::SET_DOC_SHELL,
|
nsJSContext::PokeGC(JS::GCReason::SET_DOC_SHELL,
|
||||||
(mTopLevelOuterContentWindow || mIsChrome)
|
(mTopLevelOuterContentWindow || mIsChrome)
|
||||||
? nullptr
|
? nullptr
|
||||||
: GetWrapperPreserveColor());
|
: GetWrapperPreserveColor());
|
||||||
|
|
|
@ -324,12 +324,12 @@ nsJSEnvironmentObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
||||||
// slow and it likely won't help us anyway.
|
// slow and it likely won't help us anyway.
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
|
nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
|
||||||
nsJSContext::NonIncrementalGC,
|
nsJSContext::NonIncrementalGC,
|
||||||
nsJSContext::ShrinkingGC);
|
nsJSContext::ShrinkingGC);
|
||||||
nsJSContext::CycleCollectNow();
|
nsJSContext::CycleCollectNow();
|
||||||
if (NeedsGCAfterCC()) {
|
if (NeedsGCAfterCC()) {
|
||||||
nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
|
nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
|
||||||
nsJSContext::NonIncrementalGC,
|
nsJSContext::NonIncrementalGC,
|
||||||
nsJSContext::ShrinkingGC);
|
nsJSContext::ShrinkingGC);
|
||||||
}
|
}
|
||||||
|
@ -577,7 +577,7 @@ nsJSContext::~nsJSContext() {
|
||||||
|
|
||||||
void nsJSContext::Destroy() {
|
void nsJSContext::Destroy() {
|
||||||
if (mGCOnDestruction) {
|
if (mGCOnDestruction) {
|
||||||
PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY, mWindowProxy);
|
PokeGC(JS::GCReason::NSJSCONTEXT_DESTROY, mWindowProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
DropJSObjects(this);
|
DropJSObjects(this);
|
||||||
|
@ -1079,17 +1079,17 @@ void nsJSContext::SetProcessingScriptTag(bool aFlag) {
|
||||||
void FullGCTimerFired(nsITimer* aTimer, void* aClosure) {
|
void FullGCTimerFired(nsITimer* aTimer, void* aClosure) {
|
||||||
nsJSContext::KillFullGCTimer();
|
nsJSContext::KillFullGCTimer();
|
||||||
MOZ_ASSERT(!aClosure, "Don't pass a closure to FullGCTimerFired");
|
MOZ_ASSERT(!aClosure, "Don't pass a closure to FullGCTimerFired");
|
||||||
nsJSContext::GarbageCollectNow(JS::gcreason::FULL_GC_TIMER,
|
nsJSContext::GarbageCollectNow(JS::GCReason::FULL_GC_TIMER,
|
||||||
nsJSContext::IncrementalGC);
|
nsJSContext::IncrementalGC);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
|
void nsJSContext::GarbageCollectNow(JS::GCReason aReason,
|
||||||
IsIncremental aIncremental,
|
IsIncremental aIncremental,
|
||||||
IsShrinking aShrinking,
|
IsShrinking aShrinking,
|
||||||
int64_t aSliceMillis) {
|
int64_t aSliceMillis) {
|
||||||
AUTO_PROFILER_LABEL_DYNAMIC_CSTR("nsJSContext::GarbageCollectNow", GCCC,
|
AUTO_PROFILER_LABEL_DYNAMIC_CSTR("nsJSContext::GarbageCollectNow", GCCC,
|
||||||
JS::gcreason::ExplainReason(aReason));
|
JS::ExplainGCReason(aReason));
|
||||||
|
|
||||||
MOZ_ASSERT_IF(aSliceMillis, aIncremental == IncrementalGC);
|
MOZ_ASSERT_IF(aSliceMillis, aIncremental == IncrementalGC);
|
||||||
|
|
||||||
|
@ -1113,7 +1113,7 @@ void nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
|
||||||
JSGCInvocationKind gckind = aShrinking == ShrinkingGC ? GC_SHRINK : GC_NORMAL;
|
JSGCInvocationKind gckind = aShrinking == ShrinkingGC ? GC_SHRINK : GC_NORMAL;
|
||||||
|
|
||||||
if (aIncremental == NonIncrementalGC ||
|
if (aIncremental == NonIncrementalGC ||
|
||||||
aReason == JS::gcreason::FULL_GC_TIMER) {
|
aReason == JS::GCReason::FULL_GC_TIMER) {
|
||||||
sNeedsFullGC = true;
|
sNeedsFullGC = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1139,7 +1139,7 @@ static void FinishAnyIncrementalGC() {
|
||||||
|
|
||||||
// We're in the middle of an incremental GC, so finish it.
|
// We're in the middle of an incremental GC, so finish it.
|
||||||
JS::PrepareForIncrementalGC(jsapi.cx());
|
JS::PrepareForIncrementalGC(jsapi.cx());
|
||||||
JS::FinishIncrementalGC(jsapi.cx(), JS::gcreason::CC_FORCED);
|
JS::FinishIncrementalGC(jsapi.cx(), JS::GCReason::CC_FORCED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1573,7 +1573,7 @@ void nsJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) {
|
||||||
uint32_t ccNowDuration = TimeBetween(gCCStats.mBeginTime, endCCTimeStamp);
|
uint32_t ccNowDuration = TimeBetween(gCCStats.mBeginTime, endCCTimeStamp);
|
||||||
|
|
||||||
if (NeedsGCAfterCC()) {
|
if (NeedsGCAfterCC()) {
|
||||||
PokeGC(JS::gcreason::CC_WAITING, nullptr,
|
PokeGC(JS::GCReason::CC_WAITING, nullptr,
|
||||||
NS_GC_DELAY - std::min(ccNowDuration, kMaxICCDuration));
|
NS_GC_DELAY - std::min(ccNowDuration, kMaxICCDuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1730,8 +1730,7 @@ bool InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData) {
|
||||||
TimeDuration duration = sGCUnnotifiedTotalTime;
|
TimeDuration duration = sGCUnnotifiedTotalTime;
|
||||||
uintptr_t reason = reinterpret_cast<uintptr_t>(aData);
|
uintptr_t reason = reinterpret_cast<uintptr_t>(aData);
|
||||||
nsJSContext::GarbageCollectNow(
|
nsJSContext::GarbageCollectNow(
|
||||||
aData ? static_cast<JS::gcreason::Reason>(reason)
|
aData ? static_cast<JS::GCReason>(reason) : JS::GCReason::INTER_SLICE_GC,
|
||||||
: JS::gcreason::INTER_SLICE_GC,
|
|
||||||
nsJSContext::IncrementalGC, nsJSContext::NonShrinkingGC, budget);
|
nsJSContext::IncrementalGC, nsJSContext::NonShrinkingGC, budget);
|
||||||
|
|
||||||
sGCUnnotifiedTotalTime = TimeDuration();
|
sGCUnnotifiedTotalTime = TimeDuration();
|
||||||
|
@ -1780,7 +1779,7 @@ void GCTimerFired(nsITimer* aTimer, void* aClosure) {
|
||||||
void ShrinkingGCTimerFired(nsITimer* aTimer, void* aClosure) {
|
void ShrinkingGCTimerFired(nsITimer* aTimer, void* aClosure) {
|
||||||
nsJSContext::KillShrinkingGCTimer();
|
nsJSContext::KillShrinkingGCTimer();
|
||||||
sIsCompactingOnUserInactive = true;
|
sIsCompactingOnUserInactive = true;
|
||||||
nsJSContext::GarbageCollectNow(JS::gcreason::USER_INACTIVE,
|
nsJSContext::GarbageCollectNow(JS::GCReason::USER_INACTIVE,
|
||||||
nsJSContext::IncrementalGC,
|
nsJSContext::IncrementalGC,
|
||||||
nsJSContext::ShrinkingGC);
|
nsJSContext::ShrinkingGC);
|
||||||
}
|
}
|
||||||
|
@ -1886,7 +1885,7 @@ uint32_t nsJSContext::CleanupsSinceLastGC() { return sCleanupsSinceLastGC; }
|
||||||
// collection we run on a long timer.
|
// collection we run on a long timer.
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void nsJSContext::RunNextCollectorTimer(JS::gcreason::Reason aReason,
|
void nsJSContext::RunNextCollectorTimer(JS::GCReason aReason,
|
||||||
mozilla::TimeStamp aDeadline) {
|
mozilla::TimeStamp aDeadline) {
|
||||||
if (sShuttingDown) {
|
if (sShuttingDown) {
|
||||||
return;
|
return;
|
||||||
|
@ -1925,7 +1924,7 @@ void nsJSContext::RunNextCollectorTimer(JS::gcreason::Reason aReason,
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void nsJSContext::MaybeRunNextCollectorSlice(nsIDocShell* aDocShell,
|
void nsJSContext::MaybeRunNextCollectorSlice(nsIDocShell* aDocShell,
|
||||||
JS::gcreason::Reason aReason) {
|
JS::GCReason aReason) {
|
||||||
if (!aDocShell || !XRE_IsContentProcess()) {
|
if (!aDocShell || !XRE_IsContentProcess()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1972,8 +1971,7 @@ void nsJSContext::MaybeRunNextCollectorSlice(nsIDocShell* aDocShell,
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void nsJSContext::PokeGC(JS::gcreason::Reason aReason, JSObject* aObj,
|
void nsJSContext::PokeGC(JS::GCReason aReason, JSObject* aObj, int aDelay) {
|
||||||
int aDelay) {
|
|
||||||
if (sShuttingDown) {
|
if (sShuttingDown) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1981,7 +1979,7 @@ void nsJSContext::PokeGC(JS::gcreason::Reason aReason, JSObject* aObj,
|
||||||
if (aObj) {
|
if (aObj) {
|
||||||
JS::Zone* zone = JS::GetObjectZone(aObj);
|
JS::Zone* zone = JS::GetObjectZone(aObj);
|
||||||
CycleCollectedJSRuntime::Get()->AddZoneWaitingForGC(zone);
|
CycleCollectedJSRuntime::Get()->AddZoneWaitingForGC(zone);
|
||||||
} else if (aReason != JS::gcreason::CC_WAITING) {
|
} else if (aReason != JS::GCReason::CC_WAITING) {
|
||||||
sNeedsFullGC = true;
|
sNeedsFullGC = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ class nsJSContext : public nsIScriptContext {
|
||||||
// Setup all the statics etc - safe to call multiple times after Startup().
|
// Setup all the statics etc - safe to call multiple times after Startup().
|
||||||
static void EnsureStatics();
|
static void EnsureStatics();
|
||||||
|
|
||||||
static void GarbageCollectNow(JS::gcreason::Reason reason,
|
static void GarbageCollectNow(JS::GCReason reason,
|
||||||
IsIncremental aIncremental = NonIncrementalGC,
|
IsIncremental aIncremental = NonIncrementalGC,
|
||||||
IsShrinking aShrinking = NonShrinkingGC,
|
IsShrinking aShrinking = NonShrinkingGC,
|
||||||
int64_t aSliceMillis = 0);
|
int64_t aSliceMillis = 0);
|
||||||
|
@ -97,17 +97,16 @@ class nsJSContext : public nsIScriptContext {
|
||||||
|
|
||||||
// If there is some pending CC or GC timer/runner, this will run it.
|
// If there is some pending CC or GC timer/runner, this will run it.
|
||||||
static void RunNextCollectorTimer(
|
static void RunNextCollectorTimer(
|
||||||
JS::gcreason::Reason aReason,
|
JS::GCReason aReason,
|
||||||
mozilla::TimeStamp aDeadline = mozilla::TimeStamp());
|
mozilla::TimeStamp aDeadline = mozilla::TimeStamp());
|
||||||
// If user has been idle and aDocShell is for an iframe being loaded in an
|
// If user has been idle and aDocShell is for an iframe being loaded in an
|
||||||
// already loaded top level docshell, this will run a CC or GC
|
// already loaded top level docshell, this will run a CC or GC
|
||||||
// timer/runner if there is such pending.
|
// timer/runner if there is such pending.
|
||||||
static void MaybeRunNextCollectorSlice(nsIDocShell *aDocShell,
|
static void MaybeRunNextCollectorSlice(nsIDocShell *aDocShell,
|
||||||
JS::gcreason::Reason aReason);
|
JS::GCReason aReason);
|
||||||
|
|
||||||
// The GC should probably run soon, in the zone of object aObj (if given).
|
// The GC should probably run soon, in the zone of object aObj (if given).
|
||||||
static void PokeGC(JS::gcreason::Reason aReason, JSObject *aObj,
|
static void PokeGC(JS::GCReason aReason, JSObject *aObj, int aDelay = 0);
|
||||||
int aDelay = 0);
|
|
||||||
static void KillGCTimer();
|
static void KillGCTimer();
|
||||||
|
|
||||||
static void PokeShrinkingGC();
|
static void PokeShrinkingGC();
|
||||||
|
|
|
@ -374,6 +374,10 @@ JSScript* nsJSUtils::ExecutionContext::GetScript() {
|
||||||
mScriptUsed = true;
|
mScriptUsed = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return MaybeGetScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSScript* nsJSUtils::ExecutionContext::MaybeGetScript() {
|
||||||
return mScript;
|
return mScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,6 +175,9 @@ class nsJSUtils {
|
||||||
// Get a successfully compiled script.
|
// Get a successfully compiled script.
|
||||||
JSScript* GetScript();
|
JSScript* GetScript();
|
||||||
|
|
||||||
|
// Get the compiled script if present, or nullptr.
|
||||||
|
JSScript* MaybeGetScript();
|
||||||
|
|
||||||
// Execute the compiled script and ignore the return value.
|
// Execute the compiled script and ignore the return value.
|
||||||
MOZ_MUST_USE nsresult ExecScript();
|
MOZ_MUST_USE nsresult ExecScript();
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ void MaybeCollectGarbageOnIPCMessage() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
|
nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
|
||||||
nsJSContext::CycleCollectNow();
|
nsJSContext::CycleCollectNow();
|
||||||
#endif // BUILD_GC_ON_IPC_MESSAGES
|
#endif // BUILD_GC_ON_IPC_MESSAGES
|
||||||
}
|
}
|
||||||
|
|
|
@ -2472,7 +2472,7 @@ mozilla::ipc::IPCResult ContentChild::RecvGarbageCollect() {
|
||||||
if (obs) {
|
if (obs) {
|
||||||
obs->NotifyObservers(nullptr, "child-gc-request", nullptr);
|
obs->NotifyObservers(nullptr, "child-gc-request", nullptr);
|
||||||
}
|
}
|
||||||
nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
|
nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2444,7 +2444,7 @@ class MOZ_RAII AutoSetProcessingScriptTag {
|
||||||
static nsresult ExecuteCompiledScript(JSContext* aCx,
|
static nsresult ExecuteCompiledScript(JSContext* aCx,
|
||||||
ScriptLoadRequest* aRequest,
|
ScriptLoadRequest* aRequest,
|
||||||
nsJSUtils::ExecutionContext& aExec) {
|
nsJSUtils::ExecutionContext& aExec) {
|
||||||
JS::Rooted<JSScript*> script(aCx, aExec.GetScript());
|
JS::Rooted<JSScript*> script(aCx, aExec.MaybeGetScript());
|
||||||
if (!script) {
|
if (!script) {
|
||||||
// Compilation succeeds without producing a script if scripting is
|
// Compilation succeeds without producing a script if scripting is
|
||||||
// disabled for the global.
|
// disabled for the global.
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsSMILInterval.h"
|
#include "SMILInterval.h"
|
||||||
|
|
||||||
nsSMILInterval::nsSMILInterval() : mBeginFixed(false), mEndFixed(false) {}
|
namespace mozilla {
|
||||||
|
|
||||||
nsSMILInterval::nsSMILInterval(const nsSMILInterval& aOther)
|
SMILInterval::SMILInterval() : mBeginFixed(false), mEndFixed(false) {}
|
||||||
|
|
||||||
|
SMILInterval::SMILInterval(const SMILInterval& aOther)
|
||||||
: mBegin(aOther.mBegin),
|
: mBegin(aOther.mBegin),
|
||||||
mEnd(aOther.mEnd),
|
mEnd(aOther.mEnd),
|
||||||
mBeginFixed(false),
|
mBeginFixed(false),
|
||||||
|
@ -25,13 +27,13 @@ nsSMILInterval::nsSMILInterval(const nsSMILInterval& aOther)
|
||||||
"Attempt to copy-construct an interval with fixed endpoints");
|
"Attempt to copy-construct an interval with fixed endpoints");
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSMILInterval::~nsSMILInterval() {
|
SMILInterval::~SMILInterval() {
|
||||||
MOZ_ASSERT(mDependentTimes.IsEmpty(),
|
MOZ_ASSERT(mDependentTimes.IsEmpty(),
|
||||||
"Destroying interval without disassociating dependent instance "
|
"Destroying interval without disassociating dependent instance "
|
||||||
"times. Unlink was not called");
|
"times. Unlink was not called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInterval::Unlink(bool aFiltered) {
|
void SMILInterval::Unlink(bool aFiltered) {
|
||||||
for (int32_t i = mDependentTimes.Length() - 1; i >= 0; --i) {
|
for (int32_t i = mDependentTimes.Length() - 1; i >= 0; --i) {
|
||||||
if (aFiltered) {
|
if (aFiltered) {
|
||||||
mDependentTimes[i]->HandleFilteredInterval();
|
mDependentTimes[i]->HandleFilteredInterval();
|
||||||
|
@ -50,17 +52,17 @@ void nsSMILInterval::Unlink(bool aFiltered) {
|
||||||
mEnd = nullptr;
|
mEnd = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSMILInstanceTime* nsSMILInterval::Begin() {
|
nsSMILInstanceTime* SMILInterval::Begin() {
|
||||||
MOZ_ASSERT(mBegin && mEnd, "Requesting Begin() on un-initialized interval.");
|
MOZ_ASSERT(mBegin && mEnd, "Requesting Begin() on un-initialized interval.");
|
||||||
return mBegin;
|
return mBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSMILInstanceTime* nsSMILInterval::End() {
|
nsSMILInstanceTime* SMILInterval::End() {
|
||||||
MOZ_ASSERT(mBegin && mEnd, "Requesting End() on un-initialized interval.");
|
MOZ_ASSERT(mBegin && mEnd, "Requesting End() on un-initialized interval.");
|
||||||
return mEnd;
|
return mEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin) {
|
void SMILInterval::SetBegin(nsSMILInstanceTime& aBegin) {
|
||||||
MOZ_ASSERT(aBegin.Time().IsDefinite(),
|
MOZ_ASSERT(aBegin.Time().IsDefinite(),
|
||||||
"Attempt to set unresolved or indefinite begin time on interval");
|
"Attempt to set unresolved or indefinite begin time on interval");
|
||||||
MOZ_ASSERT(!mBeginFixed,
|
MOZ_ASSERT(!mBeginFixed,
|
||||||
|
@ -74,7 +76,7 @@ void nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin) {
|
||||||
mBegin = &aBegin;
|
mBegin = &aBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInterval::SetEnd(nsSMILInstanceTime& aEnd) {
|
void SMILInterval::SetEnd(nsSMILInstanceTime& aEnd) {
|
||||||
MOZ_ASSERT(!mEndFixed, "Attempt to set end time but the end point is fixed");
|
MOZ_ASSERT(!mEndFixed, "Attempt to set end time but the end point is fixed");
|
||||||
// As with SetBegin, check we're not making an instance time dependent on
|
// As with SetBegin, check we're not making an instance time dependent on
|
||||||
// itself.
|
// itself.
|
||||||
|
@ -84,14 +86,14 @@ void nsSMILInterval::SetEnd(nsSMILInstanceTime& aEnd) {
|
||||||
mEnd = &aEnd;
|
mEnd = &aEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInterval::FixBegin() {
|
void SMILInterval::FixBegin() {
|
||||||
MOZ_ASSERT(mBegin && mEnd, "Fixing begin point on un-initialized interval");
|
MOZ_ASSERT(mBegin && mEnd, "Fixing begin point on un-initialized interval");
|
||||||
MOZ_ASSERT(!mBeginFixed, "Duplicate calls to FixBegin()");
|
MOZ_ASSERT(!mBeginFixed, "Duplicate calls to FixBegin()");
|
||||||
mBeginFixed = true;
|
mBeginFixed = true;
|
||||||
mBegin->AddRefFixedEndpoint();
|
mBegin->AddRefFixedEndpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInterval::FixEnd() {
|
void SMILInterval::FixEnd() {
|
||||||
MOZ_ASSERT(mBegin && mEnd, "Fixing end point on un-initialized interval");
|
MOZ_ASSERT(mBegin && mEnd, "Fixing end point on un-initialized interval");
|
||||||
MOZ_ASSERT(mBeginFixed,
|
MOZ_ASSERT(mBeginFixed,
|
||||||
"Fixing the end of an interval without a fixed begin");
|
"Fixing the end of an interval without a fixed begin");
|
||||||
|
@ -100,7 +102,7 @@ void nsSMILInterval::FixEnd() {
|
||||||
mEnd->AddRefFixedEndpoint();
|
mEnd->AddRefFixedEndpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInterval::AddDependentTime(nsSMILInstanceTime& aTime) {
|
void SMILInterval::AddDependentTime(nsSMILInstanceTime& aTime) {
|
||||||
RefPtr<nsSMILInstanceTime>* inserted =
|
RefPtr<nsSMILInstanceTime>* inserted =
|
||||||
mDependentTimes.InsertElementSorted(&aTime);
|
mDependentTimes.InsertElementSorted(&aTime);
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
|
@ -108,7 +110,7 @@ void nsSMILInterval::AddDependentTime(nsSMILInstanceTime& aTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInterval::RemoveDependentTime(const nsSMILInstanceTime& aTime) {
|
void SMILInterval::RemoveDependentTime(const nsSMILInstanceTime& aTime) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool found =
|
bool found =
|
||||||
#endif
|
#endif
|
||||||
|
@ -116,11 +118,11 @@ void nsSMILInterval::RemoveDependentTime(const nsSMILInstanceTime& aTime) {
|
||||||
MOZ_ASSERT(found, "Couldn't find instance time to delete.");
|
MOZ_ASSERT(found, "Couldn't find instance time to delete.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInterval::GetDependentTimes(InstanceTimeList& aTimes) {
|
void SMILInterval::GetDependentTimes(InstanceTimeList& aTimes) {
|
||||||
aTimes = mDependentTimes;
|
aTimes = mDependentTimes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsSMILInterval::IsDependencyChainLink() const {
|
bool SMILInterval::IsDependencyChainLink() const {
|
||||||
if (!mBegin || !mEnd)
|
if (!mBegin || !mEnd)
|
||||||
return false; // Not yet initialised so it can't be part of a chain
|
return false; // Not yet initialised so it can't be part of a chain
|
||||||
|
|
||||||
|
@ -132,3 +134,5 @@ bool nsSMILInterval::IsDependencyChainLink() const {
|
||||||
return (mBegin->IsDependent() && mBegin->GetBaseInterval() != this) ||
|
return (mBegin->IsDependent() && mBegin->GetBaseInterval() != this) ||
|
||||||
(mEnd->IsDependent() && mEnd->GetBaseInterval() != this);
|
(mEnd->IsDependent() && mEnd->GetBaseInterval() != this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
|
@ -10,8 +10,10 @@
|
||||||
#include "nsSMILInstanceTime.h"
|
#include "nsSMILInstanceTime.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// nsSMILInterval class
|
// SMILInterval class
|
||||||
//
|
//
|
||||||
// A structure consisting of a begin and end time. The begin time must be
|
// A structure consisting of a begin and end time. The begin time must be
|
||||||
// resolved (i.e. not indefinite or unresolved).
|
// resolved (i.e. not indefinite or unresolved).
|
||||||
|
@ -19,11 +21,11 @@
|
||||||
// For an overview of how this class is related to other SMIL time classes see
|
// For an overview of how this class is related to other SMIL time classes see
|
||||||
// the documentation in nsSMILTimeValue.h
|
// the documentation in nsSMILTimeValue.h
|
||||||
|
|
||||||
class nsSMILInterval {
|
class SMILInterval {
|
||||||
public:
|
public:
|
||||||
nsSMILInterval();
|
SMILInterval();
|
||||||
nsSMILInterval(const nsSMILInterval& aOther);
|
SMILInterval(const SMILInterval& aOther);
|
||||||
~nsSMILInterval();
|
~SMILInterval();
|
||||||
void Unlink(bool aFiltered = false);
|
void Unlink(bool aFiltered = false);
|
||||||
|
|
||||||
const nsSMILInstanceTime* Begin() const {
|
const nsSMILInstanceTime* Begin() const {
|
||||||
|
@ -79,4 +81,6 @@ class nsSMILInterval {
|
||||||
bool mEndFixed;
|
bool mEndFixed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // NS_SMILINTERVAL_H_
|
#endif // NS_SMILINTERVAL_H_
|
|
@ -5,15 +5,16 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "SMILParserUtils.h"
|
#include "SMILParserUtils.h"
|
||||||
|
|
||||||
|
#include "mozilla/SMILKeySpline.h"
|
||||||
|
#include "mozilla/SMILRepeatCount.h"
|
||||||
#include "mozilla/SVGContentUtils.h"
|
#include "mozilla/SVGContentUtils.h"
|
||||||
#include "mozilla/TextUtils.h"
|
#include "mozilla/TextUtils.h"
|
||||||
#include "SMILKeySpline.h"
|
|
||||||
#include "nsISMILAttr.h"
|
#include "nsISMILAttr.h"
|
||||||
#include "nsSMILValue.h"
|
#include "nsSMILValue.h"
|
||||||
#include "nsSMILTimeValue.h"
|
#include "nsSMILTimeValue.h"
|
||||||
#include "nsSMILTimeValueSpecParams.h"
|
#include "nsSMILTimeValueSpecParams.h"
|
||||||
#include "nsSMILTypes.h"
|
#include "nsSMILTypes.h"
|
||||||
#include "nsSMILRepeatCount.h"
|
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsCharSeparatedTokenizer.h"
|
#include "nsCharSeparatedTokenizer.h"
|
||||||
|
|
||||||
|
@ -551,7 +552,7 @@ bool SMILParserUtils::ParseValuesGeneric(const nsAString& aSpec,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SMILParserUtils::ParseRepeatCount(const nsAString& aSpec,
|
bool SMILParserUtils::ParseRepeatCount(const nsAString& aSpec,
|
||||||
nsSMILRepeatCount& aResult) {
|
SMILRepeatCount& aResult) {
|
||||||
const nsAString& spec = SMILParserUtils::TrimWhitespace(aSpec);
|
const nsAString& spec = SMILParserUtils::TrimWhitespace(aSpec);
|
||||||
|
|
||||||
if (spec.EqualsLiteral("indefinite")) {
|
if (spec.EqualsLiteral("indefinite")) {
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
#include "nsStringFwd.h"
|
#include "nsStringFwd.h"
|
||||||
|
|
||||||
class nsISMILAttr;
|
class nsISMILAttr;
|
||||||
class SMILKeySpline;
|
|
||||||
class nsSMILTimeValue;
|
class nsSMILTimeValue;
|
||||||
class nsSMILValue;
|
class nsSMILValue;
|
||||||
class nsSMILRepeatCount;
|
|
||||||
class nsSMILTimeValueSpecParams;
|
class nsSMILTimeValueSpecParams;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
class SMILKeySpline;
|
||||||
|
class SMILRepeatCount;
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class SVGAnimationElement;
|
class SVGAnimationElement;
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
@ -57,7 +57,7 @@ class SMILParserUtils {
|
||||||
GenericValueParser& aParser);
|
GenericValueParser& aParser);
|
||||||
|
|
||||||
static bool ParseRepeatCount(const nsAString& aSpec,
|
static bool ParseRepeatCount(const nsAString& aSpec,
|
||||||
nsSMILRepeatCount& aResult);
|
SMILRepeatCount& aResult);
|
||||||
|
|
||||||
static bool ParseTimeValueSpecParams(const nsAString& aSpec,
|
static bool ParseTimeValueSpecParams(const nsAString& aSpec,
|
||||||
nsSMILTimeValueSpecParams& aResult);
|
nsSMILTimeValueSpecParams& aResult);
|
||||||
|
|
|
@ -4,7 +4,12 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsSMILRepeatCount.h"
|
#include "SMILRepeatCount.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
/*static*/ const double SMILRepeatCount::kNotSet = -1.0;
|
||||||
|
/*static*/ const double SMILRepeatCount::kIndefinite = -2.0;
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
/*static*/ const double nsSMILRepeatCount::kNotSet = -1.0;
|
|
||||||
/*static*/ const double nsSMILRepeatCount::kIndefinite = -2.0;
|
|
|
@ -4,14 +4,16 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#ifndef nsSMILRepeatCount_h
|
#ifndef SMILRepeatCount_h
|
||||||
#define nsSMILRepeatCount_h
|
#define SMILRepeatCount_h
|
||||||
|
|
||||||
#include "nsDebug.h"
|
#include "nsDebug.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// nsSMILRepeatCount
|
// SMILRepeatCount
|
||||||
//
|
//
|
||||||
// A tri-state non-negative floating point number for representing the number of
|
// A tri-state non-negative floating point number for representing the number of
|
||||||
// times an animation repeat, i.e. the SMIL repeatCount attribute.
|
// times an animation repeat, i.e. the SMIL repeatCount attribute.
|
||||||
|
@ -21,10 +23,10 @@
|
||||||
// 2. set (with non-negative, non-zero count value)
|
// 2. set (with non-negative, non-zero count value)
|
||||||
// 3. indefinite
|
// 3. indefinite
|
||||||
//
|
//
|
||||||
class nsSMILRepeatCount {
|
class SMILRepeatCount {
|
||||||
public:
|
public:
|
||||||
nsSMILRepeatCount() : mCount(kNotSet) {}
|
SMILRepeatCount() : mCount(kNotSet) {}
|
||||||
explicit nsSMILRepeatCount(double aCount) : mCount(kNotSet) {
|
explicit SMILRepeatCount(double aCount) : mCount(kNotSet) {
|
||||||
SetCount(aCount);
|
SetCount(aCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +39,7 @@ class nsSMILRepeatCount {
|
||||||
bool IsIndefinite() const { return mCount == kIndefinite; }
|
bool IsIndefinite() const { return mCount == kIndefinite; }
|
||||||
bool IsSet() const { return mCount != kNotSet; }
|
bool IsSet() const { return mCount != kNotSet; }
|
||||||
|
|
||||||
nsSMILRepeatCount& operator=(double aCount) {
|
SMILRepeatCount& operator=(double aCount) {
|
||||||
SetCount(aCount);
|
SetCount(aCount);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -55,4 +57,6 @@ class nsSMILRepeatCount {
|
||||||
double mCount;
|
double mCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -548,14 +548,14 @@ void SMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly) {
|
||||||
|
|
||||||
switch (mElementState) {
|
switch (mElementState) {
|
||||||
case STATE_STARTUP: {
|
case STATE_STARTUP: {
|
||||||
nsSMILInterval firstInterval;
|
SMILInterval firstInterval;
|
||||||
mElementState =
|
mElementState =
|
||||||
GetNextInterval(nullptr, nullptr, nullptr, firstInterval)
|
GetNextInterval(nullptr, nullptr, nullptr, firstInterval)
|
||||||
? STATE_WAITING
|
? STATE_WAITING
|
||||||
: STATE_POSTACTIVE;
|
: STATE_POSTACTIVE;
|
||||||
stateChanged = true;
|
stateChanged = true;
|
||||||
if (mElementState == STATE_WAITING) {
|
if (mElementState == STATE_WAITING) {
|
||||||
mCurrentInterval = MakeUnique<nsSMILInterval>(firstInterval);
|
mCurrentInterval = MakeUnique<SMILInterval>(firstInterval);
|
||||||
NotifyNewInterval();
|
NotifyNewInterval();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
@ -592,7 +592,7 @@ void SMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly) {
|
||||||
bool didApplyEarlyEnd = ApplyEarlyEnd(sampleTime);
|
bool didApplyEarlyEnd = ApplyEarlyEnd(sampleTime);
|
||||||
|
|
||||||
if (mCurrentInterval->End()->Time() <= sampleTime) {
|
if (mCurrentInterval->End()->Time() <= sampleTime) {
|
||||||
nsSMILInterval newInterval;
|
SMILInterval newInterval;
|
||||||
mElementState = GetNextInterval(mCurrentInterval.get(), nullptr,
|
mElementState = GetNextInterval(mCurrentInterval.get(), nullptr,
|
||||||
nullptr, newInterval)
|
nullptr, newInterval)
|
||||||
? STATE_WAITING
|
? STATE_WAITING
|
||||||
|
@ -608,7 +608,7 @@ void SMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly) {
|
||||||
mOldIntervals.AppendElement(std::move(mCurrentInterval));
|
mOldIntervals.AppendElement(std::move(mCurrentInterval));
|
||||||
SampleFillValue();
|
SampleFillValue();
|
||||||
if (mElementState == STATE_WAITING) {
|
if (mElementState == STATE_WAITING) {
|
||||||
mCurrentInterval = MakeUnique<nsSMILInterval>(newInterval);
|
mCurrentInterval = MakeUnique<SMILInterval>(newInterval);
|
||||||
}
|
}
|
||||||
// We are now in a consistent state to dispatch notifications
|
// We are now in a consistent state to dispatch notifications
|
||||||
if (didApplyEarlyEnd) {
|
if (didApplyEarlyEnd) {
|
||||||
|
@ -950,7 +950,7 @@ nsresult SMILTimedElement::SetRepeatCount(const nsAString& aRepeatCountSpec) {
|
||||||
// Update the current interval before returning
|
// Update the current interval before returning
|
||||||
AutoIntervalUpdater updater(*this);
|
AutoIntervalUpdater updater(*this);
|
||||||
|
|
||||||
nsSMILRepeatCount newRepeatCount;
|
SMILRepeatCount newRepeatCount;
|
||||||
|
|
||||||
if (SMILParserUtils::ParseRepeatCount(aRepeatCountSpec, newRepeatCount)) {
|
if (SMILParserUtils::ParseRepeatCount(aRepeatCountSpec, newRepeatCount)) {
|
||||||
mRepeatCount = newRepeatCount;
|
mRepeatCount = newRepeatCount;
|
||||||
|
@ -1354,7 +1354,7 @@ void SMILTimedElement::DoPostSeek() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMILTimedElement::UnpreserveInstanceTimes(InstanceTimeList& aList) {
|
void SMILTimedElement::UnpreserveInstanceTimes(InstanceTimeList& aList) {
|
||||||
const nsSMILInterval* prevInterval = GetPreviousInterval();
|
const SMILInterval* prevInterval = GetPreviousInterval();
|
||||||
const nsSMILInstanceTime* cutoff =
|
const nsSMILInstanceTime* cutoff =
|
||||||
mCurrentInterval ? mCurrentInterval->Begin()
|
mCurrentInterval ? mCurrentInterval->Begin()
|
||||||
: prevInterval ? prevInterval->Begin() : nullptr;
|
: prevInterval ? prevInterval->Begin() : nullptr;
|
||||||
|
@ -1409,7 +1409,7 @@ void SMILTimedElement::FilterIntervals() {
|
||||||
: 0;
|
: 0;
|
||||||
IntervalList filteredList;
|
IntervalList filteredList;
|
||||||
for (uint32_t i = 0; i < mOldIntervals.Length(); ++i) {
|
for (uint32_t i = 0; i < mOldIntervals.Length(); ++i) {
|
||||||
nsSMILInterval* interval = mOldIntervals[i].get();
|
SMILInterval* interval = mOldIntervals[i].get();
|
||||||
if (i != 0 && /*skip first interval*/
|
if (i != 0 && /*skip first interval*/
|
||||||
i + 1 < mOldIntervals.Length() && /*skip previous interval*/
|
i + 1 < mOldIntervals.Length() && /*skip previous interval*/
|
||||||
(i < threshold || !interval->IsDependencyChainLink())) {
|
(i < threshold || !interval->IsDependencyChainLink())) {
|
||||||
|
@ -1477,7 +1477,7 @@ void SMILTimedElement::FilterInstanceTimes(InstanceTimeList& aList) {
|
||||||
if (mCurrentInterval) {
|
if (mCurrentInterval) {
|
||||||
timesToKeep.AppendElement(mCurrentInterval->Begin());
|
timesToKeep.AppendElement(mCurrentInterval->Begin());
|
||||||
}
|
}
|
||||||
const nsSMILInterval* prevInterval = GetPreviousInterval();
|
const SMILInterval* prevInterval = GetPreviousInterval();
|
||||||
if (prevInterval) {
|
if (prevInterval) {
|
||||||
timesToKeep.AppendElement(prevInterval->End());
|
timesToKeep.AppendElement(prevInterval->End());
|
||||||
}
|
}
|
||||||
|
@ -1496,9 +1496,8 @@ void SMILTimedElement::FilterInstanceTimes(InstanceTimeList& aList) {
|
||||||
// http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LC-Start
|
// http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LC-Start
|
||||||
//
|
//
|
||||||
bool SMILTimedElement::GetNextInterval(
|
bool SMILTimedElement::GetNextInterval(
|
||||||
const nsSMILInterval* aPrevInterval,
|
const SMILInterval* aPrevInterval, const SMILInterval* aReplacedInterval,
|
||||||
const nsSMILInterval* aReplacedInterval,
|
const nsSMILInstanceTime* aFixedBeginTime, SMILInterval& aResult) const {
|
||||||
const nsSMILInstanceTime* aFixedBeginTime, nsSMILInterval& aResult) const {
|
|
||||||
MOZ_ASSERT(!aFixedBeginTime || aFixedBeginTime->Time().IsDefinite(),
|
MOZ_ASSERT(!aFixedBeginTime || aFixedBeginTime->Time().IsDefinite(),
|
||||||
"Unresolved or indefinite begin time given for interval start");
|
"Unresolved or indefinite begin time given for interval start");
|
||||||
static const nsSMILTimeValue zeroTime(0L);
|
static const nsSMILTimeValue zeroTime(0L);
|
||||||
|
@ -1860,13 +1859,13 @@ void SMILTimedElement::UpdateCurrentInterval(bool aForceChangeNotice) {
|
||||||
// If the interval is active the begin time is fixed.
|
// If the interval is active the begin time is fixed.
|
||||||
const nsSMILInstanceTime* beginTime =
|
const nsSMILInstanceTime* beginTime =
|
||||||
mElementState == STATE_ACTIVE ? mCurrentInterval->Begin() : nullptr;
|
mElementState == STATE_ACTIVE ? mCurrentInterval->Begin() : nullptr;
|
||||||
nsSMILInterval updatedInterval;
|
SMILInterval updatedInterval;
|
||||||
if (GetNextInterval(GetPreviousInterval(), mCurrentInterval.get(), beginTime,
|
if (GetNextInterval(GetPreviousInterval(), mCurrentInterval.get(), beginTime,
|
||||||
updatedInterval)) {
|
updatedInterval)) {
|
||||||
if (mElementState == STATE_POSTACTIVE) {
|
if (mElementState == STATE_POSTACTIVE) {
|
||||||
MOZ_ASSERT(!mCurrentInterval,
|
MOZ_ASSERT(!mCurrentInterval,
|
||||||
"In postactive state but the interval has been set");
|
"In postactive state but the interval has been set");
|
||||||
mCurrentInterval = MakeUnique<nsSMILInterval>(updatedInterval);
|
mCurrentInterval = MakeUnique<SMILInterval>(updatedInterval);
|
||||||
mElementState = STATE_WAITING;
|
mElementState = STATE_WAITING;
|
||||||
NotifyNewInterval();
|
NotifyNewInterval();
|
||||||
|
|
||||||
|
@ -1930,7 +1929,7 @@ void SMILTimedElement::SampleFillValue() {
|
||||||
nsSMILTime activeTime;
|
nsSMILTime activeTime;
|
||||||
|
|
||||||
if (mElementState == STATE_WAITING || mElementState == STATE_POSTACTIVE) {
|
if (mElementState == STATE_WAITING || mElementState == STATE_POSTACTIVE) {
|
||||||
const nsSMILInterval* prevInterval = GetPreviousInterval();
|
const SMILInterval* prevInterval = GetPreviousInterval();
|
||||||
MOZ_ASSERT(prevInterval,
|
MOZ_ASSERT(prevInterval,
|
||||||
"Attempting to sample fill value but there is no previous "
|
"Attempting to sample fill value but there is no previous "
|
||||||
"interval");
|
"interval");
|
||||||
|
@ -2091,7 +2090,7 @@ void SMILTimedElement::NotifyNewInterval() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto iter = mTimeDependents.Iter(); !iter.Done(); iter.Next()) {
|
for (auto iter = mTimeDependents.Iter(); !iter.Done(); iter.Next()) {
|
||||||
nsSMILInterval* interval = mCurrentInterval.get();
|
SMILInterval* interval = mCurrentInterval.get();
|
||||||
// It's possible that in notifying one new time dependent of a new interval
|
// It's possible that in notifying one new time dependent of a new interval
|
||||||
// that a chain reaction is triggered which results in the original
|
// that a chain reaction is triggered which results in the original
|
||||||
// interval disappearing. If that's the case we can skip sending further
|
// interval disappearing. If that's the case we can skip sending further
|
||||||
|
@ -2104,7 +2103,7 @@ void SMILTimedElement::NotifyNewInterval() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMILTimedElement::NotifyChangedInterval(nsSMILInterval* aInterval,
|
void SMILTimedElement::NotifyChangedInterval(SMILInterval* aInterval,
|
||||||
bool aBeginObjectChanged,
|
bool aBeginObjectChanged,
|
||||||
bool aEndObjectChanged) {
|
bool aEndObjectChanged) {
|
||||||
MOZ_ASSERT(aInterval, "Null interval for change notification");
|
MOZ_ASSERT(aInterval, "Null interval for change notification");
|
||||||
|
@ -2144,14 +2143,14 @@ const nsSMILInstanceTime* SMILTimedElement::GetEffectiveBeginInstance() const {
|
||||||
|
|
||||||
case STATE_WAITING:
|
case STATE_WAITING:
|
||||||
case STATE_POSTACTIVE: {
|
case STATE_POSTACTIVE: {
|
||||||
const nsSMILInterval* prevInterval = GetPreviousInterval();
|
const SMILInterval* prevInterval = GetPreviousInterval();
|
||||||
return prevInterval ? prevInterval->Begin() : nullptr;
|
return prevInterval ? prevInterval->Begin() : nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MOZ_CRASH("Invalid element state");
|
MOZ_CRASH("Invalid element state");
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsSMILInterval* SMILTimedElement::GetPreviousInterval() const {
|
const SMILInterval* SMILTimedElement::GetPreviousInterval() const {
|
||||||
return mOldIntervals.IsEmpty()
|
return mOldIntervals.IsEmpty()
|
||||||
? nullptr
|
? nullptr
|
||||||
: mOldIntervals[mOldIntervals.Length() - 1].get();
|
: mOldIntervals[mOldIntervals.Length() - 1].get();
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
#include "mozilla/EventForwards.h"
|
#include "mozilla/EventForwards.h"
|
||||||
#include "mozilla/Move.h"
|
#include "mozilla/Move.h"
|
||||||
#include "mozilla/SMILMilestone.h"
|
#include "mozilla/SMILMilestone.h"
|
||||||
|
#include "mozilla/SMILInterval.h"
|
||||||
|
#include "mozilla/SMILRepeatCount.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "nsSMILInterval.h"
|
|
||||||
#include "nsSMILInstanceTime.h"
|
#include "nsSMILInstanceTime.h"
|
||||||
#include "nsSMILTimeValueSpec.h"
|
#include "nsSMILTimeValueSpec.h"
|
||||||
#include "nsSMILRepeatCount.h"
|
|
||||||
#include "nsSMILTypes.h"
|
#include "nsSMILTypes.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "nsTHashtable.h"
|
#include "nsTHashtable.h"
|
||||||
|
@ -348,7 +348,7 @@ class SMILTimedElement {
|
||||||
// Typedefs
|
// Typedefs
|
||||||
typedef nsTArray<UniquePtr<nsSMILTimeValueSpec>> TimeValueSpecList;
|
typedef nsTArray<UniquePtr<nsSMILTimeValueSpec>> TimeValueSpecList;
|
||||||
typedef nsTArray<RefPtr<nsSMILInstanceTime>> InstanceTimeList;
|
typedef nsTArray<RefPtr<nsSMILInstanceTime>> InstanceTimeList;
|
||||||
typedef nsTArray<UniquePtr<nsSMILInterval>> IntervalList;
|
typedef nsTArray<UniquePtr<SMILInterval>> IntervalList;
|
||||||
typedef nsPtrHashKey<nsSMILTimeValueSpec> TimeValueSpecPtrKey;
|
typedef nsPtrHashKey<nsSMILTimeValueSpec> TimeValueSpecPtrKey;
|
||||||
typedef nsTHashtable<TimeValueSpecPtrKey> TimeValueSpecHashSet;
|
typedef nsTHashtable<TimeValueSpecPtrKey> TimeValueSpecHashSet;
|
||||||
|
|
||||||
|
@ -459,13 +459,13 @@ class SMILTimedElement {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to iterate through this element's accumulated timing
|
* Helper function to iterate through this element's accumulated timing
|
||||||
* information (specifically old nsSMILIntervals and nsSMILTimeInstanceTimes)
|
* information (specifically old SMILIntervals and nsSMILTimeInstanceTimes)
|
||||||
* and discard items that are no longer needed or exceed some threshold of
|
* and discard items that are no longer needed or exceed some threshold of
|
||||||
* accumulated state.
|
* accumulated state.
|
||||||
*/
|
*/
|
||||||
void FilterHistory();
|
void FilterHistory();
|
||||||
|
|
||||||
// Helper functions for FilterHistory to clear old nsSMILIntervals and
|
// Helper functions for FilterHistory to clear old SMILIntervals and
|
||||||
// nsSMILInstanceTimes respectively.
|
// nsSMILInstanceTimes respectively.
|
||||||
void FilterIntervals();
|
void FilterIntervals();
|
||||||
void FilterInstanceTimes(InstanceTimeList& aList);
|
void FilterInstanceTimes(InstanceTimeList& aList);
|
||||||
|
@ -492,10 +492,10 @@ class SMILTimedElement {
|
||||||
* returned).
|
* returned).
|
||||||
* @return true if a suitable interval was found, false otherwise.
|
* @return true if a suitable interval was found, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool GetNextInterval(const nsSMILInterval* aPrevInterval,
|
bool GetNextInterval(const SMILInterval* aPrevInterval,
|
||||||
const nsSMILInterval* aReplacedInterval,
|
const SMILInterval* aReplacedInterval,
|
||||||
const nsSMILInstanceTime* aFixedBeginTime,
|
const nsSMILInstanceTime* aFixedBeginTime,
|
||||||
nsSMILInterval& aResult) const;
|
SMILInterval& aResult) const;
|
||||||
nsSMILInstanceTime* GetNextGreater(const InstanceTimeList& aList,
|
nsSMILInstanceTime* GetNextGreater(const InstanceTimeList& aList,
|
||||||
const nsSMILTimeValue& aBase,
|
const nsSMILTimeValue& aBase,
|
||||||
int32_t& aPosition) const;
|
int32_t& aPosition) const;
|
||||||
|
@ -525,12 +525,12 @@ class SMILTimedElement {
|
||||||
// (ii) after calling these methods we must assume that the state of the
|
// (ii) after calling these methods we must assume that the state of the
|
||||||
// element may have changed.
|
// element may have changed.
|
||||||
void NotifyNewInterval();
|
void NotifyNewInterval();
|
||||||
void NotifyChangedInterval(nsSMILInterval* aInterval,
|
void NotifyChangedInterval(SMILInterval* aInterval, bool aBeginObjectChanged,
|
||||||
bool aBeginObjectChanged, bool aEndObjectChanged);
|
bool aEndObjectChanged);
|
||||||
|
|
||||||
void FireTimeEventAsync(EventMessage aMsg, int32_t aDetail);
|
void FireTimeEventAsync(EventMessage aMsg, int32_t aDetail);
|
||||||
const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
|
const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
|
||||||
const nsSMILInterval* GetPreviousInterval() const;
|
const SMILInterval* GetPreviousInterval() const;
|
||||||
bool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
|
bool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
|
||||||
bool HasClientInFillRange() const;
|
bool HasClientInFillRange() const;
|
||||||
bool EndHasEventConditions() const;
|
bool EndHasEventConditions() const;
|
||||||
|
@ -557,7 +557,7 @@ class SMILTimedElement {
|
||||||
|
|
||||||
nsSMILTimeValue mSimpleDur;
|
nsSMILTimeValue mSimpleDur;
|
||||||
|
|
||||||
nsSMILRepeatCount mRepeatCount;
|
SMILRepeatCount mRepeatCount;
|
||||||
nsSMILTimeValue mRepeatDur;
|
nsSMILTimeValue mRepeatDur;
|
||||||
|
|
||||||
nsSMILTimeValue mMin;
|
nsSMILTimeValue mMin;
|
||||||
|
@ -580,7 +580,7 @@ class SMILTimedElement {
|
||||||
uint32_t mInstanceSerialIndex;
|
uint32_t mInstanceSerialIndex;
|
||||||
|
|
||||||
SMILAnimationFunction* mClient;
|
SMILAnimationFunction* mClient;
|
||||||
UniquePtr<nsSMILInterval> mCurrentInterval;
|
UniquePtr<SMILInterval> mCurrentInterval;
|
||||||
IntervalList mOldIntervals;
|
IntervalList mOldIntervals;
|
||||||
uint32_t mCurrentRepeatIteration;
|
uint32_t mCurrentRepeatIteration;
|
||||||
SMILMilestone mPrevRegisteredMilestone;
|
SMILMilestone mPrevRegisteredMilestone;
|
||||||
|
|
|
@ -12,8 +12,6 @@ MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'nsISMILAttr.h',
|
'nsISMILAttr.h',
|
||||||
'nsSMILInstanceTime.h',
|
'nsSMILInstanceTime.h',
|
||||||
'nsSMILInterval.h',
|
|
||||||
'nsSMILRepeatCount.h',
|
|
||||||
'nsSMILTimeValue.h',
|
'nsSMILTimeValue.h',
|
||||||
'nsSMILTimeValueSpec.h',
|
'nsSMILTimeValueSpec.h',
|
||||||
'nsSMILTimeValueSpecParams.h',
|
'nsSMILTimeValueSpecParams.h',
|
||||||
|
@ -26,10 +24,12 @@ EXPORTS.mozilla += [
|
||||||
'SMILAnimationFunction.h',
|
'SMILAnimationFunction.h',
|
||||||
'SMILCompositorTable.h',
|
'SMILCompositorTable.h',
|
||||||
'SMILCSSValueType.h',
|
'SMILCSSValueType.h',
|
||||||
|
'SMILInterval.h',
|
||||||
'SMILKeySpline.h',
|
'SMILKeySpline.h',
|
||||||
'SMILMilestone.h',
|
'SMILMilestone.h',
|
||||||
'SMILNullType.h',
|
'SMILNullType.h',
|
||||||
'SMILParserUtils.h',
|
'SMILParserUtils.h',
|
||||||
|
'SMILRepeatCount.h',
|
||||||
'SMILSetAnimationFunction.h',
|
'SMILSetAnimationFunction.h',
|
||||||
'SMILTargetIdentifier.h',
|
'SMILTargetIdentifier.h',
|
||||||
'SMILTimeContainer.h',
|
'SMILTimeContainer.h',
|
||||||
|
@ -43,8 +43,6 @@ EXPORTS.mozilla.dom += [
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'nsSMILInstanceTime.cpp',
|
'nsSMILInstanceTime.cpp',
|
||||||
'nsSMILInterval.cpp',
|
|
||||||
'nsSMILRepeatCount.cpp',
|
|
||||||
'nsSMILTimeValue.cpp',
|
'nsSMILTimeValue.cpp',
|
||||||
'nsSMILTimeValueSpec.cpp',
|
'nsSMILTimeValueSpec.cpp',
|
||||||
'nsSMILValue.cpp',
|
'nsSMILValue.cpp',
|
||||||
|
@ -57,9 +55,11 @@ UNIFIED_SOURCES += [
|
||||||
'SMILEnumType.cpp',
|
'SMILEnumType.cpp',
|
||||||
'SMILFloatType.cpp',
|
'SMILFloatType.cpp',
|
||||||
'SMILIntegerType.cpp',
|
'SMILIntegerType.cpp',
|
||||||
|
'SMILInterval.cpp',
|
||||||
'SMILKeySpline.cpp',
|
'SMILKeySpline.cpp',
|
||||||
'SMILNullType.cpp',
|
'SMILNullType.cpp',
|
||||||
'SMILParserUtils.cpp',
|
'SMILParserUtils.cpp',
|
||||||
|
'SMILRepeatCount.cpp',
|
||||||
'SMILSetAnimationFunction.cpp',
|
'SMILSetAnimationFunction.cpp',
|
||||||
'SMILStringType.cpp',
|
'SMILStringType.cpp',
|
||||||
'SMILTimeContainer.cpp',
|
'SMILTimeContainer.cpp',
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsSMILInstanceTime.h"
|
#include "nsSMILInstanceTime.h"
|
||||||
#include "nsSMILInterval.h"
|
|
||||||
#include "nsSMILTimeValueSpec.h"
|
|
||||||
#include "mozilla/AutoRestore.h"
|
#include "mozilla/AutoRestore.h"
|
||||||
|
#include "mozilla/SMILInterval.h"
|
||||||
|
#include "nsSMILTimeValueSpec.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Implementation
|
// Implementation
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
|
nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
|
||||||
nsSMILInstanceTimeSource aSource,
|
nsSMILInstanceTimeSource aSource,
|
||||||
nsSMILTimeValueSpec* aCreator,
|
nsSMILTimeValueSpec* aCreator,
|
||||||
nsSMILInterval* aBaseInterval)
|
SMILInterval* aBaseInterval)
|
||||||
: mTime(aTime),
|
: mTime(aTime),
|
||||||
mFlags(0),
|
mFlags(0),
|
||||||
mVisited(false),
|
mVisited(false),
|
||||||
|
@ -165,7 +166,7 @@ const nsSMILInstanceTime* nsSMILInstanceTime::GetBaseTime() const {
|
||||||
: mBaseInterval->End();
|
: mBaseInterval->End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILInstanceTime::SetBaseInterval(nsSMILInterval* aBaseInterval) {
|
void nsSMILInstanceTime::SetBaseInterval(SMILInterval* aBaseInterval) {
|
||||||
MOZ_ASSERT(!mBaseInterval,
|
MOZ_ASSERT(!mBaseInterval,
|
||||||
"Attempting to reassociate an instance time with a different "
|
"Attempting to reassociate an instance time with a different "
|
||||||
"interval.");
|
"interval.");
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
#include "nsISupportsImpl.h"
|
#include "nsISupportsImpl.h"
|
||||||
#include "nsSMILTimeValue.h"
|
#include "nsSMILTimeValue.h"
|
||||||
|
|
||||||
class nsSMILInterval;
|
|
||||||
class nsSMILTimeValueSpec;
|
class nsSMILTimeValueSpec;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
class SMILInterval;
|
||||||
class SMILTimeContainer;
|
class SMILTimeContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,15 +29,18 @@ class SMILTimeContainer;
|
||||||
// These objects are owned by an SMILTimedElement but MAY also be referenced
|
// These objects are owned by an SMILTimedElement but MAY also be referenced
|
||||||
// by:
|
// by:
|
||||||
//
|
//
|
||||||
// a) nsSMILIntervals that belong to the same SMILTimedElement and which refer
|
// a) SMILIntervals that belong to the same SMILTimedElement and which refer
|
||||||
// to the nsSMILInstanceTimes which form the interval endpoints; and/or
|
// to the nsSMILInstanceTimes which form the interval endpoints; and/or
|
||||||
// b) nsSMILIntervals that belong to other SMILTimedElements but which need to
|
// b) SMILIntervals that belong to other SMILTimedElements but which need to
|
||||||
// update dependent instance times when they change or are deleted.
|
// update dependent instance times when they change or are deleted.
|
||||||
// E.g. for begin='a.begin', 'a' needs to inform dependent
|
// E.g. for begin='a.begin', 'a' needs to inform dependent
|
||||||
// nsSMILInstanceTimes if its begin time changes. This notification is
|
// nsSMILInstanceTimes if its begin time changes. This notification is
|
||||||
// performed by the nsSMILInterval.
|
// performed by the SMILInterval.
|
||||||
|
|
||||||
class nsSMILInstanceTime final {
|
class nsSMILInstanceTime final {
|
||||||
|
typedef mozilla::SMILInterval SMILInterval;
|
||||||
|
typedef mozilla::SMILTimeContainer SMILTimeContainer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Instance time source. Times generated by events, syncbase relationships,
|
// Instance time source. Times generated by events, syncbase relationships,
|
||||||
// and DOM calls behave differently in some circumstances such as when a timed
|
// and DOM calls behave differently in some circumstances such as when a timed
|
||||||
|
@ -56,10 +59,10 @@ class nsSMILInstanceTime final {
|
||||||
explicit nsSMILInstanceTime(const nsSMILTimeValue& aTime,
|
explicit nsSMILInstanceTime(const nsSMILTimeValue& aTime,
|
||||||
nsSMILInstanceTimeSource aSource = SOURCE_NONE,
|
nsSMILInstanceTimeSource aSource = SOURCE_NONE,
|
||||||
nsSMILTimeValueSpec* aCreator = nullptr,
|
nsSMILTimeValueSpec* aCreator = nullptr,
|
||||||
nsSMILInterval* aBaseInterval = nullptr);
|
SMILInterval* aBaseInterval = nullptr);
|
||||||
|
|
||||||
void Unlink();
|
void Unlink();
|
||||||
void HandleChangedInterval(const mozilla::SMILTimeContainer* aSrcContainer,
|
void HandleChangedInterval(const SMILTimeContainer* aSrcContainer,
|
||||||
bool aBeginObjectChanged, bool aEndObjectChanged);
|
bool aBeginObjectChanged, bool aEndObjectChanged);
|
||||||
void HandleDeletedInterval();
|
void HandleDeletedInterval();
|
||||||
void HandleFilteredInterval();
|
void HandleFilteredInterval();
|
||||||
|
@ -85,7 +88,7 @@ class nsSMILInstanceTime final {
|
||||||
|
|
||||||
bool IsDependent() const { return !!mBaseInterval; }
|
bool IsDependent() const { return !!mBaseInterval; }
|
||||||
bool IsDependentOn(const nsSMILInstanceTime& aOther) const;
|
bool IsDependentOn(const nsSMILInstanceTime& aOther) const;
|
||||||
const nsSMILInterval* GetBaseInterval() const { return mBaseInterval; }
|
const SMILInterval* GetBaseInterval() const { return mBaseInterval; }
|
||||||
const nsSMILInstanceTime* GetBaseTime() const;
|
const nsSMILInstanceTime* GetBaseTime() const;
|
||||||
|
|
||||||
bool SameTimeAndBase(const nsSMILInstanceTime& aOther) const {
|
bool SameTimeAndBase(const nsSMILInstanceTime& aOther) const {
|
||||||
|
@ -103,7 +106,7 @@ class nsSMILInstanceTime final {
|
||||||
// Private destructor, to discourage deletion outside of Release():
|
// Private destructor, to discourage deletion outside of Release():
|
||||||
~nsSMILInstanceTime();
|
~nsSMILInstanceTime();
|
||||||
|
|
||||||
void SetBaseInterval(nsSMILInterval* aBaseInterval);
|
void SetBaseInterval(SMILInterval* aBaseInterval);
|
||||||
|
|
||||||
nsSMILTimeValue mTime;
|
nsSMILTimeValue mTime;
|
||||||
|
|
||||||
|
@ -159,7 +162,7 @@ class nsSMILInstanceTime final {
|
||||||
nsSMILTimeValueSpec* mCreator; // The nsSMILTimeValueSpec object that created
|
nsSMILTimeValueSpec* mCreator; // The nsSMILTimeValueSpec object that created
|
||||||
// us. (currently only needed for syncbase
|
// us. (currently only needed for syncbase
|
||||||
// instance times.)
|
// instance times.)
|
||||||
nsSMILInterval* mBaseInterval; // Interval from which this time is derived
|
SMILInterval* mBaseInterval; // Interval from which this time is derived
|
||||||
// (only used for syncbase instance times)
|
// (only used for syncbase instance times)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
* nsSMILInstanceTime -- an nsSMILTimeValue used for constructing intervals. It
|
* nsSMILInstanceTime -- an nsSMILTimeValue used for constructing intervals. It
|
||||||
* contains additional fields to govern reset behavior
|
* contains additional fields to govern reset behavior
|
||||||
* and track timing dependencies (e.g. syncbase timing).
|
* and track timing dependencies (e.g. syncbase timing).
|
||||||
* nsSMILInterval -- a pair of nsSMILInstanceTimes that defines a begin and
|
* SMILInterval -- a pair of nsSMILInstanceTimes that defines a begin and
|
||||||
* an end time for animation.
|
* an end time for animation.
|
||||||
* nsSMILTimeValueSpec -- a component of a begin or end attribute, such as the
|
* nsSMILTimeValueSpec -- a component of a begin or end attribute, such as the
|
||||||
* '5s' or 'a.end+2m' in begin="5s; a.end+2m". Acts as
|
* '5s' or 'a.end+2m' in begin="5s; a.end+2m". Acts as
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "mozilla/EventListenerManager.h"
|
#include "mozilla/EventListenerManager.h"
|
||||||
|
#include "mozilla/SMILInterval.h"
|
||||||
#include "mozilla/SMILParserUtils.h"
|
#include "mozilla/SMILParserUtils.h"
|
||||||
#include "mozilla/SMILTimeContainer.h"
|
#include "mozilla/SMILTimeContainer.h"
|
||||||
#include "mozilla/SMILTimedElement.h"
|
#include "mozilla/SMILTimedElement.h"
|
||||||
|
@ -12,7 +13,6 @@
|
||||||
#include "mozilla/dom/SVGAnimationElement.h"
|
#include "mozilla/dom/SVGAnimationElement.h"
|
||||||
#include "mozilla/dom/TimeEvent.h"
|
#include "mozilla/dom/TimeEvent.h"
|
||||||
#include "nsSMILTimeValueSpec.h"
|
#include "nsSMILTimeValueSpec.h"
|
||||||
#include "nsSMILInterval.h"
|
|
||||||
#include "nsSMILTimeValue.h"
|
#include "nsSMILTimeValue.h"
|
||||||
#include "nsSMILInstanceTime.h"
|
#include "nsSMILInstanceTime.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
@ -108,7 +108,7 @@ bool nsSMILTimeValueSpec::IsEventBased() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsSMILTimeValueSpec::HandleNewInterval(
|
void nsSMILTimeValueSpec::HandleNewInterval(
|
||||||
nsSMILInterval& aInterval, const SMILTimeContainer* aSrcContainer) {
|
SMILInterval& aInterval, const SMILTimeContainer* aSrcContainer) {
|
||||||
const nsSMILInstanceTime& baseInstance =
|
const nsSMILInstanceTime& baseInstance =
|
||||||
mParams.mSyncBegin ? *aInterval.Begin() : *aInterval.End();
|
mParams.mSyncBegin ? *aInterval.Begin() : *aInterval.End();
|
||||||
nsSMILTimeValue newTime =
|
nsSMILTimeValue newTime =
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
|
|
||||||
class nsSMILTimeValue;
|
class nsSMILTimeValue;
|
||||||
class nsSMILInstanceTime;
|
class nsSMILInstanceTime;
|
||||||
class nsSMILInterval;
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
class SMILInterval;
|
||||||
class SMILTimeContainer;
|
class SMILTimeContainer;
|
||||||
class SMILTimedElement;
|
class SMILTimedElement;
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
@ -40,6 +40,7 @@ class EventListenerManager;
|
||||||
|
|
||||||
class nsSMILTimeValueSpec {
|
class nsSMILTimeValueSpec {
|
||||||
public:
|
public:
|
||||||
|
typedef mozilla::SMILInterval SMILInterval;
|
||||||
typedef mozilla::SMILTimeContainer SMILTimeContainer;
|
typedef mozilla::SMILTimeContainer SMILTimeContainer;
|
||||||
typedef mozilla::SMILTimedElement SMILTimedElement;
|
typedef mozilla::SMILTimedElement SMILTimedElement;
|
||||||
typedef mozilla::dom::Element Element;
|
typedef mozilla::dom::Element Element;
|
||||||
|
@ -53,7 +54,7 @@ class nsSMILTimeValueSpec {
|
||||||
void ResolveReferences(Element& aContextElement);
|
void ResolveReferences(Element& aContextElement);
|
||||||
bool IsEventBased() const;
|
bool IsEventBased() const;
|
||||||
|
|
||||||
void HandleNewInterval(nsSMILInterval& aInterval,
|
void HandleNewInterval(SMILInterval& aInterval,
|
||||||
const SMILTimeContainer* aSrcContainer);
|
const SMILTimeContainer* aSrcContainer);
|
||||||
void HandleTargetElementChange(Element* aNewTarget);
|
void HandleTargetElementChange(Element* aNewTarget);
|
||||||
|
|
||||||
|
|
|
@ -4390,13 +4390,13 @@ void WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
|
||||||
JS::PrepareForFullGC(aCx);
|
JS::PrepareForFullGC(aCx);
|
||||||
|
|
||||||
if (aShrinking) {
|
if (aShrinking) {
|
||||||
JS::NonIncrementalGC(aCx, GC_SHRINK, JS::gcreason::DOM_WORKER);
|
JS::NonIncrementalGC(aCx, GC_SHRINK, JS::GCReason::DOM_WORKER);
|
||||||
|
|
||||||
if (!aCollectChildren) {
|
if (!aCollectChildren) {
|
||||||
LOG(WorkerLog(), ("Worker %p collected idle garbage\n", this));
|
LOG(WorkerLog(), ("Worker %p collected idle garbage\n", this));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JS::NonIncrementalGC(aCx, GC_NORMAL, JS::gcreason::DOM_WORKER);
|
JS::NonIncrementalGC(aCx, GC_NORMAL, JS::GCReason::DOM_WORKER);
|
||||||
LOG(WorkerLog(), ("Worker %p collected garbage\n", this));
|
LOG(WorkerLog(), ("Worker %p collected garbage\n", this));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -39,7 +39,7 @@ static void MaybeForceDebugGC() {
|
||||||
if (sDebugGCs) {
|
if (sDebugGCs) {
|
||||||
JSContext* cx = XPCJSContext::Get()->Context();
|
JSContext* cx = XPCJSContext::Get()->Context();
|
||||||
PrepareForFullGC(cx);
|
PrepareForFullGC(cx);
|
||||||
NonIncrementalGC(cx, GC_NORMAL, gcreason::COMPONENT_UTILS);
|
NonIncrementalGC(cx, GC_NORMAL, GCReason::COMPONENT_UTILS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -406,10 +406,7 @@ namespace JS {
|
||||||
D(DOCSHELL, 54) \
|
D(DOCSHELL, 54) \
|
||||||
D(HTML_PARSER, 55)
|
D(HTML_PARSER, 55)
|
||||||
|
|
||||||
namespace gcreason {
|
enum class GCReason {
|
||||||
|
|
||||||
/* GCReasons will end up looking like JSGC_MAYBEGC */
|
|
||||||
enum Reason {
|
|
||||||
#define MAKE_REASON(name, val) name = val,
|
#define MAKE_REASON(name, val) name = val,
|
||||||
GCREASONS(MAKE_REASON)
|
GCREASONS(MAKE_REASON)
|
||||||
#undef MAKE_REASON
|
#undef MAKE_REASON
|
||||||
|
@ -418,9 +415,8 @@ enum Reason {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For telemetry, we want to keep a fixed max bucket size over time so we
|
* For telemetry, we want to keep a fixed max bucket size over time so we
|
||||||
* don't have to switch histograms. 100 is conservative; as of this writing
|
* don't have to switch histograms. 100 is conservative; but the cost of extra
|
||||||
* there are 52. But the cost of extra buckets seems to be low while the
|
* buckets seems to be low while the cost of switching histograms is high.
|
||||||
* cost of switching histograms is high.
|
|
||||||
*/
|
*/
|
||||||
NUM_TELEMETRY_REASONS = 100
|
NUM_TELEMETRY_REASONS = 100
|
||||||
};
|
};
|
||||||
|
@ -428,9 +424,7 @@ enum Reason {
|
||||||
/**
|
/**
|
||||||
* Get a statically allocated C string explaining the given GC reason.
|
* Get a statically allocated C string explaining the given GC reason.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API const char* ExplainReason(JS::gcreason::Reason reason);
|
extern JS_PUBLIC_API const char* ExplainGCReason(JS::GCReason reason);
|
||||||
|
|
||||||
} /* namespace gcreason */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Zone GC:
|
* Zone GC:
|
||||||
|
@ -492,7 +486,7 @@ extern JS_PUBLIC_API void SkipZoneForGC(Zone* zone);
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API void NonIncrementalGC(JSContext* cx,
|
extern JS_PUBLIC_API void NonIncrementalGC(JSContext* cx,
|
||||||
JSGCInvocationKind gckind,
|
JSGCInvocationKind gckind,
|
||||||
gcreason::Reason reason);
|
GCReason reason);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Incremental GC:
|
* Incremental GC:
|
||||||
|
@ -525,7 +519,7 @@ extern JS_PUBLIC_API void NonIncrementalGC(JSContext* cx,
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx,
|
extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx,
|
||||||
JSGCInvocationKind gckind,
|
JSGCInvocationKind gckind,
|
||||||
gcreason::Reason reason,
|
GCReason reason,
|
||||||
int64_t millis = 0);
|
int64_t millis = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -536,8 +530,7 @@ extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx,
|
||||||
* Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
|
* Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
|
||||||
* shorter than the requested interval.
|
* shorter than the requested interval.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx,
|
extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, GCReason reason,
|
||||||
gcreason::Reason reason,
|
|
||||||
int64_t millis = 0);
|
int64_t millis = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -546,8 +539,7 @@ extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx,
|
||||||
* this is equivalent to NonIncrementalGC. When this function returns,
|
* this is equivalent to NonIncrementalGC. When this function returns,
|
||||||
* IsIncrementalGCInProgress(cx) will always be false.
|
* IsIncrementalGCInProgress(cx) will always be false.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API void FinishIncrementalGC(JSContext* cx,
|
extern JS_PUBLIC_API void FinishIncrementalGC(JSContext* cx, GCReason reason);
|
||||||
gcreason::Reason reason);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and
|
* If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and
|
||||||
|
@ -623,10 +615,10 @@ struct JS_PUBLIC_API GCDescription {
|
||||||
bool isZone_;
|
bool isZone_;
|
||||||
bool isComplete_;
|
bool isComplete_;
|
||||||
JSGCInvocationKind invocationKind_;
|
JSGCInvocationKind invocationKind_;
|
||||||
gcreason::Reason reason_;
|
GCReason reason_;
|
||||||
|
|
||||||
GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind,
|
GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind,
|
||||||
gcreason::Reason reason)
|
GCReason reason)
|
||||||
: isZone_(isZone),
|
: isZone_(isZone),
|
||||||
isComplete_(isComplete),
|
isComplete_(isComplete),
|
||||||
invocationKind_(kind),
|
invocationKind_(kind),
|
||||||
|
@ -681,7 +673,7 @@ enum class GCNurseryProgress {
|
||||||
*/
|
*/
|
||||||
using GCNurseryCollectionCallback = void (*)(JSContext* cx,
|
using GCNurseryCollectionCallback = void (*)(JSContext* cx,
|
||||||
GCNurseryProgress progress,
|
GCNurseryProgress progress,
|
||||||
gcreason::Reason reason);
|
GCReason reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the nursery collection callback for the given runtime. When set, it will
|
* Set the nursery collection callback for the given runtime. When set, it will
|
||||||
|
|
|
@ -428,7 +428,7 @@ static bool GC(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
JSGCInvocationKind gckind = shrinking ? GC_SHRINK : GC_NORMAL;
|
JSGCInvocationKind gckind = shrinking ? GC_SHRINK : GC_NORMAL;
|
||||||
JS::NonIncrementalGC(cx, gckind, JS::gcreason::API);
|
JS::NonIncrementalGC(cx, gckind, JS::GCReason::API);
|
||||||
|
|
||||||
char buf[256] = {'\0'};
|
char buf[256] = {'\0'};
|
||||||
#ifndef JS_MORE_DETERMINISTIC
|
#ifndef JS_MORE_DETERMINISTIC
|
||||||
|
@ -442,10 +442,10 @@ static bool MinorGC(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
if (args.get(0) == BooleanValue(true)) {
|
if (args.get(0) == BooleanValue(true)) {
|
||||||
cx->runtime()->gc.storeBuffer().setAboutToOverflow(
|
cx->runtime()->gc.storeBuffer().setAboutToOverflow(
|
||||||
JS::gcreason::FULL_GENERIC_BUFFER);
|
JS::GCReason::FULL_GENERIC_BUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->minorGC(JS::gcreason::API);
|
cx->minorGC(JS::GCReason::API);
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -591,7 +591,7 @@ static bool RelazifyFunctions(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
SetAllowRelazification(cx, true);
|
SetAllowRelazification(cx, true);
|
||||||
|
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
JS::NonIncrementalGC(cx, GC_SHRINK, JS::gcreason::API);
|
JS::NonIncrementalGC(cx, GC_SHRINK, JS::GCReason::API);
|
||||||
|
|
||||||
SetAllowRelazification(cx, false);
|
SetAllowRelazification(cx, false);
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
|
@ -4186,7 +4186,7 @@ static void majorGC(JSContext* cx, JSGCStatus status, void* data) {
|
||||||
if (info->depth > 0) {
|
if (info->depth > 0) {
|
||||||
info->depth--;
|
info->depth--;
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::API);
|
JS::NonIncrementalGC(cx, GC_NORMAL, JS::GCReason::API);
|
||||||
info->depth++;
|
info->depth++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4205,7 +4205,7 @@ static void minorGC(JSContext* cx, JSGCStatus status, void* data) {
|
||||||
if (info->active) {
|
if (info->active) {
|
||||||
info->active = false;
|
info->active = false;
|
||||||
if (cx->zone() && !cx->zone()->isAtomsZone()) {
|
if (cx->zone() && !cx->zone()->isAtomsZone()) {
|
||||||
cx->runtime()->gc.evictNursery(JS::gcreason::DEBUG_GC);
|
cx->runtime()->gc.evictNursery(JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
info->active = true;
|
info->active = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ static int testBinASTReaderFuzz(const uint8_t* buf, size_t size) {
|
||||||
|
|
||||||
auto gcGuard = mozilla::MakeScopeExit([&] {
|
auto gcGuard = mozilla::MakeScopeExit([&] {
|
||||||
JS::PrepareForFullGC(gCx);
|
JS::PrepareForFullGC(gCx);
|
||||||
JS::NonIncrementalGC(gCx, GC_NORMAL, JS::gcreason::API);
|
JS::NonIncrementalGC(gCx, GC_NORMAL, JS::GCReason::API);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!size) return 0;
|
if (!size) return 0;
|
||||||
|
|
|
@ -37,7 +37,7 @@ static int testExampleFuzz(const uint8_t* buf, size_t size) {
|
||||||
if it is not required in your use case, which will speed up fuzzing. */
|
if it is not required in your use case, which will speed up fuzzing. */
|
||||||
auto gcGuard = mozilla::MakeScopeExit([&] {
|
auto gcGuard = mozilla::MakeScopeExit([&] {
|
||||||
JS::PrepareForFullGC(gCx);
|
JS::PrepareForFullGC(gCx);
|
||||||
JS::NonIncrementalGC(gCx, GC_NORMAL, JS::gcreason::API);
|
JS::NonIncrementalGC(gCx, GC_NORMAL, JS::GCReason::API);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Add code here that processes the given buffer.
|
/* Add code here that processes the given buffer.
|
||||||
|
|
|
@ -26,7 +26,7 @@ static int testStructuredCloneReaderInit(int* argc, char*** argv) { return 0; }
|
||||||
static int testStructuredCloneReaderFuzz(const uint8_t* buf, size_t size) {
|
static int testStructuredCloneReaderFuzz(const uint8_t* buf, size_t size) {
|
||||||
auto gcGuard = mozilla::MakeScopeExit([&] {
|
auto gcGuard = mozilla::MakeScopeExit([&] {
|
||||||
JS::PrepareForFullGC(gCx);
|
JS::PrepareForFullGC(gCx);
|
||||||
JS::NonIncrementalGC(gCx, GC_NORMAL, JS::gcreason::API);
|
JS::NonIncrementalGC(gCx, GC_NORMAL, JS::GCReason::API);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!size) return 0;
|
if (!size) return 0;
|
||||||
|
|
|
@ -108,7 +108,7 @@ JSObject* GCRuntime::tryNewNurseryObject(JSContext* cx, size_t thingSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowGC && !cx->suppressGC) {
|
if (allowGC && !cx->suppressGC) {
|
||||||
cx->runtime()->gc.minorGC(JS::gcreason::OUT_OF_NURSERY);
|
cx->runtime()->gc.minorGC(JS::GCReason::OUT_OF_NURSERY);
|
||||||
|
|
||||||
// Exceeding gcMaxBytes while tenuring can disable the Nursery.
|
// Exceeding gcMaxBytes while tenuring can disable the Nursery.
|
||||||
if (cx->nursery().isEnabled()) {
|
if (cx->nursery().isEnabled()) {
|
||||||
|
@ -164,7 +164,7 @@ JSString* GCRuntime::tryNewNurseryString(JSContext* cx, size_t thingSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowGC && !cx->suppressGC) {
|
if (allowGC && !cx->suppressGC) {
|
||||||
cx->runtime()->gc.minorGC(JS::gcreason::OUT_OF_NURSERY);
|
cx->runtime()->gc.minorGC(JS::GCReason::OUT_OF_NURSERY);
|
||||||
|
|
||||||
// Exceeding gcMaxBytes while tenuring can disable the Nursery, and
|
// Exceeding gcMaxBytes while tenuring can disable the Nursery, and
|
||||||
// other heuristics can disable nursery strings for this zone.
|
// other heuristics can disable nursery strings for this zone.
|
||||||
|
@ -276,7 +276,7 @@ template <typename T, AllowGC allowGC>
|
||||||
// all-compartments, non-incremental, shrinking GC and wait for
|
// all-compartments, non-incremental, shrinking GC and wait for
|
||||||
// sweeping to finish.
|
// sweeping to finish.
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
cx->runtime()->gc.gc(GC_SHRINK, JS::gcreason::LAST_DITCH);
|
cx->runtime()->gc.gc(GC_SHRINK, JS::GCReason::LAST_DITCH);
|
||||||
cx->runtime()->gc.waitBackgroundSweepOrAllocEnd();
|
cx->runtime()->gc.waitBackgroundSweepOrAllocEnd();
|
||||||
|
|
||||||
t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
|
t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
|
||||||
|
@ -351,7 +351,7 @@ bool GCRuntime::gcIfNeededAtAllocation(JSContext* cx) {
|
||||||
if (isIncrementalGCInProgress() &&
|
if (isIncrementalGCInProgress() &&
|
||||||
cx->zone()->zoneSize.gcBytes() > cx->zone()->threshold.gcTriggerBytes()) {
|
cx->zone()->zoneSize.gcBytes() > cx->zone()->threshold.gcTriggerBytes()) {
|
||||||
PrepareZoneForGC(cx->zone());
|
PrepareZoneForGC(cx->zone());
|
||||||
gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW);
|
gc(GC_NORMAL, JS::GCReason::INCREMENTAL_TOO_SLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -335,7 +335,7 @@ class ArenaLists {
|
||||||
|
|
||||||
bool checkEmptyArenaList(AllocKind kind);
|
bool checkEmptyArenaList(AllocKind kind);
|
||||||
|
|
||||||
bool relocateArenas(Arena*& relocatedListOut, JS::gcreason::Reason reason,
|
bool relocateArenas(Arena*& relocatedListOut, JS::GCReason reason,
|
||||||
js::SliceBudget& sliceBudget, gcstats::Statistics& stats);
|
js::SliceBudget& sliceBudget, gcstats::Statistics& stats);
|
||||||
|
|
||||||
void queueForegroundObjectsForSweep(FreeOp* fop);
|
void queueForegroundObjectsForSweep(FreeOp* fop);
|
||||||
|
|
215
js/src/gc/GC.cpp
215
js/src/gc/GC.cpp
|
@ -915,7 +915,7 @@ GCRuntime::GCRuntime(JSRuntime* rt)
|
||||||
cleanUpEverything(false),
|
cleanUpEverything(false),
|
||||||
grayBufferState(GCRuntime::GrayBufferState::Unused),
|
grayBufferState(GCRuntime::GrayBufferState::Unused),
|
||||||
grayBitsValid(false),
|
grayBitsValid(false),
|
||||||
majorGCTriggerReason(JS::gcreason::NO_REASON),
|
majorGCTriggerReason(JS::GCReason::NO_REASON),
|
||||||
fullGCForAtomsRequested_(false),
|
fullGCForAtomsRequested_(false),
|
||||||
minorGCNumber(0),
|
minorGCNumber(0),
|
||||||
majorGCNumber(0),
|
majorGCNumber(0),
|
||||||
|
@ -1053,12 +1053,12 @@ void GCRuntime::setZeal(uint8_t zeal, uint32_t frequency) {
|
||||||
|
|
||||||
if (zeal == 0) {
|
if (zeal == 0) {
|
||||||
if (hasZealMode(ZealMode::GenerationalGC)) {
|
if (hasZealMode(ZealMode::GenerationalGC)) {
|
||||||
evictNursery(JS::gcreason::DEBUG_GC);
|
evictNursery(JS::GCReason::DEBUG_GC);
|
||||||
nursery().leaveZealMode();
|
nursery().leaveZealMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isIncrementalGCInProgress()) {
|
if (isIncrementalGCInProgress()) {
|
||||||
finishGC(JS::gcreason::DEBUG_GC);
|
finishGC(JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1098,7 +1098,7 @@ void GCRuntime::unsetZeal(uint8_t zeal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zealMode == ZealMode::GenerationalGC) {
|
if (zealMode == ZealMode::GenerationalGC) {
|
||||||
evictNursery(JS::gcreason::DEBUG_GC);
|
evictNursery(JS::GCReason::DEBUG_GC);
|
||||||
nursery().leaveZealMode();
|
nursery().leaveZealMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1106,7 +1106,7 @@ void GCRuntime::unsetZeal(uint8_t zeal) {
|
||||||
|
|
||||||
if (zealModeBits == 0) {
|
if (zealModeBits == 0) {
|
||||||
if (isIncrementalGCInProgress()) {
|
if (isIncrementalGCInProgress()) {
|
||||||
finishGC(JS::gcreason::DEBUG_GC);
|
finishGC(JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
|
|
||||||
zealFrequency = 0;
|
zealFrequency = 0;
|
||||||
|
@ -2075,8 +2075,8 @@ bool GCRuntime::shouldCompact() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initialReason == JS::gcreason::USER_INACTIVE ||
|
if (initialReason == JS::GCReason::USER_INACTIVE ||
|
||||||
initialReason == JS::gcreason::MEM_PRESSURE) {
|
initialReason == JS::GCReason::MEM_PRESSURE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2122,8 +2122,8 @@ Arena* ArenaList::removeRemainingArenas(Arena** arenap) {
|
||||||
return remainingArenas;
|
return remainingArenas;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ShouldRelocateAllArenas(JS::gcreason::Reason reason) {
|
static bool ShouldRelocateAllArenas(JS::GCReason reason) {
|
||||||
return reason == JS::gcreason::DEBUG_GC;
|
return reason == JS::GCReason::DEBUG_GC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2297,12 +2297,12 @@ static inline bool CanProtectArenas() {
|
||||||
return SystemPageSize() <= ArenaSize;
|
return SystemPageSize() <= ArenaSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool ShouldProtectRelocatedArenas(JS::gcreason::Reason reason) {
|
static inline bool ShouldProtectRelocatedArenas(JS::GCReason reason) {
|
||||||
// For zeal mode collections we don't release the relocated arenas
|
// For zeal mode collections we don't release the relocated arenas
|
||||||
// immediately. Instead we protect them and keep them around until the next
|
// immediately. Instead we protect them and keep them around until the next
|
||||||
// collection so we can catch any stray accesses to them.
|
// collection so we can catch any stray accesses to them.
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
return reason == JS::gcreason::DEBUG_GC && CanProtectArenas();
|
return reason == JS::GCReason::DEBUG_GC && CanProtectArenas();
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2336,7 +2336,7 @@ Arena* ArenaList::relocateArenas(Arena* toRelocate, Arena* relocated,
|
||||||
static const float MIN_ZONE_RECLAIM_PERCENT = 2.0;
|
static const float MIN_ZONE_RECLAIM_PERCENT = 2.0;
|
||||||
|
|
||||||
static bool ShouldRelocateZone(size_t arenaCount, size_t relocCount,
|
static bool ShouldRelocateZone(size_t arenaCount, size_t relocCount,
|
||||||
JS::gcreason::Reason reason) {
|
JS::GCReason reason) {
|
||||||
if (relocCount == 0) {
|
if (relocCount == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2358,8 +2358,7 @@ static AllocKinds CompactingAllocKinds() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArenaLists::relocateArenas(Arena*& relocatedListOut,
|
bool ArenaLists::relocateArenas(Arena*& relocatedListOut, JS::GCReason reason,
|
||||||
JS::gcreason::Reason reason,
|
|
||||||
SliceBudget& sliceBudget,
|
SliceBudget& sliceBudget,
|
||||||
gcstats::Statistics& stats) {
|
gcstats::Statistics& stats) {
|
||||||
// This is only called from the main thread while we are doing a GC, so
|
// This is only called from the main thread while we are doing a GC, so
|
||||||
|
@ -2411,7 +2410,7 @@ bool ArenaLists::relocateArenas(Arena*& relocatedListOut,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCRuntime::relocateArenas(Zone* zone, JS::gcreason::Reason reason,
|
bool GCRuntime::relocateArenas(Zone* zone, JS::GCReason reason,
|
||||||
Arena*& relocatedListOut,
|
Arena*& relocatedListOut,
|
||||||
SliceBudget& sliceBudget) {
|
SliceBudget& sliceBudget) {
|
||||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT_MOVE);
|
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT_MOVE);
|
||||||
|
@ -3190,7 +3189,7 @@ bool SliceBudget::checkOverBudget() {
|
||||||
return over;
|
return over;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::requestMajorGC(JS::gcreason::Reason reason) {
|
void GCRuntime::requestMajorGC(JS::GCReason reason) {
|
||||||
MOZ_ASSERT(!CurrentThreadIsPerformingGC());
|
MOZ_ASSERT(!CurrentThreadIsPerformingGC());
|
||||||
|
|
||||||
if (majorGCRequested()) {
|
if (majorGCRequested()) {
|
||||||
|
@ -3201,7 +3200,7 @@ void GCRuntime::requestMajorGC(JS::gcreason::Reason reason) {
|
||||||
rt->mainContextFromOwnThread()->requestInterrupt(InterruptReason::GC);
|
rt->mainContextFromOwnThread()->requestInterrupt(InterruptReason::GC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Nursery::requestMinorGC(JS::gcreason::Reason reason) const {
|
void Nursery::requestMinorGC(JS::GCReason reason) const {
|
||||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
|
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
|
||||||
MOZ_ASSERT(!CurrentThreadIsPerformingGC());
|
MOZ_ASSERT(!CurrentThreadIsPerformingGC());
|
||||||
|
|
||||||
|
@ -3222,18 +3221,18 @@ void Nursery::requestMinorGC(JS::gcreason::Reason reason) const {
|
||||||
// memory or memory used by GC things may vary between recording or replaying,
|
// memory or memory used by GC things may vary between recording or replaying,
|
||||||
// but other behaviors that would normally be non-deterministic (timers and so
|
// but other behaviors that would normally be non-deterministic (timers and so
|
||||||
// forth) are captured in the recording and replayed exactly.
|
// forth) are captured in the recording and replayed exactly.
|
||||||
static bool RecordReplayCheckCanGC(JS::gcreason::Reason reason) {
|
static bool RecordReplayCheckCanGC(JS::GCReason reason) {
|
||||||
if (!mozilla::recordreplay::IsRecordingOrReplaying()) {
|
if (!mozilla::recordreplay::IsRecordingOrReplaying()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case JS::gcreason::EAGER_ALLOC_TRIGGER:
|
case JS::GCReason::EAGER_ALLOC_TRIGGER:
|
||||||
case JS::gcreason::LAST_DITCH:
|
case JS::GCReason::LAST_DITCH:
|
||||||
case JS::gcreason::TOO_MUCH_MALLOC:
|
case JS::GCReason::TOO_MUCH_MALLOC:
|
||||||
case JS::gcreason::ALLOC_TRIGGER:
|
case JS::GCReason::ALLOC_TRIGGER:
|
||||||
case JS::gcreason::DELAYED_ATOMS_GC:
|
case JS::GCReason::DELAYED_ATOMS_GC:
|
||||||
case JS::gcreason::TOO_MUCH_WASM_MEMORY:
|
case JS::GCReason::TOO_MUCH_WASM_MEMORY:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -3247,7 +3246,7 @@ static bool RecordReplayCheckCanGC(JS::gcreason::Reason reason) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCRuntime::triggerGC(JS::gcreason::Reason reason) {
|
bool GCRuntime::triggerGC(JS::GCReason reason) {
|
||||||
/*
|
/*
|
||||||
* Don't trigger GCs if this is being called off the main thread from
|
* Don't trigger GCs if this is being called off the main thread from
|
||||||
* onTooMuchMalloc().
|
* onTooMuchMalloc().
|
||||||
|
@ -3286,7 +3285,7 @@ void GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock) {
|
||||||
if (usedBytes >= thresholdBytes) {
|
if (usedBytes >= thresholdBytes) {
|
||||||
// The threshold has been surpassed, immediately trigger a GC, which
|
// The threshold has been surpassed, immediately trigger a GC, which
|
||||||
// will be done non-incrementally.
|
// will be done non-incrementally.
|
||||||
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, thresholdBytes);
|
triggerZoneGC(zone, JS::GCReason::ALLOC_TRIGGER, usedBytes, thresholdBytes);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3311,7 +3310,7 @@ void GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock) {
|
||||||
// to try to avoid performing non-incremental GCs on zones
|
// to try to avoid performing non-incremental GCs on zones
|
||||||
// which allocate a lot of data, even when incremental slices
|
// which allocate a lot of data, even when incremental slices
|
||||||
// can't be triggered via scheduling in the event loop.
|
// can't be triggered via scheduling in the event loop.
|
||||||
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes,
|
triggerZoneGC(zone, JS::GCReason::ALLOC_TRIGGER, usedBytes,
|
||||||
igcThresholdBytes);
|
igcThresholdBytes);
|
||||||
|
|
||||||
// Delay the next slice until a certain amount of allocation
|
// Delay the next slice until a certain amount of allocation
|
||||||
|
@ -3322,8 +3321,8 @@ void GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason,
|
bool GCRuntime::triggerZoneGC(Zone* zone, JS::GCReason reason, size_t used,
|
||||||
size_t used, size_t threshold) {
|
size_t threshold) {
|
||||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
||||||
|
|
||||||
/* GC is already running. */
|
/* GC is already running. */
|
||||||
|
@ -3367,7 +3366,7 @@ void GCRuntime::maybeGC(Zone* zone) {
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::RootsChange)) {
|
if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::RootsChange)) {
|
||||||
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
|
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
|
||||||
gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
|
gc(GC_NORMAL, JS::GCReason::DEBUG_GC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -3383,7 +3382,7 @@ void GCRuntime::maybeGC(Zone* zone) {
|
||||||
!isIncrementalGCInProgress() && !isBackgroundSweeping()) {
|
!isIncrementalGCInProgress() && !isBackgroundSweeping()) {
|
||||||
stats().recordTrigger(usedBytes, threshold);
|
stats().recordTrigger(usedBytes, threshold);
|
||||||
PrepareZoneForGC(zone);
|
PrepareZoneForGC(zone);
|
||||||
startGC(GC_NORMAL, JS::gcreason::EAGER_ALLOC_TRIGGER);
|
startGC(GC_NORMAL, JS::GCReason::EAGER_ALLOC_TRIGGER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3393,7 +3392,7 @@ void GCRuntime::triggerFullGCForAtoms(JSContext* cx) {
|
||||||
MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
|
MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
|
||||||
MOZ_ASSERT(cx->canCollectAtoms());
|
MOZ_ASSERT(cx->canCollectAtoms());
|
||||||
fullGCForAtomsRequested_ = false;
|
fullGCForAtomsRequested_ = false;
|
||||||
MOZ_RELEASE_ASSERT(triggerGC(JS::gcreason::DELAYED_ATOMS_GC));
|
MOZ_RELEASE_ASSERT(triggerGC(JS::GCReason::DELAYED_ATOMS_GC));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do all possible decommit immediately from the current thread without
|
// Do all possible decommit immediately from the current thread without
|
||||||
|
@ -3962,7 +3961,7 @@ void GCRuntime::purgeRuntime() {
|
||||||
|
|
||||||
bool GCRuntime::shouldPreserveJITCode(Realm* realm,
|
bool GCRuntime::shouldPreserveJITCode(Realm* realm,
|
||||||
const TimeStamp& currentTime,
|
const TimeStamp& currentTime,
|
||||||
JS::gcreason::Reason reason,
|
JS::GCReason reason,
|
||||||
bool canAllocateMoreCode) {
|
bool canAllocateMoreCode) {
|
||||||
static const auto oneSecond = TimeDuration::FromSeconds(1);
|
static const auto oneSecond = TimeDuration::FromSeconds(1);
|
||||||
|
|
||||||
|
@ -3986,7 +3985,7 @@ bool GCRuntime::shouldPreserveJITCode(Realm* realm,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason == JS::gcreason::DEBUG_GC) {
|
if (reason == JS::GCReason::DEBUG_GC) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4107,10 +4106,10 @@ static void RelazifyFunctions(Zone* zone, AllocKind kind) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) {
|
static bool ShouldCollectZone(Zone* zone, JS::GCReason reason) {
|
||||||
// If we are repeating a GC because we noticed dead compartments haven't
|
// If we are repeating a GC because we noticed dead compartments haven't
|
||||||
// been collected, then only collect zones containing those compartments.
|
// been collected, then only collect zones containing those compartments.
|
||||||
if (reason == JS::gcreason::COMPARTMENT_REVIVED) {
|
if (reason == JS::GCReason::COMPARTMENT_REVIVED) {
|
||||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
|
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
|
||||||
if (comp->gcState.scheduledForDestruction) {
|
if (comp->gcState.scheduledForDestruction) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -4147,7 +4146,7 @@ static bool ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) {
|
||||||
return zone->canCollect();
|
return zone->canCollect();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason,
|
bool GCRuntime::prepareZonesForCollection(JS::GCReason reason,
|
||||||
bool* isFullOut) {
|
bool* isFullOut) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/* Assert that zone state is as we expect */
|
/* Assert that zone state is as we expect */
|
||||||
|
@ -4211,7 +4210,7 @@ bool GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason,
|
||||||
* Check that we do collect the atoms zone if we triggered a GC for that
|
* Check that we do collect the atoms zone if we triggered a GC for that
|
||||||
* purpose.
|
* purpose.
|
||||||
*/
|
*/
|
||||||
MOZ_ASSERT_IF(reason == JS::gcreason::DELAYED_ATOMS_GC,
|
MOZ_ASSERT_IF(reason == JS::GCReason::DELAYED_ATOMS_GC,
|
||||||
atomsZone->isGCMarking());
|
atomsZone->isGCMarking());
|
||||||
|
|
||||||
/* Check that at least one zone is scheduled for collection. */
|
/* Check that at least one zone is scheduled for collection. */
|
||||||
|
@ -4269,8 +4268,7 @@ static void BufferGrayRoots(GCParallelTask* task) {
|
||||||
task->runtime()->gc.bufferGrayRoots();
|
task->runtime()->gc.bufferGrayRoots();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCRuntime::beginMarkPhase(JS::gcreason::Reason reason,
|
bool GCRuntime::beginMarkPhase(JS::GCReason reason, AutoGCSession& session) {
|
||||||
AutoGCSession& session) {
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (fullCompartmentChecks) {
|
if (fullCompartmentChecks) {
|
||||||
checkForCompartmentMismatches();
|
checkForCompartmentMismatches();
|
||||||
|
@ -4931,7 +4929,7 @@ bool GCRuntime::findInterZoneEdges() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::groupZonesForSweeping(JS::gcreason::Reason reason) {
|
void GCRuntime::groupZonesForSweeping(JS::GCReason reason) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||||
MOZ_ASSERT(zone->gcSweepGroupEdges().empty());
|
MOZ_ASSERT(zone->gcSweepGroupEdges().empty());
|
||||||
|
@ -5809,8 +5807,7 @@ IncrementalProgress GCRuntime::endSweepingSweepGroup(FreeOp* fop,
|
||||||
return Finished;
|
return Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::beginSweepPhase(JS::gcreason::Reason reason,
|
void GCRuntime::beginSweepPhase(JS::GCReason reason, AutoGCSession& session) {
|
||||||
AutoGCSession& session) {
|
|
||||||
/*
|
/*
|
||||||
* Sweep phase.
|
* Sweep phase.
|
||||||
*
|
*
|
||||||
|
@ -6655,7 +6652,7 @@ void GCRuntime::beginCompactPhase() {
|
||||||
startedCompacting = true;
|
startedCompacting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
IncrementalProgress GCRuntime::compactPhase(JS::gcreason::Reason reason,
|
IncrementalProgress GCRuntime::compactPhase(JS::GCReason reason,
|
||||||
SliceBudget& sliceBudget,
|
SliceBudget& sliceBudget,
|
||||||
AutoGCSession& session) {
|
AutoGCSession& session) {
|
||||||
assertBackgroundSweepingFinished();
|
assertBackgroundSweepingFinished();
|
||||||
|
@ -6918,12 +6915,12 @@ void GCRuntime::pushZealSelectedObjects() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsShutdownGC(JS::gcreason::Reason reason) {
|
static bool IsShutdownGC(JS::GCReason reason) {
|
||||||
return reason == JS::gcreason::SHUTDOWN_CC ||
|
return reason == JS::GCReason::SHUTDOWN_CC ||
|
||||||
reason == JS::gcreason::DESTROY_RUNTIME;
|
reason == JS::GCReason::DESTROY_RUNTIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ShouldCleanUpEverything(JS::gcreason::Reason reason,
|
static bool ShouldCleanUpEverything(JS::GCReason reason,
|
||||||
JSGCInvocationKind gckind) {
|
JSGCInvocationKind gckind) {
|
||||||
// During shutdown, we must clean everything up, for the sake of leak
|
// During shutdown, we must clean everything up, for the sake of leak
|
||||||
// detection. When a runtime has no contexts, or we're doing a GC before a
|
// detection. When a runtime has no contexts, or we're doing a GC before a
|
||||||
|
@ -6931,17 +6928,16 @@ static bool ShouldCleanUpEverything(JS::gcreason::Reason reason,
|
||||||
return IsShutdownGC(reason) || gckind == GC_SHRINK;
|
return IsShutdownGC(reason) || gckind == GC_SHRINK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ShouldSweepOnBackgroundThread(JS::gcreason::Reason reason) {
|
static bool ShouldSweepOnBackgroundThread(JS::GCReason reason) {
|
||||||
return reason != JS::gcreason::DESTROY_RUNTIME && !gcTracer.traceEnabled() &&
|
return reason != JS::GCReason::DESTROY_RUNTIME && !gcTracer.traceEnabled() &&
|
||||||
CanUseExtraThreads();
|
CanUseExtraThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::incrementalSlice(SliceBudget& budget,
|
void GCRuntime::incrementalSlice(SliceBudget& budget, JS::GCReason reason,
|
||||||
JS::gcreason::Reason reason,
|
|
||||||
AutoGCSession& session) {
|
AutoGCSession& session) {
|
||||||
AutoDisableBarriers disableBarriers(rt);
|
AutoDisableBarriers disableBarriers(rt);
|
||||||
|
|
||||||
bool destroyingRuntime = (reason == JS::gcreason::DESTROY_RUNTIME);
|
bool destroyingRuntime = (reason == JS::GCReason::DESTROY_RUNTIME);
|
||||||
|
|
||||||
number++;
|
number++;
|
||||||
|
|
||||||
|
@ -6953,7 +6949,7 @@ void GCRuntime::incrementalSlice(SliceBudget& budget,
|
||||||
* collection was triggered by runDebugGC() and incremental GC has not been
|
* collection was triggered by runDebugGC() and incremental GC has not been
|
||||||
* cancelled by resetIncrementalGC().
|
* cancelled by resetIncrementalGC().
|
||||||
*/
|
*/
|
||||||
useZeal = reason == JS::gcreason::DEBUG_GC && !budget.isUnlimited();
|
useZeal = reason == JS::GCReason::DEBUG_GC && !budget.isUnlimited();
|
||||||
#else
|
#else
|
||||||
bool useZeal = false;
|
bool useZeal = false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -7182,7 +7178,7 @@ gc::AbortReason gc::IsIncrementalGCUnsafe(JSRuntime* rt) {
|
||||||
return gc::AbortReason::None;
|
return gc::AbortReason::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void CheckZoneIsScheduled(Zone* zone, JS::gcreason::Reason reason,
|
static inline void CheckZoneIsScheduled(Zone* zone, JS::GCReason reason,
|
||||||
const char* trigger) {
|
const char* trigger) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (zone->isGCScheduled()) {
|
if (zone->isGCScheduled()) {
|
||||||
|
@ -7192,7 +7188,7 @@ static inline void CheckZoneIsScheduled(Zone* zone, JS::gcreason::Reason reason,
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"CheckZoneIsScheduled: Zone %p not scheduled as expected in %s GC "
|
"CheckZoneIsScheduled: Zone %p not scheduled as expected in %s GC "
|
||||||
"for %s trigger\n",
|
"for %s trigger\n",
|
||||||
zone, JS::gcreason::ExplainReason(reason), trigger);
|
zone, JS::ExplainGCReason(reason), trigger);
|
||||||
JSRuntime* rt = zone->runtimeFromMainThread();
|
JSRuntime* rt = zone->runtimeFromMainThread();
|
||||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||||
fprintf(stderr, " Zone %p:%s%s\n", zone.get(),
|
fprintf(stderr, " Zone %p:%s%s\n", zone.get(),
|
||||||
|
@ -7205,8 +7201,7 @@ static inline void CheckZoneIsScheduled(Zone* zone, JS::gcreason::Reason reason,
|
||||||
}
|
}
|
||||||
|
|
||||||
GCRuntime::IncrementalResult GCRuntime::budgetIncrementalGC(
|
GCRuntime::IncrementalResult GCRuntime::budgetIncrementalGC(
|
||||||
bool nonincrementalByAPI, JS::gcreason::Reason reason,
|
bool nonincrementalByAPI, JS::GCReason reason, SliceBudget& budget) {
|
||||||
SliceBudget& budget) {
|
|
||||||
if (nonincrementalByAPI) {
|
if (nonincrementalByAPI) {
|
||||||
stats().nonincremental(gc::AbortReason::NonIncrementalRequested);
|
stats().nonincremental(gc::AbortReason::NonIncrementalRequested);
|
||||||
budget.makeUnlimited();
|
budget.makeUnlimited();
|
||||||
|
@ -7215,14 +7210,14 @@ GCRuntime::IncrementalResult GCRuntime::budgetIncrementalGC(
|
||||||
// API. This isn't required for correctness, but sometimes during tests
|
// API. This isn't required for correctness, but sometimes during tests
|
||||||
// the caller expects this GC to collect certain objects, and we need
|
// the caller expects this GC to collect certain objects, and we need
|
||||||
// to make sure to collect everything possible.
|
// to make sure to collect everything possible.
|
||||||
if (reason != JS::gcreason::ALLOC_TRIGGER) {
|
if (reason != JS::GCReason::ALLOC_TRIGGER) {
|
||||||
return resetIncrementalGC(gc::AbortReason::NonIncrementalRequested);
|
return resetIncrementalGC(gc::AbortReason::NonIncrementalRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IncrementalResult::Ok;
|
return IncrementalResult::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason == JS::gcreason::ABORT_GC) {
|
if (reason == JS::GCReason::ABORT_GC) {
|
||||||
budget.makeUnlimited();
|
budget.makeUnlimited();
|
||||||
stats().nonincremental(gc::AbortReason::AbortRequested);
|
stats().nonincremental(gc::AbortReason::AbortRequested);
|
||||||
return resetIncrementalGC(gc::AbortReason::AbortRequested);
|
return resetIncrementalGC(gc::AbortReason::AbortRequested);
|
||||||
|
@ -7230,7 +7225,7 @@ GCRuntime::IncrementalResult GCRuntime::budgetIncrementalGC(
|
||||||
|
|
||||||
AbortReason unsafeReason = IsIncrementalGCUnsafe(rt);
|
AbortReason unsafeReason = IsIncrementalGCUnsafe(rt);
|
||||||
if (unsafeReason == AbortReason::None) {
|
if (unsafeReason == AbortReason::None) {
|
||||||
if (reason == JS::gcreason::COMPARTMENT_REVIVED) {
|
if (reason == JS::GCReason::COMPARTMENT_REVIVED) {
|
||||||
unsafeReason = gc::AbortReason::CompartmentRevived;
|
unsafeReason = gc::AbortReason::CompartmentRevived;
|
||||||
} else if (mode != JSGC_MODE_INCREMENTAL) {
|
} else if (mode != JSGC_MODE_INCREMENTAL) {
|
||||||
unsafeReason = gc::AbortReason::ModeChange;
|
unsafeReason = gc::AbortReason::ModeChange;
|
||||||
|
@ -7381,7 +7376,7 @@ void GCRuntime::maybeCallGCCallback(JSGCStatus status) {
|
||||||
* implementation.
|
* implementation.
|
||||||
*/
|
*/
|
||||||
MOZ_NEVER_INLINE GCRuntime::IncrementalResult GCRuntime::gcCycle(
|
MOZ_NEVER_INLINE GCRuntime::IncrementalResult GCRuntime::gcCycle(
|
||||||
bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) {
|
bool nonincrementalByAPI, SliceBudget budget, JS::GCReason reason) {
|
||||||
// Assert if this is a GC unsafe region.
|
// Assert if this is a GC unsafe region.
|
||||||
rt->mainContextFromOwnThread()->verifyIsSafeToGC();
|
rt->mainContextFromOwnThread()->verifyIsSafeToGC();
|
||||||
|
|
||||||
|
@ -7397,7 +7392,7 @@ MOZ_NEVER_INLINE GCRuntime::IncrementalResult GCRuntime::gcCycle(
|
||||||
|
|
||||||
auto result = budgetIncrementalGC(nonincrementalByAPI, reason, budget);
|
auto result = budgetIncrementalGC(nonincrementalByAPI, reason, budget);
|
||||||
if (result == IncrementalResult::ResetIncremental) {
|
if (result == IncrementalResult::ResetIncremental) {
|
||||||
reason = JS::gcreason::RESET;
|
reason = JS::GCReason::RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldCollectNurseryForSlice(nonincrementalByAPI, budget)) {
|
if (shouldCollectNurseryForSlice(nonincrementalByAPI, budget)) {
|
||||||
|
@ -7406,7 +7401,7 @@ MOZ_NEVER_INLINE GCRuntime::IncrementalResult GCRuntime::gcCycle(
|
||||||
|
|
||||||
AutoGCSession session(rt, JS::HeapState::MajorCollecting);
|
AutoGCSession session(rt, JS::HeapState::MajorCollecting);
|
||||||
|
|
||||||
majorGCTriggerReason = JS::gcreason::NO_REASON;
|
majorGCTriggerReason = JS::GCReason::NO_REASON;
|
||||||
|
|
||||||
{
|
{
|
||||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
|
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
|
||||||
|
@ -7479,18 +7474,18 @@ bool GCRuntime::shouldCollectNurseryForSlice(bool nonincrementalByAPI,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
static bool IsDeterministicGCReason(JS::gcreason::Reason reason) {
|
static bool IsDeterministicGCReason(JS::GCReason reason) {
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case JS::gcreason::API:
|
case JS::GCReason::API:
|
||||||
case JS::gcreason::DESTROY_RUNTIME:
|
case JS::GCReason::DESTROY_RUNTIME:
|
||||||
case JS::gcreason::LAST_DITCH:
|
case JS::GCReason::LAST_DITCH:
|
||||||
case JS::gcreason::TOO_MUCH_MALLOC:
|
case JS::GCReason::TOO_MUCH_MALLOC:
|
||||||
case JS::gcreason::TOO_MUCH_WASM_MEMORY:
|
case JS::GCReason::TOO_MUCH_WASM_MEMORY:
|
||||||
case JS::gcreason::ALLOC_TRIGGER:
|
case JS::GCReason::ALLOC_TRIGGER:
|
||||||
case JS::gcreason::DEBUG_GC:
|
case JS::GCReason::DEBUG_GC:
|
||||||
case JS::gcreason::CC_FORCED:
|
case JS::GCReason::CC_FORCED:
|
||||||
case JS::gcreason::SHUTDOWN_CC:
|
case JS::GCReason::SHUTDOWN_CC:
|
||||||
case JS::gcreason::ABORT_GC:
|
case JS::GCReason::ABORT_GC:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -7547,7 +7542,7 @@ void GCRuntime::checkCanCallAPI() {
|
||||||
MOZ_RELEASE_ASSERT(!JS::RuntimeHeapIsBusy());
|
MOZ_RELEASE_ASSERT(!JS::RuntimeHeapIsBusy());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason) {
|
bool GCRuntime::checkIfGCAllowedInCurrentState(JS::GCReason reason) {
|
||||||
if (rt->mainContextFromOwnThread()->suppressGC) {
|
if (rt->mainContextFromOwnThread()->suppressGC) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -7567,8 +7562,8 @@ bool GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason) {
|
bool GCRuntime::shouldRepeatForDeadZone(JS::GCReason reason) {
|
||||||
MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental);
|
MOZ_ASSERT_IF(reason == JS::GCReason::COMPARTMENT_REVIVED, !isIncremental);
|
||||||
MOZ_ASSERT(!isIncrementalGCInProgress());
|
MOZ_ASSERT(!isIncrementalGCInProgress());
|
||||||
|
|
||||||
if (!isIncremental) {
|
if (!isIncremental) {
|
||||||
|
@ -7585,7 +7580,7 @@ bool GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget,
|
void GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget,
|
||||||
JS::gcreason::Reason reason) {
|
JS::GCReason reason) {
|
||||||
// Checks run for each request, even if we do not actually GC.
|
// Checks run for each request, even if we do not actually GC.
|
||||||
checkCanCallAPI();
|
checkCanCallAPI();
|
||||||
|
|
||||||
|
@ -7607,7 +7602,7 @@ void GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget,
|
||||||
IncrementalResult cycleResult =
|
IncrementalResult cycleResult =
|
||||||
gcCycle(nonincrementalByAPI, budget, reason);
|
gcCycle(nonincrementalByAPI, budget, reason);
|
||||||
|
|
||||||
if (reason == JS::gcreason::ABORT_GC) {
|
if (reason == JS::GCReason::ABORT_GC) {
|
||||||
MOZ_ASSERT(!isIncrementalGCInProgress());
|
MOZ_ASSERT(!isIncrementalGCInProgress());
|
||||||
stats().writeLogMessage("GC aborted by request");
|
stats().writeLogMessage("GC aborted by request");
|
||||||
break;
|
break;
|
||||||
|
@ -7629,10 +7624,10 @@ void GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget,
|
||||||
/* Need to re-schedule all zones for GC. */
|
/* Need to re-schedule all zones for GC. */
|
||||||
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
|
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
|
||||||
repeat = true;
|
repeat = true;
|
||||||
reason = JS::gcreason::ROOTS_REMOVED;
|
reason = JS::GCReason::ROOTS_REMOVED;
|
||||||
} else if (shouldRepeatForDeadZone(reason)) {
|
} else if (shouldRepeatForDeadZone(reason)) {
|
||||||
repeat = true;
|
repeat = true;
|
||||||
reason = JS::gcreason::COMPARTMENT_REVIVED;
|
reason = JS::GCReason::COMPARTMENT_REVIVED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (repeat);
|
} while (repeat);
|
||||||
|
@ -7646,7 +7641,7 @@ void GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (reason == JS::gcreason::COMPARTMENT_REVIVED) {
|
if (reason == JS::GCReason::COMPARTMENT_REVIVED) {
|
||||||
maybeDoCycleCollection();
|
maybeDoCycleCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7669,10 +7664,9 @@ js::AutoEnqueuePendingParseTasksAfterGC::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SliceBudget GCRuntime::defaultBudget(JS::gcreason::Reason reason,
|
SliceBudget GCRuntime::defaultBudget(JS::GCReason reason, int64_t millis) {
|
||||||
int64_t millis) {
|
|
||||||
if (millis == 0) {
|
if (millis == 0) {
|
||||||
if (reason == JS::gcreason::ALLOC_TRIGGER) {
|
if (reason == JS::GCReason::ALLOC_TRIGGER) {
|
||||||
millis = defaultSliceBudget();
|
millis = defaultSliceBudget();
|
||||||
} else if (schedulingState.inHighFrequencyGCMode() &&
|
} else if (schedulingState.inHighFrequencyGCMode() &&
|
||||||
tunables.isDynamicMarkSliceEnabled()) {
|
tunables.isDynamicMarkSliceEnabled()) {
|
||||||
|
@ -7685,7 +7679,7 @@ SliceBudget GCRuntime::defaultBudget(JS::gcreason::Reason reason,
|
||||||
return SliceBudget(TimeBudget(millis));
|
return SliceBudget(TimeBudget(millis));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason) {
|
void GCRuntime::gc(JSGCInvocationKind gckind, JS::GCReason reason) {
|
||||||
// Watch out for calls to gc() that don't go through triggerGC().
|
// Watch out for calls to gc() that don't go through triggerGC().
|
||||||
if (!RecordReplayCheckCanGC(reason)) {
|
if (!RecordReplayCheckCanGC(reason)) {
|
||||||
return;
|
return;
|
||||||
|
@ -7695,7 +7689,7 @@ void GCRuntime::gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason) {
|
||||||
collect(true, SliceBudget::unlimited(), reason);
|
collect(true, SliceBudget::unlimited(), reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason,
|
void GCRuntime::startGC(JSGCInvocationKind gckind, JS::GCReason reason,
|
||||||
int64_t millis) {
|
int64_t millis) {
|
||||||
MOZ_ASSERT(!isIncrementalGCInProgress());
|
MOZ_ASSERT(!isIncrementalGCInProgress());
|
||||||
if (!JS::IsIncrementalGCEnabled(rt->mainContextFromOwnThread())) {
|
if (!JS::IsIncrementalGCEnabled(rt->mainContextFromOwnThread())) {
|
||||||
|
@ -7706,12 +7700,12 @@ void GCRuntime::startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason,
|
||||||
collect(false, defaultBudget(reason, millis), reason);
|
collect(false, defaultBudget(reason, millis), reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::gcSlice(JS::gcreason::Reason reason, int64_t millis) {
|
void GCRuntime::gcSlice(JS::GCReason reason, int64_t millis) {
|
||||||
MOZ_ASSERT(isIncrementalGCInProgress());
|
MOZ_ASSERT(isIncrementalGCInProgress());
|
||||||
collect(false, defaultBudget(reason, millis), reason);
|
collect(false, defaultBudget(reason, millis), reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::finishGC(JS::gcreason::Reason reason) {
|
void GCRuntime::finishGC(JS::GCReason reason) {
|
||||||
MOZ_ASSERT(isIncrementalGCInProgress());
|
MOZ_ASSERT(isIncrementalGCInProgress());
|
||||||
|
|
||||||
// If we're not collecting because we're out of memory then skip the
|
// If we're not collecting because we're out of memory then skip the
|
||||||
|
@ -7734,7 +7728,7 @@ void GCRuntime::abortGC() {
|
||||||
checkCanCallAPI();
|
checkCanCallAPI();
|
||||||
MOZ_ASSERT(!rt->mainContextFromOwnThread()->suppressGC);
|
MOZ_ASSERT(!rt->mainContextFromOwnThread()->suppressGC);
|
||||||
|
|
||||||
collect(false, SliceBudget::unlimited(), JS::gcreason::ABORT_GC);
|
collect(false, SliceBudget::unlimited(), JS::GCReason::ABORT_GC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ZonesSelected(JSRuntime* rt) {
|
static bool ZonesSelected(JSRuntime* rt) {
|
||||||
|
@ -7752,7 +7746,7 @@ void GCRuntime::startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget) {
|
||||||
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
|
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
|
||||||
}
|
}
|
||||||
invocationKind = gckind;
|
invocationKind = gckind;
|
||||||
collect(false, budget, JS::gcreason::DEBUG_GC);
|
collect(false, budget, JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::debugGCSlice(SliceBudget& budget) {
|
void GCRuntime::debugGCSlice(SliceBudget& budget) {
|
||||||
|
@ -7760,7 +7754,7 @@ void GCRuntime::debugGCSlice(SliceBudget& budget) {
|
||||||
if (!ZonesSelected(rt)) {
|
if (!ZonesSelected(rt)) {
|
||||||
JS::PrepareForIncrementalGC(rt->mainContextFromOwnThread());
|
JS::PrepareForIncrementalGC(rt->mainContextFromOwnThread());
|
||||||
}
|
}
|
||||||
collect(false, budget, JS::gcreason::DEBUG_GC);
|
collect(false, budget, JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Schedule a full GC unless a zone will already be collected. */
|
/* Schedule a full GC unless a zone will already be collected. */
|
||||||
|
@ -7798,10 +7792,10 @@ void GCRuntime::onOutOfMallocMemory(const AutoLockGC& lock) {
|
||||||
decommitAllWithoutUnlocking(lock);
|
decommitAllWithoutUnlocking(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::PhaseKind phase) {
|
void GCRuntime::minorGC(JS::GCReason reason, gcstats::PhaseKind phase) {
|
||||||
MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
|
MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
|
||||||
|
|
||||||
MOZ_ASSERT_IF(reason == JS::gcreason::EVICT_NURSERY,
|
MOZ_ASSERT_IF(reason == JS::GCReason::EVICT_NURSERY,
|
||||||
!rt->mainContextFromOwnThread()->suppressGC);
|
!rt->mainContextFromOwnThread()->suppressGC);
|
||||||
if (rt->mainContextFromOwnThread()->suppressGC) {
|
if (rt->mainContextFromOwnThread()->suppressGC) {
|
||||||
return;
|
return;
|
||||||
|
@ -7861,7 +7855,7 @@ void GCRuntime::startBackgroundFreeAfterMinorGC() {
|
||||||
JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSContext* cx)
|
JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSContext* cx)
|
||||||
: cx(cx) {
|
: cx(cx) {
|
||||||
if (!cx->generationalDisabled) {
|
if (!cx->generationalDisabled) {
|
||||||
cx->runtime()->gc.evictNursery(JS::gcreason::API);
|
cx->runtime()->gc.evictNursery(JS::GCReason::API);
|
||||||
cx->nursery().disable();
|
cx->nursery().disable();
|
||||||
}
|
}
|
||||||
++cx->generationalDisabled;
|
++cx->generationalDisabled;
|
||||||
|
@ -7885,11 +7879,11 @@ bool GCRuntime::gcIfRequested() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (majorGCRequested()) {
|
if (majorGCRequested()) {
|
||||||
if (majorGCTriggerReason == JS::gcreason::DELAYED_ATOMS_GC &&
|
if (majorGCTriggerReason == JS::GCReason::DELAYED_ATOMS_GC &&
|
||||||
!rt->mainContextFromOwnThread()->canCollectAtoms()) {
|
!rt->mainContextFromOwnThread()->canCollectAtoms()) {
|
||||||
// A GC was requested to collect the atoms zone, but it's no longer
|
// A GC was requested to collect the atoms zone, but it's no longer
|
||||||
// possible. Skip this collection.
|
// possible. Skip this collection.
|
||||||
majorGCTriggerReason = JS::gcreason::NO_REASON;
|
majorGCTriggerReason = JS::GCReason::NO_REASON;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7907,7 +7901,7 @@ bool GCRuntime::gcIfRequested() {
|
||||||
void js::gc::FinishGC(JSContext* cx) {
|
void js::gc::FinishGC(JSContext* cx) {
|
||||||
if (JS::IsIncrementalGCInProgress(cx)) {
|
if (JS::IsIncrementalGCInProgress(cx)) {
|
||||||
JS::PrepareForIncrementalGC(cx);
|
JS::PrepareForIncrementalGC(cx);
|
||||||
JS::FinishIncrementalGC(cx, JS::gcreason::API);
|
JS::FinishIncrementalGC(cx, JS::GCReason::API);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->runtime()->gc.waitBackgroundFreeEnd();
|
cx->runtime()->gc.waitBackgroundFreeEnd();
|
||||||
|
@ -8188,7 +8182,7 @@ void GCRuntime::runDebugGC() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasZealMode(ZealMode::GenerationalGC)) {
|
if (hasZealMode(ZealMode::GenerationalGC)) {
|
||||||
return minorGC(JS::gcreason::DEBUG_GC);
|
return minorGC(JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrepareForDebugGC(rt);
|
PrepareForDebugGC(rt);
|
||||||
|
@ -8211,7 +8205,7 @@ void GCRuntime::runDebugGC() {
|
||||||
if (!isIncrementalGCInProgress()) {
|
if (!isIncrementalGCInProgress()) {
|
||||||
invocationKind = GC_SHRINK;
|
invocationKind = GC_SHRINK;
|
||||||
}
|
}
|
||||||
collect(false, budget, JS::gcreason::DEBUG_GC);
|
collect(false, budget, JS::GCReason::DEBUG_GC);
|
||||||
|
|
||||||
/* Reset the slice size when we get to the sweep or compact phases. */
|
/* Reset the slice size when we get to the sweep or compact phases. */
|
||||||
if ((initialState == State::Mark && incrementalState == State::Sweep) ||
|
if ((initialState == State::Mark && incrementalState == State::Sweep) ||
|
||||||
|
@ -8226,11 +8220,11 @@ void GCRuntime::runDebugGC() {
|
||||||
if (!isIncrementalGCInProgress()) {
|
if (!isIncrementalGCInProgress()) {
|
||||||
invocationKind = GC_NORMAL;
|
invocationKind = GC_NORMAL;
|
||||||
}
|
}
|
||||||
collect(false, budget, JS::gcreason::DEBUG_GC);
|
collect(false, budget, JS::GCReason::DEBUG_GC);
|
||||||
} else if (hasZealMode(ZealMode::Compact)) {
|
} else if (hasZealMode(ZealMode::Compact)) {
|
||||||
gc(GC_SHRINK, JS::gcreason::DEBUG_GC);
|
gc(GC_SHRINK, JS::GCReason::DEBUG_GC);
|
||||||
} else {
|
} else {
|
||||||
gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
|
gc(GC_NORMAL, JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8526,27 +8520,24 @@ JS_PUBLIC_API void JS::SkipZoneForGC(Zone* zone) { zone->unscheduleGC(); }
|
||||||
|
|
||||||
JS_PUBLIC_API void JS::NonIncrementalGC(JSContext* cx,
|
JS_PUBLIC_API void JS::NonIncrementalGC(JSContext* cx,
|
||||||
JSGCInvocationKind gckind,
|
JSGCInvocationKind gckind,
|
||||||
gcreason::Reason reason) {
|
GCReason reason) {
|
||||||
MOZ_ASSERT(gckind == GC_NORMAL || gckind == GC_SHRINK);
|
MOZ_ASSERT(gckind == GC_NORMAL || gckind == GC_SHRINK);
|
||||||
cx->runtime()->gc.gc(gckind, reason);
|
cx->runtime()->gc.gc(gckind, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API void JS::StartIncrementalGC(JSContext* cx,
|
JS_PUBLIC_API void JS::StartIncrementalGC(JSContext* cx,
|
||||||
JSGCInvocationKind gckind,
|
JSGCInvocationKind gckind,
|
||||||
gcreason::Reason reason,
|
GCReason reason, int64_t millis) {
|
||||||
int64_t millis) {
|
|
||||||
MOZ_ASSERT(gckind == GC_NORMAL || gckind == GC_SHRINK);
|
MOZ_ASSERT(gckind == GC_NORMAL || gckind == GC_SHRINK);
|
||||||
cx->runtime()->gc.startGC(gckind, reason, millis);
|
cx->runtime()->gc.startGC(gckind, reason, millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API void JS::IncrementalGCSlice(JSContext* cx,
|
JS_PUBLIC_API void JS::IncrementalGCSlice(JSContext* cx, GCReason reason,
|
||||||
gcreason::Reason reason,
|
|
||||||
int64_t millis) {
|
int64_t millis) {
|
||||||
cx->runtime()->gc.gcSlice(reason, millis);
|
cx->runtime()->gc.gcSlice(reason, millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API void JS::FinishIncrementalGC(JSContext* cx,
|
JS_PUBLIC_API void JS::FinishIncrementalGC(JSContext* cx, GCReason reason) {
|
||||||
gcreason::Reason reason) {
|
|
||||||
cx->runtime()->gc.finishGC(reason);
|
cx->runtime()->gc.finishGC(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8921,7 +8912,7 @@ void AutoAssertEmptyNursery::checkCondition(JSContext* cx) {
|
||||||
AutoEmptyNursery::AutoEmptyNursery(JSContext* cx) : AutoAssertEmptyNursery() {
|
AutoEmptyNursery::AutoEmptyNursery(JSContext* cx) : AutoAssertEmptyNursery() {
|
||||||
MOZ_ASSERT(!cx->suppressGC);
|
MOZ_ASSERT(!cx->suppressGC);
|
||||||
cx->runtime()->gc.stats().suspendPhases();
|
cx->runtime()->gc.stats().suspendPhases();
|
||||||
cx->runtime()->gc.evictNursery(JS::gcreason::EVICT_NURSERY);
|
cx->runtime()->gc.evictNursery(JS::GCReason::EVICT_NURSERY);
|
||||||
cx->runtime()->gc.stats().resumePhases();
|
cx->runtime()->gc.stats().resumePhases();
|
||||||
checkCondition(cx);
|
checkCondition(cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,9 +282,9 @@ class MOZ_RAII AutoEmptyNursery : public AutoAssertEmptyNursery {
|
||||||
|
|
||||||
extern void DelayCrossCompartmentGrayMarking(JSObject* src);
|
extern void DelayCrossCompartmentGrayMarking(JSObject* src);
|
||||||
|
|
||||||
inline bool IsOOMReason(JS::gcreason::Reason reason) {
|
inline bool IsOOMReason(JS::GCReason reason) {
|
||||||
return reason == JS::gcreason::LAST_DITCH ||
|
return reason == JS::GCReason::LAST_DITCH ||
|
||||||
reason == JS::gcreason::MEM_PRESSURE;
|
reason == JS::GCReason::MEM_PRESSURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
TenuredCell* AllocateCellInGC(JS::Zone* zone, AllocKind thingKind);
|
TenuredCell* AllocateCellInGC(JS::Zone* zone, AllocKind thingKind);
|
||||||
|
|
|
@ -246,19 +246,19 @@ class GCRuntime {
|
||||||
void resetParameter(JSGCParamKey key, AutoLockGC& lock);
|
void resetParameter(JSGCParamKey key, AutoLockGC& lock);
|
||||||
uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
|
uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
|
||||||
|
|
||||||
MOZ_MUST_USE bool triggerGC(JS::gcreason::Reason reason);
|
MOZ_MUST_USE bool triggerGC(JS::GCReason reason);
|
||||||
void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
|
void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
|
||||||
// The return value indicates if we were able to do the GC.
|
// The return value indicates if we were able to do the GC.
|
||||||
bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason, size_t usedBytes,
|
bool triggerZoneGC(Zone* zone, JS::GCReason reason, size_t usedBytes,
|
||||||
size_t thresholdBytes);
|
size_t thresholdBytes);
|
||||||
void maybeGC(Zone* zone);
|
void maybeGC(Zone* zone);
|
||||||
// The return value indicates whether a major GC was performed.
|
// The return value indicates whether a major GC was performed.
|
||||||
bool gcIfRequested();
|
bool gcIfRequested();
|
||||||
void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
|
void gc(JSGCInvocationKind gckind, JS::GCReason reason);
|
||||||
void startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason,
|
void startGC(JSGCInvocationKind gckind, JS::GCReason reason,
|
||||||
int64_t millis = 0);
|
int64_t millis = 0);
|
||||||
void gcSlice(JS::gcreason::Reason reason, int64_t millis = 0);
|
void gcSlice(JS::GCReason reason, int64_t millis = 0);
|
||||||
void finishGC(JS::gcreason::Reason reason);
|
void finishGC(JS::GCReason reason);
|
||||||
void abortGC();
|
void abortGC();
|
||||||
void startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget);
|
void startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget);
|
||||||
void debugGCSlice(SliceBudget& budget);
|
void debugGCSlice(SliceBudget& budget);
|
||||||
|
@ -356,7 +356,7 @@ class GCRuntime {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!triggerGC(JS::gcreason::TOO_MUCH_MALLOC)) {
|
if (!triggerGC(JS::GCReason::TOO_MUCH_MALLOC)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +420,7 @@ class GCRuntime {
|
||||||
void setGrayBitsInvalid() { grayBitsValid = false; }
|
void setGrayBitsInvalid() { grayBitsValid = false; }
|
||||||
|
|
||||||
bool majorGCRequested() const {
|
bool majorGCRequested() const {
|
||||||
return majorGCTriggerReason != JS::gcreason::NO_REASON;
|
return majorGCTriggerReason != JS::GCReason::NO_REASON;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fullGCForAtomsRequested() const { return fullGCForAtomsRequested_; }
|
bool fullGCForAtomsRequested() const { return fullGCForAtomsRequested_; }
|
||||||
|
@ -550,10 +550,10 @@ class GCRuntime {
|
||||||
bool wantBackgroundAllocation(const AutoLockGC& lock) const;
|
bool wantBackgroundAllocation(const AutoLockGC& lock) const;
|
||||||
bool startBackgroundAllocTaskIfIdle();
|
bool startBackgroundAllocTaskIfIdle();
|
||||||
|
|
||||||
void requestMajorGC(JS::gcreason::Reason reason);
|
void requestMajorGC(JS::GCReason reason);
|
||||||
SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis);
|
SliceBudget defaultBudget(JS::GCReason reason, int64_t millis);
|
||||||
IncrementalResult budgetIncrementalGC(bool nonincrementalByAPI,
|
IncrementalResult budgetIncrementalGC(bool nonincrementalByAPI,
|
||||||
JS::gcreason::Reason reason,
|
JS::GCReason reason,
|
||||||
SliceBudget& budget);
|
SliceBudget& budget);
|
||||||
IncrementalResult resetIncrementalGC(AbortReason reason);
|
IncrementalResult resetIncrementalGC(AbortReason reason);
|
||||||
|
|
||||||
|
@ -563,11 +563,11 @@ class GCRuntime {
|
||||||
|
|
||||||
// Check if the system state is such that GC has been supressed
|
// Check if the system state is such that GC has been supressed
|
||||||
// or otherwise delayed.
|
// or otherwise delayed.
|
||||||
MOZ_MUST_USE bool checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason);
|
MOZ_MUST_USE bool checkIfGCAllowedInCurrentState(JS::GCReason reason);
|
||||||
|
|
||||||
gcstats::ZoneGCStats scanZonesBeforeGC();
|
gcstats::ZoneGCStats scanZonesBeforeGC();
|
||||||
void collect(bool nonincrementalByAPI, SliceBudget budget,
|
void collect(bool nonincrementalByAPI, SliceBudget budget,
|
||||||
JS::gcreason::Reason reason) JS_HAZ_GC_CALL;
|
JS::GCReason reason) JS_HAZ_GC_CALL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run one GC "cycle" (either a slice of incremental GC or an entire
|
* Run one GC "cycle" (either a slice of incremental GC or an entire
|
||||||
|
@ -580,9 +580,9 @@ class GCRuntime {
|
||||||
*/
|
*/
|
||||||
MOZ_MUST_USE IncrementalResult gcCycle(bool nonincrementalByAPI,
|
MOZ_MUST_USE IncrementalResult gcCycle(bool nonincrementalByAPI,
|
||||||
SliceBudget budget,
|
SliceBudget budget,
|
||||||
JS::gcreason::Reason reason);
|
JS::GCReason reason);
|
||||||
bool shouldRepeatForDeadZone(JS::gcreason::Reason reason);
|
bool shouldRepeatForDeadZone(JS::GCReason reason);
|
||||||
void incrementalSlice(SliceBudget& budget, JS::gcreason::Reason reason,
|
void incrementalSlice(SliceBudget& budget, JS::GCReason reason,
|
||||||
AutoGCSession& session);
|
AutoGCSession& session);
|
||||||
MOZ_MUST_USE bool shouldCollectNurseryForSlice(bool nonincrementalByAPI,
|
MOZ_MUST_USE bool shouldCollectNurseryForSlice(bool nonincrementalByAPI,
|
||||||
SliceBudget& budget);
|
SliceBudget& budget);
|
||||||
|
@ -592,13 +592,11 @@ class GCRuntime {
|
||||||
|
|
||||||
void pushZealSelectedObjects();
|
void pushZealSelectedObjects();
|
||||||
void purgeRuntime();
|
void purgeRuntime();
|
||||||
MOZ_MUST_USE bool beginMarkPhase(JS::gcreason::Reason reason,
|
MOZ_MUST_USE bool beginMarkPhase(JS::GCReason reason, AutoGCSession& session);
|
||||||
AutoGCSession& session);
|
bool prepareZonesForCollection(JS::GCReason reason, bool* isFullOut);
|
||||||
bool prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut);
|
|
||||||
bool shouldPreserveJITCode(JS::Realm* realm,
|
bool shouldPreserveJITCode(JS::Realm* realm,
|
||||||
const mozilla::TimeStamp& currentTime,
|
const mozilla::TimeStamp& currentTime,
|
||||||
JS::gcreason::Reason reason,
|
JS::GCReason reason, bool canAllocateMoreCode);
|
||||||
bool canAllocateMoreCode);
|
|
||||||
void startBackgroundFreeAfterMinorGC();
|
void startBackgroundFreeAfterMinorGC();
|
||||||
void traceRuntimeForMajorGC(JSTracer* trc, AutoGCSession& session);
|
void traceRuntimeForMajorGC(JSTracer* trc, AutoGCSession& session);
|
||||||
void traceRuntimeAtoms(JSTracer* trc, const AutoAccessAtomsZone& atomsAccess);
|
void traceRuntimeAtoms(JSTracer* trc, const AutoAccessAtomsZone& atomsAccess);
|
||||||
|
@ -618,8 +616,8 @@ class GCRuntime {
|
||||||
void markAllWeakReferences(gcstats::PhaseKind phase);
|
void markAllWeakReferences(gcstats::PhaseKind phase);
|
||||||
void markAllGrayReferences(gcstats::PhaseKind phase);
|
void markAllGrayReferences(gcstats::PhaseKind phase);
|
||||||
|
|
||||||
void beginSweepPhase(JS::gcreason::Reason reason, AutoGCSession& session);
|
void beginSweepPhase(JS::GCReason reason, AutoGCSession& session);
|
||||||
void groupZonesForSweeping(JS::gcreason::Reason reason);
|
void groupZonesForSweeping(JS::GCReason reason);
|
||||||
MOZ_MUST_USE bool findInterZoneEdges();
|
MOZ_MUST_USE bool findInterZoneEdges();
|
||||||
void getNextSweepGroup();
|
void getNextSweepGroup();
|
||||||
IncrementalProgress markGrayReferencesInCurrentGroup(FreeOp* fop,
|
IncrementalProgress markGrayReferencesInCurrentGroup(FreeOp* fop,
|
||||||
|
@ -655,13 +653,13 @@ class GCRuntime {
|
||||||
void assertBackgroundSweepingFinished();
|
void assertBackgroundSweepingFinished();
|
||||||
bool shouldCompact();
|
bool shouldCompact();
|
||||||
void beginCompactPhase();
|
void beginCompactPhase();
|
||||||
IncrementalProgress compactPhase(JS::gcreason::Reason reason,
|
IncrementalProgress compactPhase(JS::GCReason reason,
|
||||||
SliceBudget& sliceBudget,
|
SliceBudget& sliceBudget,
|
||||||
AutoGCSession& session);
|
AutoGCSession& session);
|
||||||
void endCompactPhase();
|
void endCompactPhase();
|
||||||
void sweepTypesAfterCompacting(Zone* zone);
|
void sweepTypesAfterCompacting(Zone* zone);
|
||||||
void sweepZoneAfterCompacting(Zone* zone);
|
void sweepZoneAfterCompacting(Zone* zone);
|
||||||
MOZ_MUST_USE bool relocateArenas(Zone* zone, JS::gcreason::Reason reason,
|
MOZ_MUST_USE bool relocateArenas(Zone* zone, JS::GCReason reason,
|
||||||
Arena*& relocatedListOut,
|
Arena*& relocatedListOut,
|
||||||
SliceBudget& sliceBudget);
|
SliceBudget& sliceBudget);
|
||||||
void updateTypeDescrObjects(MovingTracer* trc, Zone* zone);
|
void updateTypeDescrObjects(MovingTracer* trc, Zone* zone);
|
||||||
|
@ -804,7 +802,7 @@ class GCRuntime {
|
||||||
*/
|
*/
|
||||||
UnprotectedData<bool> grayBitsValid;
|
UnprotectedData<bool> grayBitsValid;
|
||||||
|
|
||||||
mozilla::Atomic<JS::gcreason::Reason, mozilla::Relaxed,
|
mozilla::Atomic<JS::GCReason, mozilla::Relaxed,
|
||||||
mozilla::recordreplay::Behavior::DontPreserve>
|
mozilla::recordreplay::Behavior::DontPreserve>
|
||||||
majorGCTriggerReason;
|
majorGCTriggerReason;
|
||||||
|
|
||||||
|
@ -834,7 +832,7 @@ class GCRuntime {
|
||||||
MainThreadData<JSGCInvocationKind> invocationKind;
|
MainThreadData<JSGCInvocationKind> invocationKind;
|
||||||
|
|
||||||
/* The initial GC reason, taken from the first slice. */
|
/* The initial GC reason, taken from the first slice. */
|
||||||
MainThreadData<JS::gcreason::Reason> initialReason;
|
MainThreadData<JS::GCReason> initialReason;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The current incremental GC phase. This is also used internally in
|
* The current incremental GC phase. This is also used internally in
|
||||||
|
@ -1041,10 +1039,10 @@ class GCRuntime {
|
||||||
return stats().addressOfAllocsSinceMinorGCNursery();
|
return stats().addressOfAllocsSinceMinorGCNursery();
|
||||||
}
|
}
|
||||||
|
|
||||||
void minorGC(JS::gcreason::Reason reason,
|
void minorGC(JS::GCReason reason,
|
||||||
gcstats::PhaseKind phase = gcstats::PhaseKind::MINOR_GC)
|
gcstats::PhaseKind phase = gcstats::PhaseKind::MINOR_GC)
|
||||||
JS_HAZ_GC_CALL;
|
JS_HAZ_GC_CALL;
|
||||||
void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) {
|
void evictNursery(JS::GCReason reason = JS::GCReason::EVICT_NURSERY) {
|
||||||
minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY);
|
minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,20 +95,20 @@ using mozilla::PodCopy;
|
||||||
// '---------' '----------' '-----------------' //
|
// '---------' '----------' '-----------------' //
|
||||||
// | //
|
// | //
|
||||||
// | //
|
// | //
|
||||||
// .--------. //
|
// .-----------. //
|
||||||
// o---------------->|traverse| . //
|
// o------------->|traverse(T)| . //
|
||||||
// /_\ '--------' ' . //
|
// /_\ '-----------' ' . //
|
||||||
// | . . ' . //
|
// | . . ' . //
|
||||||
// | . . ' . //
|
// | . . ' . //
|
||||||
// | . . ' . //
|
// | . . ' . //
|
||||||
// | .-----------. .-----------. ' . .--------------------. //
|
// | .--------------. .--------------. ' . .-----------------------. //
|
||||||
// | |markAndScan| |markAndPush| ' - |markAndTraceChildren|----> //
|
// | |markAndScan(T)| |markAndPush(T)| ' - |markAndTraceChildren(T)| //
|
||||||
// | '-----------' '-----------' '--------------------' //
|
// | '--------------' '--------------' '-----------------------' //
|
||||||
// | | \ //
|
// | | \ | //
|
||||||
// | | \ //
|
// | | \ | //
|
||||||
// | .----------------------. .----------------. //
|
// | .----------------------. .----------------. .------------------. //
|
||||||
// | |T::eagerlyMarkChildren| |pushMarkStackTop|<===Oo //
|
// | |eagerlyMarkChildren(T)| |pushMarkStackTop|<===Oo |T::traceChildren()|--> //
|
||||||
// | '----------------------' '----------------' || //
|
// | '----------------------' '----------------' || '------------------' //
|
||||||
// | | || || //
|
// | | || || //
|
||||||
// | | || || //
|
// | | || || //
|
||||||
// | | || || //
|
// | | || || //
|
||||||
|
@ -847,7 +847,6 @@ void GCMarker::traverse(JSString* thing) {
|
||||||
template <>
|
template <>
|
||||||
void GCMarker::traverse(LazyScript* thing) {
|
void GCMarker::traverse(LazyScript* thing) {
|
||||||
markAndScan(thing);
|
markAndScan(thing);
|
||||||
markImplicitEdges(thing);
|
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
void GCMarker::traverse(Shape* thing) {
|
void GCMarker::traverse(Shape* thing) {
|
||||||
|
@ -1032,7 +1031,7 @@ void LazyScript::traceChildren(JSTracer* trc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trc->isMarkingTracer()) {
|
if (trc->isMarkingTracer()) {
|
||||||
return GCMarker::fromTracer(trc)->markImplicitEdges(this);
|
GCMarker::fromTracer(trc)->markImplicitEdges(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void js::GCMarker::eagerlyMarkChildren(LazyScript* thing) {
|
inline void js::GCMarker::eagerlyMarkChildren(LazyScript* thing) {
|
||||||
|
@ -1068,6 +1067,8 @@ inline void js::GCMarker::eagerlyMarkChildren(LazyScript* thing) {
|
||||||
for (auto i : IntegerRange(thing->numInnerFunctions())) {
|
for (auto i : IntegerRange(thing->numInnerFunctions())) {
|
||||||
traverseEdge(thing, static_cast<JSObject*>(innerFunctions[i]));
|
traverseEdge(thing, static_cast<JSObject*>(innerFunctions[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markImplicitEdges(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shape::traceChildren(JSTracer* trc) {
|
void Shape::traceChildren(JSTracer* trc) {
|
||||||
|
@ -1101,7 +1102,7 @@ inline void js::GCMarker::eagerlyMarkChildren(Shape* shape) {
|
||||||
|
|
||||||
traverseEdge(shape, shape->propidRef().get());
|
traverseEdge(shape, shape->propidRef().get());
|
||||||
|
|
||||||
// When triggered between slices on belhalf of a barrier, these
|
// When triggered between slices on behalf of a barrier, these
|
||||||
// objects may reside in the nursery, so require an extra check.
|
// objects may reside in the nursery, so require an extra check.
|
||||||
// FIXME: Bug 1157967 - remove the isTenured checks.
|
// FIXME: Bug 1157967 - remove the isTenured checks.
|
||||||
if (shape->hasGetterObject() && shape->getterObject()->isTenured()) {
|
if (shape->hasGetterObject() && shape->getterObject()->isTenured()) {
|
||||||
|
|
|
@ -112,7 +112,7 @@ js::Nursery::Nursery(JSRuntime* rt)
|
||||||
enableProfiling_(false),
|
enableProfiling_(false),
|
||||||
canAllocateStrings_(false),
|
canAllocateStrings_(false),
|
||||||
reportTenurings_(0),
|
reportTenurings_(0),
|
||||||
minorGCTriggerReason_(JS::gcreason::NO_REASON)
|
minorGCTriggerReason_(JS::GCReason::NO_REASON)
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
,
|
,
|
||||||
lastCanary_(nullptr)
|
lastCanary_(nullptr)
|
||||||
|
@ -588,7 +588,7 @@ void js::Nursery::renderProfileJSON(JSONPrinter& json) const {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousGC.reason == JS::gcreason::NO_REASON) {
|
if (previousGC.reason == JS::GCReason::NO_REASON) {
|
||||||
// If the nursery was empty when the last minorGC was requested, then
|
// If the nursery was empty when the last minorGC was requested, then
|
||||||
// no nursery collection will have been performed but JSON may still be
|
// no nursery collection will have been performed but JSON may still be
|
||||||
// requested. (And as a public API, this function should not crash in
|
// requested. (And as a public API, this function should not crash in
|
||||||
|
@ -603,7 +603,7 @@ void js::Nursery::renderProfileJSON(JSONPrinter& json) const {
|
||||||
|
|
||||||
json.property("status", "complete");
|
json.property("status", "complete");
|
||||||
|
|
||||||
json.property("reason", JS::gcreason::ExplainReason(previousGC.reason));
|
json.property("reason", JS::ExplainGCReason(previousGC.reason));
|
||||||
json.property("bytes_tenured", previousGC.tenuredBytes);
|
json.property("bytes_tenured", previousGC.tenuredBytes);
|
||||||
json.property("cells_tenured", previousGC.tenuredCells);
|
json.property("cells_tenured", previousGC.tenuredCells);
|
||||||
json.property("strings_tenured",
|
json.property("strings_tenured",
|
||||||
|
@ -702,16 +702,16 @@ bool js::Nursery::needIdleTimeCollection() const {
|
||||||
return minorGCRequested() || freeSpace() < threshold;
|
return minorGCRequested() || freeSpace() < threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool IsFullStoreBufferReason(JS::gcreason::Reason reason) {
|
static inline bool IsFullStoreBufferReason(JS::GCReason reason) {
|
||||||
return reason == JS::gcreason::FULL_WHOLE_CELL_BUFFER ||
|
return reason == JS::GCReason::FULL_WHOLE_CELL_BUFFER ||
|
||||||
reason == JS::gcreason::FULL_GENERIC_BUFFER ||
|
reason == JS::GCReason::FULL_GENERIC_BUFFER ||
|
||||||
reason == JS::gcreason::FULL_VALUE_BUFFER ||
|
reason == JS::GCReason::FULL_VALUE_BUFFER ||
|
||||||
reason == JS::gcreason::FULL_CELL_PTR_BUFFER ||
|
reason == JS::GCReason::FULL_CELL_PTR_BUFFER ||
|
||||||
reason == JS::gcreason::FULL_SLOT_BUFFER ||
|
reason == JS::GCReason::FULL_SLOT_BUFFER ||
|
||||||
reason == JS::gcreason::FULL_SHAPE_BUFFER;
|
reason == JS::GCReason::FULL_SHAPE_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
void js::Nursery::collect(JS::gcreason::Reason reason) {
|
void js::Nursery::collect(JS::GCReason reason) {
|
||||||
JSRuntime* rt = runtime();
|
JSRuntime* rt = runtime();
|
||||||
MOZ_ASSERT(!rt->mainContextFromOwnThread()->suppressGC);
|
MOZ_ASSERT(!rt->mainContextFromOwnThread()->suppressGC);
|
||||||
|
|
||||||
|
@ -750,7 +750,7 @@ void js::Nursery::collect(JS::gcreason::Reason reason) {
|
||||||
MOZ_ASSERT(!IsNurseryAllocable(AllocKind::OBJECT_GROUP));
|
MOZ_ASSERT(!IsNurseryAllocable(AllocKind::OBJECT_GROUP));
|
||||||
|
|
||||||
TenureCountCache tenureCounts;
|
TenureCountCache tenureCounts;
|
||||||
previousGC.reason = JS::gcreason::NO_REASON;
|
previousGC.reason = JS::GCReason::NO_REASON;
|
||||||
if (!isEmpty()) {
|
if (!isEmpty()) {
|
||||||
doCollection(reason, tenureCounts);
|
doCollection(reason, tenureCounts);
|
||||||
} else {
|
} else {
|
||||||
|
@ -843,9 +843,9 @@ void js::Nursery::collect(JS::gcreason::Reason reason) {
|
||||||
|
|
||||||
TimeDuration totalTime = profileDurations_[ProfileKey::Total];
|
TimeDuration totalTime = profileDurations_[ProfileKey::Total];
|
||||||
rt->addTelemetry(JS_TELEMETRY_GC_MINOR_US, totalTime.ToMicroseconds());
|
rt->addTelemetry(JS_TELEMETRY_GC_MINOR_US, totalTime.ToMicroseconds());
|
||||||
rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON, reason);
|
rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON, uint32_t(reason));
|
||||||
if (totalTime.ToMilliseconds() > 1.0) {
|
if (totalTime.ToMilliseconds() > 1.0) {
|
||||||
rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON_LONG, reason);
|
rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON_LONG, uint32_t(reason));
|
||||||
}
|
}
|
||||||
rt->addTelemetry(JS_TELEMETRY_GC_NURSERY_BYTES, sizeOfHeapCommitted());
|
rt->addTelemetry(JS_TELEMETRY_GC_NURSERY_BYTES, sizeOfHeapCommitted());
|
||||||
rt->addTelemetry(JS_TELEMETRY_GC_PRETENURE_COUNT, pretenureCount);
|
rt->addTelemetry(JS_TELEMETRY_GC_PRETENURE_COUNT, pretenureCount);
|
||||||
|
@ -859,8 +859,7 @@ void js::Nursery::collect(JS::gcreason::Reason reason) {
|
||||||
stats().maybePrintProfileHeaders();
|
stats().maybePrintProfileHeaders();
|
||||||
|
|
||||||
fprintf(stderr, "MinorGC: %20s %5.1f%% %4u ",
|
fprintf(stderr, "MinorGC: %20s %5.1f%% %4u ",
|
||||||
JS::gcreason::ExplainReason(reason), promotionRate * 100,
|
JS::ExplainGCReason(reason), promotionRate * 100, maxChunkCount());
|
||||||
maxChunkCount());
|
|
||||||
printProfileDurations(profileDurations_);
|
printProfileDurations(profileDurations_);
|
||||||
|
|
||||||
if (reportTenurings_) {
|
if (reportTenurings_) {
|
||||||
|
@ -875,7 +874,7 @@ void js::Nursery::collect(JS::gcreason::Reason reason) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void js::Nursery::doCollection(JS::gcreason::Reason reason,
|
void js::Nursery::doCollection(JS::GCReason reason,
|
||||||
TenureCountCache& tenureCounts) {
|
TenureCountCache& tenureCounts) {
|
||||||
JSRuntime* rt = runtime();
|
JSRuntime* rt = runtime();
|
||||||
AutoGCSession session(rt, JS::HeapState::MinorCollecting);
|
AutoGCSession session(rt, JS::HeapState::MinorCollecting);
|
||||||
|
@ -1119,7 +1118,7 @@ MOZ_ALWAYS_INLINE void js::Nursery::setStartPosition() {
|
||||||
currentStartPosition_ = position();
|
currentStartPosition_ = position();
|
||||||
}
|
}
|
||||||
|
|
||||||
void js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason) {
|
void js::Nursery::maybeResizeNursery(JS::GCReason reason) {
|
||||||
static const double GrowThreshold = 0.03;
|
static const double GrowThreshold = 0.03;
|
||||||
static const double ShrinkThreshold = 0.01;
|
static const double ShrinkThreshold = 0.01;
|
||||||
unsigned newMaxNurseryChunks;
|
unsigned newMaxNurseryChunks;
|
||||||
|
|
|
@ -271,7 +271,7 @@ class Nursery {
|
||||||
static const size_t MaxNurseryBufferSize = 1024;
|
static const size_t MaxNurseryBufferSize = 1024;
|
||||||
|
|
||||||
/* Do a minor collection. */
|
/* Do a minor collection. */
|
||||||
void collect(JS::gcreason::Reason reason);
|
void collect(JS::GCReason reason);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the thing at |*ref| in the Nursery has been forwarded, set |*ref| to
|
* If the thing at |*ref| in the Nursery has been forwarded, set |*ref| to
|
||||||
|
@ -352,16 +352,14 @@ class Nursery {
|
||||||
return (void*)¤tStringEnd_;
|
return (void*)¤tStringEnd_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void requestMinorGC(JS::gcreason::Reason reason) const;
|
void requestMinorGC(JS::GCReason reason) const;
|
||||||
|
|
||||||
bool minorGCRequested() const {
|
bool minorGCRequested() const {
|
||||||
return minorGCTriggerReason_ != JS::gcreason::NO_REASON;
|
return minorGCTriggerReason_ != JS::GCReason::NO_REASON;
|
||||||
}
|
|
||||||
JS::gcreason::Reason minorGCTriggerReason() const {
|
|
||||||
return minorGCTriggerReason_;
|
|
||||||
}
|
}
|
||||||
|
JS::GCReason minorGCTriggerReason() const { return minorGCTriggerReason_; }
|
||||||
void clearMinorGCRequest() {
|
void clearMinorGCRequest() {
|
||||||
minorGCTriggerReason_ = JS::gcreason::NO_REASON;
|
minorGCTriggerReason_ = JS::GCReason::NO_REASON;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needIdleTimeCollection() const;
|
bool needIdleTimeCollection() const;
|
||||||
|
@ -442,7 +440,7 @@ class Nursery {
|
||||||
* mutable as it is set by the store buffer, which otherwise cannot modify
|
* mutable as it is set by the store buffer, which otherwise cannot modify
|
||||||
* anything in the nursery.
|
* anything in the nursery.
|
||||||
*/
|
*/
|
||||||
mutable JS::gcreason::Reason minorGCTriggerReason_;
|
mutable JS::GCReason minorGCTriggerReason_;
|
||||||
|
|
||||||
/* Profiling data. */
|
/* Profiling data. */
|
||||||
|
|
||||||
|
@ -465,7 +463,7 @@ class Nursery {
|
||||||
ProfileDurations totalDurations_;
|
ProfileDurations totalDurations_;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
JS::gcreason::Reason reason = JS::gcreason::NO_REASON;
|
JS::GCReason reason = JS::GCReason::NO_REASON;
|
||||||
size_t nurseryCapacity = 0;
|
size_t nurseryCapacity = 0;
|
||||||
size_t nurseryLazyCapacity = 0;
|
size_t nurseryLazyCapacity = 0;
|
||||||
size_t nurseryUsedBytes = 0;
|
size_t nurseryUsedBytes = 0;
|
||||||
|
@ -562,8 +560,7 @@ class Nursery {
|
||||||
/* Common internal allocator function. */
|
/* Common internal allocator function. */
|
||||||
void* allocate(size_t size);
|
void* allocate(size_t size);
|
||||||
|
|
||||||
void doCollection(JS::gcreason::Reason reason,
|
void doCollection(JS::GCReason reason, gc::TenureCountCache& tenureCounts);
|
||||||
gc::TenureCountCache& tenureCounts);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Move the object at |src| in the Nursery to an already-allocated cell
|
* Move the object at |src| in the Nursery to an already-allocated cell
|
||||||
|
@ -600,7 +597,7 @@ class Nursery {
|
||||||
void sweepMapAndSetObjects();
|
void sweepMapAndSetObjects();
|
||||||
|
|
||||||
/* Change the allocable space provided by the nursery. */
|
/* Change the allocable space provided by the nursery. */
|
||||||
void maybeResizeNursery(JS::gcreason::Reason reason);
|
void maybeResizeNursery(JS::GCReason reason);
|
||||||
void growAllocableSpace();
|
void growAllocableSpace();
|
||||||
void shrinkAllocableSpace(unsigned newCount);
|
void shrinkAllocableSpace(unsigned newCount);
|
||||||
void minimizeAllocableSpace();
|
void minimizeAllocableSpace();
|
||||||
|
|
|
@ -90,13 +90,13 @@
|
||||||
*
|
*
|
||||||
* While code generally takes the above factors into account in only an ad-hoc
|
* While code generally takes the above factors into account in only an ad-hoc
|
||||||
* fashion, the API forces the user to pick a "reason" for the GC. We have a
|
* fashion, the API forces the user to pick a "reason" for the GC. We have a
|
||||||
* bunch of JS::gcreason reasons in GCAPI.h. These fall into a few categories
|
* bunch of JS::GCReason reasons in GCAPI.h. These fall into a few categories
|
||||||
* that generally coincide with one or more of the above factors.
|
* that generally coincide with one or more of the above factors.
|
||||||
*
|
*
|
||||||
* Embedding reasons:
|
* Embedding reasons:
|
||||||
*
|
*
|
||||||
* 1) Do a GC now because the embedding knows something useful about the
|
* 1) Do a GC now because the embedding knows something useful about the
|
||||||
* zone's memory retention state. These are gcreasons like LOAD_END,
|
* zone's memory retention state. These are GCReasons like LOAD_END,
|
||||||
* PAGE_HIDE, SET_NEW_DOCUMENT, DOM_UTILS. Mostly, Gecko uses these to
|
* PAGE_HIDE, SET_NEW_DOCUMENT, DOM_UTILS. Mostly, Gecko uses these to
|
||||||
* indicate that a significant fraction of the scheduled zone's memory is
|
* indicate that a significant fraction of the scheduled zone's memory is
|
||||||
* probably reclaimable.
|
* probably reclaimable.
|
||||||
|
|
|
@ -40,8 +40,8 @@ using mozilla::TimeStamp;
|
||||||
* larger-numbered reasons to pile up in the last telemetry bucket, or switch
|
* larger-numbered reasons to pile up in the last telemetry bucket, or switch
|
||||||
* to GC_REASON_3 and bump the max value.
|
* to GC_REASON_3 and bump the max value.
|
||||||
*/
|
*/
|
||||||
JS_STATIC_ASSERT(JS::gcreason::NUM_TELEMETRY_REASONS >=
|
JS_STATIC_ASSERT(JS::GCReason::NUM_TELEMETRY_REASONS >=
|
||||||
JS::gcreason::NUM_REASONS);
|
JS::GCReason::NUM_REASONS);
|
||||||
|
|
||||||
using PhaseKindRange =
|
using PhaseKindRange =
|
||||||
decltype(mozilla::MakeEnumeratedRange(PhaseKind::FIRST, PhaseKind::LIMIT));
|
decltype(mozilla::MakeEnumeratedRange(PhaseKind::FIRST, PhaseKind::LIMIT));
|
||||||
|
@ -64,11 +64,10 @@ const char* js::gcstats::ExplainInvocationKind(JSGCInvocationKind gckind) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API const char* JS::gcreason::ExplainReason(
|
JS_PUBLIC_API const char* JS::ExplainGCReason(JS::GCReason reason) {
|
||||||
JS::gcreason::Reason reason) {
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
#define SWITCH_REASON(name, _) \
|
#define SWITCH_REASON(name, _) \
|
||||||
case JS::gcreason::name: \
|
case JS::GCReason::name: \
|
||||||
return #name;
|
return #name;
|
||||||
GCREASONS(SWITCH_REASON)
|
GCREASONS(SWITCH_REASON)
|
||||||
|
|
||||||
|
@ -279,7 +278,8 @@ UniqueChars Statistics::formatCompactSliceMessage() const {
|
||||||
"%s%s; Times: ";
|
"%s%s; Times: ";
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
SprintfLiteral(buffer, format, index, t(slice.duration()), budgetDescription,
|
SprintfLiteral(buffer, format, index, t(slice.duration()), budgetDescription,
|
||||||
t(slice.start - slices_[0].start), ExplainReason(slice.reason),
|
t(slice.start - slices_[0].start),
|
||||||
|
ExplainGCReason(slice.reason),
|
||||||
slice.wasReset() ? "yes - " : "no",
|
slice.wasReset() ? "yes - " : "no",
|
||||||
slice.wasReset() ? ExplainAbortReason(slice.resetReason) : "");
|
slice.wasReset() ? ExplainAbortReason(slice.resetReason) : "");
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ UniqueChars Statistics::formatDetailedDescription() const {
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
SprintfLiteral(
|
SprintfLiteral(
|
||||||
buffer, format, ExplainInvocationKind(gckind),
|
buffer, format, ExplainInvocationKind(gckind),
|
||||||
ExplainReason(slices_[0].reason), nonincremental() ? "no - " : "yes",
|
ExplainGCReason(slices_[0].reason), nonincremental() ? "no - " : "yes",
|
||||||
nonincremental() ? ExplainAbortReason(nonincrementalReason_) : "",
|
nonincremental() ? ExplainAbortReason(nonincrementalReason_) : "",
|
||||||
zoneStats.collectedZoneCount, zoneStats.zoneCount,
|
zoneStats.collectedZoneCount, zoneStats.zoneCount,
|
||||||
zoneStats.sweptZoneCount, zoneStats.collectedCompartmentCount,
|
zoneStats.sweptZoneCount, zoneStats.collectedCompartmentCount,
|
||||||
|
@ -475,7 +475,7 @@ UniqueChars Statistics::formatDetailedSliceDescription(
|
||||||
";
|
";
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
SprintfLiteral(
|
SprintfLiteral(
|
||||||
buffer, format, i, ExplainReason(slice.reason),
|
buffer, format, i, ExplainGCReason(slice.reason),
|
||||||
slice.wasReset() ? "yes - " : "no",
|
slice.wasReset() ? "yes - " : "no",
|
||||||
slice.wasReset() ? ExplainAbortReason(slice.resetReason) : "",
|
slice.wasReset() ? ExplainAbortReason(slice.resetReason) : "",
|
||||||
gc::StateName(slice.initialState), gc::StateName(slice.finalState),
|
gc::StateName(slice.initialState), gc::StateName(slice.finalState),
|
||||||
|
@ -650,7 +650,7 @@ void Statistics::formatJsonDescription(uint64_t timestamp, JSONPrinter& json,
|
||||||
json.property("total_time", total, JSONPrinter::MILLISECONDS); // #4
|
json.property("total_time", total, JSONPrinter::MILLISECONDS); // #4
|
||||||
// We might be able to omit reason if perf.html was able to retrive it
|
// We might be able to omit reason if perf.html was able to retrive it
|
||||||
// from the first slice. But it doesn't do this yet.
|
// from the first slice. But it doesn't do this yet.
|
||||||
json.property("reason", ExplainReason(slices_[0].reason)); // #5
|
json.property("reason", ExplainGCReason(slices_[0].reason)); // #5
|
||||||
json.property("zones_collected", zoneStats.collectedZoneCount); // #6
|
json.property("zones_collected", zoneStats.collectedZoneCount); // #6
|
||||||
json.property("total_zones", zoneStats.zoneCount); // #7
|
json.property("total_zones", zoneStats.zoneCount); // #7
|
||||||
json.property("total_compartments", zoneStats.compartmentCount); // #8
|
json.property("total_compartments", zoneStats.compartmentCount); // #8
|
||||||
|
@ -713,7 +713,7 @@ void Statistics::formatJsonSliceDescription(unsigned i, const SliceData& slice,
|
||||||
|
|
||||||
json.property("slice", i); // JSON Property #1
|
json.property("slice", i); // JSON Property #1
|
||||||
json.property("pause", slice.duration(), JSONPrinter::MILLISECONDS); // #2
|
json.property("pause", slice.duration(), JSONPrinter::MILLISECONDS); // #2
|
||||||
json.property("reason", ExplainReason(slice.reason)); // #3
|
json.property("reason", ExplainGCReason(slice.reason)); // #3
|
||||||
json.property("initial_state", gc::StateName(slice.initialState)); // #4
|
json.property("initial_state", gc::StateName(slice.initialState)); // #4
|
||||||
json.property("final_state", gc::StateName(slice.finalState)); // #5
|
json.property("final_state", gc::StateName(slice.finalState)); // #5
|
||||||
json.property("budget", budgetDescription); // #6
|
json.property("budget", budgetDescription); // #6
|
||||||
|
@ -1024,7 +1024,7 @@ void Statistics::endGC() {
|
||||||
thresholdTriggered = false;
|
thresholdTriggered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statistics::beginNurseryCollection(JS::gcreason::Reason reason) {
|
void Statistics::beginNurseryCollection(JS::GCReason reason) {
|
||||||
count(COUNT_MINOR_GC);
|
count(COUNT_MINOR_GC);
|
||||||
startingMinorGCNumber = runtime->gc.minorGCCount();
|
startingMinorGCNumber = runtime->gc.minorGCCount();
|
||||||
if (nurseryCollectionCallback) {
|
if (nurseryCollectionCallback) {
|
||||||
|
@ -1034,7 +1034,7 @@ void Statistics::beginNurseryCollection(JS::gcreason::Reason reason) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statistics::endNurseryCollection(JS::gcreason::Reason reason) {
|
void Statistics::endNurseryCollection(JS::GCReason reason) {
|
||||||
if (nurseryCollectionCallback) {
|
if (nurseryCollectionCallback) {
|
||||||
(*nurseryCollectionCallback)(
|
(*nurseryCollectionCallback)(
|
||||||
runtime->mainContextFromOwnThread(),
|
runtime->mainContextFromOwnThread(),
|
||||||
|
@ -1046,7 +1046,7 @@ void Statistics::endNurseryCollection(JS::gcreason::Reason reason) {
|
||||||
|
|
||||||
void Statistics::beginSlice(const ZoneGCStats& zoneStats,
|
void Statistics::beginSlice(const ZoneGCStats& zoneStats,
|
||||||
JSGCInvocationKind gckind, SliceBudget budget,
|
JSGCInvocationKind gckind, SliceBudget budget,
|
||||||
JS::gcreason::Reason reason) {
|
JS::GCReason reason) {
|
||||||
MOZ_ASSERT(phaseStack.empty() ||
|
MOZ_ASSERT(phaseStack.empty() ||
|
||||||
(phaseStack.length() == 1 && phaseStack[0] == Phase::MUTATOR));
|
(phaseStack.length() == 1 && phaseStack[0] == Phase::MUTATOR));
|
||||||
|
|
||||||
|
@ -1064,7 +1064,7 @@ void Statistics::beginSlice(const ZoneGCStats& zoneStats,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason);
|
runtime->addTelemetry(JS_TELEMETRY_GC_REASON, uint32_t(reason));
|
||||||
|
|
||||||
// Slice callbacks should only fire for the outermost level.
|
// Slice callbacks should only fire for the outermost level.
|
||||||
bool wasFullGC = zoneStats.isFullCollection();
|
bool wasFullGC = zoneStats.isFullCollection();
|
||||||
|
@ -1485,7 +1485,7 @@ void Statistics::printSliceProfile() {
|
||||||
bool full = zoneStats.isFullCollection();
|
bool full = zoneStats.isFullCollection();
|
||||||
|
|
||||||
fprintf(stderr, "MajorGC: %20s %1d -> %1d %1s%1s%1s%1s ",
|
fprintf(stderr, "MajorGC: %20s %1d -> %1d %1s%1s%1s%1s ",
|
||||||
ExplainReason(slice.reason), int(slice.initialState),
|
ExplainGCReason(slice.reason), int(slice.initialState),
|
||||||
int(slice.finalState), full ? "F" : "", shrinking ? "S" : "",
|
int(slice.finalState), full ? "F" : "", shrinking ? "S" : "",
|
||||||
nonIncremental ? "N" : "", reset ? "R" : "");
|
nonIncremental ? "N" : "", reset ? "R" : "");
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ struct Statistics {
|
||||||
void resumePhases();
|
void resumePhases();
|
||||||
|
|
||||||
void beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
void beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
||||||
SliceBudget budget, JS::gcreason::Reason reason);
|
SliceBudget budget, JS::GCReason reason);
|
||||||
void endSlice();
|
void endSlice();
|
||||||
|
|
||||||
MOZ_MUST_USE bool startTimingMutator();
|
MOZ_MUST_USE bool startTimingMutator();
|
||||||
|
@ -223,8 +223,8 @@ struct Statistics {
|
||||||
return &allocsSinceMinorGC.nursery;
|
return &allocsSinceMinorGC.nursery;
|
||||||
}
|
}
|
||||||
|
|
||||||
void beginNurseryCollection(JS::gcreason::Reason reason);
|
void beginNurseryCollection(JS::GCReason reason);
|
||||||
void endNurseryCollection(JS::gcreason::Reason reason);
|
void endNurseryCollection(JS::GCReason reason);
|
||||||
|
|
||||||
TimeStamp beginSCC();
|
TimeStamp beginSCC();
|
||||||
void endSCC(unsigned scc, TimeStamp start);
|
void endSCC(unsigned scc, TimeStamp start);
|
||||||
|
@ -245,7 +245,7 @@ struct Statistics {
|
||||||
static const size_t MAX_SUSPENDED_PHASES = MAX_PHASE_NESTING * 3;
|
static const size_t MAX_SUSPENDED_PHASES = MAX_PHASE_NESTING * 3;
|
||||||
|
|
||||||
struct SliceData {
|
struct SliceData {
|
||||||
SliceData(SliceBudget budget, JS::gcreason::Reason reason, TimeStamp start,
|
SliceData(SliceBudget budget, JS::GCReason reason, TimeStamp start,
|
||||||
size_t startFaults, gc::State initialState)
|
size_t startFaults, gc::State initialState)
|
||||||
: budget(budget),
|
: budget(budget),
|
||||||
reason(reason),
|
reason(reason),
|
||||||
|
@ -257,7 +257,7 @@ struct Statistics {
|
||||||
endFaults(0) {}
|
endFaults(0) {}
|
||||||
|
|
||||||
SliceBudget budget;
|
SliceBudget budget;
|
||||||
JS::gcreason::Reason reason;
|
JS::GCReason reason;
|
||||||
gc::State initialState, finalState;
|
gc::State initialState, finalState;
|
||||||
gc::AbortReason resetReason;
|
gc::AbortReason resetReason;
|
||||||
TimeStamp start, end;
|
TimeStamp start, end;
|
||||||
|
@ -457,7 +457,7 @@ struct Statistics {
|
||||||
struct MOZ_RAII AutoGCSlice {
|
struct MOZ_RAII AutoGCSlice {
|
||||||
AutoGCSlice(Statistics& stats, const ZoneGCStats& zoneStats,
|
AutoGCSlice(Statistics& stats, const ZoneGCStats& zoneStats,
|
||||||
JSGCInvocationKind gckind, SliceBudget budget,
|
JSGCInvocationKind gckind, SliceBudget budget,
|
||||||
JS::gcreason::Reason reason)
|
JS::GCReason reason)
|
||||||
: stats(stats) {
|
: stats(stats) {
|
||||||
stats.beginSlice(zoneStats, gckind, budget, reason);
|
stats.beginSlice(zoneStats, gckind, budget, reason);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ void StoreBuffer::clear() {
|
||||||
bufferGeneric.clear();
|
bufferGeneric.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StoreBuffer::setAboutToOverflow(JS::gcreason::Reason reason) {
|
void StoreBuffer::setAboutToOverflow(JS::GCReason reason) {
|
||||||
if (!aboutToOverflow_) {
|
if (!aboutToOverflow_) {
|
||||||
aboutToOverflow_ = true;
|
aboutToOverflow_ = true;
|
||||||
runtime_->gc.stats().count(gcstats::COUNT_STOREBUFFER_OVERFLOW);
|
runtime_->gc.stats().count(gcstats::COUNT_STOREBUFFER_OVERFLOW);
|
||||||
|
@ -132,7 +132,7 @@ ArenaCellSet* StoreBuffer::WholeCellBuffer::allocateCellSet(Arena* arena) {
|
||||||
|
|
||||||
if (isAboutToOverflow()) {
|
if (isAboutToOverflow()) {
|
||||||
rt->gc.storeBuffer().setAboutToOverflow(
|
rt->gc.storeBuffer().setAboutToOverflow(
|
||||||
JS::gcreason::FULL_WHOLE_CELL_BUFFER);
|
JS::GCReason::FULL_WHOLE_CELL_BUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cells;
|
return cells;
|
||||||
|
|
|
@ -237,7 +237,7 @@ class StoreBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAboutToOverflow()) {
|
if (isAboutToOverflow()) {
|
||||||
owner->setAboutToOverflow(JS::gcreason::FULL_GENERIC_BUFFER);
|
owner->setAboutToOverflow(JS::GCReason::FULL_GENERIC_BUFFER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ class StoreBuffer {
|
||||||
|
|
||||||
typedef PointerEdgeHasher<CellPtrEdge> Hasher;
|
typedef PointerEdgeHasher<CellPtrEdge> Hasher;
|
||||||
|
|
||||||
static const auto FullBufferReason = JS::gcreason::FULL_CELL_PTR_BUFFER;
|
static const auto FullBufferReason = JS::GCReason::FULL_CELL_PTR_BUFFER;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ValueEdge {
|
struct ValueEdge {
|
||||||
|
@ -327,7 +327,7 @@ class StoreBuffer {
|
||||||
|
|
||||||
typedef PointerEdgeHasher<ValueEdge> Hasher;
|
typedef PointerEdgeHasher<ValueEdge> Hasher;
|
||||||
|
|
||||||
static const auto FullBufferReason = JS::gcreason::FULL_VALUE_BUFFER;
|
static const auto FullBufferReason = JS::GCReason::FULL_VALUE_BUFFER;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SlotsEdge {
|
struct SlotsEdge {
|
||||||
|
@ -410,7 +410,7 @@ class StoreBuffer {
|
||||||
static bool match(const SlotsEdge& k, const Lookup& l) { return k == l; }
|
static bool match(const SlotsEdge& k, const Lookup& l) { return k == l; }
|
||||||
} Hasher;
|
} Hasher;
|
||||||
|
|
||||||
static const auto FullBufferReason = JS::gcreason::FULL_SLOT_BUFFER;
|
static const auto FullBufferReason = JS::GCReason::FULL_SLOT_BUFFER;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Buffer, typename Edge>
|
template <typename Buffer, typename Edge>
|
||||||
|
@ -520,7 +520,7 @@ class StoreBuffer {
|
||||||
void traceGenericEntries(JSTracer* trc) { bufferGeneric.trace(this, trc); }
|
void traceGenericEntries(JSTracer* trc) { bufferGeneric.trace(this, trc); }
|
||||||
|
|
||||||
/* For use by our owned buffers and for testing. */
|
/* For use by our owned buffers and for testing. */
|
||||||
void setAboutToOverflow(JS::gcreason::Reason);
|
void setAboutToOverflow(JS::GCReason);
|
||||||
|
|
||||||
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||||
JS::GCSizes* sizes);
|
JS::GCSizes* sizes);
|
||||||
|
|
|
@ -489,7 +489,7 @@ void JS::Zone::maybeTriggerGCForTooMuchMalloc(js::gc::MemoryCounter& counter,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC,
|
if (!rt->gc.triggerZoneGC(this, JS::GCReason::TOO_MUCH_MALLOC,
|
||||||
counter.bytes(), counter.maxBytes())) {
|
counter.bytes(), counter.maxBytes())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// |jit-test| error: ReferenceError
|
||||||
|
gczeal(0);
|
||||||
|
gcparam("markStackLimit", 1);
|
||||||
|
var g = newGlobal({
|
||||||
|
newCompartment: true
|
||||||
|
});
|
||||||
|
var dbg = new Debugger;
|
||||||
|
var gw = dbg.addDebuggee(g);
|
||||||
|
dbg.onDebuggerStatement = function(frame) {
|
||||||
|
frame.environment.parent.getVariable('y')
|
||||||
|
};
|
||||||
|
g.eval(`
|
||||||
|
let y = 1;
|
||||||
|
g = function () { debugger; };
|
||||||
|
g();
|
||||||
|
`);
|
||||||
|
gczeal(9, 10);
|
||||||
|
f4();
|
|
@ -245,7 +245,7 @@ void runTestFromPath(JSContext* cx, const char* path) {
|
||||||
// running everything from the same cx and without returning to JS, there
|
// running everything from the same cx and without returning to JS, there
|
||||||
// is nothing to deallocate the ASTs.
|
// is nothing to deallocate the ASTs.
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::NO_REASON);
|
cx->runtime()->gc.gc(GC_NORMAL, JS::GCReason::NO_REASON);
|
||||||
}
|
}
|
||||||
LifoAllocScope allocScope(&cx->tempLifoAlloc());
|
LifoAllocScope allocScope(&cx->tempLifoAlloc());
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace {
|
||||||
struct ErrorInterceptorWithGC : JSErrorInterceptor {
|
struct ErrorInterceptorWithGC : JSErrorInterceptor {
|
||||||
void interceptError(JSContext* cx, JS::HandleValue val) override {
|
void interceptError(JSContext* cx, JS::HandleValue val) override {
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
JS::NonIncrementalGC(cx, GC_SHRINK, JS::gcreason::DEBUG_GC);
|
JS::NonIncrementalGC(cx, GC_SHRINK, JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ BEGIN_TEST(testGCFinalizeCallback) {
|
||||||
/* Full GC, incremental. */
|
/* Full GC, incremental. */
|
||||||
FinalizeCalls = 0;
|
FinalizeCalls = 0;
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
JS::StartIncrementalGC(cx, GC_NORMAL, JS::gcreason::API, 1000000);
|
JS::StartIncrementalGC(cx, GC_NORMAL, JS::GCReason::API, 1000000);
|
||||||
while (cx->runtime()->gc.isIncrementalGCInProgress()) {
|
while (cx->runtime()->gc.isIncrementalGCInProgress()) {
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
JS::IncrementalGCSlice(cx, JS::gcreason::API, 1000000);
|
JS::IncrementalGCSlice(cx, JS::GCReason::API, 1000000);
|
||||||
}
|
}
|
||||||
CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
|
CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
|
||||||
CHECK(cx->runtime()->gc.isFullGc());
|
CHECK(cx->runtime()->gc.isFullGc());
|
||||||
|
@ -47,7 +47,7 @@ BEGIN_TEST(testGCFinalizeCallback) {
|
||||||
/* Zone GC, non-incremental, single zone. */
|
/* Zone GC, non-incremental, single zone. */
|
||||||
FinalizeCalls = 0;
|
FinalizeCalls = 0;
|
||||||
JS::PrepareZoneForGC(global1->zone());
|
JS::PrepareZoneForGC(global1->zone());
|
||||||
JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::API);
|
JS::NonIncrementalGC(cx, GC_NORMAL, JS::GCReason::API);
|
||||||
CHECK(!cx->runtime()->gc.isFullGc());
|
CHECK(!cx->runtime()->gc.isFullGc());
|
||||||
CHECK(checkSingleGroup());
|
CHECK(checkSingleGroup());
|
||||||
CHECK(checkFinalizeStatus());
|
CHECK(checkFinalizeStatus());
|
||||||
|
@ -57,7 +57,7 @@ BEGIN_TEST(testGCFinalizeCallback) {
|
||||||
JS::PrepareZoneForGC(global1->zone());
|
JS::PrepareZoneForGC(global1->zone());
|
||||||
JS::PrepareZoneForGC(global2->zone());
|
JS::PrepareZoneForGC(global2->zone());
|
||||||
JS::PrepareZoneForGC(global3->zone());
|
JS::PrepareZoneForGC(global3->zone());
|
||||||
JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::API);
|
JS::NonIncrementalGC(cx, GC_NORMAL, JS::GCReason::API);
|
||||||
CHECK(!cx->runtime()->gc.isFullGc());
|
CHECK(!cx->runtime()->gc.isFullGc());
|
||||||
CHECK(checkSingleGroup());
|
CHECK(checkSingleGroup());
|
||||||
CHECK(checkFinalizeStatus());
|
CHECK(checkFinalizeStatus());
|
||||||
|
@ -65,10 +65,10 @@ BEGIN_TEST(testGCFinalizeCallback) {
|
||||||
/* Zone GC, incremental, single zone. */
|
/* Zone GC, incremental, single zone. */
|
||||||
FinalizeCalls = 0;
|
FinalizeCalls = 0;
|
||||||
JS::PrepareZoneForGC(global1->zone());
|
JS::PrepareZoneForGC(global1->zone());
|
||||||
JS::StartIncrementalGC(cx, GC_NORMAL, JS::gcreason::API, 1000000);
|
JS::StartIncrementalGC(cx, GC_NORMAL, JS::GCReason::API, 1000000);
|
||||||
while (cx->runtime()->gc.isIncrementalGCInProgress()) {
|
while (cx->runtime()->gc.isIncrementalGCInProgress()) {
|
||||||
JS::PrepareZoneForGC(global1->zone());
|
JS::PrepareZoneForGC(global1->zone());
|
||||||
JS::IncrementalGCSlice(cx, JS::gcreason::API, 1000000);
|
JS::IncrementalGCSlice(cx, JS::GCReason::API, 1000000);
|
||||||
}
|
}
|
||||||
CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
|
CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
|
||||||
CHECK(!cx->runtime()->gc.isFullGc());
|
CHECK(!cx->runtime()->gc.isFullGc());
|
||||||
|
@ -80,12 +80,12 @@ BEGIN_TEST(testGCFinalizeCallback) {
|
||||||
JS::PrepareZoneForGC(global1->zone());
|
JS::PrepareZoneForGC(global1->zone());
|
||||||
JS::PrepareZoneForGC(global2->zone());
|
JS::PrepareZoneForGC(global2->zone());
|
||||||
JS::PrepareZoneForGC(global3->zone());
|
JS::PrepareZoneForGC(global3->zone());
|
||||||
JS::StartIncrementalGC(cx, GC_NORMAL, JS::gcreason::API, 1000000);
|
JS::StartIncrementalGC(cx, GC_NORMAL, JS::GCReason::API, 1000000);
|
||||||
while (cx->runtime()->gc.isIncrementalGCInProgress()) {
|
while (cx->runtime()->gc.isIncrementalGCInProgress()) {
|
||||||
JS::PrepareZoneForGC(global1->zone());
|
JS::PrepareZoneForGC(global1->zone());
|
||||||
JS::PrepareZoneForGC(global2->zone());
|
JS::PrepareZoneForGC(global2->zone());
|
||||||
JS::PrepareZoneForGC(global3->zone());
|
JS::PrepareZoneForGC(global3->zone());
|
||||||
JS::IncrementalGCSlice(cx, JS::gcreason::API, 1000000);
|
JS::IncrementalGCSlice(cx, JS::GCReason::API, 1000000);
|
||||||
}
|
}
|
||||||
CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
|
CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
|
||||||
CHECK(!cx->runtime()->gc.isFullGc());
|
CHECK(!cx->runtime()->gc.isFullGc());
|
||||||
|
|
|
@ -464,7 +464,7 @@ bool TestCCWs() {
|
||||||
CHECK(GetCrossCompartmentWrapper(target) == wrapper);
|
CHECK(GetCrossCompartmentWrapper(target) == wrapper);
|
||||||
CHECK(IsMarkedBlack(wrapper));
|
CHECK(IsMarkedBlack(wrapper));
|
||||||
|
|
||||||
JS::FinishIncrementalGC(cx, JS::gcreason::API);
|
JS::FinishIncrementalGC(cx, JS::GCReason::API);
|
||||||
|
|
||||||
// Test behaviour of gray CCWs marked black by a barrier during incremental
|
// Test behaviour of gray CCWs marked black by a barrier during incremental
|
||||||
// GC.
|
// GC.
|
||||||
|
@ -500,7 +500,7 @@ bool TestCCWs() {
|
||||||
CHECK(!JS::ObjectIsMarkedGray(target));
|
CHECK(!JS::ObjectIsMarkedGray(target));
|
||||||
|
|
||||||
// Final state: source and target are black.
|
// Final state: source and target are black.
|
||||||
JS::FinishIncrementalGC(cx, JS::gcreason::API);
|
JS::FinishIncrementalGC(cx, JS::GCReason::API);
|
||||||
CHECK(IsMarkedBlack(wrapper));
|
CHECK(IsMarkedBlack(wrapper));
|
||||||
CHECK(IsMarkedBlack(target));
|
CHECK(IsMarkedBlack(target));
|
||||||
|
|
||||||
|
@ -739,7 +739,7 @@ bool ZoneGC(JS::Zone* zone) {
|
||||||
uint32_t oldMode = JS_GetGCParameter(cx, JSGC_MODE);
|
uint32_t oldMode = JS_GetGCParameter(cx, JSGC_MODE);
|
||||||
JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_ZONE);
|
JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_ZONE);
|
||||||
JS::PrepareZoneForGC(zone);
|
JS::PrepareZoneForGC(zone);
|
||||||
cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::API);
|
cx->runtime()->gc.gc(GC_NORMAL, JS::GCReason::API);
|
||||||
CHECK(!cx->runtime()->gc.isFullGc());
|
CHECK(!cx->runtime()->gc.isFullGc());
|
||||||
JS_SetGCParameter(cx, JSGC_MODE, oldMode);
|
JS_SetGCParameter(cx, JSGC_MODE, oldMode);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -131,7 +131,7 @@ bool TestHeapPostBarrierUpdate() {
|
||||||
ptr = testStruct.release();
|
ptr = testStruct.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->minorGC(JS::gcreason::API);
|
cx->minorGC(JS::GCReason::API);
|
||||||
|
|
||||||
W& wrapper = ptr->wrapper;
|
W& wrapper = ptr->wrapper;
|
||||||
CHECK(uintptr_t(wrapper.get()) != initialObjAsInt);
|
CHECK(uintptr_t(wrapper.get()) != initialObjAsInt);
|
||||||
|
@ -140,7 +140,7 @@ bool TestHeapPostBarrierUpdate() {
|
||||||
|
|
||||||
JS::DeletePolicy<TestStruct<W>>()(ptr);
|
JS::DeletePolicy<TestStruct<W>>()(ptr);
|
||||||
|
|
||||||
cx->minorGC(JS::gcreason::API);
|
cx->minorGC(JS::GCReason::API);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ bool TestHeapPostBarrierInitFailure() {
|
||||||
// testStruct deleted here, as if we left this block due to an error.
|
// testStruct deleted here, as if we left this block due to an error.
|
||||||
}
|
}
|
||||||
|
|
||||||
cx->minorGC(JS::gcreason::API);
|
cx->minorGC(JS::GCReason::API);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ static void NonIncrementalGCSliceCallback(JSContext* cx,
|
||||||
MOZ_RELEASE_ASSERT(progress == expect[gSliceCallbackCount++]);
|
MOZ_RELEASE_ASSERT(progress == expect[gSliceCallbackCount++]);
|
||||||
MOZ_RELEASE_ASSERT(desc.isZone_ == false);
|
MOZ_RELEASE_ASSERT(desc.isZone_ == false);
|
||||||
MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL);
|
MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL);
|
||||||
MOZ_RELEASE_ASSERT(desc.reason_ == JS::gcreason::API);
|
MOZ_RELEASE_ASSERT(desc.reason_ == JS::GCReason::API);
|
||||||
if (progress == GC_CYCLE_END) {
|
if (progress == GC_CYCLE_END) {
|
||||||
mozilla::UniquePtr<char16_t> summary(desc.formatSummaryMessage(cx));
|
mozilla::UniquePtr<char16_t> summary(desc.formatSummaryMessage(cx));
|
||||||
mozilla::UniquePtr<char16_t> message(desc.formatSliceMessage(cx));
|
mozilla::UniquePtr<char16_t> message(desc.formatSliceMessage(cx));
|
||||||
|
@ -41,16 +41,17 @@ END_TEST(testGCSliceCallback)
|
||||||
static void RootsRemovedGCSliceCallback(JSContext* cx, JS::GCProgress progress,
|
static void RootsRemovedGCSliceCallback(JSContext* cx, JS::GCProgress progress,
|
||||||
const JS::GCDescription& desc) {
|
const JS::GCDescription& desc) {
|
||||||
using namespace JS;
|
using namespace JS;
|
||||||
using namespace JS::gcreason;
|
|
||||||
|
|
||||||
static GCProgress expectProgress[] = {
|
static GCProgress expectProgress[] = {
|
||||||
GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END, GC_SLICE_BEGIN,
|
GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END, GC_SLICE_BEGIN,
|
||||||
GC_SLICE_END, GC_CYCLE_END, GC_CYCLE_BEGIN, GC_SLICE_BEGIN,
|
GC_SLICE_END, GC_CYCLE_END, GC_CYCLE_BEGIN, GC_SLICE_BEGIN,
|
||||||
GC_SLICE_END, GC_CYCLE_END};
|
GC_SLICE_END, GC_CYCLE_END};
|
||||||
|
|
||||||
static Reason expectReasons[] = {
|
static GCReason expectReasons[] = {
|
||||||
DEBUG_GC, DEBUG_GC, DEBUG_GC, DEBUG_GC, DEBUG_GC,
|
GCReason::DEBUG_GC, GCReason::DEBUG_GC, GCReason::DEBUG_GC,
|
||||||
DEBUG_GC, ROOTS_REMOVED, ROOTS_REMOVED, ROOTS_REMOVED, ROOTS_REMOVED};
|
GCReason::DEBUG_GC, GCReason::DEBUG_GC, GCReason::DEBUG_GC,
|
||||||
|
GCReason::ROOTS_REMOVED, GCReason::ROOTS_REMOVED, GCReason::ROOTS_REMOVED,
|
||||||
|
GCReason::ROOTS_REMOVED};
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
mozilla::ArrayLength(expectProgress) ==
|
mozilla::ArrayLength(expectProgress) ==
|
||||||
|
@ -87,7 +88,7 @@ BEGIN_TEST(testGCRootsRemoved) {
|
||||||
// Trigger another GC after the current one in shrinking / shutdown GCs.
|
// Trigger another GC after the current one in shrinking / shutdown GCs.
|
||||||
cx->runtime()->gc.notifyRootsRemoved();
|
cx->runtime()->gc.notifyRootsRemoved();
|
||||||
|
|
||||||
JS::FinishIncrementalGC(cx, JS::gcreason::DEBUG_GC);
|
JS::FinishIncrementalGC(cx, JS::GCReason::DEBUG_GC);
|
||||||
CHECK(!JS::IsIncrementalGCInProgress(cx));
|
CHECK(!JS::IsIncrementalGCInProgress(cx));
|
||||||
|
|
||||||
JS::SetGCSliceCallback(cx, nullptr);
|
JS::SetGCSliceCallback(cx, nullptr);
|
||||||
|
|
|
@ -341,7 +341,7 @@ BEGIN_TEST(testIncrementalRoots) {
|
||||||
|
|
||||||
// Tenure everything so intentionally unrooted objects don't move before we
|
// Tenure everything so intentionally unrooted objects don't move before we
|
||||||
// can use them.
|
// can use them.
|
||||||
cx->runtime()->gc.minorGC(JS::gcreason::API);
|
cx->runtime()->gc.minorGC(JS::GCReason::API);
|
||||||
|
|
||||||
// Release all roots except for the AutoObjectVector.
|
// Release all roots except for the AutoObjectVector.
|
||||||
obj = root = nullptr;
|
obj = root = nullptr;
|
||||||
|
|
|
@ -110,7 +110,7 @@ BEGIN_TEST(testGCUID) {
|
||||||
// Force a compaction to move the object and check that the uid moved to
|
// Force a compaction to move the object and check that the uid moved to
|
||||||
// the new tenured heap location.
|
// the new tenured heap location.
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
JS::NonIncrementalGC(cx, GC_SHRINK, JS::gcreason::API);
|
JS::NonIncrementalGC(cx, GC_SHRINK, JS::GCReason::API);
|
||||||
|
|
||||||
// There's a very low probability that this check could fail, but it is
|
// There's a very low probability that this check could fail, but it is
|
||||||
// possible. If it becomes an annoying intermittent then we should make
|
// possible. If it becomes an annoying intermittent then we should make
|
||||||
|
|
|
@ -249,7 +249,7 @@ bool SweepCacheAndFinishGC(JSContext* cx, const Cache& cache) {
|
||||||
CHECK(IsIncrementalGCInProgress(cx));
|
CHECK(IsIncrementalGCInProgress(cx));
|
||||||
|
|
||||||
PrepareForIncrementalGC(cx);
|
PrepareForIncrementalGC(cx);
|
||||||
IncrementalGCSlice(cx, JS::gcreason::API);
|
IncrementalGCSlice(cx, JS::GCReason::API);
|
||||||
|
|
||||||
JS::Zone* zone = JS::GetObjectZone(global);
|
JS::Zone* zone = JS::GetObjectZone(global);
|
||||||
CHECK(!IsIncrementalGCInProgress(cx));
|
CHECK(!IsIncrementalGCInProgress(cx));
|
||||||
|
|
|
@ -28,7 +28,7 @@ BEGIN_TEST(testGCWeakRef) {
|
||||||
JS::Rooted<MyHeap> heap(cx, MyHeap(obj));
|
JS::Rooted<MyHeap> heap(cx, MyHeap(obj));
|
||||||
obj = nullptr;
|
obj = nullptr;
|
||||||
|
|
||||||
cx->runtime()->gc.minorGC(JS::gcreason::API);
|
cx->runtime()->gc.minorGC(JS::GCReason::API);
|
||||||
|
|
||||||
// The minor collection should have treated the weak ref as a strong ref,
|
// The minor collection should have treated the weak ref as a strong ref,
|
||||||
// so the object should still be live, despite not having any other live
|
// so the object should still be live, despite not having any other live
|
||||||
|
|
|
@ -75,10 +75,10 @@ bool testPreserveJitCode(bool preserveJitCode, unsigned remainingIonScripts) {
|
||||||
CHECK_EQUAL(value.toInt32(), 45);
|
CHECK_EQUAL(value.toInt32(), 45);
|
||||||
CHECK_EQUAL(countIonScripts(global), 1u);
|
CHECK_EQUAL(countIonScripts(global), 1u);
|
||||||
|
|
||||||
NonIncrementalGC(cx, GC_NORMAL, gcreason::API);
|
NonIncrementalGC(cx, GC_NORMAL, GCReason::API);
|
||||||
CHECK_EQUAL(countIonScripts(global), remainingIonScripts);
|
CHECK_EQUAL(countIonScripts(global), remainingIonScripts);
|
||||||
|
|
||||||
NonIncrementalGC(cx, GC_SHRINK, gcreason::API);
|
NonIncrementalGC(cx, GC_SHRINK, GCReason::API);
|
||||||
CHECK_EQUAL(countIonScripts(global), 0u);
|
CHECK_EQUAL(countIonScripts(global), 0u);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -498,7 +498,7 @@ class AutoLeaveZeal {
|
||||||
JS_GetGCZealBits(cx_, &zealBits_, &frequency_, &dummy);
|
JS_GetGCZealBits(cx_, &zealBits_, &frequency_, &dummy);
|
||||||
JS_SetGCZeal(cx_, 0, 0);
|
JS_SetGCZeal(cx_, 0, 0);
|
||||||
JS::PrepareForFullGC(cx_);
|
JS::PrepareForFullGC(cx_);
|
||||||
JS::NonIncrementalGC(cx_, GC_SHRINK, JS::gcreason::DEBUG_GC);
|
JS::NonIncrementalGC(cx_, GC_SHRINK, JS::GCReason::DEBUG_GC);
|
||||||
}
|
}
|
||||||
~AutoLeaveZeal() {
|
~AutoLeaveZeal() {
|
||||||
JS_SetGCZeal(cx_, 0, 0);
|
JS_SetGCZeal(cx_, 0, 0);
|
||||||
|
|
|
@ -1167,14 +1167,14 @@ JS_PUBLIC_API bool JS::IsIdleGCTaskNeeded(JSRuntime* rt) {
|
||||||
JS_PUBLIC_API void JS::RunIdleTimeGCTask(JSRuntime* rt) {
|
JS_PUBLIC_API void JS::RunIdleTimeGCTask(JSRuntime* rt) {
|
||||||
gc::GCRuntime& gc = rt->gc;
|
gc::GCRuntime& gc = rt->gc;
|
||||||
if (gc.nursery().needIdleTimeCollection()) {
|
if (gc.nursery().needIdleTimeCollection()) {
|
||||||
gc.minorGC(JS::gcreason::IDLE_TIME_COLLECTION);
|
gc.minorGC(JS::GCReason::IDLE_TIME_COLLECTION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API void JS_GC(JSContext* cx) {
|
JS_PUBLIC_API void JS_GC(JSContext* cx) {
|
||||||
AssertHeapIsIdle();
|
AssertHeapIsIdle();
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::API);
|
cx->runtime()->gc.gc(GC_NORMAL, JS::GCReason::API);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API void JS_MaybeGC(JSContext* cx) {
|
JS_PUBLIC_API void JS_MaybeGC(JSContext* cx) {
|
||||||
|
|
|
@ -1118,7 +1118,7 @@ void DumpHeapTracer::onChild(const JS::GCCellPtr& thing) {
|
||||||
void js::DumpHeap(JSContext* cx, FILE* fp,
|
void js::DumpHeap(JSContext* cx, FILE* fp,
|
||||||
js::DumpHeapNurseryBehaviour nurseryBehaviour) {
|
js::DumpHeapNurseryBehaviour nurseryBehaviour) {
|
||||||
if (nurseryBehaviour == js::CollectNurseryBeforeDump) {
|
if (nurseryBehaviour == js::CollectNurseryBeforeDump) {
|
||||||
cx->runtime()->gc.evictNursery(JS::gcreason::API);
|
cx->runtime()->gc.evictNursery(JS::GCReason::API);
|
||||||
}
|
}
|
||||||
|
|
||||||
DumpHeapTracer dtrc(fp, cx);
|
DumpHeapTracer dtrc(fp, cx);
|
||||||
|
|
|
@ -1840,7 +1840,7 @@ static void my_LargeAllocFailCallback() {
|
||||||
MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
|
MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
|
||||||
|
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::SHARED_MEMORY_LIMIT);
|
cx->runtime()->gc.gc(GC_NORMAL, JS::GCReason::SHARED_MEMORY_LIMIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t CacheEntry_SOURCE = 0;
|
static const uint32_t CacheEntry_SOURCE = 0;
|
||||||
|
|
|
@ -846,12 +846,12 @@ static bool CreateBuffer(
|
||||||
// See MaximumLiveMappedBuffers comment above.
|
// See MaximumLiveMappedBuffers comment above.
|
||||||
if (liveBufferCount > StartSyncFullGCAtLiveBufferCount) {
|
if (liveBufferCount > StartSyncFullGCAtLiveBufferCount) {
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::TOO_MUCH_WASM_MEMORY);
|
JS::NonIncrementalGC(cx, GC_NORMAL, JS::GCReason::TOO_MUCH_WASM_MEMORY);
|
||||||
allocatedSinceLastTrigger = 0;
|
allocatedSinceLastTrigger = 0;
|
||||||
} else if (liveBufferCount > StartTriggeringAtLiveBufferCount) {
|
} else if (liveBufferCount > StartTriggeringAtLiveBufferCount) {
|
||||||
allocatedSinceLastTrigger++;
|
allocatedSinceLastTrigger++;
|
||||||
if (allocatedSinceLastTrigger > AllocatedBuffersPerTrigger) {
|
if (allocatedSinceLastTrigger > AllocatedBuffersPerTrigger) {
|
||||||
Unused << cx->runtime()->gc.triggerGC(JS::gcreason::TOO_MUCH_WASM_MEMORY);
|
Unused << cx->runtime()->gc.triggerGC(JS::GCReason::TOO_MUCH_WASM_MEMORY);
|
||||||
allocatedSinceLastTrigger = 0;
|
allocatedSinceLastTrigger = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12395,7 +12395,7 @@ namespace dbg {
|
||||||
// reasons this data is stored and replicated on each slice. Each
|
// reasons this data is stored and replicated on each slice. Each
|
||||||
// slice used to have its own GCReason, but now they are all the
|
// slice used to have its own GCReason, but now they are all the
|
||||||
// same.
|
// same.
|
||||||
data->reason = gcreason::ExplainReason(slice.reason);
|
data->reason = ExplainGCReason(slice.reason);
|
||||||
MOZ_ASSERT(data->reason);
|
MOZ_ASSERT(data->reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -305,7 +305,7 @@ inline js::LifoAlloc& JSContext::typeLifoAlloc() {
|
||||||
|
|
||||||
inline js::Nursery& JSContext::nursery() { return runtime()->gc.nursery(); }
|
inline js::Nursery& JSContext::nursery() { return runtime()->gc.nursery(); }
|
||||||
|
|
||||||
inline void JSContext::minorGC(JS::gcreason::Reason reason) {
|
inline void JSContext::minorGC(JS::GCReason reason) {
|
||||||
runtime()->gc.minorGC(reason);
|
runtime()->gc.minorGC(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -740,7 +740,7 @@ struct JSContext : public JS::RootingContext,
|
||||||
AllowCrossRealm allowCrossRealm = AllowCrossRealm::DontAllow) const;
|
AllowCrossRealm allowCrossRealm = AllowCrossRealm::DontAllow) const;
|
||||||
|
|
||||||
inline js::Nursery& nursery();
|
inline js::Nursery& nursery();
|
||||||
inline void minorGC(JS::gcreason::Reason reason);
|
inline void minorGC(JS::GCReason reason);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool isExceptionPending() const { return throwing; }
|
bool isExceptionPending() const { return throwing; }
|
||||||
|
|
|
@ -4202,6 +4202,10 @@ void JSObject::traceChildren(JSTracer* trc) {
|
||||||
if (clasp->hasTrace()) {
|
if (clasp->hasTrace()) {
|
||||||
clasp->doTrace(trc, this);
|
clasp->doTrace(trc, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trc->isMarkingTracer()) {
|
||||||
|
GCMarker::fromTracer(trc)->markImplicitEdges(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSAtom* displayAtomFromObjectGroup(ObjectGroup& group) {
|
static JSAtom* displayAtomFromObjectGroup(ObjectGroup& group) {
|
||||||
|
|
|
@ -4411,7 +4411,7 @@ void JSScript::traceChildren(JSTracer* trc) {
|
||||||
jit::TraceJitScripts(trc, this);
|
jit::TraceJitScripts(trc, this);
|
||||||
|
|
||||||
if (trc->isMarkingTracer()) {
|
if (trc->isMarkingTracer()) {
|
||||||
return GCMarker::fromTracer(trc)->markImplicitEdges(this);
|
GCMarker::fromTracer(trc)->markImplicitEdges(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -280,7 +280,7 @@ void JSRuntime::destroyRuntime() {
|
||||||
profilingScripts = false;
|
profilingScripts = false;
|
||||||
|
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
gc.gc(GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
|
gc.gc(GC_NORMAL, JS::GCReason::DESTROY_RUNTIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoNoteSingleThreadedRegion anstr;
|
AutoNoteSingleThreadedRegion anstr;
|
||||||
|
|
|
@ -151,7 +151,7 @@ static inline void GetterSetterWriteBarrierPost(AccessorShape* shape) {
|
||||||
if (nurseryShapes.length() == 1) {
|
if (nurseryShapes.length() == 1) {
|
||||||
sb->putGeneric(NurseryShapesRef(shape->zone()));
|
sb->putGeneric(NurseryShapesRef(shape->zone()));
|
||||||
} else if (nurseryShapes.length() == MaxShapeVectorLength) {
|
} else if (nurseryShapes.length() == MaxShapeVectorLength) {
|
||||||
sb->setAboutToOverflow(JS::gcreason::FULL_SHAPE_BUFFER);
|
sb->setAboutToOverflow(JS::GCReason::FULL_SHAPE_BUFFER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1637,7 +1637,7 @@ NS_IMETHODIMP
|
||||||
nsXPCComponents_Utils::ForceGC() {
|
nsXPCComponents_Utils::ForceGC() {
|
||||||
JSContext* cx = XPCJSContext::Get()->Context();
|
JSContext* cx = XPCJSContext::Get()->Context();
|
||||||
PrepareForFullGC(cx);
|
PrepareForFullGC(cx);
|
||||||
NonIncrementalGC(cx, GC_NORMAL, gcreason::COMPONENT_UTILS);
|
NonIncrementalGC(cx, GC_NORMAL, GCReason::COMPONENT_UTILS);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1683,7 +1683,7 @@ NS_IMETHODIMP
|
||||||
nsXPCComponents_Utils::ForceShrinkingGC() {
|
nsXPCComponents_Utils::ForceShrinkingGC() {
|
||||||
JSContext* cx = dom::danger::GetJSContext();
|
JSContext* cx = dom::danger::GetJSContext();
|
||||||
PrepareForFullGC(cx);
|
PrepareForFullGC(cx);
|
||||||
NonIncrementalGC(cx, GC_SHRINK, gcreason::COMPONENT_UTILS);
|
NonIncrementalGC(cx, GC_SHRINK, GCReason::COMPONENT_UTILS);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1696,7 +1696,7 @@ class PreciseGCRunnable : public Runnable {
|
||||||
|
|
||||||
NS_IMETHOD Run() override {
|
NS_IMETHOD Run() override {
|
||||||
nsJSContext::GarbageCollectNow(
|
nsJSContext::GarbageCollectNow(
|
||||||
gcreason::COMPONENT_UTILS, nsJSContext::NonIncrementalGC,
|
GCReason::COMPONENT_UTILS, nsJSContext::NonIncrementalGC,
|
||||||
mShrinking ? nsJSContext::ShrinkingGC : nsJSContext::NonShrinkingGC);
|
mShrinking ? nsJSContext::ShrinkingGC : nsJSContext::NonShrinkingGC);
|
||||||
|
|
||||||
mCallback->Callback();
|
mCallback->Callback();
|
||||||
|
|
|
@ -91,7 +91,7 @@ nsXPConnect::~nsXPConnect() {
|
||||||
// XPConnect, to clean the stuff we forcibly disconnected. The forced
|
// XPConnect, to clean the stuff we forcibly disconnected. The forced
|
||||||
// shutdown code defaults to leaking in a number of situations, so we can't
|
// shutdown code defaults to leaking in a number of situations, so we can't
|
||||||
// get by with only the second GC. :-(
|
// get by with only the second GC. :-(
|
||||||
mRuntime->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
|
mRuntime->GarbageCollect(JS::GCReason::XPCONNECT_SHUTDOWN);
|
||||||
|
|
||||||
mShuttingDown = true;
|
mShuttingDown = true;
|
||||||
XPCWrappedNativeScope::SystemIsBeingShutDown();
|
XPCWrappedNativeScope::SystemIsBeingShutDown();
|
||||||
|
@ -101,7 +101,7 @@ nsXPConnect::~nsXPConnect() {
|
||||||
// after which point we need to GC to clean everything up. We need to do
|
// after which point we need to GC to clean everything up. We need to do
|
||||||
// this before deleting the XPCJSContext, because doing so destroys the
|
// this before deleting the XPCJSContext, because doing so destroys the
|
||||||
// maps that our finalize callback depends on.
|
// maps that our finalize callback depends on.
|
||||||
mRuntime->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
|
mRuntime->GarbageCollect(JS::GCReason::XPCONNECT_SHUTDOWN);
|
||||||
|
|
||||||
NS_RELEASE(gSystemPrincipal);
|
NS_RELEASE(gSystemPrincipal);
|
||||||
gScriptSecurityManager = nullptr;
|
gScriptSecurityManager = nullptr;
|
||||||
|
|
|
@ -1156,7 +1156,7 @@ nsDocumentViewer::LoadComplete(nsresult aStatus) {
|
||||||
|
|
||||||
// It's probably a good idea to GC soon since we have finished loading.
|
// It's probably a good idea to GC soon since we have finished loading.
|
||||||
nsJSContext::PokeGC(
|
nsJSContext::PokeGC(
|
||||||
JS::gcreason::LOAD_END,
|
JS::GCReason::LOAD_END,
|
||||||
mDocument ? mDocument->GetWrapperPreserveColor() : nullptr);
|
mDocument ? mDocument->GetWrapperPreserveColor() : nullptr);
|
||||||
|
|
||||||
#ifdef NS_PRINTING
|
#ifdef NS_PRINTING
|
||||||
|
@ -1412,7 +1412,7 @@ nsDocumentViewer::PageHide(bool aIsUnload) {
|
||||||
|
|
||||||
if (aIsUnload) {
|
if (aIsUnload) {
|
||||||
// Poke the GC. The window might be collectable garbage now.
|
// Poke the GC. The window might be collectable garbage now.
|
||||||
nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE,
|
nsJSContext::PokeGC(JS::GCReason::PAGE_HIDE,
|
||||||
mDocument->GetWrapperPreserveColor(), NS_GC_DELAY * 2);
|
mDocument->GetWrapperPreserveColor(), NS_GC_DELAY * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2361,7 +2361,7 @@ UniquePtr<ServoStyleSet> nsDocumentViewer::CreateStyleSet(Document* aDocument) {
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDocumentViewer::ClearHistoryEntry() {
|
nsDocumentViewer::ClearHistoryEntry() {
|
||||||
if (mDocument) {
|
if (mDocument) {
|
||||||
nsJSContext::PokeGC(JS::gcreason::PAGE_HIDE,
|
nsJSContext::PokeGC(JS::GCReason::PAGE_HIDE,
|
||||||
mDocument->GetWrapperPreserveColor(), NS_GC_DELAY * 2);
|
mDocument->GetWrapperPreserveColor(), NS_GC_DELAY * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -561,7 +561,7 @@ VARCACHE_PREF(
|
||||||
VARCACHE_PREF(
|
VARCACHE_PREF(
|
||||||
"html5.flushtimer.initialdelay",
|
"html5.flushtimer.initialdelay",
|
||||||
html5_flushtimer_initialdelay,
|
html5_flushtimer_initialdelay,
|
||||||
RelaxedAtomicInt32, 120
|
RelaxedAtomicInt32, 16
|
||||||
)
|
)
|
||||||
|
|
||||||
// Time in milliseconds between the time a network buffer is seen and the timer
|
// Time in milliseconds between the time a network buffer is seen and the timer
|
||||||
|
@ -569,7 +569,7 @@ VARCACHE_PREF(
|
||||||
VARCACHE_PREF(
|
VARCACHE_PREF(
|
||||||
"html5.flushtimer.subsequentdelay",
|
"html5.flushtimer.subsequentdelay",
|
||||||
html5_flushtimer_subsequentdelay,
|
html5_flushtimer_subsequentdelay,
|
||||||
RelaxedAtomicInt32, 120
|
RelaxedAtomicInt32, 16
|
||||||
)
|
)
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -863,7 +863,7 @@ class MaybeRunCollector : public Runnable {
|
||||||
|
|
||||||
NS_IMETHOD Run() override {
|
NS_IMETHOD Run() override {
|
||||||
nsJSContext::MaybeRunNextCollectorSlice(mDocShell,
|
nsJSContext::MaybeRunNextCollectorSlice(mDocShell,
|
||||||
JS::gcreason::HTML_PARSER);
|
JS::GCReason::HTML_PARSER);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -547,7 +547,7 @@ the histogram."""
|
||||||
if not self._strict_type_checks:
|
if not self._strict_type_checks:
|
||||||
# This handles some old non-numeric expressions.
|
# This handles some old non-numeric expressions.
|
||||||
EXPRESSIONS = {
|
EXPRESSIONS = {
|
||||||
"JS::gcreason::NUM_TELEMETRY_REASONS": 101,
|
"JS::GCReason::NUM_TELEMETRY_REASONS": 101,
|
||||||
"mozilla::StartupTimeline::MAX_EVENT_ID": 12,
|
"mozilla::StartupTimeline::MAX_EVENT_ID": 12,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2342,11 +2342,11 @@ void TelemetryHistogram::InitializeGlobalState(bool canRecordBase,
|
||||||
// We add static asserts here for those values to match so that future changes
|
// We add static asserts here for those values to match so that future changes
|
||||||
// don't go unnoticed.
|
// don't go unnoticed.
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static_assert((JS::gcreason::NUM_TELEMETRY_REASONS + 1) ==
|
static_assert((uint32_t(JS::GCReason::NUM_TELEMETRY_REASONS) + 1) ==
|
||||||
gHistogramInfos[mozilla::Telemetry::GC_MINOR_REASON].bucketCount &&
|
gHistogramInfos[mozilla::Telemetry::GC_MINOR_REASON].bucketCount &&
|
||||||
(JS::gcreason::NUM_TELEMETRY_REASONS + 1) ==
|
(uint32_t(JS::GCReason::NUM_TELEMETRY_REASONS) + 1) ==
|
||||||
gHistogramInfos[mozilla::Telemetry::GC_MINOR_REASON_LONG].bucketCount &&
|
gHistogramInfos[mozilla::Telemetry::GC_MINOR_REASON_LONG].bucketCount &&
|
||||||
(JS::gcreason::NUM_TELEMETRY_REASONS + 1) ==
|
(uint32_t(JS::GCReason::NUM_TELEMETRY_REASONS) + 1) ==
|
||||||
gHistogramInfos[mozilla::Telemetry::GC_REASON_2].bucketCount,
|
gHistogramInfos[mozilla::Telemetry::GC_REASON_2].bucketCount,
|
||||||
"NUM_TELEMETRY_REASONS is assumed to be a fixed value in Histograms.json."
|
"NUM_TELEMETRY_REASONS is assumed to be a fixed value in Histograms.json."
|
||||||
" If this was an intentional change, update the n_values for the "
|
" If this was an intentional change, update the n_values for the "
|
||||||
|
|
|
@ -52,7 +52,7 @@ class TestParser(unittest.TestCase):
|
||||||
"TEST_NON_NUMERIC_HISTOGRAM": {
|
"TEST_NON_NUMERIC_HISTOGRAM": {
|
||||||
"kind": "linear",
|
"kind": "linear",
|
||||||
"description": "sample",
|
"description": "sample",
|
||||||
"n_buckets": "JS::gcreason::NUM_TELEMETRY_REASONS",
|
"n_buckets": "JS::GCReason::NUM_TELEMETRY_REASONS",
|
||||||
"high": "mozilla::StartupTimeline::MAX_EVENT_ID"
|
"high": "mozilla::StartupTimeline::MAX_EVENT_ID"
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
|
@ -814,12 +814,12 @@ void CycleCollectedJSRuntime::TraverseNativeRoots(
|
||||||
|
|
||||||
if (aProgress == JS::GC_CYCLE_END &&
|
if (aProgress == JS::GC_CYCLE_END &&
|
||||||
JS::dbg::FireOnGarbageCollectionHookRequired(aContext)) {
|
JS::dbg::FireOnGarbageCollectionHookRequired(aContext)) {
|
||||||
JS::gcreason::Reason reason = aDesc.reason_;
|
JS::GCReason reason = aDesc.reason_;
|
||||||
Unused << NS_WARN_IF(
|
Unused << NS_WARN_IF(
|
||||||
NS_FAILED(DebuggerOnGCRunnable::Enqueue(aContext, aDesc)) &&
|
NS_FAILED(DebuggerOnGCRunnable::Enqueue(aContext, aDesc)) &&
|
||||||
reason != JS::gcreason::SHUTDOWN_CC &&
|
reason != JS::GCReason::SHUTDOWN_CC &&
|
||||||
reason != JS::gcreason::DESTROY_RUNTIME &&
|
reason != JS::GCReason::DESTROY_RUNTIME &&
|
||||||
reason != JS::gcreason::XPCONNECT_SHUTDOWN);
|
reason != JS::GCReason::XPCONNECT_SHUTDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->mPrevGCSliceCallback) {
|
if (self->mPrevGCSliceCallback) {
|
||||||
|
@ -829,17 +829,17 @@ void CycleCollectedJSRuntime::TraverseNativeRoots(
|
||||||
|
|
||||||
class MinorGCMarker : public TimelineMarker {
|
class MinorGCMarker : public TimelineMarker {
|
||||||
private:
|
private:
|
||||||
JS::gcreason::Reason mReason;
|
JS::GCReason mReason;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MinorGCMarker(MarkerTracingType aTracingType, JS::gcreason::Reason aReason)
|
MinorGCMarker(MarkerTracingType aTracingType, JS::GCReason aReason)
|
||||||
: TimelineMarker("MinorGC", aTracingType, MarkerStackRequest::NO_STACK),
|
: TimelineMarker("MinorGC", aTracingType, MarkerStackRequest::NO_STACK),
|
||||||
mReason(aReason) {
|
mReason(aReason) {
|
||||||
MOZ_ASSERT(aTracingType == MarkerTracingType::START ||
|
MOZ_ASSERT(aTracingType == MarkerTracingType::START ||
|
||||||
aTracingType == MarkerTracingType::END);
|
aTracingType == MarkerTracingType::END);
|
||||||
}
|
}
|
||||||
|
|
||||||
MinorGCMarker(JS::GCNurseryProgress aProgress, JS::gcreason::Reason aReason)
|
MinorGCMarker(JS::GCNurseryProgress aProgress, JS::GCReason aReason)
|
||||||
: TimelineMarker(
|
: TimelineMarker(
|
||||||
"MinorGC",
|
"MinorGC",
|
||||||
aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_START
|
aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_START
|
||||||
|
@ -853,7 +853,7 @@ class MinorGCMarker : public TimelineMarker {
|
||||||
TimelineMarker::AddDetails(aCx, aMarker);
|
TimelineMarker::AddDetails(aCx, aMarker);
|
||||||
|
|
||||||
if (GetTracingType() == MarkerTracingType::START) {
|
if (GetTracingType() == MarkerTracingType::START) {
|
||||||
auto reason = JS::gcreason::ExplainReason(mReason);
|
auto reason = JS::ExplainGCReason(mReason);
|
||||||
aMarker.mCauseName.Construct(NS_ConvertUTF8toUTF16(reason));
|
aMarker.mCauseName.Construct(NS_ConvertUTF8toUTF16(reason));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -867,7 +867,7 @@ class MinorGCMarker : public TimelineMarker {
|
||||||
|
|
||||||
/* static */ void CycleCollectedJSRuntime::GCNurseryCollectionCallback(
|
/* static */ void CycleCollectedJSRuntime::GCNurseryCollectionCallback(
|
||||||
JSContext* aContext, JS::GCNurseryProgress aProgress,
|
JSContext* aContext, JS::GCNurseryProgress aProgress,
|
||||||
JS::gcreason::Reason aReason) {
|
JS::GCReason aReason) {
|
||||||
CycleCollectedJSRuntime* self = CycleCollectedJSRuntime::Get();
|
CycleCollectedJSRuntime* self = CycleCollectedJSRuntime::Get();
|
||||||
MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext);
|
MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext);
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
@ -1125,13 +1125,10 @@ bool CycleCollectedJSRuntime::AreGCGrayBitsValid() const {
|
||||||
return js::AreGCGrayBitsValid(mJSRuntime);
|
return js::AreGCGrayBitsValid(mJSRuntime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CycleCollectedJSRuntime::GarbageCollect(uint32_t aReason) const {
|
void CycleCollectedJSRuntime::GarbageCollect(JS::GCReason aReason) const {
|
||||||
MOZ_ASSERT(aReason < JS::gcreason::NUM_REASONS);
|
|
||||||
JS::gcreason::Reason gcreason = static_cast<JS::gcreason::Reason>(aReason);
|
|
||||||
|
|
||||||
JSContext* cx = CycleCollectedJSContext::Get()->Context();
|
JSContext* cx = CycleCollectedJSContext::Get()->Context();
|
||||||
JS::PrepareForFullGC(cx);
|
JS::PrepareForFullGC(cx);
|
||||||
JS::NonIncrementalGC(cx, GC_NORMAL, gcreason);
|
JS::NonIncrementalGC(cx, GC_NORMAL, aReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CycleCollectedJSRuntime::JSObjectsTenured() {
|
void CycleCollectedJSRuntime::JSObjectsTenured() {
|
||||||
|
|
|
@ -157,7 +157,7 @@ class CycleCollectedJSRuntime {
|
||||||
const JS::GCDescription& aDesc);
|
const JS::GCDescription& aDesc);
|
||||||
static void GCNurseryCollectionCallback(JSContext* aContext,
|
static void GCNurseryCollectionCallback(JSContext* aContext,
|
||||||
JS::GCNurseryProgress aProgress,
|
JS::GCNurseryProgress aProgress,
|
||||||
JS::gcreason::Reason aReason);
|
JS::GCReason aReason);
|
||||||
static void OutOfMemoryCallback(JSContext* aContext, void* aData);
|
static void OutOfMemoryCallback(JSContext* aContext, void* aData);
|
||||||
/**
|
/**
|
||||||
* Callback for reporting external string memory.
|
* Callback for reporting external string memory.
|
||||||
|
@ -264,7 +264,7 @@ class CycleCollectedJSRuntime {
|
||||||
void FixWeakMappingGrayBits() const;
|
void FixWeakMappingGrayBits() const;
|
||||||
void CheckGrayBits() const;
|
void CheckGrayBits() const;
|
||||||
bool AreGCGrayBitsValid() const;
|
bool AreGCGrayBitsValid() const;
|
||||||
void GarbageCollect(uint32_t aReason) const;
|
void GarbageCollect(JS::GCReason aReason) const;
|
||||||
|
|
||||||
// This needs to be an nsWrapperCache, not a JSObject, because we need to know
|
// This needs to be an nsWrapperCache, not a JSObject, because we need to know
|
||||||
// when our object gets moved. But we can't trace it (and hence update our
|
// when our object gets moved. But we can't trace it (and hence update our
|
||||||
|
|
|
@ -3272,8 +3272,8 @@ void nsCycleCollector::FixGrayBits(bool aForceGC, TimeLog& aTimeLog) {
|
||||||
|
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
do {
|
do {
|
||||||
mCCJSRuntime->GarbageCollect(aForceGC ? JS::gcreason::SHUTDOWN_CC
|
mCCJSRuntime->GarbageCollect(aForceGC ? JS::GCReason::SHUTDOWN_CC
|
||||||
: JS::gcreason::CC_FORCED);
|
: JS::GCReason::CC_FORCED);
|
||||||
|
|
||||||
mCCJSRuntime->FixWeakMappingGrayBits();
|
mCCJSRuntime->FixWeakMappingGrayBits();
|
||||||
|
|
||||||
|
@ -3296,7 +3296,7 @@ void nsCycleCollector::FinishAnyIncrementalGCInProgress() {
|
||||||
NS_WARNING("Finishing incremental GC in progress during CC");
|
NS_WARNING("Finishing incremental GC in progress during CC");
|
||||||
JSContext* cx = CycleCollectedJSContext::Get()->Context();
|
JSContext* cx = CycleCollectedJSContext::Get()->Context();
|
||||||
JS::PrepareForIncrementalGC(cx);
|
JS::PrepareForIncrementalGC(cx);
|
||||||
JS::FinishIncrementalGC(cx, JS::gcreason::CC_FORCED);
|
JS::FinishIncrementalGC(cx, JS::GCReason::CC_FORCED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче