tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 00c99c7b32988d3131c6305f991a7947d71833b5
parent be45c3dff0d54d13191e9684f34b8ebb10a8aff6
Author: Jon Coppeard <jcoppeard@mozilla.com>
Date:   Wed, 29 Oct 2025 09:19:04 +0000

Bug 1996636 - Simplify disabling barriers during sweeping r=sfink

Differential Revision: https://phabricator.services.mozilla.com/D270218

Diffstat:
Mjs/src/gc/GC.cpp | 18+++++++++---------
Mjs/src/gc/GCInternals.h | 12------------
Mjs/src/gc/GCRuntime.h | 5+++++
Mjs/src/gc/Sweeping.cpp | 42+++++++++++++++++++++++++++++++++++++++---
Mjs/src/gc/Zone.cpp | 13++-----------
5 files changed, 55 insertions(+), 35 deletions(-)

diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp @@ -3562,9 +3562,9 @@ void GCRuntime::checkGCStateNotInUse() { MOZ_ASSERT(marker->isDrained()); } MOZ_ASSERT(!hasDelayedMarking()); - MOZ_ASSERT(!lastMarkSlice); + MOZ_ASSERT(!disableBarriersForSweeping); MOZ_ASSERT(foregroundFinalizedArenas.ref().isNothing()); for (ZonesIter zone(this, WithAtoms); !zone.done(); zone.next()) { @@ -3877,12 +3877,12 @@ GCRuntime::IncrementalResult GCRuntime::resetIncrementalGC( return IncrementalResult::Reset; } -AutoDisableBarriers::AutoDisableBarriers(GCRuntime* gc) : gc(gc) { - /* - * Clear needsIncrementalBarrier early so we don't do any write barriers - * during sweeping. - */ - for (GCZonesIter zone(gc); !zone.done(); zone.next()) { +void GCRuntime::disableIncrementalBarriers() { + // Clear needsIncrementalBarrier so we don't do any write barriers during + // foreground finalization. This would otherwise happen when destroying + // HeapPtr<>s to GC things in zones which are still marking. + + for (GCZonesIter zone(this); !zone.done(); zone.next()) { if (zone->isGCMarking()) { MOZ_ASSERT(zone->needsIncrementalBarrier()); zone->setNeedsIncrementalBarrier(false); @@ -3891,8 +3891,8 @@ AutoDisableBarriers::AutoDisableBarriers(GCRuntime* gc) : gc(gc) { } } -AutoDisableBarriers::~AutoDisableBarriers() { - for (GCZonesIter zone(gc); !zone.done(); zone.next()) { +void GCRuntime::enableIncrementalBarriers() { + for (GCZonesIter zone(this); !zone.done(); zone.next()) { MOZ_ASSERT(!zone->needsIncrementalBarrier()); if (zone->isGCMarking()) { zone->setNeedsIncrementalBarrier(true); diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h @@ -106,18 +106,6 @@ class MOZ_RAII AutoEmptyNurseryAndPrepareForTracing : private AutoFinishGC, AutoTraceSession(cx->runtime()) {} }; -/* - * Temporarily disable incremental barriers. - */ -class AutoDisableBarriers { - public: - explicit AutoDisableBarriers(GCRuntime* gc); - ~AutoDisableBarriers(); - - private: - GCRuntime* gc; -}; - // Set compartments' maybeAlive flags if anything is marked while this class is // live. This is used while marking roots. class AutoUpdateLiveCompartments { diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h @@ -46,6 +46,7 @@ using BlackGrayEdgeVector = Vector<TenuredCell*, 0, SystemAllocPolicy>; using ZoneVector = Vector<JS::Zone*, 4, SystemAllocPolicy>; class AutoCallGCCallbacks; +class AutoUpdateBarriersForSweeping; class AutoGCSession; class AutoHeapSession; class AutoTraceSession; @@ -940,6 +941,8 @@ class GCRuntime { void freeFromBackgroundThread(AutoLockHelperThreadState& lock); void sweepBackgroundThings(ZoneList& zones); void prepareForSweepSlice(JS::GCReason reason); + void disableIncrementalBarriers(); + void enableIncrementalBarriers(); void assertBackgroundSweepingFinished(); #ifdef DEBUG bool zoneInCurrentSweepGroup(Zone* zone) const; @@ -1265,6 +1268,8 @@ class GCRuntime { weakCachesToSweep; MainThreadData<bool> abortSweepAfterCurrentGroup; MainThreadOrGCTaskData<IncrementalProgress> sweepMarkResult; + MainThreadData<bool> disableBarriersForSweeping; + friend class AutoUpdateBarriersForSweeping; /* * During incremental foreground finalization, we may have a list of arenas of diff --git a/js/src/gc/Sweeping.cpp b/js/src/gc/Sweeping.cpp @@ -1676,6 +1676,13 @@ IncrementalProgress GCRuntime::beginSweepingSweepGroup(JS::GCContext* gcx, AutoSetThreadIsSweeping threadIsSweeping; + // Disable incremental barriers for all zones while we are sweeping/finalizing + // zones in this sweep group. Set the |disableBarriersForSweeping| flag so we + // enable/disable the barriers on yield/resume. + MOZ_ASSERT(!disableBarriersForSweeping); + disableBarriersForSweeping = true; + disableIncrementalBarriers(); + // This must happen before sweeping realm globals. sweepDebuggerOnMainThread(gcx); @@ -1835,6 +1842,12 @@ IncrementalProgress GCRuntime::endSweepingSweepGroup(JS::GCContext* gcx, } queueZonesAndStartBackgroundSweep(std::move(zones)); + // Re-enable incremental barriers for all zones now we are we done sweeping + // zones in this group. + MOZ_ASSERT(disableBarriersForSweeping); + disableBarriersForSweeping = false; + enableIncrementalBarriers(); + return Finished; } @@ -2483,6 +2496,29 @@ void GCRuntime::prepareForSweepSlice(JS::GCReason reason) { rt->mainContextFromOwnThread()->traceWrapperGCRooters(marker().tracer()); } +// Ensure barriers are disabled if required when entering a sweep slice and +// re-enabled when yielding to the mutator. |disableBarriersForSweeping| is set +// in beginSweepingSweepGroup and cleared in endSweepingSweepGroup. +class js::gc::AutoUpdateBarriersForSweeping { + public: + explicit AutoUpdateBarriersForSweeping(GCRuntime* gc) : gc(gc) { + MOZ_ASSERT(gc->state() == State::Sweep); + if (gc->disableBarriersForSweeping) { + gc->disableIncrementalBarriers(); + } + } + + ~AutoUpdateBarriersForSweeping() { + MOZ_ASSERT(gc->state() == State::Sweep); + if (gc->disableBarriersForSweeping) { + gc->enableIncrementalBarriers(); + } + } + + private: + GCRuntime* gc; +}; + IncrementalProgress GCRuntime::performSweepActions(SliceBudget& budget) { MOZ_ASSERT_IF(storeBuffer().isEnabled(), !storeBuffer().mayHavePointersToDeadCells()); @@ -2494,9 +2530,6 @@ IncrementalProgress GCRuntime::performSweepActions(SliceBudget& budget) { AutoSetThreadIsSweeping threadIsSweeping(gcx); AutoPoisonFreedJitCode pjc(gcx); - // Don't trigger pre-barriers when finalizing. - AutoDisableBarriers disableBarriers(this); - // Drain the mark stack, possibly in a parallel task if we're in a part of // sweeping that allows it. // @@ -2515,6 +2548,9 @@ IncrementalProgress GCRuntime::performSweepActions(SliceBudget& budget) { } } + // Don't trigger pre-barriers when sweeping or finalizing. + AutoUpdateBarriersForSweeping updateBarriers(this); + // Then continue running sweep actions. SweepAction::Args args{this, gcx, budget}; diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp @@ -223,19 +223,10 @@ void Zone::setNeedsIncrementalBarrier(bool needs) { void Zone::changeGCState(GCState prev, GCState next) { MOZ_ASSERT(RuntimeHeapIsBusy()); MOZ_ASSERT(gcState() == prev); - - // This can be called when barriers have been temporarily disabled by - // AutoDisableBarriers. In that case, don't update needsIncrementalBarrier_ - // and barriers will be re-enabled by ~AutoDisableBarriers() if necessary. - bool barriersDisabled = isGCMarking() && !needsIncrementalBarrier(); + MOZ_ASSERT_IF(isGCMarkingOrVerifyingPreBarriers(), needsIncrementalBarrier_); gcState_ = next; - - // Update the barriers state when we transition between marking and - // non-marking states, unless barriers have been disabled. - if (!barriersDisabled) { - needsIncrementalBarrier_ = isGCMarking(); - } + needsIncrementalBarrier_ = isGCMarkingOrVerifyingPreBarriers(); } template <class Pred>