Chromium Code Reviews| 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 | |
| 174 Reduction ChangeToStringComparisonOperator(const Operator* op, | |
|
Benedikt Meurer
2016/05/30 18:39:50
This seems to reintroduce dead code. ChangeToStrin
Jarin
2016/05/31 20:28:52
Done.
| |
| 175 bool invert = false) { | |
| 176 if (node_->op()->ControlInputCount() > 0) { | |
| 177 lowering_->RelaxControls(node_); | |
| 178 } | |
| 179 // String comparison operators need effect and control inputs, so copy them | |
| 180 // over. | |
| 181 Node* effect = NodeProperties::GetEffectInput(node_); | |
| 182 Node* control = NodeProperties::GetControlInput(node_); | |
| 183 node_->ReplaceInput(2, effect); | |
| 184 node_->ReplaceInput(3, control); | |
| 185 | |
| 186 node_->TrimInputCount(4); | |
| 187 NodeProperties::ChangeOp(node_, op); | |
| 188 | |
| 189 if (invert) { | |
| 190 // Insert a boolean-not to invert the value. | |
| 191 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); | |
| 192 node_->ReplaceUses(value); | |
| 193 // Note: ReplaceUses() smashes all uses, so smash it back here. | |
| 194 value->ReplaceInput(0, node_); | |
| 195 return lowering_->Replace(value); | |
| 196 } | |
| 197 return lowering_->Changed(node_); | |
| 198 } | |
| 199 | |
| 110 Reduction ChangeToPureOperator(const Operator* op, Type* type) { | 200 Reduction ChangeToPureOperator(const Operator* op, Type* type) { |
| 111 return ChangeToPureOperator(op, false, type); | 201 return ChangeToPureOperator(op, false, type); |
| 112 } | 202 } |
| 113 | 203 |
| 114 bool LeftInputIs(Type* t) { return left_type()->Is(t); } | 204 bool LeftInputIs(Type* t) { return left_type()->Is(t); } |
| 115 | 205 |
| 116 bool RightInputIs(Type* t) { return right_type()->Is(t); } | 206 bool RightInputIs(Type* t) { return right_type()->Is(t); } |
| 117 | 207 |
| 118 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } | 208 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); } |
| 119 | 209 |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 double max = kMaxInt / (1 << k); | 423 double max = kMaxInt / (1 << k); |
| 334 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); | 424 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); |
| 335 } | 425 } |
| 336 } | 426 } |
| 337 | 427 |
| 338 | 428 |
| 339 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { | 429 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { |
| 340 if (flags() & kDisableBinaryOpReduction) return NoChange(); | 430 if (flags() & kDisableBinaryOpReduction) return NoChange(); |
| 341 | 431 |
| 342 JSBinopReduction r(this, node); | 432 JSBinopReduction r(this, node); |
| 433 | |
| 434 BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); | |
| 435 if (feedback != BinaryOperationHints::kAny) { | |
| 436 // Lower to the optimistic number binop. | |
| 437 return r.ChangeToSpeculativeOperator( | |
| 438 simplified()->SpeculativeNumberAdd(feedback)); | |
| 439 } | |
| 343 if (r.BothInputsAre(Type::NumberOrUndefined())) { | 440 if (r.BothInputsAre(Type::NumberOrUndefined())) { |
| 344 // JSAdd(x:number, y:number) => NumberAdd(x, y) | 441 // JSAdd(x:number, y:number) => NumberAdd(x, y) |
| 345 return ReduceNumberBinop(node, simplified()->NumberAdd()); | 442 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 443 r.ConvertInputsToNumberOrUndefined(frame_state); | |
| 444 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); | |
| 346 } | 445 } |
| 347 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { | 446 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { |
| 348 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) | 447 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) |
| 349 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 448 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 350 r.ConvertInputsToNumberOrUndefined(frame_state); | 449 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 351 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); | 450 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); |
| 352 } | 451 } |
| 353 if (r.OneInputIs(Type::String())) { | 452 if (r.OneInputIs(Type::String())) { |
| 354 StringAddFlags flags = STRING_ADD_CHECK_NONE; | 453 StringAddFlags flags = STRING_ADD_CHECK_NONE; |
| 355 if (!r.LeftInputIs(Type::String())) { | 454 if (!r.LeftInputIs(Type::String())) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 380 | 479 |
| 381 JSBinopReduction r(this, node); | 480 JSBinopReduction r(this, node); |
| 382 if (r.BothInputsAre(Type::Number())) { | 481 if (r.BothInputsAre(Type::Number())) { |
| 383 // JSModulus(x:number, x:number) => NumberModulus(x, y) | 482 // JSModulus(x:number, x:number) => NumberModulus(x, y) |
| 384 return r.ChangeToPureOperator(simplified()->NumberModulus(), | 483 return r.ChangeToPureOperator(simplified()->NumberModulus(), |
| 385 Type::Number()); | 484 Type::Number()); |
| 386 } | 485 } |
| 387 return NoChange(); | 486 return NoChange(); |
| 388 } | 487 } |
| 389 | 488 |
| 390 | 489 Reduction JSTypedLowering::ReduceJSSubtract(Node* node) { |
| 391 Reduction JSTypedLowering::ReduceNumberBinop(Node* node, | |
| 392 const Operator* numberOp) { | |
| 393 if (flags() & kDisableBinaryOpReduction) return NoChange(); | 490 if (flags() & kDisableBinaryOpReduction) return NoChange(); |
| 394 | |
| 395 JSBinopReduction r(this, node); | 491 JSBinopReduction r(this, node); |
| 396 if (numberOp == simplified()->NumberModulus()) { | 492 BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); |
| 397 if (r.BothInputsAre(Type::NumberOrUndefined())) { | 493 if (feedback != BinaryOperationHints::kAny) { |
| 398 return r.ChangeToPureOperator(numberOp, Type::Number()); | 494 // Lower to the optimistic number binop. |
| 399 } | 495 return r.ChangeToSpeculativeOperator( |
| 400 return NoChange(); | 496 simplified()->SpeculativeNumberSubtract(feedback)); |
| 401 } | 497 } |
| 402 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 498 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 403 r.ConvertInputsToNumberOrUndefined(frame_state); | 499 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 404 return r.ChangeToPureOperator(numberOp, Type::Number()); | 500 return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number()); |
| 501 } | |
| 502 | |
| 503 Reduction JSTypedLowering::ReduceJSMultiply(Node* node) { | |
| 504 if (flags() & kDisableBinaryOpReduction) return NoChange(); | |
| 505 JSBinopReduction r(this, node); | |
| 506 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | |
| 507 r.ConvertInputsToNumberOrUndefined(frame_state); | |
| 508 return r.ChangeToPureOperator(simplified()->NumberMultiply(), Type::Number()); | |
| 509 } | |
| 510 | |
| 511 Reduction JSTypedLowering::ReduceJSDivide(Node* node) { | |
| 512 if (flags() & kDisableBinaryOpReduction) return NoChange(); | |
| 513 JSBinopReduction r(this, node); | |
| 514 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | |
| 515 r.ConvertInputsToNumberOrUndefined(frame_state); | |
| 516 return r.ChangeToPureOperator(simplified()->NumberDivide(), Type::Number()); | |
| 405 } | 517 } |
| 406 | 518 |
| 407 | 519 |
| 408 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { | 520 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { |
| 409 if (flags() & kDisableBinaryOpReduction) return NoChange(); | 521 if (flags() & kDisableBinaryOpReduction) return NoChange(); |
| 410 | 522 |
| 411 JSBinopReduction r(this, node); | 523 JSBinopReduction r(this, node); |
| 412 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 524 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
| 413 r.ConvertInputsToNumberOrUndefined(frame_state); | 525 r.ConvertInputsToNumberOrUndefined(frame_state); |
| 414 r.ConvertInputsToUI32(kSigned, kSigned); | 526 r.ConvertInputsToUI32(kSigned, kSigned); |
| (...skipping 1374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1789 case IrOpcode::kJSShiftLeft: | 1901 case IrOpcode::kJSShiftLeft: |
| 1790 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft()); | 1902 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft()); |
| 1791 case IrOpcode::kJSShiftRight: | 1903 case IrOpcode::kJSShiftRight: |
| 1792 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight()); | 1904 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight()); |
| 1793 case IrOpcode::kJSShiftRightLogical: | 1905 case IrOpcode::kJSShiftRightLogical: |
| 1794 return ReduceUI32Shift(node, kUnsigned, | 1906 return ReduceUI32Shift(node, kUnsigned, |
| 1795 simplified()->NumberShiftRightLogical()); | 1907 simplified()->NumberShiftRightLogical()); |
| 1796 case IrOpcode::kJSAdd: | 1908 case IrOpcode::kJSAdd: |
| 1797 return ReduceJSAdd(node); | 1909 return ReduceJSAdd(node); |
| 1798 case IrOpcode::kJSSubtract: | 1910 case IrOpcode::kJSSubtract: |
| 1799 return ReduceNumberBinop(node, simplified()->NumberSubtract()); | 1911 return ReduceJSSubtract(node); |
| 1800 case IrOpcode::kJSMultiply: | 1912 case IrOpcode::kJSMultiply: |
| 1801 return ReduceNumberBinop(node, simplified()->NumberMultiply()); | 1913 return ReduceJSMultiply(node); |
| 1802 case IrOpcode::kJSDivide: | 1914 case IrOpcode::kJSDivide: |
| 1803 return ReduceNumberBinop(node, simplified()->NumberDivide()); | 1915 return ReduceJSDivide(node); |
| 1804 case IrOpcode::kJSModulus: | 1916 case IrOpcode::kJSModulus: |
| 1805 return ReduceJSModulus(node); | 1917 return ReduceJSModulus(node); |
| 1806 case IrOpcode::kJSToBoolean: | 1918 case IrOpcode::kJSToBoolean: |
| 1807 return ReduceJSToBoolean(node); | 1919 return ReduceJSToBoolean(node); |
| 1808 case IrOpcode::kJSToInteger: | 1920 case IrOpcode::kJSToInteger: |
| 1809 return ReduceJSToInteger(node); | 1921 return ReduceJSToInteger(node); |
| 1810 case IrOpcode::kJSToLength: | 1922 case IrOpcode::kJSToLength: |
| 1811 return ReduceJSToLength(node); | 1923 return ReduceJSToLength(node); |
| 1812 case IrOpcode::kJSToNumber: | 1924 case IrOpcode::kJSToNumber: |
| 1813 return ReduceJSToNumber(node); | 1925 return ReduceJSToNumber(node); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1898 } | 2010 } |
| 1899 | 2011 |
| 1900 | 2012 |
| 1901 CompilationDependencies* JSTypedLowering::dependencies() const { | 2013 CompilationDependencies* JSTypedLowering::dependencies() const { |
| 1902 return dependencies_; | 2014 return dependencies_; |
| 1903 } | 2015 } |
| 1904 | 2016 |
| 1905 } // namespace compiler | 2017 } // namespace compiler |
| 1906 } // namespace internal | 2018 } // namespace internal |
| 1907 } // namespace v8 | 2019 } // namespace v8 |
| OLD | NEW |