| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index e817e777f11669b4bdf7935708c4d216a6bbafad..37a320b410a4d9f34b86aaa8106cda7a2d5c2388 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -6554,7 +6554,7 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
|
| return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
|
| key, desc, should_throw);
|
| }
|
| - // TODO(jkummerow): Support Modules (ES6 9.4.6.6)
|
| + // TODO(neis): Special case for JSModuleNamespace?
|
|
|
| // OrdinaryDefineOwnProperty, by virtue of calling
|
| // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
|
| @@ -18237,6 +18237,9 @@ Object* ObjectHashTable::Lookup(Handle<Object> key) {
|
| return Lookup(isolate, key, Smi::cast(hash)->value());
|
| }
|
|
|
| +Object* ObjectHashTable::ValueAt(int entry) {
|
| + return get(EntryToValueIndex(entry));
|
| +}
|
|
|
| Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
|
| return Lookup(GetIsolate(), key, hash);
|
| @@ -19584,6 +19587,23 @@ bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
|
| return false;
|
| }
|
|
|
| +MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) {
|
| + Isolate* isolate = name->GetIsolate();
|
| +
|
| + Handle<Object> object(module()->exports()->Lookup(name), isolate);
|
| + if (object->IsTheHole(isolate)) {
|
| + return isolate->factory()->undefined_value();
|
| + }
|
| +
|
| + Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
|
| + if (value->IsTheHole(isolate)) {
|
| + THROW_NEW_ERROR(
|
| + isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
|
| + }
|
| +
|
| + return value;
|
| +}
|
| +
|
| namespace {
|
|
|
| template <typename T>
|
| @@ -19615,6 +19635,35 @@ class UnorderedStringSet
|
| StringHandleEqual(), zone_allocator<Handle<String>>(zone)) {}
|
| };
|
|
|
| +class UnorderedModuleSet
|
| + : public std::unordered_set<Handle<Module>, HandleValueHash<Module>,
|
| + ModuleHandleEqual,
|
| + zone_allocator<Handle<Module>>> {
|
| + public:
|
| + explicit UnorderedModuleSet(Zone* zone)
|
| + : std::unordered_set<Handle<Module>, HandleValueHash<Module>,
|
| + ModuleHandleEqual, zone_allocator<Handle<Module>>>(
|
| + 2 /* bucket count */, HandleValueHash<Module>(),
|
| + ModuleHandleEqual(), zone_allocator<Handle<Module>>(zone)) {}
|
| +};
|
| +
|
| +class UnorderedStringMap
|
| + : public std::unordered_map<
|
| + Handle<String>, Handle<Object>, HandleValueHash<String>,
|
| + StringHandleEqual,
|
| + zone_allocator<std::pair<const Handle<String>, Handle<Object>>>> {
|
| + public:
|
| + explicit UnorderedStringMap(Zone* zone)
|
| + : std::unordered_map<
|
| + Handle<String>, Handle<Object>, HandleValueHash<String>,
|
| + StringHandleEqual,
|
| + zone_allocator<std::pair<const Handle<String>, Handle<Object>>>>(
|
| + 2 /* bucket count */, HandleValueHash<String>(),
|
| + StringHandleEqual(),
|
| + zone_allocator<std::pair<const Handle<String>, Handle<Object>>>(
|
| + zone)) {}
|
| +};
|
| +
|
| } // anonymous namespace
|
|
|
| class Module::ResolveSet
|
| @@ -19938,5 +19987,138 @@ MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
|
| return Execution::Call(isolate, resume, generator, 0, nullptr);
|
| }
|
|
|
| +namespace {
|
| +
|
| +void FetchStarExports(Handle<Module> module, Zone* zone,
|
| + UnorderedModuleSet* visited) {
|
| + DCHECK(module->code()->IsJSFunction()); // Instantiated.
|
| +
|
| + bool cycle = !visited->insert(module).second;
|
| + if (cycle) return;
|
| +
|
| + Isolate* isolate = module->GetIsolate();
|
| + Handle<ObjectHashTable> exports(module->exports(), isolate);
|
| + UnorderedStringMap more_exports(zone);
|
| +
|
| + // TODO(neis): Only allocate more_exports if there are star exports.
|
| + // Maybe split special_exports into indirect_exports and star_exports.
|
| +
|
| + Handle<FixedArray> special_exports(module->info()->special_exports(),
|
| + isolate);
|
| + for (int i = 0, n = special_exports->length(); i < n; ++i) {
|
| + Handle<ModuleInfoEntry> entry(
|
| + ModuleInfoEntry::cast(special_exports->get(i)), isolate);
|
| + if (!entry->export_name()->IsUndefined(isolate)) {
|
| + continue; // Indirect export.
|
| + }
|
| +
|
| + int module_request = Smi::cast(entry->module_request())->value();
|
| + Handle<Module> requested_module(
|
| + Module::cast(module->requested_modules()->get(module_request)),
|
| + isolate);
|
| +
|
| + // Recurse.
|
| + FetchStarExports(requested_module, zone, visited);
|
| +
|
| + // Collect all of [requested_module]'s exports that must be added to
|
| + // [module]'s exports (i.e. to [exports]). We record these in
|
| + // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
|
| + // the name to undefined instead of a Cell.
|
| + Handle<ObjectHashTable> requested_exports(requested_module->exports(),
|
| + isolate);
|
| + for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
|
| + Handle<Object> key(requested_exports->KeyAt(i), isolate);
|
| + if (!requested_exports->IsKey(isolate, *key)) continue;
|
| + Handle<String> name = Handle<String>::cast(key);
|
| +
|
| + if (name->Equals(isolate->heap()->default_string())) continue;
|
| + if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
|
| +
|
| + Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
|
| + auto insert_result = more_exports.insert(std::make_pair(name, cell));
|
| + if (!insert_result.second) {
|
| + auto it = insert_result.first;
|
| + if (*it->second == *cell || it->second->IsUndefined(isolate)) {
|
| + // We already recorded this mapping before, or the name is already
|
| + // known to be ambiguous. In either case, there's nothing to do.
|
| + } else {
|
| + DCHECK(it->second->IsCell());
|
| + // Different star exports provide different cells for this name, hence
|
| + // mark the name as ambiguous.
|
| + it->second = isolate->factory()->undefined_value();
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Copy [more_exports] into [exports].
|
| + for (const auto& elem : more_exports) {
|
| + if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
|
| + DCHECK(!elem.first->Equals(isolate->heap()->default_string()));
|
| + DCHECK(elem.second->IsCell());
|
| + exports = ObjectHashTable::Put(exports, elem.first, elem.second);
|
| + }
|
| + module->set_exports(*exports);
|
| +}
|
| +
|
| +} // anonymous namespace
|
| +
|
| +Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module,
|
| + int module_request) {
|
| + Isolate* isolate = module->GetIsolate();
|
| + Handle<Module> requested_module(
|
| + Module::cast(module->requested_modules()->get(module_request)), isolate);
|
| + return Module::GetModuleNamespace(requested_module);
|
| +}
|
| +
|
| +Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
|
| + Isolate* isolate = module->GetIsolate();
|
| +
|
| + Handle<HeapObject> object(module->module_namespace(), isolate);
|
| + if (!object->IsUndefined(isolate)) {
|
| + // Namespace object already exists.
|
| + return Handle<JSModuleNamespace>::cast(object);
|
| + }
|
| +
|
| + // Create the namespace object (initially empty).
|
| + Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
|
| + ns->set_module(*module);
|
| + module->set_module_namespace(*ns);
|
| +
|
| + // Collect the export names.
|
| + Zone zone(isolate->allocator());
|
| + UnorderedModuleSet visited(&zone);
|
| + FetchStarExports(module, &zone, &visited);
|
| + Handle<ObjectHashTable> exports(module->exports(), isolate);
|
| + ZoneVector<Handle<String>> names(&zone);
|
| + names.reserve(exports->NumberOfElements());
|
| + for (int i = 0, n = exports->Capacity(); i < n; ++i) {
|
| + Handle<Object> key(exports->KeyAt(i), isolate);
|
| + if (!exports->IsKey(isolate, *key)) continue;
|
| + DCHECK(exports->ValueAt(i)->IsCell());
|
| + names.push_back(Handle<String>::cast(key));
|
| + }
|
| + DCHECK_EQ(names.size(), exports->NumberOfElements());
|
| +
|
| + // Sort them alphabetically.
|
| + struct {
|
| + bool operator()(Handle<String> a, Handle<String> b) {
|
| + return String::Compare(a, b) == ComparisonResult::kLessThan;
|
| + }
|
| + } StringLess;
|
| + std::sort(names.begin(), names.end(), StringLess);
|
| +
|
| + // Create the corresponding properties in the namespace object.
|
| + PropertyAttributes attr = DONT_DELETE;
|
| + for (const auto& name : names) {
|
| + JSObject::SetAccessor(
|
| + ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
|
| + .Check();
|
| + }
|
| + JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
|
| +
|
| + return ns;
|
| +}
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|