LCOV - code coverage report
Current view: top level - src/ast - modules.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 142 142 100.0 %
Date: 2019-01-20 Functions: 21 21 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-inl.h"
      10             : #include "src/pending-compilation-error-handler.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : 
      15      299102 : bool ModuleDescriptor::AstRawStringComparer::operator()(
      16      297598 :     const AstRawString* lhs, const AstRawString* rhs) const {
      17             :   // Fast path for equal pointers: a pointer is not strictly less than itself.
      18      299102 :   if (lhs == rhs) return false;
      19             : 
      20             :   // Order by contents (ordering by hash is unstable across runs).
      21      297598 :   if (lhs->is_one_byte() != rhs->is_one_byte()) {
      22             :     return lhs->is_one_byte();
      23             :   }
      24      297598 :   if (lhs->byte_length() != rhs->byte_length()) {
      25       36449 :     return lhs->byte_length() < rhs->byte_length();
      26             :   }
      27      522298 :   return memcmp(lhs->raw_data(), rhs->raw_data(), lhs->byte_length()) < 0;
      28             : }
      29             : 
      30        2064 : void ModuleDescriptor::AddImport(const AstRawString* import_name,
      31             :                                  const AstRawString* local_name,
      32             :                                  const AstRawString* module_request,
      33             :                                  const Scanner::Location loc,
      34        2064 :                                  const Scanner::Location specifier_loc,
      35             :                                  Zone* zone) {
      36        2064 :   Entry* entry = new (zone) Entry(loc);
      37        2064 :   entry->local_name = local_name;
      38        2064 :   entry->import_name = import_name;
      39        2064 :   entry->module_request = AddModuleRequest(module_request, specifier_loc);
      40             :   AddRegularImport(entry);
      41        2064 : }
      42             : 
      43         245 : void ModuleDescriptor::AddStarImport(const AstRawString* local_name,
      44             :                                      const AstRawString* module_request,
      45             :                                      const Scanner::Location loc,
      46         245 :                                      const Scanner::Location specifier_loc,
      47             :                                      Zone* zone) {
      48         245 :   Entry* entry = new (zone) Entry(loc);
      49         245 :   entry->local_name = local_name;
      50         245 :   entry->module_request = AddModuleRequest(module_request, specifier_loc);
      51             :   AddNamespaceImport(entry, zone);
      52         245 : }
      53             : 
      54         135 : void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request,
      55         135 :                                       const Scanner::Location specifier_loc) {
      56         135 :   AddModuleRequest(module_request, specifier_loc);
      57         135 : }
      58             : 
      59             : 
      60       18900 : void ModuleDescriptor::AddExport(
      61             :     const AstRawString* local_name, const AstRawString* export_name,
      62             :     Scanner::Location loc, Zone* zone) {
      63       18900 :   Entry* entry = new (zone) Entry(loc);
      64       18900 :   entry->export_name = export_name;
      65       18900 :   entry->local_name = local_name;
      66             :   AddRegularExport(entry);
      67       18900 : }
      68             : 
      69         100 : void ModuleDescriptor::AddExport(const AstRawString* import_name,
      70             :                                  const AstRawString* export_name,
      71             :                                  const AstRawString* module_request,
      72             :                                  const Scanner::Location loc,
      73         100 :                                  const Scanner::Location specifier_loc,
      74             :                                  Zone* zone) {
      75             :   DCHECK_NOT_NULL(import_name);
      76             :   DCHECK_NOT_NULL(export_name);
      77         100 :   Entry* entry = new (zone) Entry(loc);
      78         100 :   entry->export_name = export_name;
      79         100 :   entry->import_name = import_name;
      80         100 :   entry->module_request = AddModuleRequest(module_request, specifier_loc);
      81             :   AddSpecialExport(entry, zone);
      82         100 : }
      83             : 
      84         105 : void ModuleDescriptor::AddStarExport(const AstRawString* module_request,
      85             :                                      const Scanner::Location loc,
      86         105 :                                      const Scanner::Location specifier_loc,
      87             :                                      Zone* zone) {
      88         105 :   Entry* entry = new (zone) Entry(loc);
      89         105 :   entry->module_request = AddModuleRequest(module_request, specifier_loc);
      90             :   AddSpecialExport(entry, zone);
      91         105 : }
      92             : 
      93             : namespace {
      94             : 
      95        3325 : Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) {
      96             :   return (s == nullptr)
      97             :              ? Handle<Object>::cast(isolate->factory()->undefined_value())
      98        4338 :              : Handle<Object>::cast(s->string());
      99             : }
     100             : 
     101        8328 : const AstRawString* FromStringOrUndefined(Isolate* isolate,
     102             :                                           AstValueFactory* avfactory,
     103             :                                           Handle<Object> object) {
     104       16656 :   if (object->IsUndefined(isolate)) return nullptr;
     105        5257 :   return avfactory->GetString(Handle<String>::cast(object));
     106             : }
     107             : 
     108             : }  // namespace
     109             : 
     110         723 : Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
     111             :     Isolate* isolate) const {
     112         723 :   CHECK(Smi::IsValid(module_request));  // TODO(neis): Check earlier?
     113             :   return ModuleInfoEntry::New(
     114             :       isolate, ToStringOrUndefined(isolate, export_name),
     115             :       ToStringOrUndefined(isolate, local_name),
     116             :       ToStringOrUndefined(isolate, import_name), module_request, cell_index,
     117         723 :       location.beg_pos, location.end_pos);
     118             : }
     119             : 
     120        2776 : ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize(
     121        2776 :     Isolate* isolate, AstValueFactory* avfactory,
     122             :     Handle<ModuleInfoEntry> entry) {
     123             :   Entry* result = new (avfactory->zone()) Entry(Scanner::Location::invalid());
     124             :   result->export_name = FromStringOrUndefined(
     125        5552 :       isolate, avfactory, handle(entry->export_name(), isolate));
     126             :   result->local_name = FromStringOrUndefined(
     127        5552 :       isolate, avfactory, handle(entry->local_name(), isolate));
     128             :   result->import_name = FromStringOrUndefined(
     129        5552 :       isolate, avfactory, handle(entry->import_name(), isolate));
     130        2776 :   result->module_request = entry->module_request();
     131        2776 :   result->cell_index = entry->cell_index();
     132        2776 :   return result;
     133             : }
     134             : 
     135        1098 : Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate,
     136             :                                                              Zone* zone) const {
     137             :   // We serialize regular exports in a way that lets us later iterate over their
     138             :   // local names and for each local name immediately access all its export
     139             :   // names.  (Regular exports have neither import name nor module request.)
     140             : 
     141             :   ZoneVector<Handle<Object>> data(
     142        1098 :       ModuleInfo::kRegularExportLength * regular_exports_.size(), zone);
     143             :   int index = 0;
     144             : 
     145       19744 :   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
     146             :     // Find out how many export names this local name has.
     147             :     auto next = it;
     148             :     int count = 0;
     149       17623 :     do {
     150             :       DCHECK_EQ(it->second->local_name, next->second->local_name);
     151             :       DCHECK_EQ(it->second->cell_index, next->second->cell_index);
     152             :       ++next;
     153       17623 :       ++count;
     154       17623 :     } while (next != regular_exports_.end() && next->first == it->first);
     155             : 
     156       17548 :     Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(count);
     157       17548 :     data[index + ModuleInfo::kRegularExportLocalNameOffset] =
     158       17548 :         it->second->local_name->string();
     159       17548 :     data[index + ModuleInfo::kRegularExportCellIndexOffset] =
     160       35096 :         handle(Smi::FromInt(it->second->cell_index), isolate);
     161       35096 :     data[index + ModuleInfo::kRegularExportExportNamesOffset] = export_names;
     162       17548 :     index += ModuleInfo::kRegularExportLength;
     163             : 
     164             :     // Collect the export names.
     165             :     int i = 0;
     166       52719 :     for (; it != next; ++it) {
     167       52869 :       export_names->set(i++, *it->second->export_name->string());
     168             :     }
     169             :     DCHECK_EQ(i, count);
     170             : 
     171             :     // Continue with the next distinct key.
     172             :     DCHECK(it == next);
     173             :   }
     174             :   DCHECK_LE(index, static_cast<int>(data.size()));
     175        1098 :   data.resize(index);
     176             : 
     177             :   // We cannot create the FixedArray earlier because we only now know the
     178             :   // precise size.
     179        1098 :   Handle<FixedArray> result = isolate->factory()->NewFixedArray(index);
     180       53742 :   for (int i = 0; i < index; ++i) {
     181      105288 :     result->set(i, *data[i]);
     182             :   }
     183        1098 :   return result;
     184             : }
     185             : 
     186        3217 : void ModuleDescriptor::DeserializeRegularExports(
     187        3860 :     Isolate* isolate, AstValueFactory* avfactory,
     188             :     Handle<ModuleInfo> module_info) {
     189        6971 :   for (int i = 0, count = module_info->RegularExportCount(); i < count; ++i) {
     190        7508 :     Handle<String> local_name(module_info->RegularExportLocalName(i), isolate);
     191        3754 :     int cell_index = module_info->RegularExportCellIndex(i);
     192             :     Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
     193        7508 :                                     isolate);
     194             : 
     195        7614 :     for (int j = 0, length = export_names->length(); j < length; ++j) {
     196             :       Handle<String> export_name(String::cast(export_names->get(j)), isolate);
     197             : 
     198             :       Entry* entry =
     199             :           new (avfactory->zone()) Entry(Scanner::Location::invalid());
     200        3860 :       entry->local_name = avfactory->GetString(local_name);
     201        3860 :       entry->export_name = avfactory->GetString(export_name);
     202        3860 :       entry->cell_index = cell_index;
     203             : 
     204             :       AddRegularExport(entry);
     205             :     }
     206             :   }
     207        3217 : }
     208             : 
     209       35571 : void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
     210       89977 :   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
     211       18835 :     Entry* entry = it->second;
     212             :     DCHECK_NOT_NULL(entry->local_name);
     213       18835 :     auto import = regular_imports_.find(entry->local_name);
     214       18835 :     if (import != regular_imports_.end()) {
     215             :       // Found an indirect export.  Patch export entry and move it from regular
     216             :       // to special.
     217             :       DCHECK_NULL(entry->import_name);
     218             :       DCHECK_LT(entry->module_request, 0);
     219             :       DCHECK_NOT_NULL(import->second->import_name);
     220             :       DCHECK_LE(0, import->second->module_request);
     221             :       DCHECK_LT(import->second->module_request,
     222             :                 static_cast<int>(module_requests_.size()));
     223          40 :       entry->import_name = import->second->import_name;
     224          40 :       entry->module_request = import->second->module_request;
     225             :       // Hack: When the indirect export cannot be resolved, we want the error
     226             :       // message to point at the import statement, not at the export statement.
     227             :       // Therefore we overwrite [entry]'s location here.  Note that Validate()
     228             :       // has already checked for duplicate exports, so it's guaranteed that we
     229             :       // won't need to report any error pointing at the (now lost) export
     230             :       // location.
     231          40 :       entry->location = import->second->location;
     232          40 :       entry->local_name = nullptr;
     233             :       AddSpecialExport(entry, zone);
     234             :       it = regular_exports_.erase(it);
     235             :     } else {
     236             :       it++;
     237             :     }
     238             :   }
     239       35571 : }
     240             : 
     241       10039 : ModuleDescriptor::CellIndexKind ModuleDescriptor::GetCellIndexKind(
     242             :     int cell_index) {
     243       10039 :   if (cell_index > 0) return kExport;
     244        1398 :   if (cell_index < 0) return kImport;
     245           5 :   return kInvalid;
     246             : }
     247             : 
     248       35571 : void ModuleDescriptor::AssignCellIndices() {
     249             :   int export_index = 1;
     250       89852 :   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
     251       18710 :     auto current_key = it->first;
     252             :     // This local name may be exported under multiple export names.  Assign the
     253             :     // same index to each such entry.
     254       18795 :     do {
     255       18795 :       Entry* entry = it->second;
     256             :       DCHECK_NOT_NULL(entry->local_name);
     257             :       DCHECK_NULL(entry->import_name);
     258             :       DCHECK_LT(entry->module_request, 0);
     259             :       DCHECK_EQ(entry->cell_index, 0);
     260       18795 :       entry->cell_index = export_index;
     261             :       it++;
     262       18795 :     } while (it != regular_exports_.end() && it->first == current_key);
     263       18710 :     export_index++;
     264             :   }
     265             : 
     266             :   int import_index = -1;
     267       73206 :   for (const auto& elem : regular_imports_) {
     268        2064 :     Entry* entry = elem.second;
     269             :     DCHECK_NOT_NULL(entry->local_name);
     270             :     DCHECK_NOT_NULL(entry->import_name);
     271             :     DCHECK_LE(0, entry->module_request);
     272             :     DCHECK_EQ(entry->cell_index, 0);
     273        2064 :     entry->cell_index = import_index;
     274        2064 :     import_index--;
     275             :   }
     276       35571 : }
     277             : 
     278             : namespace {
     279             : 
     280       19000 : const ModuleDescriptor::Entry* BetterDuplicate(
     281             :     const ModuleDescriptor::Entry* candidate,
     282             :     ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*>& export_names,
     283             :     const ModuleDescriptor::Entry* current_duplicate) {
     284             :   DCHECK_NOT_NULL(candidate->export_name);
     285             :   DCHECK(candidate->location.IsValid());
     286             :   auto insert_result =
     287       38000 :       export_names.insert(std::make_pair(candidate->export_name, candidate));
     288       19000 :   if (insert_result.second) return current_duplicate;
     289          25 :   if (current_duplicate == nullptr) {
     290          25 :     current_duplicate = insert_result.first->second;
     291             :   }
     292          25 :   return (candidate->location.beg_pos > current_duplicate->location.beg_pos)
     293             :              ? candidate
     294          25 :              : current_duplicate;
     295             : }
     296             : 
     297             : }  // namespace
     298             : 
     299       35611 : const ModuleDescriptor::Entry* ModuleDescriptor::FindDuplicateExport(
     300             :     Zone* zone) const {
     301             :   const ModuleDescriptor::Entry* duplicate = nullptr;
     302             :   ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*> export_names(
     303             :       zone);
     304       90122 :   for (const auto& elem : regular_exports_) {
     305       18900 :     duplicate = BetterDuplicate(elem.second, export_names, duplicate);
     306             :   }
     307       71427 :   for (auto entry : special_exports_) {
     308         205 :     if (entry->export_name == nullptr) continue;  // Star export.
     309         100 :     duplicate = BetterDuplicate(entry, export_names, duplicate);
     310             :   }
     311       35611 :   return duplicate;
     312             : }
     313             : 
     314       35611 : bool ModuleDescriptor::Validate(ModuleScope* module_scope,
     315             :                                 PendingCompilationErrorHandler* error_handler,
     316             :                                 Zone* zone) {
     317             :   DCHECK_EQ(this, module_scope->module());
     318             :   DCHECK_NOT_NULL(error_handler);
     319             : 
     320             :   // Report error iff there are duplicate exports.
     321             :   {
     322       35611 :     const Entry* entry = FindDuplicateExport(zone);
     323       35611 :     if (entry != nullptr) {
     324             :       error_handler->ReportMessageAt(
     325             :           entry->location.beg_pos, entry->location.end_pos,
     326          25 :           MessageTemplate::kDuplicateExport, entry->export_name);
     327          25 :       return false;
     328             :     }
     329             :   }
     330             : 
     331             :   // Report error iff there are exports of non-existent local names.
     332       90007 :   for (const auto& elem : regular_exports_) {
     333       18850 :     const Entry* entry = elem.second;
     334             :     DCHECK_NOT_NULL(entry->local_name);
     335       37700 :     if (module_scope->LookupLocal(entry->local_name) == nullptr) {
     336             :       error_handler->ReportMessageAt(
     337             :           entry->location.beg_pos, entry->location.end_pos,
     338          15 :           MessageTemplate::kModuleExportUndefined, entry->local_name);
     339             :       return false;
     340             :     }
     341             :   }
     342             : 
     343       35571 :   MakeIndirectExportsExplicit(zone);
     344       35571 :   AssignCellIndices();
     345       35571 :   return true;
     346             : }
     347             : 
     348             : }  // namespace internal
     349      183867 : }  // namespace v8

Generated by: LCOV version 1.10