• 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 #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 
15 namespace v8 {
16 namespace internal {
17 
operator ()(const AstRawString * lhs,const AstRawString * rhs) const18 bool SourceTextModuleDescriptor::AstRawStringComparer::operator()(
19     const AstRawString* lhs, const AstRawString* rhs) const {
20   return AstRawString::Compare(lhs, rhs) < 0;
21 }
22 
operator ()(const AstModuleRequest * lhs,const AstModuleRequest * rhs) const23 bool 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 
AddImport(const AstRawString * import_name,const AstRawString * local_name,const AstRawString * module_request,const ImportAssertions * import_assertions,const Scanner::Location loc,const Scanner::Location specifier_loc,Zone * zone)54 void 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 
AddStarImport(const AstRawString * local_name,const AstRawString * module_request,const ImportAssertions * import_assertions,const Scanner::Location loc,const Scanner::Location specifier_loc,Zone * zone)67 void 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 
AddEmptyImport(const AstRawString * module_request,const ImportAssertions * import_assertions,const Scanner::Location specifier_loc,Zone * zone)78 void 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 
AddExport(const AstRawString * local_name,const AstRawString * export_name,Scanner::Location loc,Zone * zone)85 void 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 
AddExport(const AstRawString * import_name,const AstRawString * export_name,const AstRawString * module_request,const ImportAssertions * import_assertions,const Scanner::Location loc,const Scanner::Location specifier_loc,Zone * zone)94 void 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 
AddStarExport(const AstRawString * module_request,const ImportAssertions * import_assertions,const Scanner::Location loc,const Scanner::Location specifier_loc,Zone * zone)109 void 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 
119 namespace {
120 template <typename IsolateT>
ToStringOrUndefined(IsolateT * isolate,const AstRawString * s)121 Handle<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 
128 template <typename IsolateT>
Serialize(IsolateT * isolate) const129 Handle<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 }
151 template Handle<ModuleRequest>
152 SourceTextModuleDescriptor::AstModuleRequest::Serialize(Isolate* isolate) const;
153 template Handle<ModuleRequest>
154 SourceTextModuleDescriptor::AstModuleRequest::Serialize(
155     LocalIsolate* isolate) const;
156 
157 template <typename IsolateT>
Serialize(IsolateT * isolate) const158 Handle<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 }
167 template Handle<SourceTextModuleInfoEntry>
168 SourceTextModuleDescriptor::Entry::Serialize(Isolate* isolate) const;
169 template Handle<SourceTextModuleInfoEntry>
170 SourceTextModuleDescriptor::Entry::Serialize(LocalIsolate* isolate) const;
171 
172 template <typename IsolateT>
SerializeRegularExports(IsolateT * isolate,Zone * zone) const173 Handle<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 }
227 template Handle<FixedArray> SourceTextModuleDescriptor::SerializeRegularExports(
228     Isolate* isolate, Zone* zone) const;
229 template Handle<FixedArray> SourceTextModuleDescriptor::SerializeRegularExports(
230     LocalIsolate* isolate, Zone* zone) const;
231 
MakeIndirectExportsExplicit(Zone * zone)232 void 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 
264 SourceTextModuleDescriptor::CellIndexKind
GetCellIndexKind(int cell_index)265 SourceTextModuleDescriptor::GetCellIndexKind(int cell_index) {
266   if (cell_index > 0) return kExport;
267   if (cell_index < 0) return kImport;
268   return kInvalid;
269 }
270 
AssignCellIndices()271 void 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 
301 namespace {
302 
BetterDuplicate(const SourceTextModuleDescriptor::Entry * candidate,ZoneMap<const AstRawString *,const SourceTextModuleDescriptor::Entry * > & export_names,const SourceTextModuleDescriptor::Entry * current_duplicate)303 const 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 
323 const SourceTextModuleDescriptor::Entry*
FindDuplicateExport(Zone * zone) const324 SourceTextModuleDescriptor::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 
Validate(ModuleScope * module_scope,PendingCompilationErrorHandler * error_handler,Zone * zone)338 bool 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