// Copyright 2017 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/base/utils/random-number-generator.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/code-stub-assembler.h"
#include "src/codegen/macro-assembler.h"

#include "test/cctest/cctest.h"
#include "test/cctest/compiler/code-assembler-tester.h"
#include "test/cctest/compiler/function-tester.h"

namespace v8 {
namespace internal {
namespace compiler {
namespace test_run_tail_calls {

#define __ assembler.

namespace {

// Function that takes a number of pointer-sized integer arguments, calculates a
// weighted sum of them and returns it.
Handle<Code> BuildCallee(Isolate* isolate, CallDescriptor* call_descriptor) {
  CodeAssemblerTester tester(isolate, call_descriptor, "callee");
  CodeStubAssembler assembler(tester.state());
  int param_count = static_cast<int>(call_descriptor->StackParameterCount());
  Node* sum = __ IntPtrConstant(0);
  for (int i = 0; i < param_count; ++i) {
    Node* product = __ IntPtrMul(__ Parameter(i), __ IntPtrConstant(i + 1));
    sum = __ IntPtrAdd(sum, product);
  }
  __ Return(sum);
  return tester.GenerateCodeCloseAndEscape();
}

// Function that tail-calls another function with a number of pointer-sized
// integer arguments.
Handle<Code> BuildCaller(Isolate* isolate, CallDescriptor* call_descriptor,
                         CallDescriptor* callee_descriptor) {
  CodeAssemblerTester tester(isolate, call_descriptor, "caller");
  CodeStubAssembler assembler(tester.state());
  std::vector<Node*> params;
  // The first parameter is always the callee.
  params.push_back(__ HeapConstant(BuildCallee(isolate, callee_descriptor)));
  int param_count = static_cast<int>(callee_descriptor->StackParameterCount());
  for (int i = 0; i < param_count; ++i) {
    params.push_back(__ IntPtrConstant(i));
  }
  DCHECK_EQ(param_count + 1, params.size());
  tester.raw_assembler_for_testing()->TailCallN(callee_descriptor,
                                                param_count + 1, params.data());
  return tester.GenerateCodeCloseAndEscape();
}

// Setup function, which calls "caller".
Handle<Code> BuildSetupFunction(Isolate* isolate,
                                CallDescriptor* caller_descriptor,
                                CallDescriptor* callee_descriptor) {
  CodeAssemblerTester tester(isolate, 0);
  CodeStubAssembler assembler(tester.state());
  std::vector<Node*> params;
  // The first parameter is always the callee.
  params.push_back(__ HeapConstant(
      BuildCaller(isolate, caller_descriptor, callee_descriptor)));
  // Set up arguments for "Caller".
  int param_count = static_cast<int>(caller_descriptor->StackParameterCount());
  for (int i = 0; i < param_count; ++i) {
    // Use values that are different from the ones we will pass to this
    // function's callee later.
    params.push_back(__ IntPtrConstant(i + 42));
  }
  DCHECK_EQ(param_count + 1, params.size());
  Node* raw_result = tester.raw_assembler_for_testing()->CallN(
      caller_descriptor, param_count + 1, params.data());
  __ Return(__ SmiTag(raw_result));
  return tester.GenerateCodeCloseAndEscape();
}

CallDescriptor* CreateDescriptorForStackArguments(Zone* zone,
                                                  int stack_param_count) {
  LocationSignature::Builder locations(zone, 1,
                                       static_cast<size_t>(stack_param_count));

  locations.AddReturn(LinkageLocation::ForRegister(kReturnRegister0.code(),
                                                   MachineType::IntPtr()));

  for (int i = 0; i < stack_param_count; ++i) {
    locations.AddParam(LinkageLocation::ForCallerFrameSlot(
        i - stack_param_count, MachineType::IntPtr()));
  }

  return new (zone)
      CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
                     MachineType::AnyTagged(),         // target MachineType
                     LinkageLocation::ForAnyRegister(
                         MachineType::AnyTagged()),  // target location
                     locations.Build(),              // location_sig
                     stack_param_count,              // stack_parameter_count
                     Operator::kNoProperties,        // properties
                     kNoCalleeSaved,                 // callee-saved registers
                     kNoCalleeSaved,                 // callee-saved fp
                     CallDescriptor::kNoFlags);      // flags
}

// Test a tail call from a caller with n parameters to a callee with m
// parameters. All parameters are pointer-sized.
void TestHelper(int n, int m) {
  HandleAndZoneScope scope;
  Isolate* isolate = scope.main_isolate();
  CanonicalHandleScope canonical(isolate);
  Zone* zone = scope.main_zone();
  CallDescriptor* caller_descriptor =
      CreateDescriptorForStackArguments(zone, n);
  CallDescriptor* callee_descriptor =
      CreateDescriptorForStackArguments(zone, m);
  Handle<Code> setup =
      BuildSetupFunction(isolate, caller_descriptor, callee_descriptor);
  FunctionTester ft(setup, 0);
  Handle<Object> result = ft.Call().ToHandleChecked();
  int expected = 0;
  for (int i = 0; i < m; ++i) expected += (i + 1) * i;
  CHECK_EQ(expected, Handle<Smi>::cast(result)->value());
}

}  // namespace

#undef __

TEST(CallerOddCalleeEven) {
  TestHelper(1, 0);
  TestHelper(1, 2);
  TestHelper(3, 2);
  TestHelper(3, 4);
}

TEST(CallerOddCalleeOdd) {
  TestHelper(1, 1);
  TestHelper(1, 3);
  TestHelper(3, 1);
  TestHelper(3, 3);
}

TEST(CallerEvenCalleeEven) {
  TestHelper(0, 0);
  TestHelper(0, 2);
  TestHelper(2, 0);
  TestHelper(2, 2);
}

TEST(CallerEvenCalleeOdd) {
  TestHelper(0, 1);
  TestHelper(0, 3);
  TestHelper(2, 1);
  TestHelper(2, 3);
}

TEST(FuzzStackParamCount) {
  const int kNumTests = 20;
  const int kMaxSlots = 30;
  base::RandomNumberGenerator* const rng = CcTest::random_number_generator();
  for (int i = 0; i < kNumTests; ++i) {
    int n = rng->NextInt(kMaxSlots);
    int m = rng->NextInt(kMaxSlots);
    TestHelper(n, m);
  }
}

}  // namespace test_run_tail_calls
}  // namespace compiler
}  // namespace internal
}  // namespace v8
