| 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 |