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 71410 6c24a513319a1343ffa6782c1542160b6658ddc9
parent 71409 91dd5412cd4f999e8d470cdb47d0e781f3b780af
child 71411 3f40708323d91f38ff529008d05ad31206e01bc1
push id159
push usereakhgari@mozilla.com
push dateTue, 16 Aug 2011 17:53:11 +0000
treeherdermozilla-beta@8786e3e49240 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs658386
milestone7.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 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;
         }