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 
hash_value(OutputFrameStateCombine const & sc)19 size_t hash_value(OutputFrameStateCombine const& sc) {
20   return base::hash_value(sc.parameter_);
21 }
22 
23 
operator <<(std::ostream & os,OutputFrameStateCombine const & sc)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 
operator ==(FrameStateInfo const & lhs,FrameStateInfo const & rhs)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 
operator !=(FrameStateInfo const & lhs,FrameStateInfo const & rhs)38 bool operator!=(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
39   return !(lhs == rhs);
40 }
41 
42 
hash_value(FrameStateInfo const & info)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 
operator <<(std::ostream & os,FrameStateType type)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 
operator <<(std::ostream & os,FrameStateInfo const & info)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.
DeoptimizerParameterCountFor(ContinuationFrameStateMode mode)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 
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> ())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   Graph* const graph = jsgraph->graph();
110   CommonOperatorBuilder* const common = jsgraph->common();
111 
112   const Operator* op_param =
113       common->StateValues(parameter_count, SparseInputMask::Dense());
114   Node* params_node = graph->NewNode(op_param, parameter_count, parameters);
115 
116   BailoutId bailout_id = Builtins::GetContinuationBailoutId(name);
117   const FrameStateFunctionInfo* state_info =
118       common->CreateFrameStateFunctionInfo(frame_type, parameter_count, 0,
119                                            shared);
120   const Operator* op = common->FrameState(
121       bailout_id, OutputFrameStateCombine::Ignore(), state_info);
122   return graph->NewNode(op, params_node, jsgraph->EmptyStateValues(),
123                         jsgraph->EmptyStateValues(), context, closure,
124                         outer_frame_state);
125 }
126 
127 }  // namespace
128 
CreateStubBuiltinContinuationFrameState(JSGraph * jsgraph,Builtins::Name name,Node * context,Node * const * parameters,int parameter_count,Node * outer_frame_state,ContinuationFrameStateMode mode)129 Node* CreateStubBuiltinContinuationFrameState(
130     JSGraph* jsgraph, Builtins::Name name, Node* context,
131     Node* const* parameters, int parameter_count, Node* outer_frame_state,
132     ContinuationFrameStateMode mode) {
133   Callable callable = Builtins::CallableFor(jsgraph->isolate(), name);
134   CallInterfaceDescriptor descriptor = callable.descriptor();
135 
136   std::vector<Node*> actual_parameters;
137   // Stack parameters first. Depending on {mode}, final parameters are added
138   // by the deoptimizer and aren't explicitly passed in the frame state.
139   int stack_parameter_count =
140       descriptor.GetStackParameterCount() - DeoptimizerParameterCountFor(mode);
141 
142   // Ensure the parameters added by the deoptimizer are passed on the stack.
143   // This check prevents using TFS builtins as continuations while doing the
144   // lazy deopt. Use TFC or TFJ builtin as a lazy deopt continuation which
145   // would pass the result parameter on the stack.
146   DCHECK_GE(stack_parameter_count, 0);
147 
148   // Reserving space in the vector.
149   actual_parameters.reserve(stack_parameter_count +
150                             descriptor.GetRegisterParameterCount());
151   for (int i = 0; i < stack_parameter_count; ++i) {
152     actual_parameters.push_back(
153         parameters[descriptor.GetRegisterParameterCount() + i]);
154   }
155   // Register parameters follow, context will be added by instruction selector
156   // during FrameState translation.
157   for (int i = 0; i < descriptor.GetRegisterParameterCount(); ++i) {
158     actual_parameters.push_back(parameters[i]);
159   }
160 
161   return CreateBuiltinContinuationFrameStateCommon(
162       jsgraph, FrameStateType::kBuiltinContinuation, name,
163       jsgraph->UndefinedConstant(), context, actual_parameters.data(),
164       static_cast<int>(actual_parameters.size()), outer_frame_state);
165 }
166 
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)167 Node* CreateJavaScriptBuiltinContinuationFrameState(
168     JSGraph* jsgraph, const SharedFunctionInfoRef& shared, Builtins::Name name,
169     Node* target, Node* context, Node* const* stack_parameters,
170     int stack_parameter_count, Node* outer_frame_state,
171     ContinuationFrameStateMode mode) {
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   Node* new_target = jsgraph->UndefinedConstant();
188 
189   // Register parameters follow stack parameters. The context will be added by
190   // instruction selector during FrameState translation.
191   actual_parameters.push_back(target);      // kJavaScriptCallTargetRegister
192   actual_parameters.push_back(new_target);  // kJavaScriptCallNewTargetRegister
193   actual_parameters.push_back(argc);        // kJavaScriptCallArgCountRegister
194 
195   return CreateBuiltinContinuationFrameStateCommon(
196       jsgraph,
197       mode == ContinuationFrameStateMode::LAZY_WITH_CATCH
198           ? FrameStateType::kJavaScriptBuiltinContinuationWithCatch
199           : FrameStateType::kJavaScriptBuiltinContinuation,
200       name, target, context, &actual_parameters[0],
201       static_cast<int>(actual_parameters.size()), outer_frame_state,
202       shared.object());
203 }
204 
CreateGenericLazyDeoptContinuationFrameState(JSGraph * graph,const SharedFunctionInfoRef & shared,Node * target,Node * context,Node * receiver,Node * outer_frame_state)205 Node* CreateGenericLazyDeoptContinuationFrameState(
206     JSGraph* graph, const SharedFunctionInfoRef& shared, Node* target,
207     Node* context, Node* receiver, Node* outer_frame_state) {
208   Node* stack_parameters[]{receiver};
209   const int stack_parameter_count = arraysize(stack_parameters);
210   return CreateJavaScriptBuiltinContinuationFrameState(
211       graph, shared, Builtins::kGenericLazyDeoptContinuation, target, context,
212       stack_parameters, stack_parameter_count, outer_frame_state,
213       ContinuationFrameStateMode::LAZY);
214 }
215 
216 }  // namespace compiler
217 }  // namespace internal
218 }  // namespace v8
219