| 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/compilation-dependencies.h" | 6 #include "src/compilation-dependencies.h" |
| 7 #include "src/compiler/access-builder.h" | 7 #include "src/compiler/access-builder.h" |
| 8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
| 9 #include "src/compiler/js-typed-lowering.h" | 9 #include "src/compiler/js-typed-lowering.h" |
| 10 #include "src/compiler/linkage.h" | 10 #include "src/compiler/linkage.h" |
| 11 #include "src/compiler/node-matchers.h" | 11 #include "src/compiler/node-matchers.h" |
| 12 #include "src/compiler/node-properties.h" | 12 #include "src/compiler/node-properties.h" |
| 13 #include "src/compiler/operator-properties.h" | 13 #include "src/compiler/operator-properties.h" |
| 14 #include "src/type-cache.h" | 14 #include "src/type-cache.h" |
| 15 #include "src/types.h" | 15 #include "src/types.h" |
| 16 | 16 |
| 17 namespace v8 { | 17 namespace v8 { |
| 18 namespace internal { | 18 namespace internal { |
| 19 namespace compiler { | 19 namespace compiler { |
| 20 | 20 |
| 21 // A helper class to simplify the process of reducing a single binop node with a | 21 // A helper class to simplify the process of reducing a single binop node with a |
| 22 // JSOperator. This class manages the rewriting of context, control, and effect | 22 // JSOperator. This class manages the rewriting of context, control, and effect |
| 23 // dependencies during lowering of a binop and contains numerous helper | 23 // dependencies during lowering of a binop and contains numerous helper |
| 24 // functions for matching the types of inputs to an operation. | 24 // functions for matching the types of inputs to an operation. |
| 25 class JSBinopReduction final { | 25 class JSBinopReduction final { |
| 26 public: | 26 public: |
| 27 JSBinopReduction(JSTypedLowering* lowering, Node* node) | 27 JSBinopReduction(JSTypedLowering* lowering, Node* node) |
| 28 : lowering_(lowering), node_(node) {} | 28 : lowering_(lowering), node_(node) {} |
| 29 | 29 |
| 30 BinaryOperationHints::Hint GetUsableNumberFeedback() { |
| 31 if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) || |
| 32 !(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) { |
| 33 return BinaryOperationHints::kAny; |
| 34 } |
| 35 DCHECK_NE(0, node_->op()->ControlOutputCount()); |
| 36 DCHECK_EQ(1, node_->op()->EffectOutputCount()); |
| 37 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op())); |
| 38 BinaryOperationHints hints = BinaryOperationHintsOf(node_->op()); |
| 39 BinaryOperationHints::Hint combined = hints.combined(); |
| 40 if (combined == BinaryOperationHints::kSignedSmall || |
| 41 combined == BinaryOperationHints::kSigned32 || |
| 42 combined == BinaryOperationHints::kNumberOrUndefined) { |
| 43 return combined; |
| 44 } |
| 45 return BinaryOperationHints::kAny; |
| 46 } |
| 47 |
| 30 void ConvertInputsToNumberOrUndefined(Node* frame_state) { | 48 void ConvertInputsToNumberOrUndefined(Node* frame_state) { |
| 31 // To convert the inputs to numbers, we have to provide frame states | 49 // To convert the inputs to numbers, we have to provide frame states |
| 32 // for lazy bailouts in the ToNumber conversions. | 50 // for lazy bailouts in the ToNumber conversions. |
| 33 // We use a little hack here: we take the frame state before the binary | 51 // We use a little hack here: we take the frame state before the binary |
| 34 // operation and use it to construct the frame states for the conversion | 52 // operation and use it to construct the frame states for the conversion |
| 35 // so that after the deoptimization, the binary operation IC gets | 53 // so that after the deoptimization, the binary operation IC gets |
| 36 // already converted values from full code. This way we are sure that we | 54 // already converted values from full code. This way we are sure that we |
| 37 // will not re-do any of the side effects. | 55 // will not re-do any of the side effects. |
| 38 | 56 |
| 39 Node* left_input = nullptr; | 57 Node* left_input = nullptr; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 // Insert an boolean not to invert the value. | 118 // Insert an boolean not to invert the value. |
| 101 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); | 119 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); |
| 102 node_->ReplaceUses(value); | 120 node_->ReplaceUses(value); |
| 103 // Note: ReplaceUses() smashes all uses, so smash it back here. | 121 // Note: ReplaceUses() smashes all uses, so smash it back here. |
| 104 value->ReplaceInput(0, node_); | 122 value->ReplaceInput(0, node_); |
| 105 return lowering_->Replace(value); | 123 return lowering_->Replace(value); |
| 106 } | 124 } |
| 107 return lowering_->Changed(node_); | 125 return lowering_->Changed(node_); |
| 108 } | 126 } |
| 109 | 127 |
| 128 Reduction ChangeToSpeculativeOperator(const Operator* op) { |
| 129 DCHECK_EQ(1, op->EffectInputCount()); |
| 130 DCHECK_EQ(1, op->EffectOutputCount()); |
| 131 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); |
| 132 DCHECK_EQ(1, op->ControlInputCount()); |
| 133 DCHECK_EQ(1, op->ControlOutputCount()); |
| 134 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(op)); |
| 135 DCHECK_EQ(2, op->ValueInputCount()); |
| 136 |
| 137 DCHECK_EQ(1, node_->op()->EffectInputCount()); |
| 138 DCHECK_EQ(1, node_->op()->EffectOutputCount()); |
| 139 DCHECK_EQ(1, node_->op()->ControlInputCount()); |
| 140 DCHECK_LT(1, node_->op()->ControlOutputCount()); |
| 141 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op())); |
| 142 DCHECK_EQ(2, node_->op()->ValueInputCount()); |
| 143 |
| 144 // Reconnect the control output to bypass the IfSuccess node and |
| 145 // possibly disconnect from the IfException node. |
| 146 for (Edge edge : node_->use_edges()) { |
| 147 Node* const user = edge.from(); |
| 148 DCHECK(!user->IsDead()); |
| 149 if (NodeProperties::IsControlEdge(edge)) { |
| 150 if (user->opcode() == IrOpcode::kIfSuccess) { |
| 151 user->ReplaceUses(node_); |
| 152 user->Kill(); |
| 153 } else { |
| 154 DCHECK_EQ(user->opcode(), IrOpcode::kIfException); |
| 155 edge.UpdateTo(jsgraph()->Dead()); |
| 156 } |
| 157 } |
| 158 } |
| 159 |
| 160 // Remove the lazy bailout frame state and the context. |
| 161 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_)); |
| 162 node_->RemoveInput(NodeProperties::FirstContextIndex(node_)); |
| 163 |
| 164 NodeProperties::ChangeOp(node_, op); |
| 165 |
| 166 // Update the type to number. |
| 167 Type* node_type = NodeProperties::GetType(node_); |
| 168 NodeProperties::SetType(node_, |
| 169 Type::Intersect(node_type, Type::Number(), zone())); |
| 170 |
| 171 return lowering_->Changed(node_); |
| 172 } |
| 173 |
| 110 Reduction ChangeToPureOperator(const Operator* op, Type* type) { | 174 Reduction ChangeToPureOperator(const Operator* op, Type* type) { |
| 111 return ChangeToPureOperator(op, false, type); | 175 return ChangeToPureOperator(op, false, type); |
| 112 } | 176 } |
| 113 | 177 |
| 114 bool LeftInputIs(Type* t) { return left_type()->Is(t); } | 178 bool LeftInputIs(Type* t) { return left_type()->Is(t); } |
| 115 | 179 |
| 116 bool RightInputIs(Type* t) { return right_type()->Is(t); } | 180 bool RightInputIs(Type* t) { return right_type()->Is(t); } |
| 117 | 181 |
| 118 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } | 182 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } |
| 119 | 183 |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 double max = kMaxInt / (1 << k); | 397 double max = kMaxInt / (1 << k); |
| 334 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); | 398 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); |
| 335 } | 399 } |
| 336 } | 400 } |
| 337 | 401 |
| 338 | 402 |
| 339 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { | 403 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { |
| 340 if (flags() & kDisableBinaryOpReduction) return NoChange(); | 404 if (flags() & kDisableBinaryOpReduction) return NoChange(); |
| 341 | 405 |
| 342 JSBinopReduction r(this, node); | 406 JSBinopReduction r(this, node); |
| 407 |
| 408 BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); |
| 409 if (feedback != BinaryOperationHints::kAny) { |
| 410 // Lower to the optimistic number binop. |
| 411 return r.ChangeToSpeculativeOperator( |
| 412 simplified()->SpeculativeNumberAdd(feedback)); |
| 413 } |
| 343 if (r.BothInputsAre(Type::NumberOrUndefined())) { | 414 if (r.BothInputsAre(Type::NumberOrUndefined())) { |
| 344 // JSAdd(x:number, y:number) => NumberAdd(x, y) | 415 // JSAdd(x:number, y:number) => NumberAdd(x, y) |
| 345 return ReduceNumberBinop(node, simplified()->NumberAdd()); | 416 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 417 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 418 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); |
| 346 } | 419 } |
| 347 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { | 420 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { |
| 348 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) | 421 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) |
| 349 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 422 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 350 r.ConvertInputsToNumberOrUndefined(frame_state); | 423 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 351 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); | 424 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); |
| 352 } | 425 } |
| 353 if (r.OneInputIs(Type::String())) { | 426 if (r.OneInputIs(Type::String())) { |
| 354 StringAddFlags flags = STRING_ADD_CHECK_NONE; | 427 StringAddFlags flags = STRING_ADD_CHECK_NONE; |
| 355 if (!r.LeftInputIs(Type::String())) { | 428 if (!r.LeftInputIs(Type::String())) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 380 | 453 |
| 381 JSBinopReduction r(this, node); | 454 JSBinopReduction r(this, node); |
| 382 if (r.BothInputsAre(Type::Number())) { | 455 if (r.BothInputsAre(Type::Number())) { |
| 383 // JSModulus(x:number, x:number) => NumberModulus(x, y) | 456 // JSModulus(x:number, x:number) => NumberModulus(x, y) |
| 384 return r.ChangeToPureOperator(simplified()->NumberModulus(), | 457 return r.ChangeToPureOperator(simplified()->NumberModulus(), |
| 385 Type::Number()); | 458 Type::Number()); |
| 386 } | 459 } |
| 387 return NoChange(); | 460 return NoChange(); |
| 388 } | 461 } |
| 389 | 462 |
| 390 | 463 Reduction JSTypedLowering::ReduceJSSubtract(Node* node) { |
| 391 Reduction JSTypedLowering::ReduceNumberBinop(Node* node, | |
| 392 const Operator* numberOp) { | |
| 393 if (flags() & kDisableBinaryOpReduction) return NoChange(); | 464 if (flags() & kDisableBinaryOpReduction) return NoChange(); |
| 394 | |
| 395 JSBinopReduction r(this, node); | 465 JSBinopReduction r(this, node); |
| 396 if (numberOp == simplified()->NumberModulus()) { | 466 BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); |
| 397 if (r.BothInputsAre(Type::NumberOrUndefined())) { | 467 if (feedback != BinaryOperationHints::kAny) { |
| 398 return r.ChangeToPureOperator(numberOp, Type::Number()); | 468 // Lower to the optimistic number binop. |
| 399 } | 469 return r.ChangeToSpeculativeOperator( |
| 400 return NoChange(); | 470 simplified()->SpeculativeNumberSubtract(feedback)); |
| 401 } | 471 } |
| 402 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 472 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 403 r.ConvertInputsToNumberOrUndefined(frame_state); | 473 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 404 return r.ChangeToPureOperator(numberOp, Type::Number()); | 474 return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number()); |
| 475 } |
| 476 |
| 477 Reduction JSTypedLowering::ReduceJSMultiply(Node* node) { |
| 478 if (flags() & kDisableBinaryOpReduction) return NoChange(); |
| 479 JSBinopReduction r(this, node); |
| 480 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 481 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 482 return r.ChangeToPureOperator(simplified()->NumberMultiply(), Type::Number()); |
| 483 } |
| 484 |
| 485 Reduction JSTypedLowering::ReduceJSDivide(Node* node) { |
| 486 if (flags() & kDisableBinaryOpReduction) return NoChange(); |
| 487 JSBinopReduction r(this, node); |
| 488 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 489 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 490 return r.ChangeToPureOperator(simplified()->NumberDivide(), Type::Number()); |
| 405 } | 491 } |
| 406 | 492 |
| 407 | 493 |
| 408 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { | 494 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { |
| 409 if (flags() & kDisableBinaryOpReduction) return NoChange(); | 495 if (flags() & kDisableBinaryOpReduction) return NoChange(); |
| 410 | 496 |
| 411 JSBinopReduction r(this, node); | 497 JSBinopReduction r(this, node); |
| 412 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 498 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 413 r.ConvertInputsToNumberOrUndefined(frame_state); | 499 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 414 r.ConvertInputsToUI32(kSigned, kSigned); | 500 r.ConvertInputsToUI32(kSigned, kSigned); |
| (...skipping 1363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1778 case IrOpcode::kJSShiftLeft: | 1864 case IrOpcode::kJSShiftLeft: |
| 1779 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft()); | 1865 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft()); |
| 1780 case IrOpcode::kJSShiftRight: | 1866 case IrOpcode::kJSShiftRight: |
| 1781 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight()); | 1867 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight()); |
| 1782 case IrOpcode::kJSShiftRightLogical: | 1868 case IrOpcode::kJSShiftRightLogical: |
| 1783 return ReduceUI32Shift(node, kUnsigned, | 1869 return ReduceUI32Shift(node, kUnsigned, |
| 1784 simplified()->NumberShiftRightLogical()); | 1870 simplified()->NumberShiftRightLogical()); |
| 1785 case IrOpcode::kJSAdd: | 1871 case IrOpcode::kJSAdd: |
| 1786 return ReduceJSAdd(node); | 1872 return ReduceJSAdd(node); |
| 1787 case IrOpcode::kJSSubtract: | 1873 case IrOpcode::kJSSubtract: |
| 1788 return ReduceNumberBinop(node, simplified()->NumberSubtract()); | 1874 return ReduceJSSubtract(node); |
| 1789 case IrOpcode::kJSMultiply: | 1875 case IrOpcode::kJSMultiply: |
| 1790 return ReduceNumberBinop(node, simplified()->NumberMultiply()); | 1876 return ReduceJSMultiply(node); |
| 1791 case IrOpcode::kJSDivide: | 1877 case IrOpcode::kJSDivide: |
| 1792 return ReduceNumberBinop(node, simplified()->NumberDivide()); | 1878 return ReduceJSDivide(node); |
| 1793 case IrOpcode::kJSModulus: | 1879 case IrOpcode::kJSModulus: |
| 1794 return ReduceJSModulus(node); | 1880 return ReduceJSModulus(node); |
| 1795 case IrOpcode::kJSToBoolean: | 1881 case IrOpcode::kJSToBoolean: |
| 1796 return ReduceJSToBoolean(node); | 1882 return ReduceJSToBoolean(node); |
| 1797 case IrOpcode::kJSToInteger: | 1883 case IrOpcode::kJSToInteger: |
| 1798 return ReduceJSToInteger(node); | 1884 return ReduceJSToInteger(node); |
| 1799 case IrOpcode::kJSToLength: | 1885 case IrOpcode::kJSToLength: |
| 1800 return ReduceJSToLength(node); | 1886 return ReduceJSToLength(node); |
| 1801 case IrOpcode::kJSToNumber: | 1887 case IrOpcode::kJSToNumber: |
| 1802 return ReduceJSToNumber(node); | 1888 return ReduceJSToNumber(node); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1887 } | 1973 } |
| 1888 | 1974 |
| 1889 | 1975 |
| 1890 CompilationDependencies* JSTypedLowering::dependencies() const { | 1976 CompilationDependencies* JSTypedLowering::dependencies() const { |
| 1891 return dependencies_; | 1977 return dependencies_; |
| 1892 } | 1978 } |
| 1893 | 1979 |
| 1894 } // namespace compiler | 1980 } // namespace compiler |
| 1895 } // namespace internal | 1981 } // namespace internal |
| 1896 } // namespace v8 | 1982 } // namespace v8 |
| OLD | NEW |