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