Bug 1463462 - Change Zone marking states to MarkBlackOnly and MarkBlackAndGray r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 06 Dec 2018 16:27:21 -0500
changeset 450666 37a9521cad270889c718a62ccf048a14180b0172
parent 450665 e35dd56b9bc1addcb60519bd38177ee0a716ad65
child 450667 3e7a4e085ead5b20172ee33e4809770dd124a8f7
push id110516
push userjcoppeard@mozilla.com
push dateFri, 14 Dec 2018 14:22:31 +0000
treeherdermozilla-inbound@fd4d12eb1b97 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1463462
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1463462 - Change Zone marking states to MarkBlackOnly and MarkBlackAndGray r=sfink
js/public/HeapAPI.h
js/src/gc/GC.cpp
js/src/gc/Marking.cpp
js/src/gc/RootMarking.cpp
js/src/jsapi-tests/testGCGrayMarking.cpp
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -125,17 +125,24 @@ enum StackKind {
 const uint32_t DefaultNurseryBytes = 16 * js::gc::ChunkSize;
 
 /* Default maximum heap size in bytes to pass to JS_NewContext(). */
 const uint32_t DefaultHeapMaxBytes = 32 * 1024 * 1024;
 
 namespace shadow {
 
 struct Zone {
-  enum GCState : uint8_t { NoGC, Mark, MarkGray, Sweep, Finished, Compact };
+  enum GCState : uint8_t {
+    NoGC,
+    MarkBlackOnly,
+    MarkBlackAndGray,
+    Sweep,
+    Finished,
+    Compact
+  };
 
  protected:
   JSRuntime* const runtime_;
   JSTracer* const barrierTracer_;  // A pointer to the JSRuntime's |gcMarker|.
   uint32_t needsIncrementalBarrier_;
   GCState gcState_;
 
   Zone(JSRuntime* runtime, JSTracer* barrierTracerArg)
@@ -159,22 +166,24 @@ struct Zone {
   }
 
   // Note: Unrestricted access to the zone's runtime from an arbitrary
   // thread can easily lead to races. Use this method very carefully.
   JSRuntime* runtimeFromAnyThread() const { return runtime_; }
 
   GCState gcState() const { return gcState_; }
   bool wasGCStarted() const { return gcState_ != NoGC; }
-  bool isGCMarkingBlack() const { return gcState_ == Mark; }
-  bool isGCMarkingGray() const { return gcState_ == MarkGray; }
+  bool isGCMarkingBlackOnly() const { return gcState_ == MarkBlackOnly; }
+  bool isGCMarkingBlackAndGray() const { return gcState_ == MarkBlackAndGray; }
   bool isGCSweeping() const { return gcState_ == Sweep; }
   bool isGCFinished() const { return gcState_ == Finished; }
   bool isGCCompacting() const { return gcState_ == Compact; }
-  bool isGCMarking() const { return gcState_ == Mark || gcState_ == MarkGray; }
+  bool isGCMarking() const {
+    return isGCMarkingBlackOnly() || isGCMarkingBlackAndGray();
+  }
   bool isGCSweepingOrCompacting() const {
     return gcState_ == Sweep || gcState_ == Compact;
   }
 
   static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) {
     return reinterpret_cast<JS::shadow::Zone*>(zone);
   }
 };
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -4130,17 +4130,17 @@ bool GCRuntime::prepareZonesForCollectio
 
   auto currentTime = ReallyNow();
 
   for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
     /* Set up which zones will be collected. */
     if (ShouldCollectZone(zone, reason)) {
       MOZ_ASSERT(zone->canCollect());
       any = true;
-      zone->changeGCState(Zone::NoGC, Zone::Mark);
+      zone->changeGCState(Zone::NoGC, Zone::MarkBlackOnly);
     } else {
       *isFullOut = false;
     }
 
     zone->setPreservingCode(false);
   }
 
   // Discard JIT code more aggressively if the process is approaching its
