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 |