Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: src/objects.cc

Issue 2367623004: [modules] Detect and throw exceptions for cyclic dependencies (Closed)
Patch Set: Handled review comments, added a test Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/objects.h" 5 #include "src/objects.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 #include <iomanip> 8 #include <iomanip>
9 #include <memory> 9 #include <memory>
10 #include <sstream> 10 #include <sstream>
11 #include <unordered_map>
12 #include <unordered_set>
11 13
12 #include "src/objects-inl.h" 14 #include "src/objects-inl.h"
13 15
14 #include "src/accessors.h" 16 #include "src/accessors.h"
15 #include "src/allocation-site-scopes.h" 17 #include "src/allocation-site-scopes.h"
16 #include "src/api-arguments-inl.h" 18 #include "src/api-arguments-inl.h"
17 #include "src/api-natives.h" 19 #include "src/api-natives.h"
18 #include "src/api.h" 20 #include "src/api.h"
19 #include "src/base/bits.h" 21 #include "src/base/bits.h"
20 #include "src/base/utils/random-number-generator.h" 22 #include "src/base/utils/random-number-generator.h"
(...skipping 19552 matching lines...) Expand 10 before | Expand all | Expand 10 after
19573 19575
19574 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) { 19576 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19575 for (PrototypeIterator iter(isolate, this, kStartAtReceiver, 19577 for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
19576 PrototypeIterator::END_AT_NULL); 19578 PrototypeIterator::END_AT_NULL);
19577 !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) { 19579 !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19578 if (iter.GetCurrent<Object>()->IsJSProxy()) return true; 19580 if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
19579 } 19581 }
19580 return false; 19582 return false;
19581 } 19583 }
19582 19584
19585 namespace {
19586
19587 template <typename T>
19588 struct HandleValueHash {
19589 V8_INLINE size_t operator()(Handle<T> handle) const { return handle->Hash(); }
19590 };
19591
19592 struct ModuleHandleEqual {
19593 V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
19594 return *lhs == *rhs;
19595 }
19596 };
19597
19598 struct StringHandleEqual {
19599 V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
19600 return lhs->Equals(*rhs);
19601 }
19602 };
19603
19604 class UnorderedStringSet
19605 : public std::unordered_set<Handle<String>, HandleValueHash<String>,
19606 StringHandleEqual,
19607 zone_allocator<Handle<String>>> {
19608 public:
19609 explicit UnorderedStringSet(Zone* zone)
19610 : std::unordered_set<Handle<String>, HandleValueHash<String>,
19611 StringHandleEqual, zone_allocator<Handle<String>>>(
19612 2 /* bucket count */, HandleValueHash<String>(),
19613 StringHandleEqual(), zone_allocator<Handle<String>>(zone)) {}
19614 };
19615
19616 } // anonymous namespace
19617
19618 class Module::ResolveSet
19619 : public std::unordered_map<
19620 Handle<Module>, UnorderedStringSet*, HandleValueHash<Module>,
19621 ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>,
19622 UnorderedStringSet*>>> {
19623 public:
19624 explicit ResolveSet(Zone* zone)
19625 : std::unordered_map<Handle<Module>, UnorderedStringSet*,
19626 HandleValueHash<Module>, ModuleHandleEqual,
19627 zone_allocator<std::pair<const Handle<Module>,
19628 UnorderedStringSet*>>>(
19629 2 /* bucket count */, HandleValueHash<Module>(),
19630 ModuleHandleEqual(),
19631 zone_allocator<
19632 std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)),
19633 zone_(zone) {}
19634
19635 Zone* zone() const { return zone_; }
19636
19637 private:
19638 Zone* zone_;
19639 };
19640
19583 void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name, 19641 void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
19584 Handle<ModuleInfoEntry> entry) { 19642 Handle<ModuleInfoEntry> entry) {
19585 Isolate* isolate = module->GetIsolate(); 19643 Isolate* isolate = module->GetIsolate();
19586 Handle<ObjectHashTable> exports(module->exports(), isolate); 19644 Handle<ObjectHashTable> exports(module->exports(), isolate);
19587 DCHECK(exports->Lookup(name)->IsTheHole(isolate)); 19645 DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19588 exports = ObjectHashTable::Put(exports, name, entry); 19646 exports = ObjectHashTable::Put(exports, name, entry);
19589 module->set_exports(*exports); 19647 module->set_exports(*exports);
19590 } 19648 }
19591 19649
19592 void Module::CreateExport(Handle<Module> module, Handle<FixedArray> names) { 19650 void Module::CreateExport(Handle<Module> module, Handle<FixedArray> names) {
(...skipping 30 matching lines...) Expand all
19623 Handle<Object> Module::LoadImport(Handle<Module> module, Handle<String> name, 19681 Handle<Object> Module::LoadImport(Handle<Module> module, Handle<String> name,
19624 int module_request) { 19682 int module_request) {
19625 Isolate* isolate = module->GetIsolate(); 19683 Isolate* isolate = module->GetIsolate();
19626 Handle<Module> requested_module( 19684 Handle<Module> requested_module(
19627 Module::cast(module->requested_modules()->get(module_request)), isolate); 19685 Module::cast(module->requested_modules()->get(module_request)), isolate);
19628 return Module::LoadExport(requested_module, name); 19686 return Module::LoadExport(requested_module, name);
19629 } 19687 }
19630 19688
19631 MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module, 19689 MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
19632 Handle<String> name, int module_request, 19690 Handle<String> name, int module_request,
19633 bool must_resolve) { 19691 bool must_resolve,
19692 Module::ResolveSet* resolve_set) {
19634 Isolate* isolate = module->GetIsolate(); 19693 Isolate* isolate = module->GetIsolate();
19635 Handle<Module> requested_module( 19694 Handle<Module> requested_module(
19636 Module::cast(module->requested_modules()->get(module_request)), isolate); 19695 Module::cast(module->requested_modules()->get(module_request)), isolate);
19637 return Module::ResolveExport(requested_module, name, must_resolve); 19696 return Module::ResolveExport(requested_module, name, must_resolve,
19697 resolve_set);
19638 } 19698 }
19639 19699
19640 MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module, 19700 MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
19641 Handle<String> name, 19701 Handle<String> name, bool must_resolve,
19642 bool must_resolve) { 19702 Module::ResolveSet* resolve_set) {
19643 // TODO(neis): Detect cycles.
19644
19645 Isolate* isolate = module->GetIsolate(); 19703 Isolate* isolate = module->GetIsolate();
19646 Handle<Object> object(module->exports()->Lookup(name), isolate); 19704 Handle<Object> object(module->exports()->Lookup(name), isolate);
19647
19648 if (object->IsCell()) { 19705 if (object->IsCell()) {
19649 // Already resolved (e.g. because it's a local export). 19706 // Already resolved (e.g. because it's a local export).
19650 return Handle<Cell>::cast(object); 19707 return Handle<Cell>::cast(object);
19651 } 19708 }
19652 19709
19710 // Must be an indirect export of some sort, so we need to detect cycles.
19711 {
19712 // Attempt insertion with a null string set.
19713 auto result = resolve_set->insert({module, nullptr});
19714 UnorderedStringSet*& name_set = result.first->second;
19715 bool did_insert = result.second;
19716 if (did_insert) {
19717 // |module| wasn't in the map previously, so allocate a new name set.
19718 Zone* zone = resolve_set->zone();
19719 name_set =
19720 new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
19721 } else if (name_set->count(name)) {
19722 // TODO(adamk): Throwing here is incorrect in the case of star exports.
19723 THROW_NEW_ERROR(
19724 isolate,
19725 NewSyntaxError(MessageTemplate::kCyclicModuleDependency, name), Cell);
19726 }
19727 name_set->insert(name);
19728 }
19729
19653 if (object->IsModuleInfoEntry()) { 19730 if (object->IsModuleInfoEntry()) {
19654 // Not yet resolved indirect export. 19731 // Not yet resolved indirect export.
19655 Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object); 19732 Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
19656 int module_request = Smi::cast(entry->module_request())->value(); 19733 int module_request = Smi::cast(entry->module_request())->value();
19657 Handle<String> import_name(String::cast(entry->import_name()), isolate); 19734 Handle<String> import_name(String::cast(entry->import_name()), isolate);
19658 19735
19659 Handle<Cell> cell; 19736 Handle<Cell> cell;
19660 if (!ResolveImport(module, import_name, module_request, true) 19737 if (!ResolveImport(module, import_name, module_request, true, resolve_set)
19661 .ToHandle(&cell)) { 19738 .ToHandle(&cell)) {
19662 DCHECK(isolate->has_pending_exception()); 19739 DCHECK(isolate->has_pending_exception());
19663 return MaybeHandle<Cell>(); 19740 return MaybeHandle<Cell>();
19664 } 19741 }
19665 19742
19666 // The export table may have changed but the entry in question should be 19743 // The export table may have changed but the entry in question should be
19667 // unchanged. 19744 // unchanged.
19668 Handle<ObjectHashTable> exports(module->exports(), isolate); 19745 Handle<ObjectHashTable> exports(module->exports(), isolate);
19669 DCHECK(exports->Lookup(name)->IsModuleInfoEntry()); 19746 DCHECK(exports->Lookup(name)->IsModuleInfoEntry());
19670 19747
19671 exports = ObjectHashTable::Put(exports, name, cell); 19748 exports = ObjectHashTable::Put(exports, name, cell);
19672 module->set_exports(*exports); 19749 module->set_exports(*exports);
19673 return cell; 19750 return cell;
19674 } 19751 }
19675 19752
19676 DCHECK(object->IsTheHole(isolate)); 19753 DCHECK(object->IsTheHole(isolate));
19677 return Module::ResolveExportUsingStarExports(module, name, must_resolve); 19754 return Module::ResolveExportUsingStarExports(module, name, must_resolve,
19755 resolve_set);
19678 } 19756 }
19679 19757
19680 MaybeHandle<Cell> Module::ResolveExportUsingStarExports(Handle<Module> module, 19758 MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
19681 Handle<String> name, 19759 Handle<Module> module, Handle<String> name, bool must_resolve,
19682 bool must_resolve) { 19760 Module::ResolveSet* resolve_set) {
19683 Isolate* isolate = module->GetIsolate(); 19761 Isolate* isolate = module->GetIsolate();
19684 if (!name->Equals(isolate->heap()->default_string())) { 19762 if (!name->Equals(isolate->heap()->default_string())) {
19685 // Go through all star exports looking for the given name. If multiple star 19763 // Go through all star exports looking for the given name. If multiple star
19686 // exports provide the name, make sure they all map it to the same cell. 19764 // exports provide the name, make sure they all map it to the same cell.
19687 Handle<Cell> unique_cell; 19765 Handle<Cell> unique_cell;
19688 Handle<FixedArray> special_exports(module->info()->special_exports(), 19766 Handle<FixedArray> special_exports(module->info()->special_exports(),
19689 isolate); 19767 isolate);
19690 for (int i = 0, n = special_exports->length(); i < n; ++i) { 19768 for (int i = 0, n = special_exports->length(); i < n; ++i) {
19691 i::Handle<i::ModuleInfoEntry> entry( 19769 i::Handle<i::ModuleInfoEntry> entry(
19692 i::ModuleInfoEntry::cast(special_exports->get(i)), isolate); 19770 i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
19693 if (!entry->export_name()->IsUndefined(isolate)) { 19771 if (!entry->export_name()->IsUndefined(isolate)) {
19694 continue; // Indirect export. 19772 continue; // Indirect export.
19695 } 19773 }
19696 int module_request = Smi::cast(entry->module_request())->value(); 19774 int module_request = Smi::cast(entry->module_request())->value();
19697 19775
19698 Handle<Cell> cell; 19776 Handle<Cell> cell;
19699 if (ResolveImport(module, name, module_request, false).ToHandle(&cell)) { 19777 if (ResolveImport(module, name, module_request, false, resolve_set)
19778 .ToHandle(&cell)) {
19700 if (unique_cell.is_null()) unique_cell = cell; 19779 if (unique_cell.is_null()) unique_cell = cell;
19701 if (*unique_cell != *cell) { 19780 if (*unique_cell != *cell) {
19702 THROW_NEW_ERROR( 19781 THROW_NEW_ERROR(
19703 isolate, NewSyntaxError(MessageTemplate::kAmbiguousExport, name), 19782 isolate, NewSyntaxError(MessageTemplate::kAmbiguousExport, name),
19704 Cell); 19783 Cell);
19705 } 19784 }
19706 } else if (isolate->has_pending_exception()) { 19785 } else if (isolate->has_pending_exception()) {
19707 return MaybeHandle<Cell>(); 19786 return MaybeHandle<Cell>();
19708 } 19787 }
19709 } 19788 }
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
19782 isolate->ThrowIllegalOperation(); 19861 isolate->ThrowIllegalOperation();
19783 return false; 19862 return false;
19784 } 19863 }
19785 Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module); 19864 Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
19786 module->requested_modules()->set(i, *requested_module); 19865 module->requested_modules()->set(i, *requested_module);
19787 if (!Instantiate(requested_module, context, callback, callback_data)) { 19866 if (!Instantiate(requested_module, context, callback, callback_data)) {
19788 return false; 19867 return false;
19789 } 19868 }
19790 } 19869 }
19791 19870
19871 Zone zone(isolate->allocator());
19872
19792 // Resolve imports. 19873 // Resolve imports.
19793 Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate); 19874 Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
19794 for (int i = 0, n = regular_imports->length(); i < n; ++i) { 19875 for (int i = 0, n = regular_imports->length(); i < n; ++i) {
19795 Handle<ModuleInfoEntry> entry( 19876 Handle<ModuleInfoEntry> entry(
19796 ModuleInfoEntry::cast(regular_imports->get(i)), isolate); 19877 ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
19797 Handle<String> name(String::cast(entry->import_name()), isolate); 19878 Handle<String> name(String::cast(entry->import_name()), isolate);
19798 int module_request = Smi::cast(entry->module_request())->value(); 19879 int module_request = Smi::cast(entry->module_request())->value();
19799 if (ResolveImport(module, name, module_request, true).is_null()) { 19880 ResolveSet resolve_set(&zone);
19881 if (ResolveImport(module, name, module_request, true, &resolve_set)
19882 .is_null()) {
19800 return false; 19883 return false;
19801 } 19884 }
19802 } 19885 }
19803 19886
19804 // Resolve indirect exports. 19887 // Resolve indirect exports.
19805 for (int i = 0, n = special_exports->length(); i < n; ++i) { 19888 for (int i = 0, n = special_exports->length(); i < n; ++i) {
19806 Handle<ModuleInfoEntry> entry( 19889 Handle<ModuleInfoEntry> entry(
19807 ModuleInfoEntry::cast(special_exports->get(i)), isolate); 19890 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
19808 Handle<Object> name(entry->export_name(), isolate); 19891 Handle<Object> name(entry->export_name(), isolate);
19809 if (name->IsUndefined(isolate)) continue; // Star export. 19892 if (name->IsUndefined(isolate)) continue; // Star export.
19810 if (ResolveExport(module, Handle<String>::cast(name), true).is_null()) { 19893 ResolveSet resolve_set(&zone);
19894 if (ResolveExport(module, Handle<String>::cast(name), true, &resolve_set)
19895 .is_null()) {
19811 return false; 19896 return false;
19812 } 19897 }
19813 } 19898 }
19814 19899
19815 return true; 19900 return true;
19816 } 19901 }
19817 19902
19818 } // namespace internal 19903 } // namespace internal
19819 } // namespace v8 19904 } // namespace v8
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698