@@ -4179,17 +4179,17 @@ bool GCRuntime::prepareZonesForCollectio
   MOZ_ASSERT_IF(reason == JS::gcreason::DELAYED_ATOMS_GC,
                 atomsZone->isGCMarking());
 
   /* Check that at least one zone is scheduled for collection. */
   return any;
 }
 
 static void DiscardJITCodeForGC(JSRuntime* rt) {
-  js::CancelOffThreadIonCompile(rt, JS::Zone::Mark);
+  js::CancelOffThreadIonCompile(rt, JS::Zone::MarkBlackOnly);
   for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
     gcstats::AutoPhase ap(rt->gc.stats(),
                           gcstats::PhaseKind::MARK_DISCARD_CODE);
     zone->discardJitCode(rt->defaultFreeOp(),
                          /* discardBaselineCode = */ true,
                          /* releaseTypes = */ true);
   }
 }
@@ -4642,27 +4642,27 @@ void js::gc::MarkingValidator::nonIncrem
   {
     gcstats::AutoPhase ap1(gc->stats(), gcstats::PhaseKind::SWEEP);
     gcstats::AutoPhase ap2(gc->stats(), gcstats::PhaseKind::SWEEP_MARK);
 
     gc->markAllWeakReferences(gcstats::PhaseKind::SWEEP_MARK_WEAK);
 
     /* Update zone state for gray marking. */
     for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
-      zone->changeGCState(Zone::Mark, Zone::MarkGray);
+      zone->changeGCState(Zone::MarkBlackOnly, Zone::MarkBlackAndGray);
     }
 
     AutoSetMarkColor setColorGray(gc->marker, MarkColor::Gray);
 
     gc->markAllGrayReferences(gcstats::PhaseKind::SWEEP_MARK_GRAY);
     gc->markAllWeakReferences(gcstats::PhaseKind::SWEEP_MARK_GRAY_WEAK);
 
     /* Restore zone state. */
     for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
