Bug 1459568 - Expose gray object on return from shell test function r=sfink a=abillings a=jcristau
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 10 May 2018 10:08:52 +0100
changeset 802222 2b3fe14452135cb8b86fa0ab4fff5ef58be4bb1e
parent 802221 c3f38f9d316e1159bd7716f8a35f13bebc51c707
child 802223 a475573d292338fff5c00c8fe35e062f063efcb6
push id111850
push userbmo:tom@mozilla.com
push dateThu, 31 May 2018 16:41:37 +0000
reviewerssfink, abillings, jcristau
bugs1459568
milestone60.0.2
Bug 1459568 - Expose gray object on return from shell test function r=sfink a=abillings a=jcristau
js/src/gc/Marking.cpp
js/src/jit-test/tests/gc/bug-1459568.js
js/src/shell/js.cpp
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -987,33 +987,47 @@ template <typename S, typename T>
 void
 js::GCMarker::traverseEdge(S source, const T& thing)
 {
     DispatchTyped(TraverseEdgeFunctor<T, S>(), thing, this, source);
 }
 
 namespace {
 
-template <typename T> struct ParticipatesInCC {};
+template <typename T> struct TypeParticipatesInCC {};
 #define EXPAND_PARTICIPATES_IN_CC(_, type, addToCCKind) \
-    template <> struct ParticipatesInCC<type> { static const bool value = addToCCKind; };
+    template <> struct TypeParticipatesInCC<type> { static const bool value = addToCCKind; };
 JS_FOR_EACH_TRACEKIND(EXPAND_PARTICIPATES_IN_CC)
 #undef EXPAND_PARTICIPATES_IN_CC
 
+struct ParticipatesInCCFunctor
+{
+    template <typename T>
+    bool operator()() {
+        return TypeParticipatesInCC<T>::value;
+    }
+};
+
 } // namespace
 
+static bool
+TraceKindParticipatesInCC(JS::TraceKind kind)
+{
+    return DispatchTraceKindTyped(ParticipatesInCCFunctor(), kind);
+}
+
 template <typename T>
 bool
 js::GCMarker::mark(T* thing)
 {
     AssertShouldMarkInZone(thing);
     TenuredCell* cell = TenuredCell::fromPointer(thing);
     MOZ_ASSERT(!IsInsideNursery(cell));
 
-    if (!ParticipatesInCC<T>::value)
+    if (!TypeParticipatesInCC<T>::value)
         return cell->markIfUnmarked(MarkColor::Black);
 
     return cell->markIfUnmarked(markColor());
 }
 
 
 /*** Inline, Eager GC Marking *********************************************************************/
 
@@ -2557,22 +2571,28 @@ GCMarker::leaveWeakMarkingMode()
 }
 
 void
 GCMarker::markDelayedChildren(Arena* arena)
 {
     MOZ_ASSERT(arena->markOverflow);
     arena->markOverflow = 0;
 
+    JS::TraceKind kind = MapAllocToTraceKind(arena->getAllocKind());
+
+    // Whether we need to mark children of gray or black cells in the arena
+    // depends on which kind of marking we were doing when the arena as pushed
+    // onto the list.  We never change mark color without draining the mark
+    // stack though so this is the same as the current color.
+    bool markGrayCells = markColor() == MarkColor::Gray && TraceKindParticipatesInCC(kind);
+
     for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) {
         TenuredCell* t = i.getCell();
-        if (t->isMarkedAny()) {
-            t->markIfUnmarked();
-            js::TraceChildren(this, t, MapAllocToTraceKind(arena->getAllocKind()));
-        }
+        if ((markGrayCells && t->isMarkedGray()) || (!markGrayCells && t->isMarkedBlack()))
+            js::TraceChildren(this, t, kind);
     }
 }
 
 bool
 GCMarker::markDelayedChildren(SliceBudget& budget)
 {
     GCRuntime& gc = runtime()->gc;
     gcstats::AutoPhase ap(gc.stats(), gc.state() == State::Mark, gcstats::PhaseKind::MARK_DELAYED);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1459568.js
@@ -0,0 +1,7 @@
+gczeal(0);
+gcparam("markStackLimit", 1);
+gczeal(18, 1);
+grayRoot()[0] = "foo";
+grayRoot()[1] = {};
+grayRoot().x = 0;
+gc();
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -6376,17 +6376,17 @@ DumpScopeChain(JSContext* cx, unsigned a
     args.rval().setUndefined();
     return true;
 }
 
 // For testing gray marking, grayRoot() will heap-allocate an address
 // where we can store a JSObject*, and create a new object if one doesn't
 // already exist.
 //
-// Note that ensureGrayRoot() will automatically blacken the returned object,
+// Note that EnsureGrayRoot() will automatically blacken the returned object,
 // so it will not actually end up marked gray until the following GC clears the
 // black bit (assuming nothing is holding onto it.)
 //
 // The idea is that you can set up a whole graph of objects to be marked gray,
 // hanging off of the object returned from grayRoot(). Then you GC to clear the
 // black bits and set the gray bits.
 //
 // To test grayness, register the objects of interest with addMarkObservers(),