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