diff options
Diffstat (limited to 'js/src/gc/GC.cpp')
-rw-r--r-- | js/src/gc/GC.cpp | 80 |
1 files changed, 70 insertions, 10 deletions
diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 7ec63a571d..c01dfe3660 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -930,6 +930,8 @@ void GCRuntime::finish() { } #endif + releaseMarkingThreads(); + #ifdef JS_GC_ZEAL // Free memory associated with GC verification. finishVerifier(); @@ -1064,9 +1066,8 @@ bool GCRuntime::setParameter(JSGCParamKey key, uint32_t value, compactingEnabled = value != 0; break; case JSGC_PARALLEL_MARKING_ENABLED: - // Not supported on workers. - parallelMarkingEnabled = rt->isMainRuntime() && value != 0; - return initOrDisableParallelMarking(); + setParallelMarkingEnabled(value != 0); + break; case JSGC_INCREMENTAL_WEAKMAP_ENABLED: for (auto& marker : markers) { marker->incrementalWeakMapMarkingEnabled = value != 0; @@ -1151,8 +1152,7 @@ void GCRuntime::resetParameter(JSGCParamKey key, AutoLockGC& lock) { compactingEnabled = TuningDefaults::CompactingEnabled; break; case JSGC_PARALLEL_MARKING_ENABLED: - parallelMarkingEnabled = TuningDefaults::ParallelMarkingEnabled; - initOrDisableParallelMarking(); + setParallelMarkingEnabled(TuningDefaults::ParallelMarkingEnabled); break; case JSGC_INCREMENTAL_WEAKMAP_ENABLED: for (auto& marker : markers) { @@ -1350,16 +1350,56 @@ void GCRuntime::assertNoMarkingWork() const { } #endif +bool GCRuntime::setParallelMarkingEnabled(bool enabled) { + if (enabled == parallelMarkingEnabled) { + return true; + } + + parallelMarkingEnabled = enabled; + return initOrDisableParallelMarking(); +} + bool GCRuntime::initOrDisableParallelMarking() { - // Attempt to initialize parallel marking state or disable it on failure. + // Attempt to initialize parallel marking state or disable it on failure. This + // is called when parallel marking is enabled or disabled. MOZ_ASSERT(markers.length() != 0); - if (!updateMarkersVector()) { - parallelMarkingEnabled = false; + if (updateMarkersVector()) { + return true; + } + + // Failed to initialize parallel marking so disable it instead. + MOZ_ASSERT(parallelMarkingEnabled); + parallelMarkingEnabled = false; + MOZ_ALWAYS_TRUE(updateMarkersVector()); + return false; +} + +void GCRuntime::releaseMarkingThreads() { + MOZ_ALWAYS_TRUE(reserveMarkingThreads(0)); +} + +bool GCRuntime::reserveMarkingThreads(size_t newCount) { + if (reservedMarkingThreads == newCount) { + return true; + } + + // Update the helper thread system's global count by subtracting this + // runtime's current contribution |reservedMarkingThreads| and adding the new + // contribution |newCount|. + + AutoLockHelperThreadState lock; + auto& globalCount = HelperThreadState().gcParallelMarkingThreads; + MOZ_ASSERT(globalCount >= reservedMarkingThreads); + size_t newGlobalCount = globalCount - reservedMarkingThreads + newCount; + if (newGlobalCount > HelperThreadState().threadCount) { + // Not enough total threads. return false; } + globalCount = newGlobalCount; + reservedMarkingThreads = newCount; return true; } @@ -1378,6 +1418,16 @@ bool GCRuntime::updateMarkersVector() { // concurrently, otherwise one thread can deadlock waiting on another. size_t targetCount = std::min(markingWorkerCount(), getMaxParallelThreads()); + if (rt->isMainRuntime()) { + // For the main runtime, reserve helper threads as long as parallel marking + // is enabled. Worker runtimes may not mark in parallel if there are + // insufficient threads available at the time. + size_t threadsToReserve = targetCount > 1 ? targetCount : 0; + if (!reserveMarkingThreads(threadsToReserve)) { + return false; + } + } + if (markers.length() > targetCount) { return markers.resize(targetCount); } @@ -2870,7 +2920,7 @@ void GCRuntime::beginMarkPhase(AutoGCSession& session) { stats().measureInitialHeapSize(); useParallelMarking = SingleThreadedMarking; - if (canMarkInParallel() && initParallelMarkers()) { + if (canMarkInParallel() && initParallelMarking()) { useParallelMarking = AllowParallelMarking; } @@ -2989,9 +3039,19 @@ inline bool GCRuntime::canMarkInParallel() const { tunables.parallelMarkingThresholdBytes(); } -bool GCRuntime::initParallelMarkers() { +bool GCRuntime::initParallelMarking() { + // This is called at the start of collection. + MOZ_ASSERT(canMarkInParallel()); + // Reserve/release helper threads for worker runtimes. These are released at + // the end of sweeping. If there are not enough helper threads because + // other runtimes are marking in parallel then parallel marking will not be + // used. + if (!rt->isMainRuntime() && !reserveMarkingThreads(markers.length())) { + return false; + } + // Allocate stack for parallel markers. The first marker always has stack // allocated. Other markers have their stack freed in // GCRuntime::finishCollection. |