• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/codegen/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/handles-inl.h"
13 #include "src/objects/objects-inl.h"
14 
15 #if V8_ENABLE_WEBASSEMBLY
16 #include "src/wasm/value-type.h"
17 #endif  // V8_ENABLE_WEBASSEMBLY
18 
19 namespace v8 {
20 namespace internal {
21 namespace compiler {
22 
hash_value(OutputFrameStateCombine const & sc)23 size_t hash_value(OutputFrameStateCombine const& sc) {
24   return base::hash_value(sc.parameter_);
25 }
26 
27 
operator <<(std::ostream & os,OutputFrameStateCombine const & sc)28 std::ostream& operator<<(std::ostream& os, OutputFrameStateCombine const& sc) {
29   if (sc.parameter_ == OutputFrameStateCombine::kInvalidIndex)
30     return os << "Ignore";
31   return os << "PokeAt(" << sc.parameter_ << ")";
32 }
33 
34 
operator ==(FrameStateInfo const & lhs,FrameStateInfo const & rhs)35 bool operator==(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
36   return lhs.type() == rhs.type() && lhs.bailout_id() == rhs.bailout_id() &&
37          lhs.state_combine() == rhs.state_combine() &&
38          lhs.function_info() == rhs.function_info();
39 }
40 
41 
operator !=(FrameStateInfo const & lhs,FrameStateInfo const & rhs)42 bool operator!=(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
43   return !(lhs == rhs);
44 }
45 
46 
hash_value(FrameStateInfo const & info)47 size_t hash_value(FrameStateInfo const& info) {
48   return base::hash_combine(static_cast<int>(info.type()), info.bailout_id(),
49                             info.state_combine());
50 }
51 
52 
operator <<(std::ostream & os,FrameStateType type)53 std::ostream& operator<<(std::ostream& os, FrameStateType type) {
54   switch (type) {
55     case FrameStateType::kUnoptimizedFunction:
56       os << "UNOPTIMIZED_FRAME";
57       break;
58     case FrameStateType::kArgumentsAdaptor:
59       os << "ARGUMENTS_ADAPTOR";
60       break;
61     case FrameStateType::kConstructStub:
62       os << "CONSTRUCT_STUB";
63       break;
64     case FrameStateType::kBuiltinContinuation:
65       os << "BUILTIN_CONTINUATION_FRAME";
66       break;
67 #if V8_ENABLE_WEBASSEMBLY
68     case FrameStateType::kJSToWasmBuiltinContinuation:
69       os << "JS_TO_WASM_BUILTIN_CONTINUATION_FRAME";
70       break;
71 #endif  // V8_ENABLE_WEBASSEMBLY
72     case FrameStateType::kJavaScriptBuiltinContinuation:
73       os << "JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME";
74       break;
75     case FrameStateType::kJavaScriptBuiltinContinuationWithCatch:
76       os << "JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME";
77       break;
78   }
79   return os;
80 }
81 
82 
operator <<(std::ostream & os,FrameStateInfo const & info)83 std::ostream& operator<<(std::ostream& os, FrameStateInfo const& info) {
84   os << info.type() << ", " << info.bailout_id() << ", "
85      << info.state_combine();
86   Handle<SharedFunctionInfo> shared_info;
87   if (info.shared_info().ToHandle(&shared_info)) {
88     os << ", " << Brief(*shared_info);
89   }
90   return os;
91 }
92 
93 namespace {
94 
95 // Lazy deopt points where the frame state is associated with a call get an
96 // additional parameter for the return result from the call. The return result
97 // is added by the deoptimizer and not explicitly specified in the frame state.
98 // Lazy deopt points which can catch exceptions further get an additional
99 // parameter, namely the exception thrown. The exception is also added by the
100 // deoptimizer.
DeoptimizerParameterCountFor(ContinuationFrameStateMode mode)101 uint8_t DeoptimizerParameterCountFor(ContinuationFrameStateMode mode) {
102   switch (mode) {
103     case ContinuationFrameStateMode::EAGER:
104       return 0;
105     case ContinuationFrameStateMode::LAZY:
106       return 1;
107     case ContinuationFrameStateMode::LAZY_WITH_CATCH:
108       return 2;
109   }
110   UNREACHABLE();
111 }
112 
CreateBuiltinContinuationFrameStateCommon(JSGraph * jsgraph,FrameStateType frame_type,Builtin name,Node * closure,Node * context,Node ** parameters,int parameter_count,Node * outer_frame_state,Handle<SharedFunctionInfo> shared=Handle<SharedFunctionInfo> (),const wasm::FunctionSig * signature=nullptr)113 FrameState CreateBuiltinContinuationFrameStateCommon(
114     JSGraph* jsgraph, FrameStateType frame_type, Builtin name, Node* closure,
115     Node* context, Node** parameters, int parameter_count,
116     Node* outer_frame_state,
117     Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(),
118     const wasm::FunctionSig* signature = nullptr) {
119   Graph* const graph = jsgraph->graph();
120   CommonOperatorBuilder* const common = jsgraph->common();
121 
122   const Operator* op_param =
123       common->StateValues(parameter_count, SparseInputMask::Dense());
124   Node* params_node = graph->NewNode(op_param, parameter_count, parameters);
125 
126   BytecodeOffset bailout_id = Builtins::GetContinuationBytecodeOffset(name);
127 #if V8_ENABLE_WEBASSEMBLY
128   const FrameStateFunctionInfo* state_info =
129       signature ? common->CreateJSToWasmFrameStateFunctionInfo(
130                       frame_type, parameter_count, 0, shared, signature)
131                 : common->CreateFrameStateFunctionInfo(
132                       frame_type, parameter_count, 0, shared);
133 #else
134   DCHECK_NULL(signature);
135   const FrameStateFunctionInfo* state_info =
136       common->CreateFrameStateFunctionInfo(frame_type, parameter_count, 0,
137                                            shared);
138 #endif  // V8_ENABLE_WEBASSEMBLY
139 
140   const Operator* op = common->FrameState(
141       bailout_id, OutputFrameStateCombine::Ignore(), state_info);
142   return FrameState(graph->NewNode(op, params_node, jsgraph->EmptyStateValues(),
143                                    jsgraph->EmptyStateValues(), context,
144                                    closure, outer_frame_state));
145 }
146 
147 }  // namespace
148 
CreateStubBuiltinContinuationFrameState(JSGraph * jsgraph,Builtin name,Node * context,Node * const * parameters,int parameter_count,Node * outer_frame_state,ContinuationFrameStateMode mode,const wasm::FunctionSig * signature)149 FrameState CreateStubBuiltinContinuationFrameState(
150     JSGraph* jsgraph, Builtin name, Node* context, Node* const* parameters,
151     int parameter_count, Node* outer_frame_state,
152     ContinuationFrameStateMode mode, const wasm::FunctionSig* signature) {
153   Callable callable = Builtins::CallableFor(jsgraph->isolate(), name);
154   CallInterfaceDescriptor descriptor = callable.descriptor();
155 
156   std::vector<Node*> actual_parameters;
157   // Stack parameters first. Depending on {mode}, final parameters are added
158   // by the deoptimizer and aren't explicitly passed in the frame state.
159   int stack_parameter_count =
160       descriptor.GetStackParameterCount() - DeoptimizerParameterCountFor(mode);
161 
162   // Ensure the parameters added by the deoptimizer are passed on the stack.
163   // This check prevents using TFS builtins as continuations while doing the
164   // lazy deopt. Use TFC or TFJ builtin as a lazy deopt continuation which
165   // would pass the result parameter on the stack.
166   DCHECK_GE(stack_parameter_count, 0);
167 
168   // Reserving space in the vector.
169   actual_parameters.reserve(stack_parameter_count +
170                             descriptor.GetRegisterParameterCount());
171   for (int i = 0; i < stack_parameter_count; ++i) {
172     actual_parameters.push_back(
173         parameters[descriptor.GetRegisterParameterCount() + i]);
174   }
175   // Register parameters follow, context will be added by instruction selector
176   // during FrameState translation.
177   for (int i = 0; i < descriptor.GetRegisterParameterCount(); ++i) {
178     actual_parameters.push_back(parameters[i]);
179   }
180 
181   FrameStateType frame_state_type = FrameStateType::kBuiltinContinuation;
182 #if V8_ENABLE_WEBASSEMBLY
183   if (name == Builtin::kJSToWasmLazyDeoptContinuation) {
184     CHECK_NOT_NULL(signature);
185     frame_state_type = FrameStateType::kJSToWasmBuiltinContinuation;
186   }
187 #endif  // V8_ENABLE_WEBASSEMBLY
188   return CreateBuiltinContinuationFrameStateCommon(
189       jsgraph, frame_state_type, name, jsgraph->UndefinedConstant(), context,
190       actual_parameters.data(), static_cast<int>(actual_parameters.size()),
191       outer_frame_state, Handle<SharedFunctionInfo>(), signature);
192 }
193 
194 #if V8_ENABLE_WEBASSEMBLY
CreateJSWasmCallBuiltinContinuationFrameState(JSGraph * jsgraph,Node * context,Node * outer_frame_state,const wasm::FunctionSig * signature)195 FrameState CreateJSWasmCallBuiltinContinuationFrameState(
196     JSGraph* jsgraph, Node* context, Node* outer_frame_state,
197     const wasm::FunctionSig* signature) {
198   base::Optional<wasm::ValueKind> wasm_return_kind =
199       wasm::WasmReturnTypeFromSignature(signature);
200   Node* node_return_type =
201       jsgraph->SmiConstant(wasm_return_kind ? wasm_return_kind.value() : -1);
202   Node* lazy_deopt_parameters[] = {node_return_type};
203   return CreateStubBuiltinContinuationFrameState(
204       jsgraph, Builtin::kJSToWasmLazyDeoptContinuation, context,
205       lazy_deopt_parameters, arraysize(lazy_deopt_parameters),
206       outer_frame_state, ContinuationFrameStateMode::LAZY, signature);
207 }
208 #endif  // V8_ENABLE_WEBASSEMBLY
209 
CreateJavaScriptBuiltinContinuationFrameState(JSGraph * jsgraph,const SharedFunctionInfoRef & shared,Builtin name,Node * target,Node * context,Node * const * stack_parameters,int stack_parameter_count,Node * outer_frame_state,ContinuationFrameStateMode mode)210 FrameState CreateJavaScriptBuiltinContinuationFrameState(
211     JSGraph* jsgraph, const SharedFunctionInfoRef& shared, Builtin name,
212     Node* target, Node* context, Node* const* stack_parameters,
213     int stack_parameter_count, Node* outer_frame_state,
214     ContinuationFrameStateMode mode) {
215   // Depending on {mode}, final parameters are added by the deoptimizer
216   // and aren't explicitly passed in the frame state.
217   DCHECK_EQ(Builtins::GetStackParameterCount(name),
218             stack_parameter_count + DeoptimizerParameterCountFor(mode));
219 
220   Node* argc = jsgraph->Constant(Builtins::GetStackParameterCount(name));
221 
222   // Stack parameters first. They must be first because the receiver is expected
223   // to be the second value in the translation when creating stack crawls
224   // (e.g. Error.stack) of optimized JavaScript frames.
225   std::vector<Node*> actual_parameters;
226   actual_parameters.reserve(stack_parameter_count);
227   for (int i = 0; i < stack_parameter_count; ++i) {
228     actual_parameters.push_back(stack_parameters[i]);
229   }
230 
231   Node* new_target = jsgraph->UndefinedConstant();
232 
233   // Register parameters follow stack parameters. The context will be added by
234   // instruction selector during FrameState translation.
235   actual_parameters.push_back(target);      // kJavaScriptCallTargetRegister
236   actual_parameters.push_back(new_target);  // kJavaScriptCallNewTargetRegister
237   actual_parameters.push_back(argc);        // kJavaScriptCallArgCountRegister
238 
239   return CreateBuiltinContinuationFrameStateCommon(
240       jsgraph,
241       mode == ContinuationFrameStateMode::LAZY_WITH_CATCH
242           ? FrameStateType::kJavaScriptBuiltinContinuationWithCatch
243           : FrameStateType::kJavaScriptBuiltinContinuation,
244       name, target, context, &actual_parameters[0],
245       static_cast<int>(actual_parameters.size()), outer_frame_state,
246       shared.object());
247 }
248 
CreateGenericLazyDeoptContinuationFrameState(JSGraph * graph,const SharedFunctionInfoRef & shared,Node * target,Node * context,Node * receiver,Node * outer_frame_state)249 FrameState CreateGenericLazyDeoptContinuationFrameState(
250     JSGraph* graph, const SharedFunctionInfoRef& shared, Node* target,
251     Node* context, Node* receiver, Node* outer_frame_state) {
252   Node* stack_parameters[]{receiver};
253   const int stack_parameter_count = arraysize(stack_parameters);
254   return CreateJavaScriptBuiltinContinuationFrameState(
255       graph, shared, Builtin::kGenericLazyDeoptContinuation, target, context,
256       stack_parameters, stack_parameter_count, outer_frame_state,
257       ContinuationFrameStateMode::LAZY);
258 }
259 
260 }  // namespace compiler
261 }  // namespace internal
262 }  // namespace v8
263