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