1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ModuleLoadRequest.h"
9 #include "mozilla/HoldDropJSObjects.h"
10 #include "mozilla/dom/ScriptLoadContext.h"
12 #include "LoadedScript.h"
13 #include "LoadContextBase.h"
14 #include "ModuleLoaderBase.h"
16 namespace JS::loader
{
20 MOZ_LOG(ModuleLoaderBase::gModuleLoaderBaseLog, mozilla::LogLevel::Debug, \
23 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(ModuleLoadRequest
,
26 NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleLoadRequest
)
28 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleLoadRequest
,
30 if (tmp
->mWaitingParentRequest
) {
31 tmp
->mWaitingParentRequest
->ChildModuleUnlinked();
33 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader
, mRootModule
, mModuleScript
, mImports
,
34 mWaitingParentRequest
,
35 mDynamicReferencingScript
)
36 tmp
->ClearDynamicImport();
37 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleLoadRequest
,
41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader
, mRootModule
, mModuleScript
,
42 mImports
, mWaitingParentRequest
,
43 mDynamicReferencingScript
)
44 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
46 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleLoadRequest
,
48 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicSpecifier
)
49 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicPromise
)
50 NS_IMPL_CYCLE_COLLECTION_TRACE_END
53 VisitedURLSet
* ModuleLoadRequest::NewVisitedSetForTopLevelImport(nsIURI
* aURI
) {
54 auto set
= new VisitedURLSet();
59 ModuleLoadRequest::ModuleLoadRequest(
60 nsIURI
* aURI
, mozilla::dom::ReferrerPolicy aReferrerPolicy
,
61 ScriptFetchOptions
* aFetchOptions
,
62 const mozilla::dom::SRIMetadata
& aIntegrity
, nsIURI
* aReferrer
,
63 LoadContextBase
* aContext
, bool aIsTopLevel
, bool aIsDynamicImport
,
64 ModuleLoaderBase
* aLoader
, VisitedURLSet
* aVisitedSet
,
65 ModuleLoadRequest
* aRootModule
)
66 : ScriptLoadRequest(ScriptKind::eModule
, aURI
, aReferrerPolicy
,
67 aFetchOptions
, aIntegrity
, aReferrer
, aContext
),
68 mIsTopLevel(aIsTopLevel
),
69 mIsDynamicImport(aIsDynamicImport
),
71 mRootModule(aRootModule
),
72 mVisitedSet(aVisitedSet
) {
76 nsIGlobalObject
* ModuleLoadRequest::GetGlobalObject() {
77 return mLoader
->GetGlobalObject();
80 bool ModuleLoadRequest::IsErrored() const {
81 return !mModuleScript
|| mModuleScript
->HasParseError();
84 void ModuleLoadRequest::Cancel() {
86 AssertAllImportsCancelled();
94 ScriptLoadRequest::Cancel();
96 mModuleScript
= nullptr;
99 if (mWaitingParentRequest
) {
100 ChildLoadComplete(false);
104 void ModuleLoadRequest::SetReady() {
105 MOZ_ASSERT(!IsFinished());
107 // Mark a module as ready to execute. This means that this module and all it
108 // dependencies have had their source loaded, parsed as a module and the
109 // modules instantiated.
111 AssertAllImportsFinished();
113 ScriptLoadRequest::SetReady();
115 if (mWaitingParentRequest
) {
116 ChildLoadComplete(true);
120 void ModuleLoadRequest::ModuleLoaded() {
121 // A module that was found to be marked as fetching in the module map has now
124 LOG(("ScriptLoadRequest (%p): Module loaded", this));
127 AssertAllImportsCancelled();
131 MOZ_ASSERT(IsFetching() || IsPendingFetchingError());
133 mModuleScript
= mLoader
->GetFetchedModule(mURI
);
139 mLoader
->StartFetchingModuleDependencies(this);
142 void ModuleLoadRequest::LoadFailed() {
143 // We failed to load the source text or an error occurred unrelated to the
144 // content of the module (e.g. OOM).
146 LOG(("ScriptLoadRequest (%p): Module load failed", this));
149 AssertAllImportsCancelled();
153 MOZ_ASSERT(IsFetching() || IsPendingFetchingError());
154 MOZ_ASSERT(!mModuleScript
);
160 void ModuleLoadRequest::ModuleErrored() {
161 // Parse error, failure to resolve imported modules or error loading import.
163 LOG(("ScriptLoadRequest (%p): Module errored", this));
169 MOZ_ASSERT(!IsFinished());
171 CheckModuleDependenciesLoaded();
172 MOZ_ASSERT(IsErrored());
176 // Cancelling an outstanding import will error this request.
184 void ModuleLoadRequest::DependenciesLoaded() {
185 // The module and all of its dependencies have been successfully fetched and
188 LOG(("ScriptLoadRequest (%p): Module dependencies loaded", this));
194 MOZ_ASSERT(IsLoadingImports());
195 MOZ_ASSERT(!IsErrored());
197 CheckModuleDependenciesLoaded();
202 void ModuleLoadRequest::CheckModuleDependenciesLoaded() {
203 LOG(("ScriptLoadRequest (%p): Check dependencies loaded", this));
205 if (!mModuleScript
|| mModuleScript
->HasParseError()) {
209 for (const auto& childRequest
: mImports
) {
210 ModuleScript
* childScript
= childRequest
->mModuleScript
;
212 mModuleScript
= nullptr;
213 LOG(("ScriptLoadRequest (%p): %p failed (load error)", this,
214 childRequest
.get()));
218 MOZ_DIAGNOSTIC_ASSERT(mModuleScript
->HadImportMap() ==
219 childScript
->HadImportMap());
222 LOG(("ScriptLoadRequest (%p): all ok", this));
225 void ModuleLoadRequest::CancelImports() {
226 for (size_t i
= 0; i
< mImports
.Length(); i
++) {
227 mImports
[i
]->Cancel();
231 void ModuleLoadRequest::LoadFinished() {
232 RefPtr
<ModuleLoadRequest
> request(this);
233 if (IsTopLevel() && IsDynamicImport()) {
234 mLoader
->RemoveDynamicImport(request
);
237 mLoader
->OnModuleLoadComplete(request
);
240 void ModuleLoadRequest::ChildModuleUnlinked() {
241 // This module was waiting for a child request, but the child reqeust
242 // got unlinked by CC and will never complete.
243 // It also means this module itself is also in the cycle, and will be
244 // unlinked or has already been unlinked, and will be collected.
245 // There's no need to normally finish the module request.
246 // Just reflect the awaiting imports count, so that the assertion in the
247 // destructor passes.
248 MOZ_ASSERT(mAwaitingImports
> 0);
252 void ModuleLoadRequest::SetDynamicImport(LoadedScript
* aReferencingScript
,
253 JS::Handle
<JSString
*> aSpecifier
,
254 JS::Handle
<JSObject
*> aPromise
) {
255 mDynamicReferencingScript
= aReferencingScript
;
256 mDynamicSpecifier
= aSpecifier
;
257 mDynamicPromise
= aPromise
;
259 mozilla::HoldJSObjects(this);
262 void ModuleLoadRequest::ClearDynamicImport() {
263 mDynamicReferencingScript
= nullptr;
264 mDynamicSpecifier
= nullptr;
265 mDynamicPromise
= nullptr;
268 inline void ModuleLoadRequest::AssertAllImportsFinished() const {
270 for (const auto& request
: mImports
) {
271 MOZ_ASSERT(request
->IsFinished());
276 inline void ModuleLoadRequest::AssertAllImportsCancelled() const {
278 for (const auto& request
: mImports
) {
279 MOZ_ASSERT(request
->IsCanceled());
284 } // namespace JS::loader