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