Bug 1363640 Part 5 - Add a table in nsXULPrototypeCache to cache XBL documents with servo backend. r=bz,heycam
authorTing-Yu Lin <tlin@mozilla.com>
Fri, 19 May 2017 15:18:00 -0700
changeset 408593 99a6bbeaabef6867077a965acbbfc3c594d23ff3
parent 408592 c2b029d533056f58bbd48a82d64cdeb971270fff
child 408594 7f72289a5cabb3323f1ab4cdbef0306ef6c81ffd
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, heycam
bugs1363640
milestone55.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 1363640 Part 5 - Add a table in nsXULPrototypeCache to cache XBL documents with servo backend. r=bz,heycam We assume those XBL documents without a bound document use gecko style backend. Their backend type will be explicitly set when loading in Part 6. MozReview-Commit-ID: 5c5xtYFvgAD
dom/xbl/nsXBLDocumentInfo.h
dom/xbl/nsXBLService.cpp
dom/xul/nsXULPrototypeCache.cpp
dom/xul/nsXULPrototypeCache.h
--- a/dom/xbl/nsXBLDocumentInfo.h
+++ b/dom/xbl/nsXBLDocumentInfo.h
@@ -18,18 +18,17 @@ class nsXBLPrototypeBinding;
 
 class nsXBLDocumentInfo final : public nsSupportsWeakReference
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   explicit nsXBLDocumentInfo(nsIDocument* aDocument);
 
