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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 break; | 73 break; |
74 } | 74 } |
75 } | 75 } |
76 return false; | 76 return false; |
77 } | 77 } |
78 | |
79 bool IsStringCompareOperation() { | |
80 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) { | |
81 DCHECK_EQ(1, node_->op()->EffectOutputCount()); | |
82 return (CompareOperationHintOf(node_->op()) == | |
83 CompareOperationHint::kString) && | |
84 BothInputsMaybe(Type::String()); | |
85 } | |
86 return false; | |
87 } | |
88 | 78 |
89 // Check if a string addition will definitely result in creating a ConsString, | 79 // Check if a string addition will definitely result in creating a ConsString, |
90 // i.e. if the combined length of the resulting string exceeds the ConsString | 80 // i.e. if the combined length of the resulting string exceeds the ConsString |
91 // minimum length. | 81 // minimum length. |
92 bool ShouldCreateConsString() { | 82 bool ShouldCreateConsString() { |
93 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode()); | 83 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode()); |
94 if (BothInputsAre(Type::String()) || | 84 if (BothInputsAre(Type::String()) || |
95 ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) && | 85 ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) && |
96 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) { | 86 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) { |
97 HeapObjectBinopMatcher m(node_); | 87 HeapObjectBinopMatcher m(node_); |
98 if (m.right().HasValue() && m.right().Value()->IsString()) { | 88 if (m.right().HasValue() && m.right().Value()->IsString()) { |
99 Handle<String> right_string = Handle<String>::cast(m.right().Value()); | 89 Handle<String> right_string = Handle<String>::cast(m.right().Value()); |
100 if (right_string->length() >= ConsString::kMinLength) return true; | 90 if (right_string->length() >= ConsString::kMinLength) return true; |
101 } | 91 } |
102 if (m.left().HasValue() && m.left().Value()->IsString()) { | 92 if (m.left().HasValue() && m.left().Value()->IsString()) { |
103 Handle<String> left_string = Handle<String>::cast(m.left().Value()); | 93 Handle<String> left_string = Handle<String>::cast(m.left().Value()); |
104 if (left_string->length() >= ConsString::kMinLength) { | 94 if (left_string->length() >= ConsString::kMinLength) { |
105 // The invariant for ConsString requires the left hand side to be | 95 // The invariant for ConsString requires the left hand side to be |
106 // a sequential or external string if the right hand side is the | 96 // a sequential or external string if the right hand side is the |
107 // empty string. Since we don't know anything about the right hand | 97 // empty string. Since we don't know anything about the right hand |
108 // side here, we must ensure that the left hand side satisfy the | 98 // side here, we must ensure that the left hand side satisfy the |
109 // constraints independent of the right hand side. | 99 // constraints independent of the right hand side. |
110 return left_string->IsSeqString() || left_string->IsExternalString(); | 100 return left_string->IsSeqString() || left_string->IsExternalString(); |
111 } | 101 } |
112 } | 102 } |
113 } | 103 } |
114 return false; | 104 return false; |
115 } | 105 } |
116 | 106 |
117 // Checks that both inputs are String, and if we don't know statically that | |
118 // one side is already a String, insert a CheckString node. | |
119 void CheckInputsToString() { | |
120 if (!left_type()->Is(Type::String())) { | |
121 Node* left_input = graph()->NewNode(simplified()->CheckString(), left(), | |
122 effect(), control()); | |
123 node_->ReplaceInput(0, left_input); | |
124 update_effect(left_input); | |
125 } | |
126 if (!right_type()->Is(Type::String())) { | |
127 Node* right_input = graph()->NewNode(simplified()->CheckString(), right(), | |
128 effect(), control()); | |
129 node_->ReplaceInput(1, right_input); | |
130 update_effect(right_input); | |
131 } | |
132 } | |
133 | |
134 void ConvertInputsToNumber() { | 107 void ConvertInputsToNumber() { |
135 // To convert the inputs to numbers, we have to provide frame states | 108 // To convert the inputs to numbers, we have to provide frame states |
136 // for lazy bailouts in the ToNumber conversions. | 109 // for lazy bailouts in the ToNumber conversions. |
137 // We use a little hack here: we take the frame state before the binary | 110 // We use a little hack here: we take the frame state before the binary |
138 // operation and use it to construct the frame states for the conversion | 111 // operation and use it to construct the frame states for the conversion |
139 // so that after the deoptimization, the binary operation IC gets | 112 // so that after the deoptimization, the binary operation IC gets |
140 // already converted values from full code. This way we are sure that we | 113 // already converted values from full code. This way we are sure that we |
141 // will not re-do any of the side effects. | 114 // will not re-do any of the side effects. |
142 | 115 |
143 Node* left_input = nullptr; | 116 Node* left_input = nullptr; |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 } | 310 } |
338 | 311 |
339 bool LeftInputIs(Type* t) { return left_type()->Is(t); } | 312 bool LeftInputIs(Type* t) { return left_type()->Is(t); } |
340 | 313 |
341 bool RightInputIs(Type* t) { return right_type()->Is(t); } | 314 bool RightInputIs(Type* t) { return right_type()->Is(t); } |
342 | 315 |
343 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } | 316 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } |
344 | 317 |
345 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); } | 318 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); } |
346 | 319 |
347 bool BothInputsMaybe(Type* t) { | |
348 return left_type()->Maybe(t) && right_type()->Maybe(t); | |
349 } | |
350 | |
351 bool OneInputCannotBe(Type* t) { | 320 bool OneInputCannotBe(Type* t) { |
352 return !left_type()->Maybe(t) || !right_type()->Maybe(t); | 321 return !left_type()->Maybe(t) || !right_type()->Maybe(t); |
353 } | 322 } |
354 | 323 |
355 bool NeitherInputCanBe(Type* t) { | 324 bool NeitherInputCanBe(Type* t) { |
356 return !left_type()->Maybe(t) && !right_type()->Maybe(t); | 325 return !left_type()->Maybe(t) && !right_type()->Maybe(t); |
357 } | 326 } |
358 | 327 |
359 Node* effect() { return NodeProperties::GetEffectInput(node_); } | 328 Node* effect() { return NodeProperties::GetEffectInput(node_); } |
360 Node* control() { return NodeProperties::GetControlInput(node_); } | 329 Node* control() { return NodeProperties::GetControlInput(node_); } |
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 less_than_or_equal = simplified()->NumberLessThanOrEqual(); | 740 less_than_or_equal = simplified()->NumberLessThanOrEqual(); |
772 } else if (r.GetCompareNumberOperationHint(&hint)) { | 741 } else if (r.GetCompareNumberOperationHint(&hint)) { |
773 less_than = simplified()->SpeculativeNumberLessThan(hint); | 742 less_than = simplified()->SpeculativeNumberLessThan(hint); |
774 less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint); | 743 less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint); |
775 } else if (r.OneInputCannotBe(Type::StringOrReceiver()) && | 744 } else if (r.OneInputCannotBe(Type::StringOrReceiver()) && |
776 (r.BothInputsAre(Type::PlainPrimitive()) || | 745 (r.BothInputsAre(Type::PlainPrimitive()) || |
777 !(flags() & kDeoptimizationEnabled))) { | 746 !(flags() & kDeoptimizationEnabled))) { |
778 r.ConvertInputsToNumber(); | 747 r.ConvertInputsToNumber(); |
779 less_than = simplified()->NumberLessThan(); | 748 less_than = simplified()->NumberLessThan(); |
780 less_than_or_equal = simplified()->NumberLessThanOrEqual(); | 749 less_than_or_equal = simplified()->NumberLessThanOrEqual(); |
781 } else if (r.IsStringCompareOperation()) { | |
782 r.CheckInputsToString(); | |
783 less_than = simplified()->StringLessThan(); | |
784 less_than_or_equal = simplified()->StringLessThanOrEqual(); | |
785 } else { | 750 } else { |
786 return NoChange(); | 751 return NoChange(); |
787 } | 752 } |
788 const Operator* comparison; | 753 const Operator* comparison; |
789 switch (node->opcode()) { | 754 switch (node->opcode()) { |
790 case IrOpcode::kJSLessThan: | 755 case IrOpcode::kJSLessThan: |
791 comparison = less_than; | 756 comparison = less_than; |
792 break; | 757 break; |
793 case IrOpcode::kJSGreaterThan: | 758 case IrOpcode::kJSGreaterThan: |
794 comparison = less_than; | 759 comparison = less_than; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 | 878 |
914 NumberOperationHint hint; | 879 NumberOperationHint hint; |
915 if (r.BothInputsAre(Type::Signed32()) || | 880 if (r.BothInputsAre(Type::Signed32()) || |
916 r.BothInputsAre(Type::Unsigned32())) { | 881 r.BothInputsAre(Type::Unsigned32())) { |
917 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); | 882 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); |
918 } else if (r.GetCompareNumberOperationHint(&hint)) { | 883 } else if (r.GetCompareNumberOperationHint(&hint)) { |
919 return r.ChangeToSpeculativeOperator( | 884 return r.ChangeToSpeculativeOperator( |
920 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); | 885 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); |
921 } else if (r.BothInputsAre(Type::Number())) { | 886 } else if (r.BothInputsAre(Type::Number())) { |
922 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); | 887 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); |
923 } else if (r.IsStringCompareOperation()) { | |
924 r.CheckInputsToString(); | |
925 return r.ChangeToPureOperator(simplified()->StringEqual(), invert); | |
926 } | 888 } |
927 return NoChange(); | 889 return NoChange(); |
928 } | 890 } |
929 | 891 |
930 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { | 892 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { |
931 JSBinopReduction r(this, node); | 893 JSBinopReduction r(this, node); |
932 if (r.left() == r.right()) { | 894 if (r.left() == r.right()) { |
933 // x === x is always true if x != NaN | 895 // x === x is always true if x != NaN |
934 if (!r.left_type()->Maybe(Type::NaN())) { | 896 if (!r.left_type()->Maybe(Type::NaN())) { |
935 Node* replacement = jsgraph()->BooleanConstant(!invert); | 897 Node* replacement = jsgraph()->BooleanConstant(!invert); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
978 | 940 |
979 NumberOperationHint hint; | 941 NumberOperationHint hint; |
980 if (r.BothInputsAre(Type::Signed32()) || | 942 if (r.BothInputsAre(Type::Signed32()) || |
981 r.BothInputsAre(Type::Unsigned32())) { | 943 r.BothInputsAre(Type::Unsigned32())) { |
982 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); | 944 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); |
983 } else if (r.GetCompareNumberOperationHint(&hint)) { | 945 } else if (r.GetCompareNumberOperationHint(&hint)) { |
984 return r.ChangeToSpeculativeOperator( | 946 return r.ChangeToSpeculativeOperator( |
985 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); | 947 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean()); |
986 } else if (r.BothInputsAre(Type::Number())) { | 948 } else if (r.BothInputsAre(Type::Number())) { |
987 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); | 949 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert); |
988 } else if (r.IsStringCompareOperation()) { | |
989 r.CheckInputsToString(); | |
990 return r.ChangeToPureOperator(simplified()->StringEqual(), invert); | |
991 } | 950 } |
992 return NoChange(); | 951 return NoChange(); |
993 } | 952 } |
994 | 953 |
995 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { | 954 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
996 Node* const input = node->InputAt(0); | 955 Node* const input = node->InputAt(0); |
997 Type* const input_type = NodeProperties::GetType(input); | 956 Type* const input_type = NodeProperties::GetType(input); |
998 if (input_type->Is(Type::Boolean())) { | 957 if (input_type->Is(Type::Boolean())) { |
999 // JSToBoolean(x:boolean) => x | 958 // JSToBoolean(x:boolean) => x |
1000 return Replace(input); | 959 return Replace(input); |
(...skipping 1312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2313 } | 2272 } |
2314 | 2273 |
2315 | 2274 |
2316 CompilationDependencies* JSTypedLowering::dependencies() const { | 2275 CompilationDependencies* JSTypedLowering::dependencies() const { |
2317 return dependencies_; | 2276 return dependencies_; |
2318 } | 2277 } |
2319 | 2278 |
2320 } // namespace compiler | 2279 } // namespace compiler |
2321 } // namespace internal | 2280 } // namespace internal |
2322 } // namespace v8 | 2281 } // namespace v8 |
OLD | NEW |