Chromium Code Reviews| Index: src/compiler/instruction-selector.cc |
| diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc |
| index 1e2ab974854fd563640ae20861be9871eb9dfceb..4f91bfa7877c45b5eb720006bfb63345ce4cc356 100644 |
| --- a/src/compiler/instruction-selector.cc |
| +++ b/src/compiler/instruction-selector.cc |
| @@ -516,7 +516,7 @@ void InstructionSelector::VisitControl(BasicBlock* block) { |
| DCHECK_EQ(IrOpcode::kCall, input->opcode()); |
| BasicBlock* success = block->SuccessorAt(0); |
| BasicBlock* exception = block->SuccessorAt(1); |
| - return VisitCall(input, exception), VisitGoto(success); |
| + return VisitCall(input, exception, NORMAL_CALL), VisitGoto(success); |
| } |
| case BasicBlock::kBranch: { |
| DCHECK_EQ(IrOpcode::kBranch, input->opcode()); |
| @@ -559,7 +559,7 @@ void InstructionSelector::VisitControl(BasicBlock* block) { |
| } |
| case BasicBlock::kReturn: { |
| DCHECK_EQ(IrOpcode::kReturn, input->opcode()); |
| - return VisitReturn(input->InputAt(0)); |
| + return VisitReturn(input); |
| } |
| case BasicBlock::kDeoptimize: { |
| // If the result itself is a return, return its input. |
| @@ -636,7 +636,7 @@ void InstructionSelector::VisitNode(Node* node) { |
| return VisitConstant(node); |
| } |
| case IrOpcode::kCall: |
| - return VisitCall(node, nullptr); |
| + return VisitCall(node, nullptr, NORMAL_CALL); |
| case IrOpcode::kFrameState: |
| case IrOpcode::kStateValues: |
| return; |
| @@ -1041,7 +1041,40 @@ void InstructionSelector::VisitGoto(BasicBlock* target) { |
| } |
| -void InstructionSelector::VisitReturn(Node* value) { |
| +// Returns the call node if the given return node is part of a tail call, |
| +// nullptr otherwise. |
| +static Node* DetectTailCall(Node* ret) { |
|
Benedikt Meurer
2015/04/29 04:06:05
Nit: Use anonymous namespace instead of static, an
Sven Panne
2015/04/29 10:24:18
Done.
|
| + // The value which is returned must be the result of a potential tail call, |
| + // there must be no try/catch/finally around the call, and there must be no |
| + // effects between the call and the return. |
| + Node* call = NodeProperties::GetValueInput(ret, 0); |
| + if (call->opcode() != IrOpcode::kCall || |
| + !OpParameter<const CallDescriptor*>(call)->IsTailCallAllowed() || |
| + NodeProperties::IsExceptionalCall(call) || |
| + NodeProperties::GetEffectInput(ret, 0) != call) { |
| + return nullptr; |
| + } |
| + // Furthermore, control has to flow via an IfSuccess from the call (for calls |
| + // which can throw), or the return and the call have to use the same control |
| + // input (for calls which can't throw). |
| + Node* control = NodeProperties::GetControlInput(ret, 0); |
| + return ((control->opcode() == IrOpcode::kIfSuccess) |
| + ? (NodeProperties::GetControlInput(control, 0) == call) |
|
Benedikt Meurer
2015/04/29 04:06:05
Urghs, can we please not nest tenary operators?
Sven Panne
2015/04/29 10:24:18
Booh! Functional programming FTW! ;-) Nevertheless
|
| + : (control == NodeProperties::GetControlInput(call, 0))) |
| + ? call |
| + : nullptr; |
| +} |
| + |
| + |
| +void InstructionSelector::VisitReturn(Node* node) { |
| + if (FLAG_turbo_tail_calls) { |
| + Node* call = DetectTailCall(node); |
| + if (call != nullptr && |
| + OpParameter<const CallDescriptor*>(call)->UsesOnlyRegisters()) { |
| + return VisitCall(call, nullptr, TAIL_CALL); |
| + } |
| + } |
| + Node* value = NodeProperties::GetValueInput(node, 0); |
| DCHECK_NOT_NULL(value); |
| OperandGenerator g(this); |
| Emit(kArchRet, g.NoOutput(), |