Bug 1363640 Part 5 - Add a table in nsXULPrototypeCache to cache XBL documents with servo backend. draft
authorTing-Yu Lin <tlin@mozilla.com>
Fri, 19 May 2017 15:18:00 -0700
changeset 583794 c3b4a20c277e91cac33b16c9e3c591af8a9d8a01
parent 583793 c0ccbbb66db3b47f0ab170fa175826cd1f5970c1
child 583795 a464685419019f015ef2a98d78a0d0bc8afdea3c
push id60548
push userbmo:tlin@mozilla.com
push dateWed, 24 May 2017 17:00:28 +0000
bugs1363640
milestone55.0a1
Bug 1363640 Part 5 - Add a table in nsXULPrototypeCache to cache XBL documents with servo backend. 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