| 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 42920f74e0665fbc92173072180e4ce123e2f291..e83ca073d79bf2cd5005b991739c000fbede3312 100644
|
| --- a/src/compiler/js-native-context-specialization.cc
|
| +++ b/src/compiler/js-native-context-specialization.cc
|
| @@ -477,10 +477,11 @@ bool JSNativeContextSpecialization::ComputePropertyAccessInfos(
|
| }
|
|
|
|
|
| -Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
|
| - NamedAccess const& p = NamedAccessOf(node->op());
|
| - Handle<Name> name = p.name();
|
| +Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
| + Node* node, Node* value, MapHandleList const& receiver_maps,
|
| + Handle<Name> name, PropertyAccessMode access_mode) {
|
| + DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
|
| + node->opcode() == IrOpcode::kJSStoreNamed);
|
| Node* receiver = NodeProperties::GetValueInput(node, 0);
|
| Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
| Node* effect = NodeProperties::GetEffectInput(node);
|
| @@ -489,16 +490,10 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| // Not much we can do if deoptimization support is disabled.
|
| if (!(flags() & kDeoptimizationEnabled)) return NoChange();
|
|
|
| - // Extract receiver maps from the LOAD_IC using the LoadICNexus.
|
| - MapHandleList receiver_maps;
|
| - if (!p.feedback().IsValid()) return NoChange();
|
| - LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
| - if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
|
| - DCHECK_LT(0, receiver_maps.length());
|
| -
|
| // Compute property access infos for the receiver maps.
|
| ZoneVector<PropertyAccessInfo> access_infos(zone());
|
| - if (!ComputePropertyAccessInfos(receiver_maps, name, kLoad, &access_infos)) {
|
| + if (!ComputePropertyAccessInfos(receiver_maps, name, access_mode,
|
| + &access_infos)) {
|
| return NoChange();
|
| }
|
|
|
| @@ -506,7 +501,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| if (access_infos.empty()) return NoChange();
|
|
|
| // The final states for every polymorphic branch. We join them with
|
| - // Merge+Phi+EffectPhi at the bottom.
|
| + // Merge++Phi+EffectPhi at the bottom.
|
| ZoneVector<Node*> values(zone());
|
| ZoneVector<Node*> effects(zone());
|
| ZoneVector<Node*> controls(zone());
|
| @@ -532,7 +527,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| // Generate code for the various different property access patterns.
|
| Node* fallthrough_control = control;
|
| for (PropertyAccessInfo const& access_info : access_infos) {
|
| - Node* this_value = receiver;
|
| + Node* this_value = value;
|
| + Node* this_receiver = receiver;
|
| Node* this_effect = effect;
|
| Node* this_control;
|
|
|
| @@ -546,8 +542,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| Node* check =
|
| graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type,
|
| jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
|
| - Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| - check, fallthrough_control);
|
| + Node* branch =
|
| + graph()->NewNode(common()->Branch(), check, fallthrough_control);
|
| fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
|
| this_control = graph()->NewNode(common()->IfTrue(), branch);
|
| } else {
|
| @@ -559,8 +555,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| Node* check =
|
| graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
|
| receiver_map, jsgraph()->Constant(map));
|
| - Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| - check, fallthrough_control);
|
| + Node* branch =
|
| + graph()->NewNode(common()->Branch(), check, fallthrough_control);
|
| this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
|
| fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
|
| }
|
| @@ -575,44 +571,98 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| // Determine actual holder and perform prototype chain checks.
|
| Handle<JSObject> holder;
|
| if (access_info.holder().ToHandle(&holder)) {
|
| - this_value = jsgraph()->Constant(holder);
|
| AssumePrototypesStable(receiver_type, holder);
|
| + if (access_mode == kLoad) {
|
| + this_receiver = jsgraph()->Constant(holder);
|
| + }
|
| }
|
|
|
| // Generate the actual property access.
|
| if (access_info.IsDataConstant()) {
|
| this_value = jsgraph()->Constant(access_info.constant());
|
| + if (access_mode == kStore) {
|
| + Node* check = graph()->NewNode(
|
| + simplified()->ReferenceEqual(Type::Tagged()), value, this_value);
|
| + Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| + check, this_control);
|
| + exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
|
| + this_control = graph()->NewNode(common()->IfTrue(), branch);
|
| + }
|
| } else {
|
| - // TODO(bmeurer): This is sort of adhoc, and must be refactored into some
|
| - // common code once we also have support for stores.
|
| DCHECK(access_info.IsDataField());
|
| FieldIndex const field_index = access_info.field_index();
|
| Type* const field_type = access_info.field_type();
|
| if (!field_index.is_inobject()) {
|
| - this_value = this_effect = graph()->NewNode(
|
| + this_receiver = this_effect = graph()->NewNode(
|
| simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
|
| - this_value, this_effect, this_control);
|
| + this_receiver, this_effect, this_control);
|
| }
|
| - FieldAccess field_access;
|
| - field_access.base_is_tagged = kTaggedBase;
|
| - field_access.offset = field_index.offset();
|
| - field_access.name = name;
|
| - field_access.type = field_type;
|
| - field_access.machine_type = kMachAnyTagged;
|
| - if (field_type->Is(Type::UntaggedFloat64())) {
|
| - if (!field_index.is_inobject() || field_index.is_hidden_field() ||
|
| - !FLAG_unbox_double_fields) {
|
| - this_value = this_effect =
|
| - graph()->NewNode(simplified()->LoadField(field_access),
|
| - this_value, this_effect, this_control);
|
| - field_access.offset = HeapNumber::kValueOffset;
|
| - field_access.name = MaybeHandle<Name>();
|
| + FieldAccess field_access = {kTaggedBase, field_index.offset(), name,
|
| + field_type, kMachAnyTagged};
|
| + if (access_mode == kLoad) {
|
| + if (field_type->Is(Type::UntaggedFloat64())) {
|
| + if (!field_index.is_inobject() || field_index.is_hidden_field() ||
|
| + !FLAG_unbox_double_fields) {
|
| + this_receiver = this_effect =
|
| + graph()->NewNode(simplified()->LoadField(field_access),
|
| + this_receiver, this_effect, this_control);
|
| + field_access.offset = HeapNumber::kValueOffset;
|
| + field_access.name = MaybeHandle<Name>();
|
| + }
|
| + field_access.machine_type = kMachFloat64;
|
| + }
|
| + this_value = this_effect =
|
| + graph()->NewNode(simplified()->LoadField(field_access),
|
| + this_receiver, this_effect, this_control);
|
| + } else {
|
| + DCHECK_EQ(kStore, access_mode);
|
| + if (field_type->Is(Type::TaggedSigned())) {
|
| + Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
|
| + Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| + check, this_control);
|
| + exit_controls.push_back(
|
| + graph()->NewNode(common()->IfFalse(), branch));
|
| + this_control = graph()->NewNode(common()->IfTrue(), branch);
|
| + } else if (field_type->Is(Type::TaggedPointer())) {
|
| + Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
|
| + Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
|
| + check, this_control);
|
| + exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
|
| + this_control = graph()->NewNode(common()->IfFalse(), branch);
|
| + if (field_type->NumClasses() > 0) {
|
| + // Emit a (sequence of) map checks for the value.
|
| + ZoneVector<Node*> this_controls(zone());
|
| + Node* value_map = this_effect = graph()->NewNode(
|
| + simplified()->LoadField(AccessBuilder::ForMap()), value,
|
| + this_effect, this_control);
|
| + for (auto i = field_type->Classes(); !i.Done(); i.Advance()) {
|
| + Handle<Map> field_map(i.Current());
|
| + check = graph()->NewNode(
|
| + simplified()->ReferenceEqual(Type::Internal()), value_map,
|
| + jsgraph()->Constant(field_map));
|
| + branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| + check, this_control);
|
| + this_control = graph()->NewNode(common()->IfFalse(), branch);
|
| + this_controls.push_back(
|
| + graph()->NewNode(common()->IfTrue(), branch));
|
| + }
|
| + exit_controls.push_back(this_control);
|
| + int const this_control_count =
|
| + static_cast<int>(this_controls.size());
|
| + this_control =
|
| + (this_control_count == 1)
|
| + ? this_controls.front()
|
| + : graph()->NewNode(common()->Merge(this_control_count),
|
| + this_control_count,
|
| + &this_controls.front());
|
| + }
|
| + } else {
|
| + DCHECK(field_type->Is(Type::Tagged()));
|
| }
|
| - field_access.machine_type = kMachFloat64;
|
| + this_effect = graph()->NewNode(simplified()->StoreField(field_access),
|
| + this_receiver, this_value, this_effect,
|
| + this_control);
|
| }
|
| - this_value = this_effect =
|
| - graph()->NewNode(simplified()->LoadField(field_access), this_value,
|
| - this_effect, this_control);
|
| }
|
|
|
| // Remember the final state for this property access.
|
| @@ -622,6 +672,17 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| }
|
|
|
| // Collect the fallthru control as final "exit" control.
|
| + if (fallthrough_control != control) {
|
| + // Mark the last fallthru branch as deferred.
|
| + Node* branch = NodeProperties::GetControlInput(fallthrough_control);
|
| + DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
|
| + if (fallthrough_control->opcode() == IrOpcode::kIfTrue) {
|
| + NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse));
|
| + } else {
|
| + DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode());
|
| + NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue));
|
| + }
|
| + }
|
| exit_controls.push_back(fallthrough_control);
|
|
|
| // Generate the single "exit" point, where we get if either all map/instance
|
| @@ -641,7 +702,6 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
|
|
|
| // Generate the final merge point for all (polymorphic) branches.
|
| - Node* value;
|
| int const control_count = static_cast<int>(controls.size());
|
| if (control_count == 1) {
|
| value = values.front();
|
| @@ -661,215 +721,37 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| }
|
|
|
|
|
| -Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
|
| +Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
| + DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
|
| NamedAccess const& p = NamedAccessOf(node->op());
|
| - Handle<Name> name = p.name();
|
| - Node* receiver = NodeProperties::GetValueInput(node, 0);
|
| - Node* value = NodeProperties::GetValueInput(node, 1);
|
| - Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - Node* control = NodeProperties::GetControlInput(node);
|
| -
|
| - // Not much we can do if deoptimization support is disabled.
|
| - if (!(flags() & kDeoptimizationEnabled)) return NoChange();
|
| + Node* const value = jsgraph()->Dead();
|
|
|
| - // Extract receiver maps from the STORE_IC using the StoreICNexus.
|
| + // Extract receiver maps from the LOAD_IC using the LoadICNexus.
|
| MapHandleList receiver_maps;
|
| if (!p.feedback().IsValid()) return NoChange();
|
| - StoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
| + LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
| if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
|
| DCHECK_LT(0, receiver_maps.length());
|
|
|
| - // Compute property access infos for the receiver maps.
|
| - ZoneVector<PropertyAccessInfo> access_infos(zone());
|
| - if (!ComputePropertyAccessInfos(receiver_maps, name, kStore, &access_infos)) {
|
| - return NoChange();
|
| - }
|
| -
|
| - // Nothing to do if we have no non-deprecated maps.
|
| - if (access_infos.empty()) return NoChange();
|
| -
|
| - // The final states for every polymorphic branch. We join them with
|
| - // Merge+EffectPhi at the bottom.
|
| - ZoneVector<Node*> effects(zone());
|
| - ZoneVector<Node*> controls(zone());
|
| -
|
| - // The list of "exiting" controls, which currently go to a single deoptimize.
|
| - // TODO(bmeurer): Consider using an IC as fallback.
|
| - Node* const exit_effect = effect;
|
| - ZoneVector<Node*> exit_controls(zone());
|
| -
|
| - // Ensure that {receiver} is a heap object.
|
| - Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
|
| - Node* branch =
|
| - graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
|
| - exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
|
| - control = graph()->NewNode(common()->IfFalse(), branch);
|
| -
|
| - // Load the {receiver} map. The resulting effect is the dominating effect for
|
| - // all (polymorphic) branches.
|
| - Node* receiver_map = effect =
|
| - graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
|
| - receiver, effect, control);
|
| -
|
| - // Generate code for the various different property access patterns.
|
| - Node* fallthrough_control = control;
|
| - for (PropertyAccessInfo const& access_info : access_infos) {
|
| - Node* this_receiver = receiver;
|
| - Node* this_effect = effect;
|
| - Node* this_control;
|
| -
|
| - // Perform map check on {receiver}.
|
| - Type* receiver_type = access_info.receiver_type();
|
| - if (receiver_type->Is(Type::String())) {
|
| - // Emit an instance type check for strings.
|
| - Node* receiver_instance_type = this_effect = graph()->NewNode(
|
| - simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
|
| - receiver_map, this_effect, fallthrough_control);
|
| - Node* check =
|
| - graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type,
|
| - jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
|
| - Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| - check, fallthrough_control);
|
| - fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
|
| - this_control = graph()->NewNode(common()->IfTrue(), branch);
|
| - } else {
|
| - // Emit a (sequence of) map checks for other properties.
|
| - ZoneVector<Node*> this_controls(zone());
|
| - for (auto i = access_info.receiver_type()->Classes(); !i.Done();
|
| - i.Advance()) {
|
| - Handle<Map> map = i.Current();
|
| - Node* check =
|
| - graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
|
| - receiver_map, jsgraph()->Constant(map));
|
| - Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| - check, fallthrough_control);
|
| - this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
|
| - fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
|
| - }
|
| - int const this_control_count = static_cast<int>(this_controls.size());
|
| - this_control =
|
| - (this_control_count == 1)
|
| - ? this_controls.front()
|
| - : graph()->NewNode(common()->Merge(this_control_count),
|
| - this_control_count, &this_controls.front());
|
| - }
|
| -
|
| - // Determine actual holder and perform prototype chain checks.
|
| - Handle<JSObject> holder;
|
| - if (access_info.holder().ToHandle(&holder)) {
|
| - AssumePrototypesStable(receiver_type, holder);
|
| - }
|
| -
|
| - // Generate the actual property access.
|
| - if (access_info.IsDataConstant()) {
|
| - Node* check =
|
| - graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
|
| - jsgraph()->Constant(access_info.constant()));
|
| - Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| - check, this_control);
|
| - exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
|
| - this_control = graph()->NewNode(common()->IfTrue(), branch);
|
| - } else {
|
| - // TODO(bmeurer): This is sort of adhoc, and must be refactored into some
|
| - // common code once we also have support for stores.
|
| - DCHECK(access_info.IsDataField());
|
| - FieldIndex const field_index = access_info.field_index();
|
| - Type* const field_type = access_info.field_type();
|
| - if (!field_index.is_inobject()) {
|
| - this_receiver = this_effect = graph()->NewNode(
|
| - simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
|
| - this_receiver, this_effect, this_control);
|
| - }
|
| - FieldAccess field_access;
|
| - field_access.base_is_tagged = kTaggedBase;
|
| - field_access.offset = field_index.offset();
|
| - field_access.name = name;
|
| - field_access.type = field_type;
|
| - field_access.machine_type = kMachAnyTagged;
|
| - if (field_type->Is(Type::TaggedSigned())) {
|
| - Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
|
| - Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| - check, this_control);
|
| - exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
|
| - this_control = graph()->NewNode(common()->IfTrue(), branch);
|
| - } else if (field_type->Is(Type::TaggedPointer())) {
|
| - Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
|
| - Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
|
| - check, this_control);
|
| - exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
|
| - this_control = graph()->NewNode(common()->IfFalse(), branch);
|
| - if (field_type->NumClasses() > 0) {
|
| - // Emit a (sequence of) map checks for the value.
|
| - ZoneVector<Node*> this_controls(zone());
|
| - Node* value_map = this_effect =
|
| - graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
|
| - value, this_effect, this_control);
|
| - for (auto i = field_type->Classes(); !i.Done(); i.Advance()) {
|
| - Handle<Map> field_map(i.Current());
|
| - check =
|
| - graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
|
| - value_map, jsgraph()->Constant(field_map));
|
| - branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
| - check, this_control);
|
| - this_control = graph()->NewNode(common()->IfFalse(), branch);
|
| - this_controls.push_back(
|
| - graph()->NewNode(common()->IfTrue(), branch));
|
| - }
|
| - exit_controls.push_back(this_control);
|
| - int const this_control_count = static_cast<int>(this_controls.size());
|
| - this_control = (this_control_count == 1)
|
| - ? this_controls.front()
|
| - : graph()->NewNode(
|
| - common()->Merge(this_control_count),
|
| - this_control_count, &this_controls.front());
|
| - }
|
| - } else {
|
| - DCHECK(field_type->Is(Type::Tagged()));
|
| - }
|
| - this_effect =
|
| - graph()->NewNode(simplified()->StoreField(field_access),
|
| - this_receiver, value, this_effect, this_control);
|
| - }
|
| + // Try to lower the named access based on the {receiver_maps}.
|
| + return ReduceNamedAccess(node, value, receiver_maps, p.name(), kLoad);
|
| +}
|
|
|
| - // Remember the final state for this property access.
|
| - effects.push_back(this_effect);
|
| - controls.push_back(this_control);
|
| - }
|
|
|
| - // Collect the fallthru control as final "exit" control.
|
| - exit_controls.push_back(fallthrough_control);
|
| +Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
|
| + DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
|
| + NamedAccess const& p = NamedAccessOf(node->op());
|
| + Node* const value = NodeProperties::GetValueInput(node, 1);
|
|
|
| - // Generate the single "exit" point, where we get if either all map/instance
|
| - // type checks failed, or one of the assumptions inside one of the cases
|
| - // failes (i.e. failing prototype chain check).
|
| - // TODO(bmeurer): Consider falling back to IC here if deoptimization is
|
| - // disabled.
|
| - int const exit_control_count = static_cast<int>(exit_controls.size());
|
| - Node* exit_control =
|
| - (exit_control_count == 1)
|
| - ? exit_controls.front()
|
| - : graph()->NewNode(common()->Merge(exit_control_count),
|
| - exit_control_count, &exit_controls.front());
|
| - Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
|
| - exit_effect, exit_control);
|
| - // TODO(bmeurer): This should be on the AdvancedReducer somehow.
|
| - NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
|
| + // Extract receiver maps from the STORE_IC using the StoreICNexus.
|
| + MapHandleList receiver_maps;
|
| + if (!p.feedback().IsValid()) return NoChange();
|
| + StoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
| + if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
|
| + DCHECK_LT(0, receiver_maps.length());
|
|
|
| - // Generate the final merge point for all (polymorphic) branches.
|
| - int const control_count = static_cast<int>(controls.size());
|
| - if (control_count == 1) {
|
| - effect = effects.front();
|
| - control = controls.front();
|
| - } else {
|
| - control = graph()->NewNode(common()->Merge(control_count), control_count,
|
| - &controls.front());
|
| - effects.push_back(control);
|
| - effect = graph()->NewNode(common()->EffectPhi(control_count),
|
| - control_count + 1, &effects.front());
|
| - }
|
| - return Replace(node, value, effect, control);
|
| + // Try to lower the named access based on the {receiver_maps}.
|
| + return ReduceNamedAccess(node, value, receiver_maps, p.name(), kStore);
|
| }
|
|
|
|
|
|
|