linkage.h 22.8 KB
Newer Older
1 2 3 4 5 6 7
// 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.

#ifndef V8_COMPILER_LINKAGE_H_
#define V8_COMPILER_LINKAGE_H_

8
#include "src/base/compiler-specific.h"
9
#include "src/base/flags.h"
10 11
#include "src/codegen/interface-descriptors.h"
#include "src/codegen/machine-type.h"
12
#include "src/codegen/register.h"
13 14
#include "src/codegen/reglist.h"
#include "src/codegen/signature.h"
15
#include "src/common/globals.h"
16 17
#include "src/compiler/frame.h"
#include "src/compiler/operator.h"
18
#include "src/execution/encoded-c-signature.h"
19
#include "src/runtime/runtime.h"
20
#include "src/zone/zone.h"
21

22 23 24 25 26 27 28
#if !defined(__clang__) && defined(_M_ARM64)
// _M_ARM64 is an MSVC-specific macro that clang-cl emulates.
#define NO_INLINE_FOR_ARM64_MSVC __declspec(noinline)
#else
#define NO_INLINE_FOR_ARM64_MSVC
#endif

29
namespace v8 {
30 31
class CFunctionInfo;

32
namespace internal {
33 34

class CallInterfaceDescriptor;
35
class OptimizedCompilationInfo;
36

37 38
namespace compiler {

39 40
constexpr RegList kNoCalleeSaved;
constexpr DoubleRegList kNoCalleeSavedFp;
41

42 43
class OsrHelper;

44 45 46
// Describes the location for a parameter or a return value to a call.
class LinkageLocation {
 public:
47
  bool operator==(const LinkageLocation& other) const {
48 49
    return bit_field_ == other.bit_field_ &&
           machine_type_ == other.machine_type_;
50
  }
51

52 53
  bool operator!=(const LinkageLocation& other) const {
    return !(*this == other);
svenpanne's avatar
svenpanne committed
54 55
  }

56 57 58 59 60 61 62 63 64 65 66 67 68
  static bool IsSameLocation(const LinkageLocation& a,
                             const LinkageLocation& b) {
    // Different MachineTypes may end up at the same physical location. With the
    // sub-type check we make sure that types like {AnyTagged} and
    // {TaggedPointer} which would end up with the same physical location are
    // considered equal here.
    return (a.bit_field_ == b.bit_field_) &&
           (IsSubtype(a.machine_type_.representation(),
                      b.machine_type_.representation()) ||
            IsSubtype(b.machine_type_.representation(),
                      a.machine_type_.representation()));
  }

69 70 71 72 73
  static LinkageLocation ForNullRegister(
      int32_t reg, MachineType type = MachineType::None()) {
    return LinkageLocation(REGISTER, reg, type);
  }

74 75 76
  static LinkageLocation ForAnyRegister(
      MachineType type = MachineType::None()) {
    return LinkageLocation(REGISTER, ANY_REGISTER, type);
77
  }
78

79 80
  static LinkageLocation ForRegister(int32_t reg,
                                     MachineType type = MachineType::None()) {
81
    DCHECK_LE(0, reg);
82
    return LinkageLocation(REGISTER, reg, type);
83
  }
84

85
  static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) {
86
    DCHECK_GT(0, slot);
87
    return LinkageLocation(STACK_SLOT, slot, type);
svenpanne's avatar
svenpanne committed
88 89
  }

90
  static LinkageLocation ForCalleeFrameSlot(int32_t slot, MachineType type) {
91 92
    // TODO(titzer): bailout instead of crashing here.
    DCHECK(slot >= 0 && slot < LinkageLocation::MAX_STACK_SLOT);
93
    return LinkageLocation(STACK_SLOT, slot, type);
svenpanne's avatar
svenpanne committed
94 95
  }

96 97 98
  static LinkageLocation ForSavedCallerReturnAddress() {
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kCallerPCOffset) /
99
                                  kSystemPointerSize,
100
                              MachineType::Pointer());
101 102 103 104 105
  }

  static LinkageLocation ForSavedCallerFramePtr() {
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kCallerFPOffset) /
106
                                  kSystemPointerSize,
107
                              MachineType::Pointer());
