Bug 658386 - part 1: eliminate mLastChild field from PtrInfo. r=peterv
authorAndrew McCreight <amccreight@mozilla.com>
Thu, 09 Jun 2011 14:55:04 -0700
changeset 70895 6c24a513319a1343ffa6782c1542160b6658ddc9
parent 70894 91dd5412cd4f999e8d470cdb47d0e781f3b780af
child 70896 3f40708323d91f38ff529008d05ad31206e01bc1
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerspeterv
bugs658386
milestone7.0a1
Bug 658386 - part 1: eliminate mLastChild field from PtrInfo. r=peterv
xpcom/base/nsCycleCollector.cpp
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -464,19 +464,20 @@ enum NodeColor { black, white, grey };
 
 struct PtrInfo
 {
     void *mPointer;
     nsCycleCollectionParticipant *mParticipant;
     PRUint32 mColor : 2;
     PRUint32 mInternalRefs : 30;
     PRUint32 mRefCount;
-    EdgePool::Iterator mFirstChild; // first
-    EdgePool::Iterator mLastChild; // one after last
-
+private:
+    EdgePool::Iterator mFirstChild;
+
+public:
 #ifdef DEBUG_CC
     size_t mBytes;
     char *mName;
     PRUint32 mLangID;
 
     // For finding roots in ExplainLiveExpectedGarbage (when there are
     // missing calls to suspect or failures to unlink).
     PRUint32 mSCCIndex; // strongly connected component
@@ -493,18 +494,17 @@ struct PtrInfo
     PtrInfo(void *aPointer, nsCycleCollectionParticipant *aParticipant
             IF_DEBUG_CC_PARAM(PRUint32 aLangID)
             )
         : mPointer(aPointer),
           mParticipant(aParticipant),
           mColor(grey),
           mInternalRefs(0),
           mRefCount(0),
-          mFirstChild(),
-          mLastChild()
+          mFirstChild()
 #ifdef DEBUG_CC
         , mBytes(0),
           mName(nsnull),
           mLangID(aLangID),
           mSCCIndex(0),
           mReversedEdges(nsnull),
           mShortestPathToExpectedGarbage(nsnull),
           mShortestPathToExpectedGarbageEdgeName(nsnull)
@@ -518,16 +518,38 @@ struct PtrInfo
         mEdgeNames.~nsTArray<nsCString>();
     }
 #endif
 
     // Allow NodePool::Block's constructor to compile.
     PtrInfo() {
         NS_NOTREACHED("should never be called");
     }
