• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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