Home | History | Annotate | Download | only in ast
      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 void ModuleDescriptor::AddImport(
     16     const AstRawString* import_name, const AstRawString* local_name,
     17     const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
     18   Entry* entry = new (zone) Entry(loc);
     19   entry->local_name = local_name;
     20   entry->import_name = import_name;
     21   entry->module_request = AddModuleRequest(module_request);
     22   AddRegularImport(entry);
     23 }
     24 
     25 
     26 void ModuleDescriptor::AddStarImport(
     27     const AstRawString* local_name, const AstRawString* module_request,
     28     Scanner::Location loc, Zone* zone) {
     29   Entry* entry = new (zone) Entry(loc);
     30   entry->local_name = local_name;
     31   entry->module_request = AddModuleRequest(module_request);
     32   AddNamespaceImport(entry, zone);
     33 }
     34 
     35 void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request) {
     36   AddModuleRequest(module_request);
     37 }
     38 
     39 
     40 void ModuleDescriptor::AddExport(
     41     const AstRawString* local_name, const AstRawString* export_name,
     42     Scanner::Location loc, Zone* zone) {
     43   Entry* entry = new (zone) Entry(loc);
     44   entry->export_name = export_name;
     45   entry->local_name = local_name;
     46   AddRegularExport(entry);
     47 }
     48 
     49 
     50 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   Entry* entry = new (zone) Entry(loc);
     56   entry->export_name = export_name;
     57   entry->import_name = import_name;
     58   entry->module_request = AddModuleRequest(module_request);
     59   AddSpecialExport(entry, zone);
     60 }
     61 
     62 
     63 void ModuleDescriptor::AddStarExport(
     64     const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
     65   Entry* entry = new (zone) Entry(loc);
     66   entry->module_request = AddModuleRequest(module_request);
     67   AddSpecialExport(entry, zone);
     68 }
     69 
     70 namespace {
     71 
     72 Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) {
     73   return (s == nullptr)
     74              ? Handle<Object>::cast(isolate->factory()->undefined_value())
     75              : Handle<Object>::cast(s->string());
     76 }
     77 
     78 const AstRawString* FromStringOrUndefined(Isolate* isolate,
     79                                           AstValueFactory* avfactory,
     80                                           Handle<Object> object) {
     81   if (object->IsUndefined(isolate)) return nullptr;
     82   return avfactory->GetString(Handle<String>::cast(object));
     83 }
     84 
     85 }  // namespace
     86 
     87 Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
     88     Isolate* isolate) const {
     89   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       location.beg_pos, location.end_pos);
     95 }
     96 
     97 ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize(
     98     Isolate* isolate, AstValueFactory* avfactory,
     99     Handle<ModuleInfoEntry> entry) {
    100   Entry* result = new (avfactory->zone()) Entry(Scanner::Location::invalid());
    101   result->export_name = FromStringOrUndefined(
    102       isolate, avfactory, handle(entry->export_name(), isolate));
    103   result->local_name = FromStringOrUndefined(
    104       isolate, avfactory, handle(entry->local_name(), isolate));
    105   result->import_name = FromStringOrUndefined(
    106       isolate, avfactory, handle(entry->import_name(), isolate));
    107   result->module_request = entry->module_request();
    108   result->cell_index = entry->cell_index();
    109   return result;
    110 }
    111 
    112 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       ModuleInfo::kRegularExportLength * regular_exports_.size(), zone);
    120   int index = 0;
    121 
    122   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     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       ++count;
    131     } while (next != regular_exports_.end() && next->first == it->first);
    132 
    133     Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(count);
    134     data[index + ModuleInfo::kRegularExportLocalNameOffset] =
    135         it->second->local_name->string();
    136     data[index + ModuleInfo::kRegularExportCellIndexOffset] =
    137         handle(Smi::FromInt(it->second->cell_index), isolate);
    138     data[index + ModuleInfo::kRegularExportExportNamesOffset] = export_names;
    139     index += ModuleInfo::kRegularExportLength;
    140 
    141     // Collect the export names.
    142     int i = 0;
    143     for (; it != next; ++it) {
    144       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   data.resize(index);
    153 
    154   // We cannot create the FixedArray earlier because we only now know the
    155   // precise size.
    156   Handle<FixedArray> result = isolate->factory()->NewFixedArray(index);
    157   for (int i = 0; i < index; ++i) {
    158     result->set(i, *data[i]);
    159   }
    160   return result;
    161 }
    162 
    163 void ModuleDescriptor::DeserializeRegularExports(
    164     Isolate* isolate, AstValueFactory* avfactory,
    165     Handle<ModuleInfo> module_info) {
    166   for (int i = 0, count = module_info->RegularExportCount(); i < count; ++i) {
    167     Handle<String> local_name(module_info->RegularExportLocalName(i), isolate);
    168     int cell_index = module_info->RegularExportCellIndex(i);
    169     Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
    170                                     isolate);
    171 
    172     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       entry->local_name = avfactory->GetString(local_name);
    178       entry->export_name = avfactory->GetString(export_name);
    179       entry->cell_index = cell_index;
    180 
    181       AddRegularExport(entry);
    182     }
    183   }
    184 }
    185 
    186 void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
    187   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    188     Entry* entry = it->second;
    189     DCHECK_NOT_NULL(entry->local_name);
    190     auto import = regular_imports_.find(entry->local_name);
    191     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       entry->import_name = import->second->import_name;
    201       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       entry->location = import->second->location;
    209       entry->local_name = nullptr;
    210       AddSpecialExport(entry, zone);
    211       it = regular_exports_.erase(it);
    212     } else {
    213       it++;
    214     }
    215   }
    216 }
    217 
    218 ModuleDescriptor::CellIndexKind ModuleDescriptor::GetCellIndexKind(
    219     int cell_index) {
    220   if (cell_index > 0) return kExport;
    221   if (cell_index < 0) return kImport;
    222   return kInvalid;
    223 }
    224 
    225 void ModuleDescriptor::AssignCellIndices() {
    226   int export_index = 1;
    227   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    228     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     do {
    232       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       entry->cell_index = export_index;
    238       it++;
    239     } while (it != regular_exports_.end() && it->first == current_key);
    240     export_index++;
    241   }
    242 
    243   int import_index = -1;
    244   for (const auto& elem : regular_imports_) {
    245     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     entry->cell_index = import_index;
    251     import_index--;
    252   }
    253 }
    254 
    255 namespace {
    256 
    257 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       export_names.insert(std::make_pair(candidate->export_name, candidate));
    265   if (insert_result.second) return current_duplicate;
    266   if (current_duplicate == nullptr) {
    267     current_duplicate = insert_result.first->second;
    268   }
    269   return (candidate->location.beg_pos > current_duplicate->location.beg_pos)
    270              ? candidate
    271              : current_duplicate;
    272 }
    273 
    274 }  // namespace
    275 
    276 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   for (const auto& elem : regular_exports_) {
    282     duplicate = BetterDuplicate(elem.second, export_names, duplicate);
    283   }
    284   for (auto entry : special_exports_) {
    285     if (entry->export_name == nullptr) continue;  // Star export.
    286     duplicate = BetterDuplicate(entry, export_names, duplicate);
    287   }
    288   return duplicate;
    289 }
    290 
    291 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     const Entry* entry = FindDuplicateExport(zone);
    300     if (entry != nullptr) {
    301       error_handler->ReportMessageAt(
    302           entry->location.beg_pos, entry->location.end_pos,
    303           MessageTemplate::kDuplicateExport, entry->export_name);
    304       return false;
    305     }
    306   }
    307 
    308   // Report error iff there are exports of non-existent local names.
    309   for (const auto& elem : regular_exports_) {
    310     const Entry* entry = elem.second;
    311     DCHECK_NOT_NULL(entry->local_name);
    312     if (module_scope->LookupLocal(entry->local_name) == nullptr) {
    313       error_handler->ReportMessageAt(
    314           entry->location.beg_pos, entry->location.end_pos,
    315           MessageTemplate::kModuleExportUndefined, entry->local_name);
    316       return false;
    317     }
    318   }
    319 
    320   MakeIndirectExportsExplicit(zone);
    321   AssignCellIndices();
    322   return true;
    323 }
    324 
    325 }  // namespace internal
    326 }  // namespace v8
    327