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