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