diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index e94cd361e6fa..ae9afbcdedf2 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -320,8 +320,9 @@ class GCRuntime void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) { minorGC(reason); } bool gcIfNeeded(JSContext *cx = nullptr); void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason); - void gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0); - void gcFinalSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason); + void startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0); + void gcSlice(JS::gcreason::Reason reason, int64_t millis = 0); + void finishGC(JS::gcreason::Reason reason); void gcDebugSlice(SliceBudget &budget); void runDebugGC(); @@ -558,10 +559,9 @@ class GCRuntime void startBackgroundAllocTaskIfIdle(); void requestMajorGC(JS::gcreason::Reason reason); - void collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gckind, - JS::gcreason::Reason reason); - bool gcCycle(bool incremental, SliceBudget &budget, JSGCInvocationKind gckind, - JS::gcreason::Reason reason); + SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis); + void collect(bool incremental, SliceBudget budget, JS::gcreason::Reason reason); + bool gcCycle(bool incremental, SliceBudget &budget, JS::gcreason::Reason reason); gcstats::ZoneGCStats scanZonesBeforeGC(); void budgetIncrementalGC(SliceBudget &budget); void resetIncrementalGC(const char *reason); diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index c9645f7853a6..1182ac528eee 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -210,13 +210,16 @@ JS::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason) JS_FRIEND_API(void) JS::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis) { - rt->gc.gcSlice(GC_NORMAL, reason, millis); + if (!rt->gc.isIncrementalGCInProgress()) + rt->gc.startGC(GC_NORMAL, reason, millis); + else + rt->gc.gcSlice(reason, millis); } JS_FRIEND_API(void) JS::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason) { - rt->gc.gcFinalSlice(GC_NORMAL, reason); + rt->gc.finishGC(reason); } JS_FRIEND_API(JSPrincipals *) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 8bfe4f45be99..773d0c575908 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -6088,8 +6088,7 @@ class AutoDisableStoreBuffer * to run another cycle. */ MOZ_NEVER_INLINE bool -GCRuntime::gcCycle(bool incremental, SliceBudget &budget, JSGCInvocationKind gckind, - JS::gcreason::Reason reason) +GCRuntime::gcCycle(bool incremental, SliceBudget &budget, JS::gcreason::Reason reason) { minorGC(reason); @@ -6152,10 +6151,6 @@ GCRuntime::gcCycle(bool incremental, SliceBudget &budget, JSGCInvocationKind gck TraceMajorGCStart(); - /* Set the invocation kind in the first slice. */ - if (!isIncrementalGCInProgress()) - invocationKind = gckind; - incrementalCollectSlice(budget, reason); #ifndef JS_MORE_DETERMINISTIC @@ -6240,8 +6235,7 @@ GCRuntime::scanZonesBeforeGC() } void -GCRuntime::collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gckind, - JS::gcreason::Reason reason) +GCRuntime::collect(bool incremental, SliceBudget budget, JS::gcreason::Reason reason) { /* GC shouldn't be running in parallel execution mode */ MOZ_ALWAYS_TRUE(!InParallelSection()); @@ -6268,9 +6262,9 @@ GCRuntime::collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gck AutoStopVerifyingBarriers av(rt, reason == JS::gcreason::SHUTDOWN_CC || reason == JS::gcreason::DESTROY_RUNTIME); - gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), gckind, reason); + gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), invocationKind, reason); - cleanUpEverything = ShouldCleanUpEverything(reason, gckind); + cleanUpEverything = ShouldCleanUpEverything(reason, invocationKind); bool repeat = false; do { @@ -6285,7 +6279,7 @@ GCRuntime::collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gck } poked = false; - bool wasReset = gcCycle(incremental, budget, gckind, reason); + bool wasReset = gcCycle(incremental, budget, reason); if (!isIncrementalGCInProgress()) { gcstats::AutoPhase ap(stats, gcstats::PHASE_GC_END); @@ -6327,34 +6321,48 @@ GCRuntime::collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gck EnqueuePendingParseTasksAfterGC(rt); } +SliceBudget +GCRuntime::defaultBudget(JS::gcreason::Reason reason, int64_t millis) +{ + if (millis == 0) { + if (reason == JS::gcreason::ALLOC_TRIGGER) + millis = sliceBudget; + else if (schedulingState.inHighFrequencyGCMode() && tunables.isDynamicMarkSliceEnabled()) + millis = sliceBudget * IGC_MARK_SLICE_MULTIPLIER; + else + millis = sliceBudget; + } + + return SliceBudget(TimeBudget(millis)); +} + void GCRuntime::gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason) { - SliceBudget budget; - collect(false, budget, gckind, reason); + invocationKind = gckind; + collect(false, SliceBudget(), reason); } void -GCRuntime::gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis) +GCRuntime::startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis) { - SliceBudget budget; - if (millis) - budget = SliceBudget(TimeBudget(millis)); - else if (reason == JS::gcreason::ALLOC_TRIGGER) - budget = SliceBudget(TimeBudget(sliceBudget)); - else if (schedulingState.inHighFrequencyGCMode() && tunables.isDynamicMarkSliceEnabled()) - budget = SliceBudget(TimeBudget(sliceBudget * IGC_MARK_SLICE_MULTIPLIER)); - else - budget = SliceBudget(TimeBudget(sliceBudget)); - - collect(true, budget, gckind, reason); + MOZ_ASSERT(!isIncrementalGCInProgress()); + invocationKind = gckind; + collect(true, defaultBudget(reason, millis), reason); } void -GCRuntime::gcFinalSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason) +GCRuntime::gcSlice(JS::gcreason::Reason reason, int64_t millis) { - SliceBudget budget; - collect(true, budget, gckind, reason); + MOZ_ASSERT(isIncrementalGCInProgress()); + collect(true, defaultBudget(reason, millis), reason); +} + +void +GCRuntime::finishGC(JS::gcreason::Reason reason) +{ + MOZ_ASSERT(isIncrementalGCInProgress()); + collect(true, SliceBudget(), reason); } void @@ -6378,9 +6386,9 @@ GCRuntime::notifyDidPaint() } #endif - if (JS::IsIncrementalGCInProgress(rt) && !interFrameGC) { + if (isIncrementalGCInProgress() && !interFrameGC) { JS::PrepareForIncrementalGC(rt); - gcSlice(GC_NORMAL, JS::gcreason::REFRESH_FRAME); + gcSlice(JS::gcreason::REFRESH_FRAME); } interFrameGC = false; @@ -6400,12 +6408,14 @@ void GCRuntime::gcDebugSlice(SliceBudget &budget) { if (!ZonesSelected(rt)) { - if (JS::IsIncrementalGCInProgress(rt)) + if (isIncrementalGCInProgress()) JS::PrepareForIncrementalGC(rt); else JS::PrepareForFullGC(rt); } - collect(true, budget, GC_NORMAL, JS::gcreason::DEBUG_GC); + if (!isIncrementalGCInProgress()) + invocationKind = GC_NORMAL; + collect(true, budget, JS::gcreason::DEBUG_GC); } /* Schedule a full GC unless a zone will already be collected. */ @@ -6526,10 +6536,14 @@ GCRuntime::gcIfNeeded(JSContext *cx /* = nullptr */) } if (majorGCRequested) { - if (rt->gc.majorGCTriggerReason == JS::gcreason::INCREMENTAL_ALLOC_TRIGGER) - gcSlice(GC_NORMAL, rt->gc.majorGCTriggerReason); - else - gc(GC_NORMAL, rt->gc.majorGCTriggerReason); + if (majorGCTriggerReason == JS::gcreason::INCREMENTAL_ALLOC_TRIGGER) { + if (!isIncrementalGCInProgress()) + startGC(GC_NORMAL, majorGCTriggerReason); + else + gcSlice(majorGCTriggerReason); + } else { + gc(GC_NORMAL, majorGCTriggerReason); + } return true; } @@ -6694,7 +6708,9 @@ GCRuntime::runDebugGC() budget = SliceBudget(WorkBudget(1)); } - collect(true, budget, GC_NORMAL, JS::gcreason::DEBUG_GC); + if (!isIncrementalGCInProgress()) + invocationKind = GC_NORMAL; + collect(true, budget, JS::gcreason::DEBUG_GC); /* * For multi-slice zeal, reset the slice size when we get to the sweep @@ -6706,9 +6722,9 @@ GCRuntime::runDebugGC() incrementalLimit = zealFrequency / 2; } } else if (type == ZealCompactValue) { - collect(false, budget, GC_SHRINK, JS::gcreason::DEBUG_GC); + gc(GC_SHRINK, JS::gcreason::DEBUG_GC); } else { - collect(false, budget, GC_NORMAL, JS::gcreason::DEBUG_GC); + gc(GC_NORMAL, JS::gcreason::DEBUG_GC); } #endif