modules.cc revision f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3
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),
91      Handle<Object>(Smi::FromInt(module_request), isolate));
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 = Smi::cast(entry->module_request())->value();
105  return result;
106}
107
108Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate,
109                                                             Zone* zone) const {
110  // We serialize regular exports in a way that lets us later iterate over their
111  // local names and for each local name immediately access all its export
112  // names.  (Regular exports have neither import name nor module request.)
113
114  ZoneVector<Handle<Object>> data(zone);
115  data.reserve(2 * regular_exports_.size());
116
117  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
118    // Find out how many export names this local name has.
119    auto next = it;
120    int size = 0;
121    do {
122      ++next;
123      ++size;
124    } while (next != regular_exports_.end() && next->first == it->first);
125
126    Handle<FixedArray> export_names = isolate->factory()->NewFixedArray(size);
127    data.push_back(it->second->local_name->string());
128    data.push_back(export_names);
129
130    // Collect the export names.
131    int i = 0;
132    for (; it != next; ++it) {
133      export_names->set(i++, *it->second->export_name->string());
134    }
135    DCHECK_EQ(i, size);
136
137    // Continue with the next distinct key.
138    DCHECK(it == next);
139  }
140
141  // We cannot create the FixedArray earlier because we only now know the
142  // precise size (the number of unique keys in regular_exports).
143  int size = static_cast<int>(data.size());
144  Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
145  for (int i = 0; i < size; ++i) {
146    result->set(i, *data[i]);
147  }
148  return result;
149}
150
151void ModuleDescriptor::DeserializeRegularExports(Isolate* isolate,
152                                                 AstValueFactory* avfactory,
153                                                 Handle<FixedArray> data) {
154  for (int i = 0, length_i = data->length(); i < length_i;) {
155    Handle<String> local_name(String::cast(data->get(i++)), isolate);
156    Handle<FixedArray> export_names(FixedArray::cast(data->get(i++)), isolate);
157
158    for (int j = 0, length_j = export_names->length(); j < length_j; ++j) {
159      Handle<String> export_name(String::cast(export_names->get(j)), isolate);
160
161      Entry* entry =
162          new (avfactory->zone()) Entry(Scanner::Location::invalid());
163      entry->local_name = avfactory->GetString(local_name);
164      entry->export_name = avfactory->GetString(export_name);
165
166      AddRegularExport(entry);
167    }
168  }
169}
170
171void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
172  for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
173    Entry* entry = it->second;
174    DCHECK_NOT_NULL(entry->local_name);
175    auto import = regular_imports_.find(entry->local_name);
176    if (import != regular_imports_.end()) {
177      // Found an indirect export.  Patch export entry and move it from regular
178      // to special.
179      DCHECK_NULL(entry->import_name);
180      DCHECK_LT(entry->module_request, 0);
181      DCHECK_NOT_NULL(import->second->import_name);
182      DCHECK_LE(0, import->second->module_request);
183      DCHECK_LT(import->second->module_request,
184                static_cast<int>(module_requests_.size()));
185      entry->import_name = import->second->import_name;
186      entry->module_request = import->second->module_request;
187      entry->local_name = nullptr;
188      AddSpecialExport(entry, zone);
189      it = regular_exports_.erase(it);
190    } else {
191      it++;
192    }
193  }
194}
195
196namespace {
197
198const ModuleDescriptor::Entry* BetterDuplicate(
199    const ModuleDescriptor::Entry* candidate,
200    ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*>& export_names,
201    const ModuleDescriptor::Entry* current_duplicate) {
202  DCHECK_NOT_NULL(candidate->export_name);
203  DCHECK(candidate->location.IsValid());
204  auto insert_result =
205      export_names.insert(std::make_pair(candidate->export_name, candidate));
206  if (insert_result.second) return current_duplicate;
207  if (current_duplicate == nullptr) {
208    current_duplicate = insert_result.first->second;
209  }
210  return (candidate->location.beg_pos > current_duplicate->location.beg_pos)
211             ? candidate
212             : current_duplicate;
213}
214
215}  // namespace
216
217const ModuleDescriptor::Entry* ModuleDescriptor::FindDuplicateExport(
218    Zone* zone) const {
219  const ModuleDescriptor::Entry* duplicate = nullptr;
220  ZoneMap<const AstRawString*, const ModuleDescriptor::Entry*> export_names(
221      zone);
222  for (const auto& elem : regular_exports_) {
223    duplicate = BetterDuplicate(elem.second, export_names, duplicate);
224  }
225  for (auto entry : special_exports_) {
226    if (entry->export_name == nullptr) continue;  // Star export.
227    duplicate = BetterDuplicate(entry, export_names, duplicate);
228  }
229  return duplicate;
230}
231
232bool ModuleDescriptor::Validate(ModuleScope* module_scope,
233                                PendingCompilationErrorHandler* error_handler,
234                                Zone* zone) {
235  DCHECK_EQ(this, module_scope->module());
236  DCHECK_NOT_NULL(error_handler);
237
238  // Report error iff there are duplicate exports.
239  {
240    const Entry* entry = FindDuplicateExport(zone);
241    if (entry != nullptr) {
242      error_handler->ReportMessageAt(
243          entry->location.beg_pos, entry->location.end_pos,
244          MessageTemplate::kDuplicateExport, entry->export_name);
245      return false;
246    }
247  }
248
249  // Report error iff there are exports of non-existent local names.
250  for (const auto& elem : regular_exports_) {
251    const Entry* entry = elem.second;
252    DCHECK_NOT_NULL(entry->local_name);
253    if (module_scope->LookupLocal(entry->local_name) == nullptr) {
254      error_handler->ReportMessageAt(
255          entry->location.beg_pos, entry->location.end_pos,
256          MessageTemplate::kModuleExportUndefined, entry->local_name);
257      return false;
258    }
259  }
260
261  MakeIndirectExportsExplicit(zone);
262  return true;
263}
264
265}  // namespace internal
266}  // namespace v8
267