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/compiler/access-builder.h" | 6 #include "src/compiler/access-builder.h" |
7 #include "src/compiler/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
8 #include "src/compiler/js-typed-lowering.h" | 8 #include "src/compiler/js-typed-lowering.h" |
9 #include "src/compiler/linkage.h" | 9 #include "src/compiler/linkage.h" |
10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 | 114 |
115 // A helper class to simplify the process of reducing a single binop node with a | 115 // A helper class to simplify the process of reducing a single binop node with a |
116 // JSOperator. This class manages the rewriting of context, control, and effect | 116 // JSOperator. This class manages the rewriting of context, control, and effect |
117 // dependencies during lowering of a binop and contains numerous helper | 117 // dependencies during lowering of a binop and contains numerous helper |
118 // functions for matching the types of inputs to an operation. | 118 // functions for matching the types of inputs to an operation. |
119 class JSBinopReduction final { | 119 class JSBinopReduction final { |
120 public: | 120 public: |
121 JSBinopReduction(JSTypedLowering* lowering, Node* node) | 121 JSBinopReduction(JSTypedLowering* lowering, Node* node) |
122 : lowering_(lowering), node_(node) {} | 122 : lowering_(lowering), node_(node) {} |
123 | 123 |
124 void ConvertPrimitiveInputsToNumber() { | |
125 node_->ReplaceInput(0, ConvertPrimitiveToNumber(left())); | |
126 node_->ReplaceInput(1, ConvertPrimitiveToNumber(right())); | |
127 } | |
128 | |
129 void ConvertInputsToNumber(Node* frame_state) { | 124 void ConvertInputsToNumber(Node* frame_state) { |
130 // To convert the inputs to numbers, we have to provide frame states | 125 // To convert the inputs to numbers, we have to provide frame states |
131 // for lazy bailouts in the ToNumber conversions. | 126 // for lazy bailouts in the ToNumber conversions. |
132 // We use a little hack here: we take the frame state before the binary | 127 // We use a little hack here: we take the frame state before the binary |
133 // operation and use it to construct the frame states for the conversion | 128 // operation and use it to construct the frame states for the conversion |
134 // so that after the deoptimization, the binary operation IC gets | 129 // so that after the deoptimization, the binary operation IC gets |
135 // already converted values from full code. This way we are sure that we | 130 // already converted values from full code. This way we are sure that we |
136 // will not re-do any of the side effects. | 131 // will not re-do any of the side effects. |
137 | 132 |
138 Node* left_input = | 133 Node* left_input = |
139 left_type()->Is(Type::PlainPrimitive()) | 134 left_type()->Is(Type::PlainPrimitive()) |
140 ? ConvertPrimitiveToNumber(left()) | 135 ? ConvertPlainPrimitiveToNumber(left()) |
141 : ConvertToNumber(left(), | 136 : ConvertToNumber(left(), |
142 CreateFrameStateForLeftInput(frame_state)); | 137 CreateFrameStateForLeftInput(frame_state)); |
143 | 138 |
144 Node* right_input = | 139 Node* right_input = |
145 right_type()->Is(Type::PlainPrimitive()) | 140 right_type()->Is(Type::PlainPrimitive()) |
146 ? ConvertPrimitiveToNumber(right()) | 141 ? ConvertPlainPrimitiveToNumber(right()) |
147 : ConvertToNumber(right(), CreateFrameStateForRightInput( | 142 : ConvertToNumber(right(), CreateFrameStateForRightInput( |
148 frame_state, left_input)); | 143 frame_state, left_input)); |
149 | 144 |
150 node_->ReplaceInput(0, left_input); | 145 node_->ReplaceInput(0, left_input); |
151 node_->ReplaceInput(1, right_input); | 146 node_->ReplaceInput(1, right_input); |
152 } | 147 } |
153 | 148 |
154 void ConvertInputsToUI32(Signedness left_signedness, | 149 void ConvertInputsToUI32(Signedness left_signedness, |
155 Signedness right_signedness) { | 150 Signedness right_signedness) { |
156 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); | 151 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); |
157 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); | 152 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); |
158 } | 153 } |
159 | 154 |
160 void ConvertInputsToString() { | 155 void ConvertInputsToString() { |
161 node_->ReplaceInput(0, ConvertToString(left())); | 156 node_->ReplaceInput(0, ConvertToString(left())); |
162 node_->ReplaceInput(1, ConvertToString(right())); | 157 node_->ReplaceInput(1, ConvertToString(right())); |
163 } | 158 } |
164 | 159 |
165 // Convert inputs for bitwise shift operation (ES5 spec 11.7). | 160 // Convert inputs for bitwise shift operation (ES5 spec 11.7). |
166 void ConvertInputsForShift(Signedness left_signedness) { | 161 void ConvertInputsForShift(Signedness left_signedness) { |
167 node_->ReplaceInput( | 162 node_->ReplaceInput(0, ConvertToUI32(ConvertPlainPrimitiveToNumber(left()), |
168 0, ConvertToUI32(ConvertPrimitiveToNumber(left()), left_signedness)); | 163 left_signedness)); |
169 Node* rnum = ConvertToUI32(ConvertPrimitiveToNumber(right()), kUnsigned); | 164 Node* rnum = |
| 165 ConvertToUI32(ConvertPlainPrimitiveToNumber(right()), kUnsigned); |
170 Type* rnum_type = NodeProperties::GetBounds(rnum).upper; | 166 Type* rnum_type = NodeProperties::GetBounds(rnum).upper; |
171 if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) { | 167 if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) { |
172 rnum = graph()->NewNode(machine()->Word32And(), rnum, | 168 rnum = graph()->NewNode(machine()->Word32And(), rnum, |
173 jsgraph()->Int32Constant(0x1F)); | 169 jsgraph()->Int32Constant(0x1F)); |
174 } | 170 } |
175 node_->ReplaceInput(1, rnum); | 171 node_->ReplaceInput(1, rnum); |
176 } | 172 } |
177 | 173 |
178 void SwapInputs() { | 174 void SwapInputs() { |
179 Node* l = left(); | 175 Node* l = left(); |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 } | 322 } |
327 } | 323 } |
328 Node* new_stack = | 324 Node* new_stack = |
329 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front()); | 325 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front()); |
330 | 326 |
331 return graph()->NewNode(op, frame_state->InputAt(0), | 327 return graph()->NewNode(op, frame_state->InputAt(0), |
332 frame_state->InputAt(1), new_stack, | 328 frame_state->InputAt(1), new_stack, |
333 frame_state->InputAt(3), frame_state->InputAt(4)); | 329 frame_state->InputAt(3), frame_state->InputAt(4)); |
334 } | 330 } |
335 | 331 |
336 Node* ConvertPrimitiveToNumber(Node* node) { | 332 Node* ConvertPlainPrimitiveToNumber(Node* node) { |
337 return lowering_->ConvertPrimitiveToNumber(node); | 333 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())); |
| 334 // Avoid inserting too many eager ToNumber() operations. |
| 335 Reduction const reduction = lowering_->ReduceJSToNumberInput(node); |
| 336 if (reduction.Changed()) return reduction.replacement(); |
| 337 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. |
| 338 return graph()->NewNode( |
| 339 javascript()->ToNumber(), node, jsgraph()->NoContextConstant(), |
| 340 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start()); |
338 } | 341 } |
339 | 342 |
340 Node* ConvertToNumber(Node* node, Node* frame_state) { | 343 Node* ConvertToNumber(Node* node, Node* frame_state) { |
341 if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) { | 344 if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) { |
342 return ConvertPrimitiveToNumber(node); | 345 return ConvertPlainPrimitiveToNumber(node); |
343 } else { | 346 } else { |
344 Node* const n = | 347 Node* const n = |
345 graph()->NewNode(javascript()->ToNumber(), node, context(), | 348 graph()->NewNode(javascript()->ToNumber(), node, context(), |
346 frame_state, effect(), control()); | 349 frame_state, effect(), control()); |
347 update_effect(n); | 350 update_effect(n); |
348 return n; | 351 return n; |
349 } | 352 } |
350 } | 353 } |
351 | 354 |
352 Node* ConvertToUI32(Node* node, Signedness signedness) { | 355 Node* ConvertToUI32(Node* node, Signedness signedness) { |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 break; | 466 break; |
464 case IrOpcode::kJSGreaterThanOrEqual: | 467 case IrOpcode::kJSGreaterThanOrEqual: |
465 stringOp = simplified()->StringLessThanOrEqual(); | 468 stringOp = simplified()->StringLessThanOrEqual(); |
466 r.SwapInputs(); // a >= b => b <= a | 469 r.SwapInputs(); // a >= b => b <= a |
467 break; | 470 break; |
468 default: | 471 default: |
469 return NoChange(); | 472 return NoChange(); |
470 } | 473 } |
471 return r.ChangeToPureOperator(stringOp); | 474 return r.ChangeToPureOperator(stringOp); |
472 } | 475 } |
473 if (r.IsStrong() && !r.BothInputsAre(Type::Number())) { | 476 if (r.OneInputCannotBe(Type::StringOrReceiver())) { |
474 return NoChange(); | |
475 } | |
476 #if 0 | |
477 // TODO(turbofan): General ToNumber disabled for now because: | |
478 // a) The inserted ToNumber operation screws up observability of valueOf. | |
479 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. | |
480 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); | |
481 if (r.OneInputCannotBe(maybe_string)) { | |
482 // If one input cannot be a string, then emit a number comparison. | |
483 ... | |
484 } | |
485 #endif | |
486 if (r.BothInputsAre(Type::PlainPrimitive()) && | |
487 r.OneInputCannotBe(Type::StringOrReceiver())) { | |
488 const Operator* less_than; | 477 const Operator* less_than; |
489 const Operator* less_than_or_equal; | 478 const Operator* less_than_or_equal; |
490 if (r.BothInputsAre(Type::Unsigned32())) { | 479 if (r.BothInputsAre(Type::Unsigned32())) { |
491 less_than = machine()->Uint32LessThan(); | 480 less_than = machine()->Uint32LessThan(); |
492 less_than_or_equal = machine()->Uint32LessThanOrEqual(); | 481 less_than_or_equal = machine()->Uint32LessThanOrEqual(); |
493 } else if (r.BothInputsAre(Type::Signed32())) { | 482 } else if (r.BothInputsAre(Type::Signed32())) { |
494 less_than = machine()->Int32LessThan(); | 483 less_than = machine()->Int32LessThan(); |
495 less_than_or_equal = machine()->Int32LessThanOrEqual(); | 484 less_than_or_equal = machine()->Int32LessThanOrEqual(); |
496 } else { | 485 } else { |
497 // TODO(turbofan): mixed signed/unsigned int32 comparisons. | 486 // TODO(turbofan): mixed signed/unsigned int32 comparisons. |
498 r.ConvertPrimitiveInputsToNumber(); | 487 if (r.IsStrong() && !r.BothInputsAre(Type::Number())) { |
| 488 return NoChange(); |
| 489 } |
| 490 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 491 r.ConvertInputsToNumber(frame_state); |
499 less_than = simplified()->NumberLessThan(); | 492 less_than = simplified()->NumberLessThan(); |
500 less_than_or_equal = simplified()->NumberLessThanOrEqual(); | 493 less_than_or_equal = simplified()->NumberLessThanOrEqual(); |
501 } | 494 } |
502 const Operator* comparison; | 495 const Operator* comparison; |
503 switch (node->opcode()) { | 496 switch (node->opcode()) { |
504 case IrOpcode::kJSLessThan: | 497 case IrOpcode::kJSLessThan: |
505 comparison = less_than; | 498 comparison = less_than; |
506 break; | 499 break; |
507 case IrOpcode::kJSGreaterThan: | 500 case IrOpcode::kJSGreaterThan: |
508 comparison = less_than; | 501 comparison = less_than; |
(...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1185 return ReduceJSCreateWithContext(node); | 1178 return ReduceJSCreateWithContext(node); |
1186 case IrOpcode::kJSCreateBlockContext: | 1179 case IrOpcode::kJSCreateBlockContext: |
1187 return ReduceJSCreateBlockContext(node); | 1180 return ReduceJSCreateBlockContext(node); |
1188 default: | 1181 default: |
1189 break; | 1182 break; |
1190 } | 1183 } |
1191 return NoChange(); | 1184 return NoChange(); |
1192 } | 1185 } |
1193 | 1186 |
1194 | 1187 |
1195 Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) { | |
1196 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); | |
1197 // Avoid inserting too many eager ToNumber() operations. | |
1198 Reduction const reduction = ReduceJSToNumberInput(input); | |
1199 if (reduction.Changed()) return reduction.replacement(); | |
1200 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. | |
1201 return graph()->NewNode( | |
1202 javascript()->ToNumber(), input, jsgraph()->NoContextConstant(), | |
1203 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start()); | |
1204 } | |
1205 | |
1206 | |
1207 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { | 1188 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { |
1208 if (rhs == 0) return lhs; | 1189 if (rhs == 0) return lhs; |
1209 return graph()->NewNode(machine()->Word32Shl(), lhs, | 1190 return graph()->NewNode(machine()->Word32Shl(), lhs, |
1210 jsgraph()->Int32Constant(rhs)); | 1191 jsgraph()->Int32Constant(rhs)); |
1211 } | 1192 } |
1212 | 1193 |
1213 | 1194 |
1214 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } | 1195 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } |
1215 | 1196 |
1216 | 1197 |
(...skipping 10 matching lines...) Expand all Loading... |
1227 } | 1208 } |
1228 | 1209 |
1229 | 1210 |
1230 MachineOperatorBuilder* JSTypedLowering::machine() const { | 1211 MachineOperatorBuilder* JSTypedLowering::machine() const { |
1231 return jsgraph()->machine(); | 1212 return jsgraph()->machine(); |
1232 } | 1213 } |
1233 | 1214 |
1234 } // namespace compiler | 1215 } // namespace compiler |
1235 } // namespace internal | 1216 } // namespace internal |
1236 } // namespace v8 | 1217 } // namespace v8 |
OLD | NEW |