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