108 109 110 111 112 113
  }

  static LinkageLocation ForSavedCallerConstantPool() {
    DCHECK(V8_EMBEDDED_CONSTANT_POOL);
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kConstantPoolOffset) /
114
                                  kSystemPointerSize,
115
                              MachineType::AnyTagged());
116 117
  }

118
  static LinkageLocation ForSavedCallerFunction() {
119
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
120
                               StandardFrameConstants::kFunctionOffset) /
121
                                  kSystemPointerSize,
122
                              MachineType::AnyTagged());
123 124
  }

125 126 127 128
  static LinkageLocation ConvertToTailCallerLocation(
      LinkageLocation caller_location, int stack_param_delta) {
    if (!caller_location.IsRegister()) {
      return LinkageLocation(STACK_SLOT,
129 130
                             caller_location.GetLocation() + stack_param_delta,
                             caller_location.GetType());
131 132 133 134
    }
    return caller_location;
  }

135 136 137
  MachineType GetType() const { return machine_type_; }

  int GetSizeInPointers() const {
138
    return ElementSizeInPointers(GetType().representation());
139 140 141
  }

  int32_t GetLocation() const {
142 143
    // We can't use LocationField::decode here because it doesn't work for
    // negative values!
144 145 146 147
    return static_cast<int32_t>(bit_field_ & LocationField::kMask) >>
           LocationField::kShift;
  }

148 149 150
  bool IsNullRegister() const {
    return IsRegister() && GetLocation() < ANY_REGISTER;
  }
151 152 153
  NO_INLINE_FOR_ARM64_MSVC bool IsRegister() const {
    return TypeField::decode(bit_field_) == REGISTER;
  }
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  bool IsAnyRegister() const {
    return IsRegister() && GetLocation() == ANY_REGISTER;
  }
  bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
  bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; }

  int32_t AsRegister() const {
    DCHECK(IsRegister());
    return GetLocation();
  }
  int32_t AsCallerFrameSlot() const {
    DCHECK(IsCallerFrameSlot());
    return GetLocation();
  }
  int32_t AsCalleeFrameSlot() const {
    DCHECK(IsCalleeFrameSlot());
    return GetLocation();
  }

173 174 175
 private:
  enum LocationType { REGISTER, STACK_SLOT };

176
  using TypeField = base::BitField<LocationType, 0, 1>;
177
  using LocationField = TypeField::Next<int32_t, 31>;
178 179 180 181 182 183 184

  static constexpr int32_t ANY_REGISTER = -1;
  static constexpr int32_t MAX_STACK_SLOT = 32767;

  LinkageLocation(LocationType type, int32_t location,
                  MachineType machine_type) {
    bit_field_ = TypeField::encode(type) |
185 186 187
                 // {location} can be -1 (ANY_REGISTER).
                 ((static_cast<uint32_t>(location) << LocationField::kShift) &
                  LocationField::kMask);
188 189 190
    machine_type_ = machine_type;
  }

191
  int32_t bit_field_;
192
  MachineType machine_type_;
193 194
};

195
using LocationSignature = Signature<LinkageLocation>;
196

