Line data Source code
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_COMPILATION_INFO_H_
6 : #define V8_COMPILATION_INFO_H_
7 :
8 : #include <memory>
9 :
10 : #include "src/compilation-dependencies.h"
11 : #include "src/frames.h"
12 : #include "src/globals.h"
13 : #include "src/handles.h"
14 : #include "src/objects.h"
15 : #include "src/source-position-table.h"
16 : #include "src/utils.h"
17 : #include "src/vector.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 : class DeclarationScope;
23 : class DeferredHandles;
24 : class FunctionLiteral;
25 : class JavaScriptFrame;
26 : class ParseInfo;
27 : class Isolate;
28 : class Zone;
29 :
30 : // CompilationInfo encapsulates some information known at compile time. It
31 : // is constructed based on the resources available at compile-time.
32 : class V8_EXPORT_PRIVATE CompilationInfo final {
33 : public:
34 : // Various configuration flags for a compilation, as well as some properties
35 : // of the compiled code produced by a compilation.
36 : enum Flag {
37 : kDeferredCalling = 1 << 0,
38 : kNonDeferredCalling = 1 << 1,
39 : kSavesCallerDoubles = 1 << 2,
40 : kRequiresFrame = 1 << 3,
41 : kDeoptimizationSupport = 1 << 4,
42 : kAccessorInliningEnabled = 1 << 5,
43 : kSerializing = 1 << 6,
44 : kFunctionContextSpecializing = 1 << 7,
45 : kFrameSpecializing = 1 << 8,
46 : kInliningEnabled = 1 << 9,
47 : kDisableFutureOptimization = 1 << 10,
48 : kSplittingEnabled = 1 << 11,
49 : kDeoptimizationEnabled = 1 << 12,
50 : kSourcePositionsEnabled = 1 << 13,
51 : kBailoutOnUninitialized = 1 << 14,
52 : kOptimizeFromBytecode = 1 << 15,
53 : kLoopPeelingEnabled = 1 << 16,
54 : };
55 :
56 : CompilationInfo(Zone* zone, ParseInfo* parse_info, Isolate* isolate,
57 : Handle<JSFunction> closure);
58 : CompilationInfo(Vector<const char> debug_name, Isolate* isolate, Zone* zone,
59 : Code::Flags code_flags);
60 : ~CompilationInfo();
61 :
62 : ParseInfo* parse_info() const { return parse_info_; }
63 :
64 : // -----------------------------------------------------------
65 : // TODO(titzer): inline and delete accessors of ParseInfo
66 : // -----------------------------------------------------------
67 : Handle<Script> script() const;
68 : FunctionLiteral* literal() const;
69 : DeclarationScope* scope() const;
70 : Handle<SharedFunctionInfo> shared_info() const;
71 : bool has_shared_info() const;
72 : // -----------------------------------------------------------
73 :
74 : Isolate* isolate() const { return isolate_; }
75 : Zone* zone() { return zone_; }
76 395378 : bool is_osr() const { return !osr_ast_id_.IsNone(); }
77 : Handle<JSFunction> closure() const { return closure_; }
78 : Handle<Code> code() const { return code_; }
79 : Code::Flags code_flags() const { return code_flags_; }
80 : BailoutId osr_ast_id() const { return osr_ast_id_; }
81 : JavaScriptFrame* osr_frame() const { return osr_frame_; }
82 : int num_parameters() const;
83 : int num_parameters_including_this() const;
84 : bool is_this_defined() const;
85 :
86 : void set_parameter_count(int parameter_count) {
87 : DCHECK(IsStub());
88 23533 : parameter_count_ = parameter_count;
89 : }
90 :
91 : bool has_bytecode_array() const { return !bytecode_array_.is_null(); }
92 : Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
93 :
94 : bool is_calling() const {
95 : return GetFlag(kDeferredCalling) || GetFlag(kNonDeferredCalling);
96 : }
97 :
98 : void MarkAsDeferredCalling() { SetFlag(kDeferredCalling); }
99 :
100 9002 : bool is_deferred_calling() const { return GetFlag(kDeferredCalling); }
101 :
102 : void MarkAsNonDeferredCalling() { SetFlag(kNonDeferredCalling); }
103 :
104 59968 : bool is_non_deferred_calling() const { return GetFlag(kNonDeferredCalling); }
105 :
106 : void MarkAsSavesCallerDoubles() { SetFlag(kSavesCallerDoubles); }
107 :
108 5151489 : bool saves_caller_doubles() const { return GetFlag(kSavesCallerDoubles); }
109 :
110 : void MarkAsRequiresFrame() { SetFlag(kRequiresFrame); }
111 :
112 : bool requires_frame() const { return GetFlag(kRequiresFrame); }
113 :
114 : // Compiles marked as debug produce unoptimized code with debug break slots.
115 : // Inner functions that cannot be compiled w/o context are compiled eagerly.
116 : // Always include deoptimization support to avoid having to recompile again.
117 : void MarkAsDebug() {
118 10197 : set_is_debug();
119 : SetFlag(kDeoptimizationSupport);
120 : }
121 :
122 : bool is_debug() const;
123 :
124 : void PrepareForSerializing();
125 :
126 5304808 : bool will_serialize() const { return GetFlag(kSerializing); }
127 :
128 : void MarkAsFunctionContextSpecializing() {
129 : SetFlag(kFunctionContextSpecializing);
130 : }
131 :
132 1049719 : bool is_function_context_specializing() const {
133 : return GetFlag(kFunctionContextSpecializing);
134 : }
135 :
136 : void MarkAsFrameSpecializing() { SetFlag(kFrameSpecializing); }
137 :
138 395343 : bool is_frame_specializing() const { return GetFlag(kFrameSpecializing); }
139 :
140 : void MarkAsDeoptimizationEnabled() { SetFlag(kDeoptimizationEnabled); }
141 :
142 2959893 : bool is_deoptimization_enabled() const {
143 : return GetFlag(kDeoptimizationEnabled);
144 : }
145 :
146 : void MarkAsAccessorInliningEnabled() { SetFlag(kAccessorInliningEnabled); }
147 :
148 395343 : bool is_accessor_inlining_enabled() const {
149 : return GetFlag(kAccessorInliningEnabled);
150 : }
151 :
152 : void MarkAsSourcePositionsEnabled() { SetFlag(kSourcePositionsEnabled); }
153 :
154 17546148 : bool is_source_positions_enabled() const {
155 : return GetFlag(kSourcePositionsEnabled);
156 : }
157 :
158 : void MarkAsInliningEnabled() { SetFlag(kInliningEnabled); }
159 :
160 395342 : bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); }
161 :
162 : void MarkAsSplittingEnabled() { SetFlag(kSplittingEnabled); }
163 :
164 568259 : bool is_splitting_enabled() const { return GetFlag(kSplittingEnabled); }
165 :
166 : void MarkAsBailoutOnUninitialized() { SetFlag(kBailoutOnUninitialized); }
167 :
168 38030 : bool is_bailout_on_uninitialized() const {
169 : return GetFlag(kBailoutOnUninitialized);
170 : }
171 :
172 : void MarkAsOptimizeFromBytecode() { SetFlag(kOptimizeFromBytecode); }
173 :
174 2305236 : bool is_optimizing_from_bytecode() const {
175 : return GetFlag(kOptimizeFromBytecode);
176 : }
177 :
178 : void MarkAsLoopPeelingEnabled() { SetFlag(kLoopPeelingEnabled); }
179 :
180 395303 : bool is_loop_peeling_enabled() const { return GetFlag(kLoopPeelingEnabled); }
181 :
182 2194167 : bool GeneratePreagedPrologue() const {
183 : // Generate a pre-aged prologue if we are optimizing for size, which
184 : // will make code flushing more aggressive. Only apply to Code::FUNCTION,
185 : // since StaticMarkingVisitor::IsFlushable only flushes proper functions.
186 2194193 : return FLAG_optimize_for_size && FLAG_age_code && !is_debug() &&
187 2194193 : output_code_kind() == Code::FUNCTION;
188 : }
189 :
190 4716470 : void SetCode(Handle<Code> code) { code_ = code; }
191 :
192 : void SetBytecodeArray(Handle<BytecodeArray> bytecode_array) {
193 2077425 : bytecode_array_ = bytecode_array;
194 : }
195 :
196 0 : bool ShouldTrapOnDeopt() const {
197 779377 : return (FLAG_trap_on_deopt && IsOptimizing()) ||
198 0 : (FLAG_trap_on_stub_deopt && IsStub());
199 : }
200 :
201 : bool has_context() const;
202 : Context* context() const;
203 :
204 : bool has_native_context() const;
205 : Context* native_context() const;
206 :
207 : bool has_global_object() const;
208 : JSGlobalObject* global_object() const;
209 :
210 : // Accessors for the different compilation modes.
211 : bool IsOptimizing() const { return mode_ == OPTIMIZE; }
212 0 : bool IsStub() const { return mode_ == STUB; }
213 : bool IsWasm() const { return output_code_kind() == Code::WASM_FUNCTION; }
214 : void SetOptimizing();
215 : void SetOptimizingForOsr(BailoutId osr_ast_id, JavaScriptFrame* osr_frame) {
216 797360 : SetOptimizing();
217 797359 : osr_ast_id_ = osr_ast_id;
218 797359 : osr_frame_ = osr_frame;
219 : }
220 :
221 : // Deoptimization support.
222 45576796 : bool HasDeoptimizationSupport() const {
223 : return GetFlag(kDeoptimizationSupport);
224 : }
225 : void EnableDeoptimizationSupport() {
226 : DCHECK_EQ(BASE, mode_);
227 : SetFlag(kDeoptimizationSupport);
228 : }
229 7421081 : bool ShouldEnsureSpaceForLazyDeopt() { return !IsStub(); }
230 :
231 : bool ExpectsJSReceiverAsReceiver();
232 :
233 : // Determines whether or not to insert a self-optimization header.
234 : bool ShouldSelfOptimize();
235 :
236 : void set_deferred_handles(std::shared_ptr<DeferredHandles> deferred_handles);
237 : void set_deferred_handles(DeferredHandles* deferred_handles);
238 : std::shared_ptr<DeferredHandles> deferred_handles() {
239 : return deferred_handles_;
240 : }
241 :
242 : void ReopenHandlesInNewHandleScope();
243 :
244 : void AbortOptimization(BailoutReason reason) {
245 : DCHECK(reason != kNoReason);
246 48808 : if (bailout_reason_ == kNoReason) bailout_reason_ = reason;
247 : SetFlag(kDisableFutureOptimization);
248 : }
249 :
250 159 : void RetryOptimization(BailoutReason reason) {
251 : DCHECK(reason != kNoReason);
252 159 : if (GetFlag(kDisableFutureOptimization)) return;
253 128 : bailout_reason_ = reason;
254 : }
255 :
256 : BailoutReason bailout_reason() const { return bailout_reason_; }
257 :
258 : int prologue_offset() const {
259 : DCHECK_NE(Code::kPrologueOffsetNotSet, prologue_offset_);
260 : return prologue_offset_;
261 : }
262 :
263 : void set_prologue_offset(int prologue_offset) {
264 : DCHECK_EQ(Code::kPrologueOffsetNotSet, prologue_offset_);
265 2272089 : prologue_offset_ = prologue_offset;
266 : }
267 :
268 : CompilationDependencies* dependencies() { return &dependencies_; }
269 :
270 : int optimization_id() const { return optimization_id_; }
271 :
272 : int osr_expr_stack_height() { return osr_expr_stack_height_; }
273 : void set_osr_expr_stack_height(int height) {
274 : DCHECK(height >= 0);
275 68 : osr_expr_stack_height_ = height;
276 : }
277 :
278 : bool has_simple_parameters();
279 :
280 : struct InlinedFunctionHolder {
281 : Handle<SharedFunctionInfo> shared_info;
282 :
283 : // Root that holds the unoptimized code of the inlined function alive
284 : // (and out of reach of code flushing) until we finish compilation.
285 : // Do not remove.
286 : Handle<Code> inlined_code_object_root;
287 :
288 : InliningPosition position;
289 :
290 : InlinedFunctionHolder(Handle<SharedFunctionInfo> inlined_shared_info,
291 : Handle<Code> inlined_code_object_root,
292 : SourcePosition pos)
293 : : shared_info(inlined_shared_info),
294 145428 : inlined_code_object_root(inlined_code_object_root) {
295 145428 : position.position = pos;
296 : // initialized when generating the deoptimization literals
297 145428 : position.inlined_function_id = DeoptimizationInputData::kNotInlinedIndex;
298 : }
299 :
300 : void RegisterInlinedFunctionId(size_t inlined_function_id) {
301 142976 : position.inlined_function_id = static_cast<int>(inlined_function_id);
302 : }
303 : };
304 :
305 : typedef std::vector<InlinedFunctionHolder> InlinedFunctionList;
306 : InlinedFunctionList& inlined_functions() { return inlined_functions_; }
307 :
308 : // Returns the inlining id for source position tracking.
309 : int AddInlinedFunction(Handle<SharedFunctionInfo> inlined_function,
310 : SourcePosition pos);
311 :
312 : std::unique_ptr<char[]> GetDebugName() const;
313 :
314 : Code::Kind output_code_kind() const;
315 :
316 : StackFrame::Type GetOutputStackFrameType() const;
317 :
318 : int GetDeclareGlobalsFlags() const;
319 :
320 : SourcePositionTableBuilder::RecordingMode SourcePositionRecordingMode() const;
321 :
322 : private:
323 : // Compilation mode.
324 : // BASE is generated by the full codegen, optionally prepared for bailouts.
325 : // OPTIMIZE is optimized code generated by the Hydrogen-based backend.
326 : enum Mode { BASE, OPTIMIZE, STUB };
327 :
328 : CompilationInfo(ParseInfo* parse_info, Vector<const char> debug_name,
329 : Code::Flags code_flags, Mode mode, Isolate* isolate,
330 : Zone* zone);
331 :
332 : ParseInfo* parse_info_;
333 : Isolate* isolate_;
334 :
335 802252 : void SetMode(Mode mode) { mode_ = mode; }
336 :
337 9992277 : void SetFlag(Flag flag) { flags_ |= flag; }
338 :
339 : void SetFlag(Flag flag, bool value) {
340 : flags_ = value ? flags_ | flag : flags_ & ~flag;
341 : }
342 :
343 88229724 : bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; }
344 :
345 : void set_is_debug();
346 :
347 : unsigned flags_;
348 :
349 : Code::Flags code_flags_;
350 :
351 : Handle<JSFunction> closure_;
352 :
353 : // The compiled code.
354 : Handle<Code> code_;
355 :
356 : // Compilation mode flag and whether deoptimization is allowed.
357 : Mode mode_;
358 : BailoutId osr_ast_id_;
359 :
360 : // Holds the bytecode array generated by the interpreter.
361 : // TODO(rmcilroy/mstarzinger): Temporary work-around until compiler.cc is
362 : // refactored to avoid us needing to carry the BytcodeArray around.
363 : Handle<BytecodeArray> bytecode_array_;
364 :
365 : // The zone from which the compilation pipeline working on this
366 : // CompilationInfo allocates.
367 : Zone* zone_;
368 :
369 : std::shared_ptr<DeferredHandles> deferred_handles_;
370 :
371 : // Dependencies for this compilation, e.g. stable maps.
372 : CompilationDependencies dependencies_;
373 :
374 : BailoutReason bailout_reason_;
375 :
376 : int prologue_offset_;
377 :
378 : InlinedFunctionList inlined_functions_;
379 :
380 : // Number of parameters used for compilation of stubs that require arguments.
381 : int parameter_count_;
382 :
383 : int optimization_id_;
384 :
385 : int osr_expr_stack_height_;
386 :
387 : // The current OSR frame for specialization or {nullptr}.
388 : JavaScriptFrame* osr_frame_ = nullptr;
389 :
390 : Vector<const char> debug_name_;
391 :
392 : DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
393 : };
394 :
395 : } // namespace internal
396 : } // namespace v8
397 :
398 : #endif // V8_COMPILATION_INFO_H_
|