| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index adcfd89aaacb6740e8bd2942d354e2483b18613f..828fcd896a0607ecd52aacfa7f9a0e49080c15bd 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -8,6 +8,8 @@
|
| #include <iomanip>
|
| #include <memory>
|
| #include <sstream>
|
| +#include <unordered_map>
|
| +#include <unordered_set>
|
|
|
| #include "src/objects-inl.h"
|
|
|
| @@ -19580,6 +19582,62 @@ bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
|
| return false;
|
| }
|
|
|
| +namespace {
|
| +
|
| +template <typename T>
|
| +struct HandleValueHash {
|
| + V8_INLINE size_t operator()(Handle<T> handle) const { return handle->Hash(); }
|
| +};
|
| +
|
| +struct ModuleHandleEqual {
|
| + V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
|
| + return *lhs == *rhs;
|
| + }
|
| +};
|
| +
|
| +struct StringHandleEqual {
|
| + V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
|
| + return lhs->Equals(*rhs);
|
| + }
|
| +};
|
| +
|
| +class UnorderedStringSet
|
| + : public std::unordered_set<Handle<String>, HandleValueHash<String>,
|
| + StringHandleEqual,
|
| + zone_allocator<Handle<String>>> {
|
| + public:
|
| + explicit UnorderedStringSet(Zone* zone)
|
| + : std::unordered_set<Handle<String>, HandleValueHash<String>,
|
| + StringHandleEqual, zone_allocator<Handle<String>>>(
|
| + 2 /* bucket count */, HandleValueHash<String>(),
|
| + StringHandleEqual(), zone_allocator<Handle<String>>(zone)) {}
|
| +};
|
| +
|
| +} // anonymous namespace
|
| +
|
| +class Module::ResolveSet
|
| + : public std::unordered_map<
|
| + Handle<Module>, UnorderedStringSet*, HandleValueHash<Module>,
|
| + ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>,
|
| + UnorderedStringSet*>>> {
|
| + public:
|
| + explicit ResolveSet(Zone* zone)
|
| + : std::unordered_map<Handle<Module>, UnorderedStringSet*,
|
| + HandleValueHash<Module>, ModuleHandleEqual,
|
| + zone_allocator<std::pair<const Handle<Module>,
|
| + UnorderedStringSet*>>>(
|
| + 2 /* bucket count */, HandleValueHash<Module>(),
|
| + ModuleHandleEqual(),
|
| + zone_allocator<
|
| + std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)),
|
| + zone_(zone) {}
|
| +
|
| + Zone* zone() const { return zone_; }
|
| +
|
| + private:
|
| + Zone* zone_;
|
| +};
|
| +
|
| void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
|
| Handle<ModuleInfoEntry> entry) {
|
| Isolate* isolate = module->GetIsolate();
|
| @@ -19630,26 +19688,45 @@ Handle<Object> Module::LoadImport(Handle<Module> module, Handle<String> name,
|
|
|
| MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
|
| Handle<String> name, int module_request,
|
| - bool must_resolve) {
|
| + bool must_resolve,
|
| + Module::ResolveSet* resolve_set) {
|
| Isolate* isolate = module->GetIsolate();
|
| Handle<Module> requested_module(
|
| Module::cast(module->requested_modules()->get(module_request)), isolate);
|
| - return Module::ResolveExport(requested_module, name, must_resolve);
|
| + return Module::ResolveExport(requested_module, name, must_resolve,
|
| + resolve_set);
|
| }
|
|
|
| MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
|
| - Handle<String> name,
|
| - bool must_resolve) {
|
| - // TODO(neis): Detect cycles.
|
| -
|
| + Handle<String> name, bool must_resolve,
|
| + Module::ResolveSet* resolve_set) {
|
| Isolate* isolate = module->GetIsolate();
|
| Handle<Object> object(module->exports()->Lookup(name), isolate);
|
| -
|
| if (object->IsCell()) {
|
| // Already resolved (e.g. because it's a local export).
|
| return Handle<Cell>::cast(object);
|
| }
|
|
|
| + // Must be an indirect export of some sort, so we need to detect cycles.
|
| + {
|
| + // Attempt insertion with a null string set.
|
| + auto result = resolve_set->insert({module, nullptr});
|
| + UnorderedStringSet*& name_set = result.first->second;
|
| + bool did_insert = result.second;
|
| + if (did_insert) {
|
| + // |module| wasn't in the map previously, so allocate a new name set.
|
| + Zone* zone = resolve_set->zone();
|
| + name_set =
|
| + new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
|
| + } else if (name_set->count(name)) {
|
| + // TODO(adamk): Throwing here is incorrect in the case of star exports.
|
| + THROW_NEW_ERROR(
|
| + isolate,
|
| + NewSyntaxError(MessageTemplate::kCyclicModuleDependency, name), Cell);
|
| + }
|
| + name_set->insert(name);
|
| + }
|
| +
|
| if (object->IsModuleInfoEntry()) {
|
| // Not yet resolved indirect export.
|
| Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
|
| @@ -19657,7 +19734,7 @@ MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
|
| Handle<String> import_name(String::cast(entry->import_name()), isolate);
|
|
|
| Handle<Cell> cell;
|
| - if (!ResolveImport(module, import_name, module_request, true)
|
| + if (!ResolveImport(module, import_name, module_request, true, resolve_set)
|
| .ToHandle(&cell)) {
|
| DCHECK(isolate->has_pending_exception());
|
| return MaybeHandle<Cell>();
|
| @@ -19674,12 +19751,13 @@ MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
|
| }
|
|
|
| DCHECK(object->IsTheHole(isolate));
|
| - return Module::ResolveExportUsingStarExports(module, name, must_resolve);
|
| + return Module::ResolveExportUsingStarExports(module, name, must_resolve,
|
| + resolve_set);
|
| }
|
|
|
| -MaybeHandle<Cell> Module::ResolveExportUsingStarExports(Handle<Module> module,
|
| - Handle<String> name,
|
| - bool must_resolve) {
|
| +MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
|
| + Handle<Module> module, Handle<String> name, bool must_resolve,
|
| + Module::ResolveSet* resolve_set) {
|
| Isolate* isolate = module->GetIsolate();
|
| if (!name->Equals(isolate->heap()->default_string())) {
|
| // Go through all star exports looking for the given name. If multiple star
|
| @@ -19696,7 +19774,8 @@ MaybeHandle<Cell> Module::ResolveExportUsingStarExports(Handle<Module> module,
|
| int module_request = Smi::cast(entry->module_request())->value();
|
|
|
| Handle<Cell> cell;
|
| - if (ResolveImport(module, name, module_request, false).ToHandle(&cell)) {
|
| + if (ResolveImport(module, name, module_request, false, resolve_set)
|
| + .ToHandle(&cell)) {
|
| if (unique_cell.is_null()) unique_cell = cell;
|
| if (*unique_cell != *cell) {
|
| THROW_NEW_ERROR(
|
| @@ -19789,6 +19868,8 @@ bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
|
| }
|
| }
|
|
|
| + Zone zone(isolate->allocator());
|
| +
|
| // Resolve imports.
|
| Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
|
| for (int i = 0, n = regular_imports->length(); i < n; ++i) {
|
| @@ -19796,7 +19877,9 @@ bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
|
| ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
|
| Handle<String> name(String::cast(entry->import_name()), isolate);
|
| int module_request = Smi::cast(entry->module_request())->value();
|
| - if (ResolveImport(module, name, module_request, true).is_null()) {
|
| + ResolveSet resolve_set(&zone);
|
| + if (ResolveImport(module, name, module_request, true, &resolve_set)
|
| + .is_null()) {
|
| return false;
|
| }
|
| }
|
| @@ -19807,7 +19890,9 @@ bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
|
| ModuleInfoEntry::cast(special_exports->get(i)), isolate);
|
| Handle<Object> name(entry->export_name(), isolate);
|
| if (name->IsUndefined(isolate)) continue; // Star export.
|
| - if (ResolveExport(module, Handle<String>::cast(name), true).is_null()) {
|
| + ResolveSet resolve_set(&zone);
|
| + if (ResolveExport(module, Handle<String>::cast(name), true, &resolve_set)
|
| + .is_null()) {
|
| return false;
|
| }
|
| }
|
|
|