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(
54 nsIURI
* aURI
, JS::ModuleType aModuleType
) {
55 auto set
= new VisitedURLSet();
56 set
->PutEntry(ModuleMapKey(aURI
, aModuleType
));
60 ModuleLoadRequest::ModuleLoadRequest(
61 nsIURI
* aURI
, JS::ModuleType aModuleType
,
62 mozilla::dom::ReferrerPolicy aReferrerPolicy
,
63 ScriptFetchOptions
* aFetchOptions
,
64 const mozilla::dom::SRIMetadata
& aIntegrity
, nsIURI
* aReferrer
,
65 LoadContextBase
* aContext
, bool aIsTopLevel
, bool aIsDynamicImport
,
66 ModuleLoaderBase
* aLoader
, VisitedURLSet
* aVisitedSet
,
67 ModuleLoadRequest
* aRootModule
)
68 : ScriptLoadRequest(ScriptKind::eModule
, aURI
, aReferrerPolicy
,
69 aFetchOptions
, aIntegrity
, aReferrer
, aContext
),
70 mIsTopLevel(aIsTopLevel
),
71 mModuleType(aModuleType
),
72 mIsDynamicImport(aIsDynamicImport
),
74 mRootModule(aRootModule
),
75 mVisitedSet(aVisitedSet
) {
79 nsIGlobalObject
* ModuleLoadRequest::GetGlobalObject() {
80 return mLoader
->GetGlobalObject();
83 bool ModuleLoadRequest::IsErrored() const {
84 return !mModuleScript
|| mModuleScript
->HasParseError();
87 void ModuleLoadRequest::Cancel() {
89 AssertAllImportsCancelled();
97 ScriptLoadRequest::Cancel();
99 mModuleScript
= nullptr;
102 if (mWaitingParentRequest
) {
103 ChildLoadComplete(false);
107 void ModuleLoadRequest::SetReady() {
108 MOZ_ASSERT(!IsFinished());
110 // Mark a module as ready to execute. This means that this module and all it
111 // dependencies have had their source loaded, parsed as a module and the
112 // modules instantiated.
114 ScriptLoadRequest::SetReady();
116 if (mWaitingParentRequest
) {
117 ChildLoadComplete(true);
121 void ModuleLoadRequest::ModuleLoaded() {
122 // A module that was found to be marked as fetching in the module map has now
125 LOG(("ScriptLoadRequest (%p): Module loaded", this));
128 AssertAllImportsCancelled();
132 MOZ_ASSERT(IsFetching() || IsPendingFetchingError());
134 mModuleScript
= mLoader
->GetFetchedModule(ModuleMapKey(mURI
, mModuleType
));
140 mLoader
->StartFetchingModuleDependencies(this);
143 void ModuleLoadRequest::LoadFailed() {
144 // We failed to load the source text or an error occurred unrelated to the
145 // content of the module (e.g. OOM).
147 LOG(("ScriptLoadRequest (%p): Module load failed", this));
150 AssertAllImportsCancelled();
154 MOZ_ASSERT(IsFetching() || IsPendingFetchingError());
155 MOZ_ASSERT(!mModuleScript
);
161 void ModuleLoadRequest::ModuleErrored() {
162 // Parse error, failure to resolve imported modules or error loading import.
164 LOG(("ScriptLoadRequest (%p): Module errored", this));
166 if (IsCanceled() || IsCancelingImports()) {
170 MOZ_ASSERT(!IsFinished());
172 CheckModuleDependenciesLoaded();
173 MOZ_ASSERT(IsErrored());
177 // Cancelling an outstanding import will error this request.
185 void ModuleLoadRequest::DependenciesLoaded() {
186 // The module and all of its dependencies have been successfully fetched and
189 LOG(("ScriptLoadRequest (%p): Module dependencies loaded", this));
195 MOZ_ASSERT(IsLoadingImports());
196 MOZ_ASSERT(!IsErrored());
198 CheckModuleDependenciesLoaded();
199 AssertAllImportsFinished();
204 void ModuleLoadRequest::CheckModuleDependenciesLoaded() {
205 LOG(("ScriptLoadRequest (%p): Check dependencies loaded", this));
207 if (!mModuleScript
|| mModuleScript
->HasParseError()) {
211 for (const auto& childRequest
: mImports
) {
212 ModuleScript
* childScript
= childRequest
->mModuleScript
;
214 mModuleScript
= nullptr;
215 LOG(("ScriptLoadRequest (%p): %p failed (load error)", this,
216 childRequest
.get()));
220 MOZ_DIAGNOSTIC_ASSERT(mModuleScript
->HadImportMap() ==
221 childScript
->HadImportMap());
224 LOG(("ScriptLoadRequest (%p): all ok", this));
227 void ModuleLoadRequest::CancelImports() {
228 State origState
= mState
;
230 // To prevent reentering ModuleErrored() for this request via mImports[i]'s
231 // ChildLoadComplete().
232 mState
= State::CancelingImports
;
234 for (size_t i
= 0; i
< mImports
.Length(); i
++) {
235 if (mLoader
->IsFetchingAndHasWaitingRequest(mImports
[i
])) {
236 LOG(("CancelImports import %p is fetching and has waiting\n",
240 mImports
[i
]->Cancel();
246 void ModuleLoadRequest::LoadFinished() {
247 RefPtr
<ModuleLoadRequest
> request(this);
248 if (IsTopLevel() && IsDynamicImport()) {
249 mLoader
->RemoveDynamicImport(request
);
252 mLoader
->OnModuleLoadComplete(request
);
255 void ModuleLoadRequest::ChildModuleUnlinked() {
256 // This module was waiting for a child request, but the child reqeust
257 // got unlinked by CC and will never complete.
258 // It also means this module itself is also in the cycle, and will be
259 // unlinked or has already been unlinked, and will be collected.
260 // There's no need to normally finish the module request.
261 // Just reflect the awaiting imports count, so that the assertion in the
262 // destructor passes.
263 MOZ_ASSERT(mAwaitingImports
> 0);
267 void ModuleLoadRequest::SetDynamicImport(LoadedScript
* aReferencingScript
,
268 JS::Handle
<JSString
*> aSpecifier
,
269 JS::Handle
<JSObject
*> aPromise
) {
270 mDynamicReferencingScript
= aReferencingScript
;
271 mDynamicSpecifier
= aSpecifier
;
272 mDynamicPromise
= aPromise
;
274 mozilla::HoldJSObjects(this);
277 void ModuleLoadRequest::ClearDynamicImport() {
278 mDynamicReferencingScript
= nullptr;
279 mDynamicSpecifier
= nullptr;
280 mDynamicPromise
= nullptr;
283 inline void ModuleLoadRequest::AssertAllImportsFinished() const {
285 for (const auto& request
: mImports
) {
286 MOZ_ASSERT(request
->IsFinished());
291 inline void ModuleLoadRequest::AssertAllImportsCancelled() const {
293 for (const auto& request
: mImports
) {
294 MOZ_ASSERT(request
->IsCanceled());
299 } // namespace JS::loader