Bug 1326507, trace after traverse, r=mccr8
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Tue, 03 Jan 2017 21:46:49 +0200
changeset 375159 4bc85edeec992aa769d30ea0ccfd77b2b6b3cd16
parent 375158 537d724082803d09b1c783b917383dd33e9e3257
child 375160 910c551b4d72866775aa6ff9a4dd024b266a06c9
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1326507
milestone53.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 1326507, trace after traverse, r=mccr8
dom/base/nsWrapperCache.cpp
xpcom/base/nsCycleCollector.cpp
xpcom/base/nsCycleCollectorTraceJSHelpers.cpp
xpcom/glue/nsCycleCollectionParticipant.h
--- a/dom/base/nsWrapperCache.cpp
+++ b/dom/base/nsWrapperCache.cpp
@@ -128,17 +128,17 @@ nsWrapperCache::CheckCCWrapperTraversal(
   }
 
   DebugWrapperTraversalCallback callback(wrapper);
 
   // The CC traversal machinery cannot trigger GC; however, the analysis cannot
   // see through the COM layer, so we use a suppression to help it.
   JS::AutoSuppressGCAnalysis suppress;
 
-  aTracer->Traverse(aScriptObjectHolder, callback);
+  aTracer->TraverseNativeAndJS(aScriptObjectHolder, callback);
   MOZ_ASSERT(callback.mFound,
              "Cycle collection participant didn't traverse to preserved "
              "wrapper! This will probably crash.");
 
   callback.mFound = false;
   aTracer->Trace(aScriptObjectHolder,
                  TraceCallbackFunc(DebugWrapperTraceCallback), &callback);
   MOZ_ASSERT(callback.mFound,
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2274,17 +2274,17 @@ CCGraphBuilder::BuildGraph(SliceBudget& 
 
     mCurrPi = pi;
 
     // We need to call SetFirstChild() even on deleted nodes, to set their
     // firstChild() that may be read by a prior non-deleted neighbor.
     SetFirstChild();
 
     if (pi->mParticipant) {
-      nsresult rv = pi->mParticipant->Traverse(pi->mPointer, *this);
+      nsresult rv = pi->mParticipant->TraverseNativeAndJS(pi->mPointer, *this);
       MOZ_RELEASE_ASSERT(!NS_FAILED(rv), "Cycle collector Traverse method failed");
     }
 
     if (mCurrNode->AtBlockEnd()) {
       SetLastChild();
     }
 
     aBudget.step(kStep);
@@ -2548,17 +2548,17 @@ ChildFinder::NoteJSChild(const JS::GCCel
     mMayHaveChild = true;
   }
 }
 
 static bool
 MayHaveChild(void* aObj, nsCycleCollectionParticipant* aCp)
 {
   ChildFinder cf;
-  aCp->Traverse(aObj, cf);
+  aCp->TraverseNativeAndJS(aObj, cf);
   return cf.MayHaveChild();
 }
 
 // JSPurpleBuffer keeps references to GCThings which might affect the
 // next cycle collection. It is owned only by itself and during unlink its
 // self reference is broken down and the object ends up killing itself.
 // If GC happens before CC, references to GCthings and the self reference are
 // removed.
--- a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp
+++ b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp
@@ -16,18 +16,19 @@ CycleCollectionNoteEdgeNameImpl(nsCycleC
   nsAutoCString arrayEdgeName(aName);
   if (aFlags & CycleCollectionEdgeNameArrayFlag) {
     arrayEdgeName.AppendLiteral("[i]");
   }
   aCallback.NoteNextEdgeName(arrayEdgeName.get());
 }
 
 void
-nsScriptObjectTracer::NoteJSChild(JS::GCCellPtr aGCThing, const char* aName,
-                                  void* aClosure)
+nsCycleCollectionParticipant::NoteJSChild(JS::GCCellPtr aGCThing,
+                                          const char* aName,
+                                          void* aClosure)
 {
   nsCycleCollectionTraversalCallback* cb =
     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, aName);
   if (mozilla::AddToCCKind(aGCThing.kind())) {
     cb->NoteJSChild(aGCThing);
   }
 }
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -108,21 +108,48 @@ private:
 };
 
 /**
  * Participant implementation classes
  */
 class NS_NO_VTABLE nsCycleCollectionParticipant
 {
 public:
-  constexpr nsCycleCollectionParticipant() : mMightSkip(false) {}
-  constexpr explicit nsCycleCollectionParticipant(bool aSkip) : mMightSkip(aSkip) {}
+  constexpr nsCycleCollectionParticipant()
+    : mMightSkip(false)
+    , mTraverseShouldTrace(false)
+  {
+  }
+
+  constexpr explicit nsCycleCollectionParticipant(bool aSkip,
+                                                  bool aTraverseShouldTrace = false)
+    : mMightSkip(aSkip)
+    , mTraverseShouldTrace(aTraverseShouldTrace)
+  {
+  }
 
   NS_IMETHOD Traverse(void* aPtr, nsCycleCollectionTraversalCallback& aCb) = 0;
 
+  nsresult TraverseNativeAndJS(void* aPtr,
+                               nsCycleCollectionTraversalCallback& aCb)
+  {
+    nsresult rv = Traverse(aPtr, aCb);
+    if (mTraverseShouldTrace) {
+      // Note, we always call Trace, even if Traverse returned
+      // NS_SUCCESS_INTERRUPTED_TRAVERSE.
+      TraceCallbackFunc noteJsChild(&nsCycleCollectionParticipant::NoteJSChild);
+      Trace(aPtr, noteJsChild, &aCb);
+    }
+    return rv;
+  }
+
+    // Implemented in nsCycleCollectorTraceJSHelpers.cpp.
+  static void NoteJSChild(JS::GCCellPtr aGCThing, const char* aName,
+                          void* aClosure);
+
   NS_IMETHOD_(void) Root(void* aPtr) = 0;
   NS_IMETHOD_(void) Unlink(void* aPtr) = 0;
   NS_IMETHOD_(void) Unroot(void* aPtr) = 0;
   NS_IMETHOD_(const char*) ClassName() = 0;
 
   NS_IMETHOD_(void) Trace(void* aPtr, const TraceCallbacks& aCb,
                           void* aClosure) {}
 
@@ -167,36 +194,34 @@ protected:
   NS_IMETHOD_(bool) CanSkipThisReal(void* aPtr)
   {
     NS_ASSERTION(false, "Forgot to implement CanSkipThisReal?");
     return false;
   }
 
 private:
   const bool mMightSkip;
+  const bool mTraverseShouldTrace;
 };
 
 class NS_NO_VTABLE nsScriptObjectTracer : public nsCycleCollectionParticipant
 {
 public:
   constexpr nsScriptObjectTracer()
-    : nsCycleCollectionParticipant(false)
+    : nsCycleCollectionParticipant(false, true)
   {
   }
   constexpr explicit nsScriptObjectTracer(bool aSkip)
-    : nsCycleCollectionParticipant(aSkip)
+    : nsCycleCollectionParticipant(aSkip, true)
   {
   }
 
   NS_IMETHOD_(void) Trace(void* aPtr, const TraceCallbacks& aCb,
                           void* aClosure) override = 0;
 
-  // Implemented in nsCycleCollectorTraceJSHelpers.cpp.
-  static void NoteJSChild(JS::GCCellPtr aGCThing, const char* aName,
-                          void* aClosure);
 };
 
 class NS_NO_VTABLE nsXPCOMCycleCollectionParticipant : public nsScriptObjectTracer
 {
 public:
   constexpr nsXPCOMCycleCollectionParticipant()
     : nsScriptObjectTracer(false)
   {
@@ -436,20 +461,16 @@ DowncastCCParticipant(void* aPtr)
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE(...)                                 \
   MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                              \
   MOZ_FOR_EACH(NS_IMPL_CYCLE_COLLECTION_TRAVERSE_HELPER, (), (__VA_ARGS__))
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(_field)                       \
   CycleCollectionNoteChild(cb, tmp->_field, #_field);
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS                       \
-  {                                                                            \
-  TraceCallbackFunc noteJsChild(&nsScriptObjectTracer::NoteJSChild);           \
-  Trace(p, noteJsChild, &cb);                                                  \
-  }
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                                  \
     (void)tmp;                                                                 \
     return NS_OK;                                                              \
   }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Helpers for implementing nsScriptObjectTracer::Trace