1 // Copyright 2017 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 <unordered_map>
6 #include <unordered_set>
7
8 #include "src/objects/module.h"
9
10 #include "src/accessors.h"
11 #include "src/api-inl.h"
12 #include "src/ast/modules.h"
13 #include "src/objects-inl.h"
14 #include "src/objects/hash-table-inl.h"
15 #include "src/objects/js-generator-inl.h"
16 #include "src/objects/module-inl.h"
17
18 namespace v8 {
19 namespace internal {
20
21 namespace {
22
23 struct ModuleHandleHash {
operator ()v8::internal::__anon04e124a10111::ModuleHandleHash24 V8_INLINE size_t operator()(Handle<Module> module) const {
25 return module->hash();
26 }
27 };
28
29 struct ModuleHandleEqual {
operator ()v8::internal::__anon04e124a10111::ModuleHandleEqual30 V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
31 return *lhs == *rhs;
32 }
33 };
34
35 struct StringHandleHash {
operator ()v8::internal::__anon04e124a10111::StringHandleHash36 V8_INLINE size_t operator()(Handle<String> string) const {
37 return string->Hash();
38 }
39 };
40
41 struct StringHandleEqual {
operator ()v8::internal::__anon04e124a10111::StringHandleEqual42 V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
43 return lhs->Equals(*rhs);
44 }
45 };
46
47 class UnorderedStringSet
48 : public std::unordered_set<Handle<String>, StringHandleHash,
49 StringHandleEqual,
50 ZoneAllocator<Handle<String>>> {
51 public:
UnorderedStringSet(Zone * zone)52 explicit UnorderedStringSet(Zone* zone)
53 : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
54 ZoneAllocator<Handle<String>>>(
55 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
56 ZoneAllocator<Handle<String>>(zone)) {}
57 };
58
59 class UnorderedModuleSet
60 : public std::unordered_set<Handle<Module>, ModuleHandleHash,
61 ModuleHandleEqual,
62 ZoneAllocator<Handle<Module>>> {
63 public:
UnorderedModuleSet(Zone * zone)64 explicit UnorderedModuleSet(Zone* zone)
65 : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual,
66 ZoneAllocator<Handle<Module>>>(
67 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
68 ZoneAllocator<Handle<Module>>(zone)) {}
69 };
70
71 class UnorderedStringMap
72 : public std::unordered_map<
73 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
74 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> {
75 public:
UnorderedStringMap(Zone * zone)76 explicit UnorderedStringMap(Zone* zone)
77 : std::unordered_map<
78 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
79 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>>(
80 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
81 ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>(
82 zone)) {}
83 };
84
85 } // anonymous namespace
86
87 class Module::ResolveSet
88 : public std::unordered_map<
89 Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
90 ModuleHandleEqual,
91 ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> {
92 public:
ResolveSet(Zone * zone)93 explicit ResolveSet(Zone* zone)
94 : std::unordered_map<Handle<Module>, UnorderedStringSet*,
95 ModuleHandleHash, ModuleHandleEqual,
96 ZoneAllocator<std::pair<const Handle<Module>,
97 UnorderedStringSet*>>>(
98 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
99 ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>(
100 zone)),
101 zone_(zone) {}
102
zone() const103 Zone* zone() const { return zone_; }
104
105 private:
106 Zone* zone_;
107 };
108
109 namespace {
110
ExportIndex(int cell_index)111 int ExportIndex(int cell_index) {
112 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
113 ModuleDescriptor::kExport);
114 return cell_index - 1;
115 }
116
ImportIndex(int cell_index)117 int ImportIndex(int cell_index) {
118 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
119 ModuleDescriptor::kImport);
120 return -cell_index - 1;
121 }
122
123 } // anonymous namespace
124
CreateIndirectExport(Isolate * isolate,Handle<Module> module,Handle<String> name,Handle<ModuleInfoEntry> entry)125 void Module::CreateIndirectExport(Isolate* isolate, Handle<Module> module,
126 Handle<String> name,
127 Handle<ModuleInfoEntry> 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<Module> module,int cell_index,Handle<FixedArray> names)134 void Module::CreateExport(Isolate* isolate, Handle<Module> module,
135 int cell_index, Handle<FixedArray> names) {
136 DCHECK_LT(0, names->length());
137 Handle<Cell> cell =
138 isolate->factory()->NewCell(isolate->factory()->undefined_value());
139 module->regular_exports()->set(ExportIndex(cell_index), *cell);
140
141 Handle<ObjectHashTable> exports(module->exports(), isolate);
142 for (int i = 0, n = names->length(); i < n; ++i) {
143 Handle<String> name(String::cast(names->get(i)), isolate);
144 DCHECK(exports->Lookup(name)->IsTheHole(isolate));
145 exports = ObjectHashTable::Put(exports, name, cell);
146 }
147 module->set_exports(*exports);
148 }
149
GetCell(int cell_index)150 Cell* Module::GetCell(int cell_index) {
151 DisallowHeapAllocation no_gc;
152 Object* cell;
153 switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
154 case ModuleDescriptor::kImport:
155 cell = regular_imports()->get(ImportIndex(cell_index));
156 break;
157 case ModuleDescriptor::kExport:
158 cell = regular_exports()->get(ExportIndex(cell_index));
159 break;
160 case ModuleDescriptor::kInvalid:
161 UNREACHABLE();
162 break;
163 }
164 return Cell::cast(cell);
165 }
166
LoadVariable(Isolate * isolate,Handle<Module> module,int cell_index)167 Handle<Object> Module::LoadVariable(Isolate* isolate, Handle<Module> module,
168 int cell_index) {
169 return handle(module->GetCell(cell_index)->value(), isolate);
170 }
171
StoreVariable(Handle<Module> module,int cell_index,Handle<Object> value)172 void Module::StoreVariable(Handle<Module> module, int cell_index,
173 Handle<Object> value) {
174 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
175 ModuleDescriptor::kExport);
176 module->GetCell(cell_index)->set_value(*value);
177 }
178
179 #ifdef DEBUG
PrintStatusTransition(Status new_status)180 void Module::PrintStatusTransition(Status new_status) {
181 if (FLAG_trace_module_status) {
182 StdoutStream os;
183 os << "Changing module status from " << status() << " to " << new_status
184 << " for ";
185 script()->GetNameOrSourceURL()->Print(os);
186 #ifndef OBJECT_PRINT
187 os << "\n";
188 #endif // OBJECT_PRINT
189 }
190 }
191 #endif // DEBUG
192
SetStatus(Status new_status)193 void Module::SetStatus(Status new_status) {
194 DisallowHeapAllocation no_alloc;
195 DCHECK_LE(status(), new_status);
196 DCHECK_NE(new_status, Module::kErrored);
197 #ifdef DEBUG
198 PrintStatusTransition(new_status);
199 #endif // DEBUG
200 set_status(new_status);
201 }
202
ResetGraph(Isolate * isolate,Handle<Module> module)203 void Module::ResetGraph(Isolate* isolate, Handle<Module> module) {
204 DCHECK_NE(module->status(), kInstantiating);
205 DCHECK_NE(module->status(), kEvaluating);
206 if (module->status() != kPreInstantiating) return;
207 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
208 Reset(isolate, module);
209 for (int i = 0; i < requested_modules->length(); ++i) {
210 Handle<Object> descendant(requested_modules->get(i), isolate);
211 if (descendant->IsModule()) {
212 ResetGraph(isolate, Handle<Module>::cast(descendant));
213 } else {
214 DCHECK(descendant->IsUndefined(isolate));
215 }
216 }
217 }
218
Reset(Isolate * isolate,Handle<Module> module)219 void Module::Reset(Isolate* isolate, Handle<Module> module) {
220 Factory* factory = isolate->factory();
221
222 DCHECK(module->status() == kPreInstantiating ||
223 module->status() == kInstantiating);
224 DCHECK(module->exception()->IsTheHole(isolate));
225 DCHECK(module->import_meta()->IsTheHole(isolate));
226 // The namespace object cannot exist, because it would have been created
227 // by RunInitializationCode, which is called only after this module's SCC
228 // succeeds instantiation.
229 DCHECK(!module->module_namespace()->IsJSModuleNamespace());
230
231 Handle<ObjectHashTable> exports =
232 ObjectHashTable::New(isolate, module->info()->RegularExportCount());
233 Handle<FixedArray> regular_exports =
234 factory->NewFixedArray(module->regular_exports()->length());
235 Handle<FixedArray> regular_imports =
236 factory->NewFixedArray(module->regular_imports()->length());
237 Handle<FixedArray> requested_modules =
238 factory->NewFixedArray(module->requested_modules()->length());
239
240 if (module->status() == kInstantiating) {
241 module->set_code(JSFunction::cast(module->code())->shared());
242 }
243 #ifdef DEBUG
244 module->PrintStatusTransition(kUninstantiated);
245 #endif // DEBUG
246 module->set_status(kUninstantiated);
247 module->set_exports(*exports);
248 module->set_regular_exports(*regular_exports);
249 module->set_regular_imports(*regular_imports);
250 module->set_requested_modules(*requested_modules);
251 module->set_dfs_index(-1);
252 module->set_dfs_ancestor_index(-1);
253 }
254
RecordError(Isolate * isolate)255 void Module::RecordError(Isolate* isolate) {
256 DisallowHeapAllocation no_alloc;
257 DCHECK(exception()->IsTheHole(isolate));
258 Object* the_exception = isolate->pending_exception();
259 DCHECK(!the_exception->IsTheHole(isolate));
260
261 set_code(info());
262 #ifdef DEBUG
263 PrintStatusTransition(Module::kErrored);
264 #endif // DEBUG
265 set_status(Module::kErrored);
266 set_exception(the_exception);
267 }
268
GetException()269 Object* Module::GetException() {
270 DisallowHeapAllocation no_alloc;
271 DCHECK_EQ(status(), Module::kErrored);
272 DCHECK(!exception()->IsTheHole());
273 return exception();
274 }
275
GetSharedFunctionInfo() const276 SharedFunctionInfo* Module::GetSharedFunctionInfo() const {
277 DisallowHeapAllocation no_alloc;
278 DCHECK_NE(status(), Module::kEvaluating);
279 DCHECK_NE(status(), Module::kEvaluated);
280 switch (status()) {
281 case kUninstantiated:
282 case kPreInstantiating:
283 DCHECK(code()->IsSharedFunctionInfo());
284 return SharedFunctionInfo::cast(code());
285 case kInstantiating:
286 DCHECK(code()->IsJSFunction());
287 return JSFunction::cast(code())->shared();
288 case kInstantiated:
289 DCHECK(code()->IsJSGeneratorObject());
290 return JSGeneratorObject::cast(code())->function()->shared();
291 case kEvaluating:
292 case kEvaluated:
293 case kErrored:
294 UNREACHABLE();
295 }
296
297 UNREACHABLE();
298 }
299
ResolveImport(Isolate * isolate,Handle<Module> module,Handle<String> name,int module_request,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)300 MaybeHandle<Cell> Module::ResolveImport(Isolate* isolate, Handle<Module> module,
301 Handle<String> name, int module_request,
302 MessageLocation loc, bool must_resolve,
303 Module::ResolveSet* resolve_set) {
304 Handle<Module> requested_module(
305 Module::cast(module->requested_modules()->get(module_request)), isolate);
306 Handle<String> specifier(
307 String::cast(module->info()->module_requests()->get(module_request)),
308 isolate);
309 MaybeHandle<Cell> result =
310 Module::ResolveExport(isolate, requested_module, specifier, name, loc,
311 must_resolve, resolve_set);
312 DCHECK_IMPLIES(isolate->has_pending_exception(), result.is_null());
313 return result;
314 }
315
ResolveExport(Isolate * isolate,Handle<Module> module,Handle<String> module_specifier,Handle<String> export_name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)316 MaybeHandle<Cell> Module::ResolveExport(Isolate* isolate, Handle<Module> module,
317 Handle<String> module_specifier,
318 Handle<String> export_name,
319 MessageLocation loc, bool must_resolve,
320 Module::ResolveSet* resolve_set) {
321 DCHECK_GE(module->status(), kPreInstantiating);
322 DCHECK_NE(module->status(), kEvaluating);
323 Handle<Object> object(module->exports()->Lookup(export_name), isolate);
324 if (object->IsCell()) {
325 // Already resolved (e.g. because it's a local export).
326 return Handle<Cell>::cast(object);
327 }
328
329 // Check for cycle before recursing.
330 {
331 // Attempt insertion with a null string set.
332 auto result = resolve_set->insert({module, nullptr});
333 UnorderedStringSet*& name_set = result.first->second;
334 if (result.second) {
335 // |module| wasn't in the map previously, so allocate a new name set.
336 Zone* zone = resolve_set->zone();
337 name_set =
338 new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
339 } else if (name_set->count(export_name)) {
340 // Cycle detected.
341 if (must_resolve) {
342 return isolate->Throw<Cell>(
343 isolate->factory()->NewSyntaxError(
344 MessageTemplate::kCyclicModuleDependency, export_name,
345 module_specifier),
346 &loc);
347 }
348 return MaybeHandle<Cell>();
349 }
350 name_set->insert(export_name);
351 }
352
353 if (object->IsModuleInfoEntry()) {
354 // Not yet resolved indirect export.
355 Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
356 Handle<String> import_name(String::cast(entry->import_name()), isolate);
357 Handle<Script> script(module->script(), isolate);
358 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
359
360 Handle<Cell> cell;
361 if (!ResolveImport(isolate, module, import_name, entry->module_request(),
362 new_loc, true, resolve_set)
363 .ToHandle(&cell)) {
364 DCHECK(isolate->has_pending_exception());
365 return MaybeHandle<Cell>();
366 }
367
368 // The export table may have changed but the entry in question should be
369 // unchanged.
370 Handle<ObjectHashTable> exports(module->exports(), isolate);
371 DCHECK(exports->Lookup(export_name)->IsModuleInfoEntry());
372
373 exports = ObjectHashTable::Put(exports, export_name, cell);
374 module->set_exports(*exports);
375 return cell;
376 }
377
378 DCHECK(object->IsTheHole(isolate));
379 return Module::ResolveExportUsingStarExports(isolate, module,
380 module_specifier, export_name,
381 loc, must_resolve, resolve_set);
382 }
383
ResolveExportUsingStarExports(Isolate * isolate,Handle<Module> module,Handle<String> module_specifier,Handle<String> export_name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)384 MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
385 Isolate* isolate, Handle<Module> module, Handle<String> module_specifier,
386 Handle<String> export_name, MessageLocation loc, bool must_resolve,
387 Module::ResolveSet* resolve_set) {
388 if (!export_name->Equals(ReadOnlyRoots(isolate).default_string())) {
389 // Go through all star exports looking for the given name. If multiple star
390 // exports provide the name, make sure they all map it to the same cell.
391 Handle<Cell> unique_cell;
392 Handle<FixedArray> special_exports(module->info()->special_exports(),
393 isolate);
394 for (int i = 0, n = special_exports->length(); i < n; ++i) {
395 i::Handle<i::ModuleInfoEntry> entry(
396 i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
397 if (!entry->export_name()->IsUndefined(isolate)) {
398 continue; // Indirect export.
399 }
400
401 Handle<Script> script(module->script(), isolate);
402 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
403
404 Handle<Cell> cell;
405 if (ResolveImport(isolate, module, export_name, entry->module_request(),
406 new_loc, false, resolve_set)
407 .ToHandle(&cell)) {
408 if (unique_cell.is_null()) unique_cell = cell;
409 if (*unique_cell != *cell) {
410 return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError(
411 MessageTemplate::kAmbiguousExport,
412 module_specifier, export_name),
413 &loc);
414 }
415 } else if (isolate->has_pending_exception()) {
416 return MaybeHandle<Cell>();
417 }
418 }
419
420 if (!unique_cell.is_null()) {
421 // Found a unique star export for this name.
422 Handle<ObjectHashTable> exports(module->exports(), isolate);
423 DCHECK(exports->Lookup(export_name)->IsTheHole(isolate));
424 exports = ObjectHashTable::Put(exports, export_name, unique_cell);
425 module->set_exports(*exports);
426 return unique_cell;
427 }
428 }
429
430 // Unresolvable.
431 if (must_resolve) {
432 return isolate->Throw<Cell>(
433 isolate->factory()->NewSyntaxError(MessageTemplate::kUnresolvableExport,
434 module_specifier, export_name),
435 &loc);
436 }
437 return MaybeHandle<Cell>();
438 }
439
Instantiate(Isolate * isolate,Handle<Module> module,v8::Local<v8::Context> context,v8::Module::ResolveCallback callback)440 bool Module::Instantiate(Isolate* isolate, Handle<Module> module,
441 v8::Local<v8::Context> context,
442 v8::Module::ResolveCallback callback) {
443 #ifdef DEBUG
444 if (FLAG_trace_module_status) {
445 StdoutStream os;
446 os << "Instantiating module ";
447 module->script()->GetNameOrSourceURL()->Print(os);
448 #ifndef OBJECT_PRINT
449 os << "\n";
450 #endif // OBJECT_PRINT
451 }
452 #endif // DEBUG
453
454 if (!PrepareInstantiate(isolate, module, context, callback)) {
455 ResetGraph(isolate, module);
456 return false;
457 }
458 Zone zone(isolate->allocator(), ZONE_NAME);
459 ZoneForwardList<Handle<Module>> stack(&zone);
460 unsigned dfs_index = 0;
461 if (!FinishInstantiate(isolate, module, &stack, &dfs_index, &zone)) {
462 for (auto& descendant : stack) {
463 Reset(isolate, descendant);
464 }
465 DCHECK_EQ(module->status(), kUninstantiated);
466 return false;
467 }
468 DCHECK(module->status() == kInstantiated || module->status() == kEvaluated ||
469 module->status() == kErrored);
470 DCHECK(stack.empty());
471 return true;
472 }
473
PrepareInstantiate(Isolate * isolate,Handle<Module> module,v8::Local<v8::Context> context,v8::Module::ResolveCallback callback)474 bool Module::PrepareInstantiate(Isolate* isolate, Handle<Module> module,
475 v8::Local<v8::Context> context,
476 v8::Module::ResolveCallback callback) {
477 DCHECK_NE(module->status(), kEvaluating);
478 DCHECK_NE(module->status(), kInstantiating);
479 if (module->status() >= kPreInstantiating) return true;
480 module->SetStatus(kPreInstantiating);
481 STACK_CHECK(isolate, false);
482
483 // Obtain requested modules.
484 Handle<ModuleInfo> module_info(module->info(), isolate);
485 Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
486 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
487 for (int i = 0, length = module_requests->length(); i < length; ++i) {
488 Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
489 v8::Local<v8::Module> api_requested_module;
490 if (!callback(context, v8::Utils::ToLocal(specifier),
491 v8::Utils::ToLocal(module))
492 .ToLocal(&api_requested_module)) {
493 isolate->PromoteScheduledException();
494 return false;
495 }
496 Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
497 requested_modules->set(i, *requested_module);
498 }
499
500 // Recurse.
501 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
502 Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
503 isolate);
504 if (!PrepareInstantiate(isolate, requested_module, context, callback)) {
505 return false;
506 }
507 }
508
509 // Set up local exports.
510 // TODO(neis): Create regular_exports array here instead of in factory method?
511 for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
512 int cell_index = module_info->RegularExportCellIndex(i);
513 Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
514 isolate);
515 CreateExport(isolate, module, cell_index, export_names);
516 }
517
518 // Partially set up indirect exports.
519 // For each indirect export, we create the appropriate slot in the export
520 // table and store its ModuleInfoEntry there. When we later find the correct
521 // Cell in the module that actually provides the value, we replace the
522 // ModuleInfoEntry by that Cell (see ResolveExport).
523 Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
524 for (int i = 0, n = special_exports->length(); i < n; ++i) {
525 Handle<ModuleInfoEntry> entry(
526 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
527 Handle<Object> export_name(entry->export_name(), isolate);
528 if (export_name->IsUndefined(isolate)) continue; // Star export.
529 CreateIndirectExport(isolate, module, Handle<String>::cast(export_name),
530 entry);
531 }
532
533 DCHECK_EQ(module->status(), kPreInstantiating);
534 return true;
535 }
536
RunInitializationCode(Isolate * isolate,Handle<Module> module)537 bool Module::RunInitializationCode(Isolate* isolate, Handle<Module> module) {
538 DCHECK_EQ(module->status(), kInstantiating);
539 Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
540 DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
541 Handle<Object> receiver = isolate->factory()->undefined_value();
542 Handle<Object> argv[] = {module};
543 MaybeHandle<Object> maybe_generator =
544 Execution::Call(isolate, function, receiver, arraysize(argv), argv);
545 Handle<Object> generator;
546 if (!maybe_generator.ToHandle(&generator)) {
547 DCHECK(isolate->has_pending_exception());
548 return false;
549 }
550 DCHECK_EQ(*function, Handle<JSGeneratorObject>::cast(generator)->function());
551 module->set_code(*generator);
552 return true;
553 }
554
MaybeTransitionComponent(Isolate * isolate,Handle<Module> module,ZoneForwardList<Handle<Module>> * stack,Status new_status)555 bool Module::MaybeTransitionComponent(Isolate* isolate, Handle<Module> module,
556 ZoneForwardList<Handle<Module>>* stack,
557 Status new_status) {
558 DCHECK(new_status == kInstantiated || new_status == kEvaluated);
559 SLOW_DCHECK(
560 // {module} is on the {stack}.
561 std::count_if(stack->begin(), stack->end(),
562 [&](Handle<Module> m) { return *m == *module; }) == 1);
563 DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index());
564 if (module->dfs_ancestor_index() == module->dfs_index()) {
565 // This is the root of its strongly connected component.
566 Handle<Module> ancestor;
567 do {
568 ancestor = stack->front();
569 stack->pop_front();
570 DCHECK_EQ(ancestor->status(),
571 new_status == kInstantiated ? kInstantiating : kEvaluating);
572 if (new_status == kInstantiated) {
573 if (!RunInitializationCode(isolate, ancestor)) return false;
574 }
575 ancestor->SetStatus(new_status);
576 } while (*ancestor != *module);
577 }
578 return true;
579 }
580
FinishInstantiate(Isolate * isolate,Handle<Module> module,ZoneForwardList<Handle<Module>> * stack,unsigned * dfs_index,Zone * zone)581 bool Module::FinishInstantiate(Isolate* isolate, Handle<Module> module,
582 ZoneForwardList<Handle<Module>>* stack,
583 unsigned* dfs_index, Zone* zone) {
584 DCHECK_NE(module->status(), kEvaluating);
585 if (module->status() >= kInstantiating) return true;
586 DCHECK_EQ(module->status(), kPreInstantiating);
587 STACK_CHECK(isolate, false);
588
589 // Instantiate SharedFunctionInfo and mark module as instantiating for
590 // the recursion.
591 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
592 isolate);
593 Handle<JSFunction> function =
594 isolate->factory()->NewFunctionFromSharedFunctionInfo(
595 shared, isolate->native_context());
596 module->set_code(*function);
597 module->SetStatus(kInstantiating);
598 module->set_dfs_index(*dfs_index);
599 module->set_dfs_ancestor_index(*dfs_index);
600 stack->push_front(module);
601 (*dfs_index)++;
602
603 // Recurse.
604 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
605 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
606 Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
607 isolate);
608 if (!FinishInstantiate(isolate, requested_module, stack, dfs_index, zone)) {
609 return false;
610 }
611
612 DCHECK_NE(requested_module->status(), kEvaluating);
613 DCHECK_GE(requested_module->status(), kInstantiating);
614 SLOW_DCHECK(
615 // {requested_module} is instantiating iff it's on the {stack}.
616 (requested_module->status() == kInstantiating) ==
617 std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) {
618 return *m == *requested_module;
619 }));
620
621 if (requested_module->status() == kInstantiating) {
622 module->set_dfs_ancestor_index(
623 std::min(module->dfs_ancestor_index(),
624 requested_module->dfs_ancestor_index()));
625 }
626 }
627
628 Handle<Script> script(module->script(), isolate);
629 Handle<ModuleInfo> module_info(module->info(), isolate);
630
631 // Resolve imports.
632 Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
633 for (int i = 0, n = regular_imports->length(); i < n; ++i) {
634 Handle<ModuleInfoEntry> entry(
635 ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
636 Handle<String> name(String::cast(entry->import_name()), isolate);
637 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
638 ResolveSet resolve_set(zone);
639 Handle<Cell> cell;
640 if (!ResolveImport(isolate, module, name, entry->module_request(), loc,
641 true, &resolve_set)
642 .ToHandle(&cell)) {
643 return false;
644 }
645 module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
646 }
647
648 // Resolve indirect exports.
649 Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
650 for (int i = 0, n = special_exports->length(); i < n; ++i) {
651 Handle<ModuleInfoEntry> entry(
652 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
653 Handle<Object> name(entry->export_name(), isolate);
654 if (name->IsUndefined(isolate)) continue; // Star export.
655 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
656 ResolveSet resolve_set(zone);
657 if (ResolveExport(isolate, module, Handle<String>(),
658 Handle<String>::cast(name), loc, true, &resolve_set)
659 .is_null()) {
660 return false;
661 }
662 }
663
664 return MaybeTransitionComponent(isolate, module, stack, kInstantiated);
665 }
666
Evaluate(Isolate * isolate,Handle<Module> module)667 MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module) {
668 #ifdef DEBUG
669 if (FLAG_trace_module_status) {
670 StdoutStream os;
671 os << "Evaluating module ";
672 module->script()->GetNameOrSourceURL()->Print(os);
673 #ifndef OBJECT_PRINT
674 os << "\n";
675 #endif // OBJECT_PRINT
676 }
677 #endif // DEBUG
678 if (module->status() == kErrored) {
679 isolate->Throw(module->GetException());
680 return MaybeHandle<Object>();
681 }
682 DCHECK_NE(module->status(), kEvaluating);
683 DCHECK_GE(module->status(), kInstantiated);
684 Zone zone(isolate->allocator(), ZONE_NAME);
685
686 ZoneForwardList<Handle<Module>> stack(&zone);
687 unsigned dfs_index = 0;
688 Handle<Object> result;
689 if (!Evaluate(isolate, module, &stack, &dfs_index).ToHandle(&result)) {
690 for (auto& descendant : stack) {
691 DCHECK_EQ(descendant->status(), kEvaluating);
692 descendant->RecordError(isolate);
693 }
694 DCHECK_EQ(module->GetException(), isolate->pending_exception());
695 return MaybeHandle<Object>();
696 }
697 DCHECK_EQ(module->status(), kEvaluated);
698 DCHECK(stack.empty());
699 return result;
700 }
701
Evaluate(Isolate * isolate,Handle<Module> module,ZoneForwardList<Handle<Module>> * stack,unsigned * dfs_index)702 MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module,
703 ZoneForwardList<Handle<Module>>* stack,
704 unsigned* dfs_index) {
705 if (module->status() == kErrored) {
706 isolate->Throw(module->GetException());
707 return MaybeHandle<Object>();
708 }
709 if (module->status() >= kEvaluating) {
710 return isolate->factory()->undefined_value();
711 }
712 DCHECK_EQ(module->status(), kInstantiated);
713 STACK_CHECK(isolate, MaybeHandle<Object>());
714
715 Handle<JSGeneratorObject> generator(JSGeneratorObject::cast(module->code()),
716 isolate);
717 module->set_code(
718 generator->function()->shared()->scope_info()->ModuleDescriptorInfo());
719 module->SetStatus(kEvaluating);
720 module->set_dfs_index(*dfs_index);
721 module->set_dfs_ancestor_index(*dfs_index);
722 stack->push_front(module);
723 (*dfs_index)++;
724
725 // Recursion.
726 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
727 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
728 Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
729 isolate);
730 RETURN_ON_EXCEPTION(
731 isolate, Evaluate(isolate, requested_module, stack, dfs_index), Object);
732
733 DCHECK_GE(requested_module->status(), kEvaluating);
734 DCHECK_NE(requested_module->status(), kErrored);
735 SLOW_DCHECK(
736 // {requested_module} is evaluating iff it's on the {stack}.
737 (requested_module->status() == kEvaluating) ==
738 std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) {
739 return *m == *requested_module;
740 }));
741
742 if (requested_module->status() == kEvaluating) {
743 module->set_dfs_ancestor_index(
744 std::min(module->dfs_ancestor_index(),
745 requested_module->dfs_ancestor_index()));
746 }
747 }
748
749 // Evaluation of module body.
750 Handle<JSFunction> resume(
751 isolate->native_context()->generator_next_internal(), isolate);
752 Handle<Object> result;
753 ASSIGN_RETURN_ON_EXCEPTION(
754 isolate, result, Execution::Call(isolate, resume, generator, 0, nullptr),
755 Object);
756 DCHECK(static_cast<JSIteratorResult*>(JSObject::cast(*result))
757 ->done()
758 ->BooleanValue(isolate));
759
760 CHECK(MaybeTransitionComponent(isolate, module, stack, kEvaluated));
761 return handle(
762 static_cast<JSIteratorResult*>(JSObject::cast(*result))->value(),
763 isolate);
764 }
765
766 namespace {
767
FetchStarExports(Isolate * isolate,Handle<Module> module,Zone * zone,UnorderedModuleSet * visited)768 void FetchStarExports(Isolate* isolate, Handle<Module> module, Zone* zone,
769 UnorderedModuleSet* visited) {
770 DCHECK_GE(module->status(), Module::kInstantiating);
771
772 if (module->module_namespace()->IsJSModuleNamespace()) return; // Shortcut.
773
774 bool cycle = !visited->insert(module).second;
775 if (cycle) return;
776 Handle<ObjectHashTable> exports(module->exports(), isolate);
777 UnorderedStringMap more_exports(zone);
778
779 // TODO(neis): Only allocate more_exports if there are star exports.
780 // Maybe split special_exports into indirect_exports and star_exports.
781
782 ReadOnlyRoots roots(isolate);
783 Handle<FixedArray> special_exports(module->info()->special_exports(),
784 isolate);
785 for (int i = 0, n = special_exports->length(); i < n; ++i) {
786 Handle<ModuleInfoEntry> entry(
787 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
788 if (!entry->export_name()->IsUndefined(roots)) {
789 continue; // Indirect export.
790 }
791
792 Handle<Module> requested_module(
793 Module::cast(module->requested_modules()->get(entry->module_request())),
794 isolate);
795
796 // Recurse.
797 FetchStarExports(isolate, requested_module, zone, visited);
798
799 // Collect all of [requested_module]'s exports that must be added to
800 // [module]'s exports (i.e. to [exports]). We record these in
801 // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
802 // the name to undefined instead of a Cell.
803 Handle<ObjectHashTable> requested_exports(requested_module->exports(),
804 isolate);
805 for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
806 Object* key;
807 if (!requested_exports->ToKey(roots, i, &key)) continue;
808 Handle<String> name(String::cast(key), isolate);
809
810 if (name->Equals(roots.default_string())) continue;
811 if (!exports->Lookup(name)->IsTheHole(roots)) continue;
812
813 Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
814 auto insert_result = more_exports.insert(std::make_pair(name, cell));
815 if (!insert_result.second) {
816 auto it = insert_result.first;
817 if (*it->second == *cell || it->second->IsUndefined(roots)) {
818 // We already recorded this mapping before, or the name is already
819 // known to be ambiguous. In either case, there's nothing to do.
820 } else {
821 DCHECK(it->second->IsCell());
822 // Different star exports provide different cells for this name, hence
823 // mark the name as ambiguous.
824 it->second = roots.undefined_value_handle();
825 }
826 }
827 }
828 }
829
830 // Copy [more_exports] into [exports].
831 for (const auto& elem : more_exports) {
832 if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
833 DCHECK(!elem.first->Equals(ReadOnlyRoots(isolate).default_string()));
834 DCHECK(elem.second->IsCell());
835 exports = ObjectHashTable::Put(exports, elem.first, elem.second);
836 }
837 module->set_exports(*exports);
838 }
839
840 } // anonymous namespace
841
GetModuleNamespace(Isolate * isolate,Handle<Module> module,int module_request)842 Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate,
843 Handle<Module> module,
844 int module_request) {
845 Handle<Module> requested_module(
846 Module::cast(module->requested_modules()->get(module_request)), isolate);
847 return Module::GetModuleNamespace(isolate, requested_module);
848 }
849
GetModuleNamespace(Isolate * isolate,Handle<Module> module)850 Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate,
851 Handle<Module> module) {
852 Handle<HeapObject> object(module->module_namespace(), isolate);
853 ReadOnlyRoots roots(isolate);
854 if (!object->IsUndefined(roots)) {
855 // Namespace object already exists.
856 return Handle<JSModuleNamespace>::cast(object);
857 }
858
859 // Collect the export names.
860 Zone zone(isolate->allocator(), ZONE_NAME);
861 UnorderedModuleSet visited(&zone);
862 FetchStarExports(isolate, module, &zone, &visited);
863 Handle<ObjectHashTable> exports(module->exports(), isolate);
864 ZoneVector<Handle<String>> names(&zone);
865 names.reserve(exports->NumberOfElements());
866 for (int i = 0, n = exports->Capacity(); i < n; ++i) {
867 Object* key;
868 if (!exports->ToKey(roots, i, &key)) continue;
869 names.push_back(handle(String::cast(key), isolate));
870 }
871 DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
872
873 // Sort them alphabetically.
874 std::sort(names.begin(), names.end(),
875 [&isolate](Handle<String> a, Handle<String> b) {
876 return String::Compare(isolate, a, b) ==
877 ComparisonResult::kLessThan;
878 });
879
880 // Create the namespace object (initially empty).
881 Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
882 ns->set_module(*module);
883 module->set_module_namespace(*ns);
884
885 // Create the properties in the namespace object. Transition the object
886 // to dictionary mode so that property addition is faster.
887 PropertyAttributes attr = DONT_DELETE;
888 JSObject::NormalizeProperties(ns, CLEAR_INOBJECT_PROPERTIES,
889 static_cast<int>(names.size()),
890 "JSModuleNamespace");
891 for (const auto& name : names) {
892 JSObject::SetNormalizedProperty(
893 ns, name, Accessors::MakeModuleNamespaceEntryInfo(isolate, name),
894 PropertyDetails(kAccessor, attr, PropertyCellType::kMutable));
895 }
896 JSObject::PreventExtensions(ns, kThrowOnError).ToChecked();
897
898 // Optimize the namespace object as a prototype, for two reasons:
899 // - The object's map is guaranteed not to be shared. ICs rely on this.
900 // - We can store a pointer from the map back to the namespace object.
901 // Turbofan can use this for inlining the access.
902 JSObject::OptimizeAsPrototype(ns);
903
904 Handle<PrototypeInfo> proto_info =
905 Map::GetOrCreatePrototypeInfo(Handle<JSObject>::cast(ns), isolate);
906 proto_info->set_module_namespace(*ns);
907 return ns;
908 }
909
GetExport(Isolate * isolate,Handle<String> name)910 MaybeHandle<Object> JSModuleNamespace::GetExport(Isolate* isolate,
911 Handle<String> name) {
912 Handle<Object> object(module()->exports()->Lookup(name), isolate);
913 if (object->IsTheHole(isolate)) {
914 return isolate->factory()->undefined_value();
915 }
916
917 Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
918 if (value->IsTheHole(isolate)) {
919 THROW_NEW_ERROR(
920 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
921 }
922
923 return value;
924 }
925
GetPropertyAttributes(LookupIterator * it)926 Maybe<PropertyAttributes> JSModuleNamespace::GetPropertyAttributes(
927 LookupIterator* it) {
928 Handle<JSModuleNamespace> object = it->GetHolder<JSModuleNamespace>();
929 Handle<String> name = Handle<String>::cast(it->GetName());
930 DCHECK_EQ(it->state(), LookupIterator::ACCESSOR);
931
932 Isolate* isolate = it->isolate();
933
934 Handle<Object> lookup(object->module()->exports()->Lookup(name), isolate);
935 if (lookup->IsTheHole(isolate)) {
936 return Just(ABSENT);
937 }
938
939 Handle<Object> value(Handle<Cell>::cast(lookup)->value(), isolate);
940 if (value->IsTheHole(isolate)) {
941 isolate->Throw(*isolate->factory()->NewReferenceError(
942 MessageTemplate::kNotDefined, name));
943 return Nothing<PropertyAttributes>();
944 }
945
946 return Just(it->property_attributes());
947 }
948
949 } // namespace internal
950 } // namespace v8
951