Bug 1491151 - Part 5: Convert content list to use MRU cache. r=smaug
authorEric Rahm <erahm@mozilla.com>
Wed, 12 Sep 2018 18:10:08 -0700
changeset 436855 4a46b4673978475d655cfac84bf71c7ca4d8bfed
parent 436854 c138f6d72ee1065019c86754c5e3b4aa41bb3782
child 436856 5ab4db62dc822625b054a9afec6f065e96ebd771
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 5: Convert content list to use MRU cache. r=smaug
dom/base/nsContentList.cpp
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -20,16 +20,17 @@
 #include "nsGkAtoms.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/NodeListBinding.h"
 #include "mozilla/Likely.h"
 #include "nsGenericHTMLElement.h"
 #include "jsfriendapi.h"
 #include <algorithm>
 #include "mozilla/dom/NodeInfoInlines.h"
+#include "mozilla/MruCache.h"
 
 #include "PLDHashTable.h"
 
 #ifdef DEBUG_CONTENT_LIST
 #include "nsIContentIterator.h"
 #define ASSERT_IN_SYNC AssertInSync()
 #else
 #define ASSERT_IN_SYNC PR_BEGIN_MACRO PR_END_MACRO
@@ -167,25 +168,30 @@ nsIContent*
 nsEmptyContentList::Item(uint32_t aIndex)
 {
   return nullptr;
 }
 
 // Hashtable for storing nsContentLists
 static PLDHashTable* gContentListHashTable;
 
-#define RECENTLY_USED_CONTENT_LIST_CACHE_SIZE 31
-static nsContentList*
-  sRecentlyUsedContentLists[RECENTLY_USED_CONTENT_LIST_CACHE_SIZE] = {};
+struct ContentListCache :
+  public MruCache<nsContentListKey, nsContentList*, ContentListCache>
+{
+  static HashNumber Hash(const nsContentListKey& aKey)
+  {
+    return aKey.GetHash();
+  }
+  static bool Match(const nsContentListKey& aKey, const nsContentList* aVal)
+  {
+    return aVal->MatchesKey(aKey);
+  }
+};
 
-static MOZ_ALWAYS_INLINE uint32_t
-RecentlyUsedCacheIndex(const nsContentListKey& aKey)
-{
-  return aKey.GetHash() % RECENTLY_USED_CONTENT_LIST_CACHE_SIZE;
-}
+static ContentListCache sRecentlyUsedContentLists;
 
 struct ContentListHashEntry : public PLDHashEntryHdr
 {
   nsContentList* mContentList;
 };
 
 static PLDHashNumber
 ContentListHashtableHashKey(const void *key)
@@ -210,20 +216,19 @@ NS_GetContentList(nsINode* aRootNode,
                   int32_t  aMatchNameSpaceId,
                   const nsAString& aTagname)
 {
   NS_ASSERTION(aRootNode, "content list has to have a root");
 
   RefPtr<nsContentList> list;
   nsContentListKey hashKey(aRootNode, aMatchNameSpaceId, aTagname,
                            aRootNode->OwnerDoc()->IsHTMLDocument());
-  uint32_t recentlyUsedCacheIndex = RecentlyUsedCacheIndex(hashKey);
-  nsContentList* cachedList = sRecentlyUsedContentLists[recentlyUsedCacheIndex];
-  if (cachedList && cachedList->MatchesKey(hashKey)) {
-    list = cachedList;
+  auto p = sRecentlyUsedContentLists.Lookup(hashKey);
+  if (p) {
+    list = p.Data();
     return list.forget();
   }
 
   static const PLDHashTableOps hash_table_ops =
   {
     ContentListHashtableHashKey,
     ContentListHashtableMatchEntry,
     PLDHashTable::MoveEntryStub,
@@ -255,17 +260,17 @@ NS_GetContentList(nsINode* aRootNode,
       htmlAtom = xmlAtom;
     }
     list = new nsContentList(aRootNode, aMatchNameSpaceId, htmlAtom, xmlAtom);
     if (entry) {
       entry->mContentList = list;
     }
   }
 
-  sRecentlyUsedContentLists[recentlyUsedCacheIndex] = list;
+  p.Set(list);
   return list.forget();
 }
 
 #ifdef DEBUG
 const nsCacheableFuncStringContentList::ContentListType
   nsCachableElementsByNameNodeList::sType = nsCacheableFuncStringContentList::eNodeList;
 const nsCacheableFuncStringContentList::ContentListType
   nsCacheableFuncStringHTMLCollection::sType = nsCacheableFuncStringContentList::eHTMLCollection;
@@ -923,20 +928,17 @@ nsContentList::RemoveFromHashtable()
 {
   if (mFunc) {
     // This can't be in the table anyway
     return;
   }
 
   nsDependentAtomString str(mXMLMatchAtom);
   nsContentListKey key(mRootNode, mMatchNameSpaceId, str, mIsHTMLDocument);
-  uint32_t recentlyUsedCacheIndex = RecentlyUsedCacheIndex(key);
-  if (sRecentlyUsedContentLists[recentlyUsedCacheIndex] == this) {
-    sRecentlyUsedContentLists[recentlyUsedCacheIndex] = nullptr;
-  }
+  sRecentlyUsedContentLists.Remove(key);
 
   if (!gContentListHashTable)
     return;
 
   gContentListHashTable->Remove(&key);
 
   if (gContentListHashTable->EntryCount() == 0) {
     delete gContentListHashTable;