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 "GeckoProfiler.h"
8 #include "LoadedScript.h"
9 #include "ModuleLoadRequest.h"
10 #include "ScriptLoadRequest.h"
11 #include "mozilla/dom/ScriptSettings.h" // AutoJSAPI
12 #include "mozilla/dom/ScriptTrace.h"
14 #include "js/Array.h" // JS::GetArrayLength
15 #include "js/CompilationAndEvaluation.h"
16 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
17 #include "js/ContextOptions.h" // JS::ContextOptionsRef
18 #include "js/ErrorReport.h" // JSErrorBase
19 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
20 #include "js/Modules.h" // JS::FinishDynamicModuleImport, JS::{G,S}etModuleResolveHook, JS::Get{ModulePrivate,ModuleScript,RequestedModule{s,Specifier,SourcePos}}, JS::SetModule{DynamicImport,Metadata}Hook
21 #include "js/PropertyAndElement.h" // JS_DefineProperty, JS_GetElement
22 #include "js/SourceText.h"
23 #include "mozilla/BasePrincipal.h"
24 #include "mozilla/dom/AutoEntryScript.h"
25 #include "mozilla/dom/ScriptLoadContext.h"
26 #include "mozilla/CycleCollectedJSContext.h" // nsAutoMicroTask
27 #include "mozilla/Preferences.h"
28 #include "mozilla/StaticPrefs_dom.h"
29 #include "nsContentUtils.h"
30 #include "nsICacheInfoChannel.h" // nsICacheInfoChannel
31 #include "nsNetUtil.h" // NS_NewURI
32 #include "xpcpublic.h"
34 using mozilla::CycleCollectedJSContext
;
36 using mozilla::Preferences
;
37 using mozilla::UniquePtr
;
38 using mozilla::WrapNotNull
;
39 using mozilla::dom::AutoJSAPI
;
41 namespace JS::loader
{
43 mozilla::LazyLogModule
ModuleLoaderBase::gCspPRLog("CSP");
44 mozilla::LazyLogModule
ModuleLoaderBase::gModuleLoaderBaseLog(
49 MOZ_LOG(ModuleLoaderBase::gModuleLoaderBaseLog, mozilla::LogLevel::Debug, \
52 #define LOG_ENABLED() \
53 MOZ_LOG_TEST(ModuleLoaderBase::gModuleLoaderBaseLog, mozilla::LogLevel::Debug)
55 //////////////////////////////////////////////////////////////
56 // ModuleLoaderBase::WaitingRequests
57 //////////////////////////////////////////////////////////////
59 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleLoaderBase::WaitingRequests
)
60 NS_INTERFACE_MAP_ENTRY(nsISupports
)
63 NS_IMPL_CYCLE_COLLECTION(ModuleLoaderBase::WaitingRequests
, mWaiting
)
65 NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleLoaderBase::WaitingRequests
)
66 NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleLoaderBase::WaitingRequests
)
68 //////////////////////////////////////////////////////////////
70 //////////////////////////////////////////////////////////////
72 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleLoaderBase
)
73 NS_INTERFACE_MAP_ENTRY(nsISupports
)
76 NS_IMPL_CYCLE_COLLECTION(ModuleLoaderBase
, mFetchingModules
, mFetchedModules
,
77 mDynamicImportRequests
, mGlobalObject
, mEventTarget
,
80 NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleLoaderBase
)
81 NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleLoaderBase
)
84 void ModuleLoaderBase::EnsureModuleHooksInitialized() {
87 JSRuntime
* rt
= JS_GetRuntime(jsapi
.cx());
88 if (JS::GetModuleResolveHook(rt
)) {
92 JS::SetModuleResolveHook(rt
, HostResolveImportedModule
);
93 JS::SetModuleMetadataHook(rt
, HostPopulateImportMeta
);
94 JS::SetScriptPrivateReferenceHooks(rt
, HostAddRefTopLevelScript
,
95 HostReleaseTopLevelScript
);
96 JS::SetModuleDynamicImportHook(rt
, HostImportModuleDynamically
);
98 JS::ImportAssertionVector assertions
;
99 // ImportAssertionVector has inline storage for one element so this cannot
101 MOZ_ALWAYS_TRUE(assertions
.reserve(1));
102 assertions
.infallibleAppend(JS::ImportAssertion::Type
);
103 JS::SetSupportedImportAssertions(rt
, assertions
);
106 // 8.1.3.8.1 HostResolveImportedModule(referencingModule, moduleRequest)
108 * Implement the HostResolveImportedModule abstract operation.
110 * Resolve a module specifier string and look this up in the module
111 * map, returning the result. This is only called for previously
112 * loaded modules and always succeeds.
114 * @param aReferencingPrivate A JS::Value which is either undefined
115 * or contains a LoadedScript private pointer.
116 * @param aModuleRequest A module request object.
117 * @returns module This is set to the module found.
120 JSObject
* ModuleLoaderBase::HostResolveImportedModule(
121 JSContext
* aCx
, JS::Handle
<JS::Value
> aReferencingPrivate
,
122 JS::Handle
<JSObject
*> aModuleRequest
) {
123 JS::Rooted
<JSObject
*> module(aCx
);
126 // LoadedScript should only live in this block, otherwise it will be a GC
128 RefPtr
<LoadedScript
> script(
129 GetLoadedScriptOrNull(aCx
, aReferencingPrivate
));
131 JS::Rooted
<JSString
*> specifierString(
132 aCx
, JS::GetModuleRequestSpecifier(aCx
, aModuleRequest
));
133 if (!specifierString
) {
137 // Let url be the result of resolving a module specifier given referencing
138 // module script and specifier.
139 nsAutoJSString string
;
140 if (!string
.init(aCx
, specifierString
)) {
144 RefPtr
<ModuleLoaderBase
> loader
= GetCurrentModuleLoader(aCx
);
149 auto result
= loader
->ResolveModuleSpecifier(script
, string
);
150 // This cannot fail because resolving a module specifier must have been
151 // previously successful with these same two arguments.
152 MOZ_ASSERT(result
.isOk());
153 nsCOMPtr
<nsIURI
> uri
= result
.unwrap();
154 MOZ_ASSERT(uri
, "Failed to resolve previously-resolved module specifier");
156 // Let resolved module script be moduleMap[url]. (This entry must exist for
157 // us to have gotten to this point.)
158 ModuleScript
* ms
= loader
->GetFetchedModule(uri
);
159 MOZ_ASSERT(ms
, "Resolved module not found in module map");
160 MOZ_ASSERT(!ms
->HasParseError());
161 MOZ_ASSERT(ms
->ModuleRecord());
163 module
.set(ms
->ModuleRecord());
169 bool ModuleLoaderBase::ImportMetaResolve(JSContext
* cx
, unsigned argc
,
171 CallArgs args
= CallArgsFromVp(argc
, vp
);
172 RootedValue
modulePrivate(
173 cx
, js::GetFunctionNativeReserved(&args
.callee(), ModulePrivateSlot
));
175 // https://html.spec.whatwg.org/#hostgetimportmetaproperties
176 // Step 4.1. Set specifier to ? ToString(specifier).
178 // https://tc39.es/ecma262/#sec-tostring
179 RootedValue
v(cx
, args
.get(ImportMetaResolveSpecifierArg
));
180 RootedString
specifier(cx
, JS::ToString(cx
, v
));
185 // Step 4.2, 4.3 are implemented in ImportMetaResolveImpl.
186 RootedString
url(cx
, ImportMetaResolveImpl(cx
, modulePrivate
, specifier
));
191 // Step 4.4. Return the serialization of url.
192 args
.rval().setString(url
);
197 JSString
* ModuleLoaderBase::ImportMetaResolveImpl(
198 JSContext
* aCx
, JS::Handle
<JS::Value
> aReferencingPrivate
,
199 JS::Handle
<JSString
*> aSpecifier
) {
200 RootedString
urlString(aCx
);
203 // ModuleScript should only live in this block, otherwise it will be a GC
205 RefPtr
<ModuleScript
> script
=
206 static_cast<ModuleScript
*>(aReferencingPrivate
.toPrivate());
207 MOZ_ASSERT(script
->IsModuleScript());
208 MOZ_ASSERT(JS::GetModulePrivate(script
->ModuleRecord()) ==
209 aReferencingPrivate
);
211 RefPtr
<ModuleLoaderBase
> loader
= GetCurrentModuleLoader(aCx
);
216 nsAutoJSString specifier
;
217 if (!specifier
.init(aCx
, aSpecifier
)) {
221 auto result
= loader
->ResolveModuleSpecifier(script
, specifier
);
222 if (result
.isErr()) {
223 JS::Rooted
<JS::Value
> error(aCx
);
224 nsresult rv
= loader
->HandleResolveFailure(
225 aCx
, script
, specifier
, result
.unwrapErr(), 0,
226 JS::ColumnNumberOneOrigin(), &error
);
228 JS_ReportOutOfMemory(aCx
);
232 JS_SetPendingException(aCx
, error
);
237 nsCOMPtr
<nsIURI
> uri
= result
.unwrap();
239 MOZ_ALWAYS_SUCCEEDS(uri
->GetAsciiSpec(url
));
241 urlString
.set(JS_NewStringCopyZ(aCx
, url
.get()));
248 bool ModuleLoaderBase::HostPopulateImportMeta(
249 JSContext
* aCx
, JS::Handle
<JS::Value
> aReferencingPrivate
,
250 JS::Handle
<JSObject
*> aMetaObject
) {
251 RefPtr
<ModuleScript
> script
=
252 static_cast<ModuleScript
*>(aReferencingPrivate
.toPrivate());
253 MOZ_ASSERT(script
->IsModuleScript());
254 MOZ_ASSERT(JS::GetModulePrivate(script
->ModuleRecord()) ==
255 aReferencingPrivate
);
258 MOZ_DIAGNOSTIC_ASSERT(script
->BaseURL());
259 MOZ_ALWAYS_SUCCEEDS(script
->BaseURL()->GetAsciiSpec(url
));
261 JS::Rooted
<JSString
*> urlString(aCx
, JS_NewStringCopyZ(aCx
, url
.get()));
263 JS_ReportOutOfMemory(aCx
);
267 // https://html.spec.whatwg.org/#import-meta-url
268 if (!JS_DefineProperty(aCx
, aMetaObject
, "url", urlString
,
273 // https://html.spec.whatwg.org/#import-meta-resolve
274 // Define 'resolve' function on the import.meta object.
275 JSFunction
* resolveFunc
= js::DefineFunctionWithReserved(
276 aCx
, aMetaObject
, "resolve", ImportMetaResolve
, ImportMetaResolveNumArgs
,
282 // Store the 'active script' of the meta object into the function slot.
283 // https://html.spec.whatwg.org/#active-script
284 RootedObject
resolveFuncObj(aCx
, JS_GetFunctionObject(resolveFunc
));
285 js::SetFunctionNativeReserved(resolveFuncObj
, ModulePrivateSlot
,
286 aReferencingPrivate
);
292 bool ModuleLoaderBase::HostImportModuleDynamically(
293 JSContext
* aCx
, JS::Handle
<JS::Value
> aReferencingPrivate
,
294 JS::Handle
<JSObject
*> aModuleRequest
, JS::Handle
<JSObject
*> aPromise
) {
295 MOZ_DIAGNOSTIC_ASSERT(aModuleRequest
);
296 MOZ_DIAGNOSTIC_ASSERT(aPromise
);
298 RefPtr
<LoadedScript
> script(GetLoadedScriptOrNull(aCx
, aReferencingPrivate
));
300 JS::Rooted
<JSString
*> specifierString(
301 aCx
, JS::GetModuleRequestSpecifier(aCx
, aModuleRequest
));
302 if (!specifierString
) {
306 // Attempt to resolve the module specifier.
307 nsAutoJSString specifier
;
308 if (!specifier
.init(aCx
, specifierString
)) {
312 RefPtr
<ModuleLoaderBase
> loader
= GetCurrentModuleLoader(aCx
);
317 auto result
= loader
->ResolveModuleSpecifier(script
, specifier
);
318 if (result
.isErr()) {
319 JS::Rooted
<JS::Value
> error(aCx
);
321 loader
->HandleResolveFailure(aCx
, script
, specifier
, result
.unwrapErr(),
322 0, JS::ColumnNumberOneOrigin(), &error
);
324 JS_ReportOutOfMemory(aCx
);
328 JS_SetPendingException(aCx
, error
);
332 // Create a new top-level load request.
333 nsCOMPtr
<nsIURI
> uri
= result
.unwrap();
334 RefPtr
<ModuleLoadRequest
> request
=
335 loader
->CreateDynamicImport(aCx
, uri
, script
, specifierString
, aPromise
);
338 // Throws TypeError if CreateDynamicImport returns nullptr.
339 JS_ReportErrorNumberASCII(aCx
, js::GetErrorMessage
, nullptr,
340 JSMSG_DYNAMIC_IMPORT_NOT_SUPPORTED
);
345 loader
->StartDynamicImport(request
);
350 ModuleLoaderBase
* ModuleLoaderBase::GetCurrentModuleLoader(JSContext
* aCx
) {
351 auto reportError
= mozilla::MakeScopeExit([aCx
]() {
352 JS_ReportErrorASCII(aCx
, "No ScriptLoader found for the current context");
355 JS::Rooted
<JSObject
*> object(aCx
, JS::CurrentGlobalOrNull(aCx
));
360 nsIGlobalObject
* global
= xpc::NativeGlobal(object
);
365 ModuleLoaderBase
* loader
= global
->GetModuleLoader(aCx
);
370 MOZ_ASSERT(loader
->mGlobalObject
== global
);
372 reportError
.release();
377 LoadedScript
* ModuleLoaderBase::GetLoadedScriptOrNull(
378 JSContext
* aCx
, JS::Handle
<JS::Value
> aReferencingPrivate
) {
379 if (aReferencingPrivate
.isUndefined()) {
383 auto* script
= static_cast<LoadedScript
*>(aReferencingPrivate
.toPrivate());
386 script
->IsModuleScript(),
387 JS::GetModulePrivate(script
->AsModuleScript()->ModuleRecord()) ==
388 aReferencingPrivate
);
393 JS::Value
PrivateFromLoadedScript(LoadedScript
* aScript
) {
395 return JS::UndefinedValue();
398 return JS::PrivateValue(aScript
);
401 nsresult
ModuleLoaderBase::StartModuleLoad(ModuleLoadRequest
* aRequest
) {
402 return StartOrRestartModuleLoad(aRequest
, RestartRequest::No
);
405 nsresult
ModuleLoaderBase::RestartModuleLoad(ModuleLoadRequest
* aRequest
) {
406 return StartOrRestartModuleLoad(aRequest
, RestartRequest::Yes
);
409 nsresult
ModuleLoaderBase::StartOrRestartModuleLoad(ModuleLoadRequest
* aRequest
,
410 RestartRequest aRestart
) {
411 MOZ_ASSERT(aRequest
->mLoader
== this);
412 MOZ_ASSERT(aRequest
->IsFetching() || aRequest
->IsPendingFetchingError());
414 aRequest
->SetUnknownDataType();
416 // If we're restarting the request, the module should already be in the
418 MOZ_ASSERT_IF(aRestart
== RestartRequest::Yes
,
419 IsModuleFetching(aRequest
->mURI
));
421 // Check with the derived class whether we should load this module.
423 if (!CanStartLoad(aRequest
, &rv
)) {
427 // Check whether the module has been fetched or is currently being fetched,
428 // and if so wait for it rather than starting a new fetch.
429 ModuleLoadRequest
* request
= aRequest
->AsModuleRequest();
431 if (aRestart
== RestartRequest::No
&& ModuleMapContainsURL(request
->mURI
)) {
432 LOG(("ScriptLoadRequest (%p): Waiting for module fetch", aRequest
));
433 WaitForModuleFetch(request
);
437 rv
= StartFetch(aRequest
);
438 NS_ENSURE_SUCCESS(rv
, rv
);
440 // We successfully started fetching a module so put its URL in the module
441 // map and mark it as fetching.
442 if (aRestart
== RestartRequest::No
) {
443 SetModuleFetchStarted(aRequest
->AsModuleRequest());
449 bool ModuleLoaderBase::ModuleMapContainsURL(nsIURI
* aURL
) const {
450 return IsModuleFetching(aURL
) || IsModuleFetched(aURL
);
453 bool ModuleLoaderBase::IsModuleFetching(nsIURI
* aURL
) const {
454 return mFetchingModules
.Contains(aURL
);
457 bool ModuleLoaderBase::IsModuleFetched(nsIURI
* aURL
) const {
458 return mFetchedModules
.Contains(aURL
);
461 nsresult
ModuleLoaderBase::GetFetchedModuleURLs(nsTArray
<nsCString
>& aURLs
) {
462 for (const auto& entry
: mFetchedModules
) {
463 nsIURI
* uri
= entry
.GetData()->BaseURL();
466 nsresult rv
= uri
->GetSpec(spec
);
467 NS_ENSURE_SUCCESS(rv
, rv
);
469 aURLs
.AppendElement(spec
);
475 void ModuleLoaderBase::SetModuleFetchStarted(ModuleLoadRequest
* aRequest
) {
476 // Update the module map to indicate that a module is currently being fetched.
478 MOZ_ASSERT(aRequest
->IsFetching() || aRequest
->IsPendingFetchingError());
479 MOZ_ASSERT(!ModuleMapContainsURL(aRequest
->mURI
));
481 mFetchingModules
.InsertOrUpdate(aRequest
->mURI
, nullptr);
484 void ModuleLoaderBase::SetModuleFetchFinishedAndResumeWaitingRequests(
485 ModuleLoadRequest
* aRequest
, nsresult aResult
) {
486 // Update module map with the result of fetching a single module script.
488 // If any requests for the same URL are waiting on this one to complete, call
489 // ModuleLoaded or LoadFailed to resume or fail them as appropriate.
491 MOZ_ASSERT(aRequest
->mLoader
== this);
494 ("ScriptLoadRequest (%p): Module fetch finished (script == %p, result == "
496 aRequest
, aRequest
->mModuleScript
.get(), unsigned(aResult
)));
498 RefPtr
<WaitingRequests
> waitingRequests
;
499 if (!mFetchingModules
.Remove(aRequest
->mURI
,
500 getter_AddRefs(waitingRequests
))) {
502 ("ScriptLoadRequest (%p): Key not found in mFetchingModules, "
503 "assuming we have an inline module or have finished fetching already",
508 RefPtr
<ModuleScript
> moduleScript(aRequest
->mModuleScript
);
509 MOZ_ASSERT(NS_FAILED(aResult
) == !moduleScript
);
511 mFetchedModules
.InsertOrUpdate(aRequest
->mURI
, RefPtr
{moduleScript
});
513 if (waitingRequests
) {
514 LOG(("ScriptLoadRequest (%p): Resuming waiting requests", aRequest
));
515 ResumeWaitingRequests(waitingRequests
, bool(moduleScript
));
519 void ModuleLoaderBase::ResumeWaitingRequests(WaitingRequests
* aWaitingRequests
,
521 for (ModuleLoadRequest
* request
: aWaitingRequests
->mWaiting
) {
522 ResumeWaitingRequest(request
, aSuccess
);
526 void ModuleLoaderBase::ResumeWaitingRequest(ModuleLoadRequest
* aRequest
,
529 aRequest
->ModuleLoaded();
531 aRequest
->LoadFailed();
535 void ModuleLoaderBase::WaitForModuleFetch(ModuleLoadRequest
* aRequest
) {
536 nsIURI
* uri
= aRequest
->mURI
;
537 MOZ_ASSERT(ModuleMapContainsURL(uri
));
539 if (auto entry
= mFetchingModules
.Lookup(uri
)) {
540 RefPtr
<WaitingRequests
> waitingRequests
= entry
.Data();
541 if (!waitingRequests
) {
542 waitingRequests
= new WaitingRequests();
543 mFetchingModules
.InsertOrUpdate(uri
, waitingRequests
);
546 waitingRequests
->mWaiting
.AppendElement(aRequest
);
550 RefPtr
<ModuleScript
> ms
;
551 MOZ_ALWAYS_TRUE(mFetchedModules
.Get(uri
, getter_AddRefs(ms
)));
553 ResumeWaitingRequest(aRequest
, bool(ms
));
556 ModuleScript
* ModuleLoaderBase::GetFetchedModule(nsIURI
* aURL
) const {
559 aURL
->GetAsciiSpec(url
);
560 LOG(("GetFetchedModule %s", url
.get()));
564 ModuleScript
* ms
= mFetchedModules
.GetWeak(aURL
, &found
);
569 nsresult
ModuleLoaderBase::OnFetchComplete(ModuleLoadRequest
* aRequest
,
571 MOZ_ASSERT(aRequest
->mLoader
== this);
572 MOZ_ASSERT(!aRequest
->mModuleScript
);
575 if (NS_SUCCEEDED(rv
)) {
576 rv
= CreateModuleScript(aRequest
);
578 // If a module script was created, it should either have a module record
579 // object or a parse error.
580 if (ModuleScript
* ms
= aRequest
->mModuleScript
) {
581 MOZ_DIAGNOSTIC_ASSERT(bool(ms
->ModuleRecord()) != ms
->HasParseError());
584 aRequest
->ClearScriptSource();
587 aRequest
->LoadFailed();
592 MOZ_ASSERT(NS_SUCCEEDED(rv
) == bool(aRequest
->mModuleScript
));
593 SetModuleFetchFinishedAndResumeWaitingRequests(aRequest
, rv
);
595 if (!aRequest
->IsErrored()) {
596 StartFetchingModuleDependencies(aRequest
);
602 nsresult
ModuleLoaderBase::CreateModuleScript(ModuleLoadRequest
* aRequest
) {
603 MOZ_ASSERT(!aRequest
->mModuleScript
);
604 MOZ_ASSERT(aRequest
->mBaseURL
);
606 LOG(("ScriptLoadRequest (%p): Create module script", aRequest
));
609 if (!jsapi
.Init(mGlobalObject
)) {
610 return NS_ERROR_FAILURE
;
615 JSContext
* cx
= jsapi
.cx();
616 JS::Rooted
<JSObject
*> module(cx
);
618 JS::CompileOptions
options(cx
);
619 JS::RootedScript
introductionScript(cx
);
620 rv
= mLoader
->FillCompileOptionsForRequest(cx
, aRequest
, &options
,
621 &introductionScript
);
623 if (NS_SUCCEEDED(rv
)) {
624 JS::Rooted
<JSObject
*> global(cx
, mGlobalObject
->GetGlobalJSObject());
625 rv
= CompileFetchedModule(cx
, global
, options
, aRequest
, &module
);
628 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv
) == (module
!= nullptr));
631 JS::RootedValue
privateValue(cx
);
632 JS::RootedScript
moduleScript(cx
, JS::GetModuleScript(module
));
633 JS::InstantiateOptions
instantiateOptions(options
);
634 if (!JS::UpdateDebugMetadata(cx
, moduleScript
, instantiateOptions
,
635 privateValue
, nullptr, introductionScript
,
637 return NS_ERROR_OUT_OF_MEMORY
;
641 MOZ_ASSERT(aRequest
->mLoadedScript
->IsModuleScript());
642 MOZ_ASSERT(aRequest
->mLoadedScript
->GetFetchOptions() ==
643 aRequest
->mFetchOptions
);
644 MOZ_ASSERT(aRequest
->mLoadedScript
->GetURI() == aRequest
->mURI
);
645 aRequest
->mLoadedScript
->SetBaseURL(aRequest
->mBaseURL
);
646 RefPtr
<ModuleScript
> moduleScript
=
647 aRequest
->mLoadedScript
->AsModuleScript();
648 aRequest
->mModuleScript
= moduleScript
;
651 LOG(("ScriptLoadRequest (%p): compilation failed (%d)", aRequest
,
654 JS::Rooted
<JS::Value
> error(cx
);
655 if (!jsapi
.HasException() || !jsapi
.StealException(&error
) ||
656 error
.isUndefined()) {
657 aRequest
->mModuleScript
= nullptr;
658 return NS_ERROR_FAILURE
;
661 moduleScript
->SetParseError(error
);
662 aRequest
->ModuleErrored();
666 moduleScript
->SetModuleRecord(module
);
668 // Validate requested modules and treat failure to resolve module specifiers
669 // the same as a parse error.
670 rv
= ResolveRequestedModules(aRequest
, nullptr);
672 if (!aRequest
->IsErrored()) {
673 aRequest
->mModuleScript
= nullptr;
676 aRequest
->ModuleErrored();
681 LOG(("ScriptLoadRequest (%p): module script == %p", aRequest
,
682 aRequest
->mModuleScript
.get()));
687 nsresult
ModuleLoaderBase::GetResolveFailureMessage(ResolveError aError
,
688 const nsAString
& aSpecifier
,
689 nsAString
& aResult
) {
690 AutoTArray
<nsString
, 1> errorParams
;
691 errorParams
.AppendElement(aSpecifier
);
693 nsresult rv
= nsContentUtils::FormatLocalizedString(
694 nsContentUtils::eDOM_PROPERTIES
, ResolveErrorInfo::GetString(aError
),
695 errorParams
, aResult
);
696 NS_ENSURE_SUCCESS(rv
, rv
);
700 nsresult
ModuleLoaderBase::HandleResolveFailure(
701 JSContext
* aCx
, LoadedScript
* aScript
, const nsAString
& aSpecifier
,
702 ResolveError aError
, uint32_t aLineNumber
,
703 JS::ColumnNumberOneOrigin aColumnNumber
,
704 JS::MutableHandle
<JS::Value
> aErrorOut
) {
705 JS::Rooted
<JSString
*> filename(aCx
);
708 aScript
->BaseURL()->GetAsciiSpec(url
);
709 filename
= JS_NewStringCopyZ(aCx
, url
.get());
711 filename
= JS_NewStringCopyZ(aCx
, "(unknown)");
715 return NS_ERROR_OUT_OF_MEMORY
;
718 nsAutoString errorText
;
719 nsresult rv
= GetResolveFailureMessage(aError
, aSpecifier
, errorText
);
720 NS_ENSURE_SUCCESS(rv
, rv
);
722 JS::Rooted
<JSString
*> string(aCx
, JS_NewUCStringCopyZ(aCx
, errorText
.get()));
724 return NS_ERROR_OUT_OF_MEMORY
;
727 if (!JS::CreateError(aCx
, JSEXN_TYPEERR
, nullptr, filename
, aLineNumber
,
728 aColumnNumber
, nullptr, string
, JS::NothingHandleValue
,
730 return NS_ERROR_OUT_OF_MEMORY
;
736 ResolveResult
ModuleLoaderBase::ResolveModuleSpecifier(
737 LoadedScript
* aScript
, const nsAString
& aSpecifier
) {
738 // Import Maps are not supported on workers/worklets.
739 // See https://github.com/WICG/import-maps/issues/2
740 MOZ_ASSERT_IF(!NS_IsMainThread(), mImportMap
== nullptr);
741 // Forward to the updated 'Resolve a module specifier' algorithm defined in
742 // the Import Maps spec.
743 return ImportMap::ResolveModuleSpecifier(mImportMap
.get(), mLoader
, aScript
,
747 nsresult
ModuleLoaderBase::ResolveRequestedModules(
748 ModuleLoadRequest
* aRequest
, nsCOMArray
<nsIURI
>* aUrlsOut
) {
749 ModuleScript
* ms
= aRequest
->mModuleScript
;
752 if (!jsapi
.Init(mGlobalObject
)) {
753 return NS_ERROR_FAILURE
;
756 JSContext
* cx
= jsapi
.cx();
757 JS::Rooted
<JSObject
*> moduleRecord(cx
, ms
->ModuleRecord());
758 uint32_t length
= JS::GetRequestedModulesCount(cx
, moduleRecord
);
760 for (uint32_t i
= 0; i
< length
; i
++) {
761 JS::Rooted
<JSString
*> str(
762 cx
, JS::GetRequestedModuleSpecifier(cx
, moduleRecord
, i
));
765 nsAutoJSString specifier
;
766 if (!specifier
.init(cx
, str
)) {
767 return NS_ERROR_FAILURE
;
770 // Let url be the result of resolving a module specifier given module script
772 ModuleLoaderBase
* loader
= aRequest
->mLoader
;
773 auto result
= loader
->ResolveModuleSpecifier(ms
, specifier
);
774 if (result
.isErr()) {
775 uint32_t lineNumber
= 0;
776 JS::ColumnNumberOneOrigin columnNumber
;
777 JS::GetRequestedModuleSourcePos(cx
, moduleRecord
, i
, &lineNumber
,
780 JS::Rooted
<JS::Value
> error(cx
);
782 loader
->HandleResolveFailure(cx
, ms
, specifier
, result
.unwrapErr(),
783 lineNumber
, columnNumber
, &error
);
784 NS_ENSURE_SUCCESS(rv
, rv
);
786 ms
->SetParseError(error
);
787 return NS_ERROR_FAILURE
;
790 nsCOMPtr
<nsIURI
> uri
= result
.unwrap();
792 aUrlsOut
->AppendElement(uri
.forget());
799 void ModuleLoaderBase::StartFetchingModuleDependencies(
800 ModuleLoadRequest
* aRequest
) {
801 LOG(("ScriptLoadRequest (%p): Start fetching module dependencies", aRequest
));
803 if (aRequest
->IsCanceled()) {
807 MOZ_ASSERT(aRequest
->mModuleScript
);
808 MOZ_ASSERT(!aRequest
->mModuleScript
->HasParseError());
809 MOZ_ASSERT(aRequest
->IsFetching() || aRequest
->IsCompiling());
811 auto visitedSet
= aRequest
->mVisitedSet
;
812 MOZ_ASSERT(visitedSet
->Contains(aRequest
->mURI
));
814 aRequest
->mState
= ModuleLoadRequest::State::LoadingImports
;
816 nsCOMArray
<nsIURI
> urls
;
817 nsresult rv
= ResolveRequestedModules(aRequest
, &urls
);
819 aRequest
->mModuleScript
= nullptr;
820 aRequest
->ModuleErrored();
824 // Remove already visited URLs from the list. Put unvisited URLs into the
827 while (i
< urls
.Count()) {
828 nsIURI
* url
= urls
[i
];
829 if (visitedSet
->Contains(url
)) {
830 urls
.RemoveObjectAt(i
);
832 visitedSet
->PutEntry(url
);
837 if (urls
.Count() == 0) {
838 // There are no descendants to load so this request is ready.
839 aRequest
->DependenciesLoaded();
843 MOZ_ASSERT(aRequest
->mAwaitingImports
== 0);
844 aRequest
->mAwaitingImports
= urls
.Count();
846 // For each url in urls, fetch a module script graph given url, module
847 // script's CORS setting, and module script's settings object.
848 for (auto* url
: urls
) {
849 StartFetchingModuleAndDependencies(aRequest
, url
);
853 void ModuleLoaderBase::StartFetchingModuleAndDependencies(
854 ModuleLoadRequest
* aParent
, nsIURI
* aURI
) {
857 RefPtr
<ModuleLoadRequest
> childRequest
= CreateStaticImport(aURI
, aParent
);
859 aParent
->mImports
.AppendElement(childRequest
);
863 aParent
->mURI
->GetAsciiSpec(url1
);
866 aURI
->GetAsciiSpec(url2
);
868 LOG(("ScriptLoadRequest (%p): Start fetching dependency %p", aParent
,
869 childRequest
.get()));
870 LOG(("StartFetchingModuleAndDependencies \"%s\" -> \"%s\"", url1
.get(),
874 MOZ_ASSERT(!childRequest
->mWaitingParentRequest
);
875 childRequest
->mWaitingParentRequest
= aParent
;
877 nsresult rv
= StartModuleLoad(childRequest
);
879 MOZ_ASSERT(!childRequest
->mModuleScript
);
880 LOG(("ScriptLoadRequest (%p): rejecting %p", aParent
,
881 childRequest
.get()));
883 mLoader
->ReportErrorToConsole(childRequest
, rv
);
884 childRequest
->LoadFailed();
888 void ModuleLoadRequest::ChildLoadComplete(bool aSuccess
) {
889 RefPtr
<ModuleLoadRequest
> parent
= mWaitingParentRequest
;
891 MOZ_ASSERT(parent
->mAwaitingImports
!= 0);
893 mWaitingParentRequest
= nullptr;
894 parent
->mAwaitingImports
--;
896 if (parent
->IsFinished()) {
897 MOZ_ASSERT_IF(!aSuccess
, parent
->IsErrored());
902 parent
->ModuleErrored();
903 } else if (parent
->mAwaitingImports
== 0) {
904 parent
->DependenciesLoaded();
908 void ModuleLoaderBase::StartDynamicImport(ModuleLoadRequest
* aRequest
) {
909 MOZ_ASSERT(aRequest
->mLoader
== this);
911 LOG(("ScriptLoadRequest (%p): Start dynamic import", aRequest
));
913 mDynamicImportRequests
.AppendElement(aRequest
);
915 nsresult rv
= StartModuleLoad(aRequest
);
917 mLoader
->ReportErrorToConsole(aRequest
, rv
);
918 FinishDynamicImportAndReject(aRequest
, rv
);
922 void ModuleLoaderBase::FinishDynamicImportAndReject(ModuleLoadRequest
* aRequest
,
925 MOZ_ASSERT(NS_FAILED(aResult
));
926 if (!jsapi
.Init(mGlobalObject
)) {
930 FinishDynamicImport(jsapi
.cx(), aRequest
, aResult
, nullptr);
934 void ModuleLoaderBase::FinishDynamicImport(
935 JSContext
* aCx
, ModuleLoadRequest
* aRequest
, nsresult aResult
,
936 JS::Handle
<JSObject
*> aEvaluationPromise
) {
937 LOG(("ScriptLoadRequest (%p): Finish dynamic import %x %d", aRequest
,
938 unsigned(aResult
), JS_IsExceptionPending(aCx
)));
940 MOZ_ASSERT(GetCurrentModuleLoader(aCx
) == aRequest
->mLoader
);
942 // If aResult is a failed result, we don't have an EvaluationPromise. If it
943 // succeeded, evaluationPromise may still be null, but in this case it will
944 // be handled by rejecting the dynamic module import promise in the JSAPI.
945 MOZ_ASSERT_IF(NS_FAILED(aResult
), !aEvaluationPromise
);
947 // Complete the dynamic import, report failures indicated by aResult or as a
948 // pending exception on the context.
950 if (!aRequest
->mDynamicPromise
) {
951 // Import has already been completed.
955 if (NS_FAILED(aResult
) &&
956 aResult
!= NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE
) {
957 MOZ_ASSERT(!JS_IsExceptionPending(aCx
));
959 aRequest
->mURI
->GetSpec(url
);
960 JS_ReportErrorNumberASCII(aCx
, js::GetErrorMessage
, nullptr,
961 JSMSG_DYNAMIC_IMPORT_FAILED
, url
.get());
964 JS::Rooted
<JS::Value
> referencingScript(
965 aCx
, PrivateFromLoadedScript(aRequest
->mDynamicReferencingScript
));
966 JS::Rooted
<JSString
*> specifier(aCx
, aRequest
->mDynamicSpecifier
);
967 JS::Rooted
<JSObject
*> promise(aCx
, aRequest
->mDynamicPromise
);
969 JS::Rooted
<JSObject
*> moduleRequest(aCx
,
970 JS::CreateModuleRequest(aCx
, specifier
));
972 JS::FinishDynamicModuleImport(aCx
, aEvaluationPromise
, referencingScript
,
973 moduleRequest
, promise
);
975 // FinishDynamicModuleImport clears any pending exception.
976 MOZ_ASSERT(!JS_IsExceptionPending(aCx
));
978 aRequest
->ClearDynamicImport();
981 ModuleLoaderBase::ModuleLoaderBase(ScriptLoaderInterface
* aLoader
,
982 nsIGlobalObject
* aGlobalObject
,
983 nsISerialEventTarget
* aEventTarget
)
984 : mGlobalObject(aGlobalObject
),
985 mEventTarget(aEventTarget
),
987 MOZ_ASSERT(mGlobalObject
);
988 MOZ_ASSERT(mEventTarget
);
991 EnsureModuleHooksInitialized();
994 ModuleLoaderBase::~ModuleLoaderBase() {
995 mDynamicImportRequests
.CancelRequestsAndClear();
997 LOG(("ModuleLoaderBase::~ModuleLoaderBase %p", this));
1000 void ModuleLoaderBase::Shutdown() {
1001 CancelAndClearDynamicImports();
1003 for (const auto& entry
: mFetchingModules
) {
1004 RefPtr
<WaitingRequests
> waitingRequests(entry
.GetData());
1005 if (waitingRequests
) {
1006 ResumeWaitingRequests(waitingRequests
, false);
1010 for (const auto& entry
: mFetchedModules
) {
1011 if (entry
.GetData()) {
1012 entry
.GetData()->Shutdown();
1016 mFetchingModules
.Clear();
1017 mFetchedModules
.Clear();
1018 mGlobalObject
= nullptr;
1019 mEventTarget
= nullptr;
1023 bool ModuleLoaderBase::HasPendingDynamicImports() const {
1024 return !mDynamicImportRequests
.isEmpty();
1027 void ModuleLoaderBase::CancelDynamicImport(ModuleLoadRequest
* aRequest
,
1029 MOZ_ASSERT(aRequest
->mLoader
== this);
1031 RefPtr
<ScriptLoadRequest
> req
= mDynamicImportRequests
.Steal(aRequest
);
1032 if (!aRequest
->IsCanceled()) {
1034 // FinishDynamicImport must happen exactly once for each dynamic import
1035 // request. If the load is aborted we do it when we remove the request
1036 // from mDynamicImportRequests.
1037 FinishDynamicImportAndReject(aRequest
, aResult
);
1041 void ModuleLoaderBase::RemoveDynamicImport(ModuleLoadRequest
* aRequest
) {
1042 MOZ_ASSERT(aRequest
->IsDynamicImport());
1043 mDynamicImportRequests
.Remove(aRequest
);
1047 bool ModuleLoaderBase::HasDynamicImport(
1048 const ModuleLoadRequest
* aRequest
) const {
1049 MOZ_ASSERT(aRequest
->mLoader
== this);
1050 return mDynamicImportRequests
.Contains(
1051 const_cast<ModuleLoadRequest
*>(aRequest
));
1055 JS::Value
ModuleLoaderBase::FindFirstParseError(ModuleLoadRequest
* aRequest
) {
1056 MOZ_ASSERT(aRequest
);
1058 ModuleScript
* moduleScript
= aRequest
->mModuleScript
;
1059 MOZ_ASSERT(moduleScript
);
1061 if (moduleScript
->HasParseError()) {
1062 return moduleScript
->ParseError();
1065 for (ModuleLoadRequest
* childRequest
: aRequest
->mImports
) {
1066 JS::Value error
= FindFirstParseError(childRequest
);
1067 if (!error
.isUndefined()) {
1072 return JS::UndefinedValue();
1075 bool ModuleLoaderBase::InstantiateModuleGraph(ModuleLoadRequest
* aRequest
) {
1076 // Instantiate a top-level module and record any error.
1078 MOZ_ASSERT(aRequest
);
1079 MOZ_ASSERT(aRequest
->mLoader
== this);
1080 MOZ_ASSERT(aRequest
->IsTopLevel());
1082 LOG(("ScriptLoadRequest (%p): Instantiate module graph", aRequest
));
1084 AUTO_PROFILER_LABEL("ModuleLoaderBase::InstantiateModuleGraph", JS
);
1086 ModuleScript
* moduleScript
= aRequest
->mModuleScript
;
1087 MOZ_ASSERT(moduleScript
);
1089 JS::Value parseError
= FindFirstParseError(aRequest
);
1090 if (!parseError
.isUndefined()) {
1091 moduleScript
->SetErrorToRethrow(parseError
);
1092 LOG(("ScriptLoadRequest (%p): found parse error", aRequest
));
1096 MOZ_ASSERT(moduleScript
->ModuleRecord());
1099 if (NS_WARN_IF(!jsapi
.Init(mGlobalObject
))) {
1103 JS::Rooted
<JSObject
*> module(jsapi
.cx(), moduleScript
->ModuleRecord());
1104 if (!xpc::Scriptability::AllowedIfExists(module
)) {
1108 if (!JS::ModuleLink(jsapi
.cx(), module
)) {
1109 LOG(("ScriptLoadRequest (%p): Instantiate failed", aRequest
));
1110 MOZ_ASSERT(jsapi
.HasException());
1111 JS::RootedValue
exception(jsapi
.cx());
1112 if (!jsapi
.StealException(&exception
)) {
1115 MOZ_ASSERT(!exception
.isUndefined());
1116 moduleScript
->SetErrorToRethrow(exception
);
1122 nsresult
ModuleLoaderBase::InitDebuggerDataForModuleGraph(
1123 JSContext
* aCx
, ModuleLoadRequest
* aRequest
) {
1124 // JS scripts can be associated with a DOM element for use by the debugger,
1125 // but preloading can cause scripts to be compiled before DOM script element
1126 // nodes have been created. This method ensures that this association takes
1127 // place before the first time a module script is run.
1129 MOZ_ASSERT(aRequest
);
1131 ModuleScript
* moduleScript
= aRequest
->mModuleScript
;
1132 if (moduleScript
->DebuggerDataInitialized()) {
1136 for (ModuleLoadRequest
* childRequest
: aRequest
->mImports
) {
1137 nsresult rv
= InitDebuggerDataForModuleGraph(aCx
, childRequest
);
1138 NS_ENSURE_SUCCESS(rv
, rv
);
1141 JS::Rooted
<JSObject
*> module(aCx
, moduleScript
->ModuleRecord());
1144 // The script is now ready to be exposed to the debugger.
1145 JS::Rooted
<JSScript
*> script(aCx
, JS::GetModuleScript(module
));
1146 JS::ExposeScriptToDebugger(aCx
, script
);
1148 moduleScript
->SetDebuggerDataInitialized();
1152 void ModuleLoaderBase::ProcessDynamicImport(ModuleLoadRequest
* aRequest
) {
1153 if (!aRequest
->mModuleScript
) {
1154 FinishDynamicImportAndReject(aRequest
, NS_ERROR_FAILURE
);
1158 InstantiateAndEvaluateDynamicImport(aRequest
);
1161 void ModuleLoaderBase::InstantiateAndEvaluateDynamicImport(
1162 ModuleLoadRequest
* aRequest
) {
1163 MOZ_ASSERT(aRequest
->mModuleScript
);
1165 if (!InstantiateModuleGraph(aRequest
)) {
1166 aRequest
->mModuleScript
= nullptr;
1169 nsresult rv
= NS_ERROR_FAILURE
;
1170 if (aRequest
->mModuleScript
) {
1171 rv
= EvaluateModule(aRequest
);
1174 if (NS_FAILED(rv
)) {
1175 FinishDynamicImportAndReject(aRequest
, rv
);
1179 nsresult
ModuleLoaderBase::EvaluateModule(ModuleLoadRequest
* aRequest
) {
1180 MOZ_ASSERT(aRequest
->mLoader
== this);
1182 mozilla::nsAutoMicroTask mt
;
1183 mozilla::dom::AutoEntryScript
aes(mGlobalObject
, "EvaluateModule",
1186 return EvaluateModuleInContext(aes
.cx(), aRequest
,
1187 JS::ReportModuleErrorsAsync
);
1190 nsresult
ModuleLoaderBase::EvaluateModuleInContext(
1191 JSContext
* aCx
, ModuleLoadRequest
* aRequest
,
1192 JS::ModuleErrorBehaviour errorBehaviour
) {
1193 MOZ_ASSERT(aRequest
->mLoader
== this);
1194 MOZ_ASSERT(mGlobalObject
->GetModuleLoader(aCx
) == this);
1196 AUTO_PROFILER_LABEL("ModuleLoaderBase::EvaluateModule", JS
);
1198 nsAutoCString profilerLabelString
;
1199 if (aRequest
->HasScriptLoadContext()) {
1200 aRequest
->GetScriptLoadContext()->GetProfilerLabel(profilerLabelString
);
1203 LOG(("ScriptLoadRequest (%p): Evaluate Module", aRequest
));
1204 AUTO_PROFILER_MARKER_TEXT("ModuleEvaluation", JS
,
1205 MarkerInnerWindowIdFromJSContext(aCx
),
1206 profilerLabelString
);
1208 ModuleLoadRequest
* request
= aRequest
->AsModuleRequest();
1209 MOZ_ASSERT(request
->mModuleScript
);
1210 MOZ_ASSERT_IF(request
->HasScriptLoadContext(),
1211 !request
->GetScriptLoadContext()->mCompileOrDecodeTask
);
1213 ModuleScript
* moduleScript
= request
->mModuleScript
;
1214 if (moduleScript
->HasErrorToRethrow()) {
1215 LOG(("ScriptLoadRequest (%p): module has error to rethrow", aRequest
));
1216 JS::Rooted
<JS::Value
> error(aCx
, moduleScript
->ErrorToRethrow());
1217 JS_SetPendingException(aCx
, error
);
1218 // For a dynamic import, the promise is rejected. Otherwise an error
1219 // is either reported by AutoEntryScript.
1220 if (request
->IsDynamicImport()) {
1221 FinishDynamicImport(aCx
, request
, NS_OK
, nullptr);
1226 JS::Rooted
<JSObject
*> module(aCx
, moduleScript
->ModuleRecord());
1228 MOZ_ASSERT(CurrentGlobalOrNull(aCx
) == GetNonCCWObjectGlobal(module
));
1230 if (!xpc::Scriptability::AllowedIfExists(module
)) {
1234 nsresult rv
= InitDebuggerDataForModuleGraph(aCx
, request
);
1235 NS_ENSURE_SUCCESS(rv
, rv
);
1237 if (request
->HasScriptLoadContext()) {
1238 TRACE_FOR_TEST(aRequest
->GetScriptLoadContext()->GetScriptElement(),
1239 "scriptloader_evaluate_module");
1242 JS::Rooted
<JS::Value
> rval(aCx
);
1244 mLoader
->MaybePrepareModuleForBytecodeEncodingBeforeExecute(aCx
, request
);
1246 bool ok
= JS::ModuleEvaluate(aCx
, module
, &rval
);
1248 // ModuleEvaluate will usually set a pending exception if it returns false,
1249 // unless the user cancels execution.
1250 MOZ_ASSERT_IF(ok
, !JS_IsExceptionPending(aCx
));
1252 if (!ok
|| IsModuleEvaluationAborted(request
)) {
1253 LOG(("ScriptLoadRequest (%p): evaluation failed", aRequest
));
1254 // For a dynamic import, the promise is rejected. Otherwise an error is
1255 // reported by AutoEntryScript.
1256 rv
= NS_ERROR_ABORT
;
1259 // ModuleEvaluate returns a promise unless the user cancels the execution in
1260 // which case rval will be undefined. We should treat it as a failed
1261 // evaluation, and reject appropriately.
1262 JS::Rooted
<JSObject
*> evaluationPromise(aCx
);
1263 if (rval
.isObject()) {
1264 evaluationPromise
.set(&rval
.toObject());
1267 if (request
->IsDynamicImport()) {
1268 if (NS_FAILED(rv
)) {
1269 FinishDynamicImportAndReject(request
, rv
);
1271 FinishDynamicImport(aCx
, request
, NS_OK
, evaluationPromise
);
1274 // If this is not a dynamic import, and if the promise is rejected,
1275 // the value is unwrapped from the promise value.
1276 if (!JS::ThrowOnModuleEvaluationFailure(aCx
, evaluationPromise
,
1278 LOG(("ScriptLoadRequest (%p): evaluation failed on throw", aRequest
));
1279 // For a dynamic import, the promise is rejected. Otherwise an error is
1280 // reported by AutoEntryScript.
1284 rv
= mLoader
->MaybePrepareModuleForBytecodeEncodingAfterExecute(request
,
1287 mLoader
->MaybeTriggerBytecodeEncoding();
1292 void ModuleLoaderBase::CancelAndClearDynamicImports() {
1293 while (ScriptLoadRequest
* req
= mDynamicImportRequests
.getFirst()) {
1294 // This also removes the request from the list.
1295 CancelDynamicImport(req
->AsModuleRequest(), NS_ERROR_ABORT
);
1299 UniquePtr
<ImportMap
> ModuleLoaderBase::ParseImportMap(
1300 ScriptLoadRequest
* aRequest
) {
1302 if (!jsapi
.Init(GetGlobalObject())) {
1306 MOZ_ASSERT(aRequest
->IsTextSource());
1307 MaybeSourceText maybeSource
;
1308 nsresult rv
= aRequest
->GetScriptSource(jsapi
.cx(), &maybeSource
,
1309 aRequest
->mLoadContext
.get());
1310 if (NS_FAILED(rv
)) {
1314 JS::SourceText
<char16_t
>& text
= maybeSource
.ref
<SourceText
<char16_t
>>();
1315 ReportWarningHelper warning
{mLoader
, aRequest
};
1317 // https://html.spec.whatwg.org/multipage/webappapis.html#create-an-import-map-parse-result
1318 // Step 2. Parse an import map string given input and baseURL, catching any
1319 // exceptions. If this threw an exception, then set result's error to rethrow
1320 // to that exception. Otherwise, set result's import map to the return value.
1322 // https://html.spec.whatwg.org/multipage/webappapis.html#register-an-import-map
1323 // Step 1. If result's error to rethrow is not null, then report the exception
1324 // given by result's error to rethrow and return.
1326 // Impl note: We didn't implement 'Import map parse result' from the spec,
1327 // https://html.spec.whatwg.org/multipage/webappapis.html#import-map-parse-result
1328 // As the struct has another item called 'error to rethow' to store the
1329 // exception thrown during parsing import-maps, and report that exception
1330 // while registering an import map. Currently only inline import-maps are
1331 // supported, therefore parsing and registering import-maps will be executed
1332 // consecutively. To simplify the implementation, we didn't create the 'error
1333 // to rethow' item and report the exception immediately(done in ~AutoJSAPI).
1334 return ImportMap::ParseString(jsapi
.cx(), text
, aRequest
->mBaseURL
, warning
);
1337 void ModuleLoaderBase::RegisterImportMap(UniquePtr
<ImportMap
> aImportMap
) {
1338 // Check for aImportMap is done in ScriptLoader.
1339 MOZ_ASSERT(aImportMap
);
1341 // https://html.spec.whatwg.org/multipage/webappapis.html#register-an-import-map
1342 // The step 1(report the exception if there's an error) is done in
1345 // Step 2. Assert: global's import map is an empty import map.
1346 // Impl note: The default import map from the spec is an empty import map, but
1347 // from the implementation it defaults to nullptr, so we check if the global's
1348 // import map is null here.
1351 // https://html.spec.whatwg.org/multipage/webappapis.html#empty-import-map
1352 MOZ_ASSERT(!mImportMap
);
1354 // Step 3. Set global's import map to result's import map.
1355 mImportMap
= std::move(aImportMap
);
1361 } // namespace JS::loader