Index: src/compiler/js-typed-lowering.cc |
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc |
index 2547e67953548618c9d0261ca49ea81df757d0b6..f3b8012ea313fcae2d4aa02282a57bbb29aaadc2 100644 |
--- a/src/compiler/js-typed-lowering.cc |
+++ b/src/compiler/js-typed-lowering.cc |
@@ -107,17 +107,25 @@ class JSBinopReduction final { |
// already converted values from full code. This way we are sure that we |
// will not re-do any of the side effects. |
- Node* left_input = |
- left_type()->Is(Type::PlainPrimitive()) |
- ? ConvertPlainPrimitiveToNumber(left()) |
- : ConvertToNumber(left(), |
- CreateFrameStateForLeftInput(frame_state)); |
- |
- Node* right_input = |
- right_type()->Is(Type::PlainPrimitive()) |
- ? ConvertPlainPrimitiveToNumber(right()) |
- : ConvertToNumber(right(), CreateFrameStateForRightInput( |
+ Node* left_input = nullptr; |
+ Node* right_input = nullptr; |
+ bool left_is_primitive = left_type()->Is(Type::PlainPrimitive()); |
+ bool right_is_primitive = right_type()->Is(Type::PlainPrimitive()); |
+ bool handles_exception = NodeProperties::IsExceptionalCall(node_); |
+ |
+ if (!left_is_primitive && !right_is_primitive && handles_exception) { |
+ ConvertBothInputsToNumber(&left_input, &right_input, frame_state); |
+ } else { |
+ left_input = left_is_primitive |
+ ? ConvertPlainPrimitiveToNumber(left()) |
+ : ConvertSingleInputToNumber( |
+ left(), CreateFrameStateForLeftInput(frame_state)); |
+ right_input = right_is_primitive |
+ ? ConvertPlainPrimitiveToNumber(right()) |
+ : ConvertSingleInputToNumber( |
+ right(), CreateFrameStateForRightInput( |
frame_state, left_input)); |
+ } |
node_->ReplaceInput(0, left_input); |
node_->ReplaceInput(1, right_input); |
@@ -226,6 +234,7 @@ class JSBinopReduction final { |
JSGraph* jsgraph() { return lowering_->jsgraph(); } |
JSOperatorBuilder* javascript() { return lowering_->javascript(); } |
MachineOperatorBuilder* machine() { return lowering_->machine(); } |
+ CommonOperatorBuilder* common() { return jsgraph()->common(); } |
Zone* zone() const { return graph()->zone(); } |
private: |
@@ -324,16 +333,61 @@ class JSBinopReduction final { |
jsgraph()->EmptyFrameState(), graph()->start(), graph()->start()); |
} |
- Node* ConvertToNumber(Node* node, Node* frame_state) { |
- if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) { |
- return ConvertPlainPrimitiveToNumber(node); |
- } else { |
- Node* const n = |
- graph()->NewNode(javascript()->ToNumber(), node, context(), |
- frame_state, effect(), control()); |
- update_effect(n); |
- return n; |
+ Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) { |
+ DCHECK(!NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())); |
+ Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(), |
+ frame_state, effect(), control()); |
+ NodeProperties::ReplaceUses(node_, node_, node_, n, n); |
+ update_effect(n); |
+ return n; |
+ } |
+ |
+ void ConvertBothInputsToNumber(Node** left_result, Node** right_result, |
+ Node* frame_state) { |
+ Node* projections[2]; |
+ |
+ // Find {IfSuccess} and {IfException} continuations of the operation. |
+ NodeProperties::CollectControlProjections(node_, projections, 2); |
+ IfExceptionHint hint = OpParameter<IfExceptionHint>(projections[1]); |
+ Node* if_exception = projections[1]; |
+ Node* if_success = projections[0]; |
+ |
+ // Insert two ToNumber() operations that both potentially throw. |
+ Node* left_state = CreateFrameStateForLeftInput(frame_state); |
+ Node* left_conv = |
+ graph()->NewNode(javascript()->ToNumber(), left(), context(), |
+ left_state, effect(), control()); |
+ Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv); |
+ Node* right_state = CreateFrameStateForRightInput(frame_state, left_conv); |
+ Node* right_conv = |
+ graph()->NewNode(javascript()->ToNumber(), right(), context(), |
+ right_state, left_conv, left_success); |
+ Node* left_exception = |
+ graph()->NewNode(common()->IfException(hint), left_conv, left_conv); |
+ Node* right_exception = |
+ graph()->NewNode(common()->IfException(hint), right_conv, right_conv); |
+ NodeProperties::ReplaceControlInput(if_success, right_conv); |
+ update_effect(right_conv); |
+ |
+ // Wire conversions to existing {IfException} continuation. |
+ Node* exception_merge = if_exception; |
+ Node* exception_value = |
+ graph()->NewNode(common()->Phi(kMachAnyTagged, 2), left_exception, |
+ right_exception, exception_merge); |
+ Node* exception_effect = |
+ graph()->NewNode(common()->EffectPhi(2), left_exception, |
+ right_exception, exception_merge); |
+ for (Edge edge : exception_merge->use_edges()) { |
+ if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect); |
+ if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value); |
} |
+ NodeProperties::RemoveBounds(exception_merge); |
+ exception_merge->ReplaceInput(0, left_exception); |
+ exception_merge->ReplaceInput(1, right_exception); |
+ exception_merge->set_op(common()->Merge(2)); |
+ |
+ *left_result = left_conv; |
+ *right_result = right_conv; |
} |
Node* ConvertToUI32(Node* node, Signedness signedness) { |