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