Home | History | Annotate | Download | only in compiler
      1 // Copyright 2015 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/compiler/frame-states.h"
      6 
      7 #include "src/base/functional.h"
      8 #include "src/callable.h"
      9 #include "src/compiler/graph.h"
     10 #include "src/compiler/js-graph.h"
     11 #include "src/compiler/node.h"
     12 #include "src/handles-inl.h"
     13 #include "src/objects-inl.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 namespace compiler {
     18 
     19 size_t hash_value(OutputFrameStateCombine const& sc) {
     20   return base::hash_value(sc.parameter_);
     21 }
     22 
     23 
     24 std::ostream& operator<<(std::ostream& os, OutputFrameStateCombine const& sc) {
     25   if (sc.parameter_ == OutputFrameStateCombine::kInvalidIndex)
     26     return os << "Ignore";
     27   return os << "PokeAt(" << sc.parameter_ << ")";
     28 }
     29 
     30 
     31 bool operator==(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
     32   return lhs.type() == rhs.type() && lhs.bailout_id() == rhs.bailout_id() &&
     33          lhs.state_combine() == rhs.state_combine() &&
     34          lhs.function_info() == rhs.function_info();
     35 }
     36 
     37 
     38 bool operator!=(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
     39   return !(lhs == rhs);
     40 }
     41 
     42 
     43 size_t hash_value(FrameStateInfo const& info) {
     44   return base::hash_combine(static_cast<int>(info.type()), info.bailout_id(),
     45                             info.state_combine());
     46 }
     47 
     48 
     49 std::ostream& operator<<(std::ostream& os, FrameStateType type) {
     50   switch (type) {
     51     case FrameStateType::kInterpretedFunction:
     52       os << "INTERPRETED_FRAME";
     53       break;
     54     case FrameStateType::kArgumentsAdaptor:
     55       os << "ARGUMENTS_ADAPTOR";
     56       break;
     57     case FrameStateType::kConstructStub:
     58       os << "CONSTRUCT_STUB";
     59       break;
     60     case FrameStateType::kBuiltinContinuation:
     61       os << "BUILTIN_CONTINUATION_FRAME";
     62       break;
     63     case FrameStateType::kJavaScriptBuiltinContinuation:
     64       os << "JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME";
     65       break;
     66     case FrameStateType::kJavaScriptBuiltinContinuationWithCatch:
     67       os << "JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME";
     68       break;
     69   }
     70   return os;
     71 }
     72 
     73 
     74 std::ostream& operator<<(std::ostream& os, FrameStateInfo const& info) {
     75   os << info.type() << ", " << info.bailout_id() << ", "
     76      << info.state_combine();
     77   Handle<SharedFunctionInfo> shared_info;
     78   if (info.shared_info().ToHandle(&shared_info)) {
     79     os << ", " << Brief(*shared_info);
     80   }
     81   return os;
     82 }
     83 
     84 namespace {
     85 
     86 // Lazy deopt points where the frame state is assocated with a call get an
     87 // additional parameter for the return result from the call. The return result
     88 // is added by the deoptimizer and not explicitly specified in the frame state.
     89 // Lazy deopt points which can catch exceptions further get an additional
     90 // parameter, namely the exception thrown. The exception is also added by the
     91 // deoptimizer.
     92 uint8_t DeoptimizerParameterCountFor(ContinuationFrameStateMode mode) {
     93   switch (mode) {
     94     case ContinuationFrameStateMode::EAGER:
     95       return 0;
     96     case ContinuationFrameStateMode::LAZY:
     97       return 1;
     98     case ContinuationFrameStateMode::LAZY_WITH_CATCH:
     99       return 2;
    100   }
    101   UNREACHABLE();
    102 }
    103 
    104 Node* CreateBuiltinContinuationFrameStateCommon(
    105     JSGraph* jsgraph, FrameStateType frame_type, Builtins::Name name,
    106     Node* closure, Node* context, Node** parameters, int parameter_count,
    107     Node* outer_frame_state,
    108     Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>()) {
    109   Isolate* const isolate = jsgraph->isolate();
    110   Graph* const graph = jsgraph->graph();
    111   CommonOperatorBuilder* const common = jsgraph->common();
    112 
    113   BailoutId bailout_id = Builtins::GetContinuationBailoutId(name);
    114   Callable callable = Builtins::CallableFor(isolate, name);
    115 
    116   const Operator* op_param =
    117       common->StateValues(parameter_count, SparseInputMask::Dense());
    118   Node* params_node = graph->NewNode(op_param, parameter_count, parameters);
    119 
    120   const FrameStateFunctionInfo* state_info =
    121       common->CreateFrameStateFunctionInfo(frame_type, parameter_count, 0,
    122                                            shared);
    123   const Operator* op = common->FrameState(
    124       bailout_id, OutputFrameStateCombine::Ignore(), state_info);
    125 
    126   Node* frame_state = graph->NewNode(
    127       op, params_node, jsgraph->EmptyStateValues(), jsgraph->EmptyStateValues(),
    128       context, closure, outer_frame_state);
    129 
    130   return frame_state;
    131 }
    132 
    133 }  // namespace
    134 
    135 Node* CreateStubBuiltinContinuationFrameState(
    136     JSGraph* jsgraph, Builtins::Name name, Node* context,
    137     Node* const* parameters, int parameter_count, Node* outer_frame_state,
    138     ContinuationFrameStateMode mode) {
    139   Isolate* isolate = jsgraph->isolate();
    140   Callable callable = Builtins::CallableFor(isolate, name);
    141   CallInterfaceDescriptor descriptor = callable.descriptor();
    142 
    143   std::vector<Node*> actual_parameters;
    144   // Stack parameters first. Depending on {mode}, final parameters are added
    145   // by the deoptimizer and aren't explicitly passed in the frame state.
    146   int stack_parameter_count = descriptor.GetRegisterParameterCount() -
    147                               DeoptimizerParameterCountFor(mode);
    148   for (int i = 0; i < stack_parameter_count; ++i) {
    149     actual_parameters.push_back(
    150         parameters[descriptor.GetRegisterParameterCount() + i]);
    151   }
    152   // Register parameters follow, context will be added by instruction selector
    153   // during FrameState translation.
    154   for (int i = 0; i < descriptor.GetRegisterParameterCount(); ++i) {
    155     actual_parameters.push_back(parameters[i]);
    156   }
    157 
    158   return CreateBuiltinContinuationFrameStateCommon(
    159       jsgraph, FrameStateType::kBuiltinContinuation, name,
    160       jsgraph->UndefinedConstant(), context, actual_parameters.data(),
    161       static_cast<int>(actual_parameters.size()), outer_frame_state);
    162 }
    163 
    164 Node* CreateJavaScriptBuiltinContinuationFrameState(
    165     JSGraph* jsgraph, Handle<SharedFunctionInfo> shared, Builtins::Name name,
    166     Node* target, Node* context, Node* const* stack_parameters,
    167     int stack_parameter_count, Node* outer_frame_state,
    168     ContinuationFrameStateMode mode) {
    169   Isolate* const isolate = jsgraph->isolate();
    170   Callable const callable = Builtins::CallableFor(isolate, name);
    171 
    172   // Depending on {mode}, final parameters are added by the deoptimizer
    173   // and aren't explicitly passed in the frame state.
    174   DCHECK_EQ(Builtins::GetStackParameterCount(name) + 1,  // add receiver
    175             stack_parameter_count + DeoptimizerParameterCountFor(mode));
    176 
    177   Node* argc = jsgraph->Constant(Builtins::GetStackParameterCount(name));
    178 
    179   // Stack parameters first. They must be first because the receiver is expected
    180   // to be the second value in the translation when creating stack crawls
    181   // (e.g. Error.stack) of optimized JavaScript frames.
    182   std::vector<Node*> actual_parameters;
    183   for (int i = 0; i < stack_parameter_count; ++i) {
    184     actual_parameters.push_back(stack_parameters[i]);
    185   }
    186 
    187   // Register parameters follow stack paraemters. The context will be added by
    188   // instruction selector during FrameState translation.
    189   actual_parameters.push_back(target);
    190   actual_parameters.push_back(jsgraph->UndefinedConstant());
    191   actual_parameters.push_back(argc);
    192 
    193   return CreateBuiltinContinuationFrameStateCommon(
    194       jsgraph,
    195       mode == ContinuationFrameStateMode::LAZY_WITH_CATCH
    196           ? FrameStateType::kJavaScriptBuiltinContinuationWithCatch
    197           : FrameStateType::kJavaScriptBuiltinContinuation,
    198       name, target, context, &actual_parameters[0],
    199       static_cast<int>(actual_parameters.size()), outer_frame_state, shared);
    200 }
    201 
    202 }  // namespace compiler
    203 }  // namespace internal
    204 }  // namespace v8
    205