Bug 1342012 - Make load request element optional r=smaug
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 06 Dec 2018 16:52:18 -0500
changeset 509507 248ed24187a21a78acf2243ee8a1b4d247e46c36
parent 509506 65742a0032968ba2a66c33d6786d3288e8644b88
child 509508 be8cd28e487c1971f21b691befd0e268ce6d5855
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1342012
milestone66.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 1342012 - Make load request element optional r=smaug
dom/script/ScriptLoadRequest.cpp
dom/script/ScriptLoadRequest.h
dom/script/ScriptLoader.cpp
--- a/dom/script/ScriptLoadRequest.cpp
+++ b/dom/script/ScriptLoadRequest.cpp
@@ -25,16 +25,17 @@ NS_IMPL_CYCLE_COLLECTION(ScriptFetchOpti
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ScriptFetchOptions, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ScriptFetchOptions, Release)
 
 ScriptFetchOptions::ScriptFetchOptions(
     mozilla::CORSMode aCORSMode, mozilla::net::ReferrerPolicy aReferrerPolicy,
     nsIScriptElement* aElement, nsIPrincipal* aTriggeringPrincipal)
     : mCORSMode(aCORSMode),
       mReferrerPolicy(aReferrerPolicy),
+      mIsPreload(false),
       mElement(aElement),
       mTriggeringPrincipal(aTriggeringPrincipal) {
   MOZ_ASSERT(mTriggeringPrincipal);
 }
 
 ScriptFetchOptions::~ScriptFetchOptions() {}
 
 //////////////////////////////////////////////////////////////
--- a/dom/script/ScriptLoadRequest.h
+++ b/dom/script/ScriptLoadRequest.h
@@ -45,16 +45,17 @@ class ScriptFetchOptions {
 
   ScriptFetchOptions(mozilla::CORSMode aCORSMode,
                      mozilla::net::ReferrerPolicy aReferrerPolicy,
                      nsIScriptElement* aElement,
                      nsIPrincipal* aTriggeringPrincipal);
 
   const mozilla::CORSMode mCORSMode;
   const mozilla::net::ReferrerPolicy mReferrerPolicy;
+  bool mIsPreload;
   nsCOMPtr<nsIScriptElement> mElement;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
 };
 
 /*
  * A class that handles loading and evaluation of <script> elements.
  */
 
@@ -86,17 +87,20 @@ class ScriptLoadRequest
     bool isInlineClassicScript = mIsInline && !IsModuleRequest();
     Element()->ScriptAvailable(aResult, Element(), isInlineClassicScript, mURI,
                                mLineNo);
   }
   void FireScriptEvaluated(nsresult aResult) {
     Element()->ScriptEvaluated(aResult, Element(), mIsInline);
   }
 
