• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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