v8/test/cctest/compiler/test-run-tail-calls.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

170 lines
5.9 KiB
C++
Raw Normal View History

Reland "[arm64] Preparation for padding of arguments" This is a reland of bcf1172992a2d817978ff19a2d814c7629443956 The test was timing out in no snapshot builds, as each CodeAssemblerTester creates a new Context. Reduced the random iterations significantly. Original change's description: > [arm64] Preparation for padding of arguments > > As part of JSSP removal, we need to align the arguments passed to functions > on the stack, by adding a padding slot when the total number of arguments > is odd. > > This patch introduces the kPadArguments flag (which is currently set to > false for all architectures), which will control padding of arguments in > architecture-independent parts of the code (deoptimizer, instruction > selector). > > It also adds some executable tests for tail calls with various stack > parameter counts on the caller and callee sides. > > This will be turned on for arm64 together with arm64-specific changes to > the code generator, the MacroAsembler and the builtins, in a later patch. > > Bug: v8:6644 > Change-Id: I79a5c149123fe8130cedd1ccffec3d9b50361e08 > Reviewed-on: https://chromium-review.googlesource.com/806554 > Commit-Queue: Georgia Kouveli <georgia.kouveli@arm.com> > Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> > Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> > Cr-Commit-Position: refs/heads/master@{#50134} TBR=jarin@chromium.org Bug: v8:6644 Change-Id: I795877ed9791e126ffac6841dbbb65189e95d207 Reviewed-on: https://chromium-review.googlesource.com/833046 Commit-Queue: Georgia Kouveli <georgia.kouveli@arm.com> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#50238}
2017-12-18 18:55:23 +00:00
// 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/assembler-inl.h"
#include "src/base/utils/random-number-generator.h"
#include "src/code-stub-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 {
#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* descriptor) {
CodeAssemblerTester tester(isolate, descriptor, "callee");
CodeStubAssembler assembler(tester.state());
int param_count = static_cast<int>(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* descriptor,
CallDescriptor* callee_descriptor) {
CodeAssemblerTester tester(isolate, 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();
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 compiler
} // namespace internal
} // namespace v8