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