+
+    EdgePool::Iterator FirstChild()
+    {
+        return mFirstChild;
+    }
+
+    // this PtrInfo must be part of a NodePool
+    EdgePool::Iterator LastChild()
+    {
+        return (this + 1)->mFirstChild;
+    }
+
+    void SetFirstChild(EdgePool::Iterator aFirstChild)
+    {
+        mFirstChild = aFirstChild;
+    }
+
+    // this PtrInfo must be part of a NodePool
+    void SetLastChild(EdgePool::Iterator aLastChild)
+    {
+        (this + 1)->mFirstChild = aLastChild;
+    }
 };
 
 /**
  * A structure designed to be used like a linked list of PtrInfo, except
  * that allocates the PtrInfo 32K-at-a-time.
  */
 class NodePool
 {
@@ -537,17 +559,17 @@ private:
     struct Block {
         // We create and destroy Block using NS_Alloc/NS_Free rather
         // than new and delete to avoid calling its constructor and
         // destructor.
         Block() { NS_NOTREACHED("should never be called"); }
         ~Block() { NS_NOTREACHED("should never be called"); }
 
         Block* mNext;
-        PtrInfo mEntries[BlockSize];
+        PtrInfo mEntries[BlockSize + 1]; // +1 to store last child of last node
     };
 
 public:
     NodePool()
         : mBlocks(nsnull),
           mLast(nsnull)
     {
     }
@@ -1164,17 +1186,18 @@ Fault(const char *msg, PtrInfo *pi)
     printf("Fault in cycle collector: %s\n"
            "  while operating on pointer %p %s\n",
            msg, pi->mPointer, pi->mName);
     if (pi->mInternalRefs) {
         printf("  which has internal references from:\n");
         NodePool::Enumerator queue(sCollector->mGraph.mNodes);
         while (!queue.IsDone()) {
             PtrInfo *ppi = queue.GetNext();
-            for (EdgePool::Iterator e = ppi->mFirstChild, e_end = ppi->mLastChild;
+            for (EdgePool::Iterator e = ppi->FirstChild(),
+                                e_end = ppi->LastChild();
                  e != e_end; ++e) {
                 if (*e == pi) {
                     printf("    %p %s\n", ppi->mPointer, ppi->mName);
                 }
             }
         }
     }
 
@@ -1259,18 +1282,18 @@ GraphWalker<Visitor>::DoWalk(nsDeque &aQ
 {
     // 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());
 
         if (mVisitor.ShouldVisitNode(pi)) {
             mVisitor.VisitNode(pi);
-            for (EdgePool::Iterator child = pi->mFirstChild,
-                                child_end = pi->mLastChild;
+            for (EdgePool::Iterator child = pi->FirstChild(),
+                                child_end = pi->LastChild();
                  child != child_end; ++child) {
                 aQueue.Push(*child);
             }
         }
     };
 
 #ifdef DEBUG_CC
     sCollector->mStats.mWalkedGraph++;
@@ -1514,24 +1537,25 @@ GCGraphBuilder::Traverse(PtrInfo* aPtrIn
 
 #ifdef DEBUG_CC
     if (!mCurrPi->mParticipant) {
         Fault("unknown pointer during walk", aPtrInfo);
         return;
     }
 #endif
 
-    mCurrPi->mFirstChild = mEdgeBuilder.Mark();
-    
+    // this is redundant except at the start of a NodePool block
+    mCurrPi->SetFirstChild(mEdgeBuilder.Mark());
+
     nsresult rv = aPtrInfo->mParticipant->Traverse(aPtrInfo->mPointer, *this);
     if (NS_FAILED(rv)) {
         Fault("script pointer traversal failed", aPtrInfo);
     }
 
-    mCurrPi->mLastChild = mEdgeBuilder.Mark();
+    mCurrPi->SetLastChild(mEdgeBuilder.Mark());
 }
 
 NS_IMETHODIMP_(void)
 GCGraphBuilder::NoteXPCOMRoot(nsISupports *root)
 {
     root = canonicalize(root);
     NS_ASSERTION(root,
                  "Don't add objects that don't participate in collection!");
@@ -3022,18 +3046,18 @@ nsCycleCollector::ExplainLiveExpectedGar
                         PtrInfo *root_pi = etor_roots.GetNext();
                         stack.Push(root_pi);
                     }
 
                     while (stack.GetSize() > 0) {
                         PtrInfo *pi = (PtrInfo*)stack.Peek();
                         if (pi->mSCCIndex == INDEX_UNREACHED) {
                             pi->mSCCIndex = INDEX_TRAVERSING;
-                            for (EdgePool::Iterator child = pi->mFirstChild,
-                                                child_end = pi->mLastChild;
+                            for (EdgePool::Iterator child = pi->FirstChild(),
+                                                child_end = pi->LastChild();
                                  child != child_end; ++child) {
                                 stack.Push(*child);
                             }
                         } else {
                             stack.Pop();
                             // Somebody else might have numbered it already
                             // (since this is depth-first, not breadth-first).
                             // This happens if a node is pushed on the stack
@@ -3066,18 +3090,18 @@ nsCycleCollector::ExplainLiveExpectedGar
                 // Mark any white nodes reachable from other components as
                 // grey.
                 {
                     NodePool::Enumerator queue(mGraph.mNodes);
                     while (!queue.IsDone()) {
                         PtrInfo *pi = queue.GetNext();
                         if (pi->mColor != white)
                             continue;
-                        for (EdgePool::Iterator child = pi->mFirstChild,
-                                            child_end = pi->mLastChild;
+                        for (EdgePool::Iterator child = pi->FirstChild(),
+                                            child_end = pi->LastChild();
                              child != child_end; ++child) {
                             if ((*child)->mSCCIndex != pi->mSCCIndex) {
                                 GraphWalker<SetNonRootGreyVisitor>(SetNonRootGreyVisitor()).Walk(*child);
                             }
                         }
                     }
                 }
 
@@ -3129,17 +3153,17 @@ nsCycleCollector::ExplainLiveExpectedGar
 PRBool
 nsCycleCollector::CreateReversedEdges()
 {
     // Count the edges in the graph.
     PRUint32 edgeCount = 0;
     NodePool::Enumerator countQueue(mGraph.mNodes);
     while (!countQueue.IsDone()) {
         PtrInfo *pi = countQueue.GetNext();
-        for (EdgePool::Iterator e = pi->mFirstChild, e_end = pi->mLastChild;
+        for (EdgePool::Iterator e = pi->FirstChild(), e_end = pi->LastChild();
              e != e_end; ++e, ++edgeCount) {
         }
     }
 
     // Allocate a pool to hold all of the edges.
     mGraph.mReversedEdges = new ReversedEdge[edgeCount];
     if (mGraph.mReversedEdges == nsnull) {
         NS_NOTREACHED("allocation failure creating reversed edges");
@@ -3147,17 +3171,17 @@ nsCycleCollector::CreateReversedEdges()
     }
 
     // Fill in the reversed edges by scanning all forward edges.
     ReversedEdge *current = mGraph.mReversedEdges;
     NodePool::Enumerator buildQueue(mGraph.mNodes);
     while (!buildQueue.IsDone()) {
         PtrInfo *pi = buildQueue.GetNext();
         PRInt32 i = 0;
-        for (EdgePool::Iterator e = pi->mFirstChild, e_end = pi->mLastChild;
+        for (EdgePool::Iterator e = pi->FirstChild(), e_end = pi->LastChild();
              e != e_end; ++e) {
             current->mTarget = pi;
             current->mEdgeName = &pi->mEdgeNames[i];
             current->mNext = (*e)->mReversedEdges;
             (*e)->mReversedEdges = current;
             ++current;
             ++i;
         }