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