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