V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
modules.cc
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 
15 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 
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 
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 
54 void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request,
55  const Scanner::Location specifier_loc) {
56  AddModuleRequest(module_request, specifier_loc);
57 }
58 
59 
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 
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 
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 
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 
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 
110 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 
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 
135 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 
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 
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 
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 
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 
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 
299 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 
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
Definition: libplatform.h:13