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 | |
19 | namespace v8 { |
20 | |
21 | namespace tracing { |
22 | class TracedValue; |
23 | } |
24 | |
25 | namespace internal { |
26 | |
27 | class DeferredHandles; |
28 | class FunctionLiteral; |
29 | class Isolate; |
30 | class JavaScriptFrame; |
31 | class JSGlobalObject; |
32 | class Zone; |
33 | |
34 | namespace wasm { |
35 | struct 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. |
41 | class 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 | |