| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/js-typed-lowering.h" | 5 #include "src/compiler/js-typed-lowering.h" |
| 6 | 6 |
| 7 #include "src/ast/modules.h" | 7 #include "src/ast/modules.h" |
| 8 #include "src/builtins/builtins-utils.h" | 8 #include "src/builtins/builtins-utils.h" |
| 9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
| 10 #include "src/compilation-dependencies.h" | 10 #include "src/compilation-dependencies.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 return true; | 63 return true; |
| 64 case CompareOperationHint::kNumber: | 64 case CompareOperationHint::kNumber: |
| 65 *hint = NumberOperationHint::kNumber; | 65 *hint = NumberOperationHint::kNumber; |
| 66 return true; | 66 return true; |
| 67 case CompareOperationHint::kNumberOrOddball: | 67 case CompareOperationHint::kNumberOrOddball: |
| 68 *hint = NumberOperationHint::kNumberOrOddball; | 68 *hint = NumberOperationHint::kNumberOrOddball; |
| 69 return true; | 69 return true; |
| 70 case CompareOperationHint::kAny: | 70 case CompareOperationHint::kAny: |
| 71 case CompareOperationHint::kNone: | 71 case CompareOperationHint::kNone: |
| 72 case CompareOperationHint::kString: | 72 case CompareOperationHint::kString: |
| 73 case CompareOperationHint::kReceiver: |
| 73 case CompareOperationHint::kInternalizedString: | 74 case CompareOperationHint::kInternalizedString: |
| 74 break; | 75 break; |
| 75 } | 76 } |
| 76 } | 77 } |
| 77 return false; | 78 return false; |
| 78 } | 79 } |
| 79 | 80 |
| 80 bool IsInternalizedStringCompareOperation() { | 81 bool IsInternalizedStringCompareOperation() { |
| 81 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) { | 82 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) { |
| 82 DCHECK_EQ(1, node_->op()->EffectOutputCount()); | 83 DCHECK_EQ(1, node_->op()->EffectOutputCount()); |
| 83 return (CompareOperationHintOf(node_->op()) == | 84 return (CompareOperationHintOf(node_->op()) == |
| 84 CompareOperationHint::kInternalizedString) && | 85 CompareOperationHint::kInternalizedString) && |
| 85 BothInputsMaybe(Type::InternalizedString()); | 86 BothInputsMaybe(Type::InternalizedString()); |
| 86 } | 87 } |
| 87 return false; | 88 return false; |
| 88 } | 89 } |
| 89 | 90 |
| 91 bool IsReceiverCompareOperation() { |
| 92 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) { |
| 93 DCHECK_EQ(1, node_->op()->EffectOutputCount()); |
| 94 return (CompareOperationHintOf(node_->op()) == |
| 95 CompareOperationHint::kReceiver) && |
| 96 BothInputsMaybe(Type::Receiver()); |
| 97 } |
| 98 return false; |
| 99 } |
| 100 |
| 90 // Check if a string addition will definitely result in creating a ConsString, | 101 // Check if a string addition will definitely result in creating a ConsString, |
| 91 // i.e. if the combined length of the resulting string exceeds the ConsString | 102 // i.e. if the combined length of the resulting string exceeds the ConsString |
| 92 // minimum length. | 103 // minimum length. |
| 93 bool ShouldCreateConsString() { | 104 bool ShouldCreateConsString() { |
| 94 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode()); | 105 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode()); |
| 95 if (BothInputsAre(Type::String()) || | 106 if (BothInputsAre(Type::String()) || |
| 96 ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) && | 107 ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) && |
| 97 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) { | 108 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) { |
| 98 HeapObjectBinopMatcher m(node_); | 109 HeapObjectBinopMatcher m(node_); |
| 99 if (m.right().HasValue() && m.right().Value()->IsString()) { | 110 if (m.right().HasValue() && m.right().Value()->IsString()) { |
| 100 Handle<String> right_string = Handle<String>::cast(m.right().Value()); | 111 Handle<String> right_string = Handle<String>::cast(m.right().Value()); |
| 101 if (right_string->length() >= ConsString::kMinLength) return true; | 112 if (right_string->length() >= ConsString::kMinLength) return true; |
| 102 } | 113 } |
| 103 if (m.left().HasValue() && m.left().Value()->IsString()) { | 114 if (m.left().HasValue() && m.left().Value()->IsString()) { |
| 104 Handle<String> left_string = Handle<String>::cast(m.left().Value()); | 115 Handle<String> left_string = Handle<String>::cast(m.left().Value()); |
| 105 if (left_string->length() >= ConsString::kMinLength) { | 116 if (left_string->length() >= ConsString::kMinLength) { |
| 106 // The invariant for ConsString requires the left hand side to be | 117 // The invariant for ConsString requires the left hand side to be |
| 107 // a sequential or external string if the right hand side is the | 118 // a sequential or external string if the right hand side is the |
| 108 // empty string. Since we don't know anything about the right hand | 119 // empty string. Since we don't know anything about the right hand |
| 109 // side here, we must ensure that the left hand side satisfy the | 120 // side here, we must ensure that the left hand side satisfy the |
| 110 // constraints independent of the right hand side. | 121 // constraints independent of the right hand side. |
| 111 return left_string->IsSeqString() || left_string->IsExternalString(); | 122 return left_string->IsSeqString() || left_string->IsExternalString(); |
| 112 } | 123 } |
| 113 } | 124 } |
| 114 } | 125 } |
| 115 return false; | 126 return false; |
| 116 } | 127 } |
| 117 | 128 |
| 129 // Inserts a CheckReceiver for the left input. |
| 130 void CheckLeftInputToReceiver() { |
| 131 Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(), |
| 132 effect(), control()); |
| 133 node_->ReplaceInput(0, left_input); |
| 134 update_effect(left_input); |
| 135 } |
| 136 |
| 137 // Checks that both inputs are Receiver, and if we don't know |
| 138 // statically that one side is already a Receiver, insert a |
| 139 // CheckReceiver node. |
| 140 void CheckInputsToReceiver() { |
| 141 if (!left_type()->Is(Type::Receiver())) { |
| 142 CheckLeftInputToReceiver(); |
| 143 } |
| 144 if (!right_type()->Is(Type::Receiver())) { |
| 145 Node* right_input = graph()->NewNode(simplified()->CheckReceiver(), |
| 146 right(), effect(), control()); |
| 147 node_->ReplaceInput(1, right_input); |
| 148 update_effect(right_input); |
| 149 } |
| 150 } |
| 151 |
| 118 // Checks that both inputs are InternalizedString, and if we don't know | 152 // Checks that both inputs are InternalizedString, and if we don't know |
| 119 // statically that one side is already an InternalizedString, insert a | 153 // statically that one side is already an InternalizedString, insert a |
| 120 // CheckInternalizedString node. | 154 // CheckInternalizedString node. |
| 121 void CheckInputsToInternalizedString() { | 155 void CheckInputsToInternalizedString() { |
| 122 if (!left_type()->Is(Type::UniqueName())) { | 156 if (!left_type()->Is(Type::UniqueName())) { |
| 123 Node* left_input = graph()->NewNode( | 157 Node* left_input = graph()->NewNode( |
| 124 simplified()->CheckInternalizedString(), left(), effect(), control()); | 158 simplified()->CheckInternalizedString(), left(), effect(), control()); |
| 125 node_->ReplaceInput(0, left_input); | 159 node_->ReplaceInput(0, left_input); |
| 126 update_effect(left_input); | 160 update_effect(left_input); |
| 127 } | 161 } |
| (...skipping 789 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 917 | 951 |
| 918 NumberOperationHint hint; | 952 NumberOperationHint hint; |
| 919 if (r.BothInputsAre(Type::Signed32()) || | 953 if (r.BothInputsAre(Type::Signed32()) || |
| 920 r.BothInputsAre(Type::Unsigned32())) { | 954 r.BothInputsAre(Type::Unsigned32())) { |
| 921 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); | 955 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); |
| 922 } else if (r.GetCompareNumberOperationHint(&hint)) { | 956 } else if (r.GetCompareNumberOperationHint(&hint)) { |
| 923 return r.ChangeToSpeculativeOperator( | 957 return r.ChangeToSpeculativeOperator( |
| 924 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); | 958 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); |
| 925 } else if (r.BothInputsAre(Type::Number())) { | 959 } else if (r.BothInputsAre(Type::Number())) { |
| 926 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); | 960 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); |
| 961 } else if (r.IsReceiverCompareOperation()) { |
| 962 r.CheckInputsToReceiver(); |
| 963 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); |
| 927 } | 964 } |
| 928 return NoChange(); | 965 return NoChange(); |
| 929 } | 966 } |
| 930 | 967 |
| 931 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { | 968 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { |
| 932 JSBinopReduction r(this, node); | 969 JSBinopReduction r(this, node); |
| 933 if (r.left() == r.right()) { | 970 if (r.left() == r.right()) { |
| 934 // x === x is always true if x != NaN | 971 // x === x is always true if x != NaN |
| 935 if (!r.left_type()->Maybe(Type::NaN())) { | 972 if (!r.left_type()->Maybe(Type::NaN())) { |
| 936 Node* replacement = jsgraph()->BooleanConstant(!invert); | 973 Node* replacement = jsgraph()->BooleanConstant(!invert); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 | 1005 |
| 969 NumberOperationHint hint; | 1006 NumberOperationHint hint; |
| 970 if (r.BothInputsAre(Type::Signed32()) || | 1007 if (r.BothInputsAre(Type::Signed32()) || |
| 971 r.BothInputsAre(Type::Unsigned32())) { | 1008 r.BothInputsAre(Type::Unsigned32())) { |
| 972 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); | 1009 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); |
| 973 } else if (r.GetCompareNumberOperationHint(&hint)) { | 1010 } else if (r.GetCompareNumberOperationHint(&hint)) { |
| 974 return r.ChangeToSpeculativeOperator( | 1011 return r.ChangeToSpeculativeOperator( |
| 975 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); | 1012 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); |
| 976 } else if (r.BothInputsAre(Type::Number())) { | 1013 } else if (r.BothInputsAre(Type::Number())) { |
| 977 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); | 1014 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); |
| 1015 } else if (r.IsReceiverCompareOperation()) { |
| 1016 // For strict equality, it's enough to know that one input is a Receiver, |
| 1017 // as a strict equality comparison with a Receiver can only yield true if |
| 1018 // both sides refer to the same Receiver than. |
| 1019 r.CheckLeftInputToReceiver(); |
| 1020 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert); |
| 978 } | 1021 } |
| 979 return NoChange(); | 1022 return NoChange(); |
| 980 } | 1023 } |
| 981 | 1024 |
| 982 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { | 1025 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
| 983 Node* const input = node->InputAt(0); | 1026 Node* const input = node->InputAt(0); |
| 984 Type* const input_type = NodeProperties::GetType(input); | 1027 Type* const input_type = NodeProperties::GetType(input); |
| 985 if (input_type->Is(Type::Boolean())) { | 1028 if (input_type->Is(Type::Boolean())) { |
| 986 // JSToBoolean(x:boolean) => x | 1029 // JSToBoolean(x:boolean) => x |
| 987 return Replace(input); | 1030 return Replace(input); |
| (...skipping 1355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2343 } | 2386 } |
| 2344 | 2387 |
| 2345 | 2388 |
| 2346 CompilationDependencies* JSTypedLowering::dependencies() const { | 2389 CompilationDependencies* JSTypedLowering::dependencies() const { |
| 2347 return dependencies_; | 2390 return dependencies_; |
| 2348 } | 2391 } |
| 2349 | 2392 |
| 2350 } // namespace compiler | 2393 } // namespace compiler |
| 2351 } // namespace internal | 2394 } // namespace internal |
| 2352 } // namespace v8 | 2395 } // namespace v8 |
| OLD | NEW |