v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
deoptimizer.h
Go to the documentation of this file.
1// Copyright 2012 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#ifndef V8_DEOPTIMIZER_DEOPTIMIZER_H_
6#define V8_DEOPTIMIZER_DEOPTIMIZER_H_
7
8#include <optional>
9#include <vector>
10
18
19#if V8_ENABLE_WEBASSEMBLY
21#include "src/wasm/value-type.h"
22#endif // V8_ENABLE_WEBASSEMBLY
23
24namespace v8 {
25namespace internal {
26
27namespace wasm {
28class WasmCode;
29}
30
32
33class DeoptimizedFrameInfo;
34class Isolate;
35
36class Deoptimizer : public Malloced {
37 public:
51
52 // Whether the deopt exit is contained by the outermost loop containing the
53 // osr'd loop. For example:
54 //
55 // for (;;) {
56 // for (;;) {
57 // } // OSR is triggered on this backedge.
58 // } // This is the outermost loop containing the osr'd loop.
59 static bool DeoptExitIsInsideOsrLoop(Isolate* isolate,
60 Tagged<JSFunction> function,
61 BytecodeOffset deopt_exit_offset,
62 BytecodeOffset osr_offset);
63 static DeoptInfo GetDeoptInfo(Tagged<Code> code, Address from);
67
68 static const char* MessageFor(DeoptimizeKind kind);
69
73 int output_count() const { return output_count_; }
74
75 // Where the deopt exit occurred *in the outermost frame*, i.e in the
76 // function we generated OSR'd code for. If the deopt occurred in an inlined
77 // function, this would point at the corresponding outermost Call bytecode.
81
82 static Deoptimizer* New(Address raw_function, DeoptimizeKind kind,
83 Address from, int fp_to_sp_delta, Isolate* isolate);
84 static Deoptimizer* Grab(Isolate* isolate);
85
86 // Delete and deregister the deoptimizer from the current isolate. Returns the
87 // count of output (liftoff) frames that were constructed by the deoptimizer.
88 static size_t DeleteForWasm(Isolate* isolate);
89
90 // The returned object with information on the optimized frame needs to be
91 // freed before another one can be generated.
93 int jsframe_index,
94 Isolate* isolate);
95
96 // Deoptimize the function now. Its current optimized code will never be run
97 // again and any activations of the optimized code will get deoptimized when
98 // execution returns. If {code} is specified then the given code is targeted
99 // instead of the function code (e.g. OSR code not installed on function).
100 static void DeoptimizeFunction(Tagged<JSFunction> function,
102 Tagged<Code> code = {});
103
104 // Deoptimize all code in the given isolate.
105 V8_EXPORT_PRIVATE static void DeoptimizeAll(Isolate* isolate);
106
107 // Deoptimizes all optimized code that has been previously marked
108 // (via code->set_marked_for_deoptimization) and unlinks all functions that
109 // refer to that code.
110 static void DeoptimizeMarkedCode(Isolate* isolate);
111
112 // Deoptimizes all optimized code that implements the given function (whether
113 // directly or inlined).
115 Isolate* isolate, DirectHandle<SharedFunctionInfo> function);
116
117 // Check the given address against a list of allowed addresses, to prevent a
118 // potential attacker from using the frame creation process in the
119 // deoptimizer, in particular the signing process, to gain control over the
120 // program.
121 // This function makes a crash if the address is not valid. If it's valid,
122 // it returns the given address.
123 static Address EnsureValidReturnAddress(Isolate* isolate, Address address);
124
125 ~Deoptimizer();
126
128
129 static void ComputeOutputFrames(Deoptimizer* deoptimizer);
130
132
133 // InstructionStream generation support.
134 static int input_offset() { return offsetof(Deoptimizer, input_); }
135 static int output_count_offset() {
136 return offsetof(Deoptimizer, output_count_);
137 }
138 static int output_offset() { return offsetof(Deoptimizer, output_); }
139
141 return offsetof(Deoptimizer, caller_frame_top_);
142 }
143
144#ifdef V8_ENABLE_CET_SHADOW_STACK
145 static constexpr int shadow_stack_offset() {
146 return offsetof(Deoptimizer, shadow_stack_);
147 }
148
149 static constexpr int shadow_stack_count_offset() {
150 return offsetof(Deoptimizer, shadow_stack_count_);
151 }
152#endif // V8_ENABLE_CET_SHADOW_STACK
153
154 Isolate* isolate() const { return isolate_; }
155
156 static constexpr int kMaxNumberOfEntries = 16384;
157
158 // This marker is passed to Deoptimizer::New as {deopt_exit_index} on
159 // platforms that have fixed deopt sizes. The actual deoptimization id is then
160 // calculated from the return address.
161 static constexpr unsigned kFixedExitSizeMarker = kMaxUInt32;
162
163 // Size of deoptimization exit sequence.
166
167 // The size of the call instruction to Builtins::kAdaptShadowStackForDeopt.
169
170 // Tracing.
171 static void TraceMarkForDeoptimization(Isolate* isolate, Tagged<Code> code,
172 LazyDeoptimizeReason reason);
173 static void TraceEvictFromOptimizedCodeCache(Isolate* isolate,
175 const char* reason);
176
177 // Patch the generated code to jump to a safepoint entry. This is used only
178 // when Shadow Stack is enabled.
179 static void PatchToJump(Address pc, Address new_pc);
180
181 private:
182 void QueueValueForMaterialization(Address output_address, Tagged<Object> obj,
183 const TranslatedFrame::iterator& iterator);
185 Address output_address, const TranslatedFrame::iterator& iterator);
186
187 Deoptimizer(Isolate* isolate, Tagged<JSFunction> function,
188 DeoptimizeKind kind, Address from, int fp_to_sp_delta);
190
192
193#if V8_ENABLE_WEBASSEMBLY
194 void DoComputeOutputFramesWasmImpl();
195 FrameDescription* DoComputeWasmLiftoffFrame(
196 TranslatedFrame& frame, wasm::NativeModule* native_module,
197 Tagged<WasmTrustedInstanceData> wasm_trusted_instance, int frame_index,
198 std::stack<intptr_t>& shadow_stack);
199
200 void GetWasmStackSlotsCounts(const wasm::FunctionSig* sig,
201 int* parameter_stack_slots,
202 int* return_stack_slots);
203#endif
204
205 void DoComputeUnoptimizedFrame(TranslatedFrame* translated_frame,
206 int frame_index, bool goto_catch_handler);
207 void DoComputeInlinedExtraArguments(TranslatedFrame* translated_frame,
208 int frame_index);
210 int frame_index);
212 int frame_index);
213
215 bool must_handle_result);
216
217#if V8_ENABLE_WEBASSEMBLY
218 TranslatedValue TranslatedValueForWasmReturnKind(
219 std::optional<wasm::ValueKind> wasm_call_return_kind);
220#endif // V8_ENABLE_WEBASSEMBLY
221
222 void DoComputeBuiltinContinuation(TranslatedFrame* translated_frame,
223 int frame_index,
225
226 unsigned ComputeInputFrameAboveFpFixedSize() const;
227 unsigned ComputeInputFrameSize() const;
228
229 static unsigned ComputeIncomingArgumentSize(Tagged<Code> code);
230
231 // Tracing.
232 bool tracing_enabled() const { return trace_scope_ != nullptr; }
234 return v8_flags.trace_deopt_verbose && tracing_enabled();
235 }
238 return v8_flags.trace_deopt_verbose ? trace_scope() : nullptr;
239 }
240 void TraceDeoptBegin(int optimization_id, BytecodeOffset bytecode_offset);
241 void TraceDeoptEnd(double deopt_duration);
242#ifdef DEBUG
243 static void TraceFoundActivation(Isolate* isolate,
244 Tagged<JSFunction> function);
245#endif
246 static void TraceDeoptAll(Isolate* isolate);
247
248 bool is_restart_frame() const { return restart_frame_index_ >= 0; }
249
253#if V8_ENABLE_WEBASSEMBLY
254 wasm::WasmCode* compiled_optimized_wasm_code_ = nullptr;
255#endif
265
266 // Input frame description.
268 // Number of output frames.
270 // Array of output frame descriptions.
272
273 // Caller frame details computed from input frame.
275 intptr_t caller_fp_;
276 intptr_t caller_pc_;
278
279 // The argument count of the bottom most frame.
281
282 // Key for lookup of previously materialized objects.
283 intptr_t stack_fp_;
284
290 std::vector<ValueToMaterialize> values_to_materialize_;
291 std::vector<ValueToMaterialize> feedback_vector_to_materialize_;
292
293#ifdef V8_ENABLE_CET_SHADOW_STACK
294 intptr_t* shadow_stack_ = nullptr;
295 size_t shadow_stack_count_ = 0;
296#endif // V8_ENABLE_CET_SHADOW_STACK
297
298#ifdef DEBUG
299 DisallowGarbageCollection* disallow_garbage_collection_;
300#endif // DEBUG
301
302 // Note: This is intentionally not a unique_ptr s.t. the Deoptimizer
303 // satisfies is_standard_layout, needed for offsetof().
305
306#if V8_ENABLE_WEBASSEMBLY && V8_TARGET_ARCH_32_BIT
307 // Needed by webassembly for lowering signatures containing i64 types. Stored
308 // as members for reuse for multiple signatures during one de-optimization.
309 std::optional<AccountingAllocator> alloc_;
310 std::optional<Zone> zone_;
311#endif
312#if V8_ENABLE_WEBASSEMBLY && V8_ENABLE_SANDBOX
313 // Wasm deoptimizations should not access the heap at all. All deopt data is
314 // stored off-heap.
315 std::optional<SandboxHardwareSupport::BlockAccessScope>
316 no_heap_access_during_wasm_deopt_;
317#endif
318
320 friend class FrameDescription;
321 friend class FrameWriter;
322};
323
324} // namespace internal
325} // namespace v8
326
327#endif // V8_DEOPTIMIZER_DEOPTIMIZER_H_
Builtins::Kind kind
Definition builtins.cc:40
static constexpr BytecodeOffset None()
Definition utils.h:675
unsigned ComputeInputFrameSize() const
bool is_restart_frame() const
static Deoptimizer * Grab(Isolate *isolate)
static void PatchToJump(Address pc, Address new_pc)
static int caller_frame_top_offset()
void DoComputeInlinedExtraArguments(TranslatedFrame *translated_frame, int frame_index)
static void DeoptimizeAllOptimizedCodeWithFunction(Isolate *isolate, DirectHandle< SharedFunctionInfo > function)
void DoComputeConstructInvokeStubFrame(TranslatedFrame *translated_frame, int frame_index)
void DoComputeUnoptimizedFrame(TranslatedFrame *translated_frame, int frame_index, bool goto_catch_handler)
DirectHandle< JSFunction > function() const
void QueueFeedbackVectorForMaterialization(Address output_address, const TranslatedFrame::iterator &iterator)
static void ComputeOutputFrames(Deoptimizer *deoptimizer)
std::vector< ValueToMaterialize > feedback_vector_to_materialize_
static V8_EXPORT_PRIVATE const int kEagerDeoptExitSize
static size_t DeleteForWasm(Isolate *isolate)
static void TraceDeoptAll(Isolate *isolate)
void TraceDeoptBegin(int optimization_id, BytecodeOffset bytecode_offset)
DirectHandle< Code > compiled_code() const
Tagged< Code > compiled_code_
static V8_EXPORT_PRIVATE const int kAdaptShadowStackOffsetToSubtract
static void DeoptimizeFunction(Tagged< JSFunction > function, LazyDeoptimizeReason reason, Tagged< Code > code={})
void TraceDeoptEnd(double deopt_duration)
static DeoptimizedFrameInfo * DebuggerInspectableFrame(JavaScriptFrame *frame, int jsframe_index, Isolate *isolate)
static Address EnsureValidReturnAddress(Isolate *isolate, Address address)
static bool DeoptExitIsInsideOsrLoop(Isolate *isolate, Tagged< JSFunction > function, BytecodeOffset deopt_exit_offset, BytecodeOffset osr_offset)
static V8_EXPORT_PRIVATE void DeoptimizeAll(Isolate *isolate)
unsigned ComputeInputFrameAboveFpFixedSize() const
static int output_count_offset()
static void DeoptimizeMarkedCode(Isolate *isolate)
static Builtin TrampolineForBuiltinContinuation(BuiltinContinuationMode mode, bool must_handle_result)
static Deoptimizer * New(Address raw_function, DeoptimizeKind kind, Address from, int fp_to_sp_delta, Isolate *isolate)
CodeTracer::Scope * verbose_trace_scope() const
CodeTracer::Scope *const trace_scope_
static V8_EXPORT_PRIVATE Builtin GetDeoptimizationEntry(DeoptimizeKind kind)
static unsigned ComputeIncomingArgumentSize(Tagged< Code > code)
static void TraceEvictFromOptimizedCodeCache(Isolate *isolate, Tagged< SharedFunctionInfo > sfi, const char *reason)
static constexpr unsigned kFixedExitSizeMarker
static constexpr int kMaxNumberOfEntries
static V8_EXPORT_PRIVATE const int kLazyDeoptExitSize
Isolate * isolate() const
TranslatedState translated_state_
static void TraceMarkForDeoptimization(Isolate *isolate, Tagged< Code > code, LazyDeoptimizeReason reason)
DeoptimizeKind deopt_kind_
CodeTracer::Scope * trace_scope() const
void DoComputeConstructCreateStubFrame(TranslatedFrame *translated_frame, int frame_index)
FrameDescription ** output_
DeoptimizeKind deopt_kind() const
Definition deoptimizer.h:72
FrameDescription * input_
bool verbose_tracing_enabled() const
BytecodeOffset bytecode_offset_in_outermost_frame_
void DoComputeBuiltinContinuation(TranslatedFrame *translated_frame, int frame_index, BuiltinContinuationMode mode)
Deoptimizer(Isolate *isolate, Tagged< JSFunction > function, DeoptimizeKind kind, Address from, int fp_to_sp_delta)
DeoptInfo GetDeoptInfo() const
Definition deoptimizer.h:64
void QueueValueForMaterialization(Address output_address, Tagged< Object > obj, const TranslatedFrame::iterator &iterator)
BytecodeOffset bytecode_offset_in_outermost_frame() const
Definition deoptimizer.h:78
std::vector< ValueToMaterialize > values_to_materialize_
static const char * MessageFor(DeoptimizeKind kind)
Tagged< JSFunction > function_
Zone * zone_
BuiltinContinuationMode
Definition frames.h:1899
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr uint32_t kMaxUInt32
Definition globals.h:387
Definition c-api.cc:87
#define V8_EXPORT_PRIVATE
Definition macros.h:460
const DeoptimizeReason deopt_reason
Definition deoptimizer.h:47
DeoptInfo(SourcePosition position, DeoptimizeReason deopt_reason, uint32_t node_id, int deopt_id)
Definition deoptimizer.h:39