197 198
// Describes a call to various parts of the compiler. Every call has the notion
// of a "target", which is the first input to the call.
199 200
class V8_EXPORT_PRIVATE CallDescriptor final
    : public NON_EXPORTED_BASE(ZoneObject) {
201
 public:
202 203
  // Describes the kind of this call, which determines the target.
  enum Kind {
204 205 206
    kCallCodeObject,         // target is a Code object
    kCallJSFunction,         // target is a JSFunction object
    kCallAddress,            // target is a machine pointer
207
#if V8_ENABLE_WEBASSEMBLY    // ↓ WebAssembly only
208
    kCallWasmCapiFunction,   // target is a Wasm C API function
209 210
    kCallWasmFunction,       // target is a wasm function
    kCallWasmImportWrapper,  // target is a wasm import wrapper
211
#endif                       // ↑ WebAssembly only
212
    kCallBuiltinPointer,     // target is a builtin pointer
213
  };
214

215 216 217
  // NOTE: The lowest 10 bits of the Flags field are encoded in InstructionCode
  // (for use in the code generator). All higher bits are lost.
  static constexpr int kFlagsBitsEncodedInInstructionCode = 10;
218 219
  enum Flag {
    kNoFlags = 0u,
220
    kNeedsFrameState = 1u << 0,
221
    kHasExceptionHandler = 1u << 1,
222
    kCanUseRoots = 1u << 2,
223
    // Causes the code generator to initialize the root register.
224
    kInitializeRootRegister = 1u << 3,
225
    // Does not ever try to allocate space on our heap.
226
    kNoAllocate = 1u << 4,
227 228
    // Use the kJavaScriptCallCodeStartRegister (fixed) register for the
    // indirect target address when calling.
229 230
    kFixedTargetRegister = 1u << 5,
    kCallerSavedRegisters = 1u << 6,
231 232
    // The kCallerSavedFPRegisters only matters (and set) when the more general
    // flag for kCallerSavedRegisters above is also set.
233
    kCallerSavedFPRegisters = 1u << 7,
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
    // Tail calls for tier up are special (in fact they are different enough
    // from normal tail calls to warrant a dedicated opcode; but they also have
    // enough similar aspects that reusing the TailCall opcode is pragmatic).
    // Specifically:
    //
    // 1. Caller and callee are both JS-linkage Code objects.
    // 2. JS runtime arguments are passed unchanged from caller to callee.
    // 3. JS runtime arguments are not attached as inputs to the TailCall node.
    // 4. Prior to the tail call, frame and register state is torn down to just
    //    before the caller frame was constructed.
    // 5. Unlike normal tail calls, arguments adaptor frames (if present) are
    //    *not* torn down.
    //
    // In other words, behavior is identical to a jmp instruction prior caller
    // frame construction.
249 250 251 252 253
    kIsTailCallForTierUp = 1u << 8,

    // AIX has a function descriptor by default but it can be disabled for a
    // certain CFunction call (only used for Kind::kCallAddress).
    kNoFunctionDescriptor = 1u << 9,
254 255 256 257

    // Flags past here are *not* encoded in InstructionCode and are thus not
    // accessible from the code generator. See also
    // kFlagsBitsEncodedInInstructionCode.
258
  };
259
  using Flags = base::Flags<Flag>;
260

261
  CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc,
262
                 LocationSignature* location_sig, size_t param_slot_count,
263
                 Operator::Properties properties,
264
                 RegList callee_saved_registers,
265
                 DoubleRegList callee_saved_fp_registers, Flags flags,
266
                 const char* debug_name = "",
267
                 StackArgumentOrder stack_order = StackArgumentOrder::kDefault,
268
                 const RegList allocatable_registers = {},
269
                 size_t return_slot_count = 0)
270
      : kind_(kind),
271 272 273
        target_type_(target_type),
        target_loc_(target_loc),
        location_sig_(location_sig),
274 275
        param_slot_count_(param_slot_count),
        return_slot_count_(return_slot_count),
276 277
        properties_(properties),
        callee_saved_registers_(callee_saved_registers),
278
        callee_saved_fp_registers_(callee_saved_fp_registers),
279
        allocatable_registers_(allocatable_registers),
280
        flags_(flags),
281
        stack_order_(stack_order),
282
        debug_name_(debug_name) {}
283

284 285 286
  CallDescriptor(const CallDescriptor&) = delete;
  CallDescriptor& operator=(const CallDescriptor&) = delete;

287 288 289
  // Returns the kind of this call.
  Kind kind() const { return kind_; }

290 291 292
  // Returns {true} if this descriptor is a call to a C function.
  bool IsCFunctionCall() const { return kind_ == kCallAddress; }

293 294 295
  // Returns {true} if this descriptor is a call to a JSFunction.
  bool IsJSFunctionCall() const { return kind_ == kCallJSFunction; }

296
#if V8_ENABLE_WEBASSEMBLY
297 298 299
  // Returns {true} if this descriptor is a call to a WebAssembly function.
  bool IsWasmFunctionCall() const { return kind_ == kCallWasmFunction; }

300 301 302
  // Returns {true} if this descriptor is a call to a WebAssembly function.
  bool IsWasmImportWrapper() const { return kind_ == kCallWasmImportWrapper; }

303 304
  // Returns {true} if this descriptor is a call to a Wasm C API function.
  bool IsWasmCapiFunction() const { return kind_ == kCallWasmCapiFunction; }
