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/code-factory.h" | 5 #include "src/code-factory.h" |
6 #include "src/code-stubs.h" | 6 #include "src/code-stubs.h" |
7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
8 #include "src/compiler/js-generic-lowering.h" | 8 #include "src/compiler/js-generic-lowering.h" |
9 #include "src/compiler/machine-operator.h" | 9 #include "src/compiler/machine-operator.h" |
10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 return result; | 123 return result; |
124 } | 124 } |
125 | 125 |
126 | 126 |
127 void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) { | 127 void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) { |
128 Callable callable = CodeFactory::CompareIC(isolate(), token); | 128 Callable callable = CodeFactory::CompareIC(isolate(), token); |
129 bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op()); | 129 bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op()); |
130 CallDescriptor* desc_compare = Linkage::GetStubCallDescriptor( | 130 CallDescriptor* desc_compare = Linkage::GetStubCallDescriptor( |
131 isolate(), zone(), callable.descriptor(), 0, | 131 isolate(), zone(), callable.descriptor(), 0, |
132 CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node)); | 132 CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node)); |
| 133 |
| 134 // Create a new call node asking a CompareIC for help. |
133 NodeVector inputs(zone()); | 135 NodeVector inputs(zone()); |
134 inputs.reserve(node->InputCount() + 1); | 136 inputs.reserve(node->InputCount() + 1); |
135 inputs.push_back(jsgraph()->HeapConstant(callable.code())); | 137 inputs.push_back(jsgraph()->HeapConstant(callable.code())); |
136 inputs.push_back(NodeProperties::GetValueInput(node, 0)); | 138 inputs.push_back(NodeProperties::GetValueInput(node, 0)); |
137 inputs.push_back(NodeProperties::GetValueInput(node, 1)); | 139 inputs.push_back(NodeProperties::GetValueInput(node, 1)); |
138 inputs.push_back(NodeProperties::GetContextInput(node)); | 140 inputs.push_back(NodeProperties::GetContextInput(node)); |
139 if (node->op()->HasProperty(Operator::kPure)) { | 141 if (node->op()->HasProperty(Operator::kPure)) { |
140 // A pure (strict) comparison doesn't have an effect, control or frame | 142 // A pure (strict) comparison doesn't have an effect, control or frame |
141 // state. But for the graph, we need to add control and effect inputs. | 143 // state. But for the graph, we need to add control and effect inputs. |
142 DCHECK(!has_frame_state); | 144 DCHECK(!has_frame_state); |
143 inputs.push_back(graph()->start()); | 145 inputs.push_back(graph()->start()); |
144 inputs.push_back(graph()->start()); | 146 inputs.push_back(graph()->start()); |
145 } else { | 147 } else { |
146 DCHECK(has_frame_state == FLAG_turbo_deoptimization); | 148 DCHECK(has_frame_state == FLAG_turbo_deoptimization); |
147 if (FLAG_turbo_deoptimization) { | 149 if (FLAG_turbo_deoptimization) { |
148 inputs.push_back(NodeProperties::GetFrameStateInput(node)); | 150 inputs.push_back(NodeProperties::GetFrameStateInput(node)); |
149 } | 151 } |
150 inputs.push_back(NodeProperties::GetEffectInput(node)); | 152 inputs.push_back(NodeProperties::GetEffectInput(node)); |
151 inputs.push_back(NodeProperties::GetControlInput(node)); | 153 inputs.push_back(NodeProperties::GetControlInput(node)); |
152 } | 154 } |
153 Node* compare = | 155 Node* compare = |
154 graph()->NewNode(common()->Call(desc_compare), | 156 graph()->NewNode(common()->Call(desc_compare), |
155 static_cast<int>(inputs.size()), &inputs.front()); | 157 static_cast<int>(inputs.size()), &inputs.front()); |
| 158 NodeProperties::SetBounds( |
| 159 compare, Bounds(Type::None(zone()), Type::UntaggedSigned(zone()))); |
156 | 160 |
157 node->ReplaceInput(0, compare); | 161 // Decide how the return value from the above CompareIC can be converted into |
158 node->ReplaceInput(1, jsgraph()->SmiConstant(token)); | 162 // a JavaScript boolean oddball depending on the given token. |
| 163 Node* false_value = jsgraph()->FalseConstant(); |
| 164 Node* true_value = jsgraph()->TrueConstant(); |
| 165 const Operator* op = nullptr; |
| 166 switch (token) { |
| 167 case Token::EQ: // a == 0 |
| 168 case Token::EQ_STRICT: |
| 169 op = machine()->WordEqual(); |
| 170 break; |
| 171 case Token::NE: // a != 0 becomes !(a == 0) |
| 172 case Token::NE_STRICT: |
| 173 op = machine()->WordEqual(); |
| 174 std::swap(true_value, false_value); |
| 175 break; |
| 176 case Token::LT: // a < 0 |
| 177 op = machine()->IntLessThan(); |
| 178 break; |
| 179 case Token::GT: // a > 0 becomes !(a <= 0) |
| 180 op = machine()->IntLessThanOrEqual(); |
| 181 std::swap(true_value, false_value); |
| 182 break; |
| 183 case Token::LTE: // a <= 0 |
| 184 op = machine()->IntLessThanOrEqual(); |
| 185 break; |
| 186 case Token::GTE: // a >= 0 becomes !(a < 0) |
| 187 op = machine()->IntLessThan(); |
| 188 std::swap(true_value, false_value); |
| 189 break; |
| 190 default: |
| 191 UNREACHABLE(); |
| 192 } |
| 193 Node* booleanize = graph()->NewNode(op, compare, jsgraph()->ZeroConstant()); |
159 | 194 |
160 if (has_frame_state) { | 195 // Finally patch the original node to select a boolean. |
161 // Remove the frame state from inputs. | 196 NodeProperties::ReplaceWithValue(node, node, compare); |
162 node->RemoveInput(NodeProperties::FirstFrameStateIndex(node)); | 197 // TODO(mstarzinger): Just a work-around because SelectLowering might |
163 } | 198 // otherwise introduce a Phi without any uses, making Scheduler unhappy. |
164 | 199 if (node->UseCount() == 0) return; |
165 ReplaceWithRuntimeCall(node, Runtime::kBooleanize); | 200 node->TrimInputCount(3); |
| 201 node->ReplaceInput(0, booleanize); |
| 202 node->ReplaceInput(1, true_value); |
| 203 node->ReplaceInput(2, false_value); |
| 204 PatchOperator(node, common()->Select(kMachAnyTagged)); |
166 } | 205 } |
167 | 206 |
168 | 207 |
169 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable, | 208 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable, |
170 CallDescriptor::Flags flags) { | 209 CallDescriptor::Flags flags) { |
171 Operator::Properties properties = node->op()->properties(); | 210 Operator::Properties properties = node->op()->properties(); |
172 CallDescriptor* desc = | 211 CallDescriptor* desc = |
173 Linkage::GetStubCallDescriptor(isolate(), zone(), callable.descriptor(), | 212 Linkage::GetStubCallDescriptor(isolate(), zone(), callable.descriptor(), |
174 0, flags | FlagsForNode(node), properties); | 213 0, flags | FlagsForNode(node), properties); |
175 Node* stub_code = jsgraph()->HeapConstant(callable.code()); | 214 Node* stub_code = jsgraph()->HeapConstant(callable.code()); |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 | 482 |
444 | 483 |
445 void JSGenericLowering::LowerJSCallRuntime(Node* node) { | 484 void JSGenericLowering::LowerJSCallRuntime(Node* node) { |
446 const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op()); | 485 const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op()); |
447 ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity())); | 486 ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity())); |
448 } | 487 } |
449 | 488 |
450 } // namespace compiler | 489 } // namespace compiler |
451 } // namespace internal | 490 } // namespace internal |
452 } // namespace v8 | 491 } // namespace v8 |
OLD | NEW |