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