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