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

Unified Diff: src/objects.cc

Issue 2388153003: [modules] Implement namespace imports. (Closed)
Patch Set: Fix verifier. 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 side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698