Bug 1771867 - Early Hints Phase 2 - Part 6: Pass early hint preload to style preloader r=necko-reviewers,valentin
☠☠ backed out by e2b41473c7ed ☠ ☠
authorManuel Bucher <manuel@mozilla.com>
Fri, 02 Dec 2022 09:45:26 +0000
changeset 644483 110ac12e16f5fa371c85017d039180e933ab6622
parent 644482 7f20525f5e94da0a43bd6e389e7654a1953db7c3
child 644484 d33ccbbf407dcaeaef1ca8c42b41fd66d851c959
push id40449
push usercsabou@mozilla.com
push dateFri, 02 Dec 2022 21:26:33 +0000
treeherdermozilla-central@360f8b71c676 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnecko-reviewers, valentin
bugs1771867
milestone109.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 1771867 - Early Hints Phase 2 - Part 6: Pass early hint preload to style preloader r=necko-reviewers,valentin Differential Revision: https://phabricator.services.mozilla.com/D161176
dom/base/Document.cpp
dom/base/Document.h
layout/style/Loader.cpp
layout/style/Loader.h
parser/html/nsHtml5TreeOpExecutor.cpp
uriloader/preload/PreloadService.cpp
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -12393,28 +12393,28 @@ class StubCSSLoaderObserver final : publ
 };
 NS_IMPL_ISUPPORTS(StubCSSLoaderObserver, nsICSSLoaderObserver)
 
 }  // namespace
 
 SheetPreloadStatus Document::PreloadStyle(
     nsIURI* uri, const Encoding* aEncoding, const nsAString& aCrossOriginAttr,
     const enum ReferrerPolicy aReferrerPolicy, const nsAString& aIntegrity,
-    css::StylePreloadKind aKind) {
+    css::StylePreloadKind aKind, uint64_t aEarlyHintPreloaderId) {
   MOZ_ASSERT(aKind != css::StylePreloadKind::None);
 
   // The CSSLoader will retain this object after we return.
   nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver();
 
   nsCOMPtr<nsIReferrerInfo> referrerInfo =
       ReferrerInfo::CreateFromDocumentAndPolicyOverride(this, aReferrerPolicy);
 
   // Charset names are always ASCII.
   auto result = CSSLoader()->LoadSheet(
-      uri, aKind, aEncoding, referrerInfo, obs,
+      uri, aKind, aEncoding, referrerInfo, obs, aEarlyHintPreloaderId,
       Element::StringToCORSMode(aCrossOriginAttr), aIntegrity);
   if (result.isErr()) {
     return SheetPreloadStatus::Errored;
   }
   RefPtr<StyleSheet> sheet = result.unwrap();
   if (sheet->IsComplete()) {
     return SheetPreloadStatus::AlreadyComplete;
   }
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -3025,17 +3025,18 @@ class Document : public nsINode,
   /**
    * Called by the parser or the preload service to preload style sheets.
    * aCrossOriginAttr should be a void string if the attr is not present.
    */
   SheetPreloadStatus PreloadStyle(nsIURI* aURI, const Encoding* aEncoding,
                                   const nsAString& aCrossOriginAttr,
                                   ReferrerPolicyEnum aReferrerPolicy,
                                   const nsAString& aIntegrity,
-                                  css::StylePreloadKind);
+                                  css::StylePreloadKind,
+                                  uint64_t aEarlyHintPreloaderId);
 
   /**
    * Called by the chrome registry to load style sheets.
    *
    * This always does a synchronous load, and parses as a normal document sheet.
    */
   RefPtr<StyleSheet> LoadChromeSheetSync(nsIURI* aURI);
 
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/AutoRestore.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/Logging.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PreloadHashKey.h"
 #include "mozilla/ResultExtensions.h"
 #include "mozilla/SchedulerGroup.h"
 #include "mozilla/URLPreloader.h"
+#include "nsIChildChannel.h"
 #include "nsIRunnable.h"
 #include "nsISupportsPriority.h"
 #include "nsITimedChannel.h"
 #include "nsICachingChannel.h"
 #include "nsSyncLoadService.h"
 #include "nsContentSecurityManager.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
