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 82346b588b8b2ee8622da4e51a32f5bb9c250110..0fa6fe76118c3bd5aac2a184bc69fa59c3a6575e 100644 |
--- a/src/compiler/js-native-context-specialization.cc |
+++ b/src/compiler/js-native-context-specialization.cc |
@@ -354,10 +354,10 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( |
// 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)); |
+ Node* branch = graph()->NewNode(common()->Branch(), check, control); |
control = graph()->NewNode(common()->IfFalse(), branch); |
+ Node* receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); |
+ Node* receiverissmi_effect = effect; |
// Load the {receiver} map. The resulting effect is the dominating effect for |
// all (polymorphic) branches. |
@@ -388,8 +388,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( |
fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
this_control = graph()->NewNode(common()->IfTrue(), branch); |
} else { |
- // Emit a (sequence of) map checks for other properties. |
+ // Emit a (sequence of) map checks for other {receiver}s. |
ZoneVector<Node*> this_controls(zone()); |
+ ZoneVector<Node*> this_effects(zone()); |
for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |
i.Advance()) { |
Handle<Map> map = i.Current(); |
@@ -398,15 +399,37 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( |
receiver_map, jsgraph()->Constant(map)); |
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); |
+ this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |
+ this_effects.push_back(this_effect); |
} |
+ |
+ // The Number case requires special treatment to also deal with Smis. |
+ if (receiver_type->Is(Type::Number())) { |
+ // Join this check with the "receiver is smi" check above, and mark the |
+ // "receiver is smi" check as "consumed" so that we don't deoptimize if |
+ // the {receiver} is actually a Smi. |
+ if (receiverissmi_control != nullptr) { |
+ this_controls.push_back(receiverissmi_control); |
+ this_effects.push_back(receiverissmi_effect); |
+ receiverissmi_control = receiverissmi_effect = nullptr; |
+ } |
+ } |
+ |
+ // Create dominating Merge+EffectPhi for this {receiver} type. |
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()); |
+ this_effects.push_back(this_control); |
+ int const this_effect_count = static_cast<int>(this_effects.size()); |
+ this_effect = |
+ (this_control_count == 1) |
+ ? this_effects.front() |
+ : graph()->NewNode(common()->EffectPhi(this_control_count), |
+ this_effect_count, &this_effects.front()); |
} |
// Determine actual holder and perform prototype chain checks. |
@@ -584,17 +607,19 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( |
// Collect the fallthrough control as final "exit" control. |
if (fallthrough_control != control) { |
// Mark the last fallthrough 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)); |
- } |
+ MarkAsDeferred(fallthrough_control); |
} |
exit_controls.push_back(fallthrough_control); |
+ // Also collect the "receiver is smi" control if we didn't handle the case of |
+ // Number primitives in the polymorphic branches above. |
+ if (receiverissmi_control != nullptr) { |
+ // Mark the "receiver is smi" case as deferred. |
+ MarkAsDeferred(receiverissmi_control); |
+ DCHECK_EQ(exit_effect, receiverissmi_effect); |
+ exit_controls.push_back(receiverissmi_control); |
+ } |
+ |
// 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). |
@@ -876,14 +901,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( |
// Collect the fallthrough control as final "exit" control. |
if (fallthrough_control != control) { |
// Mark the last fallthrough 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)); |
- } |
+ MarkAsDeferred(fallthrough_control); |
} |
exit_controls.push_back(fallthrough_control); |
@@ -1053,6 +1071,18 @@ void JSNativeContextSpecialization::AssumePrototypesStable( |
} |
+void JSNativeContextSpecialization::MarkAsDeferred(Node* if_projection) { |
+ Node* branch = NodeProperties::GetControlInput(if_projection); |
+ DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
+ if (if_projection->opcode() == IrOpcode::kIfTrue) { |
+ NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse)); |
+ } else { |
+ DCHECK_EQ(IrOpcode::kIfFalse, if_projection->opcode()); |
+ NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue)); |
+ } |
+} |
+ |
+ |
Graph* JSNativeContextSpecialization::graph() const { |
return jsgraph()->graph(); |
} |