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