-  already_AddRefed<nsIDocument> GetDocument()
-    { nsCOMPtr<nsIDocument> copy = mDocument; return copy.forget(); }
+  nsIDocument* GetDocument() const { return mDocument; }
 
   bool GetScriptAccess() const { return mScriptAccess; }
 
   nsIURI* DocumentURI() { return mDocument->GetDocumentURI(); }
 
   nsXBLPrototypeBinding* GetPrototypeBinding(const nsACString& aRef);
   nsresult SetPrototypeBinding(const nsACString& aRef,
                                nsXBLPrototypeBinding* aBinding);
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -946,19 +946,26 @@ nsXBLService::LoadBindingDocumentInfo(ns
 
 #ifdef MOZ_XUL
   // The second line of defense is the global nsXULPrototypeCache,
   // if it's being used.
   nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
   bool useXULCache = cache && cache->IsEnabled();
 
   if (!info && useXULCache) {
+    // Assume Gecko style backend for the XBL document without a bound
+    // document. The only case is loading platformHTMLBindings.xml which
+    // doesn't have any style sheets or style attributes.
+    StyleBackendType styleBackend
+      = aBoundDocument ? aBoundDocument->GetStyleBackendType()
+                       : StyleBackendType::Gecko;
+
     // This cache crosses the entire product, so that any XBL bindings that are
     // part of chrome will be reused across all XUL documents.
-    info = cache->GetXBLDocumentInfo(documentURI);
+    info = cache->GetXBLDocumentInfo(documentURI, styleBackend);
   }
 
   bool useStartupCache = useXULCache && IsChromeOrResourceURI(documentURI);
 
   if (!info) {
     // Next, look in the startup cache
     if (!info && useStartupCache) {
       rv = nsXBLDocumentInfo::ReadPrototypeBindings(documentURI, getter_AddRefs(info));
@@ -1011,16 +1018,22 @@ nsXBLService::LoadBindingDocumentInfo(ns
     // before, it can continue to use it even if the XUL prototype
     // cache gets flushed. That way, if a flush does occur, we
     // don't get into a weird state where we're using different
     // XBLDocumentInfos for the same XBL document in a single
     // document that has loaded some bindings.
     bindingManager->PutXBLDocumentInfo(info);
   }
 
+  MOZ_ASSERT(!aBoundDocument || !info ||
+             aBoundDocument->GetStyleBackendType() ==
+               info->GetDocument()->GetStyleBackendType(),
+             "Style backend type mismatched between the bound document and "
+             "the XBL document loaded.");
+
   info.forget(aResult);
 
   return NS_OK;
 }
 
 nsresult
 nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument,
                                    nsIURI* aDocumentURI, nsIURI* aBindingURI,
--- a/dom/xul/nsXULPrototypeCache.cpp
+++ b/dom/xul/nsXULPrototypeCache.cpp
@@ -233,77 +233,90 @@ nsXULPrototypeCache::PutScript(nsIURI* a
     }
 #endif
 
     mScriptTable.Put(aURI, aScriptObject);
 
     return NS_OK;
 }
 
+nsXBLDocumentInfo*
+nsXULPrototypeCache::GetXBLDocumentInfo(nsIURI* aURL,
+                                        StyleBackendType aType)
+{
+  MOZ_ASSERT(aType != StyleBackendType::None,
+             "Please use either gecko or servo when looking up for the cache!");
+  return XBLDocTableFor(aType).GetWeak(aURL);
+}
+
 nsresult
 nsXULPrototypeCache::PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo)
 {
-    nsIURI* uri = aDocumentInfo->DocumentURI();
+  nsIURI* uri = aDocumentInfo->DocumentURI();
+  XBLDocTable& table =
+    XBLDocTableFor(aDocumentInfo->GetDocument()->GetStyleBackendType());
 
-    RefPtr<nsXBLDocumentInfo> info;
-    mXBLDocTable.Get(uri, getter_AddRefs(info));
-    if (!info) {
-        mXBLDocTable.Put(uri, aDocumentInfo);
-    }
-    return NS_OK;
+  nsXBLDocumentInfo* info = table.GetWeak(uri);
+  if (!info) {
+    table.Put(uri, aDocumentInfo);
+  }
+  return NS_OK;
 }
 
 void
 nsXULPrototypeCache::FlushSkinFiles()
 {
-  // Flush out skin XBL files from the cache.
-  for (auto iter = mXBLDocTable.Iter(); !iter.Done(); iter.Next()) {
-    nsAutoCString str;
-    iter.Key()->GetPath(str);
-    if (strncmp(str.get(), "/skin", 5) == 0) {
-      iter.Remove();
+  StyleBackendType tableTypes[] = { StyleBackendType::Gecko,
+                                    StyleBackendType::Servo };
+
+  for (auto tableType : tableTypes) {
+    // Flush out skin XBL files from the cache.
+    XBLDocTable& xblDocTable = XBLDocTableFor(tableType);
+    for (auto iter = xblDocTable.Iter(); !iter.Done(); iter.Next()) {
+      nsAutoCString str;
+      iter.Key()->GetPath(str);
+      if (strncmp(str.get(), "/skin", 5) == 0) {
+        iter.Remove();
+      }
     }
-  }
 
-  // Now flush out our skin stylesheets from the cache.
-  mozilla::StyleBackendType tableTypes[] = { StyleBackendType::Gecko,
-                                             StyleBackendType::Servo };
-  for (auto tableType : tableTypes) {
+    // Now flush out our skin stylesheets from the cache.
     StyleSheetTable& table = StyleSheetTableFor(tableType);
     for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
       nsAutoCString str;
       iter.Data()->GetSheetURI()->GetPath(str);
       if (strncmp(str.get(), "/skin", 5) == 0) {
         iter.Remove();
       }
     }
-  }
 
-  // Iterate over all the remaining XBL and make sure cached
-  // scoped skin stylesheets are flushed and refetched by the
-  // prototype bindings.
-  for (auto iter = mXBLDocTable.Iter(); !iter.Done(); iter.Next()) {
-    iter.Data()->FlushSkinStylesheets();
+    // Iterate over all the remaining XBL and make sure cached
+    // scoped skin stylesheets are flushed and refetched by the
+    // prototype bindings.
+    for (auto iter = xblDocTable.Iter(); !iter.Done(); iter.Next()) {
+      iter.Data()->FlushSkinStylesheets();
+    }
   }
 }
 
 void
 nsXULPrototypeCache::FlushScripts()
 {
     mScriptTable.Clear();
 }
 
 void
 nsXULPrototypeCache::Flush()
 {
     mPrototypeTable.Clear();
     mScriptTable.Clear();
     mGeckoStyleSheetTable.Clear();
     mServoStyleSheetTable.Clear();
-    mXBLDocTable.Clear();
+    mGeckoXBLDocTable.Clear();
+    mServoXBLDocTable.Clear();
 }
 
 
 bool
 nsXULPrototypeCache::IsEnabled()
 {
     return !gDisableXULCache;
 }
@@ -588,18 +601,24 @@ nsXULPrototypeCache::BeginCaching(nsIURI
     }
 
     return NS_OK;
 }
 
 void
 nsXULPrototypeCache::MarkInCCGeneration(uint32_t aGeneration)
 {
-    for (auto iter = mXBLDocTable.Iter(); !iter.Done(); iter.Next()) {
-        iter.Data()->MarkInCCGeneration(aGeneration);
+    StyleBackendType tableTypes[] = { StyleBackendType::Gecko,
+                                      StyleBackendType::Servo };
+
+    for (auto tableType : tableTypes) {
+        XBLDocTable& xblDocTable = XBLDocTableFor(tableType);
+        for (auto iter = xblDocTable.Iter(); !iter.Done(); iter.Next()) {
+            iter.Data()->MarkInCCGeneration(aGeneration);
+        }
     }
     for (auto iter = mPrototypeTable.Iter(); !iter.Done(); iter.Next()) {
         iter.Data()->MarkInCCGeneration(aGeneration);
     }
 }
 
 void
 nsXULPrototypeCache::MarkInGC(JSTracer* aTrc)
--- a/dom/xul/nsXULPrototypeCache.h
+++ b/dom/xul/nsXULPrototypeCache.h
@@ -60,19 +60,19 @@ public:
     // from the cache.
 
     nsXULPrototypeDocument* GetPrototype(nsIURI* aURI);
     nsresult PutPrototype(nsXULPrototypeDocument* aDocument);
 
     JSScript* GetScript(nsIURI* aURI);
     nsresult PutScript(nsIURI* aURI, JS::Handle<JSScript*> aScriptObject);
 
-    nsXBLDocumentInfo* GetXBLDocumentInfo(nsIURI* aURL) {
-        return mXBLDocTable.GetWeak(aURL);
-    }
+    nsXBLDocumentInfo* GetXBLDocumentInfo(nsIURI* aURL,
+                                          mozilla::StyleBackendType aType);
+
     nsresult PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo);
 
     /**
      * Get a style sheet by URI. If the style sheet is not in the cache,
      * returns nullptr.
      */
     mozilla::StyleSheet* GetStyleSheet(nsIURI* aURI,
                                        mozilla::StyleBackendType aType);
