Bug 1491151 - Part 3: Use MRU cache in NodeInfoManager. r=smaug
authorEric Rahm <erahm@mozilla.com>
Wed, 12 Sep 2018 16:39:43 -0700
changeset 436853 54da92d94f47a87052f9c3ca2927e8df79556804
parent 436852 8248f7b4da44d7c15f4cef9bcd756984b60e90d7
child 436854 c138f6d72ee1065019c86754c5e3b4aa41bb3782
push id34660
push userbtara@mozilla.com
push dateMon, 17 Sep 2018 21:58:52 +0000
treeherdermozilla-central@87a95e1b7ec6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1491151
milestone64.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 1491151 - Part 3: Use MRU cache in NodeInfoManager. r=smaug
dom/base/nsNodeInfoManager.cpp
dom/base/nsNodeInfoManager.h
--- a/dom/base/nsNodeInfoManager.cpp
+++ b/dom/base/nsNodeInfoManager.cpp
@@ -42,17 +42,17 @@ static const uint32_t kInitialNodeInfoHa
 
 nsNodeInfoManager::nsNodeInfoManager()
   : mNodeInfoHash(kInitialNodeInfoHashSize),
     mDocument(nullptr),
     mNonDocumentNodeInfos(0),
     mTextNodeInfo(nullptr),
     mCommentNodeInfo(nullptr),
     mDocumentNodeInfo(nullptr),
-    mRecentlyUsedNodeInfos{},
+    mRecentlyUsedNodeInfos(),
     mSVGEnabled(eTriUnset),
     mMathMLEnabled(eTriUnset)
 {
   nsLayoutStatics::AddRef();
 
   if (gNodeInfoManagerLeakPRLog)
     MOZ_LOG(gNodeInfoManagerLeakPRLog, LogLevel::Debug,
            ("NODEINFOMANAGER %p created", this));
@@ -149,20 +149,19 @@ nsNodeInfoManager::GetNodeInfo(nsAtom *a
                                int32_t aNamespaceID, uint16_t aNodeType,
                                nsAtom* aExtraName /* = nullptr */)
 {
   CheckValidNodeInfo(aNodeType, aName, aNamespaceID, aExtraName);
 
   NodeInfo::NodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType,
                                  aExtraName);
 
-  uint32_t index = tmpKey.Hash() % RECENTLY_USED_NODEINFOS_SIZE;
-  NodeInfo* ni = mRecentlyUsedNodeInfos[index];
-  if (ni && tmpKey == ni->mInner) {
-    RefPtr<NodeInfo> nodeInfo = ni;
+  auto p = mRecentlyUsedNodeInfos.Lookup(tmpKey);
+  if (p) {
+    RefPtr<NodeInfo> nodeInfo = p.Data();
     return nodeInfo.forget();
   }
 
   // We don't use LookupForAdd here as that would end up storing the temporary
   // key instead of using `mInner`.
   RefPtr<NodeInfo> nodeInfo = mNodeInfoHash.Get(&tmpKey);
   if (!nodeInfo) {
     ++mNonDocumentNodeInfos;
@@ -171,17 +170,17 @@ nsNodeInfoManager::GetNodeInfo(nsAtom *a
     }
 
     nodeInfo = new NodeInfo(aName, aPrefix, aNamespaceID, aNodeType, aExtraName, this);
     mNodeInfoHash.Put(&nodeInfo->mInner, nodeInfo);
   }
 
   // Have to do the swap thing, because already_AddRefed<nsNodeInfo>
   // doesn't cast to already_AddRefed<mozilla::dom::NodeInfo>
-  mRecentlyUsedNodeInfos[index] = nodeInfo;
+  p.Set(nodeInfo);
   return nodeInfo.forget();
 }
 
 
 nsresult
 nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsAtom *aPrefix,
                                int32_t aNamespaceID, uint16_t aNodeType,
                                NodeInfo** aNodeInfo)
@@ -191,37 +190,36 @@ nsNodeInfoManager::GetNodeInfo(const nsA
   {
     RefPtr<nsAtom> nameAtom = NS_Atomize(aName);
     CheckValidNodeInfo(aNodeType, nameAtom, aNamespaceID, nullptr);
   }
 #endif
 
   NodeInfo::NodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType);
 
-  uint32_t index = tmpKey.Hash() % RECENTLY_USED_NODEINFOS_SIZE;
-  NodeInfo* ni = mRecentlyUsedNodeInfos[index];
-  if (ni && ni->mInner == tmpKey) {
-    RefPtr<NodeInfo> nodeInfo = ni;
+  auto p = mRecentlyUsedNodeInfos.Lookup(tmpKey);
+  if (p) {
+    RefPtr<NodeInfo> nodeInfo = p.Data();
     nodeInfo.forget(aNodeInfo);
     return NS_OK;
   }
 
   RefPtr<NodeInfo> nodeInfo = mNodeInfoHash.Get(&tmpKey);
   if (!nodeInfo) {
     ++mNonDocumentNodeInfos;
     if (mNonDocumentNodeInfos == 1) {
       NS_IF_ADDREF(mDocument);
     }
 
     RefPtr<nsAtom> nameAtom = NS_Atomize(aName);
     nodeInfo = new NodeInfo(nameAtom, aPrefix, aNamespaceID, aNodeType, nullptr, this);
     mNodeInfoHash.Put(&nodeInfo->mInner, nodeInfo);
   }
 
-  mRecentlyUsedNodeInfos[index] = nodeInfo;
+  p.Set(nodeInfo);
   nodeInfo.forget(aNodeInfo);
 
   return NS_OK;
 }
 
 
 nsresult
 nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsAtom *aPrefix,
