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