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/code-stubs.h"
     10 #include "src/compiler/frame.h"
     11 #include "src/compiler/machine-type.h"
     12 #include "src/compiler/node.h"
     13 #include "src/compiler/operator.h"
     14 #include "src/zone.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 namespace compiler {
     19 
     20 // Describes the location for a parameter or a return value to a call.
     21 class LinkageLocation {
     22  public:
     23   explicit LinkageLocation(int location) : location_(location) {}
     24 
     25   static const int16_t ANY_REGISTER = 32767;
     26 
     27   static LinkageLocation AnyRegister() { return LinkageLocation(ANY_REGISTER); }
     28 
     29  private:
     30   friend class CallDescriptor;
     31   friend class OperandGenerator;
     32   int16_t location_;  // >= 0 implies register, otherwise stack slot.
     33 };
     34 
     35 typedef Signature<LinkageLocation> LocationSignature;
     36 
     37 // Describes a call to various parts of the compiler. Every call has the notion
     38 // of a "target", which is the first input to the call.
     39 class CallDescriptor FINAL : public ZoneObject {
     40  public:
     41   // Describes the kind of this call, which determines the target.
     42   enum Kind {
     43     kCallCodeObject,  // target is a Code object
     44     kCallJSFunction,  // target is a JSFunction object
     45     kCallAddress      // target is a machine pointer
     46   };
     47 
     48   enum Flag {
     49     // TODO(jarin) kLazyDeoptimization and kNeedsFrameState should be unified.
     50     kNoFlags = 0u,
     51     kNeedsFrameState = 1u << 0,
     52     kPatchableCallSite = 1u << 1,
     53     kNeedsNopAfterCall = 1u << 2,
     54     kPatchableCallSiteWithNop = kPatchableCallSite | kNeedsNopAfterCall
     55   };
     56   typedef base::Flags<Flag> Flags;
     57 
     58   CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc,
     59                  MachineSignature* machine_sig, LocationSignature* location_sig,
     60                  size_t js_param_count, Operator::Properties properties,
     61                  RegList callee_saved_registers, Flags flags,
     62                  const char* debug_name = "")
     63       : kind_(kind),
     64         target_type_(target_type),
     65         target_loc_(target_loc),
     66         machine_sig_(machine_sig),
     67         location_sig_(location_sig),
     68         js_param_count_(js_param_count),
     69         properties_(properties),
     70         callee_saved_registers_(callee_saved_registers),
     71         flags_(flags),
     72         debug_name_(debug_name) {
     73     DCHECK(machine_sig->return_count() == location_sig->return_count());
     74     DCHECK(machine_sig->parameter_count() == location_sig->parameter_count());
     75   }
     76 
     77   // Returns the kind of this call.
     78   Kind kind() const { return kind_; }
     79 
     80   // Returns {true} if this descriptor is a call to a JSFunction.
     81   bool IsJSFunctionCall() const { return kind_ == kCallJSFunction; }
     82 
     83   // The number of return values from this call.
     84   size_t ReturnCount() const { return machine_sig_->return_count(); }
     85 
     86   // The number of JavaScript parameters to this call, including the receiver
     87   // object.
     88   size_t JSParameterCount() const { return js_param_count_; }
     89 
     90   // The total number of inputs to this call, which includes the target,
     91   // receiver, context, etc.
     92   // TODO(titzer): this should input the framestate input too.
     93   size_t InputCount() const { return 1 + machine_sig_->parameter_count(); }
     94 
     95   size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
     96 
     97   Flags flags() const { return flags_; }
     98 
     99   bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
    100 
    101   LinkageLocation GetReturnLocation(size_t index) const {
    102     return location_sig_->GetReturn(index);
    103   }
    104 
    105   LinkageLocation GetInputLocation(size_t index) const {
    106     if (index == 0) return target_loc_;
    107     return location_sig_->GetParam(index - 1);
    108   }
    109 
    110   const MachineSignature* GetMachineSignature() const { return machine_sig_; }
    111 
    112   MachineType GetReturnType(size_t index) const {
    113     return machine_sig_->GetReturn(index);
    114   }
    115 
    116   MachineType GetInputType(size_t index) const {
    117     if (index == 0) return target_type_;
    118     return machine_sig_->GetParam(index - 1);
    119   }
    120 
    121   // Operator properties describe how this call can be optimized, if at all.
    122   Operator::Properties properties() const { return properties_; }
    123 
    124   // Get the callee-saved registers, if any, across this call.
    125   RegList CalleeSavedRegisters() const { return callee_saved_registers_; }
    126 
    127   const char* debug_name() const { return debug_name_; }
    128 
    129  private:
    130   friend class Linkage;
    131 
    132   Kind kind_;
    133   MachineType target_type_;
    134   LinkageLocation target_loc_;
    135   MachineSignature* machine_sig_;
    136   LocationSignature* location_sig_;
    137   size_t js_param_count_;
    138   Operator::Properties properties_;
    139   RegList callee_saved_registers_;
    140   Flags flags_;
    141   const char* debug_name_;
    142 };
    143 
    144 DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags)
    145 
    146 OStream& operator<<(OStream& os, const CallDescriptor& d);
    147 OStream& operator<<(OStream& os, const CallDescriptor::Kind& k);
    148 
    149 // Defines the linkage for a compilation, including the calling conventions
    150 // for incoming parameters and return value(s) as well as the outgoing calling
    151 // convention for any kind of call. Linkage is generally architecture-specific.
    152 //
    153 // Can be used to translate {arg_index} (i.e. index of the call node input) as
    154 // well as {param_index} (i.e. as stored in parameter nodes) into an operator
    155 // representing the architecture-specific location. The following call node
    156 // layouts are supported (where {n} is the number value inputs):
    157 //
    158 //                  #0          #1     #2     #3     [...]             #n
    159 // Call[CodeStub]   code,       arg 1, arg 2, arg 3, [...],            context
    160 // Call[JSFunction] function,   rcvr,  arg 1, arg 2, [...],            context
    161 // Call[Runtime]    CEntryStub, arg 1, arg 2, arg 3, [...], fun, #arg, context
    162 class Linkage : public ZoneObject {
    163  public:
    164   explicit Linkage(CompilationInfo* info);
    165   explicit Linkage(CompilationInfo* info, CallDescriptor* incoming)
    166       : info_(info), incoming_(incoming) {}
    167 
    168   // The call descriptor for this compilation unit describes the locations
    169   // of incoming parameters and the outgoing return value(s).
    170   CallDescriptor* GetIncomingDescriptor() { return incoming_; }
    171   CallDescriptor* GetJSCallDescriptor(int parameter_count);
    172   static CallDescriptor* GetJSCallDescriptor(int parameter_count, Zone* zone);
    173   CallDescriptor* GetRuntimeCallDescriptor(Runtime::FunctionId function,
    174                                            int parameter_count,
    175                                            Operator::Properties properties);
    176   static CallDescriptor* GetRuntimeCallDescriptor(
    177       Runtime::FunctionId function, int parameter_count,
    178       Operator::Properties properties, Zone* zone);
    179 
    180   CallDescriptor* GetStubCallDescriptor(
    181       CallInterfaceDescriptor descriptor, int stack_parameter_count = 0,
    182       CallDescriptor::Flags flags = CallDescriptor::kNoFlags);
    183   static CallDescriptor* GetStubCallDescriptor(
    184       CallInterfaceDescriptor descriptor, int stack_parameter_count,
    185       CallDescriptor::Flags flags, Zone* zone);
    186 
    187   // Creates a call descriptor for simplified C calls that is appropriate
    188   // for the host platform. This simplified calling convention only supports
    189   // integers and pointers of one word size each, i.e. no floating point,
    190   // structs, pointers to members, etc.
    191   static CallDescriptor* GetSimplifiedCDescriptor(Zone* zone,
    192                                                   MachineSignature* sig);
    193 
    194   // Get the location of an (incoming) parameter to this function.
    195   LinkageLocation GetParameterLocation(int index) {
    196     return incoming_->GetInputLocation(index + 1);  // + 1 to skip target.
    197   }
    198 
    199   // Get the machine type of an (incoming) parameter to this function.
    200   MachineType GetParameterType(int index) {
    201     return incoming_->GetInputType(index + 1);  // + 1 to skip target.
    202   }
    203 
    204   // Get the location where this function should place its return value.
    205   LinkageLocation GetReturnLocation() {
    206     return incoming_->GetReturnLocation(0);
    207   }
    208 
    209   // Get the machine type of this function's return value.
    210   MachineType GetReturnType() { return incoming_->GetReturnType(0); }
    211 
    212   // Get the frame offset for a given spill slot. The location depends on the
    213   // calling convention and the specific frame layout, and may thus be
    214   // architecture-specific. Negative spill slots indicate arguments on the
    215   // caller's frame. The {extra} parameter indicates an additional offset from
    216   // the frame offset, e.g. to index into part of a double slot.
    217   FrameOffset GetFrameOffset(int spill_slot, Frame* frame, int extra = 0);
    218 
    219   CompilationInfo* info() const { return info_; }
    220 
    221   static bool NeedsFrameState(Runtime::FunctionId function);
    222 
    223  private:
    224   CompilationInfo* info_;
    225   CallDescriptor* incoming_;
    226 };
    227 
    228 }  // namespace compiler
    229 }  // namespace internal
    230 }  // namespace v8
    231 
    232 #endif  // V8_COMPILER_LINKAGE_H_
    233