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/linkage.h"
6 #include "src/compiler/tail-call-optimization.h"
7 #include "test/unittests/compiler/graph-unittest.h"
8 #include "test/unittests/compiler/node-test-utils.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace compiler {
13 
14 class TailCallOptimizationTest : public GraphTest {
15  public:
TailCallOptimizationTest(int num_parameters=1)16   explicit TailCallOptimizationTest(int num_parameters = 1)
17       : GraphTest(num_parameters) {}
~TailCallOptimizationTest()18   ~TailCallOptimizationTest() override {}
19 
20  protected:
Reduce(Node * node)21   Reduction Reduce(Node* node) {
22     TailCallOptimization tco(common(), graph());
23     return tco.Reduce(node);
24   }
25 };
26 
27 
TEST_F(TailCallOptimizationTest,CallCodeObject0)28 TEST_F(TailCallOptimizationTest, CallCodeObject0) {
29   MachineType kMachineSignature[] = {MachineType::AnyTagged(),
30                                      MachineType::AnyTagged()};
31   LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
32                                           LinkageLocation::ForRegister(1)};
33   const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
34       CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
35       LinkageLocation::ForRegister(0),
36       new (zone()) MachineSignature(1, 1, kMachineSignature),
37       new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
38       Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags);
39   Node* p0 = Parameter(0);
40   Node* p1 = Parameter(1);
41   Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
42                                 graph()->start(), graph()->start());
43   Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
44   Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
45   Reduction r = Reduce(ret);
46   ASSERT_FALSE(r.Changed());
47 }
48 
49 
TEST_F(TailCallOptimizationTest,CallCodeObject1)50 TEST_F(TailCallOptimizationTest, CallCodeObject1) {
51   MachineType kMachineSignature[] = {MachineType::AnyTagged(),
52                                      MachineType::AnyTagged()};
53   LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
54                                           LinkageLocation::ForRegister(1)};
55   const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
56       CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
57       LinkageLocation::ForRegister(0),
58       new (zone()) MachineSignature(1, 1, kMachineSignature),
59       new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
60       Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
61   Node* p0 = Parameter(0);
62   Node* p1 = Parameter(1);
63   Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
64                                 graph()->start(), graph()->start());
65   Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
66   Node* if_exception = graph()->NewNode(
67       common()->IfException(IfExceptionHint::kLocallyUncaught), call, call);
68   Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
69   Node* end = graph()->NewNode(common()->End(1), if_exception);
70   graph()->SetEnd(end);
71   Reduction r = Reduce(ret);
72   ASSERT_FALSE(r.Changed());
73 }
74 
75 
TEST_F(TailCallOptimizationTest,CallCodeObject2)76 TEST_F(TailCallOptimizationTest, CallCodeObject2) {
77   MachineType kMachineSignature[] = {MachineType::AnyTagged(),
78                                      MachineType::AnyTagged()};
79   LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
80                                           LinkageLocation::ForRegister(1)};
81   const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
82       CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
83       LinkageLocation::ForRegister(0),
84       new (zone()) MachineSignature(1, 1, kMachineSignature),
85       new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
86       Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
87   Node* p0 = Parameter(0);
88   Node* p1 = Parameter(1);
89   Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
90                                 graph()->start(), graph()->start());
91   Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
92   Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
93   Reduction r = Reduce(ret);
94   ASSERT_TRUE(r.Changed());
95   EXPECT_THAT(r.replacement(), IsTailCall(kCallDescriptor, p0, p1,
96                                           graph()->start(), graph()->start()));
97 }
98 
99 
TEST_F(TailCallOptimizationTest,CallJSFunction0)100 TEST_F(TailCallOptimizationTest, CallJSFunction0) {
101   MachineType kMachineSignature[] = {MachineType::AnyTagged(),
102                                      MachineType::AnyTagged()};
103   LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
104                                           LinkageLocation::ForRegister(1)};
105   const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
106       CallDescriptor::kCallJSFunction, MachineType::AnyTagged(),
107       LinkageLocation::ForRegister(0),
108       new (zone()) MachineSignature(1, 1, kMachineSignature),
109       new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
110       Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags);
111   Node* p0 = Parameter(0);
112   Node* p1 = Parameter(1);
113   Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
114                                 graph()->start(), graph()->start());
115   Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
116   Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
117   Reduction r = Reduce(ret);
118   ASSERT_FALSE(r.Changed());
119 }
120 
121 
TEST_F(TailCallOptimizationTest,CallJSFunction1)122 TEST_F(TailCallOptimizationTest, CallJSFunction1) {
123   MachineType kMachineSignature[] = {MachineType::AnyTagged(),
124                                      MachineType::AnyTagged()};
125   LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
126                                           LinkageLocation::ForRegister(1)};
127   const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
128       CallDescriptor::kCallJSFunction, MachineType::AnyTagged(),
129       LinkageLocation::ForRegister(0),
130       new (zone()) MachineSignature(1, 1, kMachineSignature),
131       new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
132       Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
133   Node* p0 = Parameter(0);
134   Node* p1 = Parameter(1);
135   Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
136                                 graph()->start(), graph()->start());
137   Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
138   Node* if_exception = graph()->NewNode(
139       common()->IfException(IfExceptionHint::kLocallyUncaught), call, call);
140   Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
141   Node* end = graph()->NewNode(common()->End(1), if_exception);
142   graph()->SetEnd(end);
143   Reduction r = Reduce(ret);
144   ASSERT_FALSE(r.Changed());
145 }
146 
147 
TEST_F(TailCallOptimizationTest,CallJSFunction2)148 TEST_F(TailCallOptimizationTest, CallJSFunction2) {
149   MachineType kMachineSignature[] = {MachineType::AnyTagged(),
150                                      MachineType::AnyTagged()};
151   LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
152                                           LinkageLocation::ForRegister(1)};
153   const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
154       CallDescriptor::kCallJSFunction, MachineType::AnyTagged(),
155       LinkageLocation::ForRegister(0),
156       new (zone()) MachineSignature(1, 1, kMachineSignature),
157       new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
158       Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
159   Node* p0 = Parameter(0);
160   Node* p1 = Parameter(1);
161   Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
162                                 graph()->start(), graph()->start());
163   Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
164   Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
165   Reduction r = Reduce(ret);
166   ASSERT_TRUE(r.Changed());
167   EXPECT_THAT(r.replacement(), IsTailCall(kCallDescriptor, p0, p1,
168                                           graph()->start(), graph()->start()));
169 }
170 
171 
172 }  // namespace compiler
173 }  // namespace internal
174 }  // namespace v8
175