305
#endif  // V8_ENABLE_WEBASSEMBLY
306

307
  bool RequiresFrameAsIncoming() const {
308 309 310 311
    if (IsCFunctionCall() || IsJSFunctionCall()) return true;
#if V8_ENABLE_WEBASSEMBLY
    if (IsWasmFunctionCall()) return true;
#endif  // V8_ENABLE_WEBASSEMBLY
312
    if (CalleeSavedRegisters() != kNoCalleeSaved) return true;
313
    return false;
314 315
  }

316
  // The number of return values from this call.
317
  size_t ReturnCount() const { return location_sig_->return_count(); }
318

319 320 321
  // The number of C parameters to this call. The following invariant
  // should hold true:
  // ParameterCount() == GPParameterCount() + FPParameterCount()
322
  size_t ParameterCount() const { return location_sig_->parameter_count(); }
323

324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
  // The number of general purpose C parameters to this call.
  size_t GPParameterCount() const {
    if (!gp_param_count_) {
      ComputeParamCounts();
    }
    return gp_param_count_.value();
  }

  // The number of floating point C parameters to this call.
  size_t FPParameterCount() const {
    if (!fp_param_count_) {
      ComputeParamCounts();
    }
    return fp_param_count_.value();
  }

340
  // The number of stack parameter slots to the call.
341
  size_t ParameterSlotCount() const { return param_slot_count_; }
342

343
  // The number of stack return value slots from the call.
344
  size_t ReturnSlotCount() const { return return_slot_count_; }
345

346 347 348
  // The number of parameters to the JS function call.
  size_t JSParameterCount() const {
    DCHECK(IsJSFunctionCall());
349
    return param_slot_count_;
350
  }
351

352 353 354 355 356
  int GetStackIndexFromSlot(int slot_index) const {
    switch (GetStackArgumentOrder()) {
      case StackArgumentOrder::kDefault:
        return -slot_index - 1;
      case StackArgumentOrder::kJS:
357
        return slot_index + static_cast<int>(ParameterSlotCount());
358 359 360
    }
  }

361 362 363
  // The total number of inputs to this call, which includes the target,
  // receiver, context, etc.
  // TODO(titzer): this should input the framestate input too.
364
  size_t InputCount() const { return 1 + location_sig_->parameter_count(); }
365

366
  size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
367

368
  Flags flags() const { return flags_; }
369

370
  bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
371 372 373
  bool InitializeRootRegister() const {
    return flags() & kInitializeRootRegister;
  }
374 375 376
  bool NeedsCallerSavedRegisters() const {
    return flags() & kCallerSavedRegisters;
  }
377 378 379
  bool NeedsCallerSavedFPRegisters() const {
    return flags() & kCallerSavedFPRegisters;
  }
380
  bool IsTailCallForTierUp() const { return flags() & kIsTailCallForTierUp; }
381
  bool NoFunctionDescriptor() const { return flags() & kNoFunctionDescriptor; }
382

383 384
  LinkageLocation GetReturnLocation(size_t index) const {
    return location_sig_->GetReturn(index);
385 386
  }

387 388 389 390 391
  LinkageLocation GetInputLocation(size_t index) const {
    if (index == 0) return target_loc_;
    return location_sig_->GetParam(index - 1);
  }

392
  MachineSignature* GetMachineSignature(Zone* zone) const;
393 394

  MachineType GetReturnType(size_t index) const {
395
    return location_sig_->GetReturn(index).GetType();
396 397 398 399
  }

  MachineType GetInputType(size_t index) const {
    if (index == 0) return target_type_;
400 401 402 403 404
    return location_sig_->GetParam(index - 1).GetType();
  }

  MachineType GetParameterType(size_t index) const {
    return location_sig_->GetParam(index).GetType();
405 406
  }

407 408
  StackArgumentOrder GetStackArgumentOrder() const { return stack_order_; }

409
  // Operator properties describe how this call can be optimized, if at all.
410
  Operator::Properties properties() const { return properties_; }
411 412

  // Get the callee-saved registers, if any, across this call.
413
  RegList CalleeSavedRegisters() const { return callee_saved_registers_; }
414

415
  // Get the callee-saved FP registers, if any, across this call.
416 417 418
  DoubleRegList CalleeSavedFPRegisters() const {
    return callee_saved_fp_registers_;
  }
