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_IMPL_H_
      6 #define V8_COMPILER_LINKAGE_IMPL_H_
      7 
      8 namespace v8 {
      9 namespace internal {
     10 namespace compiler {
     11 
     12 // TODO(titzer): replace uses of int with size_t in LinkageHelper.
     13 template <typename LinkageTraits>
     14 class LinkageHelper {
     15  public:
     16   static const RegList kNoCalleeSaved = 0;
     17 
     18   static void AddReturnLocations(LocationSignature::Builder* locations) {
     19     DCHECK(locations->return_count_ <= 2);
     20     if (locations->return_count_ > 0) {
     21       locations->AddReturn(regloc(LinkageTraits::ReturnValueReg()));
     22     }
     23     if (locations->return_count_ > 1) {
     24       locations->AddReturn(regloc(LinkageTraits::ReturnValue2Reg()));
     25     }
     26   }
     27 
     28   // TODO(turbofan): cache call descriptors for JSFunction calls.
     29   static CallDescriptor* GetJSCallDescriptor(Zone* zone,
     30                                              int js_parameter_count) {
     31     const size_t return_count = 1;
     32     const size_t context_count = 1;
     33     const size_t parameter_count = js_parameter_count + context_count;
     34 
     35     LocationSignature::Builder locations(zone, return_count, parameter_count);
     36     MachineSignature::Builder types(zone, return_count, parameter_count);
     37 
     38     // Add returns.
     39     AddReturnLocations(&locations);
     40     for (size_t i = 0; i < return_count; i++) {
     41       types.AddReturn(kMachAnyTagged);
     42     }
     43 
     44     // All parameters to JS calls go on the stack.
     45     for (int i = 0; i < js_parameter_count; i++) {
     46       int spill_slot_index = i - js_parameter_count;
     47       locations.AddParam(stackloc(spill_slot_index));
     48       types.AddParam(kMachAnyTagged);
     49     }
     50     // Add context.
     51     locations.AddParam(regloc(LinkageTraits::ContextReg()));
     52     types.AddParam(kMachAnyTagged);
     53 
     54     // The target for JS function calls is the JSFunction object.
     55     MachineType target_type = kMachAnyTagged;
     56     LinkageLocation target_loc = regloc(LinkageTraits::JSCallFunctionReg());
     57     return new (zone) CallDescriptor(CallDescriptor::kCallJSFunction,  // kind
     58                                      target_type,         // target MachineType
     59                                      target_loc,          // target location
     60                                      types.Build(),       // machine_sig
     61                                      locations.Build(),   // location_sig
     62                                      js_parameter_count,  // js_parameter_count
     63                                      Operator::kNoProperties,  // properties
     64                                      kNoCalleeSaved,           // callee-saved
     65                                      CallDescriptor::kNeedsFrameState,  // flags
     66                                      "js-call");
     67   }
     68 
     69 
     70   // TODO(turbofan): cache call descriptors for runtime calls.
     71   static CallDescriptor* GetRuntimeCallDescriptor(
     72       Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
     73       Operator::Properties properties) {
     74     const size_t function_count = 1;
     75     const size_t num_args_count = 1;
     76     const size_t context_count = 1;
     77     const size_t parameter_count = function_count +
     78                                    static_cast<size_t>(js_parameter_count) +
     79                                    num_args_count + context_count;
     80 
     81     const Runtime::Function* function = Runtime::FunctionForId(function_id);
     82     const size_t return_count = static_cast<size_t>(function->result_size);
     83 
     84     LocationSignature::Builder locations(zone, return_count, parameter_count);
     85     MachineSignature::Builder types(zone, return_count, parameter_count);
     86 
     87     // Add returns.
     88     AddReturnLocations(&locations);
     89     for (size_t i = 0; i < return_count; i++) {
     90       types.AddReturn(kMachAnyTagged);
     91     }
     92 
     93     // All parameters to the runtime call go on the stack.
     94     for (int i = 0; i < js_parameter_count; i++) {
     95       locations.AddParam(stackloc(i - js_parameter_count));
     96       types.AddParam(kMachAnyTagged);
     97     }
     98     // Add runtime function itself.
     99     locations.AddParam(regloc(LinkageTraits::RuntimeCallFunctionReg()));
    100     types.AddParam(kMachAnyTagged);
    101 
    102     // Add runtime call argument count.
    103     locations.AddParam(regloc(LinkageTraits::RuntimeCallArgCountReg()));
    104     types.AddParam(kMachPtr);
    105 
    106     // Add context.
    107     locations.AddParam(regloc(LinkageTraits::ContextReg()));
    108     types.AddParam(kMachAnyTagged);
    109 
    110     CallDescriptor::Flags flags = Linkage::NeedsFrameState(function_id)
    111                                       ? CallDescriptor::kNeedsFrameState
    112                                       : CallDescriptor::kNoFlags;
    113 
    114     // The target for runtime calls is a code object.
    115     MachineType target_type = kMachAnyTagged;
    116     LinkageLocation target_loc = LinkageLocation::AnyRegister();
    117     return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
    118                                      target_type,         // target MachineType
    119                                      target_loc,          // target location
    120                                      types.Build(),       // machine_sig
    121                                      locations.Build(),   // location_sig
    122                                      js_parameter_count,  // js_parameter_count
    123                                      properties,          // properties
    124                                      kNoCalleeSaved,      // callee-saved
    125                                      flags,               // flags
    126                                      function->name);     // debug name
    127   }
    128 
    129 
    130   // TODO(turbofan): cache call descriptors for code stub calls.
    131   static CallDescriptor* GetStubCallDescriptor(
    132       Zone* zone, CallInterfaceDescriptor descriptor, int stack_parameter_count,
    133       CallDescriptor::Flags flags) {
    134     const int register_parameter_count =
    135         descriptor.GetEnvironmentParameterCount();
    136     const int js_parameter_count =
    137         register_parameter_count + stack_parameter_count;
    138     const int context_count = 1;
    139     const size_t return_count = 1;
    140     const size_t parameter_count =
    141         static_cast<size_t>(js_parameter_count + context_count);
    142 
    143     LocationSignature::Builder locations(zone, return_count, parameter_count);
    144     MachineSignature::Builder types(zone, return_count, parameter_count);
    145 
    146     // Add return location.
    147     AddReturnLocations(&locations);
    148     types.AddReturn(kMachAnyTagged);
    149 
    150     // Add parameters in registers and on the stack.
    151     for (int i = 0; i < js_parameter_count; i++) {
    152       if (i < register_parameter_count) {
    153         // The first parameters go in registers.
    154         Register reg = descriptor.GetEnvironmentParameterRegister(i);
    155         locations.AddParam(regloc(reg));
    156       } else {
    157         // The rest of the parameters go on the stack.
    158         int stack_slot = i - register_parameter_count - stack_parameter_count;
    159         locations.AddParam(stackloc(stack_slot));
    160       }
    161       types.AddParam(kMachAnyTagged);
    162     }
    163     // Add context.
    164     locations.AddParam(regloc(LinkageTraits::ContextReg()));
    165     types.AddParam(kMachAnyTagged);
    166 
    167     // The target for stub calls is a code object.
    168     MachineType target_type = kMachAnyTagged;
    169     LinkageLocation target_loc = LinkageLocation::AnyRegister();
    170     return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
    171                                      target_type,         // target MachineType
    172                                      target_loc,          // target location
    173                                      types.Build(),       // machine_sig
    174                                      locations.Build(),   // location_sig
    175                                      js_parameter_count,  // js_parameter_count
    176                                      Operator::kNoProperties,  // properties
    177                                      kNoCalleeSaved,  // callee-saved registers
    178                                      flags,           // flags
    179                                      descriptor.DebugName(zone->isolate()));
    180   }
    181 
    182   static CallDescriptor* GetSimplifiedCDescriptor(Zone* zone,
    183                                                   MachineSignature* msig) {
    184     LocationSignature::Builder locations(zone, msig->return_count(),
    185                                          msig->parameter_count());
    186     // Add return location(s).
    187     AddReturnLocations(&locations);
    188 
    189     // Add register and/or stack parameter(s).
    190     const int parameter_count = static_cast<int>(msig->parameter_count());
    191     for (int i = 0; i < parameter_count; i++) {
    192       if (i < LinkageTraits::CRegisterParametersLength()) {
    193         locations.AddParam(regloc(LinkageTraits::CRegisterParameter(i)));
    194       } else {
    195         locations.AddParam(stackloc(-1 - i));
    196       }
    197     }
    198 
    199     // The target for C calls is always an address (i.e. machine pointer).
    200     MachineType target_type = kMachPtr;
    201     LinkageLocation target_loc = LinkageLocation::AnyRegister();
    202     return new (zone) CallDescriptor(CallDescriptor::kCallAddress,  // kind
    203                                      target_type,        // target MachineType
    204                                      target_loc,         // target location
    205                                      msig,               // machine_sig
    206                                      locations.Build(),  // location_sig
    207                                      0,                  // js_parameter_count
    208                                      Operator::kNoProperties,  // properties
    209                                      LinkageTraits::CCalleeSaveRegisters(),
    210                                      CallDescriptor::kNoFlags, "c-call");
    211   }
    212 
    213   static LinkageLocation regloc(Register reg) {
    214     return LinkageLocation(Register::ToAllocationIndex(reg));
    215   }
    216 
    217   static LinkageLocation stackloc(int i) {
    218     DCHECK_LT(i, 0);
    219     return LinkageLocation(i);
    220   }
    221 };
    222 }  // namespace compiler
    223 }  // namespace internal
    224 }  // namespace v8
    225 
    226 #endif  // V8_COMPILER_LINKAGE_IMPL_H_
    227