8ef2e0a95b3ca19813347b7de738f1a1ae6a1cfe
[platform/upstream/nodejs.git] / deps / v8 / src / compiler.h
1 // Copyright 2012 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_COMPILER_H_
6 #define V8_COMPILER_H_
7
8 #include "src/allocation.h"
9 #include "src/ast.h"
10 #include "src/bailout-reason.h"
11 #include "src/zone.h"
12
13 namespace v8 {
14 namespace internal {
15
16 class AstValueFactory;
17 class HydrogenCodeStub;
18
19 // ParseRestriction is used to restrict the set of valid statements in a
20 // unit of compilation.  Restriction violations cause a syntax error.
21 enum ParseRestriction {
22   NO_PARSE_RESTRICTION,         // All expressions are allowed.
23   ONLY_SINGLE_FUNCTION_LITERAL  // Only a single FunctionLiteral expression.
24 };
25
26 struct OffsetRange {
27   OffsetRange(int from, int to) : from(from), to(to) {}
28   int from;
29   int to;
30 };
31
32
33 // This class encapsulates encoding and decoding of sources positions from
34 // which hydrogen values originated.
35 // When FLAG_track_hydrogen_positions is set this object encodes the
36 // identifier of the inlining and absolute offset from the start of the
37 // inlined function.
38 // When the flag is not set we simply track absolute offset from the
39 // script start.
40 class SourcePosition {
41  public:
42   SourcePosition(const SourcePosition& other) : value_(other.value_) {}
43
44   static SourcePosition Unknown() { return SourcePosition(kNoPosition); }
45
46   bool IsUnknown() const { return value_ == kNoPosition; }
47
48   uint32_t position() const { return PositionField::decode(value_); }
49   void set_position(uint32_t position) {
50     if (FLAG_hydrogen_track_positions) {
51       value_ = static_cast<uint32_t>(PositionField::update(value_, position));
52     } else {
53       value_ = position;
54     }
55   }
56
57   uint32_t inlining_id() const { return InliningIdField::decode(value_); }
58   void set_inlining_id(uint32_t inlining_id) {
59     if (FLAG_hydrogen_track_positions) {
60       value_ =
61           static_cast<uint32_t>(InliningIdField::update(value_, inlining_id));
62     }
63   }
64
65   uint32_t raw() const { return value_; }
66
67  private:
68   static const uint32_t kNoPosition =
69       static_cast<uint32_t>(RelocInfo::kNoPosition);
70   typedef BitField<uint32_t, 0, 9> InliningIdField;
71
72   // Offset from the start of the inlined function.
73   typedef BitField<uint32_t, 9, 23> PositionField;
74
75   explicit SourcePosition(uint32_t value) : value_(value) {}
76
77   friend class HPositionInfo;
78   friend class LCodeGenBase;
79
80   // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
81   // and PositionField.
82   // Otherwise contains absolute offset from the script start.
83   uint32_t value_;
84 };
85
86
87 std::ostream& operator<<(std::ostream& os, const SourcePosition& p);
88
89
90 class InlinedFunctionInfo {
91  public:
92   explicit InlinedFunctionInfo(Handle<SharedFunctionInfo> shared)
93       : shared_(shared), start_position_(shared->start_position()) {}
94
95   Handle<SharedFunctionInfo> shared() const { return shared_; }
96   int start_position() const { return start_position_; }
97
98  private:
99   Handle<SharedFunctionInfo> shared_;
100   int start_position_;
101 };
102
103
104 class ScriptData {
105  public:
106   ScriptData(const byte* data, int length);
107   ~ScriptData() {
108     if (owns_data_) DeleteArray(data_);
109   }
110
111   const byte* data() const { return data_; }
112   int length() const { return length_; }
113   bool rejected() const { return rejected_; }
114
115   void Reject() { rejected_ = true; }
116
117   void AcquireDataOwnership() {
118     DCHECK(!owns_data_);
119     owns_data_ = true;
120   }
121
122   void ReleaseDataOwnership() {
123     DCHECK(owns_data_);
124     owns_data_ = false;
125   }
126
127  private:
128   bool owns_data_ : 1;
129   bool rejected_ : 1;
130   const byte* data_;
131   int length_;
132
133   DISALLOW_COPY_AND_ASSIGN(ScriptData);
134 };
135
136 // CompilationInfo encapsulates some information known at compile time.  It
137 // is constructed based on the resources available at compile-time.
138 class CompilationInfo {
139  public:
140   // Various configuration flags for a compilation, as well as some properties
141   // of the compiled code produced by a compilation.
142   enum Flag {
143     kLazy = 1 << 0,
144     kEval = 1 << 1,
145     kGlobal = 1 << 2,
146     kStrictMode = 1 << 3,
147     kStrongMode = 1 << 4,
148     kThisHasUses = 1 << 5,
149     kNative = 1 << 6,
150     kDeferredCalling = 1 << 7,
151     kNonDeferredCalling = 1 << 8,
152     kSavesCallerDoubles = 1 << 9,
153     kRequiresFrame = 1 << 10,
154     kMustNotHaveEagerFrame = 1 << 11,
155     kDeoptimizationSupport = 1 << 12,
156     kDebug = 1 << 13,
157     kCompilingForDebugging = 1 << 14,
158     kParseRestriction = 1 << 15,
159     kSerializing = 1 << 16,
160     kContextSpecializing = 1 << 17,
161     kInliningEnabled = 1 << 18,
162     kTypingEnabled = 1 << 19,
163     kDisableFutureOptimization = 1 << 20,
164     kModule = 1 << 21,
165     kToplevel = 1 << 22,
166     kSplittingEnabled = 1 << 23
167   };
168
169   CompilationInfo(Handle<JSFunction> closure, Zone* zone);
170   CompilationInfo(Handle<Script> script, Zone* zone);
171   CompilationInfo(CodeStub* stub, Isolate* isolate, Zone* zone);
172   virtual ~CompilationInfo();
173
174   Isolate* isolate() const {
175     return isolate_;
176   }
177   Zone* zone() { return zone_; }
178   bool is_osr() const { return !osr_ast_id_.IsNone(); }
179   bool is_lazy() const { return GetFlag(kLazy); }
180   bool is_eval() const { return GetFlag(kEval); }
181   bool is_global() const { return GetFlag(kGlobal); }
182   bool is_module() const { return GetFlag(kModule); }
183   LanguageMode language_mode() const {
184     STATIC_ASSERT(LANGUAGE_END == 3);
185     return construct_language_mode(GetFlag(kStrictMode), GetFlag(kStrongMode));
186   }
187   FunctionLiteral* function() const { return function_; }
188   Scope* scope() const { return scope_; }
189   Scope* script_scope() const { return script_scope_; }
190   Handle<Code> code() const { return code_; }
191   Handle<JSFunction> closure() const { return closure_; }
192   Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
193   Handle<Script> script() const { return script_; }
194   void set_script(Handle<Script> script) { script_ = script; }
195   CodeStub* code_stub() const { return code_stub_; }
196   v8::Extension* extension() const { return extension_; }
197   ScriptData** cached_data() const { return cached_data_; }
198   ScriptCompiler::CompileOptions compile_options() const {
199     return compile_options_;
200   }
201   ScriptCompiler::ExternalSourceStream* source_stream() const {
202     return source_stream_;
203   }
204   ScriptCompiler::StreamedSource::Encoding source_stream_encoding() const {
205     return source_stream_encoding_;
206   }
207   Handle<Context> context() const { return context_; }
208   BailoutId osr_ast_id() const { return osr_ast_id_; }
209   Handle<Code> unoptimized_code() const { return unoptimized_code_; }
210   int opt_count() const { return opt_count_; }
211   int num_parameters() const;
212   int num_heap_slots() const;
213   Code::Flags flags() const;
214
215   void MarkAsEval() {
216     DCHECK(!is_lazy());
217     SetFlag(kEval);
218   }
219
220   void MarkAsGlobal() {
221     DCHECK(!is_lazy());
222     SetFlag(kGlobal);
223   }
224
225   void MarkAsModule() {
226     DCHECK(!is_lazy());
227     SetFlag(kModule);
228   }
229
230   void set_parameter_count(int parameter_count) {
231     DCHECK(IsStub());
232     parameter_count_ = parameter_count;
233   }
234
235   void set_this_has_uses(bool has_no_uses) {
236     SetFlag(kThisHasUses, has_no_uses);
237   }
238
239   bool this_has_uses() { return GetFlag(kThisHasUses); }
240
241   void SetLanguageMode(LanguageMode language_mode) {
242     STATIC_ASSERT(LANGUAGE_END == 3);
243     SetFlag(kStrictMode, language_mode & STRICT_BIT);
244     SetFlag(kStrongMode, language_mode & STRONG_BIT);
245   }
246
247   void MarkAsNative() { SetFlag(kNative); }
248
249   bool is_native() const { return GetFlag(kNative); }
250
251   bool is_calling() const {
252     return GetFlag(kDeferredCalling) || GetFlag(kNonDeferredCalling);
253   }
254
255   void MarkAsDeferredCalling() { SetFlag(kDeferredCalling); }
256
257   bool is_deferred_calling() const { return GetFlag(kDeferredCalling); }
258
259   void MarkAsNonDeferredCalling() { SetFlag(kNonDeferredCalling); }
260
261   bool is_non_deferred_calling() const { return GetFlag(kNonDeferredCalling); }
262
263   void MarkAsSavesCallerDoubles() { SetFlag(kSavesCallerDoubles); }
264
265   bool saves_caller_doubles() const { return GetFlag(kSavesCallerDoubles); }
266
267   void MarkAsRequiresFrame() { SetFlag(kRequiresFrame); }
268
269   bool requires_frame() const { return GetFlag(kRequiresFrame); }
270
271   void MarkMustNotHaveEagerFrame() { SetFlag(kMustNotHaveEagerFrame); }
272
273   bool GetMustNotHaveEagerFrame() const {
274     return GetFlag(kMustNotHaveEagerFrame);
275   }
276
277   void MarkAsDebug() { SetFlag(kDebug); }
278
279   bool is_debug() const { return GetFlag(kDebug); }
280
281   void PrepareForSerializing() { SetFlag(kSerializing); }
282
283   bool will_serialize() const { return GetFlag(kSerializing); }
284
285   void MarkAsContextSpecializing() { SetFlag(kContextSpecializing); }
286
287   bool is_context_specializing() const { return GetFlag(kContextSpecializing); }
288
289   void MarkAsInliningEnabled() { SetFlag(kInliningEnabled); }
290
291   bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); }
292
293   void MarkAsTypingEnabled() { SetFlag(kTypingEnabled); }
294
295   bool is_typing_enabled() const { return GetFlag(kTypingEnabled); }
296
297   void MarkAsToplevel() { SetFlag(kToplevel); }
298
299   bool is_toplevel() const { return GetFlag(kToplevel); }
300
301   void MarkAsSplittingEnabled() { SetFlag(kSplittingEnabled); }
302
303   bool is_splitting_enabled() const { return GetFlag(kSplittingEnabled); }
304
305   bool IsCodePreAgingActive() const {
306     return FLAG_optimize_for_size && FLAG_age_code && !will_serialize() &&
307            !is_debug();
308   }
309
310   void SetParseRestriction(ParseRestriction restriction) {
311     SetFlag(kParseRestriction, restriction != NO_PARSE_RESTRICTION);
312   }
313
314   ParseRestriction parse_restriction() const {
315     return GetFlag(kParseRestriction) ? ONLY_SINGLE_FUNCTION_LITERAL
316                                       : NO_PARSE_RESTRICTION;
317   }
318
319   void SetFunction(FunctionLiteral* literal) {
320     DCHECK(function_ == NULL);
321     function_ = literal;
322   }
323   void PrepareForCompilation(Scope* scope);
324   void SetScriptScope(Scope* script_scope) {
325     DCHECK(script_scope_ == NULL);
326     script_scope_ = script_scope;
327   }
328   void EnsureFeedbackVector();
329   Handle<TypeFeedbackVector> feedback_vector() const {
330     return feedback_vector_;
331   }
332   void SetCode(Handle<Code> code) { code_ = code; }
333   void SetExtension(v8::Extension* extension) {
334     DCHECK(!is_lazy());
335     extension_ = extension;
336   }
337   void SetCachedData(ScriptData** cached_data,
338                      ScriptCompiler::CompileOptions compile_options) {
339     compile_options_ = compile_options;
340     if (compile_options == ScriptCompiler::kNoCompileOptions) {
341       cached_data_ = NULL;
342     } else {
343       DCHECK(!is_lazy());
344       cached_data_ = cached_data;
345     }
346   }
347   void SetContext(Handle<Context> context) {
348     context_ = context;
349   }
350
351   void MarkCompilingForDebugging() { SetFlag(kCompilingForDebugging); }
352   bool IsCompilingForDebugging() { return GetFlag(kCompilingForDebugging); }
353   void MarkNonOptimizable() {
354     SetMode(CompilationInfo::NONOPT);
355   }
356
357   bool ShouldTrapOnDeopt() const {
358     return (FLAG_trap_on_deopt && IsOptimizing()) ||
359         (FLAG_trap_on_stub_deopt && IsStub());
360   }
361
362   bool has_global_object() const {
363     return !closure().is_null() &&
364         (closure()->context()->global_object() != NULL);
365   }
366
367   GlobalObject* global_object() const {
368     return has_global_object() ? closure()->context()->global_object() : NULL;
369   }
370
371   // Accessors for the different compilation modes.
372   bool IsOptimizing() const { return mode_ == OPTIMIZE; }
373   bool IsOptimizable() const { return mode_ == BASE; }
374   bool IsStub() const { return mode_ == STUB; }
375   void SetOptimizing(BailoutId osr_ast_id, Handle<Code> unoptimized) {
376     DCHECK(!shared_info_.is_null());
377     SetMode(OPTIMIZE);
378     osr_ast_id_ = osr_ast_id;
379     unoptimized_code_ = unoptimized;
380     optimization_id_ = isolate()->NextOptimizationId();
381   }
382
383   // Deoptimization support.
384   bool HasDeoptimizationSupport() const {
385     return GetFlag(kDeoptimizationSupport);
386   }
387   void EnableDeoptimizationSupport() {
388     DCHECK(IsOptimizable());
389     SetFlag(kDeoptimizationSupport);
390   }
391
392   // Determines whether or not to insert a self-optimization header.
393   bool ShouldSelfOptimize();
394
395   void set_deferred_handles(DeferredHandles* deferred_handles) {
396     DCHECK(deferred_handles_ == NULL);
397     deferred_handles_ = deferred_handles;
398   }
399
400   ZoneList<Handle<HeapObject> >* dependencies(
401       DependentCode::DependencyGroup group) {
402     if (dependencies_[group] == NULL) {
403       dependencies_[group] = new(zone_) ZoneList<Handle<HeapObject> >(2, zone_);
404     }
405     return dependencies_[group];
406   }
407
408   void CommitDependencies(Handle<Code> code);
409
410   void RollbackDependencies();
411
412   void SaveHandles() {
413     SaveHandle(&closure_);
414     SaveHandle(&shared_info_);
415     SaveHandle(&context_);
416     SaveHandle(&script_);
417     SaveHandle(&unoptimized_code_);
418   }
419
420   void AbortOptimization(BailoutReason reason) {
421     DCHECK(reason != kNoReason);
422     if (bailout_reason_ == kNoReason) bailout_reason_ = reason;
423     SetFlag(kDisableFutureOptimization);
424   }
425
426   void RetryOptimization(BailoutReason reason) {
427     DCHECK(reason != kNoReason);
428     if (GetFlag(kDisableFutureOptimization)) return;
429     bailout_reason_ = reason;
430   }
431
432   BailoutReason bailout_reason() const { return bailout_reason_; }
433
434   int prologue_offset() const {
435     DCHECK_NE(Code::kPrologueOffsetNotSet, prologue_offset_);
436     return prologue_offset_;
437   }
438
439   void set_prologue_offset(int prologue_offset) {
440     DCHECK_EQ(Code::kPrologueOffsetNotSet, prologue_offset_);
441     prologue_offset_ = prologue_offset;
442   }
443
444   // Adds offset range [from, to) where fp register does not point
445   // to the current frame base. Used in CPU profiler to detect stack
446   // samples where top frame is not set up.
447   inline void AddNoFrameRange(int from, int to) {
448     if (no_frame_ranges_) no_frame_ranges_->Add(OffsetRange(from, to));
449   }
450
451   List<OffsetRange>* ReleaseNoFrameRanges() {
452     List<OffsetRange>* result = no_frame_ranges_;
453     no_frame_ranges_ = NULL;
454     return result;
455   }
456
457   List<InlinedFunctionInfo>* inlined_function_infos() {
458     return inlined_function_infos_;
459   }
460   List<int>* inlining_id_to_function_id() {
461     return inlining_id_to_function_id_;
462   }
463   int TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
464                            SourcePosition position);
465
466   Handle<Foreign> object_wrapper() {
467     if (object_wrapper_.is_null()) {
468       object_wrapper_ =
469           isolate()->factory()->NewForeign(reinterpret_cast<Address>(this));
470     }
471     return object_wrapper_;
472   }
473
474   void AbortDueToDependencyChange() {
475     DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
476     aborted_due_to_dependency_change_ = true;
477   }
478
479   bool HasAbortedDueToDependencyChange() const {
480     DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
481     return aborted_due_to_dependency_change_;
482   }
483
484   bool HasSameOsrEntry(Handle<JSFunction> function, BailoutId osr_ast_id) {
485     return osr_ast_id_ == osr_ast_id && function.is_identical_to(closure_);
486   }
487
488   int optimization_id() const { return optimization_id_; }
489
490   AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
491   void SetAstValueFactory(AstValueFactory* ast_value_factory,
492                           bool owned = true) {
493     ast_value_factory_ = ast_value_factory;
494     ast_value_factory_owned_ = owned;
495   }
496
497   int osr_expr_stack_height() { return osr_expr_stack_height_; }
498   void set_osr_expr_stack_height(int height) {
499     DCHECK(height >= 0);
500     osr_expr_stack_height_ = height;
501   }
502
503 #if DEBUG
504   void PrintAstForTesting();
505 #endif
506
507   bool is_simple_parameter_list();
508
509  protected:
510   CompilationInfo(Handle<SharedFunctionInfo> shared_info,
511                   Zone* zone);
512   CompilationInfo(ScriptCompiler::ExternalSourceStream* source_stream,
513                   ScriptCompiler::StreamedSource::Encoding encoding,
514                   Isolate* isolate, Zone* zone);
515
516
517  private:
518   Isolate* isolate_;
519
520   // Compilation mode.
521   // BASE is generated by the full codegen, optionally prepared for bailouts.
522   // OPTIMIZE is optimized code generated by the Hydrogen-based backend.
523   // NONOPT is generated by the full codegen and is not prepared for
524   //   recompilation/bailouts.  These functions are never recompiled.
525   enum Mode {
526     BASE,
527     OPTIMIZE,
528     NONOPT,
529     STUB
530   };
531
532   void Initialize(Isolate* isolate, Mode mode, Zone* zone);
533
534   void SetMode(Mode mode) {
535     mode_ = mode;
536   }
537
538   void SetFlag(Flag flag) { flags_ |= flag; }
539
540   void SetFlag(Flag flag, bool value) {
541     flags_ = value ? flags_ | flag : flags_ & ~flag;
542   }
543
544   bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; }
545
546   unsigned flags_;
547
548   // Fields filled in by the compilation pipeline.
549   // AST filled in by the parser.
550   FunctionLiteral* function_;
551   // The scope of the function literal as a convenience.  Set to indicate
552   // that scopes have been analyzed.
553   Scope* scope_;
554   // The script scope provided as a convenience.
555   Scope* script_scope_;
556   // For compiled stubs, the stub object
557   CodeStub* code_stub_;
558   // The compiled code.
559   Handle<Code> code_;
560
561   // Possible initial inputs to the compilation process.
562   Handle<JSFunction> closure_;
563   Handle<SharedFunctionInfo> shared_info_;
564   Handle<Script> script_;
565   ScriptCompiler::ExternalSourceStream* source_stream_;  // Not owned.
566   ScriptCompiler::StreamedSource::Encoding source_stream_encoding_;
567
568   // Fields possibly needed for eager compilation, NULL by default.
569   v8::Extension* extension_;
570   ScriptData** cached_data_;
571   ScriptCompiler::CompileOptions compile_options_;
572
573   // The context of the caller for eval code, and the script context for a
574   // global script. Will be a null handle otherwise.
575   Handle<Context> context_;
576
577   // Used by codegen, ultimately kept rooted by the SharedFunctionInfo.
578   Handle<TypeFeedbackVector> feedback_vector_;
579
580   // Compilation mode flag and whether deoptimization is allowed.
581   Mode mode_;
582   BailoutId osr_ast_id_;
583   // The unoptimized code we patched for OSR may not be the shared code
584   // afterwards, since we may need to compile it again to include deoptimization
585   // data.  Keep track which code we patched.
586   Handle<Code> unoptimized_code_;
587
588   // The zone from which the compilation pipeline working on this
589   // CompilationInfo allocates.
590   Zone* zone_;
591
592   DeferredHandles* deferred_handles_;
593
594   ZoneList<Handle<HeapObject> >* dependencies_[DependentCode::kGroupCount];
595
596   template<typename T>
597   void SaveHandle(Handle<T> *object) {
598     if (!object->is_null()) {
599       Handle<T> handle(*(*object));
600       *object = handle;
601     }
602   }
603
604   BailoutReason bailout_reason_;
605
606   int prologue_offset_;
607
608   List<OffsetRange>* no_frame_ranges_;
609   List<InlinedFunctionInfo>* inlined_function_infos_;
610   List<int>* inlining_id_to_function_id_;
611
612   // A copy of shared_info()->opt_count() to avoid handle deref
613   // during graph optimization.
614   int opt_count_;
615
616   // Number of parameters used for compilation of stubs that require arguments.
617   int parameter_count_;
618
619   Handle<Foreign> object_wrapper_;
620
621   int optimization_id_;
622
623   AstValueFactory* ast_value_factory_;
624   bool ast_value_factory_owned_;
625
626   // This flag is used by the main thread to track whether this compilation
627   // should be abandoned due to dependency change.
628   bool aborted_due_to_dependency_change_;
629
630   int osr_expr_stack_height_;
631
632   DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
633 };
634
635
636 // Exactly like a CompilationInfo, except also creates and enters a
637 // Zone on construction and deallocates it on exit.
638 class CompilationInfoWithZone: public CompilationInfo {
639  public:
640   explicit CompilationInfoWithZone(Handle<Script> script)
641       : CompilationInfo(script, &zone_) {}
642   explicit CompilationInfoWithZone(Handle<SharedFunctionInfo> shared_info)
643       : CompilationInfo(shared_info, &zone_) {}
644   explicit CompilationInfoWithZone(Handle<JSFunction> closure)
645       : CompilationInfo(closure, &zone_) {}
646   CompilationInfoWithZone(CodeStub* stub, Isolate* isolate)
647       : CompilationInfo(stub, isolate, &zone_) {}
648   CompilationInfoWithZone(ScriptCompiler::ExternalSourceStream* stream,
649                           ScriptCompiler::StreamedSource::Encoding encoding,
650                           Isolate* isolate)
651       : CompilationInfo(stream, encoding, isolate, &zone_) {}
652
653   // Virtual destructor because a CompilationInfoWithZone has to exit the
654   // zone scope and get rid of dependent maps even when the destructor is
655   // called when cast as a CompilationInfo.
656   virtual ~CompilationInfoWithZone() {
657     RollbackDependencies();
658   }
659
660  private:
661   Zone zone_;
662 };
663
664
665 // A wrapper around a CompilationInfo that detaches the Handles from
666 // the underlying DeferredHandleScope and stores them in info_ on
667 // destruction.
668 class CompilationHandleScope BASE_EMBEDDED {
669  public:
670   explicit CompilationHandleScope(CompilationInfo* info)
671       : deferred_(info->isolate()), info_(info) {}
672   ~CompilationHandleScope() {
673     info_->set_deferred_handles(deferred_.Detach());
674   }
675
676  private:
677   DeferredHandleScope deferred_;
678   CompilationInfo* info_;
679 };
680
681
682 class HGraph;
683 class HOptimizedGraphBuilder;
684 class LChunk;
685
686 // A helper class that calls the three compilation phases in
687 // Crankshaft and keeps track of its state.  The three phases
688 // CreateGraph, OptimizeGraph and GenerateAndInstallCode can either
689 // fail, bail-out to the full code generator or succeed.  Apart from
690 // their return value, the status of the phase last run can be checked
691 // using last_status().
692 class OptimizedCompileJob: public ZoneObject {
693  public:
694   explicit OptimizedCompileJob(CompilationInfo* info)
695       : info_(info),
696         graph_builder_(NULL),
697         graph_(NULL),
698         chunk_(NULL),
699         last_status_(FAILED),
700         awaiting_install_(false) { }
701
702   enum Status {
703     FAILED, BAILED_OUT, SUCCEEDED
704   };
705
706   MUST_USE_RESULT Status CreateGraph();
707   MUST_USE_RESULT Status OptimizeGraph();
708   MUST_USE_RESULT Status GenerateCode();
709
710   Status last_status() const { return last_status_; }
711   CompilationInfo* info() const { return info_; }
712   Isolate* isolate() const { return info()->isolate(); }
713
714   Status RetryOptimization(BailoutReason reason) {
715     info_->RetryOptimization(reason);
716     return SetLastStatus(BAILED_OUT);
717   }
718
719   Status AbortOptimization(BailoutReason reason) {
720     info_->AbortOptimization(reason);
721     return SetLastStatus(BAILED_OUT);
722   }
723
724   void WaitForInstall() {
725     DCHECK(info_->is_osr());
726     awaiting_install_ = true;
727   }
728
729   bool IsWaitingForInstall() { return awaiting_install_; }
730
731  private:
732   CompilationInfo* info_;
733   HOptimizedGraphBuilder* graph_builder_;
734   HGraph* graph_;
735   LChunk* chunk_;
736   base::TimeDelta time_taken_to_create_graph_;
737   base::TimeDelta time_taken_to_optimize_;
738   base::TimeDelta time_taken_to_codegen_;
739   Status last_status_;
740   bool awaiting_install_;
741
742   MUST_USE_RESULT Status SetLastStatus(Status status) {
743     last_status_ = status;
744     return last_status_;
745   }
746   void RecordOptimizationStats();
747
748   struct Timer {
749     Timer(OptimizedCompileJob* job, base::TimeDelta* location)
750         : job_(job), location_(location) {
751       DCHECK(location_ != NULL);
752       timer_.Start();
753     }
754
755     ~Timer() {
756       *location_ += timer_.Elapsed();
757     }
758
759     OptimizedCompileJob* job_;
760     base::ElapsedTimer timer_;
761     base::TimeDelta* location_;
762   };
763 };
764
765
766 // The V8 compiler
767 //
768 // General strategy: Source code is translated into an anonymous function w/o
769 // parameters which then can be executed. If the source code contains other
770 // functions, they will be compiled and allocated as part of the compilation
771 // of the source code.
772
773 // Please note this interface returns shared function infos.  This means you
774 // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a
775 // real function with a context.
776
777 class Compiler : public AllStatic {
778  public:
779   MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCode(
780       Handle<JSFunction> function);
781   MUST_USE_RESULT static MaybeHandle<Code> GetLazyCode(
782       Handle<JSFunction> function);
783   MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCode(
784       Handle<SharedFunctionInfo> shared);
785   MUST_USE_RESULT static MaybeHandle<Code> GetDebugCode(
786       Handle<JSFunction> function);
787
788   // Parser::Parse, then Compiler::Analyze.
789   static bool ParseAndAnalyze(CompilationInfo* info);
790   // Rewrite, analyze scopes, and renumber.
791   static bool Analyze(CompilationInfo* info);
792   // Adds deoptimization support, requires ParseAndAnalyze.
793   static bool EnsureDeoptimizationSupport(CompilationInfo* info);
794
795   static bool EnsureCompiled(Handle<JSFunction> function,
796                              ClearExceptionFlag flag);
797
798   static void CompileForLiveEdit(Handle<Script> script);
799
800   // Compile a String source within a context for eval.
801   MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
802       Handle<String> source, Handle<SharedFunctionInfo> outer_info,
803       Handle<Context> context, LanguageMode language_mode,
804       ParseRestriction restriction, int scope_position);
805
806   // Compile a String source within a context.
807   static Handle<SharedFunctionInfo> CompileScript(
808       Handle<String> source, Handle<Object> script_name, int line_offset,
809       int column_offset, bool is_debugger_script, bool is_shared_cross_origin,
810       Handle<Context> context, v8::Extension* extension,
811       ScriptData** cached_data, ScriptCompiler::CompileOptions compile_options,
812       NativesFlag is_natives_code, bool is_module);
813
814   static Handle<SharedFunctionInfo> CompileStreamedScript(CompilationInfo* info,
815                                                           int source_length);
816
817   // Create a shared function info object (the code may be lazily compiled).
818   static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node,
819                                                       Handle<Script> script,
820                                                       CompilationInfo* outer);
821
822   enum ConcurrencyMode { NOT_CONCURRENT, CONCURRENT };
823
824   // Generate and return optimized code or start a concurrent optimization job.
825   // In the latter case, return the InOptimizationQueue builtin.  On failure,
826   // return the empty handle.
827   MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCode(
828       Handle<JSFunction> function,
829       Handle<Code> current_code,
830       ConcurrencyMode mode,
831       BailoutId osr_ast_id = BailoutId::None());
832
833   // Generate and return code from previously queued optimization job.
834   // On failure, return the empty handle.
835   static Handle<Code> GetConcurrentlyOptimizedCode(OptimizedCompileJob* job);
836
837   static bool DebuggerWantsEagerCompilation(
838       CompilationInfo* info, bool allow_lazy_without_ctx = false);
839 };
840
841
842 class CompilationPhase BASE_EMBEDDED {
843  public:
844   CompilationPhase(const char* name, CompilationInfo* info);
845   ~CompilationPhase();
846
847  protected:
848   bool ShouldProduceTraceOutput() const;
849
850   const char* name() const { return name_; }
851   CompilationInfo* info() const { return info_; }
852   Isolate* isolate() const { return info()->isolate(); }
853   Zone* zone() { return &zone_; }
854
855  private:
856   const char* name_;
857   CompilationInfo* info_;
858   Zone zone_;
859   size_t info_zone_start_allocation_size_;
860   base::ElapsedTimer timer_;
861
862   DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
863 };
864
865 } }  // namespace v8::internal
866
867 #endif  // V8_COMPILER_H_