@@ -460,17 +461,17 @@ void SheetLoadData::FireLoadEvent(nsIThr
                                        mLoadFailed ? u"error"_ns : u"load"_ns,
                                        CanBubble::eNo, Cancelable::eNo);
 
   MOZ_ASSERT(BlocksLoadEvent());
   mLoader->UnblockOnload(true);
 }
 
 void SheetLoadData::StartPendingLoad() {
-  mLoader->LoadSheet(*this, Loader::SheetState::NeedsParser,
+  mLoader->LoadSheet(*this, Loader::SheetState::NeedsParser, 0,
                      Loader::PendingLoad::Yes);
 }
 
 void SheetLoadData::ScheduleLoadEventIfNeeded() {
   if (!mOwningNodeBeforeLoadEvent) {
     return;
   }
 
@@ -1179,16 +1180,17 @@ void Loader::InsertChildSheet(StyleSheet
  * LoadSheet handles the actual load of a sheet.  If the load is
  * supposed to be synchronous it just opens a channel synchronously
  * using the given uri, wraps the resulting stream in a converter
  * stream and calls ParseSheet.  Otherwise it tries to look for an
  * existing load for this URI and piggyback on it.  Failing all that,
  * a new load is kicked off asynchronously.
  */
 nsresult Loader::LoadSheet(SheetLoadData& aLoadData, SheetState aSheetState,
+                           uint64_t aEarlyHintPreloaderId,
                            PendingLoad aPendingLoad) {
   LOG(("css::Loader::LoadSheet"));
   MOZ_ASSERT(aLoadData.mURI, "Need a URI to load");
   MOZ_ASSERT(aLoadData.mSheet, "Need a sheet to load into");
   MOZ_ASSERT(aSheetState != SheetState::Complete, "Why bother?");
   MOZ_ASSERT(!aLoadData.mUseSystemPrincipal || aLoadData.mSyncLoad,
              "Shouldn't use system principal for async loads");
 
@@ -1496,16 +1498,18 @@ nsresult Loader::LoadSheet(SheetLoadData
           // not be reported
           aLoadData.mBlockResourceTiming = true;
 
           // Mark the channel so PerformanceMainThread::AddEntry will not
           // report the resource.
           timedChannel->SetReportResourceTiming(false);
         }
 
+      } else if (aEarlyHintPreloaderId) {
+        timedChannel->SetInitiatorType(u"early-hints"_ns);
       } else {
         timedChannel->SetInitiatorType(u"link"_ns);
       }
     }
   }
 
   // Now tell the channel we expect text/css data back....  We do
   // this before opening it, so it's only treated as a hint.
@@ -1515,16 +1519,24 @@ nsresult Loader::LoadSheet(SheetLoadData
   // model is: Necko owns the stream loader, which owns the load data,
   // which owns us
   auto streamLoader = MakeRefPtr<StreamLoader>(aLoadData);
   if (mDocument) {
     net::PredictorLearn(aLoadData.mURI, mDocument->GetDocumentURI(),
                         nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, mDocument);
   }
 
+  if (aEarlyHintPreloaderId) {
+    nsCOMPtr<nsIHttpChannelInternal> channelInternal =
+        do_QueryInterface(channel);
+    NS_ENSURE_TRUE(channelInternal != nullptr, NS_ERROR_FAILURE);
+
+    rv = channelInternal->SetEarlyHintPreloaderId(aEarlyHintPreloaderId);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
   rv = channel->AsyncOpen(streamLoader);
   if (NS_FAILED(rv)) {
     LOG_ERROR(("  Failed to create stream loader"));
     streamLoader->ChannelOpenFailed(rv);
     // NOTE: NotifyStop will be done in SheetComplete -> NotifyObservers.
     aLoadData.NotifyStart(channel);
     SheetComplete(aLoadData, rv);
     return rv;
@@ -1905,17 +1917,17 @@ Result<Loader::LoadSheetResult, nsresult
 
   // Now we need to actually load it.
   auto result = LoadSheetResult{Completed::No, isAlternate, matched};
 
   MOZ_ASSERT(result.ShouldBlock() == !data->ShouldDefer(),
              "These should better match!");
 
   // Load completion will free the data
-  rv = LoadSheet(*data, state);
+  rv = LoadSheet(*data, state, 0);
   if (NS_FAILED(rv)) {
     return Err(rv);
   }
 
   if (!syncLoad) {
     data->mMustNotify = true;
   }
   return result;
@@ -2040,60 +2052,62 @@ nsresult Loader::LoadChildSheet(StyleShe
     data->mIntentionallyDropped = true;
 #endif
     return NS_OK;
   }
 
   bool syncLoad = data->mSyncLoad;
 
   // Load completion will release the data
-  rv = LoadSheet(*data, state);
+  rv = LoadSheet(*data, state, 0);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!syncLoad) {
     data->mMustNotify = true;
   }
   return rv;
 }
 
 Result<RefPtr<StyleSheet>, nsresult> Loader::LoadSheetSync(
     nsIURI* aURL, SheetParsingMode aParsingMode,
     UseSystemPrincipal aUseSystemPrincipal) {
   LOG(("css::Loader::LoadSheetSync"));
   nsCOMPtr<nsIReferrerInfo> referrerInfo = new ReferrerInfo(nullptr);
   return InternalLoadNonDocumentSheet(
       aURL, StylePreloadKind::None, aParsingMode, aUseSystemPrincipal, nullptr,
-      referrerInfo, nullptr, CORS_NONE, u""_ns);
+      referrerInfo, nullptr, CORS_NONE, u""_ns, 0);
 }
 
 Result<RefPtr<StyleSheet>, nsresult> Loader::LoadSheet(
     nsIURI* aURI, SheetParsingMode aParsingMode,
     UseSystemPrincipal aUseSystemPrincipal, nsICSSLoaderObserver* aObserver) {
   nsCOMPtr<nsIReferrerInfo> referrerInfo = new ReferrerInfo(nullptr);
   return InternalLoadNonDocumentSheet(
       aURI, StylePreloadKind::None, aParsingMode, aUseSystemPrincipal, nullptr,
-      referrerInfo, aObserver, CORS_NONE, u""_ns);
+      referrerInfo, aObserver, CORS_NONE, u""_ns, 0);
 }
 
 Result<RefPtr<StyleSheet>, nsresult> Loader::LoadSheet(
     nsIURI* aURL, StylePreloadKind aPreloadKind,
     const Encoding* aPreloadEncoding, nsIReferrerInfo* aReferrerInfo,
-    nsICSSLoaderObserver* aObserver, CORSMode aCORSMode,
-    const nsAString& aIntegrity) {
+    nsICSSLoaderObserver* aObserver, uint64_t aEarlyHintPreloaderId,
+    CORSMode aCORSMode, const nsAString& aIntegrity) {
   LOG(("css::Loader::LoadSheet(aURL, aObserver) api call"));
-  return InternalLoadNonDocumentSheet(
-      aURL, aPreloadKind, eAuthorSheetFeatures, UseSystemPrincipal::No,
-      aPreloadEncoding, aReferrerInfo, aObserver, aCORSMode, aIntegrity);
+  return InternalLoadNonDocumentSheet(aURL, aPreloadKind, eAuthorSheetFeatures,
+                                      UseSystemPrincipal::No, aPreloadEncoding,
+                                      aReferrerInfo, aObserver, aCORSMode,
+                                      aIntegrity, aEarlyHintPreloaderId);
 }
 
 Result<RefPtr<StyleSheet>, nsresult> Loader::InternalLoadNonDocumentSheet(
     nsIURI* aURL, StylePreloadKind aPreloadKind, SheetParsingMode aParsingMode,
     UseSystemPrincipal aUseSystemPrincipal, const Encoding* aPreloadEncoding,
     nsIReferrerInfo* aReferrerInfo, nsICSSLoaderObserver* aObserver,
-    CORSMode aCORSMode, const nsAString& aIntegrity) {
+    CORSMode aCORSMode, const nsAString& aIntegrity,
+    uint64_t aEarlyHintPreloaderId) {
   MOZ_ASSERT(aURL, "Must have a URI to load");
   MOZ_ASSERT(aUseSystemPrincipal == UseSystemPrincipal::No || !aObserver,
              "Shouldn't load system-principal sheets async");
   MOZ_ASSERT(aReferrerInfo, "Must have referrerInfo");
 
   LOG_URI("  Non-document sheet uri: '%s'", aURL);
 
   if (!mEnabled) {
@@ -2133,17 +2147,17 @@ Result<RefPtr<StyleSheet>, nsresult> Loa
       // drop it intentionally.
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
       data->mIntentionallyDropped = true;
 #endif
     }
     return sheet;
   }
 
