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