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 |