1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/tail-call-optimization.h"
6
7#include "src/compiler/common-operator.h"
8#include "src/compiler/graph.h"
9#include "src/compiler/linkage.h"
10#include "src/compiler/node-matchers.h"
11#include "src/compiler/node-properties.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17Reduction TailCallOptimization::Reduce(Node* node) {
18  if (node->opcode() != IrOpcode::kReturn) return NoChange();
19  // The value which is returned must be the result of a potential tail call,
20  // there must be no try/catch/finally around the Call, and there must be no
21  // other effect between the Call and the Return nodes.
22  Node* const call = NodeProperties::GetValueInput(node, 1);
23  if (call->opcode() == IrOpcode::kCall &&
24      CallDescriptorOf(call->op())->SupportsTailCalls() &&
25      NodeProperties::GetEffectInput(node) == call &&
26      !NodeProperties::IsExceptionalCall(call)) {
27    Node* const control = NodeProperties::GetControlInput(node);
28    // Ensure that no additional arguments are being popped other than those in
29    // the CallDescriptor, otherwise the tail call transformation is invalid.
30    DCHECK_EQ(0, Int32Matcher(NodeProperties::GetValueInput(node, 0)).Value());
31    if (control->opcode() == IrOpcode::kIfSuccess &&
32        call->OwnedBy(node, control) && control->OwnedBy(node)) {
33      // Furthermore, control has to flow via an IfSuccess from the Call, so
34      // the Return node value and effect depends directly on the Call node,
35      // and indirectly control depends on the Call via an IfSuccess.
36
37      // Value1 ... ValueN Effect Control
38      //   ^          ^      ^       ^
39      //   |          |      |       |
40      //   |          +--+ +-+       |
41      //   +----------+  | |  +------+
42      //               \ | | /
43      //             Call[Descriptor]
44      //                ^ ^ ^
45      //                | | |
46      //              +-+ | |
47      //              |   | |
48      //              | +-+ |
49      //              | | IfSuccess
50      //              | |  ^
51      //              | |  |
52      //              Return
53      //                ^
54      //                |
55
56      // The resulting graph looks like this:
57
58      // Value1 ... ValueN Effect Control
59      //   ^          ^      ^       ^
60      //   |          |      |       |
61      //   |          +--+ +-+       |
62      //   +----------+  | |  +------+
63      //               \ | | /
64      //           TailCall[Descriptor]
65      //                 ^
66      //                 |
67
68      DCHECK_EQ(call, NodeProperties::GetControlInput(control, 0));
69      DCHECK_EQ(4, node->InputCount());
70      node->ReplaceInput(0, NodeProperties::GetEffectInput(call));
71      node->ReplaceInput(1, NodeProperties::GetControlInput(call));
72      node->RemoveInput(3);
73      node->RemoveInput(2);
74      for (int index = 0; index < call->op()->ValueInputCount(); ++index) {
75        node->InsertInput(graph()->zone(), index,
76                          NodeProperties::GetValueInput(call, index));
77      }
78      NodeProperties::ChangeOp(
79          node, common()->TailCall(CallDescriptorOf(call->op())));
80      return Changed(node);
81    }
82  }
83  return NoChange();
84}
85
86}  // namespace compiler
87}  // namespace internal
88}  // namespace v8
89