-  bool IsPreload() { return Element() == nullptr; }
+  bool IsPreload() const {
+    MOZ_ASSERT_IF(mFetchOptions->mIsPreload, !Element());
+    return mFetchOptions->mIsPreload;
+  }
 
   virtual void Cancel();
 
   bool IsCanceled() const { return mIsCanceled; }
 
   virtual void SetReady();
 
   JS::OffThreadToken** OffThreadTokenPtr() {
@@ -194,21 +198,38 @@ class ScriptLoadRequest
   mozilla::net::ReferrerPolicy ReferrerPolicy() const {
     return mFetchOptions->mReferrerPolicy;
   }
   nsIScriptElement* Element() const { return mFetchOptions->mElement; }
   nsIPrincipal* TriggeringPrincipal() const {
     return mFetchOptions->mTriggeringPrincipal;
   }
 
-  void SetElement(nsIScriptElement* aElement) {
-    // Called when a preload request is later used for an actual request.
+  // Make this request a preload (speculative) request.
+  void SetIsPreloadRequest() {
+    MOZ_ASSERT(!Element());
+    MOZ_ASSERT(!IsPreload());
+    mFetchOptions->mIsPreload = true;
+  }
+
+  // Make a preload request into an actual load request for the given element.
+  void SetIsLoadRequest(nsIScriptElement* aElement) {
     MOZ_ASSERT(aElement);
     MOZ_ASSERT(!Element());
+    MOZ_ASSERT(IsPreload());
     mFetchOptions->mElement = aElement;
+    mFetchOptions->mIsPreload = false;
+  }
+
+  FromParser GetParserCreated() const {
+    nsIScriptElement* element = Element();
+    if (!element) {
+      return NOT_FROM_PARSER;
+    }
+    return element->GetParserCreated();
   }
 
   bool ShouldAcceptBinASTEncoding() const;
 
   void ClearScriptSource();
 
   void SetScript(JSScript* aScript);
 
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -205,18 +205,16 @@ static void CollectScriptTelemetry(Scrip
   }
 
   // Report the type of source. This is used to monitor the status of the
   // JavaScript Start-up Bytecode Cache, with the expectation of an almost zero
   // source-fallback and alternate-data being roughtly equal to source loads.
   if (aRequest->IsLoadingSource()) {
     if (aRequest->mIsInline) {
       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Inline);
-      nsAutoString inlineData;
-      aRequest->Element()->GetScriptText(inlineData);
     } else if (aRequest->IsTextSource()) {
       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::SourceFallback);
     }
     // TODO: Add telemetry for BinAST encoded source.
   } else {
     MOZ_ASSERT(aRequest->IsLoading());
     if (aRequest->IsTextSource()) {
       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Source);
@@ -955,17 +953,17 @@ void ScriptLoader::ProcessLoadedModuleTr
   MOZ_ASSERT(aRequest->IsReadyToRun());
 
   if (aRequest->IsTopLevel()) {
     if (aRequest->IsDynamicImport()) {
       MOZ_ASSERT(aRequest->isInList());
       RefPtr<ScriptLoadRequest> req = mDynamicImportRequests.Steal(aRequest);
       RunScriptWhenSafe(req);
     } else if (aRequest->mIsInline &&
-               aRequest->Element()->GetParserCreated() == NOT_FROM_PARSER) {
+               aRequest->GetParserCreated() == NOT_FROM_PARSER) {
       MOZ_ASSERT(!aRequest->isInList());
       RunScriptWhenSafe(aRequest);
     } else {
       MaybeMoveToLoadedList(aRequest);
       ProcessPendingRequests();
     }
   }
 
@@ -1053,20 +1051,22 @@ nsresult ScriptLoader::AssociateSourceEl
   for (ModuleLoadRequest* childRequest : aRequest->mImports) {
     nsresult rv = AssociateSourceElementsForModuleTree(aCx, childRequest);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   JS::Rooted<JSObject*> module(aCx, moduleScript->ModuleRecord());
   MOZ_ASSERT(module);
 
-  nsresult rv =
-      nsJSUtils::InitModuleSourceElement(aCx, module, aRequest->Element());
-  NS_ENSURE_SUCCESS(rv, rv);
-  moduleScript->SetSourceElementAssociated();
+  nsIScriptElement* element = aRequest->Element();
+  if (element) {
+    nsresult rv = nsJSUtils::InitModuleSourceElement(aCx, module, element);
+    NS_ENSURE_SUCCESS(rv, rv);
+    moduleScript->SetSourceElementAssociated();
+  }
 
   // The script is now ready to be exposed to the debugger.
   JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(module));
   JS::ExposeScriptToDebugger(aCx, script);
 
   return NS_OK;
 }
 
@@ -1706,17 +1706,17 @@ ScriptLoadRequest* ScriptLoader::LookupP
       mPreloads.IndexOf(aElement->GetScriptURI(), 0, PreloadURIComparator());
   if (i == nsTArray<PreloadInfo>::NoIndex) {
     return nullptr;
   }
 
   // Found preloaded request. Note that a script-inserted script can steal a
   // preload!
   RefPtr<ScriptLoadRequest> request = mPreloads[i].mRequest;
-  request->SetElement(aElement);
+  request->SetIsLoadRequest(aElement);
   nsString preloadCharset(mPreloads[i].mCharset);
   mPreloads.RemoveElementAt(i);
 
   // Double-check that the charset the preload used is the same as the charset
   // we have now.
   nsAutoString elementCharset;
   aElement->GetScriptCharset(elementCharset);
   mozilla::net::ReferrerPolicy referrerPolicy = GetReferrerPolicy(aElement);