419

420 421
  const char* debug_name() const { return debug_name_; }

422 423
  // Difference between the number of parameter slots of *this* and
  // *tail_caller* (callee minus caller).
424
  int GetStackParameterDelta(const CallDescriptor* tail_caller) const;
425

426 427 428 429
  // Returns the offset to the area below the parameter slots on the stack,
  // relative to callee slot 0, the return address. If there are no parameter
  // slots, returns +1.
  int GetOffsetToFirstUnusedStackSlot() const;
430

431 432 433 434
  // Returns the offset to the area above the return slots on the stack,
  // relative to callee slot 0, the return address. If there are no return
  // slots, returns the offset to the lowest slot of the parameter area.
  // If there are no parameter slots, returns 0.
435 436
  int GetOffsetToReturns() const;

437 438
  // Returns two 16-bit numbers packed together: (first slot << 16) | num_slots.
  uint32_t GetTaggedParameterSlots() const;
439

440
  bool CanTailCall(const CallDescriptor* callee) const;
441

442
  int CalculateFixedFrameSize(CodeKind code_kind) const;
443

444 445 446
  RegList AllocatableRegisters() const { return allocatable_registers_; }

  bool HasRestrictedAllocatableRegisters() const {
447
    return !allocatable_registers_.is_empty();
448 449
  }

450 451
  EncodedCSignature ToEncodedCSignature() const;

452
 private:
453 454
  void ComputeParamCounts() const;

455 456
  friend class Linkage;

457 458 459 460
  const Kind kind_;
  const MachineType target_type_;
  const LinkageLocation target_loc_;
  const LocationSignature* const location_sig_;
461 462
  const size_t param_slot_count_;
  const size_t return_slot_count_;
463 464
  const Operator::Properties properties_;
  const RegList callee_saved_registers_;
465
  const DoubleRegList callee_saved_fp_registers_;
466 467 468
  // Non-zero value means restricting the set of allocatable registers for
  // register allocator to use.
  const RegList allocatable_registers_;
469
  const Flags flags_;
470
  const StackArgumentOrder stack_order_;
471
  const char* const debug_name_;
472 473 474

  mutable base::Optional<size_t> gp_param_count_;
  mutable base::Optional<size_t> fp_param_count_;
475 476
};

477 478
DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags)

479
std::ostream& operator<<(std::ostream& os, const CallDescriptor& d);
480 481
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const CallDescriptor::Kind& k);
482 483 484 485 486 487 488 489

// Defines the linkage for a compilation, including the calling conventions
// for incoming parameters and return value(s) as well as the outgoing calling
// convention for any kind of call. Linkage is generally architecture-specific.
//
// Can be used to translate {arg_index} (i.e. index of the call node input) as
// well as {param_index} (i.e. as stored in parameter nodes) into an operator
// representing the architecture-specific location. The following call node
490
// layouts are supported (where {n} is the number of value inputs):
491
//
492 493 494
//                        #0          #1     #2     [...]             #n
// Call[CodeStub]         code,       arg 1, arg 2, [...],            context
// Call[JSFunction]       function,   rcvr,  arg 1, [...], new, #arg, context
495
// Call[Runtime]          CEntry,     arg 1, arg 2, [...], fun, #arg, context
496
// Call[BytecodeDispatch] address,    arg 1, arg 2, [...]
497
class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) {
498
 public:
499
  explicit Linkage(CallDescriptor* incoming) : incoming_(incoming) {}
500 501
  Linkage(const Linkage&) = delete;
  Linkage& operator=(const Linkage&) = delete;
502

503 504
  static CallDescriptor* ComputeIncoming(Zone* zone,
                                         OptimizedCompilationInfo* info);
505 506 507

