Bug 727604 - add release assertions to investigate cycle collector crashes. r=smaug
authorAndrew McCreight <amccreight@mozilla.com>
Mon, 20 Feb 2012 12:13:29 -0800
changeset 88761 096697e2beab9af9069f0f4c6897cefb6ace5f84
parent 88760 b59f89947b54fbb7f2cc47ed43622d9422784ea6
child 88762 8ee6310cecda70be036be4eadd436735677d0898
push id975
push userffxbld
push dateTue, 13 Mar 2012 21:39:16 +0000
treeherdermozilla-aurora@99faebf9dc36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs727604
milestone13.0a1
Bug 727604 - add release assertions to investigate cycle collector crashes. r=smaug
xpcom/base/nsCycleCollector.cpp
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -198,16 +198,23 @@ extern DWORD gTLSThreadIDIndex;
 extern NS_TLS mozilla::threads::ID gTLSThreadID;
 #else
 PRThread* gCycleCollectorThread = nsnull;
 #endif
 
 // If true, always log cycle collector graphs.
 const bool gAlwaysLogCCGraphs = false;
 
+MOZ_NEVER_INLINE void
+CC_AbortIfNull(void *ptr)
+{
+    if (!ptr)
+        MOZ_Assert("ptr was null", __FILE__, __LINE__);
+}
+
 // Various parameters of this collector can be tuned using environment
 // variables.
 
 struct nsCycleCollectorParams
 {
     bool mDoNothing;
     bool mLogGraphs;
 #ifdef DEBUG_CC
@@ -1367,50 +1374,55 @@ nsCycleCollectionXPCOMRuntime::ToPartici
 {
     nsXPCOMCycleCollectionParticipant *cp;
     ::ToParticipant(static_cast<nsISupports*>(p), &cp);
     return cp;
 }
 
 
 template <class Visitor>
-void
+MOZ_NEVER_INLINE void
 GraphWalker<Visitor>::Walk(PtrInfo *s0)
 {
     nsDeque queue;
+    CC_AbortIfNull(s0);
     queue.Push(s0);
     DoWalk(queue);
 }
 
 template <class Visitor>
-void
+MOZ_NEVER_INLINE void
 GraphWalker<Visitor>::WalkFromRoots(GCGraph& aGraph)
 {
     nsDeque queue;
     NodePool::Enumerator etor(aGraph.mNodes);
     for (PRUint32 i = 0; i < aGraph.mRootCount; ++i) {
-        queue.Push(etor.GetNext());
+        PtrInfo *pi = etor.GetNext();
+        CC_AbortIfNull(pi);
+        queue.Push(pi);
     }
     DoWalk(queue);
 }
 
 template <class Visitor>
-void
+MOZ_NEVER_INLINE void
 GraphWalker<Visitor>::DoWalk(nsDeque &aQueue)
 {
     // Use a aQueue to match the breadth-first traversal used when we
     // built the graph, for hopefully-better locality.
     while (aQueue.GetSize() > 0) {
         PtrInfo *pi = static_cast<PtrInfo*>(aQueue.PopFront());
+        CC_AbortIfNull(pi);
 
         if (mVisitor.ShouldVisitNode(pi)) {
             mVisitor.VisitNode(pi);
             for (EdgePool::Iterator child = pi->FirstChild(),
                                 child_end = pi->LastChild();
                  child != child_end; ++child) {
+                CC_AbortIfNull(*child);
                 aQueue.Push(*child);
             }
         }
     };
 
 #ifdef DEBUG_CC
     sCollector->mStats.mWalkedGraph++;
 #endif
@@ -1877,17 +1889,17 @@ GCGraphBuilder::AddNode(void *s, nsCycle
     } else {
         result = e->mNode;
         NS_ASSERTION(result->mParticipant == aParticipant,
                      "nsCycleCollectionParticipant shouldn't change!");
     }
     return result;
 }
 
-void
+MOZ_NEVER_INLINE void
 GCGraphBuilder::Traverse(PtrInfo* aPtrInfo)
 {
     mCurrPi = aPtrInfo;
 
 #ifdef DEBUG_CC
     if (!mCurrPi->mParticipant) {
         Fault("unknown pointer during walk", aPtrInfo);
         return;
@@ -2208,25 +2220,26 @@ nsCycleCollector::ForgetSkippable()
         obs->NotifyObservers(nsnull, "cycle-collector-forget-skippable", nsnull);
     }
     mPurpleBuf.RemoveSkippable();
     if (mForgetSkippableCB) {
         mForgetSkippableCB();
     }
 }
 
-void
+MOZ_NEVER_INLINE void
 nsCycleCollector::MarkRoots(GCGraphBuilder &builder)
 {
     mGraph.mRootCount = builder.Count();
 
     // read the PtrInfo out of the graph that we are building
     NodePool::Enumerator queue(mGraph.mNodes);
     while (!queue.IsDone()) {
         PtrInfo *pi = queue.GetNext();
+        CC_AbortIfNull(pi);
         builder.Traverse(pi);
         if (queue.AtBlockEnd())
             builder.SetLastChild();
     }
     if (mGraph.mRootCount > 0)
         builder.SetLastChild();
 }
 
@@ -2243,17 +2256,17 @@ struct ScanBlackVisitor
     {
     }
 
     bool ShouldVisitNode(PtrInfo const *pi)
     { 
         return pi->mColor != black;
     }
 
-    void VisitNode(PtrInfo *pi)
+    MOZ_NEVER_INLINE void VisitNode(PtrInfo *pi)
     {
         if (pi->mColor == white)
             --mWhiteNodeCount;
         pi->mColor = black;
 #ifdef DEBUG_CC
         sCollector->mStats.mSetColorBlack++;
 #endif
     }
@@ -2268,17 +2281,17 @@ struct scanVisitor
     {
     }
 
     bool ShouldVisitNode(PtrInfo const *pi)
     { 
         return pi->mColor == grey;
     }
 
-    void VisitNode(PtrInfo *pi)
+    MOZ_NEVER_INLINE void VisitNode(PtrInfo *pi)
     {
         if (pi->mInternalRefs > pi->mRefCount && pi->mRefCount > 0)
             Fault("traversed refs exceed refcount", pi);
 
         if (pi->mInternalRefs == pi->mRefCount || pi->mRefCount == 0) {
             pi->mColor = white;
             ++mWhiteNodeCount;
 #ifdef DEBUG_CC