3c9f69d399
Add factory methods for different types of LinkageLocations, and ensure that accesses to the underlying data in the location are classified by type and funneled through explicit accessors. Also change the representation of LinkageLocation to use a BitField rather than using a reserved section of the integer range. Review URL: https://codereview.chromium.org/1262343002 Cr-Commit-Position: refs/heads/master@{#29938}
325 lines
13 KiB
C++
325 lines
13 KiB
C++
// Copyright 2014 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/common-operator.h"
|
|
#include "src/compiler/graph.h"
|
|
#include "src/compiler/linkage.h"
|
|
#include "src/compiler/node.h"
|
|
#include "test/unittests/test-utils.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
namespace {
|
|
|
|
MachineType kMachineTypes[] = {kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
|
|
kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
|
|
kMachAnyTagged, kMachAnyTagged};
|
|
}
|
|
|
|
class LinkageTailCall : public TestWithZone {
|
|
protected:
|
|
CallDescriptor* NewStandardCallDescriptor(LocationSignature* locations) {
|
|
DCHECK(arraysize(kMachineTypes) >=
|
|
locations->return_count() + locations->parameter_count());
|
|
MachineSignature* types = new (zone()) MachineSignature(
|
|
locations->return_count(), locations->parameter_count(), kMachineTypes);
|
|
return new (zone())
|
|
CallDescriptor(CallDescriptor::kCallCodeObject, kMachAnyTagged,
|
|
LinkageLocation::ForAnyRegister(),
|
|
types, // machine_sig
|
|
locations, // location_sig
|
|
0, // js_parameter_count
|
|
Operator::kNoProperties, // properties
|
|
0, // callee-saved
|
|
0, // callee-saved fp
|
|
CallDescriptor::kNoFlags, // flags,
|
|
"");
|
|
}
|
|
|
|
LinkageLocation StackLocation(int loc) {
|
|
return LinkageLocation::ForCallerFrameSlot(-loc);
|
|
}
|
|
|
|
LinkageLocation RegisterLocation(int loc) {
|
|
return LinkageLocation::ForRegister(loc);
|
|
}
|
|
};
|
|
|
|
|
|
TEST_F(LinkageTailCall, EmptyToEmpty) {
|
|
LocationSignature locations(0, 0, nullptr);
|
|
CallDescriptor* desc = NewStandardCallDescriptor(&locations);
|
|
CommonOperatorBuilder common(zone());
|
|
const Operator* op = common.Call(desc);
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
|
EXPECT_TRUE(desc->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, SameReturn) {
|
|
// Caller
|
|
LinkageLocation location_array[] = {RegisterLocation(0)};
|
|
LocationSignature locations1(1, 0, location_array);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Callee
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, DifferingReturn) {
|
|
// Caller
|
|
LinkageLocation location_array1[] = {RegisterLocation(0)};
|
|
LocationSignature locations1(1, 0, location_array1);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Callee
|
|
LinkageLocation location_array2[] = {RegisterLocation(1)};
|
|
LocationSignature locations2(1, 0, location_array2);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
|
EXPECT_FALSE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MoreRegisterParametersCallee) {
|
|
// Caller
|
|
LinkageLocation location_array1[] = {RegisterLocation(0)};
|
|
LocationSignature locations1(1, 0, location_array1);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Callee
|
|
LinkageLocation location_array2[] = {RegisterLocation(0),
|
|
RegisterLocation(0)};
|
|
LocationSignature locations2(1, 1, location_array2);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MoreRegisterParametersCaller) {
|
|
// Caller
|
|
LinkageLocation location_array1[] = {RegisterLocation(0),
|
|
RegisterLocation(0)};
|
|
LocationSignature locations1(1, 1, location_array1);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Callee
|
|
LinkageLocation location_array2[] = {RegisterLocation(0)};
|
|
LocationSignature locations2(1, 0, location_array2);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MoreRegisterAndStackParametersCallee) {
|
|
// Caller
|
|
LinkageLocation location_array1[] = {RegisterLocation(0)};
|
|
LocationSignature locations1(1, 0, location_array1);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Callee
|
|
LinkageLocation location_array2[] = {RegisterLocation(0), RegisterLocation(0),
|
|
RegisterLocation(1), StackLocation(1)};
|
|
LocationSignature locations2(1, 3, location_array2);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
|
EXPECT_FALSE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MoreRegisterAndStackParametersCaller) {
|
|
// Caller
|
|
LinkageLocation location_array[] = {RegisterLocation(0), RegisterLocation(0),
|
|
RegisterLocation(1), StackLocation(1)};
|
|
LocationSignature locations1(1, 3, location_array);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Callee
|
|
LinkageLocation location_array2[] = {RegisterLocation(0)};
|
|
LocationSignature locations2(1, 0, location_array2);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
|
EXPECT_FALSE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParameters) {
|
|
// Caller
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
StackLocation(2), StackLocation(1)};
|
|
LocationSignature locations1(1, 3, location_array);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Caller
|
|
LocationSignature locations2(1, 3, location_array);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
Node* parameters[] = {p0, p1, p2, p3};
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node =
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, NonMatchingStackParameters) {
|
|
// Caller
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
StackLocation(2), StackLocation(1)};
|
|
LocationSignature locations1(1, 3, location_array);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Caller
|
|
LocationSignature locations2(1, 3, location_array);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
Node* parameters[] = {p0, p1, p2, p3};
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node =
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
|
EXPECT_FALSE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParametersExtraCallerRegisters) {
|
|
// Caller
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
StackLocation(2), StackLocation(1),
|
|
RegisterLocation(0), RegisterLocation(1)};
|
|
LocationSignature locations1(1, 5, location_array);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Caller
|
|
LocationSignature locations2(1, 3, location_array);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
Node* parameters[] = {p0, p1, p2, p3};
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node =
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParametersExtraCalleeRegisters) {
|
|
// Caller
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
StackLocation(2), StackLocation(1),
|
|
RegisterLocation(0), RegisterLocation(1)};
|
|
LocationSignature locations1(1, 3, location_array);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Caller
|
|
LocationSignature locations2(1, 5, location_array);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
|
|
Node* parameters[] = {p0, p1, p2, p3, p4};
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node =
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParametersExtraCallerRegistersAndStack) {
|
|
// Caller
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
StackLocation(2), StackLocation(1),
|
|
RegisterLocation(0), StackLocation(4)};
|
|
LocationSignature locations1(1, 5, location_array);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Caller
|
|
LocationSignature locations2(1, 3, location_array);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
|
|
Node* parameters[] = {p0, p1, p2, p3, p4};
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node =
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
|
EXPECT_FALSE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParametersExtraCalleeRegistersAndStack) {
|
|
// Caller
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
StackLocation(2), RegisterLocation(0),
|
|
RegisterLocation(1), StackLocation(4)};
|
|
LocationSignature locations1(1, 3, location_array);
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
// Caller
|
|
LocationSignature locations2(1, 5, location_array);
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
|
|
Node* parameters[] = {p0, p1, p2, p3, p4};
|
|
const Operator* op = common.Call(desc2);
|
|
Node* const node =
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
|
EXPECT_FALSE(desc1->CanTailCall(node));
|
|
}
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|