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 { 24 V8_INLINE size_t operator()(Handle<Module> module) const { 25 return module->hash(); 26 } 27 }; 28 29 struct ModuleHandleEqual { 30 V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const { 31 return *lhs == *rhs; 32 } 33 }; 34 35 struct StringHandleHash { 36 V8_INLINE size_t operator()(Handle<String> string) const { 37 return string->Hash(); 38 } 39 }; 40 41 struct StringHandleEqual { 42 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: 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: 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: 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: 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 103 Zone* zone() const { return zone_; } 104 105 private: 106 Zone* zone_; 107 }; 108 109 namespace { 110 111 int ExportIndex(int cell_index) { 112 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), 113 ModuleDescriptor::kExport); 114 return cell_index - 1; 115 } 116 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 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 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 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 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 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 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 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 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 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 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 269 Object* Module::GetException() { 270 DisallowHeapAllocation no_alloc; 271 DCHECK_EQ(status(), Module::kErrored); 272 DCHECK(!exception()->IsTheHole()); 273 return exception(); 274 } 275 276 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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