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