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 #include "src/ast/scopes.h"
      6 #include "src/code-stubs.h"
      7 #include "src/compiler.h"
      8 #include "src/compiler/common-operator.h"
      9 #include "src/compiler/frame.h"
     10 #include "src/compiler/linkage.h"
     11 #include "src/compiler/node.h"
     12 #include "src/compiler/osr.h"
     13 #include "src/compiler/pipeline.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 namespace compiler {
     18 
     19 namespace {
     20 LinkageLocation regloc(Register reg) {
     21   return LinkageLocation::ForRegister(reg.code());
     22 }
     23 
     24 
     25 MachineType reptyp(Representation representation) {
     26   switch (representation.kind()) {
     27     case Representation::kInteger8:
     28       return MachineType::Int8();
     29     case Representation::kUInteger8:
     30       return MachineType::Uint8();
     31     case Representation::kInteger16:
     32       return MachineType::Int16();
     33     case Representation::kUInteger16:
     34       return MachineType::Uint16();
     35     case Representation::kInteger32:
     36       return MachineType::Int32();
     37     case Representation::kSmi:
     38     case Representation::kTagged:
     39     case Representation::kHeapObject:
     40       return MachineType::AnyTagged();
     41     case Representation::kDouble:
     42       return MachineType::Float64();
     43     case Representation::kExternal:
     44       return MachineType::Pointer();
     45     case Representation::kNone:
     46     case Representation::kNumRepresentations:
     47       break;
     48   }
     49   UNREACHABLE();
     50   return MachineType::None();
     51 }
     52 }  // namespace
     53 
     54 
     55 std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
     56   switch (k) {
     57     case CallDescriptor::kCallCodeObject:
     58       os << "Code";
     59       break;
     60     case CallDescriptor::kCallJSFunction:
     61       os << "JS";
     62       break;
     63     case CallDescriptor::kCallAddress:
     64       os << "Addr";
     65       break;
     66   }
     67   return os;
     68 }
     69 
     70 
     71 std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
     72   // TODO(svenpanne) Output properties etc. and be less cryptic.
     73   return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
     74             << "s" << d.StackParameterCount() << "i" << d.InputCount() << "f"
     75             << d.FrameStateCount() << "t" << d.SupportsTailCalls();
     76 }
     77 
     78 
     79 bool CallDescriptor::HasSameReturnLocationsAs(
     80     const CallDescriptor* other) const {
     81   if (ReturnCount() != other->ReturnCount()) return false;
     82   for (size_t i = 0; i < ReturnCount(); ++i) {
     83     if (GetReturnLocation(i) != other->GetReturnLocation(i)) return false;
     84   }
     85   return true;
     86 }
     87 
     88 
     89 bool CallDescriptor::CanTailCall(const Node* node,
     90                                  int* stack_param_delta) const {
     91   CallDescriptor const* other = CallDescriptorOf(node->op());
     92   size_t current_input = 0;
     93   size_t other_input = 0;
     94   *stack_param_delta = 0;
     95   bool more_other = true;
     96   bool more_this = true;
     97   while (more_other || more_this) {
     98     if (other_input < other->InputCount()) {
     99       if (!other->GetInputLocation(other_input).IsRegister()) {
    100         (*stack_param_delta)--;
    101       }
    102     } else {
    103       more_other = false;
    104     }
    105     if (current_input < InputCount()) {
    106       if (!GetInputLocation(current_input).IsRegister()) {
    107         (*stack_param_delta)++;
    108       }
    109     } else {
    110       more_this = false;
    111     }
    112     ++current_input;
    113     ++other_input;
    114   }
    115   return HasSameReturnLocationsAs(CallDescriptorOf(node->op()));
    116 }
    117 
    118 
    119 CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
    120   DCHECK(!info->IsStub());
    121   if (!info->closure().is_null()) {
    122     // If we are compiling a JS function, use a JS call descriptor,
    123     // plus the receiver.
    124     SharedFunctionInfo* shared = info->closure()->shared();
    125     return GetJSCallDescriptor(zone, info->is_osr(),
    126                                1 + shared->internal_formal_parameter_count(),
    127                                CallDescriptor::kNoFlags);
    128   }
    129   return nullptr;  // TODO(titzer): ?
    130 }
    131 
    132 
    133 // static
    134 bool Linkage::NeedsFrameStateInput(Runtime::FunctionId function) {
    135   // Most runtime functions need a FrameState. A few chosen ones that we know
    136   // not to call into arbitrary JavaScript, not to throw, and not to deoptimize
    137   // are blacklisted here and can be called without a FrameState.
    138   switch (function) {
    139     case Runtime::kAbort:
    140     case Runtime::kAllocateInTargetSpace:
    141     case Runtime::kCreateIterResultObject:
    142     case Runtime::kDefineGetterPropertyUnchecked:  // TODO(jarin): Is it safe?
    143     case Runtime::kDefineSetterPropertyUnchecked:  // TODO(jarin): Is it safe?
    144     case Runtime::kForInDone:
    145     case Runtime::kForInStep:
    146     case Runtime::kGeneratorGetContinuation:
    147     case Runtime::kGetSuperConstructor:
    148     case Runtime::kIsFunction:
    149     case Runtime::kNewClosure:
    150     case Runtime::kNewClosure_Tenured:
    151     case Runtime::kNewFunctionContext:
    152     case Runtime::kPushBlockContext:
    153     case Runtime::kPushCatchContext:
    154     case Runtime::kReThrow:
    155     case Runtime::kStringCompare:
    156     case Runtime::kStringEqual:
    157     case Runtime::kStringNotEqual:
    158     case Runtime::kStringLessThan:
    159     case Runtime::kStringLessThanOrEqual:
    160     case Runtime::kStringGreaterThan:
    161     case Runtime::kStringGreaterThanOrEqual:
    162     case Runtime::kToFastProperties:  // TODO(conradw): Is it safe?
    163     case Runtime::kTraceEnter:
    164     case Runtime::kTraceExit:
    165       return false;
    166     case Runtime::kInlineCall:
    167     case Runtime::kInlineDeoptimizeNow:
    168     case Runtime::kInlineGetPrototype:
    169     case Runtime::kInlineNewObject:
    170     case Runtime::kInlineRegExpConstructResult:
    171     case Runtime::kInlineRegExpExec:
    172     case Runtime::kInlineSubString:
    173     case Runtime::kInlineThrowNotDateError:
    174     case Runtime::kInlineToInteger:
    175     case Runtime::kInlineToLength:
    176     case Runtime::kInlineToName:
    177     case Runtime::kInlineToNumber:
    178     case Runtime::kInlineToObject:
    179     case Runtime::kInlineToPrimitive:
    180     case Runtime::kInlineToPrimitive_Number:
    181     case Runtime::kInlineToPrimitive_String:
    182     case Runtime::kInlineToString:
    183       return true;
    184     default:
    185       break;
    186   }
    187 
    188   // Most inlined runtime functions (except the ones listed above) can be called
    189   // without a FrameState or will be lowered by JSIntrinsicLowering internally.
    190   const Runtime::Function* const f = Runtime::FunctionForId(function);
    191   if (f->intrinsic_type == Runtime::IntrinsicType::INLINE) return false;
    192 
    193   return true;
    194 }
    195 
    196 
    197 bool CallDescriptor::UsesOnlyRegisters() const {
    198   for (size_t i = 0; i < InputCount(); ++i) {
    199     if (!GetInputLocation(i).IsRegister()) return false;
    200   }
    201   for (size_t i = 0; i < ReturnCount(); ++i) {
    202     if (!GetReturnLocation(i).IsRegister()) return false;
    203   }
    204   return true;
    205 }
    206 
    207 
    208 CallDescriptor* Linkage::GetRuntimeCallDescriptor(
    209     Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
    210     Operator::Properties properties, CallDescriptor::Flags flags) {
    211   const size_t function_count = 1;
    212   const size_t num_args_count = 1;
    213   const size_t context_count = 1;
    214   const size_t parameter_count = function_count +
    215                                  static_cast<size_t>(js_parameter_count) +
    216                                  num_args_count + context_count;
    217 
    218   const Runtime::Function* function = Runtime::FunctionForId(function_id);
    219   const size_t return_count = static_cast<size_t>(function->result_size);
    220 
    221   LocationSignature::Builder locations(zone, return_count, parameter_count);
    222   MachineSignature::Builder types(zone, return_count, parameter_count);
    223 
    224   // Add returns.
    225   if (locations.return_count_ > 0) {
    226     locations.AddReturn(regloc(kReturnRegister0));
    227   }
    228   if (locations.return_count_ > 1) {
    229     locations.AddReturn(regloc(kReturnRegister1));
    230   }
    231   if (locations.return_count_ > 2) {
    232     locations.AddReturn(regloc(kReturnRegister2));
    233   }
    234   for (size_t i = 0; i < return_count; i++) {
    235     types.AddReturn(MachineType::AnyTagged());
    236   }
    237 
    238   // All parameters to the runtime call go on the stack.
    239   for (int i = 0; i < js_parameter_count; i++) {
    240     locations.AddParam(
    241         LinkageLocation::ForCallerFrameSlot(i - js_parameter_count));
    242     types.AddParam(MachineType::AnyTagged());
    243   }
    244   // Add runtime function itself.
    245   locations.AddParam(regloc(kRuntimeCallFunctionRegister));
    246   types.AddParam(MachineType::AnyTagged());
    247 
    248   // Add runtime call argument count.
    249   locations.AddParam(regloc(kRuntimeCallArgCountRegister));
    250   types.AddParam(MachineType::Pointer());
    251 
    252   // Add context.
    253   locations.AddParam(regloc(kContextRegister));
    254   types.AddParam(MachineType::AnyTagged());
    255 
    256   if (!Linkage::NeedsFrameStateInput(function_id)) {
    257     flags = static_cast<CallDescriptor::Flags>(
    258         flags & ~CallDescriptor::kNeedsFrameState);
    259   }
    260 
    261   // The target for runtime calls is a code object.
    262   MachineType target_type = MachineType::AnyTagged();
    263   LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
    264   return new (zone) CallDescriptor(     // --
    265       CallDescriptor::kCallCodeObject,  // kind
    266       target_type,                      // target MachineType
    267       target_loc,                       // target location
    268       types.Build(),                    // machine_sig
    269       locations.Build(),                // location_sig
    270       js_parameter_count,               // stack_parameter_count
    271       properties,                       // properties
    272       kNoCalleeSaved,                   // callee-saved
    273       kNoCalleeSaved,                   // callee-saved fp
    274       flags,                            // flags
    275       function->name);                  // debug name
    276 }
    277 
    278 
    279 CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr,
    280                                              int js_parameter_count,
    281                                              CallDescriptor::Flags flags) {
    282   const size_t return_count = 1;
    283   const size_t context_count = 1;
    284   const size_t new_target_count = 1;
    285   const size_t num_args_count = 1;
    286   const size_t parameter_count =
    287       js_parameter_count + new_target_count + num_args_count + context_count;
    288 
    289   LocationSignature::Builder locations(zone, return_count, parameter_count);
    290   MachineSignature::Builder types(zone, return_count, parameter_count);
    291 
    292   // All JS calls have exactly one return value.
    293   locations.AddReturn(regloc(kReturnRegister0));
    294   types.AddReturn(MachineType::AnyTagged());
    295 
    296   // All parameters to JS calls go on the stack.
    297   for (int i = 0; i < js_parameter_count; i++) {
    298     int spill_slot_index = i - js_parameter_count;
    299     locations.AddParam(LinkageLocation::ForCallerFrameSlot(spill_slot_index));
    300     types.AddParam(MachineType::AnyTagged());
    301   }
    302 
    303   // Add JavaScript call new target value.
    304   locations.AddParam(regloc(kJavaScriptCallNewTargetRegister));
    305   types.AddParam(MachineType::AnyTagged());
    306 
    307   // Add JavaScript call argument count.
    308   locations.AddParam(regloc(kJavaScriptCallArgCountRegister));
    309   types.AddParam(MachineType::Int32());
    310 
    311   // Add context.
    312   locations.AddParam(regloc(kContextRegister));
    313   types.AddParam(MachineType::AnyTagged());
    314 
    315   // The target for JS function calls is the JSFunction object.
    316   MachineType target_type = MachineType::AnyTagged();
    317   // When entering into an OSR function from unoptimized code the JSFunction
    318   // is not in a register, but it is on the stack in the marker spill slot.
    319   LinkageLocation target_loc = is_osr
    320                                    ? LinkageLocation::ForSavedCallerFunction()
    321                                    : regloc(kJSFunctionRegister);
    322   return new (zone) CallDescriptor(     // --
    323       CallDescriptor::kCallJSFunction,  // kind
    324       target_type,                      // target MachineType
    325       target_loc,                       // target location
    326       types.Build(),                    // machine_sig
    327       locations.Build(),                // location_sig
    328       js_parameter_count,               // stack_parameter_count
    329       Operator::kNoProperties,          // properties
    330       kNoCalleeSaved,                   // callee-saved
    331       kNoCalleeSaved,                   // callee-saved fp
    332       CallDescriptor::kCanUseRoots |    // flags
    333           flags,                        // flags
    334       "js-call");
    335 }
    336 
    337 // TODO(all): Add support for return representations/locations to
    338 // CallInterfaceDescriptor.
    339 // TODO(turbofan): cache call descriptors for code stub calls.
    340 CallDescriptor* Linkage::GetStubCallDescriptor(
    341     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
    342     int stack_parameter_count, CallDescriptor::Flags flags,
    343     Operator::Properties properties, MachineType return_type,
    344     size_t return_count) {
    345   const int register_parameter_count = descriptor.GetRegisterParameterCount();
    346   const int js_parameter_count =
    347       register_parameter_count + stack_parameter_count;
    348   const int context_count = 1;
    349   const size_t parameter_count =
    350       static_cast<size_t>(js_parameter_count + context_count);
    351 
    352   LocationSignature::Builder locations(zone, return_count, parameter_count);
    353   MachineSignature::Builder types(zone, return_count, parameter_count);
    354 
    355   // Add returns.
    356   if (locations.return_count_ > 0) {
    357     locations.AddReturn(regloc(kReturnRegister0));
    358   }
    359   if (locations.return_count_ > 1) {
    360     locations.AddReturn(regloc(kReturnRegister1));
    361   }
    362   if (locations.return_count_ > 2) {
    363     locations.AddReturn(regloc(kReturnRegister2));
    364   }
    365   for (size_t i = 0; i < return_count; i++) {
    366     types.AddReturn(return_type);
    367   }
    368 
    369   // Add parameters in registers and on the stack.
    370   for (int i = 0; i < js_parameter_count; i++) {
    371     if (i < register_parameter_count) {
    372       // The first parameters go in registers.
    373       Register reg = descriptor.GetRegisterParameter(i);
    374       Representation rep =
    375           RepresentationFromType(descriptor.GetParameterType(i));
    376       locations.AddParam(regloc(reg));
    377       types.AddParam(reptyp(rep));
    378     } else {
    379       // The rest of the parameters go on the stack.
    380       int stack_slot = i - register_parameter_count - stack_parameter_count;
    381       locations.AddParam(LinkageLocation::ForCallerFrameSlot(stack_slot));
    382       types.AddParam(MachineType::AnyTagged());
    383     }
    384   }
    385   // Add context.
    386   locations.AddParam(regloc(kContextRegister));
    387   types.AddParam(MachineType::AnyTagged());
    388 
    389   // The target for stub calls is a code object.
    390   MachineType target_type = MachineType::AnyTagged();
    391   LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
    392   return new (zone) CallDescriptor(     // --
    393       CallDescriptor::kCallCodeObject,  // kind
    394       target_type,                      // target MachineType
    395       target_loc,                       // target location
    396       types.Build(),                    // machine_sig
    397       locations.Build(),                // location_sig
    398       stack_parameter_count,            // stack_parameter_count
    399       properties,                       // properties
    400       kNoCalleeSaved,                   // callee-saved registers
    401       kNoCalleeSaved,                   // callee-saved fp
    402       CallDescriptor::kCanUseRoots |    // flags
    403           flags,                        // flags
    404       descriptor.DebugName(isolate));
    405 }
    406 
    407 // static
    408 CallDescriptor* Linkage::GetAllocateCallDescriptor(Zone* zone) {
    409   LocationSignature::Builder locations(zone, 1, 1);
    410   MachineSignature::Builder types(zone, 1, 1);
    411 
    412   locations.AddParam(regloc(kAllocateSizeRegister));
    413   types.AddParam(MachineType::Int32());
    414 
    415   locations.AddReturn(regloc(kReturnRegister0));
    416   types.AddReturn(MachineType::AnyTagged());
    417 
    418   // The target for allocate calls is a code object.
    419   MachineType target_type = MachineType::AnyTagged();
    420   LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
    421   return new (zone) CallDescriptor(     // --
    422       CallDescriptor::kCallCodeObject,  // kind
    423       target_type,                      // target MachineType
    424       target_loc,                       // target location
    425       types.Build(),                    // machine_sig
    426       locations.Build(),                // location_sig
    427       0,                                // stack_parameter_count
    428       Operator::kNoThrow,               // properties
    429       kNoCalleeSaved,                   // callee-saved registers
    430       kNoCalleeSaved,                   // callee-saved fp
    431       CallDescriptor::kCanUseRoots,     // flags
    432       "Allocate");
    433 }
    434 
    435 // static
    436 CallDescriptor* Linkage::GetBytecodeDispatchCallDescriptor(
    437     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
    438     int stack_parameter_count) {
    439   const int register_parameter_count = descriptor.GetRegisterParameterCount();
    440   const int parameter_count = register_parameter_count + stack_parameter_count;
    441 
    442   LocationSignature::Builder locations(zone, 0, parameter_count);
    443   MachineSignature::Builder types(zone, 0, parameter_count);
    444 
    445   // Add parameters in registers and on the stack.
    446   for (int i = 0; i < parameter_count; i++) {
    447     if (i < register_parameter_count) {
    448       // The first parameters go in registers.
    449       Register reg = descriptor.GetRegisterParameter(i);
    450       Representation rep =
    451           RepresentationFromType(descriptor.GetParameterType(i));
    452       locations.AddParam(regloc(reg));
    453       types.AddParam(reptyp(rep));
    454     } else {
    455       // The rest of the parameters go on the stack.
    456       int stack_slot = i - register_parameter_count - stack_parameter_count;
    457       locations.AddParam(LinkageLocation::ForCallerFrameSlot(stack_slot));
    458       types.AddParam(MachineType::AnyTagged());
    459     }
    460   }
    461 
    462   // The target for interpreter dispatches is a code entry address.
    463   MachineType target_type = MachineType::Pointer();
    464   LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
    465   return new (zone) CallDescriptor(            // --
    466       CallDescriptor::kCallAddress,            // kind
    467       target_type,                             // target MachineType
    468       target_loc,                              // target location
    469       types.Build(),                           // machine_sig
    470       locations.Build(),                       // location_sig
    471       stack_parameter_count,                   // stack_parameter_count
    472       Operator::kNoProperties,                 // properties
    473       kNoCalleeSaved,                          // callee-saved registers
    474       kNoCalleeSaved,                          // callee-saved fp
    475       CallDescriptor::kCanUseRoots |           // flags
    476           CallDescriptor::kSupportsTailCalls,  // flags
    477       descriptor.DebugName(isolate));
    478 }
    479 
    480 LinkageLocation Linkage::GetOsrValueLocation(int index) const {
    481   CHECK(incoming_->IsJSFunctionCall());
    482   int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1);
    483   int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count);
    484 
    485   if (index == kOsrContextSpillSlotIndex) {
    486     // Context. Use the parameter location of the context spill slot.
    487     // Parameter (arity + 2) is special for the context of the function frame.
    488     // >> context_index = target + receiver + params + new_target + #args
    489     int context_index = 1 + 1 + parameter_count + 1 + 1;
    490     return incoming_->GetInputLocation(context_index);
    491   } else if (index >= first_stack_slot) {
    492     // Local variable stored in this (callee) stack.
    493     int spill_index =
    494         index - first_stack_slot + StandardFrameConstants::kFixedSlotCount;
    495     return LinkageLocation::ForCalleeFrameSlot(spill_index);
    496   } else {
    497     // Parameter. Use the assigned location from the incoming call descriptor.
    498     int parameter_index = 1 + index;  // skip index 0, which is the target.
    499     return incoming_->GetInputLocation(parameter_index);
    500   }
    501 }
    502 
    503 
    504 bool Linkage::ParameterHasSecondaryLocation(int index) const {
    505   if (!incoming_->IsJSFunctionCall()) return false;
    506   LinkageLocation loc = GetParameterLocation(index);
    507   return (loc == regloc(kJSFunctionRegister) ||
    508           loc == regloc(kContextRegister));
    509 }
    510 
    511 LinkageLocation Linkage::GetParameterSecondaryLocation(int index) const {
    512   DCHECK(ParameterHasSecondaryLocation(index));
    513   LinkageLocation loc = GetParameterLocation(index);
    514 
    515   if (loc == regloc(kJSFunctionRegister)) {
    516     return LinkageLocation::ForCalleeFrameSlot(Frame::kJSFunctionSlot);
    517   } else {
    518     DCHECK(loc == regloc(kContextRegister));
    519     return LinkageLocation::ForCalleeFrameSlot(Frame::kContextSlot);
    520   }
    521 }
    522 
    523 
    524 }  // namespace compiler
    525 }  // namespace internal
    526 }  // namespace v8
    527