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