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