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 7#include "src/ast/ast-value-factory.h" 8#include "src/ast/scopes.h" 9#include "src/common/globals.h" 10#include "src/heap/local-factory-inl.h" 11#include "src/objects/module-inl.h" 12#include "src/objects/objects-inl.h" 13#include "src/parsing/pending-compilation-error-handler.h" 14 15namespace v8 { 16namespace internal { 17 18bool SourceTextModuleDescriptor::AstRawStringComparer::operator()( 19 const AstRawString* lhs, const AstRawString* rhs) const { 20 return AstRawString::Compare(lhs, rhs) < 0; 21} 22 23bool SourceTextModuleDescriptor::ModuleRequestComparer::operator()( 24 const AstModuleRequest* lhs, const AstModuleRequest* rhs) const { 25 if (int specifier_comparison = 26 AstRawString::Compare(lhs->specifier(), rhs->specifier())) { 27 return specifier_comparison < 0; 28 } 29 30 auto lhsIt = lhs->import_assertions()->cbegin(); 31 auto rhsIt = rhs->import_assertions()->cbegin(); 32 for (; lhsIt != lhs->import_assertions()->cend() && 33 rhsIt != rhs->import_assertions()->cend(); 34 ++lhsIt, ++rhsIt) { 35 if (int assertion_key_comparison = 36 AstRawString::Compare(lhsIt->first, rhsIt->first)) { 37 return assertion_key_comparison < 0; 38 } 39 40 if (int assertion_value_comparison = 41 AstRawString::Compare(lhsIt->second.first, rhsIt->second.first)) { 42 return assertion_value_comparison < 0; 43 } 44 } 45 46 if (lhs->import_assertions()->size() != rhs->import_assertions()->size()) { 47 return (lhs->import_assertions()->size() < 48 rhs->import_assertions()->size()); 49 } 50 51 return false; 52} 53 54void SourceTextModuleDescriptor::AddImport( 55 const AstRawString* import_name, const AstRawString* local_name, 56 const AstRawString* module_request, 57 const ImportAssertions* import_assertions, const Scanner::Location loc, 58 const Scanner::Location specifier_loc, Zone* zone) { 59 Entry* entry = zone->New<Entry>(loc); 60 entry->local_name = local_name; 61 entry->import_name = import_name; 62 entry->module_request = 63 AddModuleRequest(module_request, import_assertions, specifier_loc, zone); 64 AddRegularImport(entry); 65} 66 67void SourceTextModuleDescriptor::AddStarImport( 68 const AstRawString* local_name, const AstRawString* module_request, 69 const ImportAssertions* import_assertions, const Scanner::Location loc, 70 const Scanner::Location specifier_loc, Zone* zone) { 71 Entry* entry = zone->New<Entry>(loc); 72 entry->local_name = local_name; 73 entry->module_request = 74 AddModuleRequest(module_request, import_assertions, specifier_loc, zone); 75 AddNamespaceImport(entry, zone); 76} 77 78void SourceTextModuleDescriptor::AddEmptyImport( 79 const AstRawString* module_request, 80 const ImportAssertions* import_assertions, 81 const Scanner::Location specifier_loc, Zone* zone) { 82 AddModuleRequest(module_request, import_assertions, specifier_loc, zone); 83} 84 85void SourceTextModuleDescriptor::AddExport(const AstRawString* local_name, 86 const AstRawString* export_name, 87 Scanner::Location loc, Zone* zone) { 88 Entry* entry = zone->New<Entry>(loc); 89 entry->export_name = export_name; 90 entry->local_name = local_name; 91 AddRegularExport(entry); 92} 93 94void SourceTextModuleDescriptor::AddExport( 95 const AstRawString* import_name, const AstRawString* export_name, 96 const AstRawString* module_request, 97 const ImportAssertions* import_assertions, const Scanner::Location loc, 98 const Scanner::Location specifier_loc, Zone* zone) { 99 DCHECK_NOT_NULL(import_name); 100 DCHECK_NOT_NULL(export_name); 101 Entry* entry = zone->New<Entry>(loc); 102 entry->export_name = export_name; 103 entry->import_name = import_name; 104 entry->module_request = 105 AddModuleRequest(module_request, import_assertions, specifier_loc, zone); 106 AddSpecialExport(entry, zone); 107} 108 109void SourceTextModuleDescriptor::AddStarExport( 110 const AstRawString* module_request, 111 const ImportAssertions* import_assertions, const Scanner::Location loc, 112 const Scanner::Location specifier_loc, Zone* zone) { 113 Entry* entry = zone->New<Entry>(loc); 114 entry->module_request = 115 AddModuleRequest(module_request, import_assertions, specifier_loc, zone); 116 AddSpecialExport(entry, zone); 117} 118 119namespace { 120template <typename IsolateT> 121Handle<PrimitiveHeapObject> ToStringOrUndefined(IsolateT* isolate, 122 const AstRawString* s) { 123 if (s == nullptr) return isolate->factory()->undefined_value(); 124 return s->string(); 125} 126} // namespace 127 128template <typename IsolateT> 129Handle<ModuleRequest> SourceTextModuleDescriptor::AstModuleRequest::Serialize( 130 IsolateT* isolate) const { 131 // The import assertions will be stored in this array in the form: 132 // [key1, value1, location1, key2, value2, location2, ...] 133 Handle<FixedArray> import_assertions_array = 134 isolate->factory()->NewFixedArray( 135 static_cast<int>(import_assertions()->size() * 136 ModuleRequest::kAssertionEntrySize), 137 AllocationType::kOld); 138 139 int i = 0; 140 for (auto iter = import_assertions()->cbegin(); 141 iter != import_assertions()->cend(); 142 ++iter, i += ModuleRequest::kAssertionEntrySize) { 143 import_assertions_array->set(i, *iter->first->string()); 144 import_assertions_array->set(i + 1, *iter->second.first->string()); 145 import_assertions_array->set(i + 2, 146 Smi::FromInt(iter->second.second.beg_pos)); 147 } 148 return v8::internal::ModuleRequest::New(isolate, specifier()->string(), 149 import_assertions_array, position()); 150} 151template Handle<ModuleRequest> 152SourceTextModuleDescriptor::AstModuleRequest::Serialize(Isolate* isolate) const; 153template Handle<ModuleRequest> 154SourceTextModuleDescriptor::AstModuleRequest::Serialize( 155 LocalIsolate* isolate) const; 156 157template <typename IsolateT> 158Handle<SourceTextModuleInfoEntry> SourceTextModuleDescriptor::Entry::Serialize( 159 IsolateT* isolate) const { 160 CHECK(Smi::IsValid(module_request)); // TODO(neis): Check earlier? 161 return SourceTextModuleInfoEntry::New( 162 isolate, ToStringOrUndefined(isolate, export_name), 163 ToStringOrUndefined(isolate, local_name), 164 ToStringOrUndefined(isolate, import_name), module_request, cell_index, 165 location.beg_pos, location.end_pos); 166} 167template Handle<SourceTextModuleInfoEntry> 168SourceTextModuleDescriptor::Entry::Serialize(Isolate* isolate) const; 169template Handle<SourceTextModuleInfoEntry> 170SourceTextModuleDescriptor::Entry::Serialize(LocalIsolate* isolate) const; 171 172template <typename IsolateT> 173Handle<FixedArray> SourceTextModuleDescriptor::SerializeRegularExports( 174 IsolateT* isolate, Zone* zone) const { 175 // We serialize regular exports in a way that lets us later iterate over their 176 // local names and for each local name immediately access all its export 177 // names. (Regular exports have neither import name nor module request.) 178 179 ZoneVector<Handle<Object>> data( 180 SourceTextModuleInfo::kRegularExportLength * regular_exports_.size(), 181 zone); 182 int index = 0; 183 184 for (auto it = regular_exports_.begin(); it != regular_exports_.end();) { 185 // Find out how many export names this local name has. 186 auto next = it; 187 int count = 0; 188 do { 189 DCHECK_EQ(it->second->local_name, next->second->local_name); 190 DCHECK_EQ(it->second->cell_index, next->second->cell_index); 191 ++next; 192 ++count; 193 } while (next != regular_exports_.end() && next->first == it->first); 194 195 Handle<FixedArray> export_names = 196 isolate->factory()->NewFixedArray(count, AllocationType::kOld); 197 data[index + SourceTextModuleInfo::kRegularExportLocalNameOffset] = 198 it->second->local_name->string(); 199 data[index + SourceTextModuleInfo::kRegularExportCellIndexOffset] = 200 handle(Smi::FromInt(it->second->cell_index), isolate); 201 data[index + SourceTextModuleInfo::kRegularExportExportNamesOffset] = 202 export_names; 203 index += SourceTextModuleInfo::kRegularExportLength; 204 205 // Collect the export names. 206 int i = 0; 207 for (; it != next; ++it) { 208 export_names->set(i++, *it->second->export_name->string()); 209 } 210 DCHECK_EQ(i, count); 211 212 // Continue with the next distinct key. 213 DCHECK(it == next); 214 } 215 DCHECK_LE(index, static_cast<int>(data.size())); 216 data.resize(index); 217 218 // We cannot create the FixedArray earlier because we only now know the 219 // precise size. 220 Handle<FixedArray> result = 221 isolate->factory()->NewFixedArray(index, AllocationType::kOld); 222 for (int i = 0; i < index; ++i) { 223 result->set(i, *data[i]); 224 } 225 return result; 226} 227template Handle<FixedArray> SourceTextModuleDescriptor::SerializeRegularExports( 228 Isolate* isolate, Zone* zone) const; 229template Handle<FixedArray> SourceTextModuleDescriptor::SerializeRegularExports( 230 LocalIsolate* isolate, Zone* zone) const; 231 232void SourceTextModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) { 233 for (auto it = regular_exports_.begin(); it != regular_exports_.end();) { 234 Entry* entry = it->second; 235 DCHECK_NOT_NULL(entry->local_name); 236 auto import = regular_imports_.find(entry->local_name); 237 if (import != regular_imports_.end()) { 238 // Found an indirect export. Patch export entry and move it from regular 239 // to special. 240 DCHECK_NULL(entry->import_name); 241 DCHECK_LT(entry->module_request, 0); 242 DCHECK_NOT_NULL(import->second->import_name); 243 DCHECK_LE(0, import->second->module_request); 244 DCHECK_LT(import->second->module_request, 245 static_cast<int>(module_requests_.size())); 246 entry->import_name = import->second->import_name; 247 entry->module_request = import->second->module_request; 248 // Hack: When the indirect export cannot be resolved, we want the error 249 // message to point at the import statement, not at the export statement. 250 // Therefore we overwrite [entry]'s location here. Note that Validate() 251 // has already checked for duplicate exports, so it's guaranteed that we 252 // won't need to report any error pointing at the (now lost) export 253 // location. 254 entry->location = import->second->location; 255 entry->local_name = nullptr; 256 AddSpecialExport(entry, zone); 257 it = regular_exports_.erase(it); 258 } else { 259 it++; 260 } 261 } 262} 263 264SourceTextModuleDescriptor::CellIndexKind 265SourceTextModuleDescriptor::GetCellIndexKind(int cell_index) { 266 if (cell_index > 0) return kExport; 267 if (cell_index < 0) return kImport; 268 return kInvalid; 269} 270 271void SourceTextModuleDescriptor::AssignCellIndices() { 272 int export_index = 1; 273 for (auto it = regular_exports_.begin(); it != regular_exports_.end();) { 274 auto current_key = it->first; 275 // This local name may be exported under multiple export names. Assign the 276 // same index to each such entry. 277 do { 278 Entry* entry = it->second; 279 DCHECK_NOT_NULL(entry->local_name); 280 DCHECK_NULL(entry->import_name); 281 DCHECK_LT(entry->module_request, 0); 282 DCHECK_EQ(entry->cell_index, 0); 283 entry->cell_index = export_index; 284 it++; 285 } while (it != regular_exports_.end() && it->first == current_key); 286 export_index++; 287 } 288 289 int import_index = -1; 290 for (const auto& elem : regular_imports_) { 291 Entry* entry = elem.second; 292 DCHECK_NOT_NULL(entry->local_name); 293 DCHECK_NOT_NULL(entry->import_name); 294 DCHECK_LE(0, entry->module_request); 295 DCHECK_EQ(entry->cell_index, 0); 296 entry->cell_index = import_index; 297 import_index--; 298 } 299} 300 301namespace { 302 303const SourceTextModuleDescriptor::Entry* BetterDuplicate( 304 const SourceTextModuleDescriptor::Entry* candidate, 305 ZoneMap<const AstRawString*, const SourceTextModuleDescriptor::Entry*>& 306 export_names, 307 const SourceTextModuleDescriptor::Entry* current_duplicate) { 308 DCHECK_NOT_NULL(candidate->export_name); 309 DCHECK(candidate->location.IsValid()); 310 auto insert_result = 311 export_names.insert(std::make_pair(candidate->export_name, candidate)); 312 if (insert_result.second) return current_duplicate; 313 if (current_duplicate == nullptr) { 314 current_duplicate = insert_result.first->second; 315 } 316 return (candidate->location.beg_pos > current_duplicate->location.beg_pos) 317 ? candidate 318 : current_duplicate; 319} 320 321} // namespace 322 323const SourceTextModuleDescriptor::Entry* 324SourceTextModuleDescriptor::FindDuplicateExport(Zone* zone) const { 325 const SourceTextModuleDescriptor::Entry* duplicate = nullptr; 326 ZoneMap<const AstRawString*, const SourceTextModuleDescriptor::Entry*> 327 export_names(zone); 328 for (const auto& elem : regular_exports_) { 329 duplicate = BetterDuplicate(elem.second, export_names, duplicate); 330 } 331 for (auto entry : special_exports_) { 332 if (entry->export_name == nullptr) continue; // Star export. 333 duplicate = BetterDuplicate(entry, export_names, duplicate); 334 } 335 return duplicate; 336} 337 338bool SourceTextModuleDescriptor::Validate( 339 ModuleScope* module_scope, PendingCompilationErrorHandler* error_handler, 340 Zone* zone) { 341 DCHECK_EQ(this, module_scope->module()); 342 DCHECK_NOT_NULL(error_handler); 343 344 // Report error iff there are duplicate exports. 345 { 346 const Entry* entry = FindDuplicateExport(zone); 347 if (entry != nullptr) { 348 error_handler->ReportMessageAt( 349 entry->location.beg_pos, entry->location.end_pos, 350 MessageTemplate::kDuplicateExport, entry->export_name); 351 return false; 352 } 353 } 354 355 // Report error iff there are exports of non-existent local names. 356 for (const auto& elem : regular_exports_) { 357 const Entry* entry = elem.second; 358 DCHECK_NOT_NULL(entry->local_name); 359 if (module_scope->LookupLocal(entry->local_name) == nullptr) { 360 error_handler->ReportMessageAt( 361 entry->location.beg_pos, entry->location.end_pos, 362 MessageTemplate::kModuleExportUndefined, entry->local_name); 363 return false; 364 } 365 } 366 367 MakeIndirectExportsExplicit(zone); 368 AssignCellIndices(); 369 return true; 370} 371 372} // namespace internal 373} // namespace v8 374