Bug 935721, part 9 - Move mPtrToNodeMap into GCGraph. r=smaug
authorAndrew McCreight <continuation@gmail.com>
Wed, 20 Nov 2013 14:35:17 -0800
changeset 156642 e48c498dbe1814be0e49ac5ccd947f5516f5160f
parent 156641 374376d6e85e12a9d9e793706c7573414ee9a283
child 156643 e597cdb674ea2a41d8616a0c8b28a73f69f4a845
push id36488
push useramccreight@mozilla.com
push dateWed, 20 Nov 2013 22:36:15 +0000
treeherdermozilla-inbound@e597cdb674ea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs935721
milestone28.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 935721, part 9 - Move mPtrToNodeMap into GCGraph. r=smaug With ICC, we may have to remove things from the graph after we have finished building the graph, so move the mapping to graph addresses into the graph itself to create a more self-contained structure.
xpcom/base/nsCycleCollector.cpp
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -572,16 +572,45 @@ public:
     }
 
 private:
     Block *mBlocks;
     PtrInfo *mLast;
 };
 
 
+// Declarations for mPtrToNodeMap.
+
+struct PtrToNodeEntry : public PLDHashEntryHdr
+{
+    // The key is mNode->mPointer
+    PtrInfo *mNode;
+};
+
+static bool
+PtrToNodeMatchEntry(PLDHashTable *table,
+                    const PLDHashEntryHdr *entry,
+                    const void *key)
+{
+    const PtrToNodeEntry *n = static_cast<const PtrToNodeEntry*>(entry);
+    return n->mNode->mPointer == key;
+}
+
+static PLDHashTableOps PtrNodeOps = {
+    PL_DHashAllocTable,
+    PL_DHashFreeTable,
+    PL_DHashVoidPtrKeyStub,
+    PtrToNodeMatchEntry,
+    PL_DHashMoveEntryStub,
+    PL_DHashClearEntryStub,
+    PL_DHashFinalizeStub,
+    nullptr
+};
+
+
 struct WeakMapping
 {
     // map and key will be null if the corresponding objects are GC marked
     PtrInfo *mMap;
     PtrInfo *mKey;
     PtrInfo *mKeyDelegate;
     PtrInfo *mVal;
 };
@@ -590,41 +619,93 @@ class GCGraphBuilder;
 
 struct GCGraph
 {
     NodePool mNodes;
     EdgePool mEdges;
     nsTArray<WeakMapping> mWeakMaps;
     uint32_t mRootCount;
 
-    GCGraph() : mRootCount(0) {
+private:
+    PLDHashTable mPtrToNodeMap;
+
+public:
+    GCGraph() : mRootCount(0)
+    {
+        mPtrToNodeMap.ops = nullptr;
     }
-    ~GCGraph() {
+
+    ~GCGraph()
+    {
+        if (mPtrToNodeMap.ops) {
+            PL_DHashTableFinish(&mPtrToNodeMap);
+        }
+    }
+
+    void Init()
+    {
+        MOZ_ASSERT(!mPtrToNodeMap.ops, "Failed to clear mPtrToNodeMap");
+        if (!PL_DHashTableInit(&mPtrToNodeMap, &PtrNodeOps, nullptr,
+                               sizeof(PtrToNodeEntry), 32768)) {
+            MOZ_CRASH();
+        }
     }
 
     void Clear()
     {
         mNodes.Clear();
         mEdges.Clear();
         mWeakMaps.Clear();
         mRootCount = 0;
+        PL_DHashTableFinish(&mPtrToNodeMap);
+        mPtrToNodeMap.ops = nullptr;
+    }
+
+    PtrInfo* FindNode(void *aPtr);
+    PtrToNodeEntry* AddNodeToMap(void *aPtr);
+
+    uint32_t MapCount() const
+    {
+        return mPtrToNodeMap.entryCount;
     }
 
     void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                              size_t *aNodesSize, size_t *aEdgesSize,
                              size_t *aWeakMapsSize) const {
         *aNodesSize = mNodes.SizeOfExcludingThis(aMallocSizeOf);
         *aEdgesSize = mEdges.SizeOfExcludingThis(aMallocSizeOf);
 
         // We don't measure what the WeakMappings point to, because the
         // pointers are non-owning.
         *aWeakMapsSize = mWeakMaps.SizeOfExcludingThis(aMallocSizeOf);
     }
 };
 
+PtrInfo*
+GCGraph::FindNode(void *aPtr)
+{
+    PtrToNodeEntry *e = static_cast<PtrToNodeEntry*>(PL_DHashTableOperate(&mPtrToNodeMap, aPtr, PL_DHASH_LOOKUP));
+    if (!PL_DHASH_ENTRY_IS_BUSY(e)) {
+        return nullptr;
+    }
+    return e->mNode;
+}
+
+PtrToNodeEntry*
+GCGraph::AddNodeToMap(void *aPtr)
+{
+    PtrToNodeEntry *e = static_cast<PtrToNodeEntry*>(PL_DHashTableOperate(&mPtrToNodeMap, aPtr, PL_DHASH_ADD));
+    if (!e) {
+        // Caller should track OOMs
+        return nullptr;
+    }
+    return e;
+}
+
+
 static nsISupports *
 CanonicalizeXPCOMParticipant(nsISupports *in)
 {
     nsISupports* out;
     in->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
                        reinterpret_cast<void**>(&out));
     return out;
 }
