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/base/vector.h" 11 #include "src/codegen/bailout-reason.h" 12 #include "src/codegen/source-position-table.h" 13 #include "src/codegen/tick-counter.h" 14 #include "src/common/globals.h" 15 #include "src/diagnostics/basic-block-profiler.h" 16 #include "src/execution/frames.h" 17 #include "src/handles/handles.h" 18 #include "src/handles/persistent-handles.h" 19 #include "src/objects/objects.h" 20 #include "src/utils/identity-map.h" 21 #include "src/utils/utils.h" 22 23 namespace v8 { 24 25 namespace tracing { 26 class TracedValue; 27 } // namespace tracing 28 29 namespace internal { 30 31 class FunctionLiteral; 32 class Isolate; 33 class JavaScriptFrame; 34 class JSGlobalObject; 35 class Zone; 36 37 namespace compiler { 38 class NodeObserver; 39 } 40 41 namespace wasm { 42 struct WasmCompilationResult; 43 } // namespace wasm 44 45 // OptimizedCompilationInfo encapsulates the information needed to compile 46 // optimized code for a given function, and the results of the optimized 47 // compilation. 48 class V8_EXPORT_PRIVATE OptimizedCompilationInfo final { 49 public: 50 // Various configuration flags for a compilation, as well as some properties 51 // of the compiled code produced by a compilation. 52 53 #define FLAGS(V) \ 54 V(FunctionContextSpecializing, function_context_specializing, 0) \ 55 V(Inlining, inlining, 1) \ 56 V(DisableFutureOptimization, disable_future_optimization, 2) \ 57 V(Splitting, splitting, 3) \ 58 V(SourcePositions, source_positions, 4) \ 59 V(BailoutOnUninitialized, bailout_on_uninitialized, 5) \ 60 V(LoopPeeling, loop_peeling, 6) \ 61 V(SwitchJumpTable, switch_jump_table, 7) \ 62 V(CalledWithCodeStartRegister, called_with_code_start_register, 8) \ 63 V(AllocationFolding, allocation_folding, 9) \ 64 V(AnalyzeEnvironmentLiveness, analyze_environment_liveness, 10) \ 65 V(TraceTurboJson, trace_turbo_json, 11) \ 66 V(TraceTurboGraph, trace_turbo_graph, 12) \ 67 V(TraceTurboScheduled, trace_turbo_scheduled, 13) \ 68 V(TraceTurboAllocation, trace_turbo_allocation, 14) \ 69 V(TraceHeapBroker, trace_heap_broker, 15) \ 70 V(WasmRuntimeExceptionSupport, wasm_runtime_exception_support, 16) \ 71 V(DiscardResultForTesting, discard_result_for_testing, 17) \ 72 V(InlineJSWasmCalls, inline_js_wasm_calls, 18) 73 74 enum Flag { 75 #define DEF_ENUM(Camel, Lower, Bit) k##Camel = 1 << Bit, 76 FLAGS(DEF_ENUM) 77 #undef DEF_ENUM 78 }; 79 80 #define DEF_GETTER(Camel, Lower, Bit) \ 81 bool Lower() const { \ 82 return GetFlag(k##Camel); \ 83 } 84 FLAGS(DEF_GETTER) 85 #undef DEF_GETTER 86 87 #define DEF_SETTER(Camel, Lower, Bit) \ 88 void set_##Lower() { \ 89 SetFlag(k##Camel); \ 90 } 91 FLAGS(DEF_SETTER) 92 #undef DEF_SETTER 93 94 // Construct a compilation info for optimized compilation. 95 OptimizedCompilationInfo(Zone* zone, Isolate* isolate, 96 Handle<SharedFunctionInfo> shared, 97 Handle<JSFunction> closure, CodeKind code_kind, 98 BytecodeOffset osr_offset, 99 JavaScriptFrame* osr_frame); 100 // For testing. OptimizedCompilationInfo(Zone * zone,Isolate * isolate,Handle<SharedFunctionInfo> shared,Handle<JSFunction> closure,CodeKind code_kind)101 OptimizedCompilationInfo(Zone* zone, Isolate* isolate, 102 Handle<SharedFunctionInfo> shared, 103 Handle<JSFunction> closure, CodeKind code_kind) 104 : OptimizedCompilationInfo(zone, isolate, shared, closure, code_kind, 105 BytecodeOffset::None(), nullptr) {} 106 // Construct a compilation info for stub compilation, Wasm, and testing. 107 OptimizedCompilationInfo(base::Vector<const char> debug_name, Zone* zone, 108 CodeKind code_kind); 109 110 OptimizedCompilationInfo(const OptimizedCompilationInfo&) = delete; 111 OptimizedCompilationInfo& operator=(const OptimizedCompilationInfo&) = delete; 112 113 ~OptimizedCompilationInfo(); 114 zone()115 Zone* zone() { return zone_; } is_osr()116 bool is_osr() const { return !osr_offset_.IsNone(); } shared_info()117 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } has_shared_info()118 bool has_shared_info() const { return !shared_info().is_null(); } bytecode_array()119 Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; } has_bytecode_array()120 bool has_bytecode_array() const { return !bytecode_array_.is_null(); } closure()121 Handle<JSFunction> closure() const { return closure_; } code()122 Handle<Code> code() const { return code_; } code_kind()123 CodeKind code_kind() const { return code_kind_; } builtin()124 Builtin builtin() const { return builtin_; } set_builtin(Builtin builtin)125 void set_builtin(Builtin builtin) { builtin_ = builtin; } osr_offset()126 BytecodeOffset osr_offset() const { return osr_offset_; } osr_frame()127 JavaScriptFrame* osr_frame() const { return osr_frame_; } SetNodeObserver(compiler::NodeObserver * observer)128 void SetNodeObserver(compiler::NodeObserver* observer) { 129 DCHECK_NULL(node_observer_); 130 node_observer_ = observer; 131 } node_observer()132 compiler::NodeObserver* node_observer() const { return node_observer_; } 133 134 // Code getters and setters. 135 136 void SetCode(Handle<Code> code); 137 138 #if V8_ENABLE_WEBASSEMBLY 139 void SetWasmCompilationResult(std::unique_ptr<wasm::WasmCompilationResult>); 140 std::unique_ptr<wasm::WasmCompilationResult> ReleaseWasmCompilationResult(); 141 #endif // V8_ENABLE_WEBASSEMBLY 142 143 bool has_context() const; 144 Context context() const; 145 146 bool has_native_context() const; 147 NativeContext native_context() const; 148 149 bool has_global_object() const; 150 JSGlobalObject global_object() const; 151 152 // Accessors for the different compilation modes. IsOptimizing()153 bool IsOptimizing() const { 154 return CodeKindIsOptimizedJSFunction(code_kind()); 155 } 156 #if V8_ENABLE_WEBASSEMBLY IsWasm()157 bool IsWasm() const { return code_kind() == CodeKind::WASM_FUNCTION; } 158 #endif // V8_ENABLE_WEBASSEMBLY 159 set_persistent_handles(std::unique_ptr<PersistentHandles> persistent_handles)160 void set_persistent_handles( 161 std::unique_ptr<PersistentHandles> persistent_handles) { 162 DCHECK_NULL(ph_); 163 ph_ = std::move(persistent_handles); 164 DCHECK_NOT_NULL(ph_); 165 } 166 set_canonical_handles(std::unique_ptr<CanonicalHandlesMap> canonical_handles)167 void set_canonical_handles( 168 std::unique_ptr<CanonicalHandlesMap> canonical_handles) { 169 DCHECK_NULL(canonical_handles_); 170 canonical_handles_ = std::move(canonical_handles); 171 DCHECK_NOT_NULL(canonical_handles_); 172 } 173 174 void ReopenHandlesInNewHandleScope(Isolate* isolate); 175 176 void AbortOptimization(BailoutReason reason); 177 178 void RetryOptimization(BailoutReason reason); 179 bailout_reason()180 BailoutReason bailout_reason() const { return bailout_reason_; } 181 optimization_id()182 int optimization_id() const { 183 DCHECK(IsOptimizing()); 184 return optimization_id_; 185 } 186 inlined_bytecode_size()187 unsigned inlined_bytecode_size() const { return inlined_bytecode_size_; } 188 set_inlined_bytecode_size(unsigned size)189 void set_inlined_bytecode_size(unsigned size) { 190 inlined_bytecode_size_ = size; 191 } 192 193 struct InlinedFunctionHolder { 194 Handle<SharedFunctionInfo> shared_info; 195 Handle<BytecodeArray> bytecode_array; // Explicit to prevent flushing. 196 InliningPosition position; 197 198 InlinedFunctionHolder(Handle<SharedFunctionInfo> inlined_shared_info, 199 Handle<BytecodeArray> inlined_bytecode, 200 SourcePosition pos); 201 RegisterInlinedFunctionIdInlinedFunctionHolder202 void RegisterInlinedFunctionId(size_t inlined_function_id) { 203 position.inlined_function_id = static_cast<int>(inlined_function_id); 204 } 205 }; 206 207 using InlinedFunctionList = std::vector<InlinedFunctionHolder>; inlined_functions()208 InlinedFunctionList& inlined_functions() { return inlined_functions_; } 209 210 // Returns the inlining id for source position tracking. 211 int AddInlinedFunction(Handle<SharedFunctionInfo> inlined_function, 212 Handle<BytecodeArray> inlined_bytecode, 213 SourcePosition pos); 214 215 std::unique_ptr<char[]> GetDebugName() const; 216 217 StackFrame::Type GetOutputStackFrameType() const; 218 trace_turbo_filename()219 const char* trace_turbo_filename() const { 220 return trace_turbo_filename_.get(); 221 } 222 set_trace_turbo_filename(std::unique_ptr<char[]> filename)223 void set_trace_turbo_filename(std::unique_ptr<char[]> filename) { 224 trace_turbo_filename_ = std::move(filename); 225 } 226 tick_counter()227 TickCounter& tick_counter() { return tick_counter_; } 228 profiler_data()229 BasicBlockProfilerData* profiler_data() const { return profiler_data_; } set_profiler_data(BasicBlockProfilerData * profiler_data)230 void set_profiler_data(BasicBlockProfilerData* profiler_data) { 231 profiler_data_ = profiler_data; 232 } 233 DetachPersistentHandles()234 std::unique_ptr<PersistentHandles> DetachPersistentHandles() { 235 DCHECK_NOT_NULL(ph_); 236 return std::move(ph_); 237 } 238 DetachCanonicalHandles()239 std::unique_ptr<CanonicalHandlesMap> DetachCanonicalHandles() { 240 DCHECK_NOT_NULL(canonical_handles_); 241 return std::move(canonical_handles_); 242 } 243 244 private: 245 void ConfigureFlags(); 246 SetFlag(Flag flag)247 void SetFlag(Flag flag) { flags_ |= flag; } GetFlag(Flag flag)248 bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; } 249 250 void SetTracingFlags(bool passes_filter); 251 252 // Compilation flags. 253 unsigned flags_ = 0; 254 255 const CodeKind code_kind_; 256 Builtin builtin_ = Builtin::kNoBuiltinId; 257 258 // We retain a reference the bytecode array specifically to ensure it doesn't 259 // get flushed while we are optimizing the code. 260 Handle<BytecodeArray> bytecode_array_; 261 Handle<SharedFunctionInfo> shared_info_; 262 Handle<JSFunction> closure_; 263 264 // The compiled code. 265 Handle<Code> code_; 266 267 // Basic block profiling support. 268 BasicBlockProfilerData* profiler_data_ = nullptr; 269 270 #if V8_ENABLE_WEBASSEMBLY 271 // The WebAssembly compilation result, not published in the NativeModule yet. 272 std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result_; 273 #endif // V8_ENABLE_WEBASSEMBLY 274 275 // Entry point when compiling for OSR, {BytecodeOffset::None} otherwise. 276 const BytecodeOffset osr_offset_ = BytecodeOffset::None(); 277 // The current OSR frame for specialization or {nullptr}. 278 JavaScriptFrame* const osr_frame_ = nullptr; 279 280 // The zone from which the compilation pipeline working on this 281 // OptimizedCompilationInfo allocates. 282 Zone* const zone_; 283 284 compiler::NodeObserver* node_observer_ = nullptr; 285 286 BailoutReason bailout_reason_ = BailoutReason::kNoReason; 287 288 InlinedFunctionList inlined_functions_; 289 290 static constexpr int kNoOptimizationId = -1; 291 const int optimization_id_; 292 unsigned inlined_bytecode_size_ = 0; 293 294 base::Vector<const char> debug_name_; 295 std::unique_ptr<char[]> trace_turbo_filename_; 296 297 TickCounter tick_counter_; 298 299 // 1) PersistentHandles created via PersistentHandlesScope inside of 300 // CompilationHandleScope 301 // 2) Owned by OptimizedCompilationInfo 302 // 3) Owned by the broker's LocalHeap when entering the LocalHeapScope. 303 // 4) Back to OptimizedCompilationInfo when exiting the LocalHeapScope. 304 // 305 // In normal execution it gets destroyed when PipelineData gets destroyed. 306 // There is a special case in GenerateCodeForTesting where the JSHeapBroker 307 // will not be retired in that same method. In this case, we need to re-attach 308 // the PersistentHandles container to the JSHeapBroker. 309 std::unique_ptr<PersistentHandles> ph_; 310 311 // Canonical handles follow the same path as described by the persistent 312 // handles above. The only difference is that is created in the 313 // CanonicalHandleScope(i.e step 1) is different). 314 std::unique_ptr<CanonicalHandlesMap> canonical_handles_; 315 }; 316 317 } // namespace internal 318 } // namespace v8 319 320 #endif // V8_CODEGEN_OPTIMIZED_COMPILATION_INFO_H_ 321