  // The call descriptor for this compilation unit describes the locations
  // of incoming parameters and the outgoing return value(s).
508
  CallDescriptor* GetIncomingDescriptor() const { return incoming_; }
509 510
  static CallDescriptor* GetJSCallDescriptor(Zone* zone, bool is_osr,
                                             int parameter_count,
511
                                             CallDescriptor::Flags flags);
512

513
  static CallDescriptor* GetRuntimeCallDescriptor(
514
      Zone* zone, Runtime::FunctionId function, int js_parameter_count,
515
      Operator::Properties properties, CallDescriptor::Flags flags);
516

517 518 519
  static CallDescriptor* GetCEntryStubCallDescriptor(
      Zone* zone, int return_count, int js_parameter_count,
      const char* debug_name, Operator::Properties properties,
520 521
      CallDescriptor::Flags flags,
      StackArgumentOrder stack_order = StackArgumentOrder::kDefault);
522

523
  static CallDescriptor* GetStubCallDescriptor(
524
      Zone* zone, const CallInterfaceDescriptor& descriptor,
525
      int stack_parameter_count, CallDescriptor::Flags flags,
526
      Operator::Properties properties = Operator::kNoProperties,
527
      StubCallMode stub_mode = StubCallMode::kCallCodeObject);
528

529
  static CallDescriptor* GetBytecodeDispatchCallDescriptor(
530
      Zone* zone, const CallInterfaceDescriptor& descriptor,
531 532
      int stack_parameter_count);

533 534 535 536
  // Creates a call descriptor for simplified C calls that is appropriate
  // for the host platform. This simplified calling convention only supports
  // integers and pointers of one word size each, i.e. no floating point,
  // structs, pointers to members, etc.
537 538
  static CallDescriptor* GetSimplifiedCDescriptor(
      Zone* zone, const MachineSignature* sig,
539
      CallDescriptor::Flags flags = CallDescriptor::kNoFlags);
540 541

  // Get the location of an (incoming) parameter to this function.
542
  LinkageLocation GetParameterLocation(int index) const {
543 544 545 546
    return incoming_->GetInputLocation(index + 1);  // + 1 to skip target.
  }

  // Get the machine type of an (incoming) parameter to this function.
547
  MachineType GetParameterType(int index) const {
548
    return incoming_->GetInputType(index + 1);  // + 1 to skip target.
549 550 551
  }

  // Get the location where this function should place its return value.
552 553
  LinkageLocation GetReturnLocation(size_t index = 0) const {
    return incoming_->GetReturnLocation(index);
554 555
  }

556
  // Get the machine type of this function's return value.
557 558 559
  MachineType GetReturnType(size_t index = 0) const {
    return incoming_->GetReturnType(index);
  }
560

561 562 563
  bool ParameterHasSecondaryLocation(int index) const;
  LinkageLocation GetParameterSecondaryLocation(int index) const;

564
  static bool NeedsFrameStateInput(Runtime::FunctionId function);
565

566 567 568
  // Get the location where an incoming OSR value is stored.
  LinkageLocation GetOsrValueLocation(int index) const;

569 570 571 572 573
  // A special {Parameter} index for Stub Calls that represents context.
  static int GetStubCallContextParamIndex(int parameter_count) {
    return parameter_count + 0;  // Parameter (arity + 0) is special.
  }

574
  // A special {Parameter} index for JSCalls that represents the new target.
575
  static constexpr int GetJSCallNewTargetParamIndex(int parameter_count) {
576 577 578 579
    return parameter_count + 0;  // Parameter (arity + 0) is special.
  }

  // A special {Parameter} index for JSCalls that represents the argument count.
580
  static constexpr int GetJSCallArgCountParamIndex(int parameter_count) {
581 582 583 584
    return parameter_count + 1;  // Parameter (arity + 1) is special.
  }

  // A special {Parameter} index for JSCalls that represents the context.
585
  static constexpr int GetJSCallContextParamIndex(int parameter_count) {
586 587 588 589
    return parameter_count + 2;  // Parameter (arity + 2) is special.
  }

  // A special {Parameter} index for JSCalls that represents the closure.
590
  static constexpr int kJSCallClosureParamIndex = -1;
591

592 593 594
  // A special {OsrValue} index to indicate the context spill slot.
  static const int kOsrContextSpillSlotIndex = -1;

595 596 597
  // A special {OsrValue} index to indicate the accumulator register.
  static const int kOsrAccumulatorRegisterIndex = -1;

598
 private:
599
  CallDescriptor* const incoming_;
600
};
601 602 603 604

}  // namespace compiler
}  // namespace internal
}  // namespace v8
605
#undef NO_INLINE_FOR_ARM64_MSVC
606 607

#endif  // V8_COMPILER_LINKAGE_H_