• 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-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