v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
source-text-module.cc
Go to the documentation of this file.
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include "src/api/api-inl.h"
8#include "src/ast/modules.h"
15#include "src/utils/ostreams.h"
16
17namespace v8 {
18namespace internal {
19
22 return string->EnsureHash();
23 }
24};
25
28 DirectHandle<String> rhs) const {
29 return lhs->Equals(*rhs);
30 }
31};
32
34 : public std::unordered_set<Handle<String>, StringHandleHash,
35 StringHandleEqual,
36 ZoneAllocator<Handle<String>>> {
37 public:
38 explicit UnorderedStringSet(Zone* zone)
41 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
42 ZoneAllocator<Handle<String>>(zone)) {}
43};
44
46 : public std::unordered_map<
47 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
48 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> {
49 public:
50 explicit UnorderedStringMap(Zone* zone)
51 : std::unordered_map<
53 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>>(
54 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
55 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>(
56 zone)) {}
57};
58
60 : public std::unordered_map<
61 Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
62 ModuleHandleEqual,
63 ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> {
64 public:
65 explicit ResolveSet(Zone* zone)
66 : std::unordered_map<Handle<Module>, UnorderedStringSet*,
68 ZoneAllocator<std::pair<const Handle<Module>,
70 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
72 zone)),
73 zone_(zone) {}
74
75 Zone* zone() const { return zone_; }
76
77 private:
79};
80
84 DCHECK(lhs->HasAsyncEvaluationOrdinal());
85 DCHECK(rhs->HasAsyncEvaluationOrdinal());
86 return lhs->async_evaluation_ordinal() < rhs->async_evaluation_ordinal();
87 }
88};
89
92 switch (status()) {
93 case kUnlinked:
94 case kPreLinking:
96 case kLinking:
97 return Cast<JSFunction>(code())->shared();
98 case kLinked:
99 case kEvaluating:
100 case kEvaluatingAsync:
101 case kEvaluated:
102 return Cast<JSGeneratorObject>(code())->function()->shared();
103 case kErrored:
105 }
106 UNREACHABLE();
107}
108
113
114int SourceTextModule::ExportIndex(int cell_index) {
117 return cell_index - 1;
118}
119
120int SourceTextModule::ImportIndex(int cell_index) {
123 return -cell_index - 1;
124}
125
129 Handle<ObjectHashTable> exports(module->exports(), isolate);
130 DCHECK(IsTheHole(exports->Lookup(name), isolate));
131 exports = ObjectHashTable::Put(exports, name, entry);
132 module->set_exports(*exports);
133}
134
137 int cell_index,
139 DCHECK_LT(0, names->length());
140 DirectHandle<Cell> cell = isolate->factory()->NewCell();
141 module->regular_exports()->set(ExportIndex(cell_index), *cell);
142
143 Handle<ObjectHashTable> exports(module->exports(), isolate);
144 for (int i = 0, n = names->length(); i < n; ++i) {
145 DirectHandle<String> name(Cast<String>(names->get(i)), isolate);
146 DCHECK(IsTheHole(exports->Lookup(name), isolate));
147 exports = ObjectHashTable::Put(exports, name, cell);
148 }
149 module->set_exports(*exports);
150}
151
154 Tagged<Object> cell;
157 cell = regular_imports()->get(ImportIndex(cell_index));
158 break;
160 cell = regular_exports()->get(ExportIndex(cell_index));
161 break;
163 UNREACHABLE();
164 }
165 return Cast<Cell>(cell);
166}
167
169 Isolate* isolate, DirectHandle<SourceTextModule> module, int cell_index) {
170 return handle(module->GetCell(cell_index)->value(), isolate);
171}
172
174 int cell_index,
175 DirectHandle<Object> value) {
179 module->GetCell(cell_index)->set_value(*value);
180}
181
183 Isolate* isolate, Handle<SourceTextModule> module,
184 DirectHandle<String> module_specifier, Handle<String> export_name,
185 MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) {
186 Handle<Object> object(module->exports()->Lookup(export_name), isolate);
187 if (IsCell(*object)) {
188 // Already resolved (e.g. because it's a local export).
189 return Cast<Cell>(object);
190 }
191
192 // Check for cycle before recursing.
193 {
194 // Attempt insertion with a null string set.
195 auto result = resolve_set->insert({module, nullptr});
196 UnorderedStringSet*& name_set = result.first->second;
197 if (result.second) {
198 // |module| wasn't in the map previously, so allocate a new name set.
199 Zone* zone = resolve_set->zone();
200 name_set = zone->New<UnorderedStringSet>(zone);
201 } else if (name_set->count(export_name)) {
202 // Cycle detected.
203 if (must_resolve) {
204 isolate->ThrowAt(isolate->factory()->NewSyntaxError(
205 MessageTemplate::kCyclicModuleDependency,
206 export_name, module_specifier),
207 &loc);
208 return MaybeHandle<Cell>();
209 }
210 return MaybeHandle<Cell>();
211 }
212 name_set->insert(export_name);
213 }
214
215 if (IsSourceTextModuleInfoEntry(*object)) {
216 // Not yet resolved indirect export.
217 auto entry = Cast<SourceTextModuleInfoEntry>(object);
218 Handle<String> import_name(Cast<String>(entry->import_name()), isolate);
219 Handle<Script> script(module->GetScript(), isolate);
220 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
221
222 Handle<Cell> cell;
223 if (!ResolveImport(isolate, module, import_name, entry->module_request(),
224 new_loc, true, resolve_set)
225 .ToHandle(&cell)) {
226 DCHECK(isolate->has_exception());
227 return MaybeHandle<Cell>();
228 }
229
230 // The export table may have changed but the entry in question should be
231 // unchanged.
232 Handle<ObjectHashTable> exports(module->exports(), isolate);
233 DCHECK(IsSourceTextModuleInfoEntry(exports->Lookup(export_name)));
234
235 exports = ObjectHashTable::Put(exports, export_name, cell);
236 module->set_exports(*exports);
237 return cell;
238 }
239
240 DCHECK(IsTheHole(*object, isolate));
242 isolate, module, module_specifier, export_name, loc, must_resolve,
243 resolve_set);
244}
245
248 Handle<String> name, int module_request_index, MessageLocation loc,
249 bool must_resolve, Module::ResolveSet* resolve_set) {
250 DirectHandle<ModuleRequest> module_request(
252 module->info()->module_requests()->get(module_request_index)),
253 isolate);
254 switch (module_request->phase()) {
256 DCHECK(v8_flags.js_source_phase_imports);
257
258 // https://tc39.es/proposal-source-phase-imports/#sec-source-text-module-record-initialize-environment
259 // InitializeEnvironment
260 // 7.c. Else if in.[[ImportName]] is source, then
261 // 7.c.i. Let moduleSourceObject be ? importedModule.GetModuleSource().
262 // 7.c.ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
263 // 7.c.iii. Perform ! env.InitializeBinding(in.[[LocalName]],
264 // moduleSourceObject).
265 Handle<Cell> cell = isolate->factory()->NewCell();
266 cell->set_value(module->requested_modules()->get(module_request_index));
267 return cell;
268 }
270 DCHECK_EQ(module_request->phase(), ModuleImportPhase::kEvaluation);
271 Handle<Module> requested_module(
272 Cast<Module>(module->requested_modules()->get(module_request_index)),
273 isolate);
274 DirectHandle<String> module_specifier(
275 Cast<String>(module_request->specifier()), isolate);
277 Module::ResolveExport(isolate, requested_module, module_specifier,
278 name, loc, must_resolve, resolve_set);
279 DCHECK_IMPLIES(isolate->has_exception(), result.is_null());
280 return result;
281 }
282 default:
283 UNREACHABLE();
284 }
285}
286
289 DirectHandle<String> module_specifier, Handle<String> export_name,
290 MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) {
291 if (!export_name->Equals(ReadOnlyRoots(isolate).default_string())) {
292 // Go through all star exports looking for the given name. If multiple star
293 // exports provide the name, make sure they all map it to the same cell.
294 Handle<Cell> unique_cell;
295 DirectHandle<FixedArray> special_exports(module->info()->special_exports(),
296 isolate);
297 for (int i = 0, n = special_exports->length(); i < n; ++i) {
299 i::Cast<i::SourceTextModuleInfoEntry>(special_exports->get(i)),
300 isolate);
301 if (!IsUndefined(entry->export_name(), isolate)) {
302 continue; // Indirect export.
303 }
304
305 Handle<Script> script(module->GetScript(), isolate);
306 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
307
308 Handle<Cell> cell;
309 if (ResolveImport(isolate, module, export_name, entry->module_request(),
310 new_loc, false, resolve_set)
311 .ToHandle(&cell)) {
312 if (unique_cell.is_null()) unique_cell = cell;
313 if (*unique_cell != *cell) {
314 isolate->ThrowAt(isolate->factory()->NewSyntaxError(
315 MessageTemplate::kAmbiguousExport,
316 module_specifier, export_name),
317 &loc);
318 return MaybeHandle<Cell>();
319 }
320 } else if (isolate->has_exception()) {
321 return MaybeHandle<Cell>();
322 }
323 }
324
325 if (!unique_cell.is_null()) {
326 // Found a unique star export for this name.
327 Handle<ObjectHashTable> exports(module->exports(), isolate);
328 DCHECK(IsTheHole(exports->Lookup(export_name), isolate));
329 exports = ObjectHashTable::Put(exports, export_name, unique_cell);
330 module->set_exports(*exports);
331 return unique_cell;
332 }
333 }
334
335 // Unresolvable.
336 if (must_resolve) {
337 isolate->ThrowAt(
338 isolate->factory()->NewSyntaxError(MessageTemplate::kUnresolvableExport,
339 module_specifier, export_name),
340 &loc);
341 return MaybeHandle<Cell>();
342 }
343 return MaybeHandle<Cell>();
344}
345
349 v8::Module::ResolveModuleCallback module_callback,
350 v8::Module::ResolveSourceCallback source_callback) {
351 DCHECK_NE(module_callback, nullptr);
352 // Obtain requested modules.
353 DirectHandle<SourceTextModuleInfo> module_info(module->info(), isolate);
354 DirectHandle<FixedArray> module_requests(module_info->module_requests(),
355 isolate);
356 DirectHandle<FixedArray> requested_modules(module->requested_modules(),
357 isolate);
358 for (int i = 0, length = module_requests->length(); i < length; ++i) {
359 DirectHandle<ModuleRequest> module_request(
360 Cast<ModuleRequest>(module_requests->get(i)), isolate);
361 DirectHandle<String> specifier(module_request->specifier(), isolate);
362 DirectHandle<FixedArray> import_attributes(
363 module_request->import_attributes(), isolate);
364 switch (module_request->phase()) {
366 v8::Local<v8::Module> api_requested_module;
367 if (!module_callback(context, v8::Utils::ToLocal(specifier),
368 v8::Utils::FixedArrayToLocal(import_attributes),
369 v8::Utils::ToLocal(Cast<Module>(module)))
370 .ToLocal(&api_requested_module)) {
371 return false;
372 }
373 DirectHandle<Module> requested_module =
374 Utils::OpenDirectHandle(*api_requested_module);
375 requested_modules->set(i, *requested_module);
376 break;
377 }
379 DCHECK(v8_flags.js_source_phase_imports);
380 v8::Local<v8::Object> api_requested_module_source;
381 if (!source_callback(context, v8::Utils::ToLocal(specifier),
382 v8::Utils::FixedArrayToLocal(import_attributes),
383 v8::Utils::ToLocal(Cast<Module>(module)))
384 .ToLocal(&api_requested_module_source)) {
385 return false;
386 }
387 DirectHandle<JSReceiver> requested_module_source =
388 Utils::OpenDirectHandle(*api_requested_module_source);
389 requested_modules->set(i, *requested_module_source);
390 break;
391 }
392 default:
393 UNREACHABLE();
394 }
395 }
396
397 // Recurse.
398 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
399 DirectHandle<ModuleRequest> module_request(
400 Cast<ModuleRequest>(module_requests->get(i)), isolate);
401 if (module_request->phase() != ModuleImportPhase::kEvaluation) {
402 continue;
403 }
404 DirectHandle<Module> requested_module(
405 Cast<Module>(requested_modules->get(i)), isolate);
406 if (!Module::PrepareInstantiate(isolate, requested_module, context,
407 module_callback, source_callback)) {
408 return false;
409 }
410 }
411
412 // Set up local exports.
413 // TODO(neis): Create regular_exports array here instead of in factory method?
414 for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
415 int cell_index = module_info->RegularExportCellIndex(i);
416 DirectHandle<FixedArray> export_names(
417 module_info->RegularExportExportNames(i), isolate);
418 CreateExport(isolate, module, cell_index, export_names);
419 }
420
421 // Partially set up indirect exports.
422 // For each indirect export, we create the appropriate slot in the export
423 // table and store its SourceTextModuleInfoEntry there. When we later find
424 // the correct Cell in the module that actually provides the value, we replace
425 // the SourceTextModuleInfoEntry by that Cell (see ResolveExport).
426 DirectHandle<FixedArray> special_exports(module_info->special_exports(),
427 isolate);
428 for (int i = 0, n = special_exports->length(); i < n; ++i) {
430 Cast<SourceTextModuleInfoEntry>(special_exports->get(i)), isolate);
431 DirectHandle<Object> export_name(entry->export_name(), isolate);
432 if (IsUndefined(*export_name, isolate)) continue; // Star export.
433 CreateIndirectExport(isolate, module, Cast<String>(export_name), entry);
434 }
435
436 DCHECK_EQ(module->status(), kPreLinking);
437 return true;
438}
439
441 Isolate* isolate, DirectHandle<SourceTextModule> module) {
442 DCHECK_EQ(module->status(), kLinking);
443 DirectHandle<JSFunction> function(Cast<JSFunction>(module->code()), isolate);
444 DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
445 DirectHandle<Object> receiver = isolate->factory()->undefined_value();
446
447 DirectHandle<ScopeInfo> scope_info(function->shared()->scope_info(), isolate);
448 DirectHandle<Context> context = isolate->factory()->NewModuleContext(
449 module, isolate->native_context(), scope_info);
450 function->set_context(*context);
451
452 MaybeDirectHandle<Object> maybe_generator =
453 Execution::Call(isolate, function, receiver, {});
454 DirectHandle<Object> generator;
455 if (!maybe_generator.ToHandle(&generator)) {
456 DCHECK(isolate->has_exception());
457 return false;
458 }
459 DCHECK_EQ(*function, Cast<JSGeneratorObject>(generator)->function());
460 module->set_code(Cast<JSGeneratorObject>(*generator));
461 return true;
462}
463
464// ES#sec-innermoduleevaluation and ES#sec-innermodulelinking
467 ZoneForwardList<Handle<SourceTextModule>>* stack, Status new_status) {
468 DCHECK(new_status == kLinked || new_status == kEvaluated);
469
470#ifdef DEBUG
471 if (v8_flags.trace_module_status) {
472 StdoutStream os;
473 os << "Transitioning strongly connected module graph component to "
474 << Module::StatusString(new_status) << " {\n";
475 }
476#endif // DEBUG
477
478 // Below, N/M means step N in InnerModuleEvaluation and step M in
479 // InnerModuleLinking.
480
481 // 14/11. Assert: module occurs exactly once in stack.
483 // {module} is on the {stack}.
484 std::count_if(stack->begin(), stack->end(), [&](DirectHandle<Module> m) {
485 return *m == *module;
486 }) == 1);
487
488 // 15/12. Assert: module.[[DFSAncestorIndex]] ≤ module.[[DFSIndex]].
489 DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index());
490
491 // 16/13. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], then
492 if (module->dfs_ancestor_index() == module->dfs_index()) {
493 // This is the root of its strongly connected component.
494 DirectHandle<SourceTextModule> cycle_root = module;
496 // This loop handles the loops in both InnerModuleEvaluation and
497 // InnerModuleLinking.
498 //
499 // InnerModuleEvaluation
500 //
501 // a. Let done be false.
502 // b. Repeat, while done is false,
503 // i. Let requiredModule be the last element of stack.
504 // ii. Remove the last element of stack.
505 // iii. Assert: requiredModule is a Cyclic Module Record.
506 // iv. If requiredModule.[[AsyncEvaluation]] is false, set
507 // requiredModule.[[Status]] to EVALUATED.
508 // v. Otherwise, set requiredModule.[[Status]] to EVALUATING-ASYNC.
509 // vi. If requiredModule and module are the same Module Record, set done
510 // to true.
511 // vii. Set requiredModule.[[CycleRoot]] to module.
512 //
513 // InnerModuleLinking
514 //
515 // a. Let done be false.
516 // b. Repeat, while done is false,
517 // i. Let requiredModule be the last element of stack.
518 // ii. Remove the last element of stack.
519 // iii. Assert: requiredModule is a Cyclic Module Record.
520 // iv. Set requiredModule.[[Status]] to LINKED.
521 // v. If requiredModule and module are the same Module Record, set done
522 // to true.
523 do {
524 ancestor = stack->front();
525 stack->pop_front();
526 DCHECK_EQ(ancestor->status(),
527 new_status == kLinked ? kLinking : kEvaluating);
528 if (new_status == kLinked) {
529 if (!SourceTextModule::RunInitializationCode(isolate, ancestor)) {
530 return false;
531 }
532 ancestor->SetStatus(kLinked);
533 } else {
534 DCHECK(IsTheHole(ancestor->cycle_root(), isolate));
535 ancestor->set_cycle_root(*cycle_root);
536 ancestor->SetStatus(ancestor->HasAsyncEvaluationOrdinal()
537 ? kEvaluatingAsync
538 : kEvaluated);
539 }
540 } while (*ancestor != *module);
541 }
542#ifdef DEBUG
543 if (v8_flags.trace_module_status) {
544 StdoutStream os;
545 os << "}\n";
546 }
547#endif // DEBUG
548 return true;
549}
550
552 Isolate* isolate, Handle<SourceTextModule> module,
553 ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index,
554 Zone* zone) {
555 // Instantiate SharedFunctionInfo and mark module as instantiating for
556 // the recursion.
558 Cast<SharedFunctionInfo>(module->code()), isolate);
559 DirectHandle<JSFunction> function =
560 Factory::JSFunctionBuilder{isolate, shared, isolate->native_context()}
561 .Build();
562 module->set_code(*function);
563 module->SetStatus(kLinking);
564 module->set_dfs_index(*dfs_index);
565 module->set_dfs_ancestor_index(*dfs_index);
566 stack->push_front(module);
567 (*dfs_index)++;
568
569 // Recurse.
570 DirectHandle<FixedArray> module_requests(module->info()->module_requests(),
571 isolate);
572 DirectHandle<FixedArray> requested_modules(module->requested_modules(),
573 isolate);
574 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
575 DirectHandle<ModuleRequest> module_request(
576 Cast<ModuleRequest>(module_requests->get(i)), isolate);
577 if (module_request->phase() != ModuleImportPhase::kEvaluation) {
578 continue;
579 }
580 Handle<Module> requested_module(Cast<Module>(requested_modules->get(i)),
581 isolate);
582 if (!Module::FinishInstantiate(isolate, requested_module, stack, dfs_index,
583 zone)) {
584 return false;
585 }
586
587 DCHECK_NE(requested_module->status(), kEvaluating);
588 DCHECK_GE(requested_module->status(), kLinking);
590 // {requested_module} is instantiating iff it's on the {stack}.
591 (requested_module->status() == kLinking) ==
592 std::count_if(
593 stack->begin(), stack->end(),
594 [&](DirectHandle<Module> m) { return *m == *requested_module; }));
595
596 if (requested_module->status() == kLinking) {
597 // SyntheticModules go straight to kLinked so this must be a
598 // SourceTextModule
599 module->set_dfs_ancestor_index(std::min(
600 module->dfs_ancestor_index(),
601 Cast<SourceTextModule>(*requested_module)->dfs_ancestor_index()));
602 }
603 }
604
605 Handle<Script> script(module->GetScript(), isolate);
606 DirectHandle<SourceTextModuleInfo> module_info(module->info(), isolate);
607
608 // Resolve imports.
609 DirectHandle<FixedArray> regular_imports(module_info->regular_imports(),
610 isolate);
611 for (int i = 0, n = regular_imports->length(); i < n; ++i) {
613 Cast<SourceTextModuleInfoEntry>(regular_imports->get(i)), isolate);
614 Handle<String> name(Cast<String>(entry->import_name()), isolate);
615 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
616 ResolveSet resolve_set(zone);
618 if (!ResolveImport(isolate, module, name, entry->module_request(), loc,
619 true, &resolve_set)
620 .ToHandle(&cell)) {
621 return false;
622 }
623 module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
624 }
625
626 // Resolve indirect exports.
627 DirectHandle<FixedArray> special_exports(module_info->special_exports(),
628 isolate);
629 for (int i = 0, n = special_exports->length(); i < n; ++i) {
631 Cast<SourceTextModuleInfoEntry>(special_exports->get(i)), isolate);
632 Handle<Object> name(entry->export_name(), isolate);
633 if (IsUndefined(*name, isolate)) continue; // Star export.
634 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
635 ResolveSet resolve_set(zone);
636 if (ResolveExport(isolate, module, {}, Cast<String>(name), loc, true,
637 &resolve_set)
638 .is_null()) {
639 return false;
640 }
641 }
642
643 return MaybeTransitionComponent(isolate, module, stack, kLinked);
644}
645
648 Zone* zone,
649 UnorderedModuleSet* visited) {
650 DCHECK_GE(module->status(), Module::kLinking);
651
652 if (IsJSModuleNamespace(module->module_namespace())) return; // Shortcut.
653
654 bool cycle = !visited->insert(module).second;
655 if (cycle) return;
656 Handle<ObjectHashTable> exports(module->exports(), isolate);
657 UnorderedStringMap more_exports(zone);
658
659 // TODO(neis): Only allocate more_exports if there are star exports.
660 // Maybe split special_exports into indirect_exports and star_exports.
661
662 ReadOnlyRoots roots(isolate);
663 DirectHandle<FixedArray> special_exports(module->info()->special_exports(),
664 isolate);
665 for (int i = 0, n = special_exports->length(); i < n; ++i) {
667 Cast<SourceTextModuleInfoEntry>(special_exports->get(i)), isolate);
668 if (!IsUndefined(entry->export_name(), roots)) {
669 continue; // Indirect export.
670 }
671
672 DCHECK_EQ(Cast<ModuleRequest>(module->info()->module_requests()->get(
673 entry->module_request()))
674 ->phase(),
676 Handle<Module> requested_module(
677 Cast<Module>(module->requested_modules()->get(entry->module_request())),
678 isolate);
679
680 // Recurse.
681 if (IsSourceTextModule(*requested_module))
682 FetchStarExports(isolate, Cast<SourceTextModule>(requested_module), zone,
683 visited);
684
685 // Collect all of [requested_module]'s exports that must be added to
686 // [module]'s exports (i.e. to [exports]). We record these in
687 // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
688 // the name to undefined instead of a Cell.
689 DirectHandle<ObjectHashTable> requested_exports(requested_module->exports(),
690 isolate);
691 for (InternalIndex index : requested_exports->IterateEntries()) {
693 if (!requested_exports->ToKey(roots, index, &key)) continue;
695
696 if (name->Equals(roots.default_string())) continue;
697 if (!IsTheHole(exports->Lookup(name), roots)) continue;
698
699 Handle<Cell> cell(Cast<Cell>(requested_exports->ValueAt(index)), isolate);
700 auto insert_result = more_exports.insert(std::make_pair(name, cell));
701 if (!insert_result.second) {
702 auto it = insert_result.first;
703 if (*it->second == *cell || IsUndefined(*it->second, roots)) {
704 // We already recorded this mapping before, or the name is already
705 // known to be ambiguous. In either case, there's nothing to do.
706 } else {
707 DCHECK(IsCell(*it->second));
708 // Different star exports provide different cells for this name, hence
709 // mark the name as ambiguous.
710 it->second = isolate->factory()->undefined_value();
711 }
712 }
713 }
714 }
715
716 // Copy [more_exports] into [exports].
717 for (const auto& elem : more_exports) {
718 if (IsUndefined(*elem.second, isolate)) continue; // Ambiguous export.
719 DCHECK(!elem.first->Equals(ReadOnlyRoots(isolate).default_string()));
720 DCHECK(IsCell(*elem.second));
721 exports = ObjectHashTable::Put(exports, elem.first, elem.second);
722 }
723 module->set_exports(*exports);
724}
725
728 AvailableAncestorsSet* exec_list) {
729 // The spec algorithm is recursive. It is transformed to an equivalent
730 // iterative one here.
732 worklist.push(start);
733
734 while (!worklist.empty()) {
735 DirectHandle<SourceTextModule> module = worklist.top();
736 worklist.pop();
737
738 // 1. For each Module m of module.[[AsyncParentModules]], do
739 for (int i = module->AsyncParentModuleCount(); i-- > 0;) {
740 Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
741
742 // a. If execList does not contain m and
743 // m.[[CycleRoot]].[[EvaluationError]] is empty, then
744 if (m->GetCycleRoot(isolate)->status() != kErrored &&
745 exec_list->find(m) == exec_list->end()) {
746 // i. Assert: m.[[Status]] is EVALUATING-ASYNC.
747 // ii. Assert: m.[[EvaluationError]] is empty.
748 DCHECK_EQ(m->status(), kEvaluatingAsync);
749
750 // iii. Assert: m.[[AsyncEvaluation]] is true.
751 DCHECK(m->HasAsyncEvaluationOrdinal());
752
753 // iv. Assert: m.[[PendingAsyncDependencies]] > 0.
754 DCHECK(m->HasPendingAsyncDependencies());
755
756 // v. Set m.[[PendingAsyncDependencies]] to
757 // m.[[PendingAsyncDependencies]] - 1.
758 m->DecrementPendingAsyncDependencies();
759
760 // vi. If m.[[PendingAsyncDependencies]] = 0, then
761 if (!m->HasPendingAsyncDependencies()) {
762 // 1. Append m to execList.
763 exec_list->insert(m);
764
765 // 2. If m.[[HasTLA]] is false,
766 // perform ! GatherAvailableAncestors(m, execList).
767 if (!m->has_toplevel_await()) worklist.push(m);
768 }
769 }
770 }
771 }
772
773 // 2. Return UNUSED.
774}
775
778 int module_request) {
780 module->info()->module_requests()->get(module_request))
781 ->phase(),
783 Handle<Module> requested_module(
784 Cast<Module>(module->requested_modules()->get(module_request)), isolate);
785 return Module::GetModuleNamespace(isolate, requested_module);
786}
787
789 Isolate* isolate, DirectHandle<SourceTextModule> module) {
790 Handle<UnionOf<JSObject, Hole>> import_meta(module->import_meta(kAcquireLoad),
791 isolate);
792 if (IsTheHole(*import_meta, isolate)) {
793 if (!isolate->RunHostInitializeImportMetaObjectCallback(module).ToHandle(
794 &import_meta)) {
795 return {};
796 }
797 module->set_import_meta(*import_meta, kReleaseStore);
798 }
799 return Cast<JSObject>(import_meta);
800}
801
802// ES#sec-moduleevaluation
806 Tagged<Object> exception = isolate->exception();
807 // Step 9.
808 if (isolate->is_catchable_by_javascript(exception)) {
809 // a. For each Cyclic Module Record m in stack, do
810 for (DirectHandle<SourceTextModule> descendant : *stack) {
811 // i. Assert: m.[[Status]] is EVALUATING.
812 CHECK_EQ(descendant->status(), kEvaluating);
813 // ii. Set m.[[Status]] to EVALUATED.
814 // iii. Set m.[[EvaluationError]] to result.
815 descendant->RecordError(isolate, exception);
816 }
817 return true;
818 }
819 // If the exception was a termination exception, rejecting the promise
820 // would resume execution, and our API contract is to return an empty
821 // handle. The module's status should be set to kErrored and the
822 // exception field should be set to `null`.
823 RecordError(isolate, exception);
824 for (DirectHandle<SourceTextModule> descendant : *stack) {
825 descendant->RecordError(isolate, exception);
826 }
827 CHECK_EQ(status(), kErrored);
828 CHECK_EQ(this->exception(), *isolate->factory()->null_value());
829 return false;
830}
831
832// ES#sec-moduleevaluation
834 Isolate* isolate, Handle<SourceTextModule> module) {
835 CHECK(module->status() == kLinked || module->status() == kEvaluatingAsync ||
836 module->status() == kEvaluated);
837
838 // 5. Let stack be a new empty List.
839 Zone zone(isolate->allocator(), ZONE_NAME);
841 unsigned dfs_index = 0;
842
843 // 6. Let capability be ! NewPromiseCapability(%Promise%).
844 DirectHandle<JSPromise> capability = isolate->factory()->NewJSPromise();
845
846 // 7. Set module.[[TopLevelCapability]] to capability.
847 module->set_top_level_capability(*capability);
848 DCHECK(IsJSPromise(module->top_level_capability()));
849
850 // 8. Let result be InnerModuleEvaluation(module, stack, 0).
851 // 9. If result is an abrupt completion, then
852 v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
853 try_catch.SetVerbose(false);
854 try_catch.SetCaptureMessage(false);
855 // TODO(verwaest): Return a bool from InnerModuleEvaluation instead?
856 if (InnerModuleEvaluation(isolate, module, &stack, &dfs_index).is_null()) {
857 if (!module->MaybeHandleEvaluationException(isolate, &stack)) return {};
858 CHECK(try_catch.HasCaught());
859 // d. Perform ! Call(capability.[[Reject]], undefined,
860 // «result.[[Value]]»).
861 JSPromise::Reject(capability, direct_handle(module->exception(), isolate));
862 } else { // 10. Else,
863 // a. Assert: module.[[Status]] is either EVALUATING-ASYNC or EVALUATED.
864 CHECK_GE(module->status(), kEvaluatingAsync);
865
866 // c. If module.[[AsyncEvaluation]] is false, then
867 if (!module->HasAsyncEvaluationOrdinal()) {
868 // i. Assert: module.[[Status]] is EVALUATED.
869 DCHECK_EQ(module->status(), kEvaluated);
870
871 // ii. Perform ! Call(capability.[[Resolve]], undefined,
872 // «undefined»).
873 JSPromise::Resolve(capability, isolate->factory()->undefined_value())
874 .ToHandleChecked();
875 }
876
877 // d. Assert: stack is empty.
878 DCHECK(stack.empty());
879 }
880
881 // 11. Return capability.[[Promise]].
882 return capability;
883}
884
885// ES#sec-async-module-execution-fulfilled
887 Isolate* isolate, Handle<SourceTextModule> module) {
888 // 1. If module.[[Status]] is EVALUATED, then
889 if (module->status() == kErrored) {
890 // a. Assert: module.[[EvaluationError]] is not EMPTY.
891 DCHECK(!IsTheHole(module->exception(), isolate));
892 // b. Return UNUSED.
893 return Just(true);
894 }
895
896 // 2. Assert: module.[[Status]] is EVALUATING-ASYNC.
897 DCHECK_EQ(module->status(), kEvaluatingAsync);
898
899 // 3. Assert: module.[[AsyncEvaluation]] is true.
900 DCHECK(module->HasAsyncEvaluationOrdinal());
901
902 // 4. Assert: module.[[EvaluationError]] is EMPTY.
903 // (Done by step 2.)
904
905 // 5. Set module.[[AsyncEvaluation]] to false.
906 module->set_async_evaluation_ordinal(kAsyncEvaluateDidFinish);
907
908 // 6. Set module.[[Status]] to EVALUATED.
909 module->SetStatus(kEvaluated);
910
911 // 7. If module.[[TopLevelCapability]] is not EMPTY, then
912 if (!IsUndefined(module->top_level_capability(), isolate)) {
913 // a. Assert: module.[[CycleRoot]] is equal to module.
914 DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
915
916 // i. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined,
917 // «undefined»).
918 DirectHandle<JSPromise> capability(
919 Cast<JSPromise>(module->top_level_capability()), isolate);
920 JSPromise::Resolve(capability, isolate->factory()->undefined_value())
921 .ToHandleChecked();
922 }
923
924 // 8. Let execList be a new empty List.
925 Zone zone(isolate->allocator(), ZONE_NAME);
926 AvailableAncestorsSet exec_list(&zone);
927
928 // 9. Perform GatherAvailableAncestors(module, execList).
929 GatherAvailableAncestors(isolate, &zone, module, &exec_list);
930
931 // 10. Let sortedExecList be a List of elements that are the elements of
932 // execList, in the order in which they had their [[AsyncEvaluation]]
933 // fields set to true in InnerModuleEvaluation.
934 //
935 // This step is implemented by AvailableAncestorsSet, which is a set
936 // ordered on async_evaluation_ordinal.
937
938 // 11. Assert: All elements of sortedExecList have their [[AsyncEvaluation]]
939 // field set to true, [[PendingAsyncDependencies]] field set to 0 and
940 // [[EvaluationError]] field set to undefined.
941#ifdef DEBUG
942 for (DirectHandle<SourceTextModule> m : exec_list) {
943 DCHECK(m->HasAsyncEvaluationOrdinal());
944 DCHECK(!m->HasPendingAsyncDependencies());
945 DCHECK_NE(m->status(), kErrored);
946 }
947#endif
948
949 // 12. For each Module m of sortedExecList, do
950 for (DirectHandle<SourceTextModule> m : exec_list) {
951 if (m->status() == kErrored) { // a. If m.[[Status]] is EVALUATED, then
952 // i. Assert: m.[[EvaluationError]] is not EMPTY.
953 DCHECK(!IsTheHole(m->exception(), isolate));
954 } else if (m->has_toplevel_await()) { // b. Else if m.[[HasTLA]] is true,
955 // then
956 // i. Perform ExecuteAsyncModule(m).
957 //
958 // The execution may have been terminated and can not be resumed, so just
959 // raise the exception.
961 } else { // c. Else,
962 // i. Let result be m.ExecuteModule().
963 DirectHandle<Object> unused_result;
965 // ii. If result is an abrupt completion, then
966 if (!ExecuteModule(isolate, m, &exception).ToHandle(&unused_result)) {
967 // 1. Perform AsyncModuleExecutionRejected(m, result.[[Value]]).
968 AsyncModuleExecutionRejected(isolate, m, exception.ToHandleChecked());
969 } else { // iii. Else,
970 // 1. Set m.[[AsyncEvaluation]] to false.
971 m->set_async_evaluation_ordinal(kAsyncEvaluateDidFinish);
972
973 // 2. Set m.[[Status]] to EVALUATED.
974 m->SetStatus(kEvaluated);
975
976 // 3. If m.[[TopLevelCapability]] is not EMPTY, then
977 if (!IsUndefined(m->top_level_capability(), isolate)) {
978 // a. Assert: m.[[CycleRoot]] and m are the same Module Record.
979 DCHECK_EQ(*m->GetCycleRoot(isolate), *m);
980
981 // b. Perform ! Call(m.[[TopLevelCapability]].[[Resolve]], undefined,
982 // « undefined »).
983 DirectHandle<JSPromise> capability(
984 Cast<JSPromise>(m->top_level_capability()), isolate);
985 JSPromise::Resolve(capability, isolate->factory()->undefined_value())
986 .ToHandleChecked();
987 }
988 }
989 }
990 }
991
992 // Return UNUSED.
993 return Just(true);
994}
995
996// ES#sec-async-module-execution-rejected
999 DirectHandle<Object> exception) {
1000 // 1. If module.[[Status]] is EVALUATED, then
1001 if (module->status() == kErrored) {
1002 // a. Assert: module.[[EvaluationError]] is not empty.
1003 DCHECK(!IsTheHole(module->exception(), isolate));
1004 // b. Return UNUSED.
1005 return;
1006 }
1007
1008 DCHECK(isolate->is_catchable_by_javascript(*exception));
1009 // 2. Assert: module.[[Status]] is EVALUATING-ASYNC.
1010 CHECK_EQ(module->status(), kEvaluatingAsync);
1011 // 3. Assert: module.[[AsyncEvaluation]] is true.
1012 DCHECK(module->HasAsyncEvaluationOrdinal());
1013 // 4. Assert: module.[[EvaluationError]] is EMPTY.
1014 DCHECK(IsTheHole(module->exception(), isolate));
1015
1016 // 5. Set module.[[EvaluationError]] to ThrowCompletion(error).
1017 module->RecordError(isolate, *exception);
1018
1019 // 6. Set module.[[Status]] to EVALUATED.
1020 // (We have a status for kErrored, so don't set to kEvaluated.)
1021 module->set_async_evaluation_ordinal(kAsyncEvaluateDidFinish);
1022
1023 // 7. For each Cyclic Module Record m of module.[[AsyncParentModules]], do
1024 for (int i = 0; i < module->AsyncParentModuleCount(); i++) {
1025 // a. Perform AsyncModuleExecutionRejected(m, error).
1026 DirectHandle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
1027 AsyncModuleExecutionRejected(isolate, m, exception);
1028 }
1029
1030 // 8. If module.[[TopLevelCapability]] is not EMPTY, then
1031 if (!IsUndefined(module->top_level_capability(), isolate)) {
1032 // a. Assert: module.[[CycleRoot]] and module are the same Module Record.
1033 DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
1034
1035 // b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
1036 // undefined, «error»).
1037 DirectHandle<JSPromise> capability(
1038 Cast<JSPromise>(module->top_level_capability()), isolate);
1039 JSPromise::Reject(capability, exception);
1040 }
1041
1042 // 9. Return UNUSED.
1043}
1044
1045// static
1047 Isolate* isolate, DirectHandle<SourceTextModule> module) {
1048 // 1. Assert: module.[[Status]] is either EVALUATING or EVALUATING-ASYNC.
1049 CHECK(module->status() == kEvaluating ||
1050 module->status() == kEvaluatingAsync);
1051
1052 // 2. Assert: module.[[HasTLA]] is true.
1053 DCHECK(module->has_toplevel_await());
1054
1055 // 3. Let capability be ! NewPromiseCapability(%Promise%).
1056 DirectHandle<JSPromise> capability = isolate->factory()->NewJSPromise();
1057
1058 DirectHandle<Context> execute_async_module_context =
1059 isolate->factory()->NewBuiltinContext(
1060 isolate->native_context(),
1062 execute_async_module_context->set(ExecuteAsyncModuleContextSlots::kModule,
1063 *module);
1064
1065 // 4. Let fulfilledClosure be a new Abstract Closure with no parameters that
1066 // captures module and performs the following steps when called:
1067 // a. Perform AsyncModuleExecutionFulfilled(module).
1068 // b. Return undefined.
1069 // 5. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 0, "", « »).
1070 DirectHandle<JSFunction> on_fulfilled =
1072 isolate,
1073 isolate->factory()
1074 ->source_text_module_execute_async_module_fulfilled_sfi(),
1075 execute_async_module_context}
1076 .Build();
1077
1078 // 6. Let rejectedClosure be a new Abstract Closure with parameters (error)
1079 // that captures module and performs the following steps when called:
1080 // a. Perform AsyncModuleExecutionRejected(module, error).
1081 // b. Return undefined.
1082 // 7. Let onRejected be CreateBuiltinFunction(rejectedClosure, 0, "", « »).
1083 DirectHandle<JSFunction> on_rejected =
1085 isolate,
1086 isolate->factory()
1087 ->source_text_module_execute_async_module_rejected_sfi(),
1088 execute_async_module_context}
1089 .Build();
1090
1091 // 8. Perform ! PerformPromiseThen(capability.[[Promise]],
1092 // onFulfilled, onRejected).
1093 DirectHandle<Object> args[] = {on_fulfilled, on_rejected};
1094 if (V8_UNLIKELY(Execution::CallBuiltin(isolate, isolate->promise_then(),
1095 capability, base::VectorOf(args))
1096 .is_null())) {
1097 // TODO(349961173): We assume the builtin call can only fail with a
1098 // termination exception. If this check fails in the wild investigate why
1099 // the call fails. Otherwise turn this into a DCHECK in the future.
1100 CHECK(isolate->is_execution_terminating());
1101 return Nothing<bool>();
1102 }
1103
1104 // 9. Perform ! module.ExecuteModule(capability).
1105 // Note: In V8 we have broken module.ExecuteModule into
1106 // ExecuteModule for synchronous module execution and
1107 // InnerExecuteAsyncModule for asynchronous execution.
1109 InnerExecuteAsyncModule(isolate, module, capability);
1110 if (ret.is_null()) {
1111 // The evaluation of async module cannot throw a JavaScript observable
1112 // exception.
1113 DCHECK_IMPLIES(v8_flags.strict_termination_checks,
1114 isolate->is_execution_terminating());
1115 return Nothing<bool>();
1116 }
1117
1118 // 10. Return UNUSED.
1119 return Just<bool>(true);
1120}
1121
1123 Isolate* isolate, DirectHandle<SourceTextModule> module,
1124 DirectHandle<JSPromise> capability) {
1125 // If we have an async module, then it has an associated
1126 // JSAsyncFunctionObject, which we then evaluate with the passed in promise
1127 // capability.
1128 DirectHandle<JSAsyncFunctionObject> async_function_object(
1129 Cast<JSAsyncFunctionObject>(module->code()), isolate);
1130 async_function_object->set_promise(*capability);
1132 isolate->native_context()->async_module_evaluate_internal(), isolate);
1133 return Execution::TryCall(isolate, resume, async_function_object, {},
1135}
1136
1138 Isolate* isolate, DirectHandle<SourceTextModule> module,
1140 // Synchronous modules have an associated JSGeneratorObject.
1142 Cast<JSGeneratorObject>(module->code()), isolate);
1144 isolate->native_context()->generator_next_internal(), isolate);
1146
1147 if (!Execution::TryCall(isolate, resume, generator, {},
1150 .ToHandle(&result)) {
1151 return {};
1152 }
1153 DCHECK(
1154 Object::BooleanValue(Cast<JSIteratorResult>(*result)->done(), isolate));
1155 return direct_handle(Cast<JSIteratorResult>(*result)->value(), isolate);
1156}
1157
1159 Isolate* isolate, Handle<SourceTextModule> module,
1160 ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index) {
1162 int module_status = module->status();
1163 // InnerModuleEvaluation(module, stack, index)
1164
1165 // 2. If module.[[Status]] is either EVALUATING-ASYNC or EVALUATED, then
1166 if (module_status == kEvaluatingAsync || module_status == kEvaluating ||
1167 module_status == kEvaluated) {
1168 // a. If module.[[EvaluationError]] is undefined, return index.
1169 // (We return undefined instead)
1170 //
1171 // 3. If module.[[Status]] is EVALUATING, return index.
1172 // (Out of order)
1173 return isolate->factory()->undefined_value();
1174 } else if (module_status == kErrored) {
1175 // b. Otherwise return module.[[EvaluationError]].
1176 // (We throw on isolate and return a MaybeHandle<Object> instead)
1177 isolate->Throw(module->exception());
1179 }
1180
1181 // 4. Assert: module.[[Status]] is LINKED.
1182 CHECK_EQ(module_status, kLinked);
1183
1184 DirectHandle<FixedArray> module_requests;
1185 DirectHandle<FixedArray> requested_modules;
1186
1187 {
1189 Tagged<SourceTextModule> raw_module = *module;
1190 // 5. Set module.[[Status]] to EVALUATING.
1191 raw_module->SetStatus(kEvaluating);
1192
1193 // 6. Set module.[[DFSIndex]] to index.
1194 raw_module->set_dfs_index(*dfs_index);
1195
1196 // 7. Set module.[[DFSAncestorIndex]] to index.
1197 raw_module->set_dfs_ancestor_index(*dfs_index);
1198
1199 // 8. Set module.[[PendingAsyncDependencies]] to 0.
1200 DCHECK(!raw_module->HasPendingAsyncDependencies());
1201
1202 // 9. Set index to index + 1.
1203 (*dfs_index)++;
1204
1205 // 10. Append module to stack.
1206 stack->push_front(module);
1207
1208 // Recursion.
1209 module_requests =
1210 direct_handle(raw_module->info()->module_requests(), isolate);
1211 requested_modules = direct_handle(raw_module->requested_modules(), isolate);
1212 }
1213
1214 // 11. For each ModuleRequest Record required of module.[[RequestedModules]],
1215 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
1216 DirectHandle<ModuleRequest> module_request(
1217 Cast<ModuleRequest>(module_requests->get(i)), isolate);
1218 if (module_request->phase() != ModuleImportPhase::kEvaluation) {
1219 continue;
1220 }
1221 // b. If requiredModule.[[Phase]] is evaluation, then
1222 Handle<Module> requested_module(Cast<Module>(requested_modules->get(i)),
1223 isolate);
1224 // c. If requiredModule is a Cyclic Module Record, then
1225 if (IsSourceTextModule(*requested_module)) {
1226 // b. Set index to ? InnerModuleEvaluation(requiredModule, stack, index).
1227 // (Out of order because InnerModuleEvaluation is type-driven.)
1228 Handle<SourceTextModule> required_module(
1229 Cast<SourceTextModule>(*requested_module), isolate);
1231 isolate,
1232 InnerModuleEvaluation(isolate, required_module, stack, dfs_index));
1233 int required_module_status = required_module->status();
1234
1235 // i. Assert: requiredModule.[[Status]] is one of EVALUATING,
1236 // EVALUATING-ASYNC, or EVALUATED.
1237 // (We also assert the module cannot be errored, because if it was
1238 // we would have already returned from InnerModuleEvaluation)
1239 CHECK_GE(required_module_status, kEvaluating);
1240 CHECK_NE(required_module_status, kErrored);
1241
1242 // ii. Assert: requiredModule.[[Status]] is EVALUATING if and only if
1243 // requiredModule is in stack.
1244 SLOW_DCHECK((requested_module->status() == kEvaluating) ==
1245 std::count_if(stack->begin(), stack->end(),
1246 [&](DirectHandle<Module> m) {
1247 return *m == *requested_module;
1248 }));
1249
1250 // iii. If requiredModule.[[Status]] is EVALUATING, then
1251 if (required_module_status == kEvaluating) {
1252 // 1. Set module.[[DFSAncestorIndex]] to
1253 // min(module.[[DFSAncestorIndex]],
1254 // requiredModule.[[DFSAncestorIndex]]).
1255 module->set_dfs_ancestor_index(
1256 std::min(module->dfs_ancestor_index(),
1257 required_module->dfs_ancestor_index()));
1258 } else { // iv. Else,
1259 // 1. Set requiredModule to requiredModule.[[CycleRoot]].
1260 required_module = required_module->GetCycleRoot(isolate);
1261 required_module_status = required_module->status();
1262
1263 // 2. Assert: requiredModule.[[Status]] is either EVALUATING-ASYNC or
1264 // EVALUATED.
1265 CHECK_GE(required_module_status, kEvaluatingAsync);
1266
1267 // 3. If requiredModule.[[EvaluationError]] is not EMPTY,
1268 // return ? module.[[EvaluationError]].
1269
1270 // (If there was an exception on the original required module we would
1271 // have already returned. This check handles the case where the
1272 // AsyncCycleRoot has an error. Instead of returning the exception, we
1273 // throw on isolate and return a MaybeHandle<Object>.)
1274 if (required_module_status == kErrored) {
1275 isolate->Throw(required_module->exception());
1277 }
1278 }
1279 // v. If requiredModule.[[AsyncEvaluation]] is true, then
1280 if (required_module->HasAsyncEvaluationOrdinal()) {
1281 // 1. Set module.[[PendingAsyncDependencies]] to
1282 // module.[[PendingAsyncDependencies]] + 1.
1283 module->IncrementPendingAsyncDependencies();
1284
1285 // 2. Append module to requiredModule.[[AsyncParentModules]].
1286 AddAsyncParentModule(isolate, required_module, module);
1287 }
1288 } else {
1289 // b. Set index to ? InnerModuleEvaluation(requiredModule, stack, index).
1290 // (Out of order because InnerModuleEvaluation is type-driven.)
1291 RETURN_ON_EXCEPTION(isolate, Module::Evaluate(isolate, requested_module));
1292 }
1293 }
1294
1295 // The spec returns the module index for proper numbering of dependencies.
1296 // However, we pass the module index by pointer instead.
1297 //
1298 // Before async modules v8 returned the value result from calling next
1299 // on the module's implicit iterator. We preserve this behavior for
1300 // synchronous modules, but return undefined for AsyncModules.
1301 DirectHandle<Object> result = isolate->factory()->undefined_value();
1302
1303 // 12. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] is
1304 // true, then
1305 if (module->HasPendingAsyncDependencies() || module->has_toplevel_await()) {
1306 // a. Assert: module.[[AsyncEvaluation]] is false and was never previously
1307 // set to true.
1308 DCHECK_EQ(module->async_evaluation_ordinal(), kNotAsyncEvaluated);
1309
1310 // b. Set module.[[AsyncEvaluation]] to true.
1311 // c. NOTE: The order in which module records have their [[AsyncEvaluation]]
1312 // fields transition to true is significant.
1313 module->set_async_evaluation_ordinal(
1314 isolate->NextModuleAsyncEvaluationOrdinal());
1315
1316 // c. If module.[[PendingAsyncDependencies]] = 0, perform
1317 // ExecuteAsyncModule(module).
1318 // The execution may have been terminated and can not be resumed, so just
1319 // raise the exception.
1320 if (!module->HasPendingAsyncDependencies()) {
1323 }
1324 } else { // 13. Else,
1325 // a. Perform ? module.ExecuteModule().
1326 MaybeDirectHandle<Object> exception;
1327 DirectHandle<Object> maybe_result;
1328 if (!ExecuteModule(isolate, module, &exception).ToHandle(&maybe_result)) {
1329 if (!isolate->is_execution_terminating()) {
1330 isolate->Throw(*exception.ToHandleChecked());
1331 }
1332 return maybe_result;
1333 }
1334 }
1335
1336 CHECK(MaybeTransitionComponent(isolate, module, stack, kEvaluated));
1337 return result;
1338}
1339
1342 Factory* factory = isolate->factory();
1343
1344 DCHECK(IsTheHole(module->import_meta(kAcquireLoad), isolate));
1345
1346 DirectHandle<FixedArray> regular_exports =
1347 factory->NewFixedArray(module->regular_exports()->length());
1348 DirectHandle<FixedArray> regular_imports =
1349 factory->NewFixedArray(module->regular_imports()->length());
1350 DirectHandle<FixedArray> requested_modules =
1351 factory->NewFixedArray(module->requested_modules()->length());
1352
1354 Tagged<SourceTextModule> raw_module = *module;
1355 if (raw_module->status() == kLinking) {
1356 raw_module->set_code(Cast<JSFunction>(raw_module->code())->shared());
1357 }
1358 raw_module->set_regular_exports(*regular_exports);
1359 raw_module->set_regular_imports(*regular_imports);
1360 raw_module->set_requested_modules(*requested_modules);
1361 raw_module->set_dfs_index(-1);
1362 raw_module->set_dfs_ancestor_index(-1);
1363}
1364
1365std::pair<DirectHandleVector<SourceTextModule>,
1368 Zone zone(isolate->allocator(), ZONE_NAME);
1369 UnorderedModuleSet visited(&zone);
1370 DirectHandleVector<SourceTextModule> stalled_modules(isolate);
1371 DirectHandleVector<JSMessageObject> messages(isolate);
1372 InnerGetStalledTopLevelAwaitModule(isolate, &visited, &stalled_modules);
1373 size_t stalled_modules_size = stalled_modules.size();
1374 if (stalled_modules_size == 0) return {stalled_modules, messages};
1375
1376 messages.reserve(stalled_modules_size);
1377 for (DirectHandle<SourceTextModule> found : stalled_modules) {
1378 CHECK(IsJSGeneratorObject(found->code()));
1380 isolate);
1381 Handle<SharedFunctionInfo> shared(found->GetSharedFunctionInfo(), isolate);
1382 Handle<Object> script(shared->script(), isolate);
1383 MessageLocation location =
1384 MessageLocation(Cast<Script>(script), shared, code->code_offset());
1386 isolate, MessageTemplate::kTopLevelAwaitStalled, &location,
1387 isolate->factory()->null_value());
1388 messages.push_back(message);
1389 }
1390 return {stalled_modules, messages};
1391}
1392
1394 Isolate* isolate, UnorderedModuleSet* visited,
1397 // If it's a module that is waiting for no other modules but itself,
1398 // it's what we are looking for. Add it to the results.
1401 result->push_back(direct_handle(*this, isolate));
1402 return;
1403 }
1404 // The module isn't what we are looking for, continue looking in the graph.
1405 Tagged<FixedArray> requests = info()->module_requests();
1406 Tagged<FixedArray> requested = requested_modules();
1407 int length = requested->length();
1408 for (int i = 0; i < length; ++i) {
1409 Tagged<ModuleRequest> request = Cast<ModuleRequest>(requests->get(i));
1410 if (request->phase() != ModuleImportPhase::kEvaluation) {
1411 continue;
1412 }
1413 Tagged<Module> requested_module = Cast<Module>(requested->get(i));
1414 if (IsSourceTextModule(requested_module) &&
1415 visited->insert(handle(requested_module, isolate)).second) {
1416 Tagged<SourceTextModule> source_text_module =
1417 Cast<SourceTextModule>(requested_module);
1418 source_text_module->InnerGetStalledTopLevelAwaitModule(isolate, visited,
1419 result);
1420 }
1421 }
1422}
1423
1424} // namespace internal
1425} // namespace v8
#define SLOW_DCHECK(condition)
Definition checks.h:21
Local< Value > GetModuleNamespace()
Definition api.cc:2174
void SetVerbose(bool value)
Definition api.cc:2856
void SetCaptureMessage(bool value)
Definition api.cc:2860
bool HasCaught() const
Definition api.cc:2781
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
size_t size() const noexcept
Definition handles.h:900
static V8_EXPORT_PRIVATE MaybeDirectHandle< Object > TryCall(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args, MessageHandling message_handling, MaybeDirectHandle< Object > *exception_out)
Definition execution.cc:587
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:523
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > CallBuiltin(Isolate *isolate, DirectHandle< JSFunction > builtin, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:545
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
V8_WARN_UNUSED_RESULT Handle< JSFunction > Build()
Definition factory.cc:4732
V8_INLINE bool is_null() const
Definition handles.h:69
static Handle< Object > Reject(DirectHandle< JSPromise > promise, DirectHandle< Object > reason, bool debug_event=true)
Definition objects.cc:5069
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Resolve(DirectHandle< JSPromise > promise, DirectHandle< Object > resolution)
Definition objects.cc:5109
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
V8_INLINE bool is_null() const
static V8_EXPORT_PRIVATE Handle< JSMessageObject > MakeMessageObject(Isolate *isolate, MessageTemplate type, const MessageLocation *location, DirectHandle< Object > argument, DirectHandle< StackTraceInfo > stack_trace=DirectHandle< StackTraceInfo >::null())
Definition messages.cc:77
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Evaluate(Isolate *isolate, Handle< Module > module)
Definition module.cc:272
static V8_WARN_UNUSED_RESULT bool FinishInstantiate(Isolate *isolate, Handle< Module > module, ZoneForwardList< Handle< SourceTextModule > > *stack, unsigned *dfs_index, Zone *zone)
Definition module.cc:255
static V8_WARN_UNUSED_RESULT MaybeHandle< Cell > ResolveExport(Isolate *isolate, Handle< Module > module, DirectHandle< String > module_specifier, Handle< String > export_name, MessageLocation loc, bool must_resolve, ResolveSet *resolve_set)
Definition module.cc:187
static V8_WARN_UNUSED_RESULT bool PrepareInstantiate(Isolate *isolate, DirectHandle< Module > module, v8::Local< v8::Context > context, v8::Module::ResolveModuleCallback module_callback, v8::Module::ResolveSourceCallback source_callback)
Definition module.cc:234
static V8_EXPORT_PRIVATE bool BooleanValue(Tagged< Object > obj, IsolateT *isolate)
static CellIndexKind GetCellIndexKind(int cell_index)
Definition modules.cc:279
Tagged< Script > GetScript() const
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > InnerExecuteAsyncModule(Isolate *isolate, DirectHandle< SourceTextModule > module, DirectHandle< JSPromise > capability)
static void CreateExport(Isolate *isolate, DirectHandle< SourceTextModule > module, int cell_index, DirectHandle< FixedArray > names)
static V8_WARN_UNUSED_RESULT bool MaybeTransitionComponent(Isolate *isolate, DirectHandle< SourceTextModule > module, ZoneForwardList< Handle< SourceTextModule > > *stack, Status new_status)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Evaluate(Isolate *isolate, Handle< SourceTextModule > module)
static void CreateIndirectExport(Isolate *isolate, DirectHandle< SourceTextModule > module, DirectHandle< String > name, DirectHandle< SourceTextModuleInfoEntry > entry)
static void AddAsyncParentModule(Isolate *isolate, DirectHandle< SourceTextModule > module, DirectHandle< SourceTextModule > parent)
Definition module-inl.h:126
Tagged< Cell > GetCell(int cell_index)
static constexpr unsigned kAsyncEvaluateDidFinish
static V8_WARN_UNUSED_RESULT MaybeHandle< Cell > ResolveExportUsingStarExports(Isolate *isolate, DirectHandle< SourceTextModule > module, DirectHandle< String > module_specifier, Handle< String > export_name, MessageLocation loc, bool must_resolve, ResolveSet *resolve_set)
static V8_EXPORT_PRIVATE MaybeHandle< JSObject > GetImportMeta(Isolate *isolate, DirectHandle< SourceTextModule > module)
V8_EXPORT_PRIVATE std::pair< DirectHandleVector< SourceTextModule >, DirectHandleVector< JSMessageObject > > GetStalledTopLevelAwaitMessages(Isolate *isolate)
static DirectHandle< JSModuleNamespace > GetModuleNamespace(Isolate *isolate, DirectHandle< SourceTextModule > module, int module_request)
static V8_WARN_UNUSED_RESULT bool RunInitializationCode(Isolate *isolate, DirectHandle< SourceTextModule > module)
static void FetchStarExports(Isolate *isolate, Handle< SourceTextModule > module, Zone *zone, UnorderedModuleSet *visited)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > InnerModuleEvaluation(Isolate *isolate, Handle< SourceTextModule > module, ZoneForwardList< Handle< SourceTextModule > > *stack, unsigned *dfs_index)
static V8_WARN_UNUSED_RESULT Maybe< bool > ExecuteAsyncModule(Isolate *isolate, DirectHandle< SourceTextModule > module)
bool MaybeHandleEvaluationException(Isolate *isolate, ZoneForwardList< Handle< SourceTextModule > > *stack)
static V8_WARN_UNUSED_RESULT bool PrepareInstantiate(Isolate *isolate, DirectHandle< SourceTextModule > module, v8::Local< v8::Context > context, v8::Module::ResolveModuleCallback module_callback, v8::Module::ResolveSourceCallback source_callback)
bool HasAsyncEvaluationOrdinal() const
Definition module-inl.h:147
static void StoreVariable(DirectHandle< SourceTextModule > module, int cell_index, DirectHandle< Object > value)
static V8_WARN_UNUSED_RESULT MaybeHandle< Cell > ResolveExport(Isolate *isolate, Handle< SourceTextModule > module, DirectHandle< String > module_specifier, Handle< String > export_name, MessageLocation loc, bool must_resolve, ResolveSet *resolve_set)
static V8_WARN_UNUSED_RESULT bool FinishInstantiate(Isolate *isolate, Handle< SourceTextModule > module, ZoneForwardList< Handle< SourceTextModule > > *stack, unsigned *dfs_index, Zone *zone)
static V8_WARN_UNUSED_RESULT MaybeHandle< Cell > ResolveImport(Isolate *isolate, DirectHandle< SourceTextModule > module, Handle< String > name, int module_request_index, MessageLocation loc, bool must_resolve, ResolveSet *resolve_set)
V8_EXPORT_PRIVATE void InnerGetStalledTopLevelAwaitModule(Isolate *isolate, UnorderedModuleSet *visited, DirectHandleVector< SourceTextModule > *result)
static void Reset(Isolate *isolate, DirectHandle< SourceTextModule > module)
static void GatherAvailableAncestors(Isolate *isolate, Zone *zone, Handle< SourceTextModule > start, AvailableAncestorsSet *exec_list)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > ExecuteModule(Isolate *isolate, DirectHandle< SourceTextModule > module, MaybeDirectHandle< Object > *exception_out)
static void AsyncModuleExecutionRejected(Isolate *isolate, DirectHandle< SourceTextModule > module, DirectHandle< Object > exception)
static Handle< Object > LoadVariable(Isolate *isolate, DirectHandle< SourceTextModule > module, int cell_index)
NEVER_READ_ONLY_SPACE Tagged< SharedFunctionInfo > GetSharedFunctionInfo() const
static int ImportIndex(int cell_index)
static Maybe< bool > AsyncModuleExecutionFulfilled(Isolate *isolate, Handle< SourceTextModule > module)
Tagged< SourceTextModuleInfo > info() const
Definition module-inl.h:60
static constexpr unsigned kNotAsyncEvaluated
static int ExportIndex(int cell_index)
T * New(Args &&... args)
Definition zone.h:114
Handle< Code > code
int start
#define RETURN_ON_EXCEPTION(isolate, call)
Definition isolate.h:395
#define STACK_CHECK(isolate, result_value)
Definition isolate.h:3067
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
MaybeDirectHandle< Object > * exception_out
Definition execution.cc:80
Isolate * isolate
TNode< Object > receiver
SharedFunctionInfoRef shared
double second
ZoneVector< RpoNumber > & result
ZoneStack< RpoNumber > & stack
int m
Definition mul-fft.cc:294
STL namespace.
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
V8_EXPORT_PRIVATE FlagValues v8_flags
kInterpreterTrampolineOffset script
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Maybe< T > Nothing()
Definition v8-maybe.h:112
bool ToLocal(v8::internal::MaybeDirectHandle< v8::internal::Object > maybe, Local< T > *local)
Definition api.h:303
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_GE(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_NE(lhs, rhs)
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
bool operator()(DirectHandle< SourceTextModule > lhs, DirectHandle< SourceTextModule > rhs) const
V8_INLINE bool operator()(DirectHandle< String > lhs, DirectHandle< String > rhs) const
V8_INLINE size_t operator()(DirectHandle< String > string) const
#define V8_INLINE
Definition v8config.h:500
#define V8_UNLIKELY(condition)
Definition v8config.h:660
#define ZONE_NAME
Definition zone.h:22