@@ -1522,51 +1603,24 @@ nsCycleCollectorLoggerConstructor(nsISup
 
     return logger->QueryInterface(aIID, aInstancePtr);
 }
 
 ////////////////////////////////////////////////////////////////////////
 // Bacon & Rajan's |MarkRoots| routine.
 ////////////////////////////////////////////////////////////////////////
 
-struct PtrToNodeEntry : public PLDHashEntryHdr
-{
-    // The key is mNode->mPointer
-    PtrInfo *mNode;
-};
-
-static bool
-PtrToNodeMatchEntry(PLDHashTable *table,
-                    const PLDHashEntryHdr *entry,
-                    const void *key)
-{
-    const PtrToNodeEntry *n = static_cast<const PtrToNodeEntry*>(entry);
-    return n->mNode->mPointer == key;
-}
-
-static PLDHashTableOps PtrNodeOps = {
-    PL_DHashAllocTable,
-    PL_DHashFreeTable,
-    PL_DHashVoidPtrKeyStub,
-    PtrToNodeMatchEntry,
-    PL_DHashMoveEntryStub,
-    PL_DHashClearEntryStub,
-    PL_DHashFinalizeStub,
-    nullptr
-};
-
 class GCGraphBuilder : public nsCycleCollectionTraversalCallback,
                        public nsCycleCollectionNoteRootCallback
 {
 private:
     GCGraph &mGraph;
     CycleCollectorResults &mResults;
     NodePool::Builder mNodeBuilder;
     EdgePool::Builder mEdgeBuilder;
-    PLDHashTable mPtrToNodeMap;
     PtrInfo *mCurrPi;
     nsCycleCollectionParticipant *mJSParticipant;
     nsCycleCollectionParticipant *mJSZoneParticipant;
     nsCString mNextEdgeName;
     nsICycleCollectorListener *mListener;
     bool mMergeZones;
     bool mRanOutOfMemory;
 
@@ -1578,18 +1632,16 @@ public:
                    bool aMergeZones);
     virtual ~GCGraphBuilder();
 
     bool WantAllTraces() const
     {
         return nsCycleCollectionNoteRootCallback::WantAllTraces();
     }
 
-    uint32_t Count() const { return mPtrToNodeMap.entryCount; }
-
     PtrInfo* AddNode(void *aPtr, nsCycleCollectionParticipant *aParticipant);
     PtrInfo* AddWeakMapNode(void* node);
     void Traverse(PtrInfo* aPtrInfo);
     void SetLastChild();
 
     bool RanOutOfMemory() const { return mRanOutOfMemory; }
 
 private:
