| Index: src/compiler/js-native-context-specialization.cc
|
| diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc
|
| index 550295348864d1353fbbce7e616ce12796505c28..fa3aaf006d7612c4c3e6ef36bcc10d46701e1cb2 100644
|
| --- a/src/compiler/js-native-context-specialization.cc
|
| +++ b/src/compiler/js-native-context-specialization.cc
|
| @@ -57,6 +57,10 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
|
| return ReduceJSLoadNamed(node);
|
| case IrOpcode::kJSStoreNamed:
|
| return ReduceJSStoreNamed(node);
|
| + case IrOpcode::kJSLoadProperty:
|
| + return ReduceJSLoadProperty(node);
|
| + case IrOpcode::kJSStoreProperty:
|
| + return ReduceJSStoreProperty(node);
|
| default:
|
| break;
|
| }
|
| @@ -304,9 +308,11 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
|
| Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
| Node* node, Node* value, MapHandleList const& receiver_maps,
|
| Handle<Name> name, PropertyAccessMode access_mode,
|
| - LanguageMode language_mode) {
|
| + LanguageMode language_mode, Node* index) {
|
| DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
|
| - node->opcode() == IrOpcode::kJSStoreNamed);
|
| + node->opcode() == IrOpcode::kJSStoreNamed ||
|
| + node->opcode() == IrOpcode::kJSLoadProperty ||
|
| + node->opcode() == IrOpcode::kJSStoreProperty);
|
| Node* receiver = NodeProperties::GetValueInput(node, 0);
|
| Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
| Node* effect = NodeProperties::GetEffectInput(node);
|
| @@ -336,6 +342,16 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
| Node* const exit_effect = effect;
|
| ZoneVector<Node*> exit_controls(zone());
|
|
|
| + // Ensure that {index} matches the specified {name} (if {index} is given).
|
| + if (index != nullptr) {
|
| + Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()),
|
| + index, jsgraph()->HeapConstant(name));
|
| + Node* branch =
|
| + graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
|
| + exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
|
| + control = graph()->NewNode(common()->IfTrue(), branch);
|
| + }
|
| +
|
| // Ensure that {receiver} is a heap object.
|
| Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
|
| Node* branch =
|
| @@ -653,6 +669,80 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
|
| }
|
|
|
|
|
| +Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
|
| + Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
|
| + PropertyAccessMode access_mode, LanguageMode language_mode) {
|
| + DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
|
| + node->opcode() == IrOpcode::kJSStoreProperty);
|
| +
|
| + // Extract receiver maps from the {nexus}.
|
| + MapHandleList receiver_maps;
|
| + if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
|
| + DCHECK_LT(0, receiver_maps.length());
|
| +
|
| + // Optimize access for constant {index}.
|
| + HeapObjectMatcher mindex(index);
|
| + if (mindex.HasValue() && mindex.Value()->IsPrimitive()) {
|
| + // Keyed access requires a ToPropertyKey on the {index} first before
|
| + // looking up the property on the object (see ES6 section 12.3.2.1).
|
| + // We can only do this for non-observable ToPropertyKey invocations,
|
| + // so we limit the constant indices to primitives at this point.
|
| + Handle<Name> name;
|
| + if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) {
|
| + uint32_t array_index;
|
| + if (name->AsArrayIndex(&array_index)) {
|
| + // TODO(bmeurer): Optimize element access with constant {index}.
|
| + } else {
|
| + name = factory()->InternalizeName(name);
|
| + return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
|
| + language_mode);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Check if we have feedback for a named access.
|
| + if (Name* name = nexus.FindFirstName()) {
|
| + return ReduceNamedAccess(node, value, receiver_maps,
|
| + handle(name, isolate()), access_mode,
|
| + language_mode, index);
|
| + }
|
| +
|
| + return NoChange();
|
| +}
|
| +
|
| +
|
| +Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
|
| + DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
|
| + PropertyAccess const& p = PropertyAccessOf(node->op());
|
| + Node* const index = NodeProperties::GetValueInput(node, 1);
|
| + Node* const value = jsgraph()->Dead();
|
| +
|
| + // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus.
|
| + if (!p.feedback().IsValid()) return NoChange();
|
| + KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
| +
|
| + // Try to lower the keyed access based on the {nexus}.
|
| + return ReduceKeyedAccess(node, index, value, nexus, PropertyAccessMode::kLoad,
|
| + p.language_mode());
|
| +}
|
| +
|
| +
|
| +Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
|
| + DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
|
| + PropertyAccess const& p = PropertyAccessOf(node->op());
|
| + Node* const index = NodeProperties::GetValueInput(node, 1);
|
| + Node* const value = NodeProperties::GetValueInput(node, 2);
|
| +
|
| + // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus.
|
| + if (!p.feedback().IsValid()) return NoChange();
|
| + KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
| +
|
| + // Try to lower the keyed access based on the {nexus}.
|
| + return ReduceKeyedAccess(node, index, value, nexus,
|
| + PropertyAccessMode::kStore, p.language_mode());
|
| +}
|
| +
|
| +
|
| Reduction JSNativeContextSpecialization::Replace(Node* node,
|
| Handle<Object> value) {
|
| return Replace(node, jsgraph()->Constant(value));
|
|
|