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
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 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
CreateStubBuiltinContinuationFrameState(JSGraph * jsgraph,Builtins::Name name,Node * context,Node * const * parameters,int parameter_count,Node * outer_frame_state,ContinuationFrameStateMode mode)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
CreateJavaScriptBuiltinContinuationFrameState(JSGraph * jsgraph,Handle<SharedFunctionInfo> shared,Builtins::Name name,Node * target,Node * context,Node * const * stack_parameters,int stack_parameter_count,Node * outer_frame_state,ContinuationFrameStateMode mode)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