From 86e0057ea7f4c4e85fb32f79a2a1e034ccf918df Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 10 Apr 2023 08:48:20 -0500 Subject: [PATCH] Issue #1691 - Part 6b: Initial browser support for dynamic import from module scripts. https://bugzilla.mozilla.org/show_bug.cgi?id=1342012 Factor out script fetch options from script load request classes. https://bugzilla.mozilla.org/show_bug.cgi?id=1480720 Remove support for version parameter from script loader. https://bugzilla.mozilla.org/show_bug.cgi?id=1428745 (cherry picked from commit 3ec2529aa6303f6950622e3cb91a23580649c73b) --- dom/script/ModuleLoadRequest.cpp | 132 ++++++---- dom/script/ModuleLoadRequest.h | 44 +++- dom/script/ModuleScript.cpp | 40 ++- dom/script/ModuleScript.h | 8 +- dom/script/ScriptLoadHandler.cpp | 2 +- dom/script/ScriptLoader.cpp | 427 +++++++++++++++++++++++-------- dom/script/ScriptLoader.h | 103 ++++++-- 7 files changed, 557 insertions(+), 199 deletions(-) diff --git a/dom/script/ModuleLoadRequest.cpp b/dom/script/ModuleLoadRequest.cpp index 2abc6236e8..9144258c35 100644 --- a/dom/script/ModuleLoadRequest.cpp +++ b/dom/script/ModuleLoadRequest.cpp @@ -4,6 +4,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ModuleLoadRequest.h" + +#include "mozilla/HoldDropJSObjects.h" + #include "ModuleScript.h" #include "ScriptLoader.h" @@ -13,58 +16,93 @@ namespace dom { NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest) NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest) -NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest, - mBaseURL, - mLoader, - mModuleScript, - mImports) +NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleLoadRequest) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleLoadRequest, + ScriptLoadRequest) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL, mLoader, mModuleScript, mImports) + tmp->ClearDynamicImport(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleLoadRequest, + ScriptLoadRequest) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBaseURL, mLoader, mModuleScript, mImports) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleLoadRequest, + ScriptLoadRequest) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicReferencingPrivate) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicSpecifier) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicPromise) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest) NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest) -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, - aReferrer, - aReferrerPolicy), - mIsTopLevel(true), - mLoader(aLoader), - mVisitedSet(new VisitedURLSet()) -{ - mVisitedSet->PutEntry(aURI); +static VisitedURLSet* NewVisitedSetForTopLevelImport(nsIURI* aURI) { + auto set = new VisitedURLSet(); + set->PutEntry(aURI); + return set; } -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; +/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateTopLevel( + nsIURI* aURI, ScriptFetchOptions* aFetchOptions, + const SRIMetadata& aIntegrity, nsIURI* aReferrer, ScriptLoader* aLoader) { + return new ModuleLoadRequest(aURI, aFetchOptions, aIntegrity, aReferrer, + true, /* is top level */ + false, /* is dynamic import */ + aLoader, NewVisitedSetForTopLevelImport(aURI)); } +/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateStaticImport( + nsIURI* aURI, ModuleLoadRequest* aParent) { + auto request = + new ModuleLoadRequest(aURI, aParent->mFetchOptions, SRIMetadata(), + aParent->mURI, false, /* is top level */ + false, /* is dynamic import */ + aParent->mLoader, aParent->mVisitedSet); + + request->mIsInline = false; + request->mScriptMode = aParent->mScriptMode; + + return request; +} + +/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateDynamicImport( + nsIURI* aURI, ModuleScript* aScript, + JS::Handle aReferencingPrivate, JS::Handle aSpecifier, + JS::Handle aPromise) { + MOZ_ASSERT(aSpecifier); + MOZ_ASSERT(aPromise); + + auto request = new ModuleLoadRequest( + aURI, aScript->FetchOptions(), SRIMetadata(), aScript->BaseURL(), + true, /* is top level */ + true, /* is dynamic import */ + aScript->Loader(), NewVisitedSetForTopLevelImport(aURI)); + + request->mIsInline = false; + request->mScriptMode = ScriptMode::eAsync; + request->mDynamicReferencingPrivate = aReferencingPrivate; + request->mDynamicSpecifier = aSpecifier; + request->mDynamicPromise = aPromise; + + HoldJSObjects(request); + + return request; +} + +ModuleLoadRequest::ModuleLoadRequest( + nsIURI* aURI, ScriptFetchOptions* aFetchOptions, + const SRIMetadata& aIntegrity, nsIURI* aReferrer, bool aIsTopLevel, + bool aIsDynamicImport, ScriptLoader* aLoader, VisitedURLSet* aVisitedSet) + : ScriptLoadRequest(ScriptKind::Module, aURI, aFetchOptions, aIntegrity, + aReferrer), + mIsTopLevel(aIsTopLevel), + mIsDynamicImport(aIsDynamicImport), + mLoader(aLoader), + mVisitedSet(aVisitedSet) {} + void ModuleLoadRequest::Cancel() { ScriptLoadRequest::Cancel(); @@ -166,5 +204,11 @@ ModuleLoadRequest::LoadFinished() mLoader = nullptr; } +void ModuleLoadRequest::ClearDynamicImport() { + mDynamicReferencingPrivate = JS::UndefinedValue(); + mDynamicSpecifier = nullptr; + mDynamicPromise = nullptr; +} + } // dom namespace } // mozilla namespace diff --git a/dom/script/ModuleLoadRequest.h b/dom/script/ModuleLoadRequest.h index ad6573cf3b..996bac14d7 100644 --- a/dom/script/ModuleLoadRequest.h +++ b/dom/script/ModuleLoadRequest.h @@ -37,30 +37,42 @@ class ModuleLoadRequest final : public ScriptLoadRequest ModuleLoadRequest(const ModuleLoadRequest& aOther) = delete; ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete; + ModuleLoadRequest(nsIURI* aURI, ScriptFetchOptions* aFetchOptions, + const SRIMetadata& aIntegrity, nsIURI* aReferrer, + bool aIsTopLevel, bool aIsDynamicImport, + ScriptLoader* aLoader, VisitedURLSet* aVisitedSet); + public: NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleLoadRequest, + ScriptLoadRequest) // 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); + static ModuleLoadRequest* CreateTopLevel(nsIURI* aURI, + ScriptFetchOptions* aFetchOptions, + const SRIMetadata& aIntegrity, + nsIURI* aReferrer, + ScriptLoader* aLoader); - // Create a module load request for an imported module. - ModuleLoadRequest(nsIURI* aURI, - ModuleLoadRequest* aParent); + // Create a module load request for a static module import. + static ModuleLoadRequest* CreateStaticImport(nsIURI* aURI, + ModuleLoadRequest* aParent); + + // Create a module load request for dynamic module import. + static ModuleLoadRequest* CreateDynamicImport( + nsIURI* aURI, ModuleScript* aScript, + JS::Handle aReferencingPrivate, + JS::Handle aSpecifier, JS::Handle aPromise); bool IsTopLevel() const override { return mIsTopLevel; } + bool IsDynamicImport() const { return mIsDynamicImport; } + void SetReady() override; void Cancel() override; + void ClearDynamicImport(); void ModuleLoaded(); void ModuleErrored(); @@ -74,6 +86,9 @@ private: public: // Is this a request for a top level module script or an import? const bool mIsTopLevel; + + // Is this the top level request for a dynamic module import? + const bool mIsDynamicImport; // The base URL used for resolving relative module imports. nsCOMPtr mBaseURL; @@ -97,6 +112,11 @@ public: // Set of module URLs visited while fetching the module graph this request is // part of. RefPtr mVisitedSet; + + // For dynamic imports, the details to pass to FinishDynamicImport. + JS::Heap mDynamicReferencingPrivate; + JS::Heap mDynamicSpecifier; + JS::Heap mDynamicPromise; }; } // dom namespace diff --git a/dom/script/ModuleScript.cpp b/dom/script/ModuleScript.cpp index b2a72e6287..a8d6ce5343 100644 --- a/dom/script/ModuleScript.cpp +++ b/dom/script/ModuleScript.cpp @@ -7,9 +7,11 @@ * A class that handles loading and evaluation of