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/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 
     40   static LinkageLocation ForAnyRegister() {
     41     return LinkageLocation(REGISTER, ANY_REGISTER);
     42   }
     43 
     44   static LinkageLocation ForRegister(int32_t reg) {
     45     DCHECK(reg >= 0);
     46     return LinkageLocation(REGISTER, reg);
     47   }
     48 
     49   static LinkageLocation ForCallerFrameSlot(int32_t slot) {
     50     DCHECK(slot < 0);
     51     return LinkageLocation(STACK_SLOT, slot);
     52   }
     53 
     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 
     60   static LinkageLocation ForSavedCallerReturnAddress() {
     61     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
     62                                StandardFrameConstants::kCallerPCOffset) /
     63                               kPointerSize);
     64   }
     65 
     66   static LinkageLocation ForSavedCallerFramePtr() {
     67     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
     68                                StandardFrameConstants::kCallerFPOffset) /
     69                               kPointerSize);
     70   }
     71 
     72   static LinkageLocation ForSavedCallerConstantPool() {
     73     DCHECK(V8_EMBEDDED_CONSTANT_POOL);
     74     return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
     75                                StandardFrameConstants::kConstantPoolOffset) /
     76                               kPointerSize);
     77   }
     78 
     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 
    100   LinkageLocation(LocationType type, int32_t location) {
    101     bit_field_ = TypeField::encode(type) |
    102                  ((location << LocationField::kShift) & LocationField::kMask);
    103   }
    104 
    105   int32_t GetLocation() const {
    106     return static_cast<int32_t>(bit_field_ & LocationField::kMask) >>
    107            LocationField::kShift;
    108   }
    109 
    110   bool IsRegister() const { return TypeField::decode(bit_field_) == REGISTER; }
    111   bool IsAnyRegister() const {
    112     return IsRegister() && GetLocation() == ANY_REGISTER;
    113   }
    114   bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
    115   bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; }
    116 
    117   int32_t AsRegister() const {
    118     DCHECK(IsRegister());
    119     return GetLocation();
    120   }
    121   int32_t AsCallerFrameSlot() const {
    122     DCHECK(IsCallerFrameSlot());
    123     return GetLocation();
    124   }
    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 = "")
    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.
    186   Kind kind() const { return kind_; }
    187 
    188   // Returns {true} if this descriptor is a call to a C function.
    189   bool IsCFunctionCall() const { return kind_ == kCallAddress; }
    190 
    191   // Returns {true} if this descriptor is a call to a JSFunction.
    192   bool IsJSFunctionCall() const { return kind_ == kCallJSFunction; }
    193 
    194   bool RequiresFrameAsIncoming() const {
    195     return IsCFunctionCall() || IsJSFunctionCall();
    196   }
    197 
    198   // The number of return values from this call.
    199   size_t ReturnCount() const { return machine_sig_->return_count(); }
    200 
    201   // The number of C parameters to this call.
    202   size_t CParameterCount() const { return machine_sig_->parameter_count(); }
    203 
    204   // The number of stack parameters to the call.
    205   size_t StackParameterCount() const { return stack_param_count_; }
    206 
    207   // The number of parameters to the JS function call.
    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.
    216   size_t InputCount() const { return 1 + machine_sig_->parameter_count(); }
    217 
    218   size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
    219 
    220   Flags flags() const { return flags_; }
    221 
    222   bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
    223   bool SupportsTailCalls() const { return flags() & kSupportsTailCalls; }
    224   bool UseNativeStack() const { return flags() & kUseNativeStack; }
    225 
    226   LinkageLocation GetReturnLocation(size_t index) const {
    227     return location_sig_->GetReturn(index);
    228   }
    229 
    230   LinkageLocation GetInputLocation(size_t index) const {
    231     if (index == 0) return target_loc_;
    232     return location_sig_->GetParam(index - 1);
    233   }
    234 
    235   const MachineSignature* GetMachineSignature() const { return machine_sig_; }
    236 
    237   MachineType GetReturnType(size_t index) const {
    238     return machine_sig_->GetReturn(index);
    239   }
    240 
    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.
    247   Operator::Properties properties() const { return properties_; }
    248 
    249   // Get the callee-saved registers, if any, across this call.
    250   RegList CalleeSavedRegisters() const { return callee_saved_registers_; }
    251 
    252   // Get the callee-saved FP registers, if any, across this call.
    253   RegList CalleeSavedFPRegisters() const { return callee_saved_fp_registers_; }
    254 
    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:
    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).
    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.
    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.
    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.
    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.
    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.
    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