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
9namespace v8 {
10namespace internal {
11
12void 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
23void 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
32void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request) {
33  AddModuleRequest(module_request);
34}
35
36
37void 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
47void 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
60void 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
67namespace {
68
69Handle<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
75const 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
84Handle<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
94ModuleDescriptor::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
109Handle<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
160void 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
183void 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
215ModuleDescriptor::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
222void 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
252namespace {
253
254const 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
273const 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
288bool 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