-  rv = LoadSheet(*data, state);
+  rv = LoadSheet(*data, state, aEarlyHintPreloaderId);
   if (NS_FAILED(rv)) {
     return Err(rv);
   }
   if (aObserver) {
     data->mMustNotify = true;
   }
   return sheet;
 }
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -356,27 +356,30 @@ class Loader final {
    * @param aURL the URL of the sheet to load
    * @param aParsingMode the mode in which to parse the sheet
    *        (see comments at enum SheetParsingMode, above).
    * @param aUseSystemPrincipal if true, give the resulting sheet the system
    * principal no matter where it's being loaded from.
    * @param aReferrerInfo referrer information of the sheet.
    * @param aObserver the observer to notify when the load completes.
    *                  Must not be null.
+   * @param aEarlyHintPreloaderId to connect back to the early hint preload
+   * channel. Null means no connect back should happen
    * @return the sheet to load. Note that the sheet may well not be loaded by
    * the time this method returns.
    *
    * NOTE: At the moment, this method assumes the sheet will be UTF-8, but
    * ideally it would allow arbitrary encodings.  Callers should NOT depend on
    * non-UTF8 sheets being treated as UTF-8 by this method.
    */
   Result<RefPtr<StyleSheet>, nsresult> LoadSheet(
       nsIURI* aURI, StylePreloadKind, const Encoding* aPreloadEncoding,
       nsIReferrerInfo* aReferrerInfo, nsICSSLoaderObserver* aObserver,
-      CORSMode = CORS_NONE, const nsAString& aIntegrity = u""_ns);
+      uint64_t aEarlyHintPreloaderId, CORSMode = CORS_NONE,
+      const nsAString& aIntegrity = u""_ns);
 
   /**
    * As above, but without caring for a couple things.
    */
   Result<RefPtr<StyleSheet>, nsresult> LoadSheet(nsIURI*, SheetParsingMode,
                                                  UseSystemPrincipal,
                                                  nsICSSLoaderObserver*);
 
