Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index e817e777f11669b4bdf7935708c4d216a6bbafad..79d81af9bf122fe9a1c1e1a26277742a21c013bd 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,13 @@ bool JSReceiver::HasProxyInPrototype(Isolate* isolate) { |
| return false; |
| } |
| +Object* JSModuleNamespace::Get(Handle<String> name) { |
| + Isolate* isolate = name->GetIsolate(); |
| + Handle<Object> object(module()->exports()->Lookup(name), isolate); |
| + return object->IsTheHole(isolate) ? isolate->heap()->undefined_value() |
| + : Handle<Cell>::cast(object)->value(); |
| +} |
| + |
| namespace { |
| template <typename T> |
| @@ -19615,6 +19625,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 +19977,139 @@ MaybeHandle<Object> Module::Evaluate(Handle<Module> module) { |
| return Execution::Call(isolate, resume, generator, 0, nullptr); |
| } |
| +namespace { |
|
adamk
2016/10/04 18:26:53
Please add a blank line after this (and before the
neis
2016/10/05 08:18:41
Done.
|
| +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) { |
| + i::Handle<i::ModuleInfoEntry> entry( |
|
adamk
2016/10/04 18:26:53
No need for i:: prefixes here (and below).
neis
2016/10/05 08:18:41
Done.
|
| + i::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; |
| + if (Handle<String>::cast(key)->Equals(isolate->heap()->default_string())) |
| + continue; |
| + if (!exports->Lookup(key)->IsTheHole(isolate)) continue; |
| + |
| + Handle<String> name = Handle<String>::cast(key); |
| + Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate); |
| + auto it = more_exports.find(name); |
| + if (it == more_exports.end()) { |
| + more_exports.insert(std::make_pair(name, cell)); |
|
adamk
2016/10/04 18:26:53
Please change this code to only do a single lookup
neis
2016/10/05 08:18:41
Done.
|
| + } else if (*it->second == *cell || it->second->IsUndefined(isolate)) { |
| + // We already recorded this mapping, or the name is 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 |
| + |
| +void Module::FetchStarExports(Handle<Module> module, Zone* zone) { |
|
adamk
2016/10/04 18:26:53
Is this called anywhere other than below? Maybe ju
neis
2016/10/05 08:18:41
Ok, inlined it.
|
| + UnorderedModuleSet visited(zone); |
| + return i::FetchStarExports(module, zone, &visited); |
| +} |
| + |
| +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()); |
| + FetchStarExports(module, &zone); |
| + 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 |