@@ -1664,21 +1716,16 @@ GCGraphBuilder::GCGraphBuilder(GCGraph &
       mNodeBuilder(aGraph.mNodes),
       mEdgeBuilder(aGraph.mEdges),
       mJSParticipant(nullptr),
       mJSZoneParticipant(nullptr),
       mListener(aListener),
       mMergeZones(aMergeZones),
       mRanOutOfMemory(false)
 {
-    if (!PL_DHashTableInit(&mPtrToNodeMap, &PtrNodeOps, nullptr,
-                           sizeof(PtrToNodeEntry), 32768)) {
-        MOZ_CRASH();
-    }
-
     if (aJSRuntime) {
         mJSParticipant = aJSRuntime->GCThingParticipant();
         mJSZoneParticipant = aJSRuntime->ZoneParticipant();
     }
 
     uint32_t flags = 0;
     if (!flags && mListener) {
         flags = nsCycleCollectionTraversalCallback::WANT_DEBUG_INFO;
@@ -1695,24 +1742,22 @@ GCGraphBuilder::GCGraphBuilder(GCGraph &
     mMergeZones = mMergeZones && MOZ_LIKELY(!WantAllTraces());
 
     MOZ_ASSERT(nsCycleCollectionNoteRootCallback::WantAllTraces() ==
                nsCycleCollectionTraversalCallback::WantAllTraces());
 }
 
 GCGraphBuilder::~GCGraphBuilder()
 {
-    if (mPtrToNodeMap.ops)
-        PL_DHashTableFinish(&mPtrToNodeMap);
 }
 
 PtrInfo*
 GCGraphBuilder::AddNode(void *aPtr, nsCycleCollectionParticipant *aParticipant)
 {
-    PtrToNodeEntry *e = static_cast<PtrToNodeEntry*>(PL_DHashTableOperate(&mPtrToNodeMap, aPtr, PL_DHASH_ADD));
+    PtrToNodeEntry *e = mGraph.AddNodeToMap(aPtr);
     if (!e) {
         mRanOutOfMemory = true;
         return nullptr;
     }
 
     PtrInfo *result;
     if (!e->mNode) {
         // New entry.
@@ -2139,18 +2184,16 @@ nsCycleCollector::ForgetSkippable(bool a
 MOZ_NEVER_INLINE void
 nsCycleCollector::MarkRoots()
 {
     TimeLog timeLog;
     AutoRestore<bool> ar(mScanInProgress);
     MOZ_ASSERT(!mScanInProgress);
     mScanInProgress = true;
 
-    mGraph.mRootCount = mBuilder->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);
         mBuilder->Traverse(pi);
         if (queue.AtBlockEnd()) {
             mBuilder->SetLastChild();
@@ -2749,16 +2792,17 @@ nsCycleCollector::BeginCollection(ccType
 
     FreeSnowWhite(true);
 
     if (mListener && NS_FAILED(mListener->Begin())) {
         mListener = nullptr;
     }
 
     // Set up the data structures for building the graph.
+    mGraph.Init();
     mResults.Init();
     bool mergeZones = ShouldMergeZones(aCCType);
     mResults.mMergedZones = mergeZones;
 
     MOZ_ASSERT(!mBuilder, "Forgot to clear mBuilder");
     mBuilder = new GCGraphBuilder(mGraph, mResults, mJSRuntime, mListener, mergeZones);
 
     if (mJSRuntime) {
@@ -2766,16 +2810,19 @@ nsCycleCollector::BeginCollection(ccType
         timeLog.Checkpoint("mJSRuntime->BeginCycleCollection()");
     }
 
     AutoRestore<bool> ar(mScanInProgress);
     MOZ_ASSERT(!mScanInProgress);
     mScanInProgress = true;
     mPurpleBuf.SelectPointers(*mBuilder);
     timeLog.Checkpoint("SelectPointers()");
+
+    // We've finished adding roots, and everything in the graph is a root.
+    mGraph.mRootCount = mGraph.MapCount();
 }
 
 uint32_t
 nsCycleCollector::SuspectedCount()
 {
     CheckThreadSafety();
     return mPurpleBuf.Count();
 }