@@ -533,17 +536,18 @@ class Loader final {
   void InsertSheetInTree(StyleSheet& aSheet);
   // Inserts a style sheet into a parent style sheet.
   void InsertChildSheet(StyleSheet& aSheet, StyleSheet& aParentSheet);
 
   Result<RefPtr<StyleSheet>, nsresult> InternalLoadNonDocumentSheet(
       nsIURI* aURL, StylePreloadKind, SheetParsingMode aParsingMode,
       UseSystemPrincipal, const Encoding* aPreloadEncoding,
       nsIReferrerInfo* aReferrerInfo, nsICSSLoaderObserver* aObserver,
-      CORSMode aCORSMode, const nsAString& aIntegrity);
+      CORSMode aCORSMode, const nsAString& aIntegrity,
+      uint64_t aEarlyHintPreloaderId);
 
   RefPtr<StyleSheet> LookupInlineSheetInCache(const nsAString&);
 
   // Post a load event for aObserver to be notified about aSheet.  The
   // notification will be sent with status NS_OK unless the load event is
   // canceled at some point (in which case it will be sent with
   // NS_BINDING_ABORTED).
   nsresult PostLoadEvent(RefPtr<SheetLoadData>);
@@ -551,17 +555,18 @@ class Loader final {
   // Start the loads of all the sheets in mPendingDatas
   void StartDeferredLoads();
 
   void HandleLoadEvent(SheetLoadData&);
 
   // Note: LoadSheet is responsible for setting the sheet to complete on
   // failure.
   enum class PendingLoad { No, Yes };
-  nsresult LoadSheet(SheetLoadData&, SheetState, PendingLoad = PendingLoad::No);
+  nsresult LoadSheet(SheetLoadData&, SheetState, uint64_t aEarlyHintPreloaderId,
+                     PendingLoad = PendingLoad::No);
 
   enum class AllowAsyncParse {
     Yes,
     No,
   };
 
   // Parse the stylesheet in the load data.
   //
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -1242,17 +1242,18 @@ void nsHtml5TreeOpExecutor::PreloadStyle
       return;
     }
   }
 
   mDocument->PreloadStyle(uri, Encoding::ForLabel(aCharset), aCrossOrigin,
                           GetPreloadReferrerPolicy(aReferrerPolicy), aIntegrity,
                           aLinkPreload
                               ? css::StylePreloadKind::FromLinkRelPreloadElement
-                              : css::StylePreloadKind::FromParser);
+                              : css::StylePreloadKind::FromParser,
+                          0);
 }
 
 void nsHtml5TreeOpExecutor::PreloadImage(
     const nsAString& aURL, const nsAString& aCrossOrigin,
     const nsAString& aMedia, const nsAString& aSrcset, const nsAString& aSizes,
     const nsAString& aImageReferrerPolicy, bool aLinkPreload,
     const TimeStamp& aInitTimestamp) {
   nsCOMPtr<nsIURI> baseURI = BaseURIForPreload();
--- a/uriloader/preload/PreloadService.cpp
+++ b/uriloader/preload/PreloadService.cpp
@@ -165,17 +165,18 @@ PreloadService::PreloadOrCoalesceResult 
   if (aAs.LowerCaseEqualsASCII("script")) {
     PreloadScript(uri, aType, aCharset, aCORS, aReferrerPolicy, aIntegrity,
                   true /* isInHead - TODO */, aEarlyHintPreloaderId);
   } else if (aAs.LowerCaseEqualsASCII("style")) {
     auto status = mDocument->PreloadStyle(
         aURI, Encoding::ForLabel(aCharset), aCORS,
         PreloadReferrerPolicy(aReferrerPolicy), aIntegrity,
         aFromHeader ? css::StylePreloadKind::FromLinkRelPreloadHeader
-                    : css::StylePreloadKind::FromLinkRelPreloadElement);
+                    : css::StylePreloadKind::FromLinkRelPreloadElement,
+        aEarlyHintPreloaderId);
     switch (status) {
       case dom::SheetPreloadStatus::AlreadyComplete:
         return {nullptr, /* already_complete = */ true};
       case dom::SheetPreloadStatus::Errored:
       case dom::SheetPreloadStatus::InProgress:
         break;
     }
   } else if (aAs.LowerCaseEqualsASCII("image")) {