Bug 1469599 - Associate all module scripts in a module graph with DOM elements before execution r=hsivonen
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 22 Aug 2018 14:54:17 +0100
changeset 432835 3f1d6721cab0d1668a2441f7b0b7d018f1ac6475
parent 432834 6bb8792d978ca0b0b84a0fd1218260392b897ed1
child 432836 c9b2f96523b17a7da4a5827e350a11c2b049bbb7
push id34488
push usernerli@mozilla.com
push dateWed, 22 Aug 2018 16:28:54 +0000
treeherdermozilla-central@d6e4d3e69d4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs1469599
milestone63.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 1469599 - Associate all module scripts in a module graph with DOM elements before execution r=hsivonen
dom/script/ScriptLoader.cpp
dom/script/ScriptLoader.h
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -960,16 +960,49 @@ ScriptLoader::InstantiateModuleTree(Modu
     MOZ_ASSERT(!exception.isUndefined());
     moduleScript->SetErrorToRethrow(exception);
   }
 
   return true;
 }
 
 nsresult
+ScriptLoader::AssociateSourceElementsForModuleTree(JSContext* aCx,
+                                                   ModuleLoadRequest* aRequest)
+{
+  // Preloading can cause JS scripts to be compiled before DOM script element
+  // nodes have been created. This method ensures compiled scripts are
+  // associated with DOM element nodes before execution.
+
+  MOZ_ASSERT(aRequest);
+
+  ModuleScript* moduleScript = aRequest->mModuleScript;
+  if (moduleScript->SourceElementAssociated()) {
+    return NS_OK;
+  }
+
+  for (ModuleLoadRequest* childRequest : aRequest->mImports) {
+    nsresult rv = AssociateSourceElementsForModuleTree(aCx, childRequest);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  JS::Rooted<JSScript*> script(aCx, moduleScript->Script());
+  MOZ_ASSERT(script);
+
+  nsresult rv = nsJSUtils::InitModuleSourceElement(aCx, script, aRequest->Element());
+  NS_ENSURE_SUCCESS(rv, rv);
+  moduleScript->SetSourceElementAssociated();
+
+  // The script is now ready to be exposed to the debugger.
+  JS::ExposeScriptToDebugger(aCx, script);
+
+  return NS_OK;
+}
+
+nsresult
 ScriptLoader::RestartLoad(ScriptLoadRequest* aRequest)
 {
   MOZ_ASSERT(aRequest->IsBytecode());
   aRequest->mScriptBytecode.clearAndFree();
   TRACE_FOR_TEST(aRequest->Element(), "scriptloader_fallback");
 
   // Start a new channel from which we explicitly request to stream the source
   // instead of the bytecode.
@@ -2307,22 +2340,18 @@ ScriptLoader::EvaluateScript(ScriptLoadR
         JS_SetPendingException(cx, error);
         return NS_OK; // An error is reported by AutoEntryScript.
       }
 
       JS::Rooted<JSScript*> script(cx, moduleScript->Script());
       MOZ_ASSERT(script);
 
       if (!moduleScript->SourceElementAssociated()) {
-        rv = nsJSUtils::InitModuleSourceElement(cx, script, aRequest->Element());
+        rv = AssociateSourceElementsForModuleTree(cx, request);
         NS_ENSURE_SUCCESS(rv, rv);
-        moduleScript->SetSourceElementAssociated();
-
-        // The script is now ready to be exposed to the debugger.
-        JS::ExposeScriptToDebugger(cx, script);
       }
 
       rv = nsJSUtils::ModuleEvaluate(cx, script);
       MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
       if (NS_FAILED(rv)) {
         LOG(("ScriptLoadRequest (%p):   evaluation failed", aRequest));
         rv = NS_OK; // An error is reported by AutoEntryScript.
       }
--- a/dom/script/ScriptLoader.h
+++ b/dom/script/ScriptLoader.h
@@ -535,16 +535,19 @@ private:
   void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
   bool InstantiateModuleTree(ModuleLoadRequest* aRequest);
   JS::Value FindFirstParseError(ModuleLoadRequest* aRequest);
   void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
 
   RefPtr<mozilla::GenericPromise>
   StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent, nsIURI* aURI);
 
+  nsresult AssociateSourceElementsForModuleTree(JSContext* aCx,
+                                                ModuleLoadRequest* aRequest);
+
   nsIDocument* mDocument;                   // [WEAK]
   nsCOMArray<nsIScriptLoaderObserver> mObservers;
   ScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests;
   // mLoadingAsyncRequests holds async requests while they're loading; when they
   // have been loaded they are moved to mLoadedAsyncRequests.
   ScriptLoadRequestList mLoadingAsyncRequests;
   ScriptLoadRequestList mLoadedAsyncRequests;
   ScriptLoadRequestList mDeferRequests;