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 #ifndef V8_AST_MODULES_H_ 6 #define V8_AST_MODULES_H_ 7 8 #include "src/parsing/scanner.h" // Only for Scanner::Location. 9 #include "src/zone/zone-containers.h" 10 11 namespace v8 { 12 namespace internal { 13 14 15 class AstRawString; 16 class ModuleRequest; 17 class SourceTextModuleInfo; 18 class SourceTextModuleInfoEntry; 19 class PendingCompilationErrorHandler; 20 21 class SourceTextModuleDescriptor : public ZoneObject { 22 public: SourceTextModuleDescriptor(Zone * zone)23 explicit SourceTextModuleDescriptor(Zone* zone) 24 : module_requests_(zone), 25 special_exports_(zone), 26 namespace_imports_(zone), 27 regular_exports_(zone), 28 regular_imports_(zone) {} 29 30 using ImportAssertions = 31 ZoneMap<const AstRawString*, 32 std::pair<const AstRawString*, Scanner::Location>>; 33 34 // The following Add* methods are high-level convenience functions for use by 35 // the parser. 36 37 // import x from "foo.js"; 38 // import {x} from "foo.js"; 39 // import {x as y} from "foo.js"; 40 void AddImport(const AstRawString* import_name, 41 const AstRawString* local_name, 42 const AstRawString* module_request, 43 const ImportAssertions* import_assertions, 44 const Scanner::Location loc, 45 const Scanner::Location specifier_loc, Zone* zone); 46 47 // import * as x from "foo.js"; 48 void AddStarImport(const AstRawString* local_name, 49 const AstRawString* module_request, 50 const ImportAssertions* import_assertions, 51 const Scanner::Location loc, 52 const Scanner::Location specifier_loc, Zone* zone); 53 54 // import "foo.js"; 55 // import {} from "foo.js"; 56 // export {} from "foo.js"; (sic!) 57 void AddEmptyImport(const AstRawString* module_request, 58 const ImportAssertions* import_assertions, 59 const Scanner::Location specifier_loc, Zone* zone); 60 61 // export {x}; 62 // export {x as y}; 63 // export VariableStatement 64 // export Declaration 65 // export default ... 66 void AddExport( 67 const AstRawString* local_name, const AstRawString* export_name, 68 const Scanner::Location loc, Zone* zone); 69 70 // export {x} from "foo.js"; 71 // export {x as y} from "foo.js"; 72 void AddExport(const AstRawString* export_name, 73 const AstRawString* import_name, 74 const AstRawString* module_request, 75 const ImportAssertions* import_assertions, 76 const Scanner::Location loc, 77 const Scanner::Location specifier_loc, Zone* zone); 78 79 // export * from "foo.js"; 80 void AddStarExport(const AstRawString* module_request, 81 const ImportAssertions* import_assertions, 82 const Scanner::Location loc, 83 const Scanner::Location specifier_loc, Zone* zone); 84 85 // Check if module is well-formed and report error if not. 86 // Also canonicalize indirect exports. 87 bool Validate(ModuleScope* module_scope, 88 PendingCompilationErrorHandler* error_handler, Zone* zone); 89 90 struct Entry : public ZoneObject { 91 Scanner::Location location; 92 const AstRawString* export_name; 93 const AstRawString* local_name; 94 const AstRawString* import_name; 95 96 // The module_request value records the order in which modules are 97 // requested. It also functions as an index into the SourceTextModuleInfo's 98 // array of module specifiers and into the Module's array of requested 99 // modules. A negative value means no module request. 100 int module_request; 101 102 // Import/export entries that are associated with a MODULE-allocated 103 // variable (i.e. regular_imports and regular_exports after Validate) use 104 // the cell_index value to encode the location of their cell. During 105 // variable allocation, this will be be copied into the variable's index 106 // field. 107 // Entries that are not associated with a MODULE-allocated variable have 108 // GetCellIndexKind(cell_index) == kInvalid. 109 int cell_index; 110 111 // TODO(neis): Remove local_name component? EntryEntry112 explicit Entry(Scanner::Location loc) 113 : location(loc), 114 export_name(nullptr), 115 local_name(nullptr), 116 import_name(nullptr), 117 module_request(-1), 118 cell_index(0) {} 119 120 template <typename LocalIsolate> 121 Handle<SourceTextModuleInfoEntry> Serialize(LocalIsolate* isolate) const; 122 }; 123 124 enum CellIndexKind { kInvalid, kExport, kImport }; 125 static CellIndexKind GetCellIndexKind(int cell_index); 126 127 class AstModuleRequest : public ZoneObject { 128 public: 129 // TODO(v8:10958): Consider storing module request location here 130 // instead of using separate ModuleRequestLocation struct. AstModuleRequest(const AstRawString * specifier,const ImportAssertions * import_assertions)131 AstModuleRequest(const AstRawString* specifier, 132 const ImportAssertions* import_assertions) 133 : specifier_(specifier), import_assertions_(import_assertions) {} 134 135 template <typename LocalIsolate> 136 Handle<v8::internal::ModuleRequest> Serialize(LocalIsolate* isolate) const; 137 specifier()138 const AstRawString* specifier() const { return specifier_; } import_assertions()139 const ImportAssertions* import_assertions() const { 140 return import_assertions_; 141 } 142 143 private: 144 const AstRawString* specifier_; 145 const ImportAssertions* import_assertions_; 146 }; 147 148 struct ModuleRequestLocation { 149 // The index at which we will place the request in SourceTextModuleInfo's 150 // module_requests FixedArray. 151 int index; 152 153 // The JS source code position of the request, used for reporting errors. 154 int position; 155 ModuleRequestLocationModuleRequestLocation156 ModuleRequestLocation(int index, int position) 157 : index(index), position(position) {} 158 }; 159 160 // Custom content-based comparer for the below maps, to keep them stable 161 // across parses. 162 struct V8_EXPORT_PRIVATE AstRawStringComparer { 163 bool operator()(const AstRawString* lhs, const AstRawString* rhs) const; 164 static int ThreeWayCompare(const AstRawString* lhs, 165 const AstRawString* rhs); 166 }; 167 168 struct V8_EXPORT_PRIVATE ModuleRequestComparer { 169 bool operator()(const AstModuleRequest* lhs, 170 const AstModuleRequest* rhs) const; 171 }; 172 173 using ModuleRequestMap = 174 ZoneMap<const AstModuleRequest*, ModuleRequestLocation, 175 ModuleRequestComparer>; 176 using RegularExportMap = 177 ZoneMultimap<const AstRawString*, Entry*, AstRawStringComparer>; 178 using RegularImportMap = 179 ZoneMap<const AstRawString*, Entry*, AstRawStringComparer>; 180 181 // Module requests. module_requests()182 const ModuleRequestMap& module_requests() const { return module_requests_; } 183 184 // Namespace imports. namespace_imports()185 const ZoneVector<const Entry*>& namespace_imports() const { 186 return namespace_imports_; 187 } 188 189 // All the remaining imports, indexed by local name. regular_imports()190 const RegularImportMap& regular_imports() const { return regular_imports_; } 191 192 // Star exports and explicitly indirect exports. special_exports()193 const ZoneVector<const Entry*>& special_exports() const { 194 return special_exports_; 195 } 196 197 // All the remaining exports, indexed by local name. 198 // After canonicalization (see Validate), these are exactly the local exports. regular_exports()199 const RegularExportMap& regular_exports() const { return regular_exports_; } 200 AddRegularExport(Entry * entry)201 void AddRegularExport(Entry* entry) { 202 DCHECK_NOT_NULL(entry->export_name); 203 DCHECK_NOT_NULL(entry->local_name); 204 DCHECK_NULL(entry->import_name); 205 DCHECK_LT(entry->module_request, 0); 206 regular_exports_.insert(std::make_pair(entry->local_name, entry)); 207 } 208 AddSpecialExport(const Entry * entry,Zone * zone)209 void AddSpecialExport(const Entry* entry, Zone* zone) { 210 DCHECK_NULL(entry->local_name); 211 DCHECK_LE(0, entry->module_request); 212 special_exports_.push_back(entry); 213 } 214 AddRegularImport(Entry * entry)215 void AddRegularImport(Entry* entry) { 216 DCHECK_NOT_NULL(entry->import_name); 217 DCHECK_NOT_NULL(entry->local_name); 218 DCHECK_NULL(entry->export_name); 219 DCHECK_LE(0, entry->module_request); 220 regular_imports_.insert(std::make_pair(entry->local_name, entry)); 221 // We don't care if there's already an entry for this local name, as in that 222 // case we will report an error when declaring the variable. 223 } 224 AddNamespaceImport(const Entry * entry,Zone * zone)225 void AddNamespaceImport(const Entry* entry, Zone* zone) { 226 DCHECK_NULL(entry->import_name); 227 DCHECK_NULL(entry->export_name); 228 DCHECK_NOT_NULL(entry->local_name); 229 DCHECK_LE(0, entry->module_request); 230 namespace_imports_.push_back(entry); 231 } 232 233 template <typename LocalIsolate> 234 Handle<FixedArray> SerializeRegularExports(LocalIsolate* isolate, 235 Zone* zone) const; 236 237 private: 238 ModuleRequestMap module_requests_; 239 ZoneVector<const Entry*> special_exports_; 240 ZoneVector<const Entry*> namespace_imports_; 241 RegularExportMap regular_exports_; 242 RegularImportMap regular_imports_; 243 244 // If there are multiple export entries with the same export name, return the 245 // last of them (in source order). Otherwise return nullptr. 246 const Entry* FindDuplicateExport(Zone* zone) const; 247 248 // Find any implicitly indirect exports and make them explicit. 249 // 250 // An explicitly indirect export is an export entry arising from an export 251 // statement of the following form: 252 // export {a as c} from "X"; 253 // An implicitly indirect export corresponds to 254 // export {b as c}; 255 // in the presence of an import statement of the form 256 // import {a as b} from "X"; 257 // This function finds such implicitly indirect export entries and rewrites 258 // them by filling in the import name and module request, as well as nulling 259 // out the local name. Effectively, it turns 260 // import {a as b} from "X"; export {b as c}; 261 // into: 262 // import {a as b} from "X"; export {a as c} from "X"; 263 // (The import entry is never deleted.) 264 void MakeIndirectExportsExplicit(Zone* zone); 265 266 // Assign a cell_index of -1,-2,... to regular imports. 267 // Assign a cell_index of +1,+2,... to regular (local) exports. 268 // Assign a cell_index of 0 to anything else. 269 void AssignCellIndices(); 270 AddModuleRequest(const AstRawString * specifier,const ImportAssertions * import_assertions,Scanner::Location specifier_loc,Zone * zone)271 int AddModuleRequest(const AstRawString* specifier, 272 const ImportAssertions* import_assertions, 273 Scanner::Location specifier_loc, Zone* zone) { 274 DCHECK_NOT_NULL(specifier); 275 int module_requests_count = static_cast<int>(module_requests_.size()); 276 auto it = module_requests_ 277 .insert(std::make_pair( 278 zone->New<AstModuleRequest>(specifier, import_assertions), 279 ModuleRequestLocation(module_requests_count, 280 specifier_loc.beg_pos))) 281 .first; 282 return it->second.index; 283 } 284 }; 285 286 } // namespace internal 287 } // namespace v8 288 289 #endif // V8_AST_MODULES_H_ 290