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