| // Copyright 2015 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/compiler/linkage.h" |
| #include "src/compiler/tail-call-optimization.h" |
| #include "test/unittests/compiler/graph-unittest.h" |
| #include "test/unittests/compiler/node-test-utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| class TailCallOptimizationTest : public GraphTest { |
| public: |
| explicit TailCallOptimizationTest(int num_parameters = 1) |
| : GraphTest(num_parameters) {} |
| ~TailCallOptimizationTest() override {} |
| |
| protected: |
| Reduction Reduce(Node* node) { |
| TailCallOptimization tco(common(), graph()); |
| return tco.Reduce(node); |
| } |
| }; |
| |
| |
| TEST_F(TailCallOptimizationTest, CallCodeObject0) { |
| MachineType kMachineSignature[] = {MachineType::AnyTagged(), |
| MachineType::AnyTagged()}; |
| LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0), |
| LinkageLocation::ForRegister(1)}; |
| const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor( |
| CallDescriptor::kCallCodeObject, MachineType::AnyTagged(), |
| LinkageLocation::ForRegister(0), |
| new (zone()) MachineSignature(1, 1, kMachineSignature), |
| new (zone()) LocationSignature(1, 1, kLocationSignature), 0, |
| Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags); |
| Node* p0 = Parameter(0); |
| Node* p1 = Parameter(1); |
| Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, |
| graph()->start(), graph()->start()); |
| Node* if_success = graph()->NewNode(common()->IfSuccess(), call); |
| Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); |
| Reduction r = Reduce(ret); |
| ASSERT_FALSE(r.Changed()); |
| } |
| |
| |
| TEST_F(TailCallOptimizationTest, CallCodeObject1) { |
| MachineType kMachineSignature[] = {MachineType::AnyTagged(), |
| MachineType::AnyTagged()}; |
| LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0), |
| LinkageLocation::ForRegister(1)}; |
| const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor( |
| CallDescriptor::kCallCodeObject, MachineType::AnyTagged(), |
| LinkageLocation::ForRegister(0), |
| new (zone()) MachineSignature(1, 1, kMachineSignature), |
| new (zone()) LocationSignature(1, 1, kLocationSignature), 0, |
| Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls); |
| Node* p0 = Parameter(0); |
| Node* p1 = Parameter(1); |
| Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, |
| graph()->start(), graph()->start()); |
| Node* if_success = graph()->NewNode(common()->IfSuccess(), call); |
| Node* if_exception = graph()->NewNode( |
| common()->IfException(IfExceptionHint::kLocallyUncaught), call, call); |
| Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); |
| Node* end = graph()->NewNode(common()->End(1), if_exception); |
| graph()->SetEnd(end); |
| Reduction r = Reduce(ret); |
| ASSERT_FALSE(r.Changed()); |
| } |
| |
| |
| TEST_F(TailCallOptimizationTest, CallCodeObject2) { |
| MachineType kMachineSignature[] = {MachineType::AnyTagged(), |
| MachineType::AnyTagged()}; |
| LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0), |
| LinkageLocation::ForRegister(1)}; |
| const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor( |
| CallDescriptor::kCallCodeObject, MachineType::AnyTagged(), |
| LinkageLocation::ForRegister(0), |
| new (zone()) MachineSignature(1, 1, kMachineSignature), |
| new (zone()) LocationSignature(1, 1, kLocationSignature), 0, |
| Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls); |
| Node* p0 = Parameter(0); |
| Node* p1 = Parameter(1); |
| Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, |
| graph()->start(), graph()->start()); |
| Node* if_success = graph()->NewNode(common()->IfSuccess(), call); |
| Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); |
| Reduction r = Reduce(ret); |
| ASSERT_TRUE(r.Changed()); |
| EXPECT_THAT(r.replacement(), IsTailCall(kCallDescriptor, p0, p1, |
| graph()->start(), graph()->start())); |
| } |
| |
| |
| TEST_F(TailCallOptimizationTest, CallJSFunction0) { |
| MachineType kMachineSignature[] = {MachineType::AnyTagged(), |
| MachineType::AnyTagged()}; |
| LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0), |
| LinkageLocation::ForRegister(1)}; |
| const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor( |
| CallDescriptor::kCallJSFunction, MachineType::AnyTagged(), |
| LinkageLocation::ForRegister(0), |
| new (zone()) MachineSignature(1, 1, kMachineSignature), |
| new (zone()) LocationSignature(1, 1, kLocationSignature), 0, |
| Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags); |
| Node* p0 = Parameter(0); |
| Node* p1 = Parameter(1); |
| Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, |
| graph()->start(), graph()->start()); |
| Node* if_success = graph()->NewNode(common()->IfSuccess(), call); |
| Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); |
| Reduction r = Reduce(ret); |
| ASSERT_FALSE(r.Changed()); |
| } |
| |
| |
| TEST_F(TailCallOptimizationTest, CallJSFunction1) { |
| MachineType kMachineSignature[] = {MachineType::AnyTagged(), |
| MachineType::AnyTagged()}; |
| LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0), |
| LinkageLocation::ForRegister(1)}; |
| const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor( |
| CallDescriptor::kCallJSFunction, MachineType::AnyTagged(), |
| LinkageLocation::ForRegister(0), |
| new (zone()) MachineSignature(1, 1, kMachineSignature), |
| new (zone()) LocationSignature(1, 1, kLocationSignature), 0, |
| Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls); |
| Node* p0 = Parameter(0); |
| Node* p1 = Parameter(1); |
| Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, |
| graph()->start(), graph()->start()); |
| Node* if_success = graph()->NewNode(common()->IfSuccess(), call); |
| Node* if_exception = graph()->NewNode( |
| common()->IfException(IfExceptionHint::kLocallyUncaught), call, call); |
| Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); |
| Node* end = graph()->NewNode(common()->End(1), if_exception); |
| graph()->SetEnd(end); |
| Reduction r = Reduce(ret); |
| ASSERT_FALSE(r.Changed()); |
| } |
| |
| |
| TEST_F(TailCallOptimizationTest, CallJSFunction2) { |
| MachineType kMachineSignature[] = {MachineType::AnyTagged(), |
| MachineType::AnyTagged()}; |
| LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0), |
| LinkageLocation::ForRegister(1)}; |
| const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor( |
| CallDescriptor::kCallJSFunction, MachineType::AnyTagged(), |
| LinkageLocation::ForRegister(0), |
| new (zone()) MachineSignature(1, 1, kMachineSignature), |
| new (zone()) LocationSignature(1, 1, kLocationSignature), 0, |
| Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls); |
| Node* p0 = Parameter(0); |
| Node* p1 = Parameter(1); |
| Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, |
| graph()->start(), graph()->start()); |
| Node* if_success = graph()->NewNode(common()->IfSuccess(), call); |
| Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); |
| Reduction r = Reduce(ret); |
| ASSERT_TRUE(r.Changed()); |
| EXPECT_THAT(r.replacement(), IsTailCall(kCallDescriptor, p0, p1, |
| graph()->start(), graph()->start())); |
| } |
| |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |