Backed out changeset 8f976ed899d7 (bug 1847231) for causing bc failures on browser_se...
[gecko.git] / js / src / vm / Modules.cpp
blob7a75371d18eb526a23527d90a7b3f13b6e33e6fa
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 /* JavaScript modules (as in, the syntactic construct) implementation. */
9 #include "vm/Modules.h"
11 #include "mozilla/Assertions.h" // MOZ_ASSERT
12 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
14 #include <stdint.h> // uint32_t
16 #include "jstypes.h" // JS_PUBLIC_API
18 #include "builtin/ModuleObject.h" // js::FinishDynamicModuleImport, js::{,Requested}ModuleObject
19 #include "ds/Sort.h"
20 #include "frontend/BytecodeCompiler.h" // js::frontend::CompileModule
21 #include "frontend/FrontendContext.h" // js::AutoReportFrontendContext
22 #include "js/ColumnNumber.h" // JS::ColumnNumberZeroOrigin, JS::ColumnNumberOneOrigin
23 #include "js/Context.h" // js::AssertHeapIsIdle
24 #include "js/ErrorReport.h" // JSErrorBase
25 #include "js/RootingAPI.h" // JS::MutableHandle
26 #include "js/Value.h" // JS::Value
27 #include "vm/EnvironmentObject.h" // js::ModuleEnvironmentObject
28 #include "vm/JSAtomUtils.h" // AtomizeString
29 #include "vm/JSContext.h" // CHECK_THREAD, JSContext
30 #include "vm/JSObject.h" // JSObject
31 #include "vm/List.h" // ListObject
32 #include "vm/Runtime.h" // JSRuntime
34 #include "vm/JSAtomUtils-inl.h" // AtomToId
35 #include "vm/JSContext-inl.h" // JSContext::{c,releaseC}heck
37 using namespace js;
39 using mozilla::Utf8Unit;
41 ////////////////////////////////////////////////////////////////////////////////
42 // Public API
44 JS_PUBLIC_API void JS::SetSupportedImportAssertions(
45 JSRuntime* rt, const ImportAssertionVector& assertions) {
46 AssertHeapIsIdle();
47 MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
48 MOZ_ASSERT(rt->supportedImportAssertions.ref().empty());
50 AutoEnterOOMUnsafeRegion oomUnsafe;
51 if (!rt->supportedImportAssertions.ref().appendAll(assertions)) {
52 oomUnsafe.crash("SetSupportedImportAssertions");
56 JS_PUBLIC_API JS::ModuleResolveHook JS::GetModuleResolveHook(JSRuntime* rt) {
57 AssertHeapIsIdle();
59 return rt->moduleResolveHook;
62 JS_PUBLIC_API void JS::SetModuleResolveHook(JSRuntime* rt,
63 ModuleResolveHook func) {
64 AssertHeapIsIdle();
66 rt->moduleResolveHook = func;
69 JS_PUBLIC_API JS::ModuleMetadataHook JS::GetModuleMetadataHook(JSRuntime* rt) {
70 AssertHeapIsIdle();
72 return rt->moduleMetadataHook;
75 JS_PUBLIC_API void JS::SetModuleMetadataHook(JSRuntime* rt,
76 ModuleMetadataHook func) {
77 AssertHeapIsIdle();
79 rt->moduleMetadataHook = func;
82 JS_PUBLIC_API JS::ModuleDynamicImportHook JS::GetModuleDynamicImportHook(
83 JSRuntime* rt) {
84 AssertHeapIsIdle();
86 return rt->moduleDynamicImportHook;
89 JS_PUBLIC_API void JS::SetModuleDynamicImportHook(
90 JSRuntime* rt, ModuleDynamicImportHook func) {
91 AssertHeapIsIdle();
93 rt->moduleDynamicImportHook = func;
96 JS_PUBLIC_API bool JS::FinishDynamicModuleImport(
97 JSContext* cx, Handle<JSObject*> evaluationPromise,
98 Handle<Value> referencingPrivate, Handle<JSObject*> moduleRequest,
99 Handle<JSObject*> promise) {
100 AssertHeapIsIdle();
101 CHECK_THREAD(cx);
102 cx->check(referencingPrivate, promise);
104 return js::FinishDynamicModuleImport(
105 cx, evaluationPromise, referencingPrivate, moduleRequest, promise);
108 template <typename Unit>
109 static JSObject* CompileModuleHelper(JSContext* cx,
110 const JS::ReadOnlyCompileOptions& options,
111 JS::SourceText<Unit>& srcBuf) {
112 MOZ_ASSERT(!cx->zone()->isAtomsZone());
113 AssertHeapIsIdle();
114 CHECK_THREAD(cx);
116 JS::Rooted<JSObject*> mod(cx);
118 AutoReportFrontendContext fc(cx);
119 mod = frontend::CompileModule(cx, &fc, options, srcBuf);
121 return mod;
124 JS_PUBLIC_API JSObject* JS::CompileModule(JSContext* cx,
125 const ReadOnlyCompileOptions& options,
126 SourceText<char16_t>& srcBuf) {
127 return CompileModuleHelper(cx, options, srcBuf);
130 JS_PUBLIC_API JSObject* JS::CompileModule(JSContext* cx,
131 const ReadOnlyCompileOptions& options,
132 SourceText<Utf8Unit>& srcBuf) {
133 return CompileModuleHelper(cx, options, srcBuf);
136 JS_PUBLIC_API void JS::SetModulePrivate(JSObject* module, const Value& value) {
137 JSRuntime* rt = module->zone()->runtimeFromMainThread();
138 module->as<ModuleObject>().scriptSourceObject()->setPrivate(rt, value);
141 JS_PUBLIC_API void JS::ClearModulePrivate(JSObject* module) {
142 // |module| may be gray, be careful not to create edges to it.
143 JSRuntime* rt = module->zone()->runtimeFromMainThread();
144 module->as<ModuleObject>().scriptSourceObject()->clearPrivate(rt);
147 JS_PUBLIC_API JS::Value JS::GetModulePrivate(JSObject* module) {
148 return module->as<ModuleObject>().scriptSourceObject()->getPrivate();
151 JS_PUBLIC_API bool JS::ModuleLink(JSContext* cx, Handle<JSObject*> moduleArg) {
152 AssertHeapIsIdle();
153 CHECK_THREAD(cx);
154 cx->releaseCheck(moduleArg);
156 return js::ModuleLink(cx, moduleArg.as<ModuleObject>());
159 JS_PUBLIC_API bool JS::ModuleEvaluate(JSContext* cx,
160 Handle<JSObject*> moduleRecord,
161 MutableHandle<JS::Value> rval) {
162 AssertHeapIsIdle();
163 CHECK_THREAD(cx);
164 cx->releaseCheck(moduleRecord);
166 return js::ModuleEvaluate(cx, moduleRecord.as<ModuleObject>(), rval);
169 JS_PUBLIC_API bool JS::ThrowOnModuleEvaluationFailure(
170 JSContext* cx, Handle<JSObject*> evaluationPromise,
171 ModuleErrorBehaviour errorBehaviour) {
172 AssertHeapIsIdle();
173 CHECK_THREAD(cx);
174 cx->releaseCheck(evaluationPromise);
176 return OnModuleEvaluationFailure(cx, evaluationPromise, errorBehaviour);
179 JS_PUBLIC_API uint32_t
180 JS::GetRequestedModulesCount(JSContext* cx, Handle<JSObject*> moduleRecord) {
181 AssertHeapIsIdle();
182 CHECK_THREAD(cx);
183 cx->check(moduleRecord);
185 return moduleRecord->as<ModuleObject>().requestedModules().Length();
188 JS_PUBLIC_API JSString* JS::GetRequestedModuleSpecifier(
189 JSContext* cx, Handle<JSObject*> moduleRecord, uint32_t index) {
190 AssertHeapIsIdle();
191 CHECK_THREAD(cx);
192 cx->check(moduleRecord);
194 auto& module = moduleRecord->as<ModuleObject>();
195 return module.requestedModules()[index].moduleRequest()->specifier();
198 JS_PUBLIC_API void JS::GetRequestedModuleSourcePos(
199 JSContext* cx, Handle<JSObject*> moduleRecord, uint32_t index,
200 uint32_t* lineNumber, JS::ColumnNumberZeroOrigin* columnNumber) {
201 AssertHeapIsIdle();
202 CHECK_THREAD(cx);
203 cx->check(moduleRecord);
204 MOZ_ASSERT(lineNumber);
205 MOZ_ASSERT(columnNumber);
207 auto& module = moduleRecord->as<ModuleObject>();
208 *lineNumber = module.requestedModules()[index].lineNumber();
209 *columnNumber = module.requestedModules()[index].columnNumber();
212 JS_PUBLIC_API JSScript* JS::GetModuleScript(JS::HandleObject moduleRecord) {
213 AssertHeapIsIdle();
215 return moduleRecord->as<ModuleObject>().script();
218 JS_PUBLIC_API JSObject* JS::GetModuleObject(HandleScript moduleScript) {
219 AssertHeapIsIdle();
220 MOZ_ASSERT(moduleScript->isModule());
222 return moduleScript->module();
225 JS_PUBLIC_API JSObject* JS::GetModuleNamespace(JSContext* cx,
226 HandleObject moduleRecord) {
227 AssertHeapIsIdle();
228 CHECK_THREAD(cx);
229 cx->check(moduleRecord);
230 MOZ_ASSERT(moduleRecord->is<ModuleObject>());
232 return GetOrCreateModuleNamespace(cx, moduleRecord.as<ModuleObject>());
235 JS_PUBLIC_API JSObject* JS::GetModuleForNamespace(
236 JSContext* cx, HandleObject moduleNamespace) {
237 AssertHeapIsIdle();
238 CHECK_THREAD(cx);
239 cx->check(moduleNamespace);
240 MOZ_ASSERT(moduleNamespace->is<ModuleNamespaceObject>());
242 return &moduleNamespace->as<ModuleNamespaceObject>().module();
245 JS_PUBLIC_API JSObject* JS::GetModuleEnvironment(JSContext* cx,
246 Handle<JSObject*> moduleObj) {
247 AssertHeapIsIdle();
248 CHECK_THREAD(cx);
249 cx->check(moduleObj);
250 MOZ_ASSERT(moduleObj->is<ModuleObject>());
252 return moduleObj->as<ModuleObject>().environment();
255 JS_PUBLIC_API JSObject* JS::CreateModuleRequest(
256 JSContext* cx, Handle<JSString*> specifierArg) {
257 AssertHeapIsIdle();
258 CHECK_THREAD(cx);
260 Rooted<JSAtom*> specifierAtom(cx, AtomizeString(cx, specifierArg));
261 if (!specifierAtom) {
262 return nullptr;
265 return ModuleRequestObject::create(cx, specifierAtom, nullptr);
268 JS_PUBLIC_API JSString* JS::GetModuleRequestSpecifier(
269 JSContext* cx, Handle<JSObject*> moduleRequestArg) {
270 AssertHeapIsIdle();
271 CHECK_THREAD(cx);
272 cx->check(moduleRequestArg);
274 return moduleRequestArg->as<ModuleRequestObject>().specifier();
277 JS_PUBLIC_API void JS::ClearModuleEnvironment(JSObject* moduleObj) {
278 MOZ_ASSERT(moduleObj);
279 AssertHeapIsIdle();
281 js::ModuleEnvironmentObject* env =
282 moduleObj->as<js::ModuleObject>().environment();
283 if (!env) {
284 return;
287 const JSClass* clasp = env->getClass();
288 uint32_t numReserved = JSCLASS_RESERVED_SLOTS(clasp);
289 uint32_t numSlots = env->slotSpan();
290 for (uint32_t i = numReserved; i < numSlots; i++) {
291 env->setSlot(i, UndefinedValue());
295 JS_PUBLIC_API void JS::AssertModuleUnlinked(JSObject* moduleObj) {
296 MOZ_ASSERT(moduleObj);
297 AssertHeapIsIdle();
299 MOZ_DIAGNOSTIC_ASSERT(moduleObj->as<ModuleObject>().status() ==
300 ModuleStatus::Unlinked);
303 ////////////////////////////////////////////////////////////////////////////////
304 // Internal implementation
306 class ResolveSetEntry {
307 ModuleObject* module_;
308 JSAtom* exportName_;
310 public:
311 ResolveSetEntry(ModuleObject* module, JSAtom* exportName)
312 : module_(module), exportName_(exportName) {}
314 ModuleObject* module() const { return module_; }
315 JSAtom* exportName() const { return exportName_; }
317 void trace(JSTracer* trc) {
318 TraceRoot(trc, &module_, "ResolveSetEntry::module_");
319 TraceRoot(trc, &exportName_, "ResolveSetEntry::exportName_");
323 using ResolveSet = GCVector<ResolveSetEntry, 0, SystemAllocPolicy>;
325 using ModuleSet =
326 GCHashSet<ModuleObject*, DefaultHasher<ModuleObject*>, SystemAllocPolicy>;
328 static ModuleObject* HostResolveImportedModule(
329 JSContext* cx, Handle<ModuleObject*> module,
330 Handle<ModuleRequestObject*> moduleRequest,
331 ModuleStatus expectedMinimumStatus);
332 static bool ModuleResolveExport(JSContext* cx, Handle<ModuleObject*> module,
333 Handle<JSAtom*> exportName,
334 MutableHandle<ResolveSet> resolveSet,
335 MutableHandle<Value> result);
336 static ModuleNamespaceObject* ModuleNamespaceCreate(
337 JSContext* cx, Handle<ModuleObject*> module,
338 MutableHandle<UniquePtr<ExportNameVector>> exports);
339 static bool InnerModuleLinking(JSContext* cx, Handle<ModuleObject*> module,
340 MutableHandle<ModuleVector> stack, size_t index,
341 size_t* indexOut);
342 static bool InnerModuleEvaluation(JSContext* cx, Handle<ModuleObject*> module,
343 MutableHandle<ModuleVector> stack,
344 size_t index, size_t* indexOut);
345 static bool ExecuteAsyncModule(JSContext* cx, Handle<ModuleObject*> module);
346 static bool GatherAvailableModuleAncestors(
347 JSContext* cx, Handle<ModuleObject*> module,
348 MutableHandle<ModuleVector> execList);
350 static const char* ModuleStatusName(ModuleStatus status) {
351 switch (status) {
352 case ModuleStatus::Unlinked:
353 return "Unlinked";
354 case ModuleStatus::Linking:
355 return "Linking";
356 case ModuleStatus::Linked:
357 return "Linked";
358 case ModuleStatus::Evaluating:
359 return "Evaluating";
360 case ModuleStatus::EvaluatingAsync:
361 return "EvaluatingAsync";
362 case ModuleStatus::Evaluated:
363 return "Evaluated";
364 default:
365 MOZ_CRASH("Unexpected ModuleStatus");
369 static bool ContainsElement(Handle<ExportNameVector> list, JSAtom* atom) {
370 for (JSAtom* a : list) {
371 if (a == atom) {
372 return true;
376 return false;
379 static bool ContainsElement(Handle<ModuleVector> stack, ModuleObject* module) {
380 for (ModuleObject* m : stack) {
381 if (m == module) {
382 return true;
386 return false;
389 #ifdef DEBUG
390 static size_t CountElements(Handle<ModuleVector> stack, ModuleObject* module) {
391 size_t count = 0;
392 for (ModuleObject* m : stack) {
393 if (m == module) {
394 count++;
398 return count;
400 #endif
402 // https://tc39.es/ecma262/#sec-getexportednames
403 // ES2023 16.2.1.6.2 GetExportedNames
404 static bool ModuleGetExportedNames(
405 JSContext* cx, Handle<ModuleObject*> module,
406 MutableHandle<ModuleSet> exportStarSet,
407 MutableHandle<ExportNameVector> exportedNames) {
408 // Step 4. Let exportedNames be a new empty List.
409 MOZ_ASSERT(exportedNames.empty());
411 // Step 2. If exportStarSet contains module, then:
412 if (exportStarSet.has(module)) {
413 // Step 2.a. We've reached the starting point of an export * circularity.
414 // Step 2.b. Return a new empty List.
415 return true;
418 // Step 3. Append module to exportStarSet.
419 if (!exportStarSet.put(module)) {
420 ReportOutOfMemory(cx);
421 return false;
424 // Step 5. For each ExportEntry Record e of module.[[LocalExportEntries]], do:
425 for (const ExportEntry& e : module->localExportEntries()) {
426 // Step 5.a. Assert: module provides the direct binding for this export.
427 // Step 5.b. Append e.[[ExportName]] to exportedNames.
428 if (!exportedNames.append(e.exportName())) {
429 ReportOutOfMemory(cx);
430 return false;
434 // Step 6. For each ExportEntry Record e of module.[[IndirectExportEntries]],
435 // do:
436 for (const ExportEntry& e : module->indirectExportEntries()) {
437 // Step 6.a. Assert: module imports a specific binding for this export.
438 // Step 6.b. Append e.[[ExportName]] to exportedNames.
439 if (!exportedNames.append(e.exportName())) {
440 ReportOutOfMemory(cx);
441 return false;
445 // Step 7. For each ExportEntry Record e of module.[[StarExportEntries]], do:
446 Rooted<ModuleRequestObject*> moduleRequest(cx);
447 Rooted<ModuleObject*> requestedModule(cx);
448 Rooted<JSAtom*> name(cx);
449 for (const ExportEntry& e : module->starExportEntries()) {
450 // Step 7.a. Let requestedModule be ? HostResolveImportedModule(module,
451 // e.[[ModuleRequest]]).
452 moduleRequest = e.moduleRequest();
453 requestedModule = HostResolveImportedModule(cx, module, moduleRequest,
454 ModuleStatus::Unlinked);
455 if (!requestedModule) {
456 return false;
459 // Step 7.b. Let starNames be ?
460 // requestedModule.GetExportedNames(exportStarSet).
461 Rooted<ExportNameVector> starNames(cx);
462 if (!ModuleGetExportedNames(cx, requestedModule, exportStarSet,
463 &starNames)) {
464 return false;
467 // Step 7.c. For each element n of starNames, do:
468 for (JSAtom* name : starNames) {
469 // Step 7.c.i. If SameValue(n, "default") is false, then:
470 if (name != cx->names().default_) {
471 // Step 7.c.i.1. If n is not an element of exportedNames, then:
472 if (!ContainsElement(exportedNames, name)) {
473 // Step 7.c.i.1.a. Append n to exportedNames.
474 if (!exportedNames.append(name)) {
475 ReportOutOfMemory(cx);
476 return false;
483 // Step 8. Return exportedNames.
484 return true;
487 static void ThrowUnexpectedModuleStatus(JSContext* cx, ModuleStatus status) {
488 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
489 JSMSG_BAD_MODULE_STATUS, ModuleStatusName(status));
492 static ModuleObject* HostResolveImportedModule(
493 JSContext* cx, Handle<ModuleObject*> module,
494 Handle<ModuleRequestObject*> moduleRequest,
495 ModuleStatus expectedMinimumStatus) {
496 MOZ_ASSERT(module);
497 MOZ_ASSERT(moduleRequest);
499 Rooted<Value> referencingPrivate(cx, JS::GetModulePrivate(module));
500 Rooted<ModuleObject*> requestedModule(cx);
501 requestedModule =
502 CallModuleResolveHook(cx, referencingPrivate, moduleRequest);
503 if (!requestedModule) {
504 return nullptr;
507 if (requestedModule->status() < expectedMinimumStatus) {
508 ThrowUnexpectedModuleStatus(cx, requestedModule->status());
509 return nullptr;
512 return requestedModule;
515 // https://tc39.es/ecma262/#sec-resolveexport
516 // ES2023 16.2.1.6.3 ResolveExport
518 // Returns an value describing the location of the resolved export or indicating
519 // a failure.
521 // On success this returns a resolved binding record: { module, bindingName }
523 // There are two failure cases:
525 // - If no definition was found or the request is found to be circular, *null*
526 // is returned.
528 // - If the request is found to be ambiguous, the string `"ambiguous"` is
529 // returned.
531 bool js::ModuleResolveExport(JSContext* cx, Handle<ModuleObject*> module,
532 Handle<JSAtom*> exportName,
533 MutableHandle<Value> result) {
534 // Step 1. If resolveSet is not present, set resolveSet to a new empty List.
535 Rooted<ResolveSet> resolveSet(cx);
537 return ::ModuleResolveExport(cx, module, exportName, &resolveSet, result);
540 static bool CreateResolvedBindingObject(JSContext* cx,
541 Handle<ModuleObject*> module,
542 Handle<JSAtom*> bindingName,
543 MutableHandle<Value> result) {
544 Rooted<ResolvedBindingObject*> obj(
545 cx, ResolvedBindingObject::create(cx, module, bindingName));
546 if (!obj) {
547 return false;
550 result.setObject(*obj);
551 return true;
554 static bool ModuleResolveExport(JSContext* cx, Handle<ModuleObject*> module,
555 Handle<JSAtom*> exportName,
556 MutableHandle<ResolveSet> resolveSet,
557 MutableHandle<Value> result) {
558 // Step 2. For each Record { [[Module]], [[ExportName]] } r of resolveSet, do:
559 for (const auto& entry : resolveSet) {
560 // Step 2.a. If module and r.[[Module]] are the same Module Record and
561 // SameValue(exportName, r.[[ExportName]]) is true, then:
562 if (entry.module() == module && entry.exportName() == exportName) {
563 // Step 2.a.i. Assert: This is a circular import request.
564 // Step 2.a.ii. Return null.
565 result.setNull();
566 return true;
570 // Step 3. Append the Record { [[Module]]: module, [[ExportName]]: exportName
571 // } to resolveSet.
572 if (!resolveSet.emplaceBack(module, exportName)) {
573 ReportOutOfMemory(cx);
574 return false;
577 // Step 4. For each ExportEntry Record e of module.[[LocalExportEntries]], do:
578 for (const ExportEntry& e : module->localExportEntries()) {
579 // Step 4.a. If SameValue(exportName, e.[[ExportName]]) is true, then:
580 if (exportName == e.exportName()) {
581 // Step 4.a.i. Assert: module provides the direct binding for this export.
582 // Step 4.a.ii. Return ResolvedBinding Record { [[Module]]: module,
583 // [[BindingName]]: e.[[LocalName]] }.
584 Rooted<JSAtom*> localName(cx, e.localName());
585 return CreateResolvedBindingObject(cx, module, localName, result);
589 // Step 5. For each ExportEntry Record e of module.[[IndirectExportEntries]],
590 // do:
591 Rooted<ModuleRequestObject*> moduleRequest(cx);
592 Rooted<ModuleObject*> importedModule(cx);
593 Rooted<JSAtom*> name(cx);
594 for (const ExportEntry& e : module->indirectExportEntries()) {
595 // Step 5.a. If SameValue(exportName, e.[[ExportName]]) is true, then:
596 if (exportName == e.exportName()) {
597 // Step 5.a.i. Let importedModule be ? HostResolveImportedModule(module,
598 // e.[[ModuleRequest]]).
599 moduleRequest = e.moduleRequest();
600 importedModule = HostResolveImportedModule(cx, module, moduleRequest,
601 ModuleStatus::Unlinked);
602 if (!importedModule) {
603 return false;
606 // Step 5.a.ii. If e.[[ImportName]] is all, then:
607 if (!e.importName()) {
608 // Step 5.a.ii.1. Assert: module does not provide the direct binding for
609 // this export.
610 // Step 5.a.ii.2. Return ResolvedBinding Record { [[Module]]:
611 // importedModule, [[BindingName]]: namespace }.
612 name = cx->names().star_namespace_star_;
613 return CreateResolvedBindingObject(cx, importedModule, name, result);
614 } else {
615 // Step 5.a.iii.1. Assert: module imports a specific binding for this
616 // export.
617 // Step 5.a.iii.2. Return ?
618 // importedModule.ResolveExport(e.[[ImportName]],
619 // resolveSet).
620 name = e.importName();
621 return ModuleResolveExport(cx, importedModule, name, resolveSet,
622 result);
627 // Step 6. If SameValue(exportName, "default") is true, then:
628 if (exportName == cx->names().default_) {
629 // Step 6.a. Assert: A default export was not explicitly defined by this
630 // module.
631 // Step 6.b. Return null.
632 // Step 6.c. NOTE: A default export cannot be provided by an export * from
633 // "mod" declaration.
634 result.setNull();
635 return true;
638 // Step 7. Let starResolution be null.
639 Rooted<ResolvedBindingObject*> starResolution(cx);
641 // Step 8. For each ExportEntry Record e of module.[[StarExportEntries]], do:
642 Rooted<Value> resolution(cx);
643 Rooted<ResolvedBindingObject*> binding(cx);
644 for (const ExportEntry& e : module->starExportEntries()) {
645 // Step 8.a. Let importedModule be ? HostResolveImportedModule(module,
646 // e.[[ModuleRequest]]).
647 moduleRequest = e.moduleRequest();
648 importedModule = HostResolveImportedModule(cx, module, moduleRequest,
649 ModuleStatus::Unlinked);
650 if (!importedModule) {
651 return false;
654 // Step 8.b. Let resolution be ? importedModule.ResolveExport(exportName,
655 // resolveSet).
656 if (!ModuleResolveExport(cx, importedModule, exportName, resolveSet,
657 &resolution)) {
658 return false;
661 // Step 8.c. If resolution is ambiguous, return ambiguous.
662 if (resolution == StringValue(cx->names().ambiguous)) {
663 result.set(resolution);
664 return true;
667 // Step 8.d. If resolution is not null, then:
668 if (!resolution.isNull()) {
669 // Step 8.d.i. Assert: resolution is a ResolvedBinding Record.
670 binding = &resolution.toObject().as<ResolvedBindingObject>();
672 // Step 8.d.ii. If starResolution is null, set starResolution to
673 // resolution.
674 if (!starResolution) {
675 starResolution = binding;
676 } else {
677 // Step 8.d.iii. Else:
678 // Step 8.d.iii.1. Assert: There is more than one * import that includes
679 // the requested name.
680 // Step 8.d.iii.2. If resolution.[[Module]] and
681 // starResolution.[[Module]] are not the same Module
682 // Record, return ambiguous.
683 // Step 8.d.iii.3. If resolution.[[BindingName]] is namespace and
684 // starResolution.[[BindingName]] is not namespace, or
685 // if resolution.[[BindingName]] is not namespace and
686 // starResolution.[[BindingName]] is namespace, return
687 // ambiguous.
688 // Step 8.d.iii.4. If resolution.[[BindingName]] is a String,
689 // starResolution.[[BindingName]] is a String, and
690 // SameValue(resolution.[[BindingName]],
691 // starResolution.[[BindingName]]) is false, return
692 // ambiguous.
693 if (binding->module() != starResolution->module() ||
694 binding->bindingName() != starResolution->bindingName()) {
695 result.set(StringValue(cx->names().ambiguous));
696 return true;
702 // Step 9. Return starResolution.
703 result.setObjectOrNull(starResolution);
704 return true;
707 // https://tc39.es/ecma262/#sec-getmodulenamespace
708 // ES2023 16.2.1.10 GetModuleNamespace
709 ModuleNamespaceObject* js::GetOrCreateModuleNamespace(
710 JSContext* cx, Handle<ModuleObject*> module) {
711 // Step 1. Assert: If module is a Cyclic Module Record, then module.[[Status]]
712 // is not unlinked.
713 MOZ_ASSERT(module->status() != ModuleStatus::Unlinked);
715 // Step 2. Let namespace be module.[[Namespace]].
716 Rooted<ModuleNamespaceObject*> ns(cx, module->namespace_());
718 // Step 3. If namespace is empty, then:
719 if (!ns) {
720 // Step 3.a. Let exportedNames be ? module.GetExportedNames().
721 Rooted<ModuleSet> exportStarSet(cx);
722 Rooted<ExportNameVector> exportedNames(cx);
723 if (!ModuleGetExportedNames(cx, module, &exportStarSet, &exportedNames)) {
724 return nullptr;
727 // Step 3.b. Let unambiguousNames be a new empty List.
728 Rooted<UniquePtr<ExportNameVector>> unambiguousNames(
729 cx, cx->make_unique<ExportNameVector>());
730 if (!unambiguousNames) {
731 return nullptr;
734 // Step 3.c. For each element name of exportedNames, do:
735 Rooted<JSAtom*> name(cx);
736 Rooted<Value> resolution(cx);
737 for (JSAtom* atom : exportedNames) {
738 name = atom;
740 // Step 3.c.i. Let resolution be ? module.ResolveExport(name).
741 if (!ModuleResolveExport(cx, module, name, &resolution)) {
742 return nullptr;
745 // Step 3.c.ii. If resolution is a ResolvedBinding Record, append name to
746 // unambiguousNames.
747 if (resolution.isObject() && !unambiguousNames->append(name)) {
748 ReportOutOfMemory(cx);
749 return nullptr;
753 // Step 3.d. Set namespace to ModuleNamespaceCreate(module,
754 // unambiguousNames).
755 ns = ModuleNamespaceCreate(cx, module, &unambiguousNames);
758 // Step 4. Return namespace.
759 return ns;
762 static bool IsResolvedBinding(JSContext* cx, Handle<Value> resolution) {
763 MOZ_ASSERT(resolution.isObjectOrNull() ||
764 resolution.toString() == cx->names().ambiguous);
765 return resolution.isObject();
768 static void InitNamespaceBinding(JSContext* cx,
769 Handle<ModuleEnvironmentObject*> env,
770 Handle<JSAtom*> name,
771 Handle<ModuleNamespaceObject*> ns) {
772 // The property already exists in the evironment but is not writable, so set
773 // the slot directly.
774 RootedId id(cx, AtomToId(name));
775 mozilla::Maybe<PropertyInfo> prop = env->lookup(cx, id);
776 MOZ_ASSERT(prop.isSome());
777 env->setSlot(prop->slot(), ObjectValue(*ns));
780 struct AtomComparator {
781 bool operator()(JSAtom* a, JSAtom* b, bool* lessOrEqualp) {
782 int32_t result = CompareStrings(a, b);
783 *lessOrEqualp = (result <= 0);
784 return true;
788 // https://tc39.es/ecma262/#sec-modulenamespacecreate
789 // ES2023 10.4.6.12 ModuleNamespaceCreate
790 static ModuleNamespaceObject* ModuleNamespaceCreate(
791 JSContext* cx, Handle<ModuleObject*> module,
792 MutableHandle<UniquePtr<ExportNameVector>> exports) {
793 // Step 1. Assert: module.[[Namespace]] is empty.
794 MOZ_ASSERT(!module->namespace_());
796 // Step 6. Let sortedExports be a List whose elements are the elements of
797 // exports ordered as if an Array of the same values had been sorted
798 // using %Array.prototype.sort% using undefined as comparefn.
799 ExportNameVector scratch;
800 if (!scratch.resize(exports->length())) {
801 ReportOutOfMemory(cx);
802 return nullptr;
804 MOZ_ALWAYS_TRUE(MergeSort(exports->begin(), exports->length(),
805 scratch.begin(), AtomComparator()));
807 // Steps 2 - 5.
808 Rooted<ModuleNamespaceObject*> ns(
809 cx, ModuleObject::createNamespace(cx, module, exports));
810 if (!ns) {
811 return nullptr;
814 // Pre-compute all binding mappings now instead of on each access.
815 // See:
816 // https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-get-p-receiver
817 // ES2023 10.4.6.8 Module Namespace Exotic Object [[Get]]
818 Rooted<JSAtom*> name(cx);
819 Rooted<Value> resolution(cx);
820 Rooted<ResolvedBindingObject*> binding(cx);
821 Rooted<ModuleObject*> importedModule(cx);
822 Rooted<ModuleNamespaceObject*> importedNamespace(cx);
823 Rooted<JSAtom*> bindingName(cx);
824 for (JSAtom* atom : ns->exports()) {
825 name = atom;
827 if (!ModuleResolveExport(cx, module, name, &resolution)) {
828 return nullptr;
831 MOZ_ASSERT(IsResolvedBinding(cx, resolution));
832 binding = &resolution.toObject().as<ResolvedBindingObject>();
833 importedModule = binding->module();
834 bindingName = binding->bindingName();
836 if (bindingName == cx->names().star_namespace_star_) {
837 importedNamespace = GetOrCreateModuleNamespace(cx, importedModule);
838 if (!importedNamespace) {
839 return nullptr;
842 // The spec uses an immutable binding here but we have already generated
843 // bytecode for an indirect binding. Instead, use an indirect binding to
844 // "*namespace*" slot of the target environment.
845 Rooted<ModuleEnvironmentObject*> env(
846 cx, &importedModule->initialEnvironment());
847 InitNamespaceBinding(cx, env, bindingName, importedNamespace);
850 if (!ns->addBinding(cx, name, importedModule, bindingName)) {
851 return nullptr;
855 // Step 10. Return M.
856 return ns;
859 static void ThrowResolutionError(JSContext* cx, Handle<ModuleObject*> module,
860 Handle<Value> resolution, bool isDirectImport,
861 Handle<JSAtom*> name, uint32_t line,
862 JS::ColumnNumberZeroOrigin column) {
863 MOZ_ASSERT(line != 0);
865 bool isAmbiguous = resolution == StringValue(cx->names().ambiguous);
867 static constexpr unsigned ErrorNumbers[2][2] = {
868 {JSMSG_AMBIGUOUS_IMPORT, JSMSG_MISSING_IMPORT},
869 {JSMSG_AMBIGUOUS_INDIRECT_EXPORT, JSMSG_MISSING_INDIRECT_EXPORT}};
870 unsigned errorNumber = ErrorNumbers[isDirectImport][isAmbiguous];
872 const JSErrorFormatString* errorString =
873 GetErrorMessage(nullptr, errorNumber);
874 MOZ_ASSERT(errorString);
876 MOZ_ASSERT(errorString->argCount == 0);
877 Rooted<JSString*> message(cx, JS_NewStringCopyZ(cx, errorString->format));
878 if (!message) {
879 return;
882 Rooted<JSString*> separator(cx, JS_NewStringCopyZ(cx, ": "));
883 if (!separator) {
884 return;
887 message = ConcatStrings<CanGC>(cx, message, separator);
888 if (!message) {
889 return;
892 message = ConcatStrings<CanGC>(cx, message, name);
893 if (!message) {
894 return;
897 RootedString filename(cx);
898 if (const char* chars = module->script()->filename()) {
899 filename =
900 JS_NewStringCopyUTF8Z(cx, JS::ConstUTF8CharsZ(chars, strlen(chars)));
901 } else {
902 filename = cx->names().empty_;
904 if (!filename) {
905 return;
908 RootedValue error(cx);
909 if (!JS::CreateError(cx, JSEXN_SYNTAXERR, nullptr, filename, line,
910 JS::ColumnNumberOneOrigin(column), nullptr, message,
911 JS::NothingHandleValue, &error)) {
912 return;
915 cx->setPendingException(error, nullptr);
918 // https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment
919 // ES2023 16.2.1.6.4 InitializeEnvironment
920 bool js::ModuleInitializeEnvironment(JSContext* cx,
921 Handle<ModuleObject*> module) {
922 MOZ_ASSERT(module->status() == ModuleStatus::Linking);
924 // Step 1. For each ExportEntry Record e of module.[[IndirectExportEntries]],
925 // do:
926 Rooted<JSAtom*> exportName(cx);
927 Rooted<Value> resolution(cx);
928 for (const ExportEntry& e : module->indirectExportEntries()) {
929 // Step 1.a. Let resolution be ? module.ResolveExport(e.[[ExportName]]).
930 exportName = e.exportName();
931 if (!ModuleResolveExport(cx, module, exportName, &resolution)) {
932 return false;
935 // Step 1.b. If resolution is null or ambiguous, throw a SyntaxError
936 // exception.
937 if (!IsResolvedBinding(cx, resolution)) {
938 ThrowResolutionError(cx, module, resolution, false, exportName,
939 e.lineNumber(), e.columnNumber());
940 return false;
944 // Step 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
945 // Step 6. Set module.[[Environment]] to env.
946 // Note that we have already created the environment by this point.
947 Rooted<ModuleEnvironmentObject*> env(cx, &module->initialEnvironment());
949 // Step 7. For each ImportEntry Record in of module.[[ImportEntries]], do:
950 Rooted<ModuleRequestObject*> moduleRequest(cx);
951 Rooted<ModuleObject*> importedModule(cx);
952 Rooted<JSAtom*> importName(cx);
953 Rooted<JSAtom*> localName(cx);
954 Rooted<ModuleObject*> sourceModule(cx);
955 Rooted<JSAtom*> bindingName(cx);
956 for (const ImportEntry& in : module->importEntries()) {
957 // Step 7.a. Let importedModule be ! HostResolveImportedModule(module,
958 // in.[[ModuleRequest]]).
959 moduleRequest = in.moduleRequest();
960 importedModule = HostResolveImportedModule(cx, module, moduleRequest,
961 ModuleStatus::Linking);
962 if (!importedModule) {
963 return false;
966 localName = in.localName();
967 importName = in.importName();
969 // Step 7.c. If in.[[ImportName]] is namespace-object, then:
970 if (!importName) {
971 // Step 7.c.i. Let namespace be ? GetModuleNamespace(importedModule).
972 Rooted<ModuleNamespaceObject*> ns(
973 cx, GetOrCreateModuleNamespace(cx, importedModule));
974 if (!ns) {
975 return false;
978 // Step 7.c.ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]],
979 // true). This happens when the environment is created.
981 // Step 7.c.iii. Perform ! env.InitializeBinding(in.[[LocalName]],
982 // namespace).
983 InitNamespaceBinding(cx, env, localName, ns);
984 } else {
985 // Step 7.d. Else:
986 // Step 7.d.i. Let resolution be ?
987 // importedModule.ResolveExport(in.[[ImportName]]).
988 if (!ModuleResolveExport(cx, importedModule, importName, &resolution)) {
989 return false;
992 // Step 7.d.ii. If resolution is null or ambiguous, throw a SyntaxError
993 // exception.
994 if (!IsResolvedBinding(cx, resolution)) {
995 ThrowResolutionError(cx, module, resolution, true, importName,
996 in.lineNumber(), in.columnNumber());
997 return false;
1000 auto* binding = &resolution.toObject().as<ResolvedBindingObject>();
1001 sourceModule = binding->module();
1002 bindingName = binding->bindingName();
1004 // Step 7.d.iii. If resolution.[[BindingName]] is namespace, then:
1005 if (bindingName == cx->names().star_namespace_star_) {
1006 // Step 7.d.iii.1. Let namespace be ?
1007 // GetModuleNamespace(resolution.[[Module]]).
1008 Rooted<ModuleNamespaceObject*> ns(
1009 cx, GetOrCreateModuleNamespace(cx, sourceModule));
1010 if (!ns) {
1011 return false;
1014 // Step 7.d.iii.2. Perform !
1015 // env.CreateImmutableBinding(in.[[LocalName]], true).
1016 // Step 7.d.iii.3. Perform ! env.InitializeBinding(in.[[LocalName]],
1017 // namespace).
1019 // This should be InitNamespaceBinding, but we have already generated
1020 // bytecode assuming an indirect binding. Instead, ensure a special
1021 // "*namespace*"" binding exists on the target module's environment. We
1022 // then generate an indirect binding to this synthetic binding.
1023 Rooted<ModuleEnvironmentObject*> sourceEnv(
1024 cx, &sourceModule->initialEnvironment());
1025 InitNamespaceBinding(cx, sourceEnv, bindingName, ns);
1026 if (!env->createImportBinding(cx, localName, sourceModule,
1027 bindingName)) {
1028 return false;
1030 } else {
1031 // Step 7.d.iv. Else:
1032 // Step 7.d.iv.1. 1. Perform env.CreateImportBinding(in.[[LocalName]],
1033 // resolution.[[Module]], resolution.[[BindingName]]).
1034 if (!env->createImportBinding(cx, localName, sourceModule,
1035 bindingName)) {
1036 return false;
1042 // Steps 8-26.
1044 // Some of these do not need to happen for practical purposes. For steps
1045 // 21-23, the bindings that can be handled in a similar way to regulars
1046 // scripts are done separately. Function Declarations are special due to
1047 // hoisting and are handled within this function. See ModuleScope and
1048 // ModuleEnvironmentObject for further details.
1050 // Step 24. For each element d of lexDeclarations, do:
1051 // Step 24.a. For each element dn of the BoundNames of d, do:
1052 // Step 24.a.iii. If d is a FunctionDeclaration, a GeneratorDeclaration, an
1053 // AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration,
1054 // then:
1055 // Step 24.a.iii.1 Let fo be InstantiateFunctionObject of d with arguments env
1056 // and privateEnv.
1057 // Step 24.a.iii.2. Perform ! env.InitializeBinding(dn, fo).
1058 return ModuleObject::instantiateFunctionDeclarations(cx, module);
1061 // https://tc39.es/ecma262/#sec-moduledeclarationlinking
1062 // ES2023 16.2.1.5.1 Link
1063 bool js::ModuleLink(JSContext* cx, Handle<ModuleObject*> module) {
1064 // Step 1. Assert: module.[[Status]] is not linking or evaluating.
1065 ModuleStatus status = module->status();
1066 if (status == ModuleStatus::Linking || status == ModuleStatus::Evaluating) {
1067 ThrowUnexpectedModuleStatus(cx, status);
1068 return false;
1071 // Step 2. Let stack be a new empty List.
1072 Rooted<ModuleVector> stack(cx);
1074 // Step 3. Let result be Completion(InnerModuleLinking(module, stack, 0)).
1075 size_t ignored;
1076 bool ok = InnerModuleLinking(cx, module, &stack, 0, &ignored);
1078 // Step 4. If result is an abrupt completion, then:
1079 if (!ok) {
1080 // Step 4.a. For each Cyclic Module Record m of stack, do:
1081 for (ModuleObject* m : stack) {
1082 // Step 4.a.i. Assert: m.[[Status]] is linking.
1083 MOZ_ASSERT(m->status() == ModuleStatus::Linking);
1084 // Step 4.a.ii. Set m.[[Status]] to unlinked.
1085 m->setStatus(ModuleStatus::Unlinked);
1086 m->clearDfsIndexes();
1089 // Step 4.b. Assert: module.[[Status]] is unlinked.
1090 MOZ_ASSERT(module->status() == ModuleStatus::Unlinked);
1092 // Step 4.c.
1093 return false;
1096 // Step 5. Assert: module.[[Status]] is linked, evaluating-async, or
1097 // evaluated.
1098 MOZ_ASSERT(module->status() == ModuleStatus::Linked ||
1099 module->status() == ModuleStatus::EvaluatingAsync ||
1100 module->status() == ModuleStatus::Evaluated);
1102 // Step 6. Assert: stack is empty.
1103 MOZ_ASSERT(stack.empty());
1105 // Step 7. Return unused.
1106 return true;
1109 // https://tc39.es/ecma262/#sec-InnerModuleLinking
1110 // ES2023 16.2.1.5.1.1 InnerModuleLinking
1111 static bool InnerModuleLinking(JSContext* cx, Handle<ModuleObject*> module,
1112 MutableHandle<ModuleVector> stack, size_t index,
1113 size_t* indexOut) {
1114 // Step 2. If module.[[Status]] is linking, linked, evaluating-async, or
1115 // evaluated, then:
1116 if (module->status() == ModuleStatus::Linking ||
1117 module->status() == ModuleStatus::Linked ||
1118 module->status() == ModuleStatus::EvaluatingAsync ||
1119 module->status() == ModuleStatus::Evaluated) {
1120 // Step 2.a. Return index.
1121 *indexOut = index;
1122 return true;
1125 // Step 3. Assert: module.[[Status]] is unlinked.
1126 if (module->status() != ModuleStatus::Unlinked) {
1127 ThrowUnexpectedModuleStatus(cx, module->status());
1128 return false;
1131 // Step 8. Append module to stack.
1132 // Do this before changing the status so that we can recover on failure.
1133 if (!stack.append(module)) {
1134 ReportOutOfMemory(cx);
1135 return false;
1138 // Step 4. Set module.[[Status]] to linking.
1139 module->setStatus(ModuleStatus::Linking);
1141 // Step 5. Set module.[[DFSIndex]] to index.
1142 module->setDfsIndex(index);
1144 // Step 6. Set module.[[DFSAncestorIndex]] to index.
1145 module->setDfsAncestorIndex(index);
1147 // Step 7. Set index to index + 1.
1148 index++;
1150 // Step 9. For each String required that is an element of
1151 // module.[[RequestedModules]], do:
1152 Rooted<ModuleRequestObject*> moduleRequest(cx);
1153 Rooted<ModuleObject*> requiredModule(cx);
1154 for (const RequestedModule& request : module->requestedModules()) {
1155 moduleRequest = request.moduleRequest();
1157 // Step 9.a. Let requiredModule be ? HostResolveImportedModule(module,
1158 // required).
1159 requiredModule = HostResolveImportedModule(cx, module, moduleRequest,
1160 ModuleStatus::Unlinked);
1161 if (!requiredModule) {
1162 return false;
1165 // Step 9.b. Set index to ? InnerModuleLinking(requiredModule, stack,
1166 // index).
1167 if (!InnerModuleLinking(cx, requiredModule, stack, index, &index)) {
1168 return false;
1171 // Step 9.c. If requiredModule is a Cyclic Module Record, then:
1172 // Step 9.c.i. Assert: requiredModule.[[Status]] is either linking, linked,
1173 // evaluating-async, or evaluated.
1174 MOZ_ASSERT(requiredModule->status() == ModuleStatus::Linking ||
1175 requiredModule->status() == ModuleStatus::Linked ||
1176 requiredModule->status() == ModuleStatus::EvaluatingAsync ||
1177 requiredModule->status() == ModuleStatus::Evaluated);
1179 // Step 9.c.ii. Assert: requiredModule.[[Status]] is linking if and only if
1180 // requiredModule is in stack.
1181 MOZ_ASSERT((requiredModule->status() == ModuleStatus::Linking) ==
1182 ContainsElement(stack, requiredModule));
1184 // Step 9.c.iii. If requiredModule.[[Status]] is linking, then:
1185 if (requiredModule->status() == ModuleStatus::Linking) {
1186 // Step 9.c.iii.1. Set module.[[DFSAncestorIndex]] to
1187 // min(module.[[DFSAncestorIndex]],
1188 // requiredModule.[[DFSAncestorIndex]]).
1189 module->setDfsAncestorIndex(std::min(module->dfsAncestorIndex(),
1190 requiredModule->dfsAncestorIndex()));
1194 // Step 10. Perform ? module.InitializeEnvironment().
1195 if (!ModuleInitializeEnvironment(cx, module)) {
1196 return false;
1199 // Step 11. Assert: module occurs exactly once in stack.
1200 MOZ_ASSERT(CountElements(stack, module) == 1);
1202 // Step 12. Assert: module.[[DFSAncestorIndex]] <= module.[[DFSIndex]].
1203 MOZ_ASSERT(module->dfsAncestorIndex() <= module->dfsIndex());
1205 // Step 13. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], then
1206 if (module->dfsAncestorIndex() == module->dfsIndex()) {
1207 // Step 13.a.
1208 bool done = false;
1210 // Step 13.b. Repeat, while done is false:
1211 while (!done) {
1212 // Step 13.b.i. Let requiredModule be the last element in stack.
1213 // Step 13.b.ii. Remove the last element of stack.
1214 requiredModule = stack.popCopy();
1216 // Step 13.b.iv. Set requiredModule.[[Status]] to linked.
1217 requiredModule->setStatus(ModuleStatus::Linked);
1219 // Step 13.b.v. If requiredModule and module are the same Module Record,
1220 // set done to true.
1221 done = requiredModule == module;
1225 // Step 14. Return index.
1226 *indexOut = index;
1227 return true;
1230 // https://tc39.es/ecma262/#sec-moduleevaluation
1231 // ES2023 16.2.1.5.2 Evaluate
1232 bool js::ModuleEvaluate(JSContext* cx, Handle<ModuleObject*> moduleArg,
1233 MutableHandle<Value> result) {
1234 Rooted<ModuleObject*> module(cx, moduleArg);
1236 // Step 2. Assert: module.[[Status]] is linked, evaluating-async, or
1237 // evaluated.
1238 ModuleStatus status = module->status();
1239 if (status != ModuleStatus::Linked &&
1240 status != ModuleStatus::EvaluatingAsync &&
1241 status != ModuleStatus::Evaluated) {
1242 ThrowUnexpectedModuleStatus(cx, status);
1243 return false;
1246 // Note: we return early in the error case, as the spec assumes we can get the
1247 // cycle root of |module| which may not be available.
1248 if (module->hadEvaluationError()) {
1249 Rooted<PromiseObject*> capability(cx);
1250 if (!module->hasTopLevelCapability()) {
1251 capability = ModuleObject::createTopLevelCapability(cx, module);
1252 if (!capability) {
1253 return false;
1256 Rooted<Value> error(cx, module->evaluationError());
1257 if (!ModuleObject::topLevelCapabilityReject(cx, module, error)) {
1258 return false;
1262 capability = module->topLevelCapability();
1263 MOZ_ASSERT(JS::GetPromiseState(capability) == JS::PromiseState::Rejected);
1264 MOZ_ASSERT(JS::GetPromiseResult(capability) == module->evaluationError());
1265 result.set(ObjectValue(*capability));
1266 return true;
1269 // Step 3. If module.[[Status]] is evaluating-async or evaluated, set module
1270 // to module.[[CycleRoot]].
1271 if (module->status() == ModuleStatus::EvaluatingAsync ||
1272 module->status() == ModuleStatus::Evaluated) {
1273 module = module->getCycleRoot();
1276 // Step 4. If module.[[TopLevelCapability]] is not empty, then:
1277 if (module->hasTopLevelCapability()) {
1278 // Step 4.a. Return module.[[TopLevelCapability]].[[Promise]].
1279 result.set(ObjectValue(*module->topLevelCapability()));
1280 return true;
1283 // Step 5. Let stack be a new empty List.
1284 Rooted<ModuleVector> stack(cx);
1286 // Step 6. Let capability be ! NewPromiseCapability(%Promise%).
1287 // Step 7. Set module.[[TopLevelCapability]] to capability.
1288 Rooted<PromiseObject*> capability(
1289 cx, ModuleObject::createTopLevelCapability(cx, module));
1290 if (!capability) {
1291 return false;
1294 // Step 8. Let result be Completion(InnerModuleEvaluation(module, stack, 0)).
1295 size_t ignored;
1296 bool ok = InnerModuleEvaluation(cx, module, &stack, 0, &ignored);
1298 // Step 9. f result is an abrupt completion, then:
1299 if (!ok) {
1300 // Attempt to take any pending exception, but make sure we still handle
1301 // uncatchable exceptions.
1302 Rooted<Value> error(cx);
1303 if (cx->isExceptionPending()) {
1304 std::ignore = cx->getPendingException(&error);
1305 cx->clearPendingException();
1308 // Step 9.a. For each Cyclic Module Record m of stack, do
1309 for (ModuleObject* m : stack) {
1310 // Step 9.a.i. Assert: m.[[Status]] is evaluating.
1311 MOZ_ASSERT(m->status() == ModuleStatus::Evaluating);
1313 // Step 9.a.ii. Set m.[[Status]] to evaluated.
1314 // Step 9.a.iii. Set m.[[EvaluationError]] to result.
1315 m->setEvaluationError(error);
1318 // Handle OOM when appending to the stack or over-recursion errors.
1319 if (stack.empty() && !module->hadEvaluationError()) {
1320 module->setEvaluationError(error);
1323 // Step 9.b. Assert: module.[[Status]] is evaluated.
1324 MOZ_ASSERT(module->status() == ModuleStatus::Evaluated);
1326 // Step 9.c. Assert: module.[[EvaluationError]] is result.
1327 MOZ_ASSERT(module->evaluationError() == error);
1329 // Step 9.d. Perform ! Call(capability.[[Reject]], undefined,
1330 // result.[[Value]]).
1331 if (!ModuleObject::topLevelCapabilityReject(cx, module, error)) {
1332 return false;
1334 } else {
1335 // Step 10. Else:
1336 // Step 10.a. Assert: module.[[Status]] is evaluating-async or evaluated.
1337 MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync ||
1338 module->status() == ModuleStatus::Evaluated);
1340 // Step 10.b. Assert: module.[[EvaluationError]] is empty.
1341 MOZ_ASSERT(!module->hadEvaluationError());
1343 // Step 10.c. If module.[[AsyncEvaluation]] is false, then:
1344 if (module->status() == ModuleStatus::Evaluated) {
1345 // Step 10.c.ii. Perform ! Call(capability.[[Resolve]], undefined,
1346 // undefined).
1347 if (!ModuleObject::topLevelCapabilityResolve(cx, module)) {
1348 return false;
1352 // Step 10.d. Assert: stack is empty.
1353 MOZ_ASSERT(stack.empty());
1356 // Step 11. Return capability.[[Promise]].
1357 result.set(ObjectValue(*capability));
1358 return true;
1361 // https://tc39.es/ecma262/#sec-innermoduleevaluation
1362 // 16.2.1.5.2.1 InnerModuleEvaluation
1363 static bool InnerModuleEvaluation(JSContext* cx, Handle<ModuleObject*> module,
1364 MutableHandle<ModuleVector> stack,
1365 size_t index, size_t* indexOut) {
1366 // Step 2. If module.[[Status]] is evaluating-async or evaluated, then:
1367 if (module->status() == ModuleStatus::EvaluatingAsync ||
1368 module->status() == ModuleStatus::Evaluated) {
1369 // Step 2.a. If module.[[EvaluationError]] is empty, return index.
1370 if (!module->hadEvaluationError()) {
1371 *indexOut = index;
1372 return true;
1375 // Step 2.b. Otherwise, return ? module.[[EvaluationError]].
1376 Rooted<Value> error(cx, module->evaluationError());
1377 cx->setPendingException(error, ShouldCaptureStack::Maybe);
1378 return false;
1381 // Step 3. If module.[[Status]] is evaluating, return index.
1382 if (module->status() == ModuleStatus::Evaluating) {
1383 *indexOut = index;
1384 return true;
1387 // Step 4. Assert: module.[[Status]] is linked.
1388 MOZ_ASSERT(module->status() == ModuleStatus::Linked);
1390 // Step 10. Append module to stack.
1391 // Do this before changing the status so that we can recover on failure.
1392 if (!stack.append(module)) {
1393 ReportOutOfMemory(cx);
1394 return false;
1397 // Step 5. Set module.[[Status]] to evaluating.
1398 module->setStatus(ModuleStatus::Evaluating);
1400 // Step 6. Set module.[[DFSIndex]] to index.
1401 module->setDfsIndex(index);
1403 // Step 7. Set module.[[DFSAncestorIndex]] to index.
1404 module->setDfsAncestorIndex(index);
1406 // Step 8. Set module.[[PendingAsyncDependencies]] to 0.
1407 module->setPendingAsyncDependencies(0);
1409 // Step 9. Set index to index + 1.
1410 index++;
1412 // Step 11. For each String required of module.[[RequestedModules]], do:
1413 Rooted<ModuleRequestObject*> required(cx);
1414 Rooted<ModuleObject*> requiredModule(cx);
1415 for (const RequestedModule& request : module->requestedModules()) {
1416 required = request.moduleRequest();
1418 // Step 11.a. Let requiredModule be ! HostResolveImportedModule(module,
1419 // required).
1420 // Step 11.b. NOTE: Link must be completed successfully prior to invoking
1421 // this method, so every requested module is guaranteed to
1422 // resolve successfully.
1423 requiredModule =
1424 HostResolveImportedModule(cx, module, required, ModuleStatus::Linked);
1425 if (!requiredModule) {
1426 return false;
1429 // Step 11.c. Set index to ? InnerModuleEvaluation(requiredModule, stack,
1430 // index).
1431 if (!InnerModuleEvaluation(cx, requiredModule, stack, index, &index)) {
1432 return false;
1435 // Step 11.d. If requiredModule is a Cyclic Module Record, then:
1436 // Step 11.d.i. Assert: requiredModule.[[Status]] is either evaluating,
1437 // evaluating-async, or evaluated.
1438 MOZ_ASSERT(requiredModule->status() == ModuleStatus::Evaluating ||
1439 requiredModule->status() == ModuleStatus::EvaluatingAsync ||
1440 requiredModule->status() == ModuleStatus::Evaluated);
1442 // Step 11.d.ii. Assert: requiredModule.[[Status]] is evaluating if and only
1443 // if requiredModule is in stack.
1444 MOZ_ASSERT((requiredModule->status() == ModuleStatus::Evaluating) ==
1445 ContainsElement(stack, requiredModule));
1447 // Step 11.d.iii. If requiredModule.[[Status]] is evaluating, then:
1448 if (requiredModule->status() == ModuleStatus::Evaluating) {
1449 // Step 11.d.iii.1. Set module.[[DFSAncestorIndex]] to
1450 // min(module.[[DFSAncestorIndex]],
1451 // requiredModule.[[DFSAncestorIndex]]).
1452 module->setDfsAncestorIndex(std::min(module->dfsAncestorIndex(),
1453 requiredModule->dfsAncestorIndex()));
1454 } else {
1455 // Step 11.d.iv. Else:
1456 // Step 11.d.iv.1. Set requiredModule to requiredModule.[[CycleRoot]].
1457 requiredModule = requiredModule->getCycleRoot();
1459 // Step 11.d.iv.2. Assert: requiredModule.[[Status]] is evaluating-async
1460 // or evaluated.
1461 MOZ_ASSERT(requiredModule->status() >= ModuleStatus::EvaluatingAsync ||
1462 requiredModule->status() == ModuleStatus::Evaluated);
1464 // Step 11.d.iv.3. If requiredModule.[[EvaluationError]] is not empty,
1465 // return ? requiredModule.[[EvaluationError]].
1466 if (requiredModule->hadEvaluationError()) {
1467 Rooted<Value> error(cx, requiredModule->evaluationError());
1468 cx->setPendingException(error, ShouldCaptureStack::Maybe);
1469 return false;
1473 // Step 11.d.v. If requiredModule.[[AsyncEvaluation]] is true, then:
1474 if (requiredModule->isAsyncEvaluating() &&
1475 requiredModule->status() != ModuleStatus::Evaluated) {
1476 // Step 11.d.v.2. Append module to requiredModule.[[AsyncParentModules]].
1477 if (!ModuleObject::appendAsyncParentModule(cx, requiredModule, module)) {
1478 return false;
1481 // Step 11.d.v.1. Set module.[[PendingAsyncDependencies]] to
1482 // module.[[PendingAsyncDependencies]] + 1.
1483 module->setPendingAsyncDependencies(module->pendingAsyncDependencies() +
1488 // Step 12. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] is
1489 // true, then:
1490 if (module->pendingAsyncDependencies() > 0 || module->hasTopLevelAwait()) {
1491 // Step 12.a. Assert: module.[[AsyncEvaluation]] is false and was never
1492 // previously set to true.
1493 MOZ_ASSERT(!module->isAsyncEvaluating());
1495 // Step 12.b. Set module.[[AsyncEvaluation]] to true.
1496 // Step 12.c. NOTE: The order in which module records have their
1497 // [[AsyncEvaluation]] fields transition to true is
1498 // significant. (See 16.2.1.5.2.4.)
1499 module->setAsyncEvaluating();
1501 // Step 12.d. If module.[[PendingAsyncDependencies]] is 0, perform
1502 // ExecuteAsyncModule(module).
1503 if (module->pendingAsyncDependencies() == 0) {
1504 if (!ExecuteAsyncModule(cx, module)) {
1505 return false;
1508 } else {
1509 // Step 13. Otherwise, perform ? module.ExecuteModule().
1510 if (!ModuleObject::execute(cx, module)) {
1511 return false;
1515 // Step 14. Assert: module occurs exactly once in stack.
1516 MOZ_ASSERT(CountElements(stack, module) == 1);
1518 // Step 15. Assert: module.[[DFSAncestorIndex]] <= module.[[DFSIndex]].
1519 MOZ_ASSERT(module->dfsAncestorIndex() <= module->dfsIndex());
1521 // Step 16. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], then:
1522 if (module->dfsAncestorIndex() == module->dfsIndex()) {
1523 // Step 16.a. Let done be false.
1524 bool done = false;
1526 // Step 16.b. Repeat, while done is false:
1527 while (!done) {
1528 // Step 16.b.i. Let requiredModule be the last element in stack.
1529 // Step 16.b.ii. Remove the last element of stack.
1530 requiredModule = stack.popCopy();
1532 // Step 16.b.iv. If requiredModule.[[AsyncEvaluation]] is false, set
1533 // requiredModule.[[Status]] to evaluated.
1534 if (!requiredModule->isAsyncEvaluating()) {
1535 requiredModule->setStatus(ModuleStatus::Evaluated);
1536 } else {
1537 // Step 16.b.v. Otherwise, set requiredModule.[[Status]] to
1538 // evaluating-async.
1539 requiredModule->setStatus(ModuleStatus::EvaluatingAsync);
1542 // Step 16.b.vi. If requiredModule and module are the same Module Record,
1543 // set done to true.
1544 done = requiredModule == module;
1546 // Step 16.b.vii. Set requiredModule.[[CycleRoot]] to module.
1547 requiredModule->setCycleRoot(module);
1551 // Step 17. Return index.
1552 *indexOut = index;
1553 return true;
1556 // https://tc39.es/ecma262/#sec-execute-async-module
1557 // ES2023 16.2.1.5.2.2 ExecuteAsyncModule
1558 static bool ExecuteAsyncModule(JSContext* cx, Handle<ModuleObject*> module) {
1559 // Step 1. Assert: module.[[Status]] is evaluating or evaluating-async.
1560 MOZ_ASSERT(module->status() == ModuleStatus::Evaluating ||
1561 module->status() == ModuleStatus::EvaluatingAsync);
1563 // Step 2. Assert: module.[[HasTLA]] is true.
1564 MOZ_ASSERT(module->hasTopLevelAwait());
1566 // Steps 3 - 8 are performed by the AsyncAwait opcode.
1568 // Step 9. Perform ! module.ExecuteModule(capability).
1569 // Step 10. Return unused.
1570 return ModuleObject::execute(cx, module);
1573 // https://tc39.es/ecma262/#sec-gather-available-ancestors
1574 // ES2023 16.2.1.5.2.3 GatherAvailableAncestors
1575 static bool GatherAvailableModuleAncestors(
1576 JSContext* cx, Handle<ModuleObject*> module,
1577 MutableHandle<ModuleVector> execList) {
1578 MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync);
1580 // Step 1. For each Cyclic Module Record m of module.[[AsyncParentModules]],
1581 // do:
1582 Rooted<ListObject*> asyncParentModules(cx, module->asyncParentModules());
1583 Rooted<ModuleObject*> m(cx);
1584 for (uint32_t i = 0; i != asyncParentModules->length(); i++) {
1585 m = &asyncParentModules->getDenseElement(i).toObject().as<ModuleObject>();
1587 // Step 1.a. If execList does not contain m and
1588 // m.[[CycleRoot]].[[EvaluationError]] is empty, then:
1590 // Note: we also check whether m.[[EvaluationError]] is empty since an error
1591 // in synchronous execution can prevent the CycleRoot field from being set.
1592 if (!m->hadEvaluationError() && !m->getCycleRoot()->hadEvaluationError() &&
1593 !ContainsElement(execList, m)) {
1594 // Step 1.a.i. Assert: m.[[Status]] is evaluating-async.
1595 MOZ_ASSERT(m->status() == ModuleStatus::EvaluatingAsync);
1597 // Step 1.a.ii. Assert: m.[[EvaluationError]] is empty.
1598 MOZ_ASSERT(!m->hadEvaluationError());
1600 // Step 1.a.iii. Assert: m.[[AsyncEvaluation]] is true.
1601 MOZ_ASSERT(m->isAsyncEvaluating());
1603 // Step 1.a.iv. Assert: m.[[PendingAsyncDependencies]] > 0.
1604 MOZ_ASSERT(m->pendingAsyncDependencies() > 0);
1606 // Step 1.a.v. Set m.[[PendingAsyncDependencies]] to
1607 // m.[[PendingAsyncDependencies]] - 1.
1608 m->setPendingAsyncDependencies(m->pendingAsyncDependencies() - 1);
1610 // Step 1.a.vi. If m.[[PendingAsyncDependencies]] = 0, then:
1611 if (m->pendingAsyncDependencies() == 0) {
1612 // Step 1.a.vi.1. Append m to execList.
1613 if (!execList.append(m)) {
1614 return false;
1617 // Step 1.a.vi.2. If m.[[HasTLA]] is false, perform
1618 // GatherAvailableAncestors(m, execList).
1619 if (!m->hasTopLevelAwait() &&
1620 !GatherAvailableModuleAncestors(cx, m, execList)) {
1621 return false;
1627 // Step 2. Return unused.
1628 return true;
1631 struct EvalOrderComparator {
1632 bool operator()(ModuleObject* a, ModuleObject* b, bool* lessOrEqualp) {
1633 int32_t result = int32_t(a->getAsyncEvaluatingPostOrder()) -
1634 int32_t(b->getAsyncEvaluatingPostOrder());
1635 *lessOrEqualp = (result <= 0);
1636 return true;
1640 static void RejectExecutionWithPendingException(JSContext* cx,
1641 Handle<ModuleObject*> module) {
1642 // If there is no exception pending then we have been interrupted or have
1643 // OOM'd and all bets are off. We reject the execution by throwing
1644 // undefined. Not much more we can do.
1645 RootedValue exception(cx);
1646 if (cx->isExceptionPending()) {
1647 std::ignore = cx->getPendingException(&exception);
1649 cx->clearPendingException();
1650 AsyncModuleExecutionRejected(cx, module, exception);
1653 // https://tc39.es/ecma262/#sec-async-module-execution-fulfilled
1654 // ES2023 16.2.1.5.2.4 AsyncModuleExecutionFulfilled
1655 void js::AsyncModuleExecutionFulfilled(JSContext* cx,
1656 Handle<ModuleObject*> module) {
1657 // Step 1. If module.[[Status]] is evaluated, then:
1658 if (module->status() == ModuleStatus::Evaluated) {
1659 // Step 1.a. Assert: module.[[EvaluationError]] is not empty.
1660 MOZ_ASSERT(module->hadEvaluationError());
1662 // Step 1.b. Return unused.
1663 return;
1666 // Step 2. Assert: module.[[Status]] is evaluating-async.
1667 MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync);
1669 // Step 3. Assert: module.[[AsyncEvaluation]] is true.
1670 MOZ_ASSERT(module->isAsyncEvaluating());
1672 // Step 4. Assert: module.[[EvaluationError]] is empty.
1673 MOZ_ASSERT(!module->hadEvaluationError());
1675 // The following steps are performed in a different order from the
1676 // spec. Gather available module ancestors before mutating the module object
1677 // as this can fail in our implementation.
1679 // Step 8. Let execList be a new empty List.
1680 Rooted<ModuleVector> execList(cx);
1682 // Step 9. Perform GatherAvailableAncestors(module, execList).
1683 if (!GatherAvailableModuleAncestors(cx, module, &execList)) {
1684 RejectExecutionWithPendingException(cx, module);
1685 return;
1688 // Step 10. Let sortedExecList be a List whose elements are the elements of
1689 // execList, in the order in which they had their [[AsyncEvaluation]]
1690 // fields set to true in InnerModuleEvaluation.
1692 Rooted<ModuleVector> scratch(cx);
1693 if (!scratch.resize(execList.length())) {
1694 ReportOutOfMemory(cx);
1695 RejectExecutionWithPendingException(cx, module);
1696 return;
1699 MOZ_ALWAYS_TRUE(MergeSort(execList.begin(), execList.length(),
1700 scratch.begin(), EvalOrderComparator()));
1702 // Step 11. Assert: All elements of sortedExecList have their
1703 // [[AsyncEvaluation]] field set to true,
1704 // [[PendingAsyncDependencies]] field set to 0, and
1705 // [[EvaluationError]] field set to empty.
1706 #ifdef DEBUG
1707 for (ModuleObject* m : execList) {
1708 MOZ_ASSERT(m->isAsyncEvaluating());
1709 MOZ_ASSERT(m->pendingAsyncDependencies() == 0);
1710 MOZ_ASSERT(!m->hadEvaluationError());
1712 #endif
1714 // Return to original order of steps.
1716 ModuleObject::onTopLevelEvaluationFinished(module);
1718 // Step 6. Set module.[[Status]] to evaluated.
1719 module->setStatus(ModuleStatus::Evaluated);
1720 module->clearAsyncEvaluatingPostOrder();
1722 // Step 7. If module.[[TopLevelCapability]] is not empty, then:
1723 if (module->hasTopLevelCapability()) {
1724 // Step 7.a. Assert: module.[[CycleRoot]] is module.
1725 MOZ_ASSERT(module->getCycleRoot() == module);
1727 // Step 7.b. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]],
1728 // undefined, undefined).
1729 if (!ModuleObject::topLevelCapabilityResolve(cx, module)) {
1730 // If Resolve fails, there's nothing more we can do here.
1731 cx->clearPendingException();
1735 // Step 12. For each Cyclic Module Record m of sortedExecList, do:
1736 Rooted<ModuleObject*> m(cx);
1737 for (ModuleObject* obj : execList) {
1738 m = obj;
1740 // Step 12.a. If m.[[Status]] is evaluated, then:
1741 if (m->status() == ModuleStatus::Evaluated) {
1742 // Step 12.a.i. Assert: m.[[EvaluationError]] is not empty.
1743 MOZ_ASSERT(m->hadEvaluationError());
1744 } else if (m->hasTopLevelAwait()) {
1745 // Step 12.b. Else if m.[[HasTLA]] is true, then:
1746 // Step 12.b.i. Perform ExecuteAsyncModule(m).
1747 MOZ_ALWAYS_TRUE(ExecuteAsyncModule(cx, m));
1748 } else {
1749 // Step 12.c. Else:
1750 // Step 12.c.i. Let result be m.ExecuteModule().
1751 bool ok = ModuleObject::execute(cx, m);
1753 // Step 12.c.ii. If result is an abrupt completion, then:
1754 if (!ok) {
1755 // Step 12.c.ii.1. Perform AsyncModuleExecutionRejected(m,
1756 // result.[[Value]]).
1757 RejectExecutionWithPendingException(cx, m);
1758 } else {
1759 // Step 12.c.iii. Else:
1760 // Step 12.c.iii.1. Set m.[[Status]] to evaluated.
1761 m->setStatus(ModuleStatus::Evaluated);
1762 m->clearAsyncEvaluatingPostOrder();
1764 // Step 12.c.iii.2. If m.[[TopLevelCapability]] is not empty, then:
1765 if (m->hasTopLevelCapability()) {
1766 // Step 12.c.iii.2.a. Assert: m.[[CycleRoot]] is m.
1767 MOZ_ASSERT(m->getCycleRoot() == m);
1769 // Step 12.c.iii.2.b. Perform !
1770 // Call(m.[[TopLevelCapability]].[[Resolve]],
1771 // undefined, undefined).
1772 if (!ModuleObject::topLevelCapabilityResolve(cx, m)) {
1773 // If Resolve fails, there's nothing more we can do here.
1774 cx->clearPendingException();
1781 // Step 13. Return unused.
1784 // https://tc39.es/ecma262/#sec-async-module-execution-rejected
1785 // ES2023 16.2.1.5.2.5 AsyncModuleExecutionRejected
1786 void js::AsyncModuleExecutionRejected(JSContext* cx,
1787 Handle<ModuleObject*> module,
1788 HandleValue error) {
1789 // Step 1. If module.[[Status]] is evaluated, then:
1790 if (module->status() == ModuleStatus::Evaluated) {
1791 // Step 1.a. Assert: module.[[EvaluationError]] is not empty
1792 MOZ_ASSERT(module->hadEvaluationError());
1794 // Step 1.b. Return unused.
1795 return;
1798 // Step 2. Assert: module.[[Status]] is evaluating-async.
1799 MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync);
1801 // Step 3. Assert: module.[[AsyncEvaluation]] is true.
1802 MOZ_ASSERT(module->isAsyncEvaluating());
1804 // Step 4. 4. Assert: module.[[EvaluationError]] is empty.
1805 MOZ_ASSERT(!module->hadEvaluationError());
1807 ModuleObject::onTopLevelEvaluationFinished(module);
1809 // Step 5. Set module.[[EvaluationError]] to ThrowCompletion(error).
1810 module->setEvaluationError(error);
1812 // Step 6. Set module.[[Status]] to evaluated.
1813 MOZ_ASSERT(module->status() == ModuleStatus::Evaluated);
1815 module->clearAsyncEvaluatingPostOrder();
1817 // Step 7. For each Cyclic Module Record m of module.[[AsyncParentModules]],
1818 // do:
1819 Rooted<ListObject*> parents(cx, module->asyncParentModules());
1820 Rooted<ModuleObject*> parent(cx);
1821 for (uint32_t i = 0; i < parents->length(); i++) {
1822 parent = &parents->get(i).toObject().as<ModuleObject>();
1824 // Step 7.a. Perform AsyncModuleExecutionRejected(m, error).
1825 AsyncModuleExecutionRejected(cx, parent, error);
1828 // Step 8. If module.[[TopLevelCapability]] is not empty, then:
1829 if (module->hasTopLevelCapability()) {
1830 // Step 8.a. Assert: module.[[CycleRoot]] is module.
1831 MOZ_ASSERT(module->getCycleRoot() == module);
1833 // Step 8.b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
1834 // undefined, error).
1835 if (!ModuleObject::topLevelCapabilityReject(cx, module, error)) {
1836 // If Reject fails, there's nothing more we can do here.
1837 cx->clearPendingException();
1841 // Step 9. Return unused.