@@ -117,27 +117,35 @@ protected:
 
     nsXULPrototypeCache();
     virtual ~nsXULPrototypeCache();
 
     static nsXULPrototypeCache* sInstance;
 
     void FlushSkinFiles();
 
-    typedef nsRefPtrHashtable<nsURIHashKey, mozilla::StyleSheet> StyleSheetTable;
+    using StyleSheetTable = nsRefPtrHashtable<nsURIHashKey, mozilla::StyleSheet>;
+    using XBLDocTable = nsRefPtrHashtable<nsURIHashKey, nsXBLDocumentInfo>;
+
     StyleSheetTable& StyleSheetTableFor(mozilla::StyleBackendType aType) {
       return aType == mozilla::StyleBackendType::Gecko ? mGeckoStyleSheetTable
                                                        : mServoStyleSheetTable;
     }
 
+    XBLDocTable& XBLDocTableFor(mozilla::StyleBackendType aType) {
+      return aType == mozilla::StyleBackendType::Gecko ? mGeckoXBLDocTable
+                                                       : mServoXBLDocTable;
+    }
+
     nsRefPtrHashtable<nsURIHashKey,nsXULPrototypeDocument>   mPrototypeTable; // owns the prototypes
     StyleSheetTable                                          mGeckoStyleSheetTable;
     StyleSheetTable                                          mServoStyleSheetTable;
     nsJSThingHashtable<nsURIHashKey, JSScript*>              mScriptTable;
-    nsRefPtrHashtable<nsURIHashKey,nsXBLDocumentInfo>        mXBLDocTable;
+    XBLDocTable                                              mGeckoXBLDocTable;
+    XBLDocTable                                              mServoXBLDocTable;
 
     // URIs already written to the startup cache, to prevent double-caching.
     nsTHashtable<nsURIHashKey>                               mStartupCacheURITable;
 
     nsInterfaceHashtable<nsURIHashKey, nsIStorageStream>     mOutputStreamTable;
     nsInterfaceHashtable<nsURIHashKey, nsIObjectInputStream> mInputStreamTable;
 
     // Bootstrap caching service