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
23namespace v8 {
24
25namespace tracing {
26class TracedValue;
27}  // namespace tracing
28
29namespace internal {
30
31class FunctionLiteral;
32class Isolate;
33class JavaScriptFrame;
34class JSGlobalObject;
35class Zone;
36
37namespace compiler {
38class NodeObserver;
39}
40
41namespace wasm {
42struct 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.
48class 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.
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
115  Zone* zone() { return zone_; }
116  bool is_osr() const { return !osr_offset_.IsNone(); }
117  Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
118  bool has_shared_info() const { return !shared_info().is_null(); }
119  Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
120  bool has_bytecode_array() const { return !bytecode_array_.is_null(); }
121  Handle<JSFunction> closure() const { return closure_; }
122  Handle<Code> code() const { return code_; }
123  CodeKind code_kind() const { return code_kind_; }
124  Builtin builtin() const { return builtin_; }
125  void set_builtin(Builtin builtin) { builtin_ = builtin; }
126  BytecodeOffset osr_offset() const { return osr_offset_; }
127  JavaScriptFrame* osr_frame() const { return osr_frame_; }
128  void SetNodeObserver(compiler::NodeObserver* observer) {
129    DCHECK_NULL(node_observer_);
130    node_observer_ = observer;
131  }
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.
153  bool IsOptimizing() const {
154    return CodeKindIsOptimizedJSFunction(code_kind());
155  }
156#if V8_ENABLE_WEBASSEMBLY
157  bool IsWasm() const { return code_kind() == CodeKind::WASM_FUNCTION; }
158#endif  // V8_ENABLE_WEBASSEMBLY
159
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
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
180  BailoutReason bailout_reason() const { return bailout_reason_; }
181
182  int optimization_id() const {
183    DCHECK(IsOptimizing());
184    return optimization_id_;
185  }
186
187  unsigned inlined_bytecode_size() const { return inlined_bytecode_size_; }
188
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
202    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>;
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
219  const char* trace_turbo_filename() const {
220    return trace_turbo_filename_.get();
221  }
222
223  void set_trace_turbo_filename(std::unique_ptr<char[]> filename) {
224    trace_turbo_filename_ = std::move(filename);
225  }
226
227  TickCounter& tick_counter() { return tick_counter_; }
228
229  BasicBlockProfilerData* profiler_data() const { return profiler_data_; }
230  void set_profiler_data(BasicBlockProfilerData* profiler_data) {
231    profiler_data_ = profiler_data;
232  }
233
234  std::unique_ptr<PersistentHandles> DetachPersistentHandles() {
235    DCHECK_NOT_NULL(ph_);
236    return std::move(ph_);
237  }
238
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
247  void SetFlag(Flag flag) { flags_ |= 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