Commit 8d7379c0 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[modules] Turbofan inlining support for namespace accesses

Bug: v8:1569
Change-Id: I84317ce1ac145b69caa26452721f71aac88f219e
Reviewed-on: https://chromium-review.googlesource.com/636699
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47839}
parent b6bf9ad9
......@@ -96,6 +96,13 @@ PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
}
// static
PropertyAccessInfo PropertyAccessInfo::ModuleExport(
MapHandles const& receiver_maps, Handle<Cell> cell) {
return PropertyAccessInfo(kModuleExport, MaybeHandle<JSObject>(), cell,
receiver_maps);
}
PropertyAccessInfo::PropertyAccessInfo()
: kind_(kInvalid),
field_representation_(MachineRepresentation::kNone),
......@@ -209,6 +216,9 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
that->receiver_maps_.end());
return true;
}
case kModuleExport: {
return false;
}
}
UNREACHABLE();
......@@ -400,6 +410,26 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
return true;
} else {
DCHECK_EQ(kAccessor, details.kind());
if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) {
DCHECK(map->is_prototype_map());
Handle<PrototypeInfo> proto_info =
Map::GetOrCreatePrototypeInfo(map, isolate());
DCHECK(proto_info->weak_cell()->IsWeakCell());
Object* obj = WeakCell::cast(proto_info->weak_cell())->value();
DCHECK(obj->IsJSModuleNamespace());
ObjectHashTable* exports =
JSModuleNamespace::cast(obj)->module()->exports();
Object* value =
exports->Lookup(isolate(), name, Smi::ToInt(name->GetHash()));
DCHECK(value->IsCell());
if (Cell::cast(value)->value()->IsTheHole(isolate())) {
// This module has not been fully initialized yet.
return false;
}
*access_info = PropertyAccessInfo::ModuleExport(
MapHandles{receiver_map}, handle(Cell::cast(value), isolate()));
return true;
}
Handle<Object> accessors(descriptors->GetValue(number), isolate());
if (!accessors->IsAccessorPair()) return false;
Handle<Object> accessor(
......
......@@ -63,7 +63,8 @@ class PropertyAccessInfo final {
kDataConstant,
kDataField,
kDataConstantField,
kAccessorConstant
kAccessorConstant,
kModuleExport
};
static PropertyAccessInfo NotFound(MapHandles const& receiver_maps,
......@@ -80,6 +81,8 @@ class PropertyAccessInfo final {
static PropertyAccessInfo AccessorConstant(MapHandles const& receiver_maps,
Handle<Object> constant,
MaybeHandle<JSObject> holder);
static PropertyAccessInfo ModuleExport(MapHandles const& receiver_maps,
Handle<Cell> cell);
PropertyAccessInfo();
......@@ -93,6 +96,7 @@ class PropertyAccessInfo final {
// is done.
bool IsDataConstantField() const { return kind() == kDataConstantField; }
bool IsAccessorConstant() const { return kind() == kAccessorConstant; }
bool IsModuleExport() const { return kind() == kModuleExport; }
bool HasTransitionMap() const { return !transition_map().is_null(); }
......@@ -107,6 +111,10 @@ class PropertyAccessInfo final {
}
MaybeHandle<Map> field_map() const { return field_map_; }
MapHandles const& receiver_maps() const { return receiver_maps_; }
Handle<Cell> export_cell() const {
DCHECK_EQ(kModuleExport, kind_);
return Handle<Cell>::cast(constant_);
}
private:
PropertyAccessInfo(MaybeHandle<JSObject> holder,
......
......@@ -1639,6 +1639,11 @@ JSNativeContextSpecialization::BuildPropertyLoad(
} else if (access_info.IsAccessorConstant()) {
value = InlinePropertyGetterCall(receiver, context, frame_state, &effect,
&control, if_exceptions, access_info);
} else if (access_info.IsModuleExport()) {
Node* cell = jsgraph()->Constant(access_info.export_cell());
value = effect =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
cell, effect, control);
} else {
DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
value = access_builder.BuildLoadDataField(name, access_info, receiver,
......
......@@ -840,15 +840,25 @@ Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
ns->set_module(*module);
module->set_module_namespace(*ns);
// Create the properties in the namespace object.
// Create the properties in the namespace object. Transition the object
// to dictionary mode so that property addition is faster.
PropertyAttributes attr = DONT_DELETE;
JSObject::NormalizeProperties(ns, CLEAR_INOBJECT_PROPERTIES,
static_cast<int>(names.size()),
"JSModuleNamespace");
for (const auto& name : names) {
JSObject::SetAccessor(
ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
.Check();
JSObject::SetNormalizedProperty(
ns, name, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr),
PropertyDetails(kAccessor, attr, PropertyCellType::kMutable));
}
JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
// Optimize the namespace object as a prototype, for two reasons:
// - The object's map is guaranteed not to be shared. ICs rely on this.
// - We can store a pointer from the map back to the namespace object.
// Turbofan can use this for inlining the access.
JSObject::OptimizeAsPrototype(ns);
Map::GetOrCreatePrototypeWeakCell(ns, isolate);
return ns;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment