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