@@ -336,21 +334,17 @@ nsNodeInfoManager::RemoveNodeInfo(NodeIn
     if (aNodeInfo == mTextNodeInfo) {
       mTextNodeInfo = nullptr;
     }
     else if (aNodeInfo == mCommentNodeInfo) {
       mCommentNodeInfo = nullptr;
     }
   }
 
-  uint32_t index = aNodeInfo->mInner.Hash() % RECENTLY_USED_NODEINFOS_SIZE;
-  if (mRecentlyUsedNodeInfos[index] == aNodeInfo) {
-    mRecentlyUsedNodeInfos[index] = nullptr;
-  }
-
+  mRecentlyUsedNodeInfos.Remove(aNodeInfo->mInner);
   DebugOnly<bool> ret = mNodeInfoHash.Remove(&aNodeInfo->mInner);
   MOZ_ASSERT(ret, "Can't find mozilla::dom::NodeInfo to remove!!!");
 }
 
 bool
 nsNodeInfoManager::InternalSVGEnabled()
 {
   // If the svg.disabled pref. is true, convert all SVG nodes into
--- a/dom/base/nsNodeInfoManager.h
+++ b/dom/base/nsNodeInfoManager.h
@@ -8,30 +8,29 @@
  * A class for handing out nodeinfos and ensuring sharing of them as needed.
  */
 
 #ifndef nsNodeInfoManager_h___
 #define nsNodeInfoManager_h___
 
 #include "mozilla/Attributes.h"           // for final
 #include "mozilla/dom/NodeInfo.h"
+#include "mozilla/MruCache.h"
 #include "nsCOMPtr.h"                     // for member
 #include "nsCycleCollectionParticipant.h" // for NS_DECL_CYCLE_*
 #include "nsDataHashtable.h"
 #include "nsStringFwd.h"
 
 class nsBindingManager;
 class nsAtom;
 class nsIDocument;
 class nsIPrincipal;
 class nsWindowSizes;
 template<class T> struct already_AddRefed;
 
-#define RECENTLY_USED_NODEINFOS_SIZE 31
-
 class nsNodeInfoManager final
 {
 private:
   ~nsNodeInfoManager();
 
 public:
   nsNodeInfoManager();
 
@@ -149,23 +148,40 @@ private:
   {
   public:
     explicit NodeInfoInnerKey(KeyTypePointer aKey) : nsPtrHashKey(aKey) {}
     ~NodeInfoInnerKey() = default;
     bool KeyEquals(KeyTypePointer aKey) const { return *mKey == *aKey; }
     static PLDHashNumber HashKey(KeyTypePointer aKey) { return aKey->Hash(); }
   };
 
+  struct NodeInfoCache : public mozilla::MruCache<
+                              mozilla::dom::NodeInfo::NodeInfoInner,
+                              mozilla::dom::NodeInfo*,
+                              NodeInfoCache>
+  {
+    static mozilla::HashNumber Hash(
+        const mozilla::dom::NodeInfo::NodeInfoInner& aKey)
+    {
+      return aKey.Hash();
+    }
+    static bool Match(const mozilla::dom::NodeInfo::NodeInfoInner& aKey,
+                      const mozilla::dom::NodeInfo* aVal)
+    {
+      return aKey == aVal->mInner;
+    }
+  };
+
   nsDataHashtable<NodeInfoInnerKey, mozilla::dom::NodeInfo*> mNodeInfoHash;
   nsIDocument * MOZ_NON_OWNING_REF mDocument; // WEAK
   uint32_t mNonDocumentNodeInfos;
   nsCOMPtr<nsIPrincipal> mPrincipal; // Never null after Init() succeeds.
   nsCOMPtr<nsIPrincipal> mDefaultPrincipal; // Never null after Init() succeeds
   mozilla::dom::NodeInfo * MOZ_NON_OWNING_REF mTextNodeInfo; // WEAK to avoid circular ownership
   mozilla::dom::NodeInfo * MOZ_NON_OWNING_REF mCommentNodeInfo; // WEAK to avoid circular ownership
   mozilla::dom::NodeInfo * MOZ_NON_OWNING_REF mDocumentNodeInfo; // WEAK to avoid circular ownership
   RefPtr<nsBindingManager> mBindingManager;
-  mozilla::dom::NodeInfo* mRecentlyUsedNodeInfos[RECENTLY_USED_NODEINFOS_SIZE];
+  NodeInfoCache mRecentlyUsedNodeInfos;
   Tri mSVGEnabled;
   Tri mMathMLEnabled;
 };
 
 #endif /* nsNodeInfoManager_h___ */