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