Backed out changeset 4191b252db9b (bug 1886734) for causing build bustages @netwerk...
[gecko.git] / js / loader / ModuleLoadRequest.cpp
blob7313563df9d5f847d4968eac5c784b70c2c2fda0
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 {
18 #undef LOG
19 #define LOG(args) \
20 MOZ_LOG(ModuleLoaderBase::gModuleLoaderBaseLog, mozilla::LogLevel::Debug, \
21 args)
23 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(ModuleLoadRequest,
24 ScriptLoadRequest)
26 NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleLoadRequest)
28 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleLoadRequest,
29 ScriptLoadRequest)
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,
40 ScriptLoadRequest)
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,
47 ScriptLoadRequest)
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
52 /* static */
53 VisitedURLSet* ModuleLoadRequest::NewVisitedSetForTopLevelImport(nsIURI* aURI) {
54 auto set = new VisitedURLSet();
55 set->PutEntry(aURI);
56 return set;
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),
70 mLoader(aLoader),
71 mRootModule(aRootModule),
72 mVisitedSet(aVisitedSet) {
73 MOZ_ASSERT(mLoader);
76 nsIGlobalObject* ModuleLoadRequest::GetGlobalObject() {
77 return mLoader->GetGlobalObject();
80 bool ModuleLoadRequest::IsErrored() const {
81 return !mModuleScript || mModuleScript->HasParseError();
84 void ModuleLoadRequest::Cancel() {
85 if (IsCanceled()) {
86 AssertAllImportsCancelled();
87 return;
90 if (IsFinished()) {
91 return;
94 ScriptLoadRequest::Cancel();
96 mModuleScript = nullptr;
97 CancelImports();
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
122 // been loaded.
124 LOG(("ScriptLoadRequest (%p): Module loaded", this));
126 if (IsCanceled()) {
127 AssertAllImportsCancelled();
128 return;
131 MOZ_ASSERT(IsFetching() || IsPendingFetchingError());
133 mModuleScript = mLoader->GetFetchedModule(mURI);
134 if (IsErrored()) {
135 ModuleErrored();
136 return;
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));
148 if (IsCanceled()) {
149 AssertAllImportsCancelled();
150 return;
153 MOZ_ASSERT(IsFetching() || IsPendingFetchingError());
154 MOZ_ASSERT(!mModuleScript);
156 Cancel();
157 LoadFinished();
160 void ModuleLoadRequest::ModuleErrored() {
161 // Parse error, failure to resolve imported modules or error loading import.
163 LOG(("ScriptLoadRequest (%p): Module errored", this));
165 if (IsCanceled()) {
166 return;
169 MOZ_ASSERT(!IsFinished());
171 CheckModuleDependenciesLoaded();
172 MOZ_ASSERT(IsErrored());
174 CancelImports();
175 if (IsFinished()) {
176 // Cancelling an outstanding import will error this request.
177 return;
180 SetReady();
181 LoadFinished();
184 void ModuleLoadRequest::DependenciesLoaded() {
185 // The module and all of its dependencies have been successfully fetched and
186 // compiled.
188 LOG(("ScriptLoadRequest (%p): Module dependencies loaded", this));
190 if (IsCanceled()) {
191 return;
194 MOZ_ASSERT(IsLoadingImports());
195 MOZ_ASSERT(!IsErrored());
197 CheckModuleDependenciesLoaded();
198 SetReady();
199 LoadFinished();
202 void ModuleLoadRequest::CheckModuleDependenciesLoaded() {
203 LOG(("ScriptLoadRequest (%p): Check dependencies loaded", this));
205 if (!mModuleScript || mModuleScript->HasParseError()) {
206 return;
209 for (const auto& childRequest : mImports) {
210 ModuleScript* childScript = childRequest->mModuleScript;
211 if (!childScript) {
212 mModuleScript = nullptr;
213 LOG(("ScriptLoadRequest (%p): %p failed (load error)", this,
214 childRequest.get()));
215 return;
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);
249 mAwaitingImports--;
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 {
269 #ifdef DEBUG
270 for (const auto& request : mImports) {
271 MOZ_ASSERT(request->IsFinished());
273 #endif
276 inline void ModuleLoadRequest::AssertAllImportsCancelled() const {
277 #ifdef DEBUG
278 for (const auto& request : mImports) {
279 MOZ_ASSERT(request->IsCanceled());
281 #endif
284 } // namespace JS::loader