LCOV - code coverage report
Current view: top level - src/objects - module.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 238 254 93.7 %
Date: 2017-10-20 Functions: 25 26 96.2 %

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

Generated by: LCOV version 1.10