V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
module.cc
1 // Copyright 2017 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 <unordered_map>
6 #include <unordered_set>
7 
8 #include "src/objects/module.h"
9 
10 #include "src/accessors.h"
11 #include "src/api-inl.h"
12 #include "src/ast/modules.h"
13 #include "src/objects-inl.h"
14 #include "src/objects/hash-table-inl.h"
15 #include "src/objects/js-generator-inl.h"
16 #include "src/objects/module-inl.h"
17 
18 namespace v8 {
19 namespace internal {
20 
22  V8_INLINE size_t operator()(Handle<Module> module) const {
23  return module->hash();
24  }
25 };
26 
28  V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
29  return *lhs == *rhs;
30  }
31 };
32 
34  V8_INLINE size_t operator()(Handle<String> string) const {
35  return string->Hash();
36  }
37 };
38 
40  V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
41  return lhs->Equals(*rhs);
42  }
43 };
44 
46  : public std::unordered_set<Handle<String>, StringHandleHash,
47  StringHandleEqual,
48  ZoneAllocator<Handle<String>>> {
49  public:
50  explicit UnorderedStringSet(Zone* zone)
51  : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
53  2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
55 };
56 
58  : public std::unordered_set<Handle<Module>, ModuleHandleHash,
59  ModuleHandleEqual,
60  ZoneAllocator<Handle<Module>>> {
61  public:
62  explicit UnorderedModuleSet(Zone* zone)
63  : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual,
65  2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
67 };
68 
70  : public std::unordered_map<
71  Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
72  ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> {
73  public:
74  explicit UnorderedStringMap(Zone* zone)
75  : std::unordered_map<
78  2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
80  zone)) {}
81 };
82 
84  : public std::unordered_map<
85  Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
86  ModuleHandleEqual,
87  ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> {
88  public:
89  explicit ResolveSet(Zone* zone)
90  : std::unordered_map<Handle<Module>, UnorderedStringSet*,
94  2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
96  zone)),
97  zone_(zone) {}
98 
99  Zone* zone() const { return zone_; }
100 
101  private:
102  Zone* zone_;
103 };
104 
105 int Module::ExportIndex(int cell_index) {
106  DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
107  ModuleDescriptor::kExport);
108  return cell_index - 1;
109 }
110 
111 int Module::ImportIndex(int cell_index) {
112  DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
113  ModuleDescriptor::kImport);
114  return -cell_index - 1;
115 }
116 
117 void Module::CreateIndirectExport(Isolate* isolate, Handle<Module> module,
118  Handle<String> name,
119  Handle<ModuleInfoEntry> entry) {
120  Handle<ObjectHashTable> exports(module->exports(), isolate);
121  DCHECK(exports->Lookup(name)->IsTheHole(isolate));
122  exports = ObjectHashTable::Put(exports, name, entry);
123  module->set_exports(*exports);
124 }
125 
126 void Module::CreateExport(Isolate* isolate, Handle<Module> module,
127  int cell_index, Handle<FixedArray> names) {
128  DCHECK_LT(0, names->length());
129  Handle<Cell> cell =
130  isolate->factory()->NewCell(isolate->factory()->undefined_value());
131  module->regular_exports()->set(ExportIndex(cell_index), *cell);
132 
133  Handle<ObjectHashTable> exports(module->exports(), isolate);
134  for (int i = 0, n = names->length(); i < n; ++i) {
135  Handle<String> name(String::cast(names->get(i)), isolate);
136  DCHECK(exports->Lookup(name)->IsTheHole(isolate));
137  exports = ObjectHashTable::Put(exports, name, cell);
138  }
139  module->set_exports(*exports);
140 }
141 
142 Cell* Module::GetCell(int cell_index) {
143  DisallowHeapAllocation no_gc;
144  Object* cell;
145  switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
146  case ModuleDescriptor::kImport:
147  cell = regular_imports()->get(ImportIndex(cell_index));
148  break;
149  case ModuleDescriptor::kExport:
150  cell = regular_exports()->get(ExportIndex(cell_index));
151  break;
152  case ModuleDescriptor::kInvalid:
153  UNREACHABLE();
154  break;
155  }
156  return Cell::cast(cell);
157 }
158 
159 Handle<Object> Module::LoadVariable(Isolate* isolate, Handle<Module> module,
160  int cell_index) {
161  return handle(module->GetCell(cell_index)->value(), isolate);
162 }
163 
164 void Module::StoreVariable(Handle<Module> module, int cell_index,
165  Handle<Object> value) {
166  DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
167  ModuleDescriptor::kExport);
168  module->GetCell(cell_index)->set_value(*value);
169 }
170 
171 #ifdef DEBUG
172 void Module::PrintStatusTransition(Status new_status) {
173  if (FLAG_trace_module_status) {
174  StdoutStream os;
175  os << "Changing module status from " << status() << " to " << new_status
176  << " for ";
177  script()->GetNameOrSourceURL()->Print(os);
178 #ifndef OBJECT_PRINT
179  os << "\n";
180 #endif // OBJECT_PRINT
181  }
182 }
183 #endif // DEBUG
184 
185 void Module::SetStatus(Status new_status) {
186  DisallowHeapAllocation no_alloc;
187  DCHECK_LE(status(), new_status);
188  DCHECK_NE(new_status, Module::kErrored);
189 #ifdef DEBUG
190  PrintStatusTransition(new_status);
191 #endif // DEBUG
192  set_status(new_status);
193 }
194 
195 void Module::ResetGraph(Isolate* isolate, Handle<Module> module) {
196  DCHECK_NE(module->status(), kInstantiating);
197  DCHECK_NE(module->status(), kEvaluating);
198  if (module->status() != kPreInstantiating) return;
199  Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
200  Reset(isolate, module);
201  for (int i = 0; i < requested_modules->length(); ++i) {
202  Handle<Object> descendant(requested_modules->get(i), isolate);
203  if (descendant->IsModule()) {
204  ResetGraph(isolate, Handle<Module>::cast(descendant));
205  } else {
206  DCHECK(descendant->IsUndefined(isolate));
207  }
208  }
209 }
210 
211 void Module::Reset(Isolate* isolate, Handle<Module> module) {
212  Factory* factory = isolate->factory();
213 
214  DCHECK(module->status() == kPreInstantiating ||
215  module->status() == kInstantiating);
216  DCHECK(module->exception()->IsTheHole(isolate));
217  DCHECK(module->import_meta()->IsTheHole(isolate));
218  // The namespace object cannot exist, because it would have been created
219  // by RunInitializationCode, which is called only after this module's SCC
220  // succeeds instantiation.
221  DCHECK(!module->module_namespace()->IsJSModuleNamespace());
222 
223  Handle<ObjectHashTable> exports =
224  ObjectHashTable::New(isolate, module->info()->RegularExportCount());
225  Handle<FixedArray> regular_exports =
226  factory->NewFixedArray(module->regular_exports()->length());
227  Handle<FixedArray> regular_imports =
228  factory->NewFixedArray(module->regular_imports()->length());
229  Handle<FixedArray> requested_modules =
230  factory->NewFixedArray(module->requested_modules()->length());
231 
232  if (module->status() == kInstantiating) {
233  module->set_code(JSFunction::cast(module->code())->shared());
234  }
235 #ifdef DEBUG
236  module->PrintStatusTransition(kUninstantiated);
237 #endif // DEBUG
238  module->set_status(kUninstantiated);
239  module->set_exports(*exports);
240  module->set_regular_exports(*regular_exports);
241  module->set_regular_imports(*regular_imports);
242  module->set_requested_modules(*requested_modules);
243  module->set_dfs_index(-1);
244  module->set_dfs_ancestor_index(-1);
245 }
246 
247 void Module::RecordError(Isolate* isolate) {
248  DisallowHeapAllocation no_alloc;
249  DCHECK(exception()->IsTheHole(isolate));
250  Object* the_exception = isolate->pending_exception();
251  DCHECK(!the_exception->IsTheHole(isolate));
252 
253  set_code(info());
254 #ifdef DEBUG
255  PrintStatusTransition(Module::kErrored);
256 #endif // DEBUG
257  set_status(Module::kErrored);
258  set_exception(the_exception);
259 }
260 
261 Object* Module::GetException() {
262  DisallowHeapAllocation no_alloc;
263  DCHECK_EQ(status(), Module::kErrored);
264  DCHECK(!exception()->IsTheHole());
265  return exception();
266 }
267 
268 SharedFunctionInfo* Module::GetSharedFunctionInfo() const {
269  DisallowHeapAllocation no_alloc;
270  DCHECK_NE(status(), Module::kEvaluating);
271  DCHECK_NE(status(), Module::kEvaluated);
272  switch (status()) {
273  case kUninstantiated:
274  case kPreInstantiating:
275  DCHECK(code()->IsSharedFunctionInfo());
276  return SharedFunctionInfo::cast(code());
277  case kInstantiating:
278  DCHECK(code()->IsJSFunction());
279  return JSFunction::cast(code())->shared();
280  case kInstantiated:
281  DCHECK(code()->IsJSGeneratorObject());
282  return JSGeneratorObject::cast(code())->function()->shared();
283  case kEvaluating:
284  case kEvaluated:
285  case kErrored:
286  UNREACHABLE();
287  }
288 
289  UNREACHABLE();
290 }
291 
292 MaybeHandle<Cell> Module::ResolveImport(Isolate* isolate, Handle<Module> module,
293  Handle<String> name, int module_request,
294  MessageLocation loc, bool must_resolve,
295  Module::ResolveSet* resolve_set) {
296  Handle<Module> requested_module(
297  Module::cast(module->requested_modules()->get(module_request)), isolate);
298  Handle<String> specifier(
299  String::cast(module->info()->module_requests()->get(module_request)),
300  isolate);
301  MaybeHandle<Cell> result =
302  Module::ResolveExport(isolate, requested_module, specifier, name, loc,
303  must_resolve, resolve_set);
304  DCHECK_IMPLIES(isolate->has_pending_exception(), result.is_null());
305  return result;
306 }
307 
308 MaybeHandle<Cell> Module::ResolveExport(Isolate* isolate, Handle<Module> module,
309  Handle<String> module_specifier,
310  Handle<String> export_name,
311  MessageLocation loc, bool must_resolve,
312  Module::ResolveSet* resolve_set) {
313  DCHECK_GE(module->status(), kPreInstantiating);
314  DCHECK_NE(module->status(), kEvaluating);
315  Handle<Object> object(module->exports()->Lookup(export_name), isolate);
316  if (object->IsCell()) {
317  // Already resolved (e.g. because it's a local export).
318  return Handle<Cell>::cast(object);
319  }
320 
321  // Check for cycle before recursing.
322  {
323  // Attempt insertion with a null string set.
324  auto result = resolve_set->insert({module, nullptr});
325  UnorderedStringSet*& name_set = result.first->second;
326  if (result.second) {
327  // |module| wasn't in the map previously, so allocate a new name set.
328  Zone* zone = resolve_set->zone();
329  name_set =
330  new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
331  } else if (name_set->count(export_name)) {
332  // Cycle detected.
333  if (must_resolve) {
334  return isolate->Throw<Cell>(
335  isolate->factory()->NewSyntaxError(
336  MessageTemplate::kCyclicModuleDependency, export_name,
337  module_specifier),
338  &loc);
339  }
340  return MaybeHandle<Cell>();
341  }
342  name_set->insert(export_name);
343  }
344 
345  if (object->IsModuleInfoEntry()) {
346  // Not yet resolved indirect export.
347  Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
348  Handle<String> import_name(String::cast(entry->import_name()), isolate);
349  Handle<Script> script(module->script(), isolate);
350  MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
351 
352  Handle<Cell> cell;
353  if (!ResolveImport(isolate, module, import_name, entry->module_request(),
354  new_loc, true, resolve_set)
355  .ToHandle(&cell)) {
356  DCHECK(isolate->has_pending_exception());
357  return MaybeHandle<Cell>();
358  }
359 
360  // The export table may have changed but the entry in question should be
361  // unchanged.
362  Handle<ObjectHashTable> exports(module->exports(), isolate);
363  DCHECK(exports->Lookup(export_name)->IsModuleInfoEntry());
364 
365  exports = ObjectHashTable::Put(exports, export_name, cell);
366  module->set_exports(*exports);
367  return cell;
368  }
369 
370  DCHECK(object->IsTheHole(isolate));
371  return Module::ResolveExportUsingStarExports(isolate, module,
372  module_specifier, export_name,
373  loc, must_resolve, resolve_set);
374 }
375 
376 MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
377  Isolate* isolate, Handle<Module> module, Handle<String> module_specifier,
378  Handle<String> export_name, MessageLocation loc, bool must_resolve,
379  Module::ResolveSet* resolve_set) {
380  if (!export_name->Equals(ReadOnlyRoots(isolate).default_string())) {
381  // Go through all star exports looking for the given name. If multiple star
382  // exports provide the name, make sure they all map it to the same cell.
383  Handle<Cell> unique_cell;
384  Handle<FixedArray> special_exports(module->info()->special_exports(),
385  isolate);
386  for (int i = 0, n = special_exports->length(); i < n; ++i) {
388  i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
389  if (!entry->export_name()->IsUndefined(isolate)) {
390  continue; // Indirect export.
391  }
392 
393  Handle<Script> script(module->script(), isolate);
394  MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
395 
396  Handle<Cell> cell;
397  if (ResolveImport(isolate, module, export_name, entry->module_request(),
398  new_loc, false, resolve_set)
399  .ToHandle(&cell)) {
400  if (unique_cell.is_null()) unique_cell = cell;
401  if (*unique_cell != *cell) {
402  return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError(
403  MessageTemplate::kAmbiguousExport,
404  module_specifier, export_name),
405  &loc);
406  }
407  } else if (isolate->has_pending_exception()) {
408  return MaybeHandle<Cell>();
409  }
410  }
411 
412  if (!unique_cell.is_null()) {
413  // Found a unique star export for this name.
414  Handle<ObjectHashTable> exports(module->exports(), isolate);
415  DCHECK(exports->Lookup(export_name)->IsTheHole(isolate));
416  exports = ObjectHashTable::Put(exports, export_name, unique_cell);
417  module->set_exports(*exports);
418  return unique_cell;
419  }
420  }
421 
422  // Unresolvable.
423  if (must_resolve) {
424  return isolate->Throw<Cell>(
425  isolate->factory()->NewSyntaxError(MessageTemplate::kUnresolvableExport,
426  module_specifier, export_name),
427  &loc);
428  }
429  return MaybeHandle<Cell>();
430 }
431 
432 bool Module::Instantiate(Isolate* isolate, Handle<Module> module,
433  v8::Local<v8::Context> context,
434  v8::Module::ResolveCallback callback) {
435 #ifdef DEBUG
436  if (FLAG_trace_module_status) {
437  StdoutStream os;
438  os << "Instantiating module ";
439  module->script()->GetNameOrSourceURL()->Print(os);
440 #ifndef OBJECT_PRINT
441  os << "\n";
442 #endif // OBJECT_PRINT
443  }
444 #endif // DEBUG
445 
446  if (!PrepareInstantiate(isolate, module, context, callback)) {
447  ResetGraph(isolate, module);
448  return false;
449  }
450  Zone zone(isolate->allocator(), ZONE_NAME);
451  ZoneForwardList<Handle<Module>> stack(&zone);
452  unsigned dfs_index = 0;
453  if (!FinishInstantiate(isolate, module, &stack, &dfs_index, &zone)) {
454  for (auto& descendant : stack) {
455  Reset(isolate, descendant);
456  }
457  DCHECK_EQ(module->status(), kUninstantiated);
458  return false;
459  }
460  DCHECK(module->status() == kInstantiated || module->status() == kEvaluated ||
461  module->status() == kErrored);
462  DCHECK(stack.empty());
463  return true;
464 }
465 
466 bool Module::PrepareInstantiate(Isolate* isolate, Handle<Module> module,
467  v8::Local<v8::Context> context,
468  v8::Module::ResolveCallback callback) {
469  DCHECK_NE(module->status(), kEvaluating);
470  DCHECK_NE(module->status(), kInstantiating);
471  if (module->status() >= kPreInstantiating) return true;
472  module->SetStatus(kPreInstantiating);
473  STACK_CHECK(isolate, false);
474 
475  // Obtain requested modules.
476  Handle<ModuleInfo> module_info(module->info(), isolate);
477  Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
478  Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
479  for (int i = 0, length = module_requests->length(); i < length; ++i) {
480  Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
481  v8::Local<v8::Module> api_requested_module;
482  if (!callback(context, v8::Utils::ToLocal(specifier),
483  v8::Utils::ToLocal(module))
484  .ToLocal(&api_requested_module)) {
485  isolate->PromoteScheduledException();
486  return false;
487  }
488  Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
489  requested_modules->set(i, *requested_module);
490  }
491 
492  // Recurse.
493  for (int i = 0, length = requested_modules->length(); i < length; ++i) {
494  Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
495  isolate);
496  if (!PrepareInstantiate(isolate, requested_module, context, callback)) {
497  return false;
498  }
499  }
500 
501  // Set up local exports.
502  // TODO(neis): Create regular_exports array here instead of in factory method?
503  for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
504  int cell_index = module_info->RegularExportCellIndex(i);
505  Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
506  isolate);
507  CreateExport(isolate, module, cell_index, export_names);
508  }
509 
510  // Partially set up indirect exports.
511  // For each indirect export, we create the appropriate slot in the export
512  // table and store its ModuleInfoEntry there. When we later find the correct
513  // Cell in the module that actually provides the value, we replace the
514  // ModuleInfoEntry by that Cell (see ResolveExport).
515  Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
516  for (int i = 0, n = special_exports->length(); i < n; ++i) {
517  Handle<ModuleInfoEntry> entry(
518  ModuleInfoEntry::cast(special_exports->get(i)), isolate);
519  Handle<Object> export_name(entry->export_name(), isolate);
520  if (export_name->IsUndefined(isolate)) continue; // Star export.
521  CreateIndirectExport(isolate, module, Handle<String>::cast(export_name),
522  entry);
523  }
524 
525  DCHECK_EQ(module->status(), kPreInstantiating);
526  return true;
527 }
528 
529 bool Module::RunInitializationCode(Isolate* isolate, Handle<Module> module) {
530  DCHECK_EQ(module->status(), kInstantiating);
531  Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
532  DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
533  Handle<Object> receiver = isolate->factory()->undefined_value();
534  Handle<Object> argv[] = {module};
535  MaybeHandle<Object> maybe_generator =
536  Execution::Call(isolate, function, receiver, arraysize(argv), argv);
537  Handle<Object> generator;
538  if (!maybe_generator.ToHandle(&generator)) {
539  DCHECK(isolate->has_pending_exception());
540  return false;
541  }
542  DCHECK_EQ(*function, Handle<JSGeneratorObject>::cast(generator)->function());
543  module->set_code(*generator);
544  return true;
545 }
546 
547 bool Module::MaybeTransitionComponent(Isolate* isolate, Handle<Module> module,
548  ZoneForwardList<Handle<Module>>* stack,
549  Status new_status) {
550  DCHECK(new_status == kInstantiated || new_status == kEvaluated);
551  SLOW_DCHECK(
552  // {module} is on the {stack}.
553  std::count_if(stack->begin(), stack->end(),
554  [&](Handle<Module> m) { return *m == *module; }) == 1);
555  DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index());
556  if (module->dfs_ancestor_index() == module->dfs_index()) {
557  // This is the root of its strongly connected component.
558  Handle<Module> ancestor;
559  do {
560  ancestor = stack->front();
561  stack->pop_front();
562  DCHECK_EQ(ancestor->status(),
563  new_status == kInstantiated ? kInstantiating : kEvaluating);
564  if (new_status == kInstantiated) {
565  if (!RunInitializationCode(isolate, ancestor)) return false;
566  }
567  ancestor->SetStatus(new_status);
568  } while (*ancestor != *module);
569  }
570  return true;
571 }
572 
573 bool Module::FinishInstantiate(Isolate* isolate, Handle<Module> module,
574  ZoneForwardList<Handle<Module>>* stack,
575  unsigned* dfs_index, Zone* zone) {
576  DCHECK_NE(module->status(), kEvaluating);
577  if (module->status() >= kInstantiating) return true;
578  DCHECK_EQ(module->status(), kPreInstantiating);
579  STACK_CHECK(isolate, false);
580 
581  // Instantiate SharedFunctionInfo and mark module as instantiating for
582  // the recursion.
583  Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
584  isolate);
585  Handle<JSFunction> function =
586  isolate->factory()->NewFunctionFromSharedFunctionInfo(
587  shared, isolate->native_context());
588  module->set_code(*function);
589  module->SetStatus(kInstantiating);
590  module->set_dfs_index(*dfs_index);
591  module->set_dfs_ancestor_index(*dfs_index);
592  stack->push_front(module);
593  (*dfs_index)++;
594 
595  // Recurse.
596  Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
597  for (int i = 0, length = requested_modules->length(); i < length; ++i) {
598  Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
599  isolate);
600  if (!FinishInstantiate(isolate, requested_module, stack, dfs_index, zone)) {
601  return false;
602  }
603 
604  DCHECK_NE(requested_module->status(), kEvaluating);
605  DCHECK_GE(requested_module->status(), kInstantiating);
606  SLOW_DCHECK(
607  // {requested_module} is instantiating iff it's on the {stack}.
608  (requested_module->status() == kInstantiating) ==
609  std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) {
610  return *m == *requested_module;
611  }));
612 
613  if (requested_module->status() == kInstantiating) {
614  module->set_dfs_ancestor_index(
615  std::min(module->dfs_ancestor_index(),
616  requested_module->dfs_ancestor_index()));
617  }
618  }
619 
620  Handle<Script> script(module->script(), isolate);
621  Handle<ModuleInfo> module_info(module->info(), isolate);
622 
623  // Resolve imports.
624  Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
625  for (int i = 0, n = regular_imports->length(); i < n; ++i) {
626  Handle<ModuleInfoEntry> entry(
627  ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
628  Handle<String> name(String::cast(entry->import_name()), isolate);
629  MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
630  ResolveSet resolve_set(zone);
631  Handle<Cell> cell;
632  if (!ResolveImport(isolate, module, name, entry->module_request(), loc,
633  true, &resolve_set)
634  .ToHandle(&cell)) {
635  return false;
636  }
637  module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
638  }
639 
640  // Resolve indirect exports.
641  Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
642  for (int i = 0, n = special_exports->length(); i < n; ++i) {
643  Handle<ModuleInfoEntry> entry(
644  ModuleInfoEntry::cast(special_exports->get(i)), isolate);
645  Handle<Object> name(entry->export_name(), isolate);
646  if (name->IsUndefined(isolate)) continue; // Star export.
647  MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
648  ResolveSet resolve_set(zone);
649  if (ResolveExport(isolate, module, Handle<String>(),
650  Handle<String>::cast(name), loc, true, &resolve_set)
651  .is_null()) {
652  return false;
653  }
654  }
655 
656  return MaybeTransitionComponent(isolate, module, stack, kInstantiated);
657 }
658 
659 MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module) {
660 #ifdef DEBUG
661  if (FLAG_trace_module_status) {
662  StdoutStream os;
663  os << "Evaluating module ";
664  module->script()->GetNameOrSourceURL()->Print(os);
665 #ifndef OBJECT_PRINT
666  os << "\n";
667 #endif // OBJECT_PRINT
668  }
669 #endif // DEBUG
670  if (module->status() == kErrored) {
671  isolate->Throw(module->GetException());
672  return MaybeHandle<Object>();
673  }
674  DCHECK_NE(module->status(), kEvaluating);
675  DCHECK_GE(module->status(), kInstantiated);
676  Zone zone(isolate->allocator(), ZONE_NAME);
677 
678  ZoneForwardList<Handle<Module>> stack(&zone);
679  unsigned dfs_index = 0;
680  Handle<Object> result;
681  if (!Evaluate(isolate, module, &stack, &dfs_index).ToHandle(&result)) {
682  for (auto& descendant : stack) {
683  DCHECK_EQ(descendant->status(), kEvaluating);
684  descendant->RecordError(isolate);
685  }
686  DCHECK_EQ(module->GetException(), isolate->pending_exception());
687  return MaybeHandle<Object>();
688  }
689  DCHECK_EQ(module->status(), kEvaluated);
690  DCHECK(stack.empty());
691  return result;
692 }
693 
694 MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module,
695  ZoneForwardList<Handle<Module>>* stack,
696  unsigned* dfs_index) {
697  if (module->status() == kErrored) {
698  isolate->Throw(module->GetException());
699  return MaybeHandle<Object>();
700  }
701  if (module->status() >= kEvaluating) {
702  return isolate->factory()->undefined_value();
703  }
704  DCHECK_EQ(module->status(), kInstantiated);
705  STACK_CHECK(isolate, MaybeHandle<Object>());
706 
707  Handle<JSGeneratorObject> generator(JSGeneratorObject::cast(module->code()),
708  isolate);
709  module->set_code(
710  generator->function()->shared()->scope_info()->ModuleDescriptorInfo());
711  module->SetStatus(kEvaluating);
712  module->set_dfs_index(*dfs_index);
713  module->set_dfs_ancestor_index(*dfs_index);
714  stack->push_front(module);
715  (*dfs_index)++;
716 
717  // Recursion.
718  Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
719  for (int i = 0, length = requested_modules->length(); i < length; ++i) {
720  Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
721  isolate);
722  RETURN_ON_EXCEPTION(
723  isolate, Evaluate(isolate, requested_module, stack, dfs_index), Object);
724 
725  DCHECK_GE(requested_module->status(), kEvaluating);
726  DCHECK_NE(requested_module->status(), kErrored);
727  SLOW_DCHECK(
728  // {requested_module} is evaluating iff it's on the {stack}.
729  (requested_module->status() == kEvaluating) ==
730  std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) {
731  return *m == *requested_module;
732  }));
733 
734  if (requested_module->status() == kEvaluating) {
735  module->set_dfs_ancestor_index(
736  std::min(module->dfs_ancestor_index(),
737  requested_module->dfs_ancestor_index()));
738  }
739  }
740 
741  // Evaluation of module body.
742  Handle<JSFunction> resume(
743  isolate->native_context()->generator_next_internal(), isolate);
744  Handle<Object> result;
745  ASSIGN_RETURN_ON_EXCEPTION(
746  isolate, result, Execution::Call(isolate, resume, generator, 0, nullptr),
747  Object);
748  DCHECK(static_cast<JSIteratorResult*>(JSObject::cast(*result))
749  ->done()
750  ->BooleanValue(isolate));
751 
752  CHECK(MaybeTransitionComponent(isolate, module, stack, kEvaluated));
753  return handle(
754  static_cast<JSIteratorResult*>(JSObject::cast(*result))->value(),
755  isolate);
756 }
757 
758 namespace {
759 
760 void FetchStarExports(Isolate* isolate, Handle<Module> module, Zone* zone,
761  UnorderedModuleSet* visited) {
762  DCHECK_GE(module->status(), Module::kInstantiating);
763 
764  if (module->module_namespace()->IsJSModuleNamespace()) return; // Shortcut.
765 
766  bool cycle = !visited->insert(module).second;
767  if (cycle) return;
768  Handle<ObjectHashTable> exports(module->exports(), isolate);
769  UnorderedStringMap more_exports(zone);
770 
771  // TODO(neis): Only allocate more_exports if there are star exports.
772  // Maybe split special_exports into indirect_exports and star_exports.
773 
774  ReadOnlyRoots roots(isolate);
775  Handle<FixedArray> special_exports(module->info()->special_exports(),
776  isolate);
777  for (int i = 0, n = special_exports->length(); i < n; ++i) {
778  Handle<ModuleInfoEntry> entry(
779  ModuleInfoEntry::cast(special_exports->get(i)), isolate);
780  if (!entry->export_name()->IsUndefined(roots)) {
781  continue; // Indirect export.
782  }
783 
784  Handle<Module> requested_module(
785  Module::cast(module->requested_modules()->get(entry->module_request())),
786  isolate);
787 
788  // Recurse.
789  FetchStarExports(isolate, requested_module, zone, visited);
790 
791  // Collect all of [requested_module]'s exports that must be added to
792  // [module]'s exports (i.e. to [exports]). We record these in
793  // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
794  // the name to undefined instead of a Cell.
795  Handle<ObjectHashTable> requested_exports(requested_module->exports(),
796  isolate);
797  for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
798  Object* key;
799  if (!requested_exports->ToKey(roots, i, &key)) continue;
800  Handle<String> name(String::cast(key), isolate);
801 
802  if (name->Equals(roots.default_string())) continue;
803  if (!exports->Lookup(name)->IsTheHole(roots)) continue;
804 
805  Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
806  auto insert_result = more_exports.insert(std::make_pair(name, cell));
807  if (!insert_result.second) {
808  auto it = insert_result.first;
809  if (*it->second == *cell || it->second->IsUndefined(roots)) {
810  // We already recorded this mapping before, or the name is already
811  // known to be ambiguous. In either case, there's nothing to do.
812  } else {
813  DCHECK(it->second->IsCell());
814  // Different star exports provide different cells for this name, hence
815  // mark the name as ambiguous.
816  it->second = roots.undefined_value_handle();
817  }
818  }
819  }
820  }
821 
822  // Copy [more_exports] into [exports].
823  for (const auto& elem : more_exports) {
824  if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
825  DCHECK(!elem.first->Equals(ReadOnlyRoots(isolate).default_string()));
826  DCHECK(elem.second->IsCell());
827  exports = ObjectHashTable::Put(exports, elem.first, elem.second);
828  }
829  module->set_exports(*exports);
830 }
831 
832 } // anonymous namespace
833 
834 Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate,
835  Handle<Module> module,
836  int module_request) {
837  Handle<Module> requested_module(
838  Module::cast(module->requested_modules()->get(module_request)), isolate);
839  return Module::GetModuleNamespace(isolate, requested_module);
840 }
841 
842 Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate,
843  Handle<Module> module) {
844  Handle<HeapObject> object(module->module_namespace(), isolate);
845  ReadOnlyRoots roots(isolate);
846  if (!object->IsUndefined(roots)) {
847  // Namespace object already exists.
848  return Handle<JSModuleNamespace>::cast(object);
849  }
850 
851  // Collect the export names.
852  Zone zone(isolate->allocator(), ZONE_NAME);
853  UnorderedModuleSet visited(&zone);
854  FetchStarExports(isolate, module, &zone, &visited);
855  Handle<ObjectHashTable> exports(module->exports(), isolate);
856  ZoneVector<Handle<String>> names(&zone);
857  names.reserve(exports->NumberOfElements());
858  for (int i = 0, n = exports->Capacity(); i < n; ++i) {
859  Object* key;
860  if (!exports->ToKey(roots, i, &key)) continue;
861  names.push_back(handle(String::cast(key), isolate));
862  }
863  DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
864 
865  // Sort them alphabetically.
866  std::sort(names.begin(), names.end(),
867  [&isolate](Handle<String> a, Handle<String> b) {
868  return String::Compare(isolate, a, b) ==
869  ComparisonResult::kLessThan;
870  });
871 
872  // Create the namespace object (initially empty).
873  Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
874  ns->set_module(*module);
875  module->set_module_namespace(*ns);
876 
877  // Create the properties in the namespace object. Transition the object
878  // to dictionary mode so that property addition is faster.
879  PropertyAttributes attr = DONT_DELETE;
880  JSObject::NormalizeProperties(ns, CLEAR_INOBJECT_PROPERTIES,
881  static_cast<int>(names.size()),
882  "JSModuleNamespace");
883  for (const auto& name : names) {
884  JSObject::SetNormalizedProperty(
885  ns, name, Accessors::MakeModuleNamespaceEntryInfo(isolate, name),
886  PropertyDetails(kAccessor, attr, PropertyCellType::kMutable));
887  }
888  JSObject::PreventExtensions(ns, kThrowOnError).ToChecked();
889 
890  // Optimize the namespace object as a prototype, for two reasons:
891  // - The object's map is guaranteed not to be shared. ICs rely on this.
892  // - We can store a pointer from the map back to the namespace object.
893  // Turbofan can use this for inlining the access.
894  JSObject::OptimizeAsPrototype(ns);
895 
896  Handle<PrototypeInfo> proto_info =
897  Map::GetOrCreatePrototypeInfo(Handle<JSObject>::cast(ns), isolate);
898  proto_info->set_module_namespace(*ns);
899  return ns;
900 }
901 
902 MaybeHandle<Object> JSModuleNamespace::GetExport(Isolate* isolate,
903  Handle<String> name) {
904  Handle<Object> object(module()->exports()->Lookup(name), isolate);
905  if (object->IsTheHole(isolate)) {
906  return isolate->factory()->undefined_value();
907  }
908 
909  Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
910  if (value->IsTheHole(isolate)) {
911  THROW_NEW_ERROR(
912  isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
913  }
914 
915  return value;
916 }
917 
918 Maybe<PropertyAttributes> JSModuleNamespace::GetPropertyAttributes(
919  LookupIterator* it) {
920  Handle<JSModuleNamespace> object = it->GetHolder<JSModuleNamespace>();
921  Handle<String> name = Handle<String>::cast(it->GetName());
922  DCHECK_EQ(it->state(), LookupIterator::ACCESSOR);
923 
924  Isolate* isolate = it->isolate();
925 
926  Handle<Object> lookup(object->module()->exports()->Lookup(name), isolate);
927  if (lookup->IsTheHole(isolate)) {
928  return Just(ABSENT);
929  }
930 
931  Handle<Object> value(Handle<Cell>::cast(lookup)->value(), isolate);
932  if (value->IsTheHole(isolate)) {
933  isolate->Throw(*isolate->factory()->NewReferenceError(
934  MessageTemplate::kNotDefined, name));
935  return Nothing<PropertyAttributes>();
936  }
937 
938  return Just(it->property_attributes());
939 }
940 
941 } // namespace internal
942 } // namespace v8
Definition: v8.h:85
Definition: libplatform.h:13