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
5 #include "src/objects/source-text-module.h"
6
7 #include "src/api/api-inl.h"
8 #include "src/ast/modules.h"
9 #include "src/builtins/accessors.h"
10 #include "src/common/assert-scope.h"
11 #include "src/objects/js-generator-inl.h"
12 #include "src/objects/module-inl.h"
13 #include "src/objects/objects-inl.h"
14 #include "src/objects/shared-function-info.h"
15 #include "src/utils/ostreams.h"
16
17 namespace v8 {
18 namespace internal {
19
20 struct StringHandleHash {
operator ()v8::internal::StringHandleHash21 V8_INLINE size_t operator()(Handle<String> string) const {
22 return string->EnsureHash();
23 }
24 };
25
26 struct StringHandleEqual {
operator ()v8::internal::StringHandleEqual27 V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
28 return lhs->Equals(*rhs);
29 }
30 };
31
32 class UnorderedStringSet
33 : public std::unordered_set<Handle<String>, StringHandleHash,
34 StringHandleEqual,
35 ZoneAllocator<Handle<String>>> {
36 public:
UnorderedStringSet(Zone * zone)37 explicit UnorderedStringSet(Zone* zone)
38 : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
39 ZoneAllocator<Handle<String>>>(
40 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
41 ZoneAllocator<Handle<String>>(zone)) {}
42 };
43
44 class UnorderedStringMap
45 : public std::unordered_map<
46 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
47 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> {
48 public:
UnorderedStringMap(Zone * zone)49 explicit UnorderedStringMap(Zone* zone)
50 : std::unordered_map<
51 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
52 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>>(
53 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
54 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>(
55 zone)) {}
56 };
57
58 class Module::ResolveSet
59 : public std::unordered_map<
60 Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
61 ModuleHandleEqual,
62 ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> {
63 public:
ResolveSet(Zone * zone)64 explicit ResolveSet(Zone* zone)
65 : std::unordered_map<Handle<Module>, UnorderedStringSet*,
66 ModuleHandleHash, ModuleHandleEqual,
67 ZoneAllocator<std::pair<const Handle<Module>,
68 UnorderedStringSet*>>>(
69 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
70 ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>(
71 zone)),
72 zone_(zone) {}
73
zone() const74 Zone* zone() const { return zone_; }
75
76 private:
77 Zone* zone_;
78 };
79
80 struct SourceTextModule::AsyncEvaluatingOrdinalCompare {
operator ()v8::internal::SourceTextModule::AsyncEvaluatingOrdinalCompare81 bool operator()(Handle<SourceTextModule> lhs,
82 Handle<SourceTextModule> rhs) const {
83 DCHECK(lhs->IsAsyncEvaluating());
84 DCHECK(rhs->IsAsyncEvaluating());
85 return lhs->async_evaluating_ordinal() < rhs->async_evaluating_ordinal();
86 }
87 };
88
GetSharedFunctionInfo() const89 SharedFunctionInfo SourceTextModule::GetSharedFunctionInfo() const {
90 DisallowGarbageCollection no_gc;
91 switch (status()) {
92 case kUnlinked:
93 case kPreLinking:
94 return SharedFunctionInfo::cast(code());
95 case kLinking:
96 return JSFunction::cast(code()).shared();
97 case kLinked:
98 case kEvaluating:
99 case kEvaluatingAsync:
100 case kEvaluated:
101 return JSGeneratorObject::cast(code()).function().shared();
102 case kErrored:
103 return SharedFunctionInfo::cast(code());
104 }
105 UNREACHABLE();
106 }
107
GetScript() const108 Script SourceTextModule::GetScript() const {
109 DisallowGarbageCollection no_gc;
110 return Script::cast(GetSharedFunctionInfo().script());
111 }
112
ExportIndex(int cell_index)113 int SourceTextModule::ExportIndex(int cell_index) {
114 DCHECK_EQ(SourceTextModuleDescriptor::GetCellIndexKind(cell_index),
115 SourceTextModuleDescriptor::kExport);
116 return cell_index - 1;
117 }
118
ImportIndex(int cell_index)119 int SourceTextModule::ImportIndex(int cell_index) {
120 DCHECK_EQ(SourceTextModuleDescriptor::GetCellIndexKind(cell_index),
121 SourceTextModuleDescriptor::kImport);
122 return -cell_index - 1;
123 }
124
CreateIndirectExport(Isolate * isolate,Handle<SourceTextModule> module,Handle<String> name,Handle<SourceTextModuleInfoEntry> entry)125 void SourceTextModule::CreateIndirectExport(
126 Isolate* isolate, Handle<SourceTextModule> module, Handle<String> name,
127 Handle<SourceTextModuleInfoEntry> entry) {
128 Handle<ObjectHashTable> exports(module->exports(), isolate);
129 DCHECK(exports->Lookup(name).IsTheHole(isolate));
130 exports = ObjectHashTable::Put(exports, name, entry);
131 module->set_exports(*exports);
132 }
133
CreateExport(Isolate * isolate,Handle<SourceTextModule> module,int cell_index,Handle<FixedArray> names)134 void SourceTextModule::CreateExport(Isolate* isolate,
135 Handle<SourceTextModule> module,
136 int cell_index, Handle<FixedArray> names) {
137 DCHECK_LT(0, names->length());
138 Handle<Cell> cell =
139 isolate->factory()->NewCell(isolate->factory()->undefined_value());
140 module->regular_exports().set(ExportIndex(cell_index), *cell);
141
142 Handle<ObjectHashTable> exports(module->exports(), isolate);
143 for (int i = 0, n = names->length(); i < n; ++i) {
144 Handle<String> name(String::cast(names->get(i)), isolate);
145 DCHECK(exports->Lookup(name).IsTheHole(isolate));
146 exports = ObjectHashTable::Put(exports, name, cell);
147 }
148 module->set_exports(*exports);
149 }
150
GetCell(int cell_index)151 Cell SourceTextModule::GetCell(int cell_index) {
152 DisallowGarbageCollection no_gc;
153 Object cell;
154 switch (SourceTextModuleDescriptor::GetCellIndexKind(cell_index)) {
155 case SourceTextModuleDescriptor::kImport:
156 cell = regular_imports().get(ImportIndex(cell_index));
157 break;
158 case SourceTextModuleDescriptor::kExport:
159 cell = regular_exports().get(ExportIndex(cell_index));
160 break;
161 case SourceTextModuleDescriptor::kInvalid:
162 UNREACHABLE();
163 }
164 return Cell::cast(cell);
165 }
166
LoadVariable(Isolate * isolate,Handle<SourceTextModule> module,int cell_index)167 Handle<Object> SourceTextModule::LoadVariable(Isolate* isolate,
168 Handle<SourceTextModule> module,
169 int cell_index) {
170 return handle(module->GetCell(cell_index).value(), isolate);
171 }
172
StoreVariable(Handle<SourceTextModule> module,int cell_index,Handle<Object> value)173 void SourceTextModule::StoreVariable(Handle<SourceTextModule> module,
174 int cell_index, Handle<Object> value) {
175 DisallowGarbageCollection no_gc;
176 DCHECK_EQ(SourceTextModuleDescriptor::GetCellIndexKind(cell_index),
177 SourceTextModuleDescriptor::kExport);
178 module->GetCell(cell_index).set_value(*value);
179 }
180
ResolveExport(Isolate * isolate,Handle<SourceTextModule> module,Handle<String> module_specifier,Handle<String> export_name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)181 MaybeHandle<Cell> SourceTextModule::ResolveExport(
182 Isolate* isolate, Handle<SourceTextModule> module,
183 Handle<String> module_specifier, Handle<String> export_name,
184 MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) {
185 Handle<Object> object(module->exports().Lookup(export_name), isolate);
186 if (object->IsCell()) {
187 // Already resolved (e.g. because it's a local export).
188 return Handle<Cell>::cast(object);
189 }
190
191 // Check for cycle before recursing.
192 {
193 // Attempt insertion with a null string set.
194 auto result = resolve_set->insert({module, nullptr});
195 UnorderedStringSet*& name_set = result.first->second;
196 if (result.second) {
197 // |module| wasn't in the map previously, so allocate a new name set.
198 Zone* zone = resolve_set->zone();
199 name_set = zone->New<UnorderedStringSet>(zone);
200 } else if (name_set->count(export_name)) {
201 // Cycle detected.
202 if (must_resolve) {
203 return isolate->ThrowAt<Cell>(
204 isolate->factory()->NewSyntaxError(
205 MessageTemplate::kCyclicModuleDependency, export_name,
206 module_specifier),
207 &loc);
208 }
209 return MaybeHandle<Cell>();
210 }
211 name_set->insert(export_name);
212 }
213
214 if (object->IsSourceTextModuleInfoEntry()) {
215 // Not yet resolved indirect export.
216 Handle<SourceTextModuleInfoEntry> entry =
217 Handle<SourceTextModuleInfoEntry>::cast(object);
218 Handle<String> import_name(String::cast(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_pending_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(exports->Lookup(export_name).IsSourceTextModuleInfoEntry());
234
235 exports = ObjectHashTable::Put(exports, export_name, cell);
236 module->set_exports(*exports);
237 return cell;
238 }
239
240 DCHECK(object->IsTheHole(isolate));
241 return SourceTextModule::ResolveExportUsingStarExports(
242 isolate, module, module_specifier, export_name, loc, must_resolve,
243 resolve_set);
244 }
245
ResolveImport(Isolate * isolate,Handle<SourceTextModule> module,Handle<String> name,int module_request_index,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)246 MaybeHandle<Cell> SourceTextModule::ResolveImport(
247 Isolate* isolate, Handle<SourceTextModule> module, Handle<String> name,
248 int module_request_index, MessageLocation loc, bool must_resolve,
249 Module::ResolveSet* resolve_set) {
250 Handle<Module> requested_module(
251 Module::cast(module->requested_modules().get(module_request_index)),
252 isolate);
253 Handle<ModuleRequest> module_request(
254 ModuleRequest::cast(
255 module->info().module_requests().get(module_request_index)),
256 isolate);
257 Handle<String> module_specifier(String::cast(module_request->specifier()),
258 isolate);
259 MaybeHandle<Cell> result =
260 Module::ResolveExport(isolate, requested_module, module_specifier, name,
261 loc, must_resolve, resolve_set);
262 DCHECK_IMPLIES(isolate->has_pending_exception(), result.is_null());
263 return result;
264 }
265
ResolveExportUsingStarExports(Isolate * isolate,Handle<SourceTextModule> module,Handle<String> module_specifier,Handle<String> export_name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)266 MaybeHandle<Cell> SourceTextModule::ResolveExportUsingStarExports(
267 Isolate* isolate, Handle<SourceTextModule> module,
268 Handle<String> module_specifier, Handle<String> export_name,
269 MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) {
270 if (!export_name->Equals(ReadOnlyRoots(isolate).default_string())) {
271 // Go through all star exports looking for the given name. If multiple star
272 // exports provide the name, make sure they all map it to the same cell.
273 Handle<Cell> unique_cell;
274 Handle<FixedArray> special_exports(module->info().special_exports(),
275 isolate);
276 for (int i = 0, n = special_exports->length(); i < n; ++i) {
277 i::Handle<i::SourceTextModuleInfoEntry> entry(
278 i::SourceTextModuleInfoEntry::cast(special_exports->get(i)), isolate);
279 if (!entry->export_name().IsUndefined(isolate)) {
280 continue; // Indirect export.
281 }
282
283 Handle<Script> script(module->GetScript(), isolate);
284 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
285
286 Handle<Cell> cell;
287 if (ResolveImport(isolate, module, export_name, entry->module_request(),
288 new_loc, false, resolve_set)
289 .ToHandle(&cell)) {
290 if (unique_cell.is_null()) unique_cell = cell;
291 if (*unique_cell != *cell) {
292 return isolate->ThrowAt<Cell>(isolate->factory()->NewSyntaxError(
293 MessageTemplate::kAmbiguousExport,
294 module_specifier, export_name),
295 &loc);
296 }
297 } else if (isolate->has_pending_exception()) {
298 return MaybeHandle<Cell>();
299 }
300 }
301
302 if (!unique_cell.is_null()) {
303 // Found a unique star export for this name.
304 Handle<ObjectHashTable> exports(module->exports(), isolate);
305 DCHECK(exports->Lookup(export_name).IsTheHole(isolate));
306 exports = ObjectHashTable::Put(exports, export_name, unique_cell);
307 module->set_exports(*exports);
308 return unique_cell;
309 }
310 }
311
312 // Unresolvable.
313 if (must_resolve) {
314 return isolate->ThrowAt<Cell>(
315 isolate->factory()->NewSyntaxError(MessageTemplate::kUnresolvableExport,
316 module_specifier, export_name),
317 &loc);
318 }
319 return MaybeHandle<Cell>();
320 }
321
PrepareInstantiate(Isolate * isolate,Handle<SourceTextModule> module,v8::Local<v8::Context> context,v8::Module::ResolveModuleCallback callback,Module::DeprecatedResolveCallback callback_without_import_assertions)322 bool SourceTextModule::PrepareInstantiate(
323 Isolate* isolate, Handle<SourceTextModule> module,
324 v8::Local<v8::Context> context, v8::Module::ResolveModuleCallback callback,
325 Module::DeprecatedResolveCallback callback_without_import_assertions) {
326 DCHECK_EQ(callback != nullptr, callback_without_import_assertions == nullptr);
327 // Obtain requested modules.
328 Handle<SourceTextModuleInfo> module_info(module->info(), isolate);
329 Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
330 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
331 for (int i = 0, length = module_requests->length(); i < length; ++i) {
332 Handle<ModuleRequest> module_request(
333 ModuleRequest::cast(module_requests->get(i)), isolate);
334 Handle<String> specifier(module_request->specifier(), isolate);
335 v8::Local<v8::Module> api_requested_module;
336 if (callback) {
337 Handle<FixedArray> import_assertions(module_request->import_assertions(),
338 isolate);
339 if (!callback(context, v8::Utils::ToLocal(specifier),
340 v8::Utils::FixedArrayToLocal(import_assertions),
341 v8::Utils::ToLocal(Handle<Module>::cast(module)))
342 .ToLocal(&api_requested_module)) {
343 isolate->PromoteScheduledException();
344 return false;
345 }
346 } else {
347 if (!callback_without_import_assertions(
348 context, v8::Utils::ToLocal(specifier),
349 v8::Utils::ToLocal(Handle<Module>::cast(module)))
350 .ToLocal(&api_requested_module)) {
351 isolate->PromoteScheduledException();
352 return false;
353 }
354 }
355 Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
356 requested_modules->set(i, *requested_module);
357 }
358
359 // Recurse.
360 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
361 Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
362 isolate);
363 if (!Module::PrepareInstantiate(isolate, requested_module, context,
364 callback,
365 callback_without_import_assertions)) {
366 return false;
367 }
368 }
369
370 // Set up local exports.
371 // TODO(neis): Create regular_exports array here instead of in factory method?
372 for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
373 int cell_index = module_info->RegularExportCellIndex(i);
374 Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
375 isolate);
376 CreateExport(isolate, module, cell_index, export_names);
377 }
378
379 // Partially set up indirect exports.
380 // For each indirect export, we create the appropriate slot in the export
381 // table and store its SourceTextModuleInfoEntry there. When we later find
382 // the correct Cell in the module that actually provides the value, we replace
383 // the SourceTextModuleInfoEntry by that Cell (see ResolveExport).
384 Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
385 for (int i = 0, n = special_exports->length(); i < n; ++i) {
386 Handle<SourceTextModuleInfoEntry> entry(
387 SourceTextModuleInfoEntry::cast(special_exports->get(i)), isolate);
388 Handle<Object> export_name(entry->export_name(), isolate);
389 if (export_name->IsUndefined(isolate)) continue; // Star export.
390 CreateIndirectExport(isolate, module, Handle<String>::cast(export_name),
391 entry);
392 }
393
394 DCHECK_EQ(module->status(), kPreLinking);
395 return true;
396 }
397
RunInitializationCode(Isolate * isolate,Handle<SourceTextModule> module)398 bool SourceTextModule::RunInitializationCode(Isolate* isolate,
399 Handle<SourceTextModule> module) {
400 DCHECK_EQ(module->status(), kLinking);
401 Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
402 DCHECK_EQ(MODULE_SCOPE, function->shared().scope_info().scope_type());
403 Handle<Object> receiver = isolate->factory()->undefined_value();
404
405 Handle<ScopeInfo> scope_info(function->shared().scope_info(), isolate);
406 Handle<Context> context = isolate->factory()->NewModuleContext(
407 module, isolate->native_context(), scope_info);
408 function->set_context(*context);
409
410 MaybeHandle<Object> maybe_generator =
411 Execution::Call(isolate, function, receiver, 0, {});
412 Handle<Object> generator;
413 if (!maybe_generator.ToHandle(&generator)) {
414 DCHECK(isolate->has_pending_exception());
415 return false;
416 }
417 DCHECK_EQ(*function, Handle<JSGeneratorObject>::cast(generator)->function());
418 module->set_code(JSGeneratorObject::cast(*generator));
419 return true;
420 }
421
MaybeTransitionComponent(Isolate * isolate,Handle<SourceTextModule> module,ZoneForwardList<Handle<SourceTextModule>> * stack,Status new_status)422 bool SourceTextModule::MaybeTransitionComponent(
423 Isolate* isolate, Handle<SourceTextModule> module,
424 ZoneForwardList<Handle<SourceTextModule>>* stack, Status new_status) {
425 DCHECK(new_status == kLinked || new_status == kEvaluated);
426 SLOW_DCHECK(
427 // {module} is on the {stack}.
428 std::count_if(stack->begin(), stack->end(),
429 [&](Handle<Module> m) { return *m == *module; }) == 1);
430 DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index());
431 if (module->dfs_ancestor_index() == module->dfs_index()) {
432 // This is the root of its strongly connected component.
433 Handle<SourceTextModule> cycle_root = module;
434 Handle<SourceTextModule> ancestor;
435 do {
436 ancestor = stack->front();
437 stack->pop_front();
438 DCHECK_EQ(ancestor->status(),
439 new_status == kLinked ? kLinking : kEvaluating);
440 if (new_status == kLinked) {
441 if (!SourceTextModule::RunInitializationCode(isolate, ancestor))
442 return false;
443 } else if (new_status == kEvaluated) {
444 DCHECK(ancestor->cycle_root().IsTheHole(isolate));
445 ancestor->set_cycle_root(*cycle_root);
446 }
447 ancestor->SetStatus(new_status);
448 } while (*ancestor != *module);
449 }
450 return true;
451 }
452
FinishInstantiate(Isolate * isolate,Handle<SourceTextModule> module,ZoneForwardList<Handle<SourceTextModule>> * stack,unsigned * dfs_index,Zone * zone)453 bool SourceTextModule::FinishInstantiate(
454 Isolate* isolate, Handle<SourceTextModule> module,
455 ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index,
456 Zone* zone) {
457 // Instantiate SharedFunctionInfo and mark module as instantiating for
458 // the recursion.
459 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
460 isolate);
461 Handle<JSFunction> function =
462 Factory::JSFunctionBuilder{isolate, shared, isolate->native_context()}
463 .Build();
464 module->set_code(*function);
465 module->SetStatus(kLinking);
466 module->set_dfs_index(*dfs_index);
467 module->set_dfs_ancestor_index(*dfs_index);
468 stack->push_front(module);
469 (*dfs_index)++;
470
471 // Recurse.
472 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
473 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
474 Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
475 isolate);
476 if (!Module::FinishInstantiate(isolate, requested_module, stack, dfs_index,
477 zone)) {
478 return false;
479 }
480
481 DCHECK_NE(requested_module->status(), kEvaluating);
482 DCHECK_GE(requested_module->status(), kLinking);
483 SLOW_DCHECK(
484 // {requested_module} is instantiating iff it's on the {stack}.
485 (requested_module->status() == kLinking) ==
486 std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) {
487 return *m == *requested_module;
488 }));
489
490 if (requested_module->status() == kLinking) {
491 // SyntheticModules go straight to kLinked so this must be a
492 // SourceTextModule
493 module->set_dfs_ancestor_index(std::min(
494 module->dfs_ancestor_index(),
495 SourceTextModule::cast(*requested_module).dfs_ancestor_index()));
496 }
497 }
498
499 Handle<Script> script(module->GetScript(), isolate);
500 Handle<SourceTextModuleInfo> module_info(module->info(), isolate);
501
502 // Resolve imports.
503 Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
504 for (int i = 0, n = regular_imports->length(); i < n; ++i) {
505 Handle<SourceTextModuleInfoEntry> entry(
506 SourceTextModuleInfoEntry::cast(regular_imports->get(i)), isolate);
507 Handle<String> name(String::cast(entry->import_name()), isolate);
508 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
509 ResolveSet resolve_set(zone);
510 Handle<Cell> cell;
511 if (!ResolveImport(isolate, module, name, entry->module_request(), loc,
512 true, &resolve_set)
513 .ToHandle(&cell)) {
514 return false;
515 }
516 module->regular_imports().set(ImportIndex(entry->cell_index()), *cell);
517 }
518
519 // Resolve indirect exports.
520 Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
521 for (int i = 0, n = special_exports->length(); i < n; ++i) {
522 Handle<SourceTextModuleInfoEntry> entry(
523 SourceTextModuleInfoEntry::cast(special_exports->get(i)), isolate);
524 Handle<Object> name(entry->export_name(), isolate);
525 if (name->IsUndefined(isolate)) continue; // Star export.
526 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
527 ResolveSet resolve_set(zone);
528 if (ResolveExport(isolate, module, Handle<String>(),
529 Handle<String>::cast(name), loc, true, &resolve_set)
530 .is_null()) {
531 return false;
532 }
533 }
534
535 return MaybeTransitionComponent(isolate, module, stack, kLinked);
536 }
537
FetchStarExports(Isolate * isolate,Handle<SourceTextModule> module,Zone * zone,UnorderedModuleSet * visited)538 void SourceTextModule::FetchStarExports(Isolate* isolate,
539 Handle<SourceTextModule> module,
540 Zone* zone,
541 UnorderedModuleSet* visited) {
542 DCHECK_GE(module->status(), Module::kLinking);
543
544 if (module->module_namespace().IsJSModuleNamespace()) return; // Shortcut.
545
546 bool cycle = !visited->insert(module).second;
547 if (cycle) return;
548 Handle<ObjectHashTable> exports(module->exports(), isolate);
549 UnorderedStringMap more_exports(zone);
550
551 // TODO(neis): Only allocate more_exports if there are star exports.
552 // Maybe split special_exports into indirect_exports and star_exports.
553
554 ReadOnlyRoots roots(isolate);
555 Handle<FixedArray> special_exports(module->info().special_exports(), isolate);
556 for (int i = 0, n = special_exports->length(); i < n; ++i) {
557 Handle<SourceTextModuleInfoEntry> entry(
558 SourceTextModuleInfoEntry::cast(special_exports->get(i)), isolate);
559 if (!entry->export_name().IsUndefined(roots)) {
560 continue; // Indirect export.
561 }
562
563 Handle<Module> requested_module(
564 Module::cast(module->requested_modules().get(entry->module_request())),
565 isolate);
566
567 // Recurse.
568 if (requested_module->IsSourceTextModule())
569 FetchStarExports(isolate,
570 Handle<SourceTextModule>::cast(requested_module), zone,
571 visited);
572
573 // Collect all of [requested_module]'s exports that must be added to
574 // [module]'s exports (i.e. to [exports]). We record these in
575 // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
576 // the name to undefined instead of a Cell.
577 Handle<ObjectHashTable> requested_exports(requested_module->exports(),
578 isolate);
579 for (InternalIndex i : requested_exports->IterateEntries()) {
580 Object key;
581 if (!requested_exports->ToKey(roots, i, &key)) continue;
582 Handle<String> name(String::cast(key), isolate);
583
584 if (name->Equals(roots.default_string())) continue;
585 if (!exports->Lookup(name).IsTheHole(roots)) continue;
586
587 Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
588 auto insert_result = more_exports.insert(std::make_pair(name, cell));
589 if (!insert_result.second) {
590 auto it = insert_result.first;
591 if (*it->second == *cell || it->second->IsUndefined(roots)) {
592 // We already recorded this mapping before, or the name is already
593 // known to be ambiguous. In either case, there's nothing to do.
594 } else {
595 DCHECK(it->second->IsCell());
596 // Different star exports provide different cells for this name, hence
597 // mark the name as ambiguous.
598 it->second = roots.undefined_value_handle();
599 }
600 }
601 }
602 }
603
604 // Copy [more_exports] into [exports].
605 for (const auto& elem : more_exports) {
606 if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
607 DCHECK(!elem.first->Equals(ReadOnlyRoots(isolate).default_string()));
608 DCHECK(elem.second->IsCell());
609 exports = ObjectHashTable::Put(exports, elem.first, elem.second);
610 }
611 module->set_exports(*exports);
612 }
613
GatherAsyncParentCompletions(Isolate * isolate,Zone * zone,Handle<SourceTextModule> start,AsyncParentCompletionSet * exec_list)614 void SourceTextModule::GatherAsyncParentCompletions(
615 Isolate* isolate, Zone* zone, Handle<SourceTextModule> start,
616 AsyncParentCompletionSet* exec_list) {
617 // The spec algorithm is recursive. It is transformed to an equivalent
618 // iterative one here.
619 ZoneStack<Handle<SourceTextModule>> worklist(zone);
620 worklist.push(start);
621
622 while (!worklist.empty()) {
623 Handle<SourceTextModule> module = worklist.top();
624 worklist.pop();
625
626 // 1. Assert: module.[[Status]] is evaluated.
627 DCHECK_EQ(module->status(), kEvaluated);
628
629 // 2. For each Module m of module.[[AsyncParentModules]], do
630 for (int i = module->AsyncParentModuleCount(); i-- > 0;) {
631 Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
632
633 // a. If execList does not contain m and
634 // m.[[CycleRoot]].[[EvaluationError]] is empty, then
635 if (exec_list->find(m) == exec_list->end() &&
636 m->GetCycleRoot(isolate)->status() != kErrored) {
637 // i. Assert: m.[[EvaluationError]] is empty.
638 DCHECK_NE(m->status(), kErrored);
639
640 // ii. Assert: m.[[AsyncEvaluating]] is true.
641 DCHECK(m->IsAsyncEvaluating());
642
643 // iii. Assert: m.[[PendingAsyncDependencies]] > 0.
644 DCHECK(m->HasPendingAsyncDependencies());
645
646 // iv. Set m.[[PendingAsyncDependencies]] to
647 // m.[[PendingAsyncDependencies]] - 1.
648 m->DecrementPendingAsyncDependencies();
649
650 // v. If m.[[PendingAsyncDependencies]] is equal to 0, then
651 if (!m->HasPendingAsyncDependencies()) {
652 // 1. Append m to execList.
653 exec_list->insert(m);
654
655 // 2. If m.[[Async]] is false,
656 // perform ! GatherAsyncParentCompletions(m, execList).
657 if (!m->async()) worklist.push(m);
658 }
659 }
660 }
661 }
662
663 // 3. Return undefined.
664 }
665
GetModuleNamespace(Isolate * isolate,Handle<SourceTextModule> module,int module_request)666 Handle<JSModuleNamespace> SourceTextModule::GetModuleNamespace(
667 Isolate* isolate, Handle<SourceTextModule> module, int module_request) {
668 Handle<Module> requested_module(
669 Module::cast(module->requested_modules().get(module_request)), isolate);
670 return Module::GetModuleNamespace(isolate, requested_module);
671 }
672
GetImportMeta(Isolate * isolate,Handle<SourceTextModule> module)673 MaybeHandle<JSObject> SourceTextModule::GetImportMeta(
674 Isolate* isolate, Handle<SourceTextModule> module) {
675 Handle<HeapObject> import_meta(module->import_meta(kAcquireLoad), isolate);
676 if (import_meta->IsTheHole(isolate)) {
677 if (!isolate->RunHostInitializeImportMetaObjectCallback(module).ToHandle(
678 &import_meta)) {
679 return {};
680 }
681 module->set_import_meta(*import_meta, kReleaseStore);
682 }
683 return Handle<JSObject>::cast(import_meta);
684 }
685
EvaluateMaybeAsync(Isolate * isolate,Handle<SourceTextModule> module)686 MaybeHandle<Object> SourceTextModule::EvaluateMaybeAsync(
687 Isolate* isolate, Handle<SourceTextModule> module) {
688 // 6. Let capability be ! NewPromiseCapability(%Promise%).
689 Handle<JSPromise> capability = isolate->factory()->NewJSPromise();
690
691 // 7. Set module.[[TopLevelCapability]] to capability.
692 module->set_top_level_capability(*capability);
693 DCHECK(module->top_level_capability().IsJSPromise());
694
695 // 9. If result is an abrupt completion, then
696 Handle<Object> unused_result;
697 if (!Evaluate(isolate, module).ToHandle(&unused_result)) {
698 // If the exception was a termination exception, rejecting the promise
699 // would resume execution, and our API contract is to return an empty
700 // handle. The module's status should be set to kErrored and the
701 // exception field should be set to `null`.
702 if (!isolate->is_catchable_by_javascript(isolate->pending_exception())) {
703 DCHECK_EQ(module->status(), kErrored);
704 DCHECK_EQ(module->exception(), *isolate->factory()->null_value());
705 return {};
706 }
707
708 // d. Perform ! Call(capability.[[Reject]], undefined,
709 // «result.[[Value]]»).
710 isolate->clear_pending_exception();
711 JSPromise::Reject(capability, handle(module->exception(), isolate));
712 } else {
713 // 10. Otherwise,
714 // a. Assert: module.[[Status]] is "evaluated"...
715 CHECK_EQ(module->status(), kEvaluated);
716
717 // b. If module.[[AsyncEvaluating]] is false, then
718 if (!module->IsAsyncEvaluating()) {
719 // i. Perform ! Call(capability.[[Resolve]], undefined,
720 // «undefined»).
721 JSPromise::Resolve(capability, isolate->factory()->undefined_value())
722 .ToHandleChecked();
723 }
724 }
725
726 // 11. Return capability.[[Promise]].
727 return capability;
728 }
729
Evaluate(Isolate * isolate,Handle<SourceTextModule> module)730 MaybeHandle<Object> SourceTextModule::Evaluate(
731 Isolate* isolate, Handle<SourceTextModule> module) {
732 // Evaluate () Concrete Method continued from EvaluateMaybeAsync.
733 CHECK(module->status() == kLinked || module->status() == kEvaluated);
734
735 // 5. Let stack be a new empty List.
736 Zone zone(isolate->allocator(), ZONE_NAME);
737 ZoneForwardList<Handle<SourceTextModule>> stack(&zone);
738 unsigned dfs_index = 0;
739
740 // 8. Let result be InnerModuleEvaluation(module, stack, 0).
741 // 9. If result is an abrupt completion, then
742 Handle<Object> result;
743 if (!InnerModuleEvaluation(isolate, module, &stack, &dfs_index)
744 .ToHandle(&result)) {
745 // a. For each Cyclic Module Record m in stack, do
746 for (auto& descendant : stack) {
747 // i. Assert: m.[[Status]] is "evaluating".
748 CHECK_EQ(descendant->status(), kEvaluating);
749 // ii. Set m.[[Status]] to "evaluated".
750 // iii. Set m.[[EvaluationError]] to result.
751 Module::RecordErrorUsingPendingException(isolate, descendant);
752 }
753
754 #ifdef DEBUG
755 if (isolate->is_catchable_by_javascript(isolate->pending_exception())) {
756 CHECK_EQ(module->exception(), isolate->pending_exception());
757 } else {
758 CHECK_EQ(module->exception(), *isolate->factory()->null_value());
759 }
760 #endif // DEBUG
761 } else {
762 // 10. Otherwise,
763 // c. Assert: stack is empty.
764 DCHECK(stack.empty());
765 }
766 return result;
767 }
768
AsyncModuleExecutionFulfilled(Isolate * isolate,Handle<SourceTextModule> module)769 void SourceTextModule::AsyncModuleExecutionFulfilled(
770 Isolate* isolate, Handle<SourceTextModule> module) {
771 // 1. If module.[[Status]] is evaluated, then
772 if (module->status() == kErrored) {
773 // a. Assert: module.[[EvaluationError]] is not empty.
774 DCHECK(!module->exception().IsTheHole(isolate));
775 // b. Return.
776 return;
777 }
778 // 3. Assert: module.[[AsyncEvaluating]] is true.
779 DCHECK(module->IsAsyncEvaluating());
780 // 4. Assert: module.[[EvaluationError]] is empty.
781 CHECK_EQ(module->status(), kEvaluated);
782 // 5. Set module.[[AsyncEvaluating]] to false.
783 isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal());
784 module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
785 // TODO(cbruni): update to match spec.
786 // 7. If module.[[TopLevelCapability]] is not empty, then
787 if (!module->top_level_capability().IsUndefined(isolate)) {
788 // a. Assert: module.[[CycleRoot]] is equal to module.
789 DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
790 // i. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined,
791 // «undefined»).
792 Handle<JSPromise> capability(
793 JSPromise::cast(module->top_level_capability()), isolate);
794 JSPromise::Resolve(capability, isolate->factory()->undefined_value())
795 .ToHandleChecked();
796 }
797
798 // 8. Let execList be a new empty List.
799 Zone zone(isolate->allocator(), ZONE_NAME);
800 AsyncParentCompletionSet exec_list(&zone);
801
802 // 9. Perform ! GatherAsyncParentCompletions(module, execList).
803 GatherAsyncParentCompletions(isolate, &zone, module, &exec_list);
804
805 // 10. Let sortedExecList be a List of elements that are the elements of
806 // execList, in the order in which they had their [[AsyncEvaluating]]
807 // fields set to true in InnerModuleEvaluation.
808 //
809 // This step is implemented by AsyncParentCompletionSet, which is a set
810 // ordered on async_evaluating_ordinal.
811
812 // 11. Assert: All elements of sortedExecList have their [[AsyncEvaluating]]
813 // field set to true, [[PendingAsyncDependencies]] field set to 0 and
814 // [[EvaluationError]] field set to undefined.
815 #ifdef DEBUG
816 for (Handle<SourceTextModule> m : exec_list) {
817 DCHECK(m->IsAsyncEvaluating());
818 DCHECK(!m->HasPendingAsyncDependencies());
819 DCHECK_NE(m->status(), kErrored);
820 }
821 #endif
822
823 // 12. For each Module m of sortedExecList, do
824 for (Handle<SourceTextModule> m : exec_list) {
825 // i. If m.[[AsyncEvaluating]] is false, then
826 if (!m->IsAsyncEvaluating()) {
827 // a. Assert: m.[[EvaluatingError]] is not empty.
828 DCHECK_EQ(m->status(), kErrored);
829 } else if (m->async()) {
830 // ii. Otherwise, if m.[[Async]] is *true*, then
831 // a. Perform ! ExecuteAsyncModule(m).
832 ExecuteAsyncModule(isolate, m);
833 } else {
834 // iii. Otherwise,
835 // a. Let _result_ be m.ExecuteModule().
836 Handle<Object> unused_result;
837 // b. If _result_ is an abrupt completion,
838 if (!ExecuteModule(isolate, m).ToHandle(&unused_result)) {
839 // 1. Perform ! AsyncModuleExecutionRejected(m, result.[[Value]]).
840 Handle<Object> exception(isolate->pending_exception(), isolate);
841 isolate->clear_pending_exception();
842 AsyncModuleExecutionRejected(isolate, m, exception);
843 } else {
844 // c. Otherwise,
845 // 1. Set m.[[AsyncEvaluating]] to false.
846 isolate->DidFinishModuleAsyncEvaluation(m->async_evaluating_ordinal());
847 m->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
848
849 // 2. If m.[[TopLevelCapability]] is not empty, then
850 if (!m->top_level_capability().IsUndefined(isolate)) {
851 // i. Assert: m.[[CycleRoot]] is equal to m.
852 DCHECK_EQ(*m->GetCycleRoot(isolate), *m);
853
854 // ii. Perform ! Call(m.[[TopLevelCapability]].[[Resolve]],
855 // undefined, «undefined»).
856 Handle<JSPromise> capability(
857 JSPromise::cast(m->top_level_capability()), isolate);
858 JSPromise::Resolve(capability, isolate->factory()->undefined_value())
859 .ToHandleChecked();
860 }
861 }
862 }
863 }
864
865 // 10. Return undefined.
866 }
867
AsyncModuleExecutionRejected(Isolate * isolate,Handle<SourceTextModule> module,Handle<Object> exception)868 void SourceTextModule::AsyncModuleExecutionRejected(
869 Isolate* isolate, Handle<SourceTextModule> module,
870 Handle<Object> exception) {
871 // 1. If module.[[Status]] is evaluated, then
872 if (module->status() == kErrored) {
873 // a. Assert: module.[[EvaluationError]] is not empty.
874 DCHECK(!module->exception().IsTheHole(isolate));
875 // b. Return.
876 return;
877 }
878
879 // TODO(cbruni): update to match spec.
880 DCHECK(isolate->is_catchable_by_javascript(*exception));
881 // 1. Assert: module.[[Status]] is "evaluated".
882 CHECK(module->status() == kEvaluated || module->status() == kErrored);
883 // 2. If module.[[AsyncEvaluating]] is false,
884 if (!module->IsAsyncEvaluating()) {
885 // a. Assert: module.[[EvaluationError]] is not empty.
886 CHECK_EQ(module->status(), kErrored);
887 // b. Return undefined.
888 return;
889 }
890
891 // 5. Set module.[[EvaluationError]] to ThrowCompletion(error).
892 Module::RecordError(isolate, module, exception);
893
894 // 6. Set module.[[AsyncEvaluating]] to false.
895 isolate->DidFinishModuleAsyncEvaluation(module->async_evaluating_ordinal());
896 module->set_async_evaluating_ordinal(kAsyncEvaluateDidFinish);
897
898 // 7. For each Module m of module.[[AsyncParentModules]], do
899 for (int i = 0; i < module->AsyncParentModuleCount(); i++) {
900 Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i);
901 // TODO(cbruni): update to match spec.
902 // a. If module.[[DFSIndex]] is not equal to module.[[DFSAncestorIndex]],
903 // then
904 if (module->dfs_index() != module->dfs_ancestor_index()) {
905 // i. Assert: m.[[DFSAncestorIndex]] is equal to
906 // module.[[DFSAncestorIndex]].
907 DCHECK_EQ(m->dfs_ancestor_index(), module->dfs_ancestor_index());
908 }
909 // b. Perform ! AsyncModuleExecutionRejected(m, error).
910 AsyncModuleExecutionRejected(isolate, m, exception);
911 }
912
913 // 8. If module.[[TopLevelCapability]] is not empty, then
914 if (!module->top_level_capability().IsUndefined(isolate)) {
915 // a. Assert: module.[[CycleRoot]] is equal to module.
916 DCHECK_EQ(*module->GetCycleRoot(isolate), *module);
917 // b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
918 // undefined, «error»).
919 Handle<JSPromise> capability(
920 JSPromise::cast(module->top_level_capability()), isolate);
921 JSPromise::Reject(capability, exception);
922 }
923 }
924
ExecuteAsyncModule(Isolate * isolate,Handle<SourceTextModule> module)925 void SourceTextModule::ExecuteAsyncModule(Isolate* isolate,
926 Handle<SourceTextModule> module) {
927 // 1. Assert: module.[[Status]] is "evaluating" or "evaluated".
928 CHECK(module->status() == kEvaluating || module->status() == kEvaluated);
929
930 // 2. Assert: module.[[Async]] is true.
931 DCHECK(module->async());
932
933 // 3. Set module.[[AsyncEvaluating]] to true.
934 module->set_async_evaluating_ordinal(
935 isolate->NextModuleAsyncEvaluatingOrdinal());
936
937 // 4. Let capability be ! NewPromiseCapability(%Promise%).
938 Handle<JSPromise> capability = isolate->factory()->NewJSPromise();
939
940 // 5. Let stepsFulfilled be the steps of a CallAsyncModuleFulfilled
941 Handle<JSFunction> steps_fulfilled(
942 isolate->native_context()->call_async_module_fulfilled(), isolate);
943
944 base::ScopedVector<Handle<Object>> empty_argv(0);
945
946 // 6. Let onFulfilled be CreateBuiltinFunction(stepsFulfilled,
947 // «[[Module]]»).
948 // 7. Set onFulfilled.[[Module]] to module.
949 Handle<JSBoundFunction> on_fulfilled =
950 isolate->factory()
951 ->NewJSBoundFunction(steps_fulfilled, module, empty_argv)
952 .ToHandleChecked();
953
954 // 8. Let stepsRejected be the steps of a CallAsyncModuleRejected.
955 Handle<JSFunction> steps_rejected(
956 isolate->native_context()->call_async_module_rejected(), isolate);
957
958 // 9. Let onRejected be CreateBuiltinFunction(stepsRejected, «[[Module]]»).
959 // 10. Set onRejected.[[Module]] to module.
960 Handle<JSBoundFunction> on_rejected =
961 isolate->factory()
962 ->NewJSBoundFunction(steps_rejected, module, empty_argv)
963 .ToHandleChecked();
964
965 // 11. Perform ! PerformPromiseThen(capability.[[Promise]],
966 // onFulfilled, onRejected).
967 Handle<Object> argv[] = {on_fulfilled, on_rejected};
968 Execution::CallBuiltin(isolate, isolate->promise_then(), capability,
969 arraysize(argv), argv)
970 .ToHandleChecked();
971
972 // 12. Perform ! module.ExecuteModule(capability).
973 // Note: In V8 we have broken module.ExecuteModule into
974 // ExecuteModule for synchronous module execution and
975 // InnerExecuteAsyncModule for asynchronous execution.
976 InnerExecuteAsyncModule(isolate, module, capability).ToHandleChecked();
977
978 // 13. Return.
979 }
980
InnerExecuteAsyncModule(Isolate * isolate,Handle<SourceTextModule> module,Handle<JSPromise> capability)981 MaybeHandle<Object> SourceTextModule::InnerExecuteAsyncModule(
982 Isolate* isolate, Handle<SourceTextModule> module,
983 Handle<JSPromise> capability) {
984 // If we have an async module, then it has an associated
985 // JSAsyncFunctionObject, which we then evaluate with the passed in promise
986 // capability.
987 Handle<JSAsyncFunctionObject> async_function_object(
988 JSAsyncFunctionObject::cast(module->code()), isolate);
989 async_function_object->set_promise(*capability);
990 Handle<JSFunction> resume(
991 isolate->native_context()->async_module_evaluate_internal(), isolate);
992 Handle<Object> result;
993 ASSIGN_RETURN_ON_EXCEPTION(
994 isolate, result,
995 Execution::TryCall(isolate, resume, async_function_object, 0, nullptr,
996 Execution::MessageHandling::kKeepPending, nullptr,
997 false),
998 Object);
999 return result;
1000 }
1001
ExecuteModule(Isolate * isolate,Handle<SourceTextModule> module)1002 MaybeHandle<Object> SourceTextModule::ExecuteModule(
1003 Isolate* isolate, Handle<SourceTextModule> module) {
1004 // Synchronous modules have an associated JSGeneratorObject.
1005 Handle<JSGeneratorObject> generator(JSGeneratorObject::cast(module->code()),
1006 isolate);
1007 Handle<JSFunction> resume(
1008 isolate->native_context()->generator_next_internal(), isolate);
1009 Handle<Object> result;
1010
1011 // With top_level_await, we need to catch any exceptions and reject
1012 // the top level capability.
1013 if (FLAG_harmony_top_level_await) {
1014 ASSIGN_RETURN_ON_EXCEPTION(
1015 isolate, result,
1016 Execution::TryCall(isolate, resume, generator, 0, nullptr,
1017 Execution::MessageHandling::kKeepPending, nullptr,
1018 false),
1019 Object);
1020 } else {
1021 ASSIGN_RETURN_ON_EXCEPTION(
1022 isolate, result,
1023 Execution::Call(isolate, resume, generator, 0, nullptr), Object);
1024 }
1025 DCHECK(JSIteratorResult::cast(*result).done().BooleanValue(isolate));
1026 return handle(JSIteratorResult::cast(*result).value(), isolate);
1027 }
1028
InnerModuleEvaluation(Isolate * isolate,Handle<SourceTextModule> module,ZoneForwardList<Handle<SourceTextModule>> * stack,unsigned * dfs_index)1029 MaybeHandle<Object> SourceTextModule::InnerModuleEvaluation(
1030 Isolate* isolate, Handle<SourceTextModule> module,
1031 ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index) {
1032 STACK_CHECK(isolate, MaybeHandle<Object>());
1033
1034 // InnerModuleEvaluation(module, stack, index)
1035 // 2. If module.[[Status]] is "evaluated", then
1036 // a. If module.[[EvaluationError]] is undefined, return index.
1037 // (We return undefined instead)
1038 if (module->status() == kEvaluated || module->status() == kEvaluating) {
1039 return isolate->factory()->undefined_value();
1040 }
1041
1042 // b. Otherwise return module.[[EvaluationError]].
1043 // (We throw on isolate and return a MaybeHandle<Object>
1044 // instead)
1045 if (module->status() == kErrored) {
1046 isolate->Throw(module->exception());
1047 return MaybeHandle<Object>();
1048 }
1049
1050 // 4. Assert: module.[[Status]] is "linked".
1051 CHECK_EQ(module->status(), kLinked);
1052
1053 // 5. Set module.[[Status]] to "evaluating".
1054 module->SetStatus(kEvaluating);
1055
1056 // 6. Set module.[[DFSIndex]] to index.
1057 module->set_dfs_index(*dfs_index);
1058
1059 // 7. Set module.[[DFSAncestorIndex]] to index.
1060 module->set_dfs_ancestor_index(*dfs_index);
1061
1062 // 8. Set module.[[PendingAsyncDependencies]] to 0.
1063 DCHECK(!module->HasPendingAsyncDependencies());
1064
1065 // 9. Set module.[[AsyncParentModules]] to a new empty List.
1066 Handle<ArrayList> async_parent_modules = ArrayList::New(isolate, 0);
1067 module->set_async_parent_modules(*async_parent_modules);
1068
1069 // 10. Set index to index + 1.
1070 (*dfs_index)++;
1071
1072 // 11. Append module to stack.
1073 stack->push_front(module);
1074
1075 // Recursion.
1076 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
1077
1078 // 12. For each String required that is an element of
1079 // module.[[RequestedModules]], do
1080 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
1081 Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
1082 isolate);
1083 // d. If requiredModule is a Cyclic Module Record, then
1084 if (requested_module->IsSourceTextModule()) {
1085 Handle<SourceTextModule> required_module(
1086 SourceTextModule::cast(*requested_module), isolate);
1087 RETURN_ON_EXCEPTION(
1088 isolate,
1089 InnerModuleEvaluation(isolate, required_module, stack, dfs_index),
1090 Object);
1091
1092 // i. Assert: requiredModule.[[Status]] is either "evaluating" or
1093 // "evaluated".
1094 // (We also assert the module cannot be errored, because if it was
1095 // we would have already returned from InnerModuleEvaluation)
1096 CHECK_GE(required_module->status(), kEvaluating);
1097 CHECK_NE(required_module->status(), kErrored);
1098
1099 // ii. Assert: requiredModule.[[Status]] is "evaluating" if and
1100 // only if requiredModule is in stack.
1101 SLOW_DCHECK(
1102 (requested_module->status() == kEvaluating) ==
1103 std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) {
1104 return *m == *requested_module;
1105 }));
1106
1107 // iii. If requiredModule.[[Status]] is "evaluating", then
1108 if (required_module->status() == kEvaluating) {
1109 // 1. Set module.[[DFSAncestorIndex]] to
1110 // min(
1111 // module.[[DFSAncestorIndex]],
1112 // requiredModule.[[DFSAncestorIndex]]).
1113 module->set_dfs_ancestor_index(
1114 std::min(module->dfs_ancestor_index(),
1115 required_module->dfs_ancestor_index()));
1116 } else {
1117 // iv. Otherwise,
1118 // 1. Set requiredModule to requiredModule.[[CycleRoot]].
1119 required_module = required_module->GetCycleRoot(isolate);
1120
1121 // 2. Assert: requiredModule.[[Status]] is "evaluated".
1122 CHECK_GE(required_module->status(), kEvaluated);
1123
1124 // 3. If requiredModule.[[EvaluationError]] is not undefined,
1125 // return module.[[EvaluationError]].
1126 // (If there was an exception on the original required module
1127 // we would have already returned. This check handles the case
1128 // where the AsyncCycleRoot has an error. Instead of returning
1129 // the exception, we throw on isolate and return a
1130 // MaybeHandle<Object>)
1131 if (required_module->status() == kErrored) {
1132 isolate->Throw(required_module->exception());
1133 return MaybeHandle<Object>();
1134 }
1135 }
1136 // v. If requiredModule.[[AsyncEvaluating]] is true, then
1137 if (required_module->IsAsyncEvaluating()) {
1138 // 1. Set module.[[PendingAsyncDependencies]] to
1139 // module.[[PendingAsyncDependencies]] + 1.
1140 module->IncrementPendingAsyncDependencies();
1141
1142 // 2. Append module to requiredModule.[[AsyncParentModules]].
1143 AddAsyncParentModule(isolate, required_module, module);
1144 }
1145 } else {
1146 RETURN_ON_EXCEPTION(isolate, Module::Evaluate(isolate, requested_module),
1147 Object);
1148 }
1149 }
1150
1151 // The spec returns the module index for proper numbering of dependencies.
1152 // However, we pass the module index by pointer instead.
1153 //
1154 // Before async modules v8 returned the value result from calling next
1155 // on the module's implicit iterator. We preserve this behavior for
1156 // synchronous modules, but return undefined for AsyncModules.
1157 Handle<Object> result = isolate->factory()->undefined_value();
1158
1159 // 14. If module.[[PendingAsyncDependencies]] > 0 or module.[[Async]] is
1160 // true, then
1161 if (module->HasPendingAsyncDependencies() || module->async()) {
1162 // a. Assert: module.[[AsyncEvaluating]] is false and was never previously
1163 // set to true.
1164 DCHECK_EQ(module->async_evaluating_ordinal(), kNotAsyncEvaluated);
1165
1166 // b. Set module.[[AsyncEvaluating]] to true.
1167 // NOTE: The order in which modules transition to async evaluating is
1168 // significant.
1169 module->set_async_evaluating_ordinal(
1170 isolate->NextModuleAsyncEvaluatingOrdinal());
1171
1172 // c. If module.[[PendingAsyncDependencies]] is 0,
1173 // perform ! ExecuteAsyncModule(_module_).
1174 if (!module->HasPendingAsyncDependencies()) {
1175 SourceTextModule::ExecuteAsyncModule(isolate, module);
1176 }
1177 } else {
1178 // 15. Otherwise, perform ? module.ExecuteModule().
1179 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, ExecuteModule(isolate, module),
1180 Object);
1181 }
1182
1183 CHECK(MaybeTransitionComponent(isolate, module, stack, kEvaluated));
1184 return result;
1185 }
1186
Reset(Isolate * isolate,Handle<SourceTextModule> module)1187 void SourceTextModule::Reset(Isolate* isolate,
1188 Handle<SourceTextModule> module) {
1189 Factory* factory = isolate->factory();
1190
1191 DCHECK(module->import_meta(kAcquireLoad).IsTheHole(isolate));
1192
1193 Handle<FixedArray> regular_exports =
1194 factory->NewFixedArray(module->regular_exports().length());
1195 Handle<FixedArray> regular_imports =
1196 factory->NewFixedArray(module->regular_imports().length());
1197 Handle<FixedArray> requested_modules =
1198 factory->NewFixedArray(module->requested_modules().length());
1199
1200 if (module->status() == kLinking) {
1201 module->set_code(JSFunction::cast(module->code()).shared());
1202 }
1203 module->set_regular_exports(*regular_exports);
1204 module->set_regular_imports(*regular_imports);
1205 module->set_requested_modules(*requested_modules);
1206 module->set_dfs_index(-1);
1207 module->set_dfs_ancestor_index(-1);
1208 }
1209
1210 } // namespace internal
1211 } // namespace v8
1212