-      zone->changeGCState(Zone::MarkGray, Zone::Mark);
+      zone->changeGCState(Zone::MarkBlackAndGray, Zone::MarkBlackOnly);
     }
     MOZ_ASSERT(gc->marker.isDrained());
   }
 
   /* Take a copy of the non-incremental mark state and restore the original. */
   {
     AutoLockGC lock(runtime);
     for (auto chunk = gc->allNonEmptyChunks(lock); !chunk.done();
@@ -4968,17 +4968,17 @@ void GCRuntime::getNextSweepGroup() {
     MOZ_ASSERT(zone->isGCMarking());
     MOZ_ASSERT(!zone->isQueuedForBackgroundSweep());
   }
 
   if (abortSweepAfterCurrentGroup) {
     for (SweepGroupZonesIter zone(rt); !zone.done(); zone.next()) {
       MOZ_ASSERT(!zone->gcNextGraphComponent);
       zone->setNeedsIncrementalBarrier(false);
-      zone->changeGCState(Zone::Mark, Zone::NoGC);
+      zone->changeGCState(Zone::MarkBlackOnly, Zone::NoGC);
       zone->arenas.unmarkPreMarkedFreeCells();
       zone->gcGrayRoots().clearAndFree();
     }
 
     for (SweepGroupCompartmentsIter comp(rt); !comp.done(); comp.next()) {
       ResetGrayList(comp);
     }
 
@@ -5103,18 +5103,19 @@ void GCRuntime::markIncomingCrossCompart
   static const gcstats::PhaseKind statsPhases[] = {
       gcstats::PhaseKind::SWEEP_MARK_INCOMING_BLACK,
       gcstats::PhaseKind::SWEEP_MARK_INCOMING_GRAY};
   gcstats::AutoPhase ap1(stats(), statsPhases[unsigned(color)]);
 
   bool unlinkList = color == MarkColor::Gray;
 
   for (SweepGroupCompartmentsIter c(rt); !c.done(); c.next()) {
-    MOZ_ASSERT_IF(color == MarkColor::Gray, c->zone()->isGCMarkingGray());
-    MOZ_ASSERT_IF(color == MarkColor::Black, c->zone()->isGCMarkingBlack());
+    MOZ_ASSERT_IF(color == MarkColor::Gray,
+                  c->zone()->isGCMarkingBlackAndGray());
+    MOZ_ASSERT_IF(color == MarkColor::Black, c->zone()->isGCMarkingBlackOnly());
     MOZ_ASSERT_IF(c->gcIncomingGrayPointers,
                   IsGrayListObject(c->gcIncomingGrayPointers));
 
     for (JSObject* src = c->gcIncomingGrayPointers; src;
          src = NextIncomingCrossCompartmentPointer(src, unlinkList)) {
       JSObject* dst = CrossCompartmentPointerReferent(src);
       MOZ_ASSERT(dst->compartment() == c);
 
@@ -5249,33 +5250,29 @@ IncrementalProgress GCRuntime::endMarkin
   markIncomingCrossCompartmentPointers(MarkColor::Black);
   markWeakReferencesInCurrentGroup(gcstats::PhaseKind::SWEEP_MARK_WEAK);
 
   // Change state of current group to MarkGray to restrict marking to this
   // group.  Note that there may be pointers to the atoms zone, and
   // these will be marked through, as they are not marked with
   // TraceCrossCompartmentEdge.
   for (SweepGroupZonesIter zone(rt); !zone.done(); zone.next()) {
-    zone->changeGCState(Zone::Mark, Zone::MarkGray);
+    zone->changeGCState(Zone::MarkBlackOnly, Zone::MarkBlackAndGray);
   }
 
   AutoSetMarkColor setColorGray(marker, MarkColor::Gray);
 
   // Mark incoming gray pointers from previously swept compartments.
   markIncomingCrossCompartmentPointers(MarkColor::Gray);
 
   // Mark gray roots and mark transitively inside the current compartment
   // group.
   markGrayReferencesInCurrentGroup(gcstats::PhaseKind::SWEEP_MARK_GRAY);
   markWeakReferencesInCurrentGroup(gcstats::PhaseKind::SWEEP_MARK_GRAY_WEAK);
 
-  // Restore marking state.
-  for (SweepGroupZonesIter zone(rt); !zone.done(); zone.next()) {
-    zone->changeGCState(Zone::MarkGray, Zone::Mark);
-  }
   MOZ_ASSERT(marker.isDrained());
 
   // We must not yield after this point before we start sweeping the group.
   safeToYield = false;
 
   MaybeCheckWeakMapMarking(this);
 
   return Finished;
@@ -5570,17 +5567,17 @@ IncrementalProgress GCRuntime::beginSwee
 
   using namespace gcstats;
 
   AutoSCC scc(stats(), sweepGroupIndex);
 
   bool sweepingAtoms = false;
   for (SweepGroupZonesIter zone(rt); !zone.done(); zone.next()) {
     /* Set the GC state to sweeping. */
-    zone->changeGCState(Zone::Mark, Zone::Sweep);
+    zone->changeGCState(Zone::MarkBlackAndGray, Zone::Sweep);
 
     /* Purge the ArenaLists before sweeping. */
     zone->arenas.unmarkPreMarkedFreeCells();
     zone->arenas.clearFreeLists();
 
     if (zone->isAtomsZone()) {
       sweepingAtoms = true;
     }
@@ -6738,17 +6735,17 @@ GCRuntime::IncrementalResult GCRuntime::
       clearBufferedGrayRoots();
 
       for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
         ResetGrayList(c);
       }
 
       for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
         zone->setNeedsIncrementalBarrier(false);
-        zone->changeGCState(Zone::Mark, Zone::NoGC);
+        zone->changeGCState(Zone::MarkBlackOnly, Zone::NoGC);
         zone->arenas.unmarkPreMarkedFreeCells();
       }
 
       {
         AutoLockHelperThreadState lock;
         blocksToFreeAfterSweeping.ref().freeAll();
       }
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -245,17 +245,17 @@ void js::CheckTracedThing(JSTracer* trc,
                     IsUnmarkGrayTracer(trc) || IsClearEdgesTracer(trc));
 
   if (isGcMarkingTracer) {
     GCMarker* gcMarker = GCMarker::fromTracer(trc);
     MOZ_ASSERT_IF(gcMarker->shouldCheckCompartments(),
                   zone->isCollecting() || zone->isAtomsZone());
 
     MOZ_ASSERT_IF(gcMarker->markColor() == MarkColor::Gray,
-                  !zone->isGCMarkingBlack() || zone->isAtomsZone());
+                  !zone->isGCMarkingBlackOnly() || zone->isAtomsZone());
 
     MOZ_ASSERT(!(zone->isGCSweeping() || zone->isGCFinished() ||
                  zone->isGCCompacting()));
   }
 
   /*
    * Try to assert that the thing is allocated.
    *
@@ -331,29 +331,29 @@ static inline bool ShouldMarkCrossCompar
                         JS::GCCellPtr(&dst, dst.getTraceKind()));
     }
 
     return dstZone->isGCMarking();
   } else {
     // Check our sweep groups are correct as above.
     MOZ_ASSERT_IF(!dst.isMarkedAny(), !dstZone->isGCSweeping());
 
-    if (dstZone->isGCMarkingBlack()) {
+    if (dstZone->isGCMarkingBlackOnly()) {
       /*
        * The destination compartment is being not being marked gray now,
        * but it will be later, so record the cell so it can be marked gray
        * at the appropriate time.
        */
       if (!dst.isMarkedAny()) {
         DelayCrossCompartmentGrayMarking(src);
       }
       return false;
     }
 
-    return dstZone->isGCMarkingGray();
+    return dstZone->isGCMarkingBlackAndGray();
   }
 }
 
 static bool ShouldTraceCrossCompartment(JSTracer* trc, JSObject* src,
                                         Cell* dstCell) {
   if (!trc->isMarkingTracer()) {
     return true;
   }
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -545,17 +545,17 @@ inline void BufferGrayRootsTracer::buffe
     if (!zone->gcGrayRoots().append(tenured)) {
       bufferingGrayRootsFailed = true;
     }
   }
 }
 
 void GCRuntime::markBufferedGrayRoots(JS::Zone* zone) {
   MOZ_ASSERT(grayBufferState == GrayBufferState::Okay);
-  MOZ_ASSERT(zone->isGCMarkingGray() || zone->isGCCompacting());
+  MOZ_ASSERT(zone->isGCMarkingBlackAndGray() || zone->isGCCompacting());
 
   auto& roots = zone->gcGrayRoots();
   if (roots.empty()) {
     return;
   }
 
   for (size_t i = 0; i < roots.length(); i++) {
     Cell* cell = roots[i];
--- a/js/src/jsapi-tests/testGCGrayMarking.cpp
+++ b/js/src/jsapi-tests/testGCGrayMarking.cpp
@@ -455,17 +455,17 @@ bool TestCCWs() {
 
   JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_INCREMENTAL);
   JS::PrepareForFullGC(cx);
   js::SliceBudget budget(js::WorkBudget(1));
   cx->runtime()->gc.startDebugGC(GC_NORMAL, budget);
   CHECK(JS::IsIncrementalGCInProgress(cx));
 
   CHECK(!IsMarkedBlack(wrapper));
-  CHECK(wrapper->zone()->isGCMarkingBlack());
+  CHECK(wrapper->zone()->isGCMarkingBlackOnly());
 
   CHECK(GetCrossCompartmentWrapper(target) == wrapper);
   CHECK(IsMarkedBlack(wrapper));
 
   JS::FinishIncrementalGC(cx, JS::gcreason::API);
 
   // Test behaviour of gray CCWs marked black by a barrier during incremental
   // GC.
@@ -479,17 +479,17 @@ bool TestCCWs() {
   CHECK(IsMarkedGray(target));
 
   // Incremental zone GC started: the source is now unmarked.
   JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_INCREMENTAL);
   JS::PrepareZoneForGC(wrapper->zone());
   budget = js::SliceBudget(js::WorkBudget(1));
   cx->runtime()->gc.startDebugGC(GC_NORMAL, budget);
   CHECK(JS::IsIncrementalGCInProgress(cx));
-  CHECK(wrapper->zone()->isGCMarkingBlack());
+  CHECK(wrapper->zone()->isGCMarkingBlackOnly());
   CHECK(!target->zone()->wasGCStarted());
   CHECK(!IsMarkedBlack(wrapper));
   CHECK(!IsMarkedGray(wrapper));
   CHECK(IsMarkedGray(target));
 
   // Betweeen GC slices: source marked black by barrier, target is still
   // gray. Target will be marked gray eventually. ObjectIsMarkedGray() is
   // conservative and reports that target is not marked gray; ObjectIsNotGray