From a84aca97e25c3dc34a50a70926e301de91037c16 Mon Sep 17 00:00:00 2001 From: Fedor Date: Wed, 9 Sep 2020 17:29:41 +0300 Subject: [PATCH] Next part 2 of the Implement module type scripting. --- dom/base/nsDocument.cpp | 13 + dom/base/nsIDocument.h | 2 + dom/html/HTMLScriptElement.cpp | 23 +- dom/html/HTMLScriptElement.h | 2 +- dom/script/ModuleLoadRequest.cpp | 45 +- dom/script/ModuleLoadRequest.h | 33 +- dom/script/ModuleScript.cpp | 43 +- dom/script/ModuleScript.h | 12 +- dom/script/ScriptElement.cpp | 8 +- dom/script/ScriptLoader.cpp | 692 ++++++++++-------- dom/script/ScriptLoader.h | 89 ++- dom/script/nsIScriptElement.h | 29 +- dom/script/nsIScriptLoaderObserver.idl | 9 +- dom/svg/SVGScriptElement.cpp | 2 +- dom/svg/SVGScriptElement.h | 2 +- dom/xslt/xslt/txMozillaXMLOutput.cpp | 2 +- js/public/Class.h | 2 +- js/src/builtin/Module.js | 300 ++++---- js/src/builtin/ModuleObject.cpp | 121 +-- js/src/builtin/ModuleObject.h | 33 +- js/src/builtin/SelfHostingDefines.h | 22 +- js/src/builtin/TestingFunctions.cpp | 8 +- js/src/jit-test/tests/modules/bug-1284486.js | 12 +- .../jit-test/tests/modules/bug-1420420-2.js | 19 + .../jit-test/tests/modules/bug-1420420-3.js | 9 + .../jit-test/tests/modules/bug-1420420-4.js | 16 + js/src/jit-test/tests/modules/bug-1420420.js | 19 + js/src/js.msg | 1 - js/src/jsapi.cpp | 27 +- js/src/jsapi.h | 22 +- js/src/shell/js.cpp | 33 +- js/src/vm/EnvironmentObject.cpp | 2 +- js/src/vm/GlobalObject.h | 14 - js/src/vm/Runtime.cpp | 6 +- js/src/vm/Runtime.h | 3 + js/src/vm/SelfHosting.cpp | 28 +- parser/html/nsHtml5SpeculativeLoad.cpp | 11 +- parser/html/nsHtml5SpeculativeLoad.h | 13 +- parser/html/nsHtml5TreeBuilderCppSupplement.h | 16 +- parser/html/nsHtml5TreeOpExecutor.cpp | 6 +- parser/html/nsHtml5TreeOpExecutor.h | 4 +- parser/html/nsHtml5TreeOperation.cpp | 2 +- 42 files changed, 1012 insertions(+), 743 deletions(-) create mode 100644 js/src/jit-test/tests/modules/bug-1420420-2.js create mode 100644 js/src/jit-test/tests/modules/bug-1420420-3.js create mode 100644 js/src/jit-test/tests/modules/bug-1420420-4.js create mode 100644 js/src/jit-test/tests/modules/bug-1420420.js diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index dc4b23f2c..76490e6b4 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -12446,3 +12446,16 @@ nsIDocument::GetSelection(ErrorResult& aRv) return nsGlobalWindow::Cast(window)->GetSelection(aRv); } + +bool +nsIDocument::ModuleScriptsEnabled() +{ + static bool sEnabledForContent = false; + static bool sCachedPref = false; + if (!sCachedPref) { + sCachedPref = true; + Preferences::AddBoolVarCache(&sEnabledForContent, "dom.moduleScripts.enabled", false); + } + + return nsContentUtils::IsChromeDoc(this) || sEnabledForContent; +} \ No newline at end of file diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 33aac3a3d..7c1f5b584 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -2830,6 +2830,8 @@ public: virtual void ScheduleIntersectionObserverNotification() = 0; virtual void NotifyIntersectionObservers() = 0; + bool ModuleScriptsEnabled(); + bool ShouldThrowOnDynamicMarkupInsertion() { return mThrowOnDynamicMarkupInsertionCounter; diff --git a/dom/html/HTMLScriptElement.cpp b/dom/html/HTMLScriptElement.cpp index 5b727280f..f1463d6aa 100644 --- a/dom/html/HTMLScriptElement.cpp +++ b/dom/html/HTMLScriptElement.cpp @@ -280,12 +280,20 @@ HTMLScriptElement::GetScriptCharset(nsAString& charset) } void -HTMLScriptElement::FreezeUriAsyncDefer() +HTMLScriptElement::FreezeExecutionAttrs(nsIDocument* aOwnerDoc) { if (mFrozen) { return; } + MOZ_ASSERT(!mIsModule && !mAsync && !mDefer && !mExternal); + + // Determine whether this is a classic script or a module script. + nsAutoString type; + GetScriptType(type); + mIsModule = aOwnerDoc->ModuleScriptsEnabled() && + !type.IsEmpty() && type.LowerCaseEqualsASCII("module"); + // variation of this code in nsSVGScriptElement - check if changes // need to be transfered when modifying. Note that we don't use GetSrc here // because it will return the base URL when the attr value is "". @@ -300,14 +308,13 @@ HTMLScriptElement::FreezeUriAsyncDefer() // At this point mUri will be null for invalid URLs. mExternal = true; - - bool defer, async; - GetAsync(&async); - GetDefer(&defer); - - mDefer = !async && defer; - mAsync = async; } + + bool defer, async; + GetAsync(&async); + mAsync = (mExternal || mIsModule) && async; + GetDefer(&defer); + mDefer = mExternal && !async && defer; mFrozen = true; } diff --git a/dom/html/HTMLScriptElement.h b/dom/html/HTMLScriptElement.h index 6edeb9832..198df1ed0 100644 --- a/dom/html/HTMLScriptElement.h +++ b/dom/html/HTMLScriptElement.h @@ -41,7 +41,7 @@ public: virtual bool GetScriptType(nsAString& type) override; virtual void GetScriptText(nsAString& text) override; virtual void GetScriptCharset(nsAString& charset) override; - virtual void FreezeUriAsyncDefer() override; + virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) override; virtual CORSMode GetCORSMode() const override; // nsIContent diff --git a/dom/script/ModuleLoadRequest.cpp b/dom/script/ModuleLoadRequest.cpp index d62214304..743f30fb9 100644 --- a/dom/script/ModuleLoadRequest.cpp +++ b/dom/script/ModuleLoadRequest.cpp @@ -17,26 +17,54 @@ NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest) NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest, mBaseURL, mLoader, - mParent, mModuleScript, mImports) NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest) NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest) -ModuleLoadRequest::ModuleLoadRequest(nsIScriptElement* aElement, +ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI, + nsIScriptElement* aElement, uint32_t aVersion, CORSMode aCORSMode, const SRIMetadata &aIntegrity, + nsIURI* aReferrer, + mozilla::net::ReferrerPolicy aReferrerPolicy, ScriptLoader* aLoader) : ScriptLoadRequest(ScriptKind::Module, + aURI, aElement, aVersion, aCORSMode, - aIntegrity), + aIntegrity, + aReferrer, + aReferrerPolicy), mIsTopLevel(true), - mLoader(aLoader) -{} + mLoader(aLoader), + mVisitedSet(new VisitedURLSet()) +{ + mVisitedSet->PutEntry(aURI); +} + +ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI, + ModuleLoadRequest* aParent) + : ScriptLoadRequest(ScriptKind::Module, + aURI, + aParent->mElement, + aParent->mJSVersion, + aParent->mCORSMode, + SRIMetadata(), + aParent->mURI, + aParent->mReferrerPolicy), + mIsTopLevel(false), + mLoader(aParent->mLoader), + mVisitedSet(aParent->mVisitedSet) +{ + MOZ_ASSERT(mVisitedSet->Contains(aURI)); + + mIsInline = false; + mScriptMode = aParent->mScriptMode; +} void ModuleLoadRequest::Cancel() { @@ -83,7 +111,7 @@ ModuleLoadRequest::ModuleLoaded() // been loaded. mModuleScript = mLoader->GetFetchedModule(mURI); - if (!mModuleScript || mModuleScript->IsErrored()) { + if (!mModuleScript || mModuleScript->HasParseError()) { ModuleErrored(); return; } @@ -95,7 +123,7 @@ void ModuleLoadRequest::ModuleErrored() { mLoader->CheckModuleDependenciesLoaded(this); - MOZ_ASSERT(!mModuleScript || mModuleScript->IsErrored()); + MOZ_ASSERT(!mModuleScript || mModuleScript->HasParseError()); CancelImports(); SetReady(); @@ -132,8 +160,7 @@ ModuleLoadRequest::LoadFinished() { mLoader->ProcessLoadedModuleTree(this); mLoader = nullptr; - mParent = nullptr; } } // dom namespace -} // mozilla namespace \ No newline at end of file +} // mozilla namespace diff --git a/dom/script/ModuleLoadRequest.h b/dom/script/ModuleLoadRequest.h index 7b06dd2cf..eefb7dad5 100644 --- a/dom/script/ModuleLoadRequest.h +++ b/dom/script/ModuleLoadRequest.h @@ -8,6 +8,7 @@ #define mozilla_dom_ModuleLoadRequest_h #include "mozilla/dom/ScriptLoader.h" +#include "nsURIHashKey.h" #include "mozilla/MozPromise.h" namespace mozilla { @@ -16,6 +17,16 @@ namespace dom { class ModuleScript; class ScriptLoader; +// A reference counted set of URLs we have visited in the process of loading a +// module graph. +class VisitedURLSet : public nsTHashtable +{ + NS_INLINE_DECL_REFCOUNTING(VisitedURLSet) + +private: + ~VisitedURLSet() = default; +}; + // A load request for a module, created for every top level module script and // every module import. Load request can share a ModuleScript if there are // multiple imports of the same module. @@ -31,12 +42,20 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest) - ModuleLoadRequest(nsIScriptElement* aElement, + // Create a top-level module load request. + ModuleLoadRequest(nsIURI* aURI, + nsIScriptElement* aElement, uint32_t aVersion, CORSMode aCORSMode, const SRIMetadata& aIntegrity, + nsIURI* aReferrer, + mozilla::net::ReferrerPolicy, ScriptLoader* aLoader); + // Create a module load request for an imported module. + ModuleLoadRequest(nsIURI* aURI, + ModuleLoadRequest* aParent); + bool IsTopLevel() const { return mIsTopLevel; } @@ -55,7 +74,7 @@ private: public: // Is this a request for a top level module script or an import? - bool mIsTopLevel; + const bool mIsTopLevel; // The base URL used for resolving relative module imports. nsCOMPtr mBaseURL; @@ -64,10 +83,6 @@ public: // finishes. RefPtr mLoader; - // The importing module, or nullptr for top level module scripts. Used to - // implement the ancestor list checked when fetching module dependencies. - RefPtr mParent; - // Set to a module script object after a successful load or nullptr on // failure. RefPtr mModuleScript; @@ -79,9 +94,13 @@ public: // Array of imported modules. nsTArray> mImports; + + // Set of module URLs visited while fetching the module graph this request is + // part of. + RefPtr mVisitedSet; }; } // dom namespace } // mozilla namespace -#endif // mozilla_dom_ModuleLoadRequest_h \ No newline at end of file +#endif // mozilla_dom_ModuleLoadRequest_h diff --git a/dom/script/ModuleScript.cpp b/dom/script/ModuleScript.cpp index 28b97a3cb..1bf9d0b0f 100644 --- a/dom/script/ModuleScript.cpp +++ b/dom/script/ModuleScript.cpp @@ -26,7 +26,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript) NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader) NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL) tmp->UnlinkModuleRecord(); - tmp->mError.setUndefined(); + tmp->mParseError.setUndefined(); + tmp->mErrorToRethrow.setUndefined(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript) @@ -35,7 +36,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript) NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mError) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript) @@ -48,7 +50,8 @@ ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL) MOZ_ASSERT(mLoader); MOZ_ASSERT(mBaseURL); MOZ_ASSERT(!mModuleRecord); - MOZ_ASSERT(mError.isUndefined()); + MOZ_ASSERT(!HasParseError()); + MOZ_ASSERT(!HasErrorToRethrow()); } void @@ -74,7 +77,8 @@ void ModuleScript::SetModuleRecord(JS::Handle aModuleRecord) { MOZ_ASSERT(!mModuleRecord); - MOZ_ASSERT(mError.isUndefined()); + MOZ_ASSERT(!HasParseError()); + MOZ_ASSERT(!HasErrorToRethrow()); mModuleRecord = aModuleRecord; @@ -85,37 +89,24 @@ ModuleScript::SetModuleRecord(JS::Handle aModuleRecord) } void -ModuleScript::SetPreInstantiationError(const JS::Value& aError) +ModuleScript::SetParseError(const JS::Value& aError) { MOZ_ASSERT(!aError.isUndefined()); + MOZ_ASSERT(!HasParseError()); + MOZ_ASSERT(!HasErrorToRethrow()); UnlinkModuleRecord(); - mError = aError; - + mParseError = aError; HoldJSObjects(this); } -bool -ModuleScript::IsErrored() const +void +ModuleScript::SetErrorToRethrow(const JS::Value& aError) { - if (!mModuleRecord) { - MOZ_ASSERT(!mError.isUndefined()); - return true; - } + MOZ_ASSERT(!aError.isUndefined()); + MOZ_ASSERT(!HasErrorToRethrow()); - return JS::IsModuleErrored(mModuleRecord); -} - -JS::Value -ModuleScript::Error() const -{ - MOZ_ASSERT(IsErrored()); - - if (!mModuleRecord) { - return mError; - } - - return JS::GetModuleError(mModuleRecord); + mErrorToRethrow = aError; } } // dom namespace diff --git a/dom/script/ModuleScript.h b/dom/script/ModuleScript.h index 571359859..f765aa0fa 100644 --- a/dom/script/ModuleScript.h +++ b/dom/script/ModuleScript.h @@ -23,7 +23,8 @@ class ModuleScript final : public nsISupports RefPtr mLoader; nsCOMPtr mBaseURL; JS::Heap mModuleRecord; - JS::Heap mError; + JS::Heap mParseError; + JS::Heap mErrorToRethrow; ~ModuleScript(); @@ -35,14 +36,17 @@ public: nsIURI* aBaseURL); void SetModuleRecord(JS::Handle aModuleRecord); - void SetPreInstantiationError(const JS::Value& aError); + void SetParseError(const JS::Value& aError); + void SetErrorToRethrow(const JS::Value& aError); ScriptLoader* Loader() const { return mLoader; } JSObject* ModuleRecord() const { return mModuleRecord; } nsIURI* BaseURL() const { return mBaseURL; } - bool IsErrored() const; - JS::Value Error() const; + JS::Value ParseError() const { return mParseError; } + JS::Value ErrorToRethrow() const { return mErrorToRethrow; } + bool HasParseError() const { return !mParseError.isUndefined(); } + bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); } void UnlinkModuleRecord(); }; diff --git a/dom/script/ScriptElement.cpp b/dom/script/ScriptElement.cpp index 0cb17dcb0..eb20dbf32 100644 --- a/dom/script/ScriptElement.cpp +++ b/dom/script/ScriptElement.cpp @@ -21,11 +21,11 @@ using namespace mozilla::dom; NS_IMETHODIMP ScriptElement::ScriptAvailable(nsresult aResult, nsIScriptElement *aElement, - bool aIsInline, + bool aIsInlineClassicScript, nsIURI *aURI, int32_t aLineNo) { - if (!aIsInline && NS_FAILED(aResult)) { + if (!aIsInlineClassicScript && NS_FAILED(aResult)) { nsCOMPtr parser = do_QueryReferent(mCreatorParser); if (parser) { parser->PushDefinedInsertionPoint(); @@ -128,11 +128,11 @@ ScriptElement::MaybeProcessScript() return false; } - FreezeUriAsyncDefer(); + nsIDocument* ownerDoc = cont->OwnerDoc(); + FreezeExecutionAttrs(ownerDoc); mAlreadyStarted = true; - nsIDocument* ownerDoc = cont->OwnerDoc(); nsCOMPtr parser = ((nsIScriptElement*) this)->GetCreatorParser(); if (parser) { nsCOMPtr sink = parser->GetContentSink(); diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index a53098974..989301b91 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -140,6 +140,18 @@ ScriptLoadRequest::AsModuleRequest() return static_cast(this); } +void +ScriptLoadRequest::SetScriptMode(bool aDeferAttr, bool aAsyncAttr) +{ + if (aAsyncAttr) { + mScriptMode = ScriptMode::eAsync; + } else if (aDeferAttr || IsModuleRequest()) { + mScriptMode = ScriptMode::eDeferred; + } else { + mScriptMode = ScriptMode::eBlocking; + } +} + ////////////////////////////////////////////////////////////// // ScriptLoadRequestList @@ -299,8 +311,12 @@ ScriptLoader::~ScriptLoader() //