1// Copyright 2016 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_OPTIMIZED_COMPILATION_INFO_H_
6#define V8_OPTIMIZED_COMPILATION_INFO_H_
7
8#include <memory>
9
10#include "src/bailout-reason.h"
11#include "src/frames.h"
12#include "src/globals.h"
13#include "src/handles.h"
14#include "src/objects.h"
15#include "src/source-position-table.h"
16#include "src/utils.h"
17#include "src/vector.h"
18
19namespace v8 {
20
21namespace tracing {
22class TracedValue;
23}
24
25namespace internal {
26
27class DeferredHandles;
28class FunctionLiteral;
29class Isolate;
30class JavaScriptFrame;
31class JSGlobalObject;
32class Zone;
33
34namespace wasm {
35struct WasmCompilationResult;
36}
37
38// OptimizedCompilationInfo encapsulates the information needed to compile
39// optimized code for a given function, and the results of the optimized
40// compilation.
41class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
42 public:
43 // Various configuration flags for a compilation, as well as some properties
44 // of the compiled code produced by a compilation.
45 enum Flag {
46 kAccessorInliningEnabled = 1 << 0,
47 kFunctionContextSpecializing = 1 << 1,
48 kInliningEnabled = 1 << 2,
49 kDisableFutureOptimization = 1 << 3,
50 kSplittingEnabled = 1 << 4,
51 kSourcePositionsEnabled = 1 << 5,
52 kBailoutOnUninitialized = 1 << 6,
53 kLoopPeelingEnabled = 1 << 7,
54 kUntrustedCodeMitigations = 1 << 8,
55 kSwitchJumpTableEnabled = 1 << 9,
56 kCalledWithCodeStartRegister = 1 << 10,
57 kPoisonRegisterArguments = 1 << 11,
58 kAllocationFoldingEnabled = 1 << 12,
59 kAnalyzeEnvironmentLiveness = 1 << 13,
60 kTraceTurboJson = 1 << 14,
61 kTraceTurboGraph = 1 << 15,
62 kTraceTurboScheduled = 1 << 16,
63 kWasmRuntimeExceptionSupport = 1 << 17,
64 kTurboControlFlowAwareAllocation = 1 << 18,
65 kTurboPreprocessRanges = 1 << 19
66 };
67
68 // Construct a compilation info for optimized compilation.
69 OptimizedCompilationInfo(Zone* zone, Isolate* isolate,
70 Handle<SharedFunctionInfo> shared,
71 Handle<JSFunction> closure);
72 // Construct a compilation info for stub compilation, Wasm, and testing.
73 OptimizedCompilationInfo(Vector<const char> debug_name, Zone* zone,
74 Code::Kind code_kind);
75
76 ~OptimizedCompilationInfo();
77
78 Zone* zone() { return zone_; }
79 bool is_osr() const { return !osr_offset_.IsNone(); }
80 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
81 bool has_shared_info() const { return !shared_info().is_null(); }
82 Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
83 bool has_bytecode_array() const { return !bytecode_array_.is_null(); }
84 Handle<JSFunction> closure() const { return closure_; }
85 Handle<Code> code() const { return code_; }
86 Code::Kind code_kind() const { return code_kind_; }
87 int32_t builtin_index() const { return builtin_index_; }
88 void set_builtin_index(int32_t index) { builtin_index_ = index; }
89 BailoutId osr_offset() const { return osr_offset_; }
90 JavaScriptFrame* osr_frame() const { return osr_frame_; }
91
92 // Flags used by optimized compilation.
93
94 void MarkAsTurboControlFlowAwareAllocation() {
95 SetFlag(kTurboControlFlowAwareAllocation);
96 }
97 bool is_turbo_control_flow_aware_allocation() const {
98 return GetFlag(kTurboControlFlowAwareAllocation);
99 }
100
101 void MarkAsTurboPreprocessRanges() { SetFlag(kTurboPreprocessRanges); }
102 bool is_turbo_preprocess_ranges() const {
103 return GetFlag(kTurboPreprocessRanges);
104 }
105
106 void MarkAsFunctionContextSpecializing() {
107 SetFlag(kFunctionContextSpecializing);
108 }
109 bool is_function_context_specializing() const {
110 return GetFlag(kFunctionContextSpecializing);
111 }
112
113 void MarkAsAccessorInliningEnabled() { SetFlag(kAccessorInliningEnabled); }
114 bool is_accessor_inlining_enabled() const {
115 return GetFlag(kAccessorInliningEnabled);
116 }
117
118 void MarkAsSourcePositionsEnabled() { SetFlag(kSourcePositionsEnabled); }
119 bool is_source_positions_enabled() const {
120 return GetFlag(kSourcePositionsEnabled);
121 }
122
123 void MarkAsInliningEnabled() { SetFlag(kInliningEnabled); }
124 bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); }
125
126 void SetPoisoningMitigationLevel(PoisoningMitigationLevel poisoning_level) {
127 poisoning_level_ = poisoning_level;
128 }
129 PoisoningMitigationLevel GetPoisoningMitigationLevel() const {
130 return poisoning_level_;
131 }
132
133 void MarkAsSplittingEnabled() { SetFlag(kSplittingEnabled); }
134 bool is_splitting_enabled() const { return GetFlag(kSplittingEnabled); }
135
136 void MarkAsBailoutOnUninitialized() { SetFlag(kBailoutOnUninitialized); }
137 bool is_bailout_on_uninitialized() const {
138 return GetFlag(kBailoutOnUninitialized);
139 }
140
141 void MarkAsLoopPeelingEnabled() { SetFlag(kLoopPeelingEnabled); }
142 bool is_loop_peeling_enabled() const { return GetFlag(kLoopPeelingEnabled); }
143
144 bool has_untrusted_code_mitigations() const {
145 return GetFlag(kUntrustedCodeMitigations);
146 }
147
148 bool switch_jump_table_enabled() const {
149 return GetFlag(kSwitchJumpTableEnabled);
150 }
151
152 bool called_with_code_start_register() const {
153 bool enabled = GetFlag(kCalledWithCodeStartRegister);
154 return enabled;
155 }
156
157 void MarkAsPoisoningRegisterArguments() {
158 DCHECK(has_untrusted_code_mitigations());
159 SetFlag(kPoisonRegisterArguments);
160 }
161 bool is_poisoning_register_arguments() const {
162 bool enabled = GetFlag(kPoisonRegisterArguments);
163 DCHECK_IMPLIES(enabled, has_untrusted_code_mitigations());
164 DCHECK_IMPLIES(enabled, called_with_code_start_register());
165 return enabled;
166 }
167
168 void MarkAsAllocationFoldingEnabled() { SetFlag(kAllocationFoldingEnabled); }
169 bool is_allocation_folding_enabled() const {
170 return GetFlag(kAllocationFoldingEnabled);
171 }
172
173 void MarkAsAnalyzeEnvironmentLiveness() {
174 SetFlag(kAnalyzeEnvironmentLiveness);
175 }
176 bool is_analyze_environment_liveness() const {
177 return GetFlag(kAnalyzeEnvironmentLiveness);
178 }
179
180 void SetWasmRuntimeExceptionSupport() {
181 SetFlag(kWasmRuntimeExceptionSupport);
182 }
183
184 bool wasm_runtime_exception_support() {
185 return GetFlag(kWasmRuntimeExceptionSupport);
186 }
187
188 bool trace_turbo_json_enabled() const { return GetFlag(kTraceTurboJson); }
189
190 bool trace_turbo_graph_enabled() const { return GetFlag(kTraceTurboGraph); }
191
192 bool trace_turbo_scheduled_enabled() const {
193 return GetFlag(kTraceTurboScheduled);
194 }
195
196 // Code getters and setters.
197
198 void SetCode(Handle<Code> code) { code_ = code; }
199
200 void SetWasmCompilationResult(std::unique_ptr<wasm::WasmCompilationResult>);
201 std::unique_ptr<wasm::WasmCompilationResult> ReleaseWasmCompilationResult();
202
203 bool has_context() const;
204 Context context() const;
205
206 bool has_native_context() const;
207 Context native_context() const;
208
209 bool has_global_object() const;
210 JSGlobalObject global_object() const;
211
212 // Accessors for the different compilation modes.
213 bool IsOptimizing() const { return code_kind() == Code::OPTIMIZED_FUNCTION; }
214 bool IsWasm() const { return code_kind() == Code::WASM_FUNCTION; }
215 bool IsNotOptimizedFunctionOrWasmFunction() const {
216 return code_kind() != Code::OPTIMIZED_FUNCTION &&
217 code_kind() != Code::WASM_FUNCTION;
218 }
219 void SetOptimizingForOsr(BailoutId osr_offset, JavaScriptFrame* osr_frame) {
220 DCHECK(IsOptimizing());
221 osr_offset_ = osr_offset;
222 osr_frame_ = osr_frame;
223 }
224
225 void set_deferred_handles(std::shared_ptr<DeferredHandles> deferred_handles);
226 void set_deferred_handles(DeferredHandles* deferred_handles);
227 std::shared_ptr<DeferredHandles> deferred_handles() {
228 return deferred_handles_;
229 }
230
231 void ReopenHandlesInNewHandleScope(Isolate* isolate);
232
233 void AbortOptimization(BailoutReason reason);
234
235 void RetryOptimization(BailoutReason reason);
236
237 BailoutReason bailout_reason() const { return bailout_reason_; }
238
239 bool is_disable_future_optimization() const {
240 return GetFlag(kDisableFutureOptimization);
241 }
242
243 int optimization_id() const {
244 DCHECK(IsOptimizing());
245 return optimization_id_;
246 }
247
248 struct InlinedFunctionHolder {
249 Handle<SharedFunctionInfo> shared_info;
250 Handle<BytecodeArray> bytecode_array; // Explicit to prevent flushing.
251 InliningPosition position;
252
253 InlinedFunctionHolder(Handle<SharedFunctionInfo> inlined_shared_info,
254 Handle<BytecodeArray> inlined_bytecode,
255 SourcePosition pos);
256
257 void RegisterInlinedFunctionId(size_t inlined_function_id) {
258 position.inlined_function_id = static_cast<int>(inlined_function_id);
259 }
260 };
261
262 typedef std::vector<InlinedFunctionHolder> InlinedFunctionList;
263 InlinedFunctionList& inlined_functions() { return inlined_functions_; }
264
265 // Returns the inlining id for source position tracking.
266 int AddInlinedFunction(Handle<SharedFunctionInfo> inlined_function,
267 Handle<BytecodeArray> inlined_bytecode,
268 SourcePosition pos);
269
270 std::unique_ptr<char[]> GetDebugName() const;
271
272 StackFrame::Type GetOutputStackFrameType() const;
273
274 const char* trace_turbo_filename() const {
275 return trace_turbo_filename_.get();
276 }
277
278 void set_trace_turbo_filename(std::unique_ptr<char[]> filename) {
279 trace_turbo_filename_ = std::move(filename);
280 }
281
282 std::unique_ptr<v8::tracing::TracedValue> ToTracedValue();
283
284 private:
285 OptimizedCompilationInfo(Code::Kind code_kind, Zone* zone);
286 void ConfigureFlags();
287
288 void SetFlag(Flag flag) { flags_ |= flag; }
289 bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; }
290
291 void SetTracingFlags(bool passes_filter);
292
293 // Compilation flags.
294 unsigned flags_ = 0;
295 PoisoningMitigationLevel poisoning_level_ =
296 PoisoningMitigationLevel::kDontPoison;
297
298 Code::Kind code_kind_;
299 int32_t builtin_index_ = -1;
300
301 // We retain a reference the bytecode array specifically to ensure it doesn't
302 // get flushed while we are optimizing the code.
303 Handle<BytecodeArray> bytecode_array_;
304
305 Handle<SharedFunctionInfo> shared_info_;
306
307 Handle<JSFunction> closure_;
308
309 // The compiled code.
310 Handle<Code> code_;
311
312 // The WebAssembly compilation result, not published in the NativeModule yet.
313 std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result_;
314
315 // Entry point when compiling for OSR, {BailoutId::None} otherwise.
316 BailoutId osr_offset_ = BailoutId::None();
317
318 // The zone from which the compilation pipeline working on this
319 // OptimizedCompilationInfo allocates.
320 Zone* zone_;
321
322 std::shared_ptr<DeferredHandles> deferred_handles_;
323
324 BailoutReason bailout_reason_ = BailoutReason::kNoReason;
325
326 InlinedFunctionList inlined_functions_;
327
328 int optimization_id_ = -1;
329
330 // The current OSR frame for specialization or {nullptr}.
331 JavaScriptFrame* osr_frame_ = nullptr;
332
333 Vector<const char> debug_name_;
334 std::unique_ptr<char[]> trace_turbo_filename_;
335
336 DISALLOW_COPY_AND_ASSIGN(OptimizedCompilationInfo);
337};
338
339} // namespace internal
340} // namespace v8
341
342#endif // V8_OPTIMIZED_COMPILATION_INFO_H_
343