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 87247 096697e2beab9af9069f0f4c6897cefb6ace5f84
parent 87246 b59f89947b54fbb7f2cc47ed43622d9422784ea6
child 87248 8ee6310cecda70be036be4eadd436735677d0898
push id22103
push userbmo@edmorley.co.uk
push dateTue, 21 Feb 2012 12:01:45 +0000
treeherdermozilla-central@4038ffaa5d82 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs727604
milestone13.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 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