• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_COMPILER_LINKAGE_H_
6 #define V8_COMPILER_LINKAGE_H_
7 
8 #include "src/base/compiler-specific.h"
9 #include "src/base/flags.h"
10 #include "src/codegen/interface-descriptors.h"
11 #include "src/codegen/machine-type.h"
12 #include "src/codegen/register.h"
13 #include "src/codegen/reglist.h"
14 #include "src/codegen/signature.h"
15 #include "src/common/globals.h"
16 #include "src/compiler/frame.h"
17 #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 #if !defined(__clang__) && defined(_M_ARM64)
23 // _M_ARM64 is an MSVC-specific macro that clang-cl emulates.
24 #define NO_INLINE_FOR_ARM64_MSVC __declspec(noinline)
25 #else
26 #define NO_INLINE_FOR_ARM64_MSVC
27 #endif
28 
29 namespace v8 {
30 class CFunctionInfo;
31 
32 namespace internal {
33 
34 class CallInterfaceDescriptor;
35 class OptimizedCompilationInfo;
36 
37 namespace compiler {
38 
39 constexpr RegList kNoCalleeSaved;
40 constexpr DoubleRegList kNoCalleeSavedFp;
41 
42 class OsrHelper;
43 
44 // Describes the location for a parameter or a return value to a call.
45 class LinkageLocation {
46  public:
47   bool operator==(const LinkageLocation& other) const {
48     return bit_field_ == other.bit_field_ &&
49            machine_type_ == other.machine_type_;
50   }
51 
52   bool operator!=(const LinkageLocation& other) const {
53     return !(*this == other);
54   }
55 
IsSameLocation(const LinkageLocation & a,const LinkageLocation & b)56   static bool IsSameLocation(const LinkageLocation& a,
57                              const LinkageLocation& b) {
58     // Different MachineTypes may end up at the same physical location. With the
59     // sub-type check we make sure that types like {AnyTagged} and
60     // {TaggedPointer} which would end up with the same physical location are
61     // considered equal here.
62     return (a.bit_field_ == b.bit_field_) &&
63            (IsSubtype(a.machine_type_.representation(),
64                       b.machine_type_.representation()) ||
65             IsSubtype(b.machine_type_.representation(),
66                       a.machine_type_.representation()));
67   }
68 
69   static LinkageLocation ForAnyRegister(
70       MachineType type = MachineType::None()) {
71     return LinkageLocation(REGISTER, ANY_REGISTER, type);
72   }
73 
74   static LinkageLocation ForRegister(int32_t reg,
75                                      MachineType type = MachineType::None()) {
76     DCHECK_LE(0, reg);
77     return LinkageLocation(REGISTER, reg, type);
78   }
79 
ForCallerFrameSlot(int32_t slot,MachineType type)80   static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) {
81     DCHECK_GT(0, slot);
82     return LinkageLocation(STACK_SLOT, slot, type);
83   }
84 
ForCalleeFrameSlot(int32_t slot,MachineType type)85   static LinkageLocation ForCalleeFrameSlot(int32_t slot, MachineType type) {
86     // TODO(titzer): bailout instead of crashing here.
87     DCHECK(slot >= 0 && slot < LinkageLocation::MAX_STACK_SLOT);
88     return LinkageLocation(STACK_SLOT, slot, type);
89   }
90 
ForSavedCallerReturnAddress()91   static LinkageLocation ForSavedCallerReturnAddress() {
92     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
93                                StandardFrameConstants::kCallerPCOffset) /
94                                   kSystemPointerSize,
95                               MachineType::Pointer());
96   }
97 
ForSavedCallerFramePtr()98   static LinkageLocation ForSavedCallerFramePtr() {
99     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
100                                StandardFrameConstants::kCallerFPOffset) /
101                                   kSystemPointerSize,
102                               MachineType::Pointer());
103   }
104 
ForSavedCallerConstantPool()105   static LinkageLocation ForSavedCallerConstantPool() {
106     DCHECK(V8_EMBEDDED_CONSTANT_POOL);
107     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
108                                StandardFrameConstants::kConstantPoolOffset) /
109                                   kSystemPointerSize,
110                               MachineType::AnyTagged());
111   }
112 
ForSavedCallerFunction()113   static LinkageLocation ForSavedCallerFunction() {
114     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
115                                StandardFrameConstants::kFunctionOffset) /
116                                   kSystemPointerSize,
117                               MachineType::AnyTagged());
118   }
119 
ConvertToTailCallerLocation(LinkageLocation caller_location,int stack_param_delta)120   static LinkageLocation ConvertToTailCallerLocation(
121       LinkageLocation caller_location, int stack_param_delta) {
122     if (!caller_location.IsRegister()) {
123       return LinkageLocation(STACK_SLOT,
124                              caller_location.GetLocation() + stack_param_delta,
125                              caller_location.GetType());
126     }
127     return caller_location;
128   }
129 
GetType()130   MachineType GetType() const { return machine_type_; }
131 
GetSizeInPointers()132   int GetSizeInPointers() const {
133     return ElementSizeInPointers(GetType().representation());
134   }
135 
GetLocation()136   int32_t GetLocation() const {
137     // We can't use LocationField::decode here because it doesn't work for
138     // negative values!
139     return static_cast<int32_t>(bit_field_ & LocationField::kMask) >>
140            LocationField::kShift;
141   }
142 
IsRegister()143   NO_INLINE_FOR_ARM64_MSVC bool IsRegister() const {
144     return TypeField::decode(bit_field_) == REGISTER;
145   }
IsAnyRegister()146   bool IsAnyRegister() const {
147     return IsRegister() && GetLocation() == ANY_REGISTER;
148   }
IsCallerFrameSlot()149   bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
IsCalleeFrameSlot()150   bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; }
151 
AsRegister()152   int32_t AsRegister() const {
153     DCHECK(IsRegister());
154     return GetLocation();
155   }
AsCallerFrameSlot()156   int32_t AsCallerFrameSlot() const {
157     DCHECK(IsCallerFrameSlot());
158     return GetLocation();
159   }
AsCalleeFrameSlot()160   int32_t AsCalleeFrameSlot() const {
161     DCHECK(IsCalleeFrameSlot());
162     return GetLocation();
163   }
164 
165  private:
166   enum LocationType { REGISTER, STACK_SLOT };
167 
168   using TypeField = base::BitField<LocationType, 0, 1>;
169   using LocationField = TypeField::Next<int32_t, 31>;
170 
171   static constexpr int32_t ANY_REGISTER = -1;
172   static constexpr int32_t MAX_STACK_SLOT = 32767;
173 
LinkageLocation(LocationType type,int32_t location,MachineType machine_type)174   LinkageLocation(LocationType type, int32_t location,
175                   MachineType machine_type) {
176     bit_field_ = TypeField::encode(type) |
177                  // {location} can be -1 (ANY_REGISTER).
178                  ((static_cast<uint32_t>(location) << LocationField::kShift) &
179                   LocationField::kMask);
180     machine_type_ = machine_type;
181   }
182 
183   int32_t bit_field_;
184   MachineType machine_type_;
185 };
186 
187 using LocationSignature = Signature<LinkageLocation>;
188 
189 // Describes a call to various parts of the compiler. Every call has the notion
190 // of a "target", which is the first input to the call.
191 class V8_EXPORT_PRIVATE CallDescriptor final
NON_EXPORTED_BASE(ZoneObject)192     : public NON_EXPORTED_BASE(ZoneObject) {
193  public:
194   // Describes the kind of this call, which determines the target.
195   enum Kind {
196     kCallCodeObject,         // target is a Code object
197     kCallJSFunction,         // target is a JSFunction object
198     kCallAddress,            // target is a machine pointer
199 #if V8_ENABLE_WEBASSEMBLY    // ↓ WebAssembly only
200     kCallWasmCapiFunction,   // target is a Wasm C API function
201     kCallWasmFunction,       // target is a wasm function
202     kCallWasmImportWrapper,  // target is a wasm import wrapper
203 #endif                       // ↑ WebAssembly only
204     kCallBuiltinPointer,     // target is a builtin pointer
205   };
206 
207   // NOTE: The lowest 10 bits of the Flags field are encoded in InstructionCode
208   // (for use in the code generator). All higher bits are lost.
209   static constexpr int kFlagsBitsEncodedInInstructionCode = 10;
210   enum Flag {
211     kNoFlags = 0u,
212     kNeedsFrameState = 1u << 0,
213     kHasExceptionHandler = 1u << 1,
214     kCanUseRoots = 1u << 2,
215     // Causes the code generator to initialize the root register.
216     kInitializeRootRegister = 1u << 3,
217     // Does not ever try to allocate space on our heap.
218     kNoAllocate = 1u << 4,
219     // Use the kJavaScriptCallCodeStartRegister (fixed) register for the
220     // indirect target address when calling.
221     kFixedTargetRegister = 1u << 5,
222     kCallerSavedRegisters = 1u << 6,
223     // The kCallerSavedFPRegisters only matters (and set) when the more general
224     // flag for kCallerSavedRegisters above is also set.
225     kCallerSavedFPRegisters = 1u << 7,
226     // Tail calls for tier up are special (in fact they are different enough
227     // from normal tail calls to warrant a dedicated opcode; but they also have
228     // enough similar aspects that reusing the TailCall opcode is pragmatic).
229     // Specifically:
230     //
231     // 1. Caller and callee are both JS-linkage Code objects.
232     // 2. JS runtime arguments are passed unchanged from caller to callee.
233     // 3. JS runtime arguments are not attached as inputs to the TailCall node.
234     // 4. Prior to the tail call, frame and register state is torn down to just
235     //    before the caller frame was constructed.
236     // 5. Unlike normal tail calls, arguments adaptor frames (if present) are
237     //    *not* torn down.
238     //
239     // In other words, behavior is identical to a jmp instruction prior caller
240     // frame construction.
241     kIsTailCallForTierUp = 1u << 8,
242 
243     // AIX has a function descriptor by default but it can be disabled for a
244     // certain CFunction call (only used for Kind::kCallAddress).
245     kNoFunctionDescriptor = 1u << 9,
246 
247     // Flags past here are *not* encoded in InstructionCode and are thus not
248     // accessible from the code generator. See also
249     // kFlagsBitsEncodedInInstructionCode.
250   };
251   using Flags = base::Flags<Flag>;
252 
253   CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc,
254                  LocationSignature* location_sig, size_t param_slot_count,
255                  Operator::Properties properties,
256                  RegList callee_saved_registers,
257                  DoubleRegList callee_saved_fp_registers, Flags flags,
258                  const char* debug_name = "",
259                  StackArgumentOrder stack_order = StackArgumentOrder::kDefault,
260 #if V8_ENABLE_WEBASSEMBLY
261                  const wasm::FunctionSig* wasm_sig = nullptr,
262 #endif
263                  const RegList allocatable_registers = {},
264                  size_t return_slot_count = 0)
265       : kind_(kind),
266         target_type_(target_type),
267         target_loc_(target_loc),
268         location_sig_(location_sig),
269         param_slot_count_(param_slot_count),
270         return_slot_count_(return_slot_count),
271         properties_(properties),
272         callee_saved_registers_(callee_saved_registers),
273         callee_saved_fp_registers_(callee_saved_fp_registers),
274         allocatable_registers_(allocatable_registers),
275         flags_(flags),
276         stack_order_(stack_order),
277 #if V8_ENABLE_WEBASSEMBLY
278         wasm_sig_(wasm_sig),
279 #endif
280         debug_name_(debug_name) {
281   }
282 
283   CallDescriptor(const CallDescriptor&) = delete;
284   CallDescriptor& operator=(const CallDescriptor&) = delete;
285 
286   // Returns the kind of this call.
287   Kind kind() const { return kind_; }
288 
289   // Returns {true} if this descriptor is a call to a C function.
290   bool IsCFunctionCall() const { return kind_ == kCallAddress; }
291 
292   // Returns {true} if this descriptor is a call to a JSFunction.
293   bool IsJSFunctionCall() const { return kind_ == kCallJSFunction; }
294 
295 #if V8_ENABLE_WEBASSEMBLY
296   // Returns {true} if this descriptor is a call to a WebAssembly function.
297   bool IsWasmFunctionCall() const { return kind_ == kCallWasmFunction; }
298 
299   // Returns {true} if this descriptor is a call to a WebAssembly function.
300   bool IsWasmImportWrapper() const { return kind_ == kCallWasmImportWrapper; }
301 
302   // Returns {true} if this descriptor is a call to a Wasm C API function.
303   bool IsWasmCapiFunction() const { return kind_ == kCallWasmCapiFunction; }
304 
305   // Returns the wasm signature for this call based on the real parameter types.
306   const wasm::FunctionSig* wasm_sig() const { return wasm_sig_; }
307 #endif  // V8_ENABLE_WEBASSEMBLY
308 
309   bool RequiresFrameAsIncoming() const {
310     if (IsCFunctionCall() || IsJSFunctionCall()) return true;
311 #if V8_ENABLE_WEBASSEMBLY
312     if (IsWasmFunctionCall()) return true;
313 #endif  // V8_ENABLE_WEBASSEMBLY
314     if (CalleeSavedRegisters() != kNoCalleeSaved) return true;
315     return false;
316   }
317 
318   // The number of return values from this call.
319   size_t ReturnCount() const { return location_sig_->return_count(); }
320 
321   // The number of C parameters to this call. The following invariant
322   // should hold true:
323   // ParameterCount() == GPParameterCount() + FPParameterCount()
324   size_t ParameterCount() const { return location_sig_->parameter_count(); }
325 
326   // The number of general purpose C parameters to this call.
327   size_t GPParameterCount() const {
328     if (!gp_param_count_) {
329       ComputeParamCounts();
330     }
331     return gp_param_count_.value();
332   }
333 
334   // The number of floating point C parameters to this call.
335   size_t FPParameterCount() const {
336     if (!fp_param_count_) {
337       ComputeParamCounts();
338     }
339     return fp_param_count_.value();
340   }
341 
342   // The number of stack parameter slots to the call.
343   size_t ParameterSlotCount() const { return param_slot_count_; }
344 
345   // The number of stack return value slots from the call.
346   size_t ReturnSlotCount() const { return return_slot_count_; }
347 
348   // The number of parameters to the JS function call.
349   size_t JSParameterCount() const {
350     DCHECK(IsJSFunctionCall());
351     return param_slot_count_;
352   }
353 
354   int GetStackIndexFromSlot(int slot_index) const {
355     switch (GetStackArgumentOrder()) {
356       case StackArgumentOrder::kDefault:
357         return -slot_index - 1;
358       case StackArgumentOrder::kJS:
359         return slot_index + static_cast<int>(ParameterSlotCount());
360     }
361   }
362 
363   // The total number of inputs to this call, which includes the target,
364   // receiver, context, etc.
365   // TODO(titzer): this should input the framestate input too.
366   size_t InputCount() const { return 1 + location_sig_->parameter_count(); }
367 
368   size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
369 
370   Flags flags() const { return flags_; }
371 
372   bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
373   bool InitializeRootRegister() const {
374     return flags() & kInitializeRootRegister;
375   }
376   bool NeedsCallerSavedRegisters() const {
377     return flags() & kCallerSavedRegisters;
378   }
379   bool NeedsCallerSavedFPRegisters() const {
380     return flags() & kCallerSavedFPRegisters;
381   }
382   bool IsTailCallForTierUp() const { return flags() & kIsTailCallForTierUp; }
383   bool NoFunctionDescriptor() const { return flags() & kNoFunctionDescriptor; }
384 
385   LinkageLocation GetReturnLocation(size_t index) const {
386     return location_sig_->GetReturn(index);
387   }
388 
389   LinkageLocation GetInputLocation(size_t index) const {
390     if (index == 0) return target_loc_;
391     return location_sig_->GetParam(index - 1);
392   }
393 
394   MachineSignature* GetMachineSignature(Zone* zone) const;
395 
396   MachineType GetReturnType(size_t index) const {
397     return location_sig_->GetReturn(index).GetType();
398   }
399 
400   MachineType GetInputType(size_t index) const {
401     if (index == 0) return target_type_;
402     return location_sig_->GetParam(index - 1).GetType();
403   }
404 
405   MachineType GetParameterType(size_t index) const {
406     return location_sig_->GetParam(index).GetType();
407   }
408 
409   StackArgumentOrder GetStackArgumentOrder() const { return stack_order_; }
410 
411   // Operator properties describe how this call can be optimized, if at all.
412   Operator::Properties properties() const { return properties_; }
413 
414   // Get the callee-saved registers, if any, across this call.
415   RegList CalleeSavedRegisters() const { return callee_saved_registers_; }
416 
417   // Get the callee-saved FP registers, if any, across this call.
418   DoubleRegList CalleeSavedFPRegisters() const {
419     return callee_saved_fp_registers_;
420   }
421 
422   const char* debug_name() const { return debug_name_; }
423 
424   // Difference between the number of parameter slots of *this* and
425   // *tail_caller* (callee minus caller).
426   int GetStackParameterDelta(const CallDescriptor* tail_caller) const;
427 
428   // Returns the offset to the area below the parameter slots on the stack,
429   // relative to callee slot 0, the return address. If there are no parameter
430   // slots, returns +1.
431   int GetOffsetToFirstUnusedStackSlot() const;
432 
433   // Returns the offset to the area above the return slots on the stack,
434   // relative to callee slot 0, the return address. If there are no return
435   // slots, returns the offset to the lowest slot of the parameter area.
436   // If there are no parameter slots, returns 0.
437   int GetOffsetToReturns() const;
438 
439   // Returns two 16-bit numbers packed together: (first slot << 16) | num_slots.
440   uint32_t GetTaggedParameterSlots() const;
441 
442   bool CanTailCall(const CallDescriptor* callee) const;
443 
444   int CalculateFixedFrameSize(CodeKind code_kind) const;
445 
446   RegList AllocatableRegisters() const { return allocatable_registers_; }
447 
448   bool HasRestrictedAllocatableRegisters() const {
449     return !allocatable_registers_.is_empty();
450   }
451 
452   EncodedCSignature ToEncodedCSignature() const;
453 
454  private:
455   void ComputeParamCounts() const;
456 
457   friend class Linkage;
458 
459   const Kind kind_;
460   const MachineType target_type_;
461   const LinkageLocation target_loc_;
462   const LocationSignature* const location_sig_;
463   const size_t param_slot_count_;
464   const size_t return_slot_count_;
465   const Operator::Properties properties_;
466   const RegList callee_saved_registers_;
467   const DoubleRegList callee_saved_fp_registers_;
468   // Non-zero value means restricting the set of allocatable registers for
469   // register allocator to use.
470   const RegList allocatable_registers_;
471   const Flags flags_;
472   const StackArgumentOrder stack_order_;
473 #if V8_ENABLE_WEBASSEMBLY
474   const wasm::FunctionSig* wasm_sig_;
475 #endif
476   const char* const debug_name_;
477 
478   mutable base::Optional<size_t> gp_param_count_;
479   mutable base::Optional<size_t> fp_param_count_;
480 };
481 
482 DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags)
483 
484 std::ostream& operator<<(std::ostream& os, const CallDescriptor& d);
485 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
486                                            const CallDescriptor::Kind& k);
487 
488 // Defines the linkage for a compilation, including the calling conventions
489 // for incoming parameters and return value(s) as well as the outgoing calling
490 // convention for any kind of call. Linkage is generally architecture-specific.
491 //
492 // Can be used to translate {arg_index} (i.e. index of the call node input) as
493 // well as {param_index} (i.e. as stored in parameter nodes) into an operator
494 // representing the architecture-specific location. The following call node
495 // layouts are supported (where {n} is the number of value inputs):
496 //
497 //                        #0          #1     #2     [...]             #n
498 // Call[CodeStub]         code,       arg 1, arg 2, [...],            context
499 // Call[JSFunction]       function,   rcvr,  arg 1, [...], new, #arg, context
500 // Call[Runtime]          CEntry,     arg 1, arg 2, [...], fun, #arg, context
501 // Call[BytecodeDispatch] address,    arg 1, arg 2, [...]
NON_EXPORTED_BASE(ZoneObject)502 class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) {
503  public:
504   explicit Linkage(CallDescriptor* incoming) : incoming_(incoming) {}
505   Linkage(const Linkage&) = delete;
506   Linkage& operator=(const Linkage&) = delete;
507 
508   static CallDescriptor* ComputeIncoming(Zone* zone,
509                                          OptimizedCompilationInfo* info);
510 
511   // The call descriptor for this compilation unit describes the locations
512   // of incoming parameters and the outgoing return value(s).
513   CallDescriptor* GetIncomingDescriptor() const { return incoming_; }
514   static CallDescriptor* GetJSCallDescriptor(Zone* zone, bool is_osr,
515                                              int parameter_count,
516                                              CallDescriptor::Flags flags);
517 
518   static CallDescriptor* GetRuntimeCallDescriptor(
519       Zone* zone, Runtime::FunctionId function, int js_parameter_count,
520       Operator::Properties properties, CallDescriptor::Flags flags);
521 
522   static CallDescriptor* GetCEntryStubCallDescriptor(
523       Zone* zone, int return_count, int js_parameter_count,
524       const char* debug_name, Operator::Properties properties,
525       CallDescriptor::Flags flags,
526       StackArgumentOrder stack_order = StackArgumentOrder::kDefault);
527 
528   static CallDescriptor* GetStubCallDescriptor(
529       Zone* zone, const CallInterfaceDescriptor& descriptor,
530       int stack_parameter_count, CallDescriptor::Flags flags,
531       Operator::Properties properties = Operator::kNoProperties,
532       StubCallMode stub_mode = StubCallMode::kCallCodeObject);
533 
534   static CallDescriptor* GetBytecodeDispatchCallDescriptor(
535       Zone* zone, const CallInterfaceDescriptor& descriptor,
536       int stack_parameter_count);
537 
538   // Creates a call descriptor for simplified C calls that is appropriate
539   // for the host platform. This simplified calling convention only supports
540   // integers and pointers of one word size each, i.e. no floating point,
541   // structs, pointers to members, etc.
542   static CallDescriptor* GetSimplifiedCDescriptor(
543       Zone* zone, const MachineSignature* sig,
544       CallDescriptor::Flags flags = CallDescriptor::kNoFlags);
545 
546   // Get the location of an (incoming) parameter to this function.
547   LinkageLocation GetParameterLocation(int index) const {
548     return incoming_->GetInputLocation(index + 1);  // + 1 to skip target.
549   }
550 
551   // Get the machine type of an (incoming) parameter to this function.
552   MachineType GetParameterType(int index) const {
553     return incoming_->GetInputType(index + 1);  // + 1 to skip target.
554   }
555 
556   // Get the location where this function should place its return value.
557   LinkageLocation GetReturnLocation(size_t index = 0) const {
558     return incoming_->GetReturnLocation(index);
559   }
560 
561   // Get the machine type of this function's return value.
562   MachineType GetReturnType(size_t index = 0) const {
563     return incoming_->GetReturnType(index);
564   }
565 
566   bool ParameterHasSecondaryLocation(int index) const;
567   LinkageLocation GetParameterSecondaryLocation(int index) const;
568 
569   static bool NeedsFrameStateInput(Runtime::FunctionId function);
570 
571   // Get the location where an incoming OSR value is stored.
572   LinkageLocation GetOsrValueLocation(int index) const;
573 
574   // A special {Parameter} index for Stub Calls that represents context.
575   static int GetStubCallContextParamIndex(int parameter_count) {
576     return parameter_count + 0;  // Parameter (arity + 0) is special.
577   }
578 
579   // A special {Parameter} index for JSCalls that represents the new target.
580   static constexpr int GetJSCallNewTargetParamIndex(int parameter_count) {
581     return parameter_count + 0;  // Parameter (arity + 0) is special.
582   }
583 
584   // A special {Parameter} index for JSCalls that represents the argument count.
585   static constexpr int GetJSCallArgCountParamIndex(int parameter_count) {
586     return parameter_count + 1;  // Parameter (arity + 1) is special.
587   }
588 
589   // A special {Parameter} index for JSCalls that represents the context.
590   static constexpr int GetJSCallContextParamIndex(int parameter_count) {
591     return parameter_count + 2;  // Parameter (arity + 2) is special.
592   }
593 
594   // A special {Parameter} index for JSCalls that represents the closure.
595   static constexpr int kJSCallClosureParamIndex = -1;
596 
597   // A special {OsrValue} index to indicate the context spill slot.
598   static const int kOsrContextSpillSlotIndex = -1;
599 
600   // A special {OsrValue} index to indicate the accumulator register.
601   static const int kOsrAccumulatorRegisterIndex = -1;
602 
603  private:
604   CallDescriptor* const incoming_;
605 };
606 
607 }  // namespace compiler
608 }  // namespace internal
609 }  // namespace v8
610 #undef NO_INLINE_FOR_ARM64_MSVC
611 
612 #endif  // V8_COMPILER_LINKAGE_H_
613