LCOV - code coverage report
Current view: top level - test/cctest/compiler - test-run-tail-calls.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 80 80 100.0 %
Date: 2019-01-20 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // Copyright 2017 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/assembler-inl.h"
       6             : #include "src/base/utils/random-number-generator.h"
       7             : #include "src/code-stub-assembler.h"
       8             : #include "src/macro-assembler.h"
       9             : 
      10             : #include "test/cctest/cctest.h"
      11             : #include "test/cctest/compiler/code-assembler-tester.h"
      12             : #include "test/cctest/compiler/function-tester.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : namespace compiler {
      17             : namespace test_run_tail_calls {
      18             : 
      19             : #define __ assembler.
      20             : 
      21             : namespace {
      22             : 
      23             : // Function that takes a number of pointer-sized integer arguments, calculates a
      24             : // weighted sum of them and returns it.
      25         360 : Handle<Code> BuildCallee(Isolate* isolate, CallDescriptor* call_descriptor) {
      26         180 :   CodeAssemblerTester tester(isolate, call_descriptor, "callee");
      27         180 :   CodeStubAssembler assembler(tester.state());
      28         180 :   int param_count = static_cast<int>(call_descriptor->StackParameterCount());
      29         360 :   Node* sum = __ IntPtrConstant(0);
      30        1750 :   for (int i = 0; i < param_count; ++i) {
      31        5560 :     Node* product = __ IntPtrMul(__ Parameter(i), __ IntPtrConstant(i + 1));
      32        2780 :     sum = __ IntPtrAdd(sum, product);
      33             :   }
      34         180 :   __ Return(sum);
      35         360 :   return tester.GenerateCodeCloseAndEscape();
      36             : }
      37             : 
      38             : // Function that tail-calls another function with a number of pointer-sized
      39             : // integer arguments.
      40         180 : Handle<Code> BuildCaller(Isolate* isolate, CallDescriptor* call_descriptor,
      41         180 :                          CallDescriptor* callee_descriptor) {
      42         180 :   CodeAssemblerTester tester(isolate, call_descriptor, "caller");
      43         180 :   CodeStubAssembler assembler(tester.state());
      44             :   std::vector<Node*> params;
      45             :   // The first parameter is always the callee.
      46         540 :   params.push_back(__ HeapConstant(BuildCallee(isolate, callee_descriptor)));
      47         180 :   int param_count = static_cast<int>(callee_descriptor->StackParameterCount());
      48        1570 :   for (int i = 0; i < param_count; ++i) {
      49        4170 :     params.push_back(__ IntPtrConstant(i));
      50             :   }
      51             :   DCHECK_EQ(param_count + 1, params.size());
      52             :   tester.raw_assembler_for_testing()->TailCallN(callee_descriptor,
      53         360 :                                                 param_count + 1, params.data());
      54         360 :   return tester.GenerateCodeCloseAndEscape();
      55             : }
      56             : 
      57             : // Setup function, which calls "caller".
      58         180 : Handle<Code> BuildSetupFunction(Isolate* isolate,
      59         180 :                                 CallDescriptor* caller_descriptor,
      60             :                                 CallDescriptor* callee_descriptor) {
      61         180 :   CodeAssemblerTester tester(isolate, 0);
      62         180 :   CodeStubAssembler assembler(tester.state());
      63             :   std::vector<Node*> params;
      64             :   // The first parameter is always the callee.
      65             :   params.push_back(__ HeapConstant(
      66         540 :       BuildCaller(isolate, caller_descriptor, callee_descriptor)));
      67             :   // Set up arguments for "Caller".
      68         180 :   int param_count = static_cast<int>(caller_descriptor->StackParameterCount());
      69        1845 :   for (int i = 0; i < param_count; ++i) {
      70             :     // Use values that are different from the ones we will pass to this
      71             :     // function's callee later.
      72        4995 :     params.push_back(__ IntPtrConstant(i + 42));
      73             :   }
      74             :   DCHECK_EQ(param_count + 1, params.size());
      75             :   Node* raw_result = tester.raw_assembler_for_testing()->CallN(
      76         360 :       caller_descriptor, param_count + 1, params.data());
      77         360 :   __ Return(__ SmiTag(raw_result));
      78         360 :   return tester.GenerateCodeCloseAndEscape();
      79             : }
      80             : 
      81         360 : CallDescriptor* CreateDescriptorForStackArguments(Zone* zone,
      82             :                                                   int stack_param_count) {
      83             :   LocationSignature::Builder locations(zone, 1,
      84         360 :                                        static_cast<size_t>(stack_param_count));
      85             : 
      86             :   locations.AddReturn(LinkageLocation::ForRegister(kReturnRegister0.code(),
      87             :                                                    MachineType::IntPtr()));
      88             : 
      89        3415 :   for (int i = 0; i < stack_param_count; ++i) {
      90             :     locations.AddParam(LinkageLocation::ForCallerFrameSlot(
      91        3055 :         i - stack_param_count, MachineType::IntPtr()));
      92             :   }
      93             : 
      94             :   return new (zone)
      95             :       CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
      96             :                      MachineType::AnyTagged(),         // target MachineType
      97             :                      LinkageLocation::ForAnyRegister(
      98             :                          MachineType::AnyTagged()),  // target location
      99             :                      locations.Build(),              // location_sig
     100             :                      stack_param_count,              // stack_parameter_count
     101             :                      Operator::kNoProperties,        // properties
     102             :                      kNoCalleeSaved,                 // callee-saved registers
     103             :                      kNoCalleeSaved,                 // callee-saved fp
     104         720 :                      CallDescriptor::kNoFlags);      // flags
     105             : }
     106             : 
     107             : // Test a tail call from a caller with n parameters to a callee with m
     108             : // parameters. All parameters are pointer-sized.
     109         180 : void TestHelper(int n, int m) {
     110         180 :   HandleAndZoneScope scope;
     111         180 :   Isolate* isolate = scope.main_isolate();
     112         360 :   CanonicalHandleScope canonical(isolate);
     113             :   Zone* zone = scope.main_zone();
     114             :   CallDescriptor* caller_descriptor =
     115         180 :       CreateDescriptorForStackArguments(zone, n);
     116             :   CallDescriptor* callee_descriptor =
     117         180 :       CreateDescriptorForStackArguments(zone, m);
     118             :   Handle<Code> setup =
     119         180 :       BuildSetupFunction(isolate, caller_descriptor, callee_descriptor);
     120         180 :   FunctionTester ft(setup, 0);
     121         360 :   Handle<Object> result = ft.Call().ToHandleChecked();
     122             :   int expected = 0;
     123         180 :   for (int i = 0; i < m; ++i) expected += (i + 1) * i;
     124         540 :   CHECK_EQ(expected, Handle<Smi>::cast(result)->value());
     125         180 : }
     126             : 
     127             : }  // namespace
     128             : 
     129             : #undef __
     130             : 
     131       28342 : TEST(CallerOddCalleeEven) {
     132           5 :   TestHelper(1, 0);
     133           5 :   TestHelper(1, 2);
     134           5 :   TestHelper(3, 2);
     135           5 :   TestHelper(3, 4);
     136           5 : }
     137             : 
     138       28342 : TEST(CallerOddCalleeOdd) {
     139           5 :   TestHelper(1, 1);
     140           5 :   TestHelper(1, 3);
     141           5 :   TestHelper(3, 1);
     142           5 :   TestHelper(3, 3);
     143           5 : }
     144             : 
     145       28342 : TEST(CallerEvenCalleeEven) {
     146           5 :   TestHelper(0, 0);
     147           5 :   TestHelper(0, 2);
     148           5 :   TestHelper(2, 0);
     149           5 :   TestHelper(2, 2);
     150           5 : }
     151             : 
     152       28342 : TEST(CallerEvenCalleeOdd) {
     153           5 :   TestHelper(0, 1);
     154           5 :   TestHelper(0, 3);
     155           5 :   TestHelper(2, 1);
     156           5 :   TestHelper(2, 3);
     157           5 : }
     158             : 
     159       28342 : TEST(FuzzStackParamCount) {
     160             :   const int kNumTests = 20;
     161             :   const int kMaxSlots = 30;
     162           5 :   base::RandomNumberGenerator* const rng = CcTest::random_number_generator();
     163         105 :   for (int i = 0; i < kNumTests; ++i) {
     164         100 :     int n = rng->NextInt(kMaxSlots);
     165         100 :     int m = rng->NextInt(kMaxSlots);
     166         100 :     TestHelper(n, m);
     167             :   }
     168           5 : }
     169             : 
     170             : }  // namespace test_run_tail_calls
     171             : }  // namespace compiler
     172             : }  // namespace internal
     173       85011 : }  // namespace v8

Generated by: LCOV version 1.10