Home | History | Annotate | Download | only in compiler
      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 
     55   static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) {
     56     DCHECK_GT(0, slot);
     57     return LinkageLocation(STACK_SLOT, slot, type);
     58   }
     59 
     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 
     66   static LinkageLocation ForSavedCallerReturnAddress() {
     67     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
     68                                StandardFrameConstants::kCallerPCOffset) /
     69                                   kPointerSize,
     70                               MachineType::Pointer());
     71   }
     72 
     73   static LinkageLocation ForSavedCallerFramePtr() {
     74     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
     75                                StandardFrameConstants::kCallerFPOffset) /
     76                                   kPointerSize,
     77                               MachineType::Pointer());
     78   }
     79 
     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 
     88   static LinkageLocation ForSavedCallerFunction() {
     89     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
     90                                StandardFrameConstants::kFunctionOffset) /
     91                                   kPointerSize,
     92                               MachineType::AnyTagged());
     93   }
     94 
     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 
    105   MachineType GetType() const { return machine_type_; }
    106 
    107   int GetSize() const {
    108     return 1 << ElementSizeLog2Of(GetType().representation());
    109   }
    110 
    111   int GetSizeInPointers() const {
    112     // Round up
    113     return (GetSize() + kPointerSize - 1) / kPointerSize;
    114   }
    115 
    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 
    123   bool IsRegister() const { return TypeField::decode(bit_field_) == REGISTER; }
    124   bool IsAnyRegister() const {
    125     return IsRegister() && GetLocation() == ANY_REGISTER;
    126   }
    127   bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
    128   bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; }
    129 
    130   int32_t AsRegister() const {
    131     DCHECK(IsRegister());
    132     return GetLocation();
    133   }
    134   int32_t AsCallerFrameSlot() const {
    135     DCHECK(IsCallerFrameSlot());
    136     return GetLocation();
    137   }
    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 
    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
    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, [...]
    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