Bug 1943761 - Add class alignment to the mozsearch analysis file. r=asuth
[gecko.git] / js / xpconnect / loader / SyncModuleLoader.cpp
blob83fc0cf2dadc8cada183692aeb52ef3e8ad86e1e
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 "SyncModuleLoader.h"
9 #include "nsISupportsImpl.h"
11 #include "js/loader/ModuleLoadRequest.h"
12 #include "js/RootingAPI.h" // JS::Rooted
13 #include "js/PropertyAndElement.h" // JS_SetProperty
14 #include "js/Value.h" // JS::Value, JS::NumberValue
15 #include "mozJSModuleLoader.h"
17 using namespace JS::loader;
19 namespace mozilla {
20 namespace loader {
22 //////////////////////////////////////////////////////////////
23 // SyncScriptLoader
24 //////////////////////////////////////////////////////////////
26 NS_IMPL_ISUPPORTS0(SyncScriptLoader)
28 nsIURI* SyncScriptLoader::GetBaseURI() const { return nullptr; }
30 void SyncScriptLoader::ReportErrorToConsole(ScriptLoadRequest* aRequest,
31 nsresult aResult) const {}
33 void SyncScriptLoader::ReportWarningToConsole(
34 ScriptLoadRequest* aRequest, const char* aMessageName,
35 const nsTArray<nsString>& aParams) const {}
37 nsresult SyncScriptLoader::FillCompileOptionsForRequest(
38 JSContext* cx, ScriptLoadRequest* aRequest, JS::CompileOptions* aOptions,
39 JS::MutableHandle<JSScript*> aIntroductionScript) {
40 return NS_OK;
43 //////////////////////////////////////////////////////////////
44 // SyncModuleLoader
45 //////////////////////////////////////////////////////////////
47 NS_IMPL_ADDREF_INHERITED(SyncModuleLoader, JS::loader::ModuleLoaderBase)
48 NS_IMPL_RELEASE_INHERITED(SyncModuleLoader, JS::loader::ModuleLoaderBase)
50 NS_IMPL_CYCLE_COLLECTION_INHERITED(SyncModuleLoader,
51 JS::loader::ModuleLoaderBase, mLoadRequests)
53 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SyncModuleLoader)
54 NS_INTERFACE_MAP_END_INHERITING(JS::loader::ModuleLoaderBase)
56 SyncModuleLoader::SyncModuleLoader(SyncScriptLoader* aScriptLoader,
57 nsIGlobalObject* aGlobalObject)
58 : ModuleLoaderBase(aScriptLoader, aGlobalObject) {}
60 SyncModuleLoader::~SyncModuleLoader() { MOZ_ASSERT(mLoadRequests.isEmpty()); }
62 already_AddRefed<ModuleLoadRequest> SyncModuleLoader::CreateStaticImport(
63 nsIURI* aURI, JS::ModuleType aModuleType, ModuleLoadRequest* aParent) {
64 RefPtr<SyncLoadContext> context = new SyncLoadContext();
65 RefPtr<ModuleLoadRequest> request = new ModuleLoadRequest(
66 aURI, aModuleType, aParent->ReferrerPolicy(), aParent->mFetchOptions,
67 dom::SRIMetadata(), aParent->mURI, context, false, /* is top level */
68 false, /* is dynamic import */
69 this, aParent->mVisitedSet, aParent->GetRootModule());
70 request->NoCacheEntryFound();
71 return request.forget();
74 already_AddRefed<ModuleLoadRequest> SyncModuleLoader::CreateDynamicImport(
75 JSContext* aCx, nsIURI* aURI, JS::ModuleType aModuleType,
76 LoadedScript* aMaybeActiveScript, JS::Handle<JSString*> aSpecifier,
77 JS::Handle<JSObject*> aPromise) {
78 RefPtr<SyncLoadContext> context = new SyncLoadContext();
79 RefPtr<VisitedURLSet> visitedSet =
80 ModuleLoadRequest::NewVisitedSetForTopLevelImport(aURI, aModuleType);
81 RefPtr<ModuleLoadRequest> request = new ModuleLoadRequest(
82 aURI, aModuleType, aMaybeActiveScript->ReferrerPolicy(),
83 aMaybeActiveScript->GetFetchOptions(), dom::SRIMetadata(),
84 aMaybeActiveScript->BaseURL(), context,
85 /* aIsTopLevel = */ true, /* aIsDynamicImport = */ true, this,
86 visitedSet, nullptr);
88 request->SetDynamicImport(aMaybeActiveScript, aSpecifier, aPromise);
89 request->NoCacheEntryFound();
91 return request.forget();
94 void SyncModuleLoader::OnDynamicImportStarted(ModuleLoadRequest* aRequest) {
95 MOZ_ASSERT(aRequest->IsDynamicImport());
96 MOZ_ASSERT(!mLoadRequests.Contains(aRequest));
98 if (aRequest->IsFetching()) {
99 // This module is newly imported.
101 // DynamicImportRequests() can contain multiple requests when a dynamic
102 // import is performed while evaluating the top-level script of other
103 // dynamic imports.
105 // mLoadRequests should be empty given evaluation is performed after
106 // handling all fetching requests.
107 MOZ_ASSERT(DynamicImportRequests().Contains(aRequest));
108 MOZ_ASSERT(mLoadRequests.isEmpty());
110 nsresult rv = OnFetchComplete(aRequest, NS_OK);
111 if (NS_FAILED(rv)) {
112 mLoadRequests.CancelRequestsAndClear();
113 CancelDynamicImport(aRequest, rv);
114 return;
117 rv = ProcessRequests();
118 if (NS_FAILED(rv)) {
119 CancelDynamicImport(aRequest, rv);
120 return;
122 } else {
123 // This module had already been imported.
124 MOZ_ASSERT(DynamicImportRequests().isEmpty());
125 MOZ_ASSERT(mLoadRequests.isEmpty());
128 ProcessDynamicImport(aRequest);
131 bool SyncModuleLoader::CanStartLoad(ModuleLoadRequest* aRequest,
132 nsresult* aRvOut) {
133 return mozJSModuleLoader::IsTrustedScheme(aRequest->mURI);
136 nsresult SyncModuleLoader::StartFetch(ModuleLoadRequest* aRequest) {
137 MOZ_ASSERT(aRequest->HasLoadContext());
139 aRequest->mBaseURL = aRequest->mURI;
141 // Loading script source and compilation are intertwined in
142 // mozJSModuleLoader. Perform both operations here but only report load
143 // failures. Compilation failure is reported in CompileFetchedModule.
145 dom::AutoJSAPI jsapi;
146 if (!jsapi.Init(GetGlobalObject())) {
147 return NS_ERROR_FAILURE;
150 JSContext* cx = jsapi.cx();
151 JS::RootedScript script(cx);
152 nsresult rv =
153 mozJSModuleLoader::LoadSingleModuleScript(this, cx, aRequest, &script);
154 MOZ_ASSERT_IF(jsapi.HasException(), NS_FAILED(rv));
155 MOZ_ASSERT(bool(script) == NS_SUCCEEDED(rv));
157 // Check for failure to load script source and abort.
158 bool threwException = jsapi.HasException();
159 if (NS_FAILED(rv) && !threwException) {
160 nsAutoCString uri;
161 nsresult rv2 = aRequest->mURI->GetSpec(uri);
162 NS_ENSURE_SUCCESS(rv2, rv2);
164 JS_ReportErrorUTF8(cx, "Failed to load %s", PromiseFlatCString(uri).get());
166 // Remember the error for MaybeReportLoadError.
167 if (!mLoadException.initialized()) {
168 mLoadException.init(cx);
170 if (!jsapi.StealException(&mLoadException)) {
171 return NS_ERROR_OUT_OF_MEMORY;
174 if (mLoadException.isObject()) {
175 // Expose `nsresult`.
176 JS::Rooted<JS::Value> resultVal(cx, JS::NumberValue(uint32_t(rv)));
177 JS::Rooted<JSObject*> exceptionObj(cx, &mLoadException.toObject());
178 if (!JS_SetProperty(cx, exceptionObj, "result", resultVal)) {
179 // Ignore the error and keep reporting the exception without the result
180 // property.
181 JS_ClearPendingException(cx);
185 return rv;
188 // Otherwise remember the results in this context so we can report them later.
189 SyncLoadContext* context = aRequest->GetSyncLoadContext();
190 context->mRv = rv;
191 if (threwException) {
192 context->mExceptionValue.init(cx);
193 if (!jsapi.StealException(&context->mExceptionValue)) {
194 return NS_ERROR_OUT_OF_MEMORY;
197 if (script) {
198 context->mScript.init(cx);
199 context->mScript = script;
202 if (!aRequest->IsDynamicImport()) {
203 // NOTE: Dynamic import is stored into mDynamicImportRequests.
204 mLoadRequests.AppendElement(aRequest);
207 return NS_OK;
210 nsresult SyncModuleLoader::CompileFetchedModule(
211 JSContext* aCx, JS::Handle<JSObject*> aGlobal, JS::CompileOptions& aOptions,
212 ModuleLoadRequest* aRequest, JS::MutableHandle<JSObject*> aModuleOut) {
213 // Compilation already happened in StartFetch. Report the result here.
214 SyncLoadContext* context = aRequest->GetSyncLoadContext();
215 nsresult rv = context->mRv;
216 if (context->mScript) {
217 aModuleOut.set(JS::GetModuleObject(context->mScript));
218 context->mScript = nullptr;
220 if (NS_FAILED(rv)) {
221 JS_SetPendingException(aCx, context->mExceptionValue);
222 context->mExceptionValue = JS::UndefinedValue();
225 MOZ_ASSERT(JS_IsExceptionPending(aCx) == NS_FAILED(rv));
226 MOZ_ASSERT(bool(aModuleOut) == NS_SUCCEEDED(rv));
228 return rv;
231 void SyncModuleLoader::MaybeReportLoadError(JSContext* aCx) {
232 if (JS_IsExceptionPending(aCx)) {
233 // Do not override.
234 return;
237 if (mLoadException.isUndefined()) {
238 return;
241 JS_SetPendingException(aCx, mLoadException);
242 mLoadException = JS::UndefinedValue();
245 void SyncModuleLoader::OnModuleLoadComplete(ModuleLoadRequest* aRequest) {}
247 nsresult SyncModuleLoader::ProcessRequests() {
248 // Work list to drive module loader since this is all synchronous.
249 while (!mLoadRequests.isEmpty()) {
250 RefPtr<ScriptLoadRequest> request = mLoadRequests.StealFirst();
251 nsresult rv = OnFetchComplete(request->AsModuleRequest(), NS_OK);
252 if (NS_FAILED(rv)) {
253 mLoadRequests.CancelRequestsAndClear();
254 return rv;
258 return NS_OK;
261 } // namespace loader
262 } // namespace mozilla