linkage-tail-call-unittest.cc 14.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 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 {

17 18 19 20 21
MachineType kMachineTypes[] = {
    MachineType::AnyTagged(), MachineType::AnyTagged(),
    MachineType::AnyTagged(), MachineType::AnyTagged(),
    MachineType::AnyTagged(), MachineType::AnyTagged(),
    MachineType::AnyTagged(), MachineType::AnyTagged()};
22 23 24 25 26 27 28
}

class LinkageTailCall : public TestWithZone {
 protected:
  CallDescriptor* NewStandardCallDescriptor(LocationSignature* locations) {
    DCHECK(arraysize(kMachineTypes) >=
           locations->return_count() + locations->parameter_count());
29
    USE(kMachineTypes);
30 31 32 33 34 35 36 37 38 39
    return new (zone()) CallDescriptor(
        CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
        LinkageLocation::ForAnyRegister(MachineType::Pointer()),
        locations,                 // location_sig
        0,                         // js_parameter_count
        Operator::kNoProperties,   // properties
        0,                         // callee-saved
        0,                         // callee-saved fp
        CallDescriptor::kNoFlags,  // flags,
        "");
40 41
  }

42
  LinkageLocation StackLocation(int loc) {
43
    return LinkageLocation::ForCallerFrameSlot(-loc, MachineType::Pointer());
44
  }
45

46
  LinkageLocation RegisterLocation(int loc) {
47
    return LinkageLocation::ForRegister(loc, MachineType::Pointer());
48
  }
49 50 51 52 53 54 55 56 57
};


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);
58 59 60
  EXPECT_TRUE(desc->CanTailCall(node));
  const CallDescriptor* callee = CallDescriptorOf(node->op());
  int stack_param_delta = callee->GetStackParameterDelta(desc);
61
  EXPECT_EQ(0, stack_param_delta);
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
}


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);
77 78
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
79
  EXPECT_EQ(0, stack_param_delta);
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
}


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);
97
  EXPECT_TRUE(!desc1->CanTailCall(node));
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
}


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);
116 117
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
118
  EXPECT_EQ(0, stack_param_delta);
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
}


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);
137 138
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
139
  EXPECT_EQ(0, stack_param_delta);
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
}


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);
158 159
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
160 161 162
  // We might need to add one slot of padding to the callee arguments.
  int expected = kPadArguments ? 2 : 1;
  EXPECT_EQ(expected, stack_param_delta);
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
}


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);
181 182
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
183 184 185
  // We might need to drop one slot of padding from the caller's arguments.
  int expected = kPadArguments ? -2 : -1;
  EXPECT_EQ(expected, stack_param_delta);
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
}


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);
209 210
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
211
  EXPECT_EQ(0, stack_param_delta);
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
}


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);
235 236
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
237
  EXPECT_EQ(0, stack_param_delta);
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
}


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);
262 263
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
264
  EXPECT_EQ(0, stack_param_delta);
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
}


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);
290 291
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
292
  EXPECT_EQ(0, stack_param_delta);
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
}


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);
318 319
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
320 321 322
  // We might need to add one slot of padding to the callee arguments.
  int expected = kPadArguments ? 0 : -1;
  EXPECT_EQ(expected, stack_param_delta);
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
}


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);
348 349
  EXPECT_TRUE(desc1->CanTailCall(node));
  int stack_param_delta = desc2->GetStackParameterDelta(desc1);
350 351 352
  // We might need to drop one slot of padding from the caller's arguments.
  int expected = kPadArguments ? 0 : 1;
  EXPECT_EQ(expected, stack_param_delta);
353 354 355 356 357
}

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