Backed out changeset 9d8b4c0b99ed (bug 1945683) for causing btime failures. CLOSED...
[gecko.git] / js / loader / ModuleLoadRequest.cpp
blobc6e31268060563c8cb93180efdeadbcfc0017153
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(
54 nsIURI* aURI, JS::ModuleType aModuleType) {
55 auto set = new VisitedURLSet();
56 set->PutEntry(ModuleMapKey(aURI, aModuleType));
57 return set;
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),
73 mLoader(aLoader),
74 mRootModule(aRootModule),
75 mVisitedSet(aVisitedSet) {
76 MOZ_ASSERT(mLoader);
79 nsIGlobalObject* ModuleLoadRequest::GetGlobalObject() {
80 return mLoader->GetGlobalObject();
83 bool ModuleLoadRequest::IsErrored() const {
84 return !mModuleScript || mModuleScript->HasParseError();
87 void ModuleLoadRequest::Cancel() {
88 if (IsCanceled()) {
89 AssertAllImportsCancelled();
90 return;
93 if (IsFinished()) {
94 return;
97 ScriptLoadRequest::Cancel();
99 mModuleScript = nullptr;
100 CancelImports();
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
123 // been loaded.
125 LOG(("ScriptLoadRequest (%p): Module loaded", this));
127 if (IsCanceled()) {
128 AssertAllImportsCancelled();
129 return;
132 MOZ_ASSERT(IsFetching() || IsPendingFetchingError());
134 mModuleScript = mLoader->GetFetchedModule(ModuleMapKey(mURI, mModuleType));
135 if (IsErrored()) {
136 ModuleErrored();
137 return;
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));
149 if (IsCanceled()) {
150 AssertAllImportsCancelled();
151 return;
154 MOZ_ASSERT(IsFetching() || IsPendingFetchingError());
155 MOZ_ASSERT(!mModuleScript);
157 Cancel();
158 LoadFinished();
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()) {
167 return;
170 MOZ_ASSERT(!IsFinished());
172 CheckModuleDependenciesLoaded();
173 MOZ_ASSERT(IsErrored());
175 CancelImports();
176 if (IsFinished()) {
177 // Cancelling an outstanding import will error this request.
178 return;
181 SetReady();
182 LoadFinished();
185 void ModuleLoadRequest::DependenciesLoaded() {
186 // The module and all of its dependencies have been successfully fetched and
187 // compiled.
189 LOG(("ScriptLoadRequest (%p): Module dependencies loaded", this));
191 if (IsCanceled()) {
192 return;
195 MOZ_ASSERT(IsLoadingImports());
196 MOZ_ASSERT(!IsErrored());
198 CheckModuleDependenciesLoaded();
199 AssertAllImportsFinished();
200 SetReady();
201 LoadFinished();
204 void ModuleLoadRequest::CheckModuleDependenciesLoaded() {
205 LOG(("ScriptLoadRequest (%p): Check dependencies loaded", this));
207 if (!mModuleScript || mModuleScript->HasParseError()) {
208 return;
211 for (const auto& childRequest : mImports) {
212 ModuleScript* childScript = childRequest->mModuleScript;
213 if (!childScript) {
214 mModuleScript = nullptr;
215 LOG(("ScriptLoadRequest (%p): %p failed (load error)", this,
216 childRequest.get()));
217 return;
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",
237 mImports[i].get()));
238 continue;
240 mImports[i]->Cancel();
243 mState = origState;
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);
264 mAwaitingImports--;
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 {
284 #ifdef DEBUG
285 for (const auto& request : mImports) {
286 MOZ_ASSERT(request->IsFinished());
288 #endif
291 inline void ModuleLoadRequest::AssertAllImportsCancelled() const {
292 #ifdef DEBUG
293 for (const auto& request : mImports) {
294 MOZ_ASSERT(request->IsCanceled());
296 #endif
299 } // namespace JS::loader