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