LCOV - code coverage report
Current view: top level - src/ast - modules.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 127 128 99.2 %
Date: 2017-04-26 Functions: 17 17 100.0 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/ast/modules.h"
       6             : #include "src/ast/ast-value-factory.h"
       7             : #include "src/ast/scopes.h"
       8             : #include "src/objects-inl.h"
       9             : #include "src/objects/module-info.h"
      10             : #include "src/pending-compilation-error-handler.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : 
      15         709 : void ModuleDescriptor::AddImport(
      16             :     const AstRawString* import_name, const AstRawString* local_name,
      17             :     const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
      18         709 :   Entry* entry = new (zone) Entry(loc);
      19         709 :   entry->local_name = local_name;
      20         709 :   entry->import_name = import_name;
      21         709 :   entry->module_request = AddModuleRequest(module_request);
      22             :   AddRegularImport(entry);
      23         709 : }
      24             : 
      25             : 
      26         116 : void ModuleDescriptor::AddStarImport(
      27             :     const AstRawString* local_name, const AstRawString* module_request,
      28             :     Scanner::Location loc, Zone* zone) {
      29         116 :   Entry* entry = new (zone) Entry(loc);
      30         116 :   entry->local_name = local_name;
      31         116 :   entry->module_request = AddModuleRequest(module_request);
      32             :   AddNamespaceImport(entry, zone);
      33         116 : }
      34             : 
      35         144 : void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request) {
      36         144 :   AddModuleRequest(module_request);
      37         144 : }
      38             : 
      39             : 
      40        1639 : void ModuleDescriptor::AddExport(
      41             :     const AstRawString* local_name, const AstRawString* export_name,
      42             :     Scanner::Location loc, Zone* zone) {
      43        1639 :   Entry* entry = new (zone) Entry(loc);
      44        1639 :   entry->export_name = export_name;
      45        1639 :   entry->local_name = local_name;
      46             :   AddRegularExport(entry);
      47        1639 : }
      48             : 
      49             : 
      50         112 : void ModuleDescriptor::AddExport(
      51             :     const AstRawString* import_name, const AstRawString* export_name,
      52             :     const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
      53             :   DCHECK_NOT_NULL(import_name);
      54             :   DCHECK_NOT_NULL(export_name);
      55         112 :   Entry* entry = new (zone) Entry(loc);
      56         112 :   entry->export_name = export_name;
      57         112 :   entry->import_name = import_name;
      58         112 :   entry->module_request = AddModuleRequest(module_request);
      59             :   AddSpecialExport(entry, zone);
      60         112 : }
      61             : 
      62             : 
      63         122 : void ModuleDescriptor::AddStarExport(
      64             :     const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
      65         122 :   Entry* entry = new (zone) Entry(loc);
      66         122 :   entry->module_request = AddModuleRequest(module_request);
      67             :   AddSpecialExport(entry, zone);
      68         122 : }
      69             : 
      70             : namespace {
      71             : 
      72        1488 : Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) {
      73             :   return (s == nullptr)
      74             :              ? Handle<Object>::cast(isolate->factory()->undefined_value())
      75        2718 :              : Handle<Object>::cast(s->string());
      76             : }
      77             : 
      78        8598 : const AstRawString* FromStringOrUndefined(Isolate* isolate,
      79             :                                           AstValueFactory* avfactory,
      80             :                                           Handle<Object> object) {
      81        8598 :   if (object->IsUndefined(isolate)) return nullptr;
      82        5488 :   return avfactory->GetString(Handle<String>::cast(object));
      83             : }
      84             : 
      85             : }  // namespace
      86             : 
      87         906 : Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
      88             :     Isolate* isolate) const {
      89         906 :   CHECK(Smi::IsValid(module_request));  // TODO(neis): Check earlier?
      90             :   return ModuleInfoEntry::New(
      91             :       isolate, ToStringOrUndefined(isolate, export_name),
      92             :       ToStringOrUndefined(isolate, local_name),
      93             :       ToStringOrUndefined(isolate, import_name), module_request, cell_index,
      94        3624 :       location.beg_pos, location.end_pos);
      95             : }
      96             : 
      97        2866 : ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize(
      98        2866 :     Isolate* isolate, AstValueFactory* avfactory,
      99             :     Handle<ModuleInfoEntry> entry) {
     100             :   Entry* result = new (avfactory->zone()) Entry(Scanner::Location::invalid());
     101             :   result->export_name = FromStringOrUndefined(
     102        2866 :       isolate, avfactory, handle(entry->export_name(), isolate));
     103             :   result->local_name = FromStringOrUndefined(
     104        2866 :       isolate, avfactory, handle(entry->local_name(), isolate));
     105             :   result->import_name = FromStringOrUndefined(
     106        2866 :       isolate, avfactory, handle(entry->import_name(), isolate));
     107        2866 :   result->module_request = entry->module_request();
     108        2866 :   result->cell_index = entry->cell_index();
     109        2866 :   return result;
     110             : }
     111             : 
     112        6456 : Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate,
     113             :                                                              Zone* zone) const {
     114             :   // We serialize regular exports in a way that lets us later iterate over their
     115             :   // local names and for each local name immediately access all its export
     116             :   // names.  (Regular exports have neither import name nor module request.)
     117             : 
     118             :   ZoneVector<Handle<Object>> data(
     119        6456 :       ModuleInfo::kRegularExportLength * regular_exports_.size(), zone);
     120             :   int index = 0;
     121             : 
     122       14097 :   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
     123             :     // Find out how many export names this local name has.
     124             :     auto next = it;
     125             :     int count = 0;
     126        1282 :     do {
     127             :       DCHECK_EQ(it->second->local_name, next->second->local_name);
     128             :       DCHECK_EQ(it->second->cell_index, next->second->cell_index);
     129             :       ++next;
     130        1282 :       ++count;
     131        1282 :     } while (next != regular_exports_.end() && next->first == it->first);
     132             : 
     133        1185 :     Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(count);
     134        1185 :     data[index + ModuleInfo::kRegularExportLocalNameOffset] =
     135        1185 :         it->second->local_name->string();
     136        1185 :     data[index + ModuleInfo::kRegularExportCellIndexOffset] =
     137        2370 :         handle(Smi::FromInt(it->second->cell_index), isolate);
     138        2370 :     data[index + ModuleInfo::kRegularExportExportNamesOffset] = export_names;
     139        1185 :     index += ModuleInfo::kRegularExportLength;
     140             : 
     141             :     // Collect the export names.
     142             :     int i = 0;
     143        3652 :     for (; it != next; ++it) {
     144        3846 :       export_names->set(i++, *it->second->export_name->string());
     145             :     }
     146             :     DCHECK_EQ(i, count);
     147             : 
     148             :     // Continue with the next distinct key.
     149             :     DCHECK(it == next);
     150             :   }
     151             :   DCHECK_LE(index, static_cast<int>(data.size()));
     152        6456 :   data.resize(index);
     153             : 
     154             :   // We cannot create the FixedArray earlier because we only now know the
     155             :   // precise size.
     156        6456 :   Handle<FixedArray> result = isolate->factory()->NewFixedArray(index);
     157       10011 :   for (int i = 0; i < index; ++i) {
     158        7110 :     result->set(i, *data[i]);
     159             :   }
     160        6456 :   return result;
     161             : }
     162             : 
     163        5406 : void ModuleDescriptor::DeserializeRegularExports(
     164        3746 :     Isolate* isolate, AstValueFactory* avfactory,
     165             :     Handle<ModuleInfo> module_info) {
     166        8866 :   for (int i = 0, count = module_info->RegularExportCount(); i < count; ++i) {
     167        3460 :     Handle<String> local_name(module_info->RegularExportLocalName(i), isolate);
     168        3460 :     int cell_index = module_info->RegularExportCellIndex(i);
     169             :     Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
     170        3460 :                                     isolate);
     171             : 
     172        7206 :     for (int j = 0, length = export_names->length(); j < length; ++j) {
     173             :       Handle<String> export_name(String::cast(export_names->get(j)), isolate);
     174             : 
     175             :       Entry* entry =
     176             :           new (avfactory->zone()) Entry(Scanner::Location::invalid());
     177        3746 :       entry->local_name = avfactory->GetString(local_name);
     178        3746 :       entry->export_name = avfactory->GetString(export_name);
     179        3746 :       entry->cell_index = cell_index;
     180             : 
     181             :       AddRegularExport(entry);
     182             :     }
     183             :   }
     184        5406 : }
     185             : 
     186        7410 : void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
     187       16381 :   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
     188        1561 :     Entry* entry = it->second;
     189             :     DCHECK_NOT_NULL(entry->local_name);
     190        1561 :     auto import = regular_imports_.find(entry->local_name);
     191        1561 :     if (import != regular_imports_.end()) {
     192             :       // Found an indirect export.  Patch export entry and move it from regular
     193             :       // to special.
     194             :       DCHECK_NULL(entry->import_name);
     195             :       DCHECK_LT(entry->module_request, 0);
     196             :       DCHECK_NOT_NULL(import->second->import_name);
     197             :       DCHECK_LE(0, import->second->module_request);
     198             :       DCHECK_LT(import->second->module_request,
     199             :                 static_cast<int>(module_requests_.size()));
     200          51 :       entry->import_name = import->second->import_name;
     201          51 :       entry->module_request = import->second->module_request;
     202             :       // Hack: When the indirect export cannot be resolved, we want the error
     203             :       // message to point at the import statement, not at the export statement.
     204             :       // Therefore we overwrite [entry]'s location here.  Note that Validate()
     205             :       // has already checked for duplicate exports, so it's guaranteed that we
     206             :       // won't need to report any error pointing at the (now lost) export
     207             :       // location.
     208          51 :       entry->location = import->second->location;
     209          51 :       entry->local_name = nullptr;
     210             :       AddSpecialExport(entry, zone);
     211             :       it = regular_exports_.erase(it);
     212             :     } else {
     213             :       it++;
     214             :     }
     215             :   }
     216        7410 : }
     217             : 
     218        1084 : ModuleDescriptor::CellIndexKind ModuleDescriptor::GetCellIndexKind(
     219             :     int cell_index) {
     220        1084 :   if (cell_index > 0) return kExport;
     221         280 :   if (cell_index < 0) return kImport;
     222           0 :   return kInvalid;
     223             : }
     224             : 
     225        7410 : void ModuleDescriptor::AssignCellIndices() {
     226             :   int export_index = 1;
     227       16227 :   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
     228        1407 :     auto current_key = it->first;
     229             :     // This local name may be exported under multiple export names.  Assign the
     230             :     // same index to each such entry.
     231        1510 :     do {
     232        1510 :       Entry* entry = it->second;
     233             :       DCHECK_NOT_NULL(entry->local_name);
     234             :       DCHECK_NULL(entry->import_name);
     235             :       DCHECK_LT(entry->module_request, 0);
     236             :       DCHECK_EQ(entry->cell_index, 0);
     237        1510 :       entry->cell_index = export_index;
     238             :       it++;
     239        1510 :     } while (it != regular_exports_.end() && it->first == current_key);
     240        1407 :     export_index++;
     241             :   }
     242             : 
     243             :   int import_index = -1;
     244       15529 :   for (const auto& elem : regular_imports_) {
     245         709 :     Entry* entry = elem.second;
     246             :     DCHECK_NOT_NULL(entry->local_name);
     247             :     DCHECK_NOT_NULL(entry->import_name);
     248             :     DCHECK_LE(0, entry->module_request);
     249             :     DCHECK_EQ(entry->cell_index, 0);
     250         709 :     entry->cell_index = import_index;
     251         709 :     import_index--;
     252             :   }
     253        7410 : }
     254             : 
     255             : namespace {
     256             : 
     257        1751 : const ModuleDescriptor::Entry* BetterDuplicate(
     258             :     const ModuleDescriptor::Entry* candidate,
     259             :     ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*>& export_names,
     260             :     const ModuleDescriptor::Entry* current_duplicate) {
     261             :   DCHECK_NOT_NULL(candidate->export_name);
     262             :   DCHECK(candidate->location.IsValid());
     263             :   auto insert_result =
     264        3502 :       export_names.insert(std::make_pair(candidate->export_name, candidate));
     265        1751 :   if (insert_result.second) return current_duplicate;
     266          30 :   if (current_duplicate == nullptr) {
     267          30 :     current_duplicate = insert_result.first->second;
     268             :   }
     269          30 :   return (candidate->location.beg_pos > current_duplicate->location.beg_pos)
     270             :              ? candidate
     271          30 :              : current_duplicate;
     272             : }
     273             : 
     274             : }  // namespace
     275             : 
     276        7458 : const ModuleDescriptor::Entry* ModuleDescriptor::FindDuplicateExport(
     277             :     Zone* zone) const {
     278             :   const ModuleDescriptor::Entry* duplicate = nullptr;
     279             :   ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*> export_names(
     280             :       zone);
     281       16555 :   for (const auto& elem : regular_exports_) {
     282        1639 :     duplicate = BetterDuplicate(elem.second, export_names, duplicate);
     283             :   }
     284       15150 :   for (auto entry : special_exports_) {
     285         234 :     if (entry->export_name == nullptr) continue;  // Star export.
     286         112 :     duplicate = BetterDuplicate(entry, export_names, duplicate);
     287             :   }
     288        7458 :   return duplicate;
     289             : }
     290             : 
     291        7458 : bool ModuleDescriptor::Validate(ModuleScope* module_scope,
     292             :                                 PendingCompilationErrorHandler* error_handler,
     293             :                                 Zone* zone) {
     294             :   DCHECK_EQ(this, module_scope->module());
     295             :   DCHECK_NOT_NULL(error_handler);
     296             : 
     297             :   // Report error iff there are duplicate exports.
     298             :   {
     299        7458 :     const Entry* entry = FindDuplicateExport(zone);
     300        7458 :     if (entry != nullptr) {
     301             :       error_handler->ReportMessageAt(
     302             :           entry->location.beg_pos, entry->location.end_pos,
     303          30 :           MessageTemplate::kDuplicateExport, entry->export_name);
     304             :       return false;
     305             :     }
     306             :   }
     307             : 
     308             :   // Report error iff there are exports of non-existent local names.
     309       16417 :   for (const auto& elem : regular_exports_) {
     310        1579 :     const Entry* entry = elem.second;
     311             :     DCHECK_NOT_NULL(entry->local_name);
     312        1579 :     if (module_scope->LookupLocal(entry->local_name) == nullptr) {
     313             :       error_handler->ReportMessageAt(
     314             :           entry->location.beg_pos, entry->location.end_pos,
     315          18 :           MessageTemplate::kModuleExportUndefined, entry->local_name);
     316             :       return false;
     317             :     }
     318             :   }
     319             : 
     320        7410 :   MakeIndirectExportsExplicit(zone);
     321        7410 :   AssignCellIndices();
     322        7410 :   return true;
     323             : }
     324             : 
     325             : }  // namespace internal
     326             : }  // namespace v8

Generated by: LCOV version 1.10