• 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/compiler/frame.h"
11 #include "src/compiler/operator.h"
12 #include "src/globals.h"
13 #include "src/interface-descriptors.h"
14 #include "src/machine-type.h"
15 #include "src/reglist.h"
16 #include "src/runtime/runtime.h"
17 #include "src/signature.h"
18 #include "src/zone/zone.h"
19 
20 namespace v8 {
21 namespace internal {
22 
23 class CallInterfaceDescriptor;
24 class OptimizedCompilationInfo;
25 
26 namespace compiler {
27 
28 const RegList kNoCalleeSaved = 0;
29 
30 class Node;
31 class OsrHelper;
32 
33 // Describes the location for a parameter or a return value to a call.
34 class LinkageLocation {
35  public:
36   bool operator==(const LinkageLocation& other) const {
37     return bit_field_ == other.bit_field_;
38   }
39 
40   bool operator!=(const LinkageLocation& other) const {
41     return !(*this == other);
42   }
43 
44   static LinkageLocation ForAnyRegister(
45       MachineType type = MachineType::None()) {
46     return LinkageLocation(REGISTER, ANY_REGISTER, type);
47   }
48 
49   static LinkageLocation ForRegister(int32_t reg,
50                                      MachineType type = MachineType::None()) {
51     DCHECK_LE(0, reg);
52     return LinkageLocation(REGISTER, reg, type);
53   }
54 
ForCallerFrameSlot(int32_t slot,MachineType type)55   static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) {
56     DCHECK_GT(0, slot);
57     return LinkageLocation(STACK_SLOT, slot, type);
58   }
59 
ForCalleeFrameSlot(int32_t slot,MachineType type)60   static LinkageLocation ForCalleeFrameSlot(int32_t slot, MachineType type) {
61     // TODO(titzer): bailout instead of crashing here.
62     DCHECK(slot >= 0 && slot < LinkageLocation::MAX_STACK_SLOT);
63     return LinkageLocation(STACK_SLOT, slot, type);
64   }
65 
ForSavedCallerReturnAddress()66   static LinkageLocation ForSavedCallerReturnAddress() {
67     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
68                                StandardFrameConstants::kCallerPCOffset) /
69                                   kPointerSize,
70                               MachineType::Pointer());
71   }
72 
ForSavedCallerFramePtr()73   static LinkageLocation ForSavedCallerFramePtr() {
74     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
75                                StandardFrameConstants::kCallerFPOffset) /
76                                   kPointerSize,
77                               MachineType::Pointer());
78   }
79 
ForSavedCallerConstantPool()80   static LinkageLocation ForSavedCallerConstantPool() {
81     DCHECK(V8_EMBEDDED_CONSTANT_POOL);
82     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
83                                StandardFrameConstants::kConstantPoolOffset) /
84                                   kPointerSize,
85                               MachineType::AnyTagged());
86   }
87 
ForSavedCallerFunction()88   static LinkageLocation ForSavedCallerFunction() {
89     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
90                                StandardFrameConstants::kFunctionOffset) /
91                                   kPointerSize,
92                               MachineType::AnyTagged());
93   }
94 
ConvertToTailCallerLocation(LinkageLocation caller_location,int stack_param_delta)95   static LinkageLocation ConvertToTailCallerLocation(
96       LinkageLocation caller_location, int stack_param_delta) {
97     if (!caller_location.IsRegister()) {
98       return LinkageLocation(STACK_SLOT,
99                              caller_location.GetLocation() + stack_param_delta,
100                              caller_location.GetType());
101     }
102     return caller_location;
103   }
104 
GetType()105   MachineType GetType() const { return machine_type_; }
106 
GetSize()107   int GetSize() const {
108     return 1 << ElementSizeLog2Of(GetType().representation());
109   }
110 
GetSizeInPointers()111   int GetSizeInPointers() const {
112     // Round up
113     return (GetSize() + kPointerSize - 1) / kPointerSize;
114   }
115 
GetLocation()116   int32_t GetLocation() const {
117     // We can't use LocationField::decode here because it doesn't work for
118     // negative values!
119     return static_cast<int32_t>(bit_field_ & LocationField::kMask) >>
120            LocationField::kShift;
121   }
122 
IsRegister()123   bool IsRegister() const { return TypeField::decode(bit_field_) == REGISTER; }
IsAnyRegister()124   bool IsAnyRegister() const {
125     return IsRegister() && GetLocation() == ANY_REGISTER;
126   }
IsCallerFrameSlot()127   bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
IsCalleeFrameSlot()128   bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; }
129 
AsRegister()130   int32_t AsRegister() const {
131     DCHECK(IsRegister());
132     return GetLocation();
133   }
AsCallerFrameSlot()134   int32_t AsCallerFrameSlot() const {
135     DCHECK(IsCallerFrameSlot());
136     return GetLocation();
137   }
AsCalleeFrameSlot()138   int32_t AsCalleeFrameSlot() const {
139     DCHECK(IsCalleeFrameSlot());
140     return GetLocation();
141   }
142 
143  private:
144   enum LocationType { REGISTER, STACK_SLOT };
145 
146   class TypeField : public BitField<LocationType, 0, 1> {};
147   class LocationField : public BitField<int32_t, TypeField::kNext, 31> {};
148 
149   static constexpr int32_t ANY_REGISTER = -1;
150   static constexpr int32_t MAX_STACK_SLOT = 32767;
151 
LinkageLocation(LocationType type,int32_t location,MachineType machine_type)152   LinkageLocation(LocationType type, int32_t location,
153                   MachineType machine_type) {
154     bit_field_ = TypeField::encode(type) |
155                  ((location << LocationField::kShift) & LocationField::kMask);
156     machine_type_ = machine_type;
157   }
158 
159   int32_t bit_field_;
160   MachineType machine_type_;
161 };
162 
163 typedef Signature<LinkageLocation> LocationSignature;
164 
165 // Describes a call to various parts of the compiler. Every call has the notion
166 // of a "target", which is the first input to the call.
167 class V8_EXPORT_PRIVATE CallDescriptor final
NON_EXPORTED_BASE(ZoneObject)168     : public NON_EXPORTED_BASE(ZoneObject) {
169  public:
170   // Describes the kind of this call, which determines the target.
171   enum Kind {
172     kCallCodeObject,   // target is a Code object
173     kCallJSFunction,   // target is a JSFunction object
174     kCallAddress,      // target is a machine pointer
175     kCallWasmFunction  // target is a wasm function
176   };
177 
178   enum Flag {
179     kNoFlags = 0u,
180     kNeedsFrameState = 1u << 0,
181     kHasExceptionHandler = 1u << 1,
182     kCanUseRoots = 1u << 2,
183     // Causes the code generator to initialize the root register.
184     kInitializeRootRegister = 1u << 3,
185     // Does not ever try to allocate space on our heap.
186     kNoAllocate = 1u << 4,
187     // Push argument count as part of function prologue.
188     kPushArgumentCount = 1u << 5,
189     // Use retpoline for this call if indirect.
190     kRetpoline = 1u << 6,
191     // Use the kJavaScriptCallCodeStartRegister (fixed) register for the
192     // indirect target address when calling.
193     kFixedTargetRegister = 1u << 7
194   };
195   typedef base::Flags<Flag> Flags;
196 
197   CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc,
198                  LocationSignature* location_sig, size_t stack_param_count,
199                  Operator::Properties properties,
200                  RegList callee_saved_registers,
201                  RegList callee_saved_fp_registers, Flags flags,
202                  const char* debug_name = "",
203                  const RegList allocatable_registers = 0,
204                  size_t stack_return_count = 0)
205       : kind_(kind),
206         target_type_(target_type),
207         target_loc_(target_loc),
208         location_sig_(location_sig),
209         stack_param_count_(stack_param_count),
210         stack_return_count_(stack_return_count),
211         properties_(properties),
212         callee_saved_registers_(callee_saved_registers),
213         callee_saved_fp_registers_(callee_saved_fp_registers),
214         allocatable_registers_(allocatable_registers),
215         flags_(flags),
216         debug_name_(debug_name) {}
217 
218   // Returns the kind of this call.
219   Kind kind() const { return kind_; }
220 
221   // Returns {true} if this descriptor is a call to a C function.
222   bool IsCFunctionCall() const { return kind_ == kCallAddress; }
223 
224   // Returns {true} if this descriptor is a call to a JSFunction.
225   bool IsJSFunctionCall() const { return kind_ == kCallJSFunction; }
226 
227   // Returns {true} if this descriptor is a call to a WebAssembly function.
228   bool IsWasmFunctionCall() const { return kind_ == kCallWasmFunction; }
229 
230   bool RequiresFrameAsIncoming() const {
231     return IsCFunctionCall() || IsJSFunctionCall() || IsWasmFunctionCall();
232   }
233 
234   // The number of return values from this call.
235   size_t ReturnCount() const { return location_sig_->return_count(); }
236 
237   // The number of C parameters to this call.
238   size_t ParameterCount() const { return location_sig_->parameter_count(); }
239 
240   // The number of stack parameters to the call.
241   size_t StackParameterCount() const { return stack_param_count_; }
242 
243   // The number of stack return values from the call.
244   size_t StackReturnCount() const { return stack_return_count_; }
245 
246   // The number of parameters to the JS function call.
247   size_t JSParameterCount() const {
248     DCHECK(IsJSFunctionCall());
249     return stack_param_count_;
250   }
251 
252   // The total number of inputs to this call, which includes the target,
253   // receiver, context, etc.
254   // TODO(titzer): this should input the framestate input too.
255   size_t InputCount() const { return 1 + location_sig_->parameter_count(); }
256 
257   size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
258 
259   Flags flags() const { return flags_; }
260 
261   bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
262   bool PushArgumentCount() const { return flags() & kPushArgumentCount; }
263   bool InitializeRootRegister() const {
264     return flags() & kInitializeRootRegister;
265   }
266 
267   LinkageLocation GetReturnLocation(size_t index) const {
268     return location_sig_->GetReturn(index);
269   }
270 
271   LinkageLocation GetInputLocation(size_t index) const {
272     if (index == 0) return target_loc_;
273     return location_sig_->GetParam(index - 1);
274   }
275 
276   MachineSignature* GetMachineSignature(Zone* zone) const;
277 
278   MachineType GetReturnType(size_t index) const {
279     return location_sig_->GetReturn(index).GetType();
280   }
281 
282   MachineType GetInputType(size_t index) const {
283     if (index == 0) return target_type_;
284     return location_sig_->GetParam(index - 1).GetType();
285   }
286 
287   MachineType GetParameterType(size_t index) const {
288     return location_sig_->GetParam(index).GetType();
289   }
290 
291   // Operator properties describe how this call can be optimized, if at all.
292   Operator::Properties properties() const { return properties_; }
293 
294   // Get the callee-saved registers, if any, across this call.
295   RegList CalleeSavedRegisters() const { return callee_saved_registers_; }
296 
297   // Get the callee-saved FP registers, if any, across this call.
298   RegList CalleeSavedFPRegisters() const { return callee_saved_fp_registers_; }
299 
300   const char* debug_name() const { return debug_name_; }
301 
302   bool UsesOnlyRegisters() const;
303 
304   bool HasSameReturnLocationsAs(const CallDescriptor* other) const;
305 
306   // Returns the first stack slot that is not used by the stack parameters.
307   int GetFirstUnusedStackSlot() const;
308 
309   int GetStackParameterDelta(const CallDescriptor* tail_caller) const;
310 
311   bool CanTailCall(const Node* call) const;
312 
313   int CalculateFixedFrameSize() const;
314 
315   RegList AllocatableRegisters() const { return allocatable_registers_; }
316 
317   bool HasRestrictedAllocatableRegisters() const {
318     return allocatable_registers_ != 0;
319   }
320 
321   void set_save_fp_mode(SaveFPRegsMode mode) { save_fp_mode_ = mode; }
322 
323   SaveFPRegsMode get_save_fp_mode() const { return save_fp_mode_; }
324 
325  private:
326   friend class Linkage;
327   SaveFPRegsMode save_fp_mode_ = kSaveFPRegs;
328 
329   const Kind kind_;
330   const MachineType target_type_;
331   const LinkageLocation target_loc_;
332   const LocationSignature* const location_sig_;
333   const size_t stack_param_count_;
334   const size_t stack_return_count_;
335   const Operator::Properties properties_;
336   const RegList callee_saved_registers_;
337   const RegList callee_saved_fp_registers_;
338   // Non-zero value means restricting the set of allocatable registers for
339   // register allocator to use.
340   const RegList allocatable_registers_;
341   const Flags flags_;
342   const char* const debug_name_;
343 
344   DISALLOW_COPY_AND_ASSIGN(CallDescriptor);
345 };
346 
347 DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags)
348 
349 std::ostream& operator<<(std::ostream& os, const CallDescriptor& d);
350 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
351                                            const CallDescriptor::Kind& k);
352 
353 // Defines the linkage for a compilation, including the calling conventions
354 // for incoming parameters and return value(s) as well as the outgoing calling
355 // convention for any kind of call. Linkage is generally architecture-specific.
356 //
357 // Can be used to translate {arg_index} (i.e. index of the call node input) as
358 // well as {param_index} (i.e. as stored in parameter nodes) into an operator
359 // representing the architecture-specific location. The following call node
360 // layouts are supported (where {n} is the number of value inputs):
361 //
362 //                        #0          #1     #2     [...]             #n
363 // Call[CodeStub]         code,       arg 1, arg 2, [...],            context
364 // Call[JSFunction]       function,   rcvr,  arg 1, [...], new, #arg, context
365 // Call[Runtime]          CEntry,     arg 1, arg 2, [...], fun, #arg, context
366 // Call[BytecodeDispatch] address,    arg 1, arg 2, [...]
NON_EXPORTED_BASE(ZoneObject)367 class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) {
368  public:
369   explicit Linkage(CallDescriptor* incoming) : incoming_(incoming) {}
370 
371   static CallDescriptor* ComputeIncoming(Zone* zone,
372                                          OptimizedCompilationInfo* info);
373 
374   // The call descriptor for this compilation unit describes the locations
375   // of incoming parameters and the outgoing return value(s).
376   CallDescriptor* GetIncomingDescriptor() const { return incoming_; }
377   static CallDescriptor* GetJSCallDescriptor(Zone* zone, bool is_osr,
378                                              int parameter_count,
379                                              CallDescriptor::Flags flags);
380 
381   static CallDescriptor* GetRuntimeCallDescriptor(
382       Zone* zone, Runtime::FunctionId function, int js_parameter_count,
383       Operator::Properties properties, CallDescriptor::Flags flags);
384 
385   static CallDescriptor* GetCEntryStubCallDescriptor(
386       Zone* zone, int return_count, int js_parameter_count,
387       const char* debug_name, Operator::Properties properties,
388       CallDescriptor::Flags flags);
389 
390   static CallDescriptor* GetStubCallDescriptor(
391       Zone* zone, const CallInterfaceDescriptor& descriptor,
392       int stack_parameter_count, CallDescriptor::Flags flags,
393       Operator::Properties properties = Operator::kNoProperties,
394       StubCallMode stub_mode = StubCallMode::kCallOnHeapBuiltin);
395 
396   static CallDescriptor* GetBytecodeDispatchCallDescriptor(
397       Zone* zone, const CallInterfaceDescriptor& descriptor,
398       int stack_parameter_count);
399 
400   // Creates a call descriptor for simplified C calls that is appropriate
401   // for the host platform. This simplified calling convention only supports
402   // integers and pointers of one word size each, i.e. no floating point,
403   // structs, pointers to members, etc.
404   static CallDescriptor* GetSimplifiedCDescriptor(
405       Zone* zone, const MachineSignature* sig,
406       bool set_initialize_root_flag = false);
407 
408   // Get the location of an (incoming) parameter to this function.
409   LinkageLocation GetParameterLocation(int index) const {
410     return incoming_->GetInputLocation(index + 1);  // + 1 to skip target.
411   }
412 
413   // Get the machine type of an (incoming) parameter to this function.
414   MachineType GetParameterType(int index) const {
415     return incoming_->GetInputType(index + 1);  // + 1 to skip target.
416   }
417 
418   // Get the location where this function should place its return value.
419   LinkageLocation GetReturnLocation(size_t index = 0) const {
420     return incoming_->GetReturnLocation(index);
421   }
422 
423   // Get the machine type of this function's return value.
424   MachineType GetReturnType(size_t index = 0) const {
425     return incoming_->GetReturnType(index);
426   }
427 
428   bool ParameterHasSecondaryLocation(int index) const;
429   LinkageLocation GetParameterSecondaryLocation(int index) const;
430 
431   static bool NeedsFrameStateInput(Runtime::FunctionId function);
432 
433   // Get the location where an incoming OSR value is stored.
434   LinkageLocation GetOsrValueLocation(int index) const;
435 
436   // A special {Parameter} index for Stub Calls that represents context.
437   static int GetStubCallContextParamIndex(int parameter_count) {
438     return parameter_count + 0;  // Parameter (arity + 0) is special.
439   }
440 
441   // A special {Parameter} index for JSCalls that represents the new target.
442   static int GetJSCallNewTargetParamIndex(int parameter_count) {
443     return parameter_count + 0;  // Parameter (arity + 0) is special.
444   }
445 
446   // A special {Parameter} index for JSCalls that represents the argument count.
447   static int GetJSCallArgCountParamIndex(int parameter_count) {
448     return parameter_count + 1;  // Parameter (arity + 1) is special.
449   }
450 
451   // A special {Parameter} index for JSCalls that represents the context.
452   static int GetJSCallContextParamIndex(int parameter_count) {
453     return parameter_count + 2;  // Parameter (arity + 2) is special.
454   }
455 
456   // A special {Parameter} index for JSCalls that represents the closure.
457   static const int kJSCallClosureParamIndex = -1;
458 
459   // A special {OsrValue} index to indicate the context spill slot.
460   static const int kOsrContextSpillSlotIndex = -1;
461 
462   // A special {OsrValue} index to indicate the accumulator register.
463   static const int kOsrAccumulatorRegisterIndex = -1;
464 
465  private:
466   CallDescriptor* const incoming_;
467 
468   DISALLOW_COPY_AND_ASSIGN(Linkage);
469 };
470 
471 }  // namespace compiler
472 }  // namespace internal
473 }  // namespace v8
474 
475 #endif  // V8_COMPILER_LINKAGE_H_
476