@@ -2068,17 +2068,17 @@ nsresult ScriptLoader::ProcessRequest(Sc
   nsCOMPtr<nsINode> scriptElem = do_QueryInterface(aRequest->Element());
 
   nsCOMPtr<nsIDocument> doc;
   if (!aRequest->mIsInline) {
     doc = scriptElem->OwnerDoc();
   }
 
   nsCOMPtr<nsIScriptElement> oldParserInsertedScript;
-  uint32_t parserCreated = aRequest->Element()->GetParserCreated();
+  uint32_t parserCreated = aRequest->GetParserCreated();
   if (parserCreated) {
     oldParserInsertedScript = mCurrentParserInsertedScript;
     mCurrentParserInsertedScript = aRequest->Element();
   }
 
   aRequest->Element()->BeginEvaluating();
 
   FireScriptAvailable(NS_OK, aRequest);
@@ -2374,25 +2374,25 @@ nsresult ScriptLoader::EvaluateScript(Sc
   MOZ_ASSERT(aRequest->IsReadyToRun());
 
   // We need a document to evaluate scripts.
   if (!mDocument) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->Element()));
-  nsIDocument* ownerDoc = scriptContent->OwnerDoc();
-  if (ownerDoc != mDocument) {
-    // Willful violation of HTML5 as of 2010-12-01
-    return NS_ERROR_FAILURE;
+  MOZ_ASSERT_IF(!scriptContent, aRequest->AsModuleRequest()->IsDynamicImport());
+  if (scriptContent) {
+    nsIDocument* ownerDoc = scriptContent->OwnerDoc();
+    if (ownerDoc != mDocument) {
+      // Willful violation of HTML5 as of 2010-12-01
+      return NS_ERROR_FAILURE;
+    }
   }
 
-  // Get the script-type to be used by this element.
-  NS_ASSERTION(scriptContent, "no content - what is default script-type?");
-
   nsCOMPtr<nsIScriptGlobalObject> globalObject = GetScriptGlobalObject();
   if (!globalObject) {
     return NS_ERROR_FAILURE;
   }
 
   // Make sure context is a strong reference since we access it after
   // we've executed a script, which may cause all other references to
   // the context to go away.
@@ -3101,17 +3101,17 @@ nsresult ScriptLoader::SaveSRIHash(
 
   return NS_OK;
 }
 
 void ScriptLoader::ReportErrorToConsole(ScriptLoadRequest* aRequest,
                                         nsresult aResult) const {
   MOZ_ASSERT(aRequest);
 
-  if (!aRequest->Element()) {
+  if (aRequest->IsPreload()) {
     return;
   }
 
   bool isScript = !aRequest->IsModuleRequest();
   const char* message;
   if (aResult == NS_ERROR_MALFORMED_URI) {
     message = isScript ? "ScriptSourceMalformed" : "ModuleSourceMalformed";
   } else if (aResult == NS_ERROR_DOM_BAD_URI) {
@@ -3121,18 +3121,19 @@ void ScriptLoader::ReportErrorToConsole(
     return;
   } else {
     message = isScript ? "ScriptSourceLoadFailed" : "ModuleSourceLoadFailed";
   }
 
   NS_ConvertUTF8toUTF16 url(aRequest->mURI->GetSpecOrDefault());
   const char16_t* params[] = {url.get()};
 
-  uint32_t lineNo = aRequest->Element()->GetScriptLineNumber();
-  uint32_t columnNo = aRequest->Element()->GetScriptColumnNumber();
+  nsIScriptElement* element = aRequest->Element();
+  uint32_t lineNo = element ? element->GetScriptLineNumber() : 0;
+  uint32_t columnNo = element ? element->GetScriptColumnNumber() : 0;
 
   nsContentUtils::ReportToConsole(
       nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Script Loader"),
       mDocument, nsContentUtils::eDOM_PROPERTIES, message, params,
       ArrayLength(params), nullptr, EmptyString(), lineNo, columnNo);
 }
 
 void ScriptLoader::HandleLoadError(ScriptLoadRequest* aRequest,
@@ -3454,16 +3455,17 @@ void ScriptLoader::PreloadURI(
   GetSRIMetadata(aIntegrity, &sriMetadata);
 
   RefPtr<ScriptLoadRequest> request = CreateLoadRequest(
       scriptKind, aURI, nullptr, mDocument->NodePrincipal(),
       Element::StringToCORSMode(aCrossOrigin), sriMetadata, aReferrerPolicy);
   request->mIsInline = false;
   request->mScriptFromHead = aScriptFromHead;
   request->SetScriptMode(aDefer, aAsync);
+  request->SetIsPreloadRequest();
 
   if (LOG_ENABLED()) {
     nsAutoCString url;
     aURI->GetAsciiSpec(url);
     LOG(("ScriptLoadRequest (%p): Created preload request for %s",
          request.get(), url.get()));
   }