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