diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 9e5ca10bccdf..e8efae001dd0 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1696,9 +1696,17 @@ void nsJSContext::MaybeRunNextCollectorSlice(nsIDocShell* aDocShell, Maybe next = nsRefreshDriver::GetNextTickHint(); // Try to not delay the next RefreshDriver tick, so give a reasonable // deadline for collectors. - if (next.isSome() && - (sScheduler.InIncrementalGC() || sScheduler.IsCollectingCycles())) { - sScheduler.RunNextCollectorTimer(aReason, next.value()); + if (next.isSome()) { + if (sScheduler.InIncrementalGC() || sScheduler.IsCollectingCycles()) { + sScheduler.RunNextCollectorTimer(aReason, next.value()); + } else { + // In order to improve performance on the next page, run a minor GC. + // The 16ms limit ensures it isn't called all the time if there are for + // example multiple iframes loading at the same time. + JS::RunNurseryCollection(CycleCollectedJSRuntime::Get()->Runtime(), + JS::GCReason::PREPARE_FOR_PAGELOAD, + mozilla::TimeDuration::FromMilliseconds(16)); + } } } } diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h index 919ff47709ac..cd2cb4fd23e0 100644 --- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -639,6 +639,7 @@ namespace JS { D(DOCSHELL, 54) \ D(HTML_PARSER, 55) \ D(DOM_TESTUTILS, 56) \ + D(PREPARE_FOR_PAGELOAD, 57) \ \ /* Reasons reserved for embeddings. */ \ D(RESERVED1, FIRST_RESERVED_REASON) \ @@ -1299,6 +1300,10 @@ extern JS_PUBLIC_API GCReason WantEagerMajorGC(JSRuntime* rt); extern JS_PUBLIC_API void MaybeRunNurseryCollection(JSRuntime* rt, JS::GCReason reason); +extern JS_PUBLIC_API void RunNurseryCollection( + JSRuntime* rt, JS::GCReason reason, + mozilla::TimeDuration aSinceLastMinorGC); + extern JS_PUBLIC_API void SetHostCleanupFinalizationRegistryCallback( JSContext* cx, JSHostCleanupFinalizationRegistryCallback cb, void* data); diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index a467421462f9..03e825e47e58 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -1050,7 +1050,7 @@ inline TimeStamp js::Nursery::collectionStartTime() const { return startTimes_[ProfileKey::Total]; } -inline TimeStamp js::Nursery::lastCollectionEndTime() const { +TimeStamp js::Nursery::lastCollectionEndTime() const { return previousGC.endTime; } @@ -1871,6 +1871,10 @@ size_t js::Nursery::targetSize(JS::GCOptions options, JS::GCReason reason) { TimeStamp now = TimeStamp::Now(); + if (reason == JS::GCReason::PREPARE_FOR_PAGELOAD) { + return roundSize(tunables().gcMaxNurseryBytes()); + } + // If the nursery is completely unused then minimise it. if (hasRecentGrowthData && previousGC.nurseryUsedBytes == 0 && now - lastCollectionEndTime() > diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index adf19e708ef4..14321a5f92d4 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -409,6 +409,8 @@ class Nursery { return mallocedBlockCache_.sizeOfExcludingThis(mallocSizeOf); } + mozilla::TimeStamp lastCollectionEndTime() const; + private: // Fields used during allocation fast path are grouped first: @@ -703,7 +705,6 @@ class Nursery { Sprinter& sprinter); mozilla::TimeStamp collectionStartTime() const; - mozilla::TimeStamp lastCollectionEndTime() const; friend class gc::GCRuntime; friend class gc::TenuringTracer; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index c78fc95388ee..6cad46c143b8 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1304,6 +1304,17 @@ JS_PUBLIC_API void JS::MaybeRunNurseryCollection(JSRuntime* rt, } } +JS_PUBLIC_API void JS::RunNurseryCollection( + JSRuntime* rt, JS::GCReason reason, + mozilla::TimeDuration aSinceLastMinorGC) { + gc::GCRuntime& gc = rt->gc; + if (!gc.nursery().lastCollectionEndTime() || + (mozilla::TimeStamp::Now() - gc.nursery().lastCollectionEndTime() > + aSinceLastMinorGC)) { + gc.minorGC(reason); + } +} + JS_PUBLIC_API void JS_GC(JSContext* cx, JS::GCReason reason) { AssertHeapIsIdle(); JS::PrepareForFullGC(cx);