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-inl.h"
     10 #include "src/pending-compilation-error-handler.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 bool ModuleDescriptor::AstRawStringComparer::operator()(
     16     const AstRawString* lhs, const AstRawString* rhs) const {
     17   // Fast path for equal pointers: a pointer is not strictly less than itself.
     18   if (lhs == rhs) return false;
     19 
     20   // Order by contents (ordering by hash is unstable across runs).
     21   if (lhs->is_one_byte() != rhs->is_one_byte()) {
     22     return lhs->is_one_byte();
     23   }
     24   if (lhs->byte_length() != rhs->byte_length()) {
     25     return lhs->byte_length() < rhs->byte_length();
     26   }
     27   return memcmp(lhs->raw_data(), rhs->raw_data(), lhs->byte_length()) < 0;
     28 }
     29 
     30 void ModuleDescriptor::AddImport(const AstRawString* import_name,
     31                                  const AstRawString* local_name,
     32                                  const AstRawString* module_request,
     33                                  const Scanner::Location loc,
     34                                  const Scanner::Location specifier_loc,
     35                                  Zone* zone) {
     36   Entry* entry = new (zone) Entry(loc);
     37   entry->local_name = local_name;
     38   entry->import_name = import_name;
     39   entry->module_request = AddModuleRequest(module_request, specifier_loc);
     40   AddRegularImport(entry);
     41 }
     42 
     43 void ModuleDescriptor::AddStarImport(const AstRawString* local_name,
     44                                      const AstRawString* module_request,
     45                                      const Scanner::Location loc,
     46                                      const Scanner::Location specifier_loc,
     47                                      Zone* zone) {
     48   Entry* entry = new (zone) Entry(loc);
     49   entry->local_name = local_name;
     50   entry->module_request = AddModuleRequest(module_request, specifier_loc);
     51   AddNamespaceImport(entry, zone);
     52 }
     53 
     54 void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request,
     55                                       const Scanner::Location specifier_loc) {
     56   AddModuleRequest(module_request, specifier_loc);
     57 }
     58 
     59 
     60 void ModuleDescriptor::AddExport(
     61     const AstRawString* local_name, const AstRawString* export_name,
     62     Scanner::Location loc, Zone* zone) {
     63   Entry* entry = new (zone) Entry(loc);
     64   entry->export_name = export_name;
     65   entry->local_name = local_name;
     66   AddRegularExport(entry);
     67 }
     68 
     69 void ModuleDescriptor::AddExport(const AstRawString* import_name,
     70                                  const AstRawString* export_name,
     71                                  const AstRawString* module_request,
     72                                  const Scanner::Location loc,
     73                                  const Scanner::Location specifier_loc,
     74                                  Zone* zone) {
     75   DCHECK_NOT_NULL(import_name);
     76   DCHECK_NOT_NULL(export_name);
     77   Entry* entry = new (zone) Entry(loc);
     78   entry->export_name = export_name;
     79   entry->import_name = import_name;
     80   entry->module_request = AddModuleRequest(module_request, specifier_loc);
     81   AddSpecialExport(entry, zone);
     82 }
     83 
     84 void ModuleDescriptor::AddStarExport(const AstRawString* module_request,
     85                                      const Scanner::Location loc,
     86                                      const Scanner::Location specifier_loc,
     87                                      Zone* zone) {
     88   Entry* entry = new (zone) Entry(loc);
     89   entry->module_request = AddModuleRequest(module_request, specifier_loc);
     90   AddSpecialExport(entry, zone);
     91 }
     92 
     93 namespace {
     94 
     95 Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) {
     96   return (s == nullptr)
     97              ? Handle<Object>::cast(isolate->factory()->undefined_value())
     98              : Handle<Object>::cast(s->string());
     99 }
    100 
    101 const AstRawString* FromStringOrUndefined(Isolate* isolate,
    102                                           AstValueFactory* avfactory,
    103                                           Handle<Object> object) {
    104   if (object->IsUndefined(isolate)) return nullptr;
    105   return avfactory->GetString(Handle<String>::cast(object));
    106 }
    107 
    108 }  // namespace
    109 
    110 Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
    111     Isolate* isolate) const {
    112   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       location.beg_pos, location.end_pos);
    118 }
    119 
    120 ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize(
    121     Isolate* isolate, AstValueFactory* avfactory,
    122     Handle<ModuleInfoEntry> entry) {
    123   Entry* result = new (avfactory->zone()) Entry(Scanner::Location::invalid());
    124   result->export_name = FromStringOrUndefined(
    125       isolate, avfactory, handle(entry->export_name(), isolate));
    126   result->local_name = FromStringOrUndefined(
    127       isolate, avfactory, handle(entry->local_name(), isolate));
    128   result->import_name = FromStringOrUndefined(
    129       isolate, avfactory, handle(entry->import_name(), isolate));
    130   result->module_request = entry->module_request();
    131   result->cell_index = entry->cell_index();
    132   return result;
    133 }
    134 
    135 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       ModuleInfo::kRegularExportLength * regular_exports_.size(), zone);
    143   int index = 0;
    144 
    145   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     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       ++count;
    154     } while (next != regular_exports_.end() && next->first == it->first);
    155 
    156     Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(count);
    157     data[index + ModuleInfo::kRegularExportLocalNameOffset] =
    158         it->second->local_name->string();
    159     data[index + ModuleInfo::kRegularExportCellIndexOffset] =
    160         handle(Smi::FromInt(it->second->cell_index), isolate);
    161     data[index + ModuleInfo::kRegularExportExportNamesOffset] = export_names;
    162     index += ModuleInfo::kRegularExportLength;
    163 
    164     // Collect the export names.
    165     int i = 0;
    166     for (; it != next; ++it) {
    167       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   data.resize(index);
    176 
    177   // We cannot create the FixedArray earlier because we only now know the
    178   // precise size.
    179   Handle<FixedArray> result = isolate->factory()->NewFixedArray(index);
    180   for (int i = 0; i < index; ++i) {
    181     result->set(i, *data[i]);
    182   }
    183   return result;
    184 }
    185 
    186 void ModuleDescriptor::DeserializeRegularExports(
    187     Isolate* isolate, AstValueFactory* avfactory,
    188     Handle<ModuleInfo> module_info) {
    189   for (int i = 0, count = module_info->RegularExportCount(); i < count; ++i) {
    190     Handle<String> local_name(module_info->RegularExportLocalName(i), isolate);
    191     int cell_index = module_info->RegularExportCellIndex(i);
    192     Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
    193                                     isolate);
    194 
    195     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       entry->local_name = avfactory->GetString(local_name);
    201       entry->export_name = avfactory->GetString(export_name);
    202       entry->cell_index = cell_index;
    203 
    204       AddRegularExport(entry);
    205     }
    206   }
    207 }
    208 
    209 void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
    210   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    211     Entry* entry = it->second;
    212     DCHECK_NOT_NULL(entry->local_name);
    213     auto import = regular_imports_.find(entry->local_name);
    214     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       entry->import_name = import->second->import_name;
    224       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       entry->location = import->second->location;
    232       entry->local_name = nullptr;
    233       AddSpecialExport(entry, zone);
    234       it = regular_exports_.erase(it);
    235     } else {
    236       it++;
    237     }
    238   }
    239 }
    240 
    241 ModuleDescriptor::CellIndexKind ModuleDescriptor::GetCellIndexKind(
    242     int cell_index) {
    243   if (cell_index > 0) return kExport;
    244   if (cell_index < 0) return kImport;
    245   return kInvalid;
    246 }
    247 
    248 void ModuleDescriptor::AssignCellIndices() {
    249   int export_index = 1;
    250   for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
    251     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     do {
    255       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       entry->cell_index = export_index;
    261       it++;
    262     } while (it != regular_exports_.end() && it->first == current_key);
    263     export_index++;
    264   }
    265 
    266   int import_index = -1;
    267   for (const auto& elem : regular_imports_) {
    268     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     entry->cell_index = import_index;
    274     import_index--;
    275   }
    276 }
    277 
    278 namespace {
    279 
    280 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       export_names.insert(std::make_pair(candidate->export_name, candidate));
    288   if (insert_result.second) return current_duplicate;
    289   if (current_duplicate == nullptr) {
    290     current_duplicate = insert_result.first->second;
    291   }
    292   return (candidate->location.beg_pos > current_duplicate->location.beg_pos)
    293              ? candidate
    294              : current_duplicate;
    295 }
    296 
    297 }  // namespace
    298 
    299 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   for (const auto& elem : regular_exports_) {
    305     duplicate = BetterDuplicate(elem.second, export_names, duplicate);
    306   }
    307   for (auto entry : special_exports_) {
    308     if (entry->export_name == nullptr) continue;  // Star export.
    309     duplicate = BetterDuplicate(entry, export_names, duplicate);
    310   }
    311   return duplicate;
    312 }
    313 
    314 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     const Entry* entry = FindDuplicateExport(zone);
    323     if (entry != nullptr) {
    324       error_handler->ReportMessageAt(
    325           entry->location.beg_pos, entry->location.end_pos,
    326           MessageTemplate::kDuplicateExport, entry->export_name);
    327       return false;
    328     }
    329   }
    330 
    331   // Report error iff there are exports of non-existent local names.
    332   for (const auto& elem : regular_exports_) {
    333     const Entry* entry = elem.second;
    334     DCHECK_NOT_NULL(entry->local_name);
    335     if (module_scope->LookupLocal(entry->local_name) == nullptr) {
    336       error_handler->ReportMessageAt(
    337           entry->location.beg_pos, entry->location.end_pos,
    338           MessageTemplate::kModuleExportUndefined, entry->local_name);
    339       return false;
    340     }
    341   }
    342 
    343   MakeIndirectExportsExplicit(zone);
    344   AssignCellIndices();
    345   return true;
    346 }
    347 
    348 }  // namespace internal
    349 }  // namespace v8
    350