v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
frame-states.cc
Go to the documentation of this file.
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
6
7#include <optional>
8
9#include "src/base/hashing.h"
12#include "src/compiler/node.h"
16
17#if V8_ENABLE_WEBASSEMBLY
18#include "src/wasm/value-type.h"
19#endif // V8_ENABLE_WEBASSEMBLY
20
21namespace v8 {
22namespace internal {
23namespace compiler {
24
27}
28
29std::ostream& operator<<(std::ostream& os, OutputFrameStateCombine const& sc) {
31 return os << "Ignore";
32 return os << "PokeAt(" << sc.parameter_ << ")";
33}
34
36 FrameStateFunctionInfo const& rhs) {
37#if V8_HOST_ARCH_X64
38// If this static_assert fails, then you've probably added a new field to
39// FrameStateFunctionInfo. Make sure to take it into account in this equality
40// function, and update the static_assert.
41#if V8_ENABLE_WEBASSEMBLY
42 static_assert(sizeof(FrameStateFunctionInfo) == 40);
43#else
44 static_assert(sizeof(FrameStateFunctionInfo) == 32);
45#endif
46#endif
47
48#if V8_ENABLE_WEBASSEMBLY
51 return false;
52 }
53#endif
54
55 return lhs.type() == rhs.type() &&
56 lhs.parameter_count() == rhs.parameter_count() &&
57 lhs.max_arguments() == rhs.max_arguments() &&
58 lhs.local_count() == rhs.local_count() &&
59 lhs.shared_info().equals(rhs.shared_info()) &&
60 lhs.bytecode_array().equals(rhs.bytecode_array());
61}
62
63bool operator==(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
64#if V8_HOST_ARCH_X64
65 // If this static_assert fails, then you've probably added a new field to
66 // FrameStateInfo. Make sure to take it into account in this equality
67 // function, and update the static_assert.
68 static_assert(sizeof(FrameStateInfo) == 24);
69#endif
70
71 return lhs.type() == rhs.type() && lhs.bailout_id() == rhs.bailout_id() &&
72 lhs.state_combine() == rhs.state_combine() &&
73 *lhs.function_info() == *rhs.function_info();
74}
75
76bool operator!=(FrameStateInfo const& lhs, FrameStateInfo const& rhs) {
77 return !(lhs == rhs);
78}
79
80size_t hash_value(FrameStateInfo const& info) {
81 return base::hash_combine(static_cast<int>(info.type()), info.bailout_id(),
82 info.state_combine());
83}
84
85std::ostream& operator<<(std::ostream& os, FrameStateType type) {
86 switch (type) {
88 os << "UNOPTIMIZED_FRAME";
89 break;
91 os << "INLINED_EXTRA_ARGUMENTS";
92 break;
94 os << "CONSTRUCT_CREATE_STUB";
95 break;
97 os << "CONSTRUCT_INVOKE_STUB";
98 break;
100 os << "BUILTIN_CONTINUATION_FRAME";
101 break;
102#if V8_ENABLE_WEBASSEMBLY
103 case FrameStateType::kWasmInlinedIntoJS:
104 os << "WASM_INLINED_INTO_JS_FRAME";
105 break;
106 case FrameStateType::kJSToWasmBuiltinContinuation:
107 os << "JS_TO_WASM_BUILTIN_CONTINUATION_FRAME";
108 break;
109 case FrameStateType::kLiftoffFunction:
110 os << "LIFTOFF_FRAME";
111 break;
112#endif // V8_ENABLE_WEBASSEMBLY
114 os << "JAVASCRIPT_BUILTIN_CONTINUATION_FRAME";
115 break;
117 os << "JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME";
118 break;
119 }
120 return os;
121}
122
123std::ostream& operator<<(std::ostream& os, FrameStateInfo const& info) {
124 os << info.type() << ", " << info.bailout_id() << ", "
125 << info.state_combine();
127 if (info.shared_info().ToHandle(&shared_info)) {
128 os << ", " << Brief(*shared_info);
129 }
130 return os;
131}
132
133namespace {
134
135// Lazy deopt points where the frame state is associated with a call get an
136// additional parameter for the return result from the call. The return result
137// is added by the deoptimizer and not explicitly specified in the frame state.
138// Lazy deopt points which can catch exceptions further get an additional
139// parameter, namely the exception thrown. The exception is also added by the
140// deoptimizer.
141uint8_t DeoptimizerParameterCountFor(ContinuationFrameStateMode mode) {
142 switch (mode) {
144 return 0;
146 return 1;
148 return 2;
149 }
150 UNREACHABLE();
151}
152
153FrameState CreateBuiltinContinuationFrameStateCommon(
154 JSGraph* jsgraph, FrameStateType frame_type, Builtin name, Node* closure,
155 Node* context, Node** parameters, int parameter_count,
156 Node* outer_frame_state,
158 const wasm::CanonicalSig* signature = nullptr) {
159 TFGraph* const graph = jsgraph->graph();
160 CommonOperatorBuilder* const common = jsgraph->common();
161
162 const Operator* op_param =
164 Node* params_node = graph->NewNode(op_param, parameter_count, parameters);
165
166 BytecodeOffset bailout_id = Builtins::GetContinuationBytecodeOffset(name);
167#if V8_ENABLE_WEBASSEMBLY
168 const FrameStateFunctionInfo* state_info =
169 signature ? common->CreateJSToWasmFrameStateFunctionInfo(
170 frame_type, parameter_count, 0, shared, signature)
171 : common->CreateFrameStateFunctionInfo(
172 frame_type, parameter_count, 0, 0, shared, {});
173#else
174 DCHECK_NULL(signature);
175 const FrameStateFunctionInfo* state_info =
176 common->CreateFrameStateFunctionInfo(frame_type, parameter_count, 0, 0,
177 shared, {});
178#endif // V8_ENABLE_WEBASSEMBLY
179
180 const Operator* op = common->FrameState(
181 bailout_id, OutputFrameStateCombine::Ignore(), state_info);
182 return FrameState(graph->NewNode(op, params_node, jsgraph->EmptyStateValues(),
183 jsgraph->EmptyStateValues(), context,
184 closure, outer_frame_state));
185}
186
187} // namespace
188
190 JSGraph* jsgraph, Builtin name, Node* context, Node* const* parameters,
192 ContinuationFrameStateMode mode, const wasm::CanonicalSig* signature) {
193 Callable callable = Builtins::CallableFor(jsgraph->isolate(), name);
194 CallInterfaceDescriptor descriptor = callable.descriptor();
195
196 std::vector<Node*> actual_parameters;
197 // Stack parameters first. Depending on {mode}, final parameters are added
198 // by the deoptimizer and aren't explicitly passed in the frame state.
199 int stack_parameter_count =
200 descriptor.GetStackParameterCount() - DeoptimizerParameterCountFor(mode);
201
202 // Ensure the parameters added by the deoptimizer are passed on the stack.
203 // This check prevents using TFS builtins as continuations while doing the
204 // lazy deopt. Use TFC or TFJ builtin as a lazy deopt continuation which
205 // would pass the result parameter on the stack.
206 DCHECK_GE(stack_parameter_count, 0);
207
208 // Reserving space in the vector.
209 actual_parameters.reserve(stack_parameter_count +
210 descriptor.GetRegisterParameterCount());
211 for (int i = 0; i < stack_parameter_count; ++i) {
212 actual_parameters.push_back(
213 parameters[descriptor.GetRegisterParameterCount() + i]);
214 }
215 // Register parameters follow, context will be added by instruction selector
216 // during FrameState translation.
217 for (int i = 0; i < descriptor.GetRegisterParameterCount(); ++i) {
218 actual_parameters.push_back(parameters[i]);
219 }
220
222#if V8_ENABLE_WEBASSEMBLY
223 if (name == Builtin::kJSToWasmLazyDeoptContinuation) {
224 CHECK_NOT_NULL(signature);
225 frame_state_type = FrameStateType::kJSToWasmBuiltinContinuation;
226 }
227#endif // V8_ENABLE_WEBASSEMBLY
228 return CreateBuiltinContinuationFrameStateCommon(
229 jsgraph, frame_state_type, name, jsgraph->UndefinedConstant(), context,
230 actual_parameters.data(), static_cast<int>(actual_parameters.size()),
232}
233
234#if V8_ENABLE_WEBASSEMBLY
235FrameState CreateJSWasmCallBuiltinContinuationFrameState(
236 JSGraph* jsgraph, Node* context, Node* outer_frame_state,
237 const wasm::CanonicalSig* signature) {
238 std::optional<wasm::ValueKind> wasm_return_kind =
240 Node* node_return_type =
241 jsgraph->SmiConstant(wasm_return_kind ? wasm_return_kind.value() : -1);
242 Node* lazy_deopt_parameters[] = {node_return_type};
244 jsgraph, Builtin::kJSToWasmLazyDeoptContinuation, context,
245 lazy_deopt_parameters, arraysize(lazy_deopt_parameters),
247}
248#endif // V8_ENABLE_WEBASSEMBLY
249
251 JSGraph* jsgraph, SharedFunctionInfoRef shared, Builtin name, Node* target,
252 Node* context, Node* const* stack_parameters, int stack_parameter_count,
254 // Depending on {mode}, final parameters are added by the deoptimizer
255 // and aren't explicitly passed in the frame state.
257 stack_parameter_count + DeoptimizerParameterCountFor(mode));
258
260
261 // Stack parameters first. They must be first because the receiver is expected
262 // to be the second value in the translation when creating stack crawls
263 // (e.g. Error.stack) of optimized JavaScript frames.
264 std::vector<Node*> actual_parameters;
265 actual_parameters.reserve(stack_parameter_count);
266 for (int i = 0; i < stack_parameter_count; ++i) {
267 actual_parameters.push_back(stack_parameters[i]);
268 }
269
270 Node* new_target = jsgraph->UndefinedConstant();
271
272 // Register parameters follow stack parameters. The context will be added by
273 // instruction selector during FrameState translation.
274 DCHECK_EQ(
275 Builtins::CallInterfaceDescriptorFor(name).GetRegisterParameterCount(),
277 actual_parameters.push_back(target); // kJavaScriptCallTargetRegister
278 actual_parameters.push_back(new_target); // kJavaScriptCallNewTargetRegister
279 actual_parameters.push_back(argc); // kJavaScriptCallArgCountRegister
280#ifdef V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE
281 // The dispatch handle isn't used by the continuation builtins.
283 actual_parameters.push_back(handle); // kJavaScriptDispatchHandleRegister
284#endif
285
286 return CreateBuiltinContinuationFrameStateCommon(
287 jsgraph,
291 name, target, context, &actual_parameters[0],
292 static_cast<int>(actual_parameters.size()), outer_frame_state,
293 shared.object());
294}
295
297 JSGraph* graph, SharedFunctionInfoRef shared, Node* target, Node* context,
299 Node* stack_parameters[]{receiver};
300 const int stack_parameter_count = arraysize(stack_parameters);
302 graph, shared, Builtin::kGenericLazyDeoptContinuation, target, context,
303 stack_parameters, stack_parameter_count, outer_frame_state,
305}
306
309 Node* target, Node* context,
310 Node* receiver,
312 return outer_frame_state;
313}
314
316 OutputFrameStateCombine changed_state_combine) {
317 TFGraph* graph = jsgraph->graph();
319
320 DCHECK_EQ(IrOpcode::kFrameState, frame_state->op()->opcode());
321
322 const Operator* op = common->FrameState(
323 frame_state.frame_state_info().bailout_id(), changed_state_combine,
324 frame_state.frame_state_info().function_info());
325 return FrameState(
326 graph->NewNode(op, frame_state.parameters(), frame_state.locals(),
327 frame_state.stack(), frame_state.context(),
328 frame_state.function(), frame_state.outer_frame_state()));
329}
330
331} // namespace compiler
332} // namespace internal
333} // namespace v8
JSGraph * jsgraph
int16_t parameter_count
Definition builtins.cc:67
constexpr UnderlyingType & value() &
static BytecodeOffset GetContinuationBytecodeOffset(Builtin builtin)
Definition builtins.cc:97
static CallInterfaceDescriptor CallInterfaceDescriptorFor(Builtin builtin)
Definition builtins.cc:189
static V8_EXPORT_PRIVATE int GetStackParameterCount(Builtin builtin)
Definition builtins.cc:160
static V8_EXPORT_PRIVATE Callable CallableFor(Isolate *isolate, Builtin builtin)
Definition builtins.cc:214
CallInterfaceDescriptor descriptor() const
Definition callable.h:23
const Operator * StateValues(int arguments, SparseInputMask bitmask)
const Operator * FrameState(BytecodeOffset bailout_id, OutputFrameStateCombine state_combine, const FrameStateFunctionInfo *function_info)
IndirectHandle< SharedFunctionInfo > shared_info() const
MaybeIndirectHandle< BytecodeArray > bytecode_array() const
OutputFrameStateCombine state_combine() const
const FrameStateFunctionInfo * function_info() const
const FrameStateInfo & frame_state_info() const
Isolate * isolate() const
Definition js-graph.h:106
Node * ConstantNoHole(ObjectRef ref, JSHeapBroker *broker)
Definition js-graph.cc:51
Node * SmiConstant(int32_t immediate)
Definition js-graph.h:99
CommonOperatorBuilder * common() const
static OutputFrameStateCombine Ignore()
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL
Definition globals.h:161
DirectHandle< Object > new_target
Definition execution.cc:75
TNode< Object > receiver
FrameState outer_frame_state
V8_INLINE size_t hash_value(unsigned int v)
Definition hashing.h:205
V8_INLINE size_t hash_combine(size_t seed, size_t hash)
Definition hashing.h:77
FrameState CloneFrameState(JSGraph *jsgraph, FrameState frame_state, OutputFrameStateCombine changed_state_combine)
FrameState CreateGenericLazyDeoptContinuationFrameState(JSGraph *graph, SharedFunctionInfoRef shared, Node *target, Node *context, Node *receiver, Node *outer_frame_state)
FrameState CreateStubBuiltinContinuationFrameState(JSGraph *jsgraph, Builtin name, Node *context, Node *const *parameters, int parameter_count, Node *outer_frame_state, ContinuationFrameStateMode mode, const wasm::CanonicalSig *signature)
size_t hash_value(const BranchParameters &p)
Node * CreateInlinedApiFunctionFrameState(JSGraph *graph, SharedFunctionInfoRef shared, Node *target, Node *context, Node *receiver, Node *outer_frame_state)
FrameState CreateJavaScriptBuiltinContinuationFrameState(JSGraph *jsgraph, SharedFunctionInfoRef shared, Builtin name, Node *target, Node *context, Node *const *stack_parameters, int stack_parameter_count, Node *outer_frame_state, ContinuationFrameStateMode mode)
bool operator!=(DeoptimizeParameters lhs, DeoptimizeParameters rhs)
bool operator==(const BranchParameters &lhs, const BranchParameters &rhs)
std::ostream & operator<<(std::ostream &os, AccessMode access_mode)
std::optional< wasm::ValueKind > WasmReturnTypeFromSignature(const CanonicalSig *wasm_signature)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
constexpr JSDispatchHandle kInvalidDispatchHandle(0xffffffff<< kJSDispatchHandleShift)
Local< T > Handle
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK_NOT_NULL(val)
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define arraysize(array)
Definition macros.h:67