• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_HYDROGEN_H_
29 #define V8_HYDROGEN_H_
30 
31 #include "v8.h"
32 
33 #include "allocation.h"
34 #include "ast.h"
35 #include "compiler.h"
36 #include "hydrogen-instructions.h"
37 #include "type-info.h"
38 #include "zone.h"
39 
40 namespace v8 {
41 namespace internal {
42 
43 // Forward declarations.
44 class BitVector;
45 class HEnvironment;
46 class HGraph;
47 class HLoopInformation;
48 class HTracer;
49 class LAllocator;
50 class LChunk;
51 class LiveRange;
52 
53 
54 class HBasicBlock: public ZoneObject {
55  public:
56   explicit HBasicBlock(HGraph* graph);
~HBasicBlock()57   virtual ~HBasicBlock() { }
58 
59   // Simple accessors.
block_id()60   int block_id() const { return block_id_; }
set_block_id(int id)61   void set_block_id(int id) { block_id_ = id; }
graph()62   HGraph* graph() const { return graph_; }
phis()63   const ZoneList<HPhi*>* phis() const { return &phis_; }
first()64   HInstruction* first() const { return first_; }
last()65   HInstruction* last() const { return last_; }
set_last(HInstruction * instr)66   void set_last(HInstruction* instr) { last_ = instr; }
67   HInstruction* GetLastInstruction();
end()68   HControlInstruction* end() const { return end_; }
loop_information()69   HLoopInformation* loop_information() const { return loop_information_; }
predecessors()70   const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
HasPredecessor()71   bool HasPredecessor() const { return predecessors_.length() > 0; }
dominated_blocks()72   const ZoneList<HBasicBlock*>* dominated_blocks() const {
73     return &dominated_blocks_;
74   }
deleted_phis()75   const ZoneList<int>* deleted_phis() const {
76     return &deleted_phis_;
77   }
RecordDeletedPhi(int merge_index)78   void RecordDeletedPhi(int merge_index) {
79     deleted_phis_.Add(merge_index);
80   }
dominator()81   HBasicBlock* dominator() const { return dominator_; }
last_environment()82   HEnvironment* last_environment() const { return last_environment_; }
argument_count()83   int argument_count() const { return argument_count_; }
set_argument_count(int count)84   void set_argument_count(int count) { argument_count_ = count; }
first_instruction_index()85   int first_instruction_index() const { return first_instruction_index_; }
set_first_instruction_index(int index)86   void set_first_instruction_index(int index) {
87     first_instruction_index_ = index;
88   }
last_instruction_index()89   int last_instruction_index() const { return last_instruction_index_; }
set_last_instruction_index(int index)90   void set_last_instruction_index(int index) {
91     last_instruction_index_ = index;
92   }
93 
94   void AttachLoopInformation();
95   void DetachLoopInformation();
IsLoopHeader()96   bool IsLoopHeader() const { return loop_information() != NULL; }
IsStartBlock()97   bool IsStartBlock() const { return block_id() == 0; }
98   void PostProcessLoopHeader(IterationStatement* stmt);
99 
IsFinished()100   bool IsFinished() const { return end_ != NULL; }
101   void AddPhi(HPhi* phi);
102   void RemovePhi(HPhi* phi);
103   void AddInstruction(HInstruction* instr);
104   bool Dominates(HBasicBlock* other) const;
105   int LoopNestingDepth() const;
106 
107   void SetInitialEnvironment(HEnvironment* env);
ClearEnvironment()108   void ClearEnvironment() { last_environment_ = NULL; }
HasEnvironment()109   bool HasEnvironment() const { return last_environment_ != NULL; }
UpdateEnvironment(HEnvironment * env)110   void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
parent_loop_header()111   HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
112 
set_parent_loop_header(HBasicBlock * block)113   void set_parent_loop_header(HBasicBlock* block) {
114     ASSERT(parent_loop_header_ == NULL);
115     parent_loop_header_ = block;
116   }
117 
HasParentLoopHeader()118   bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
119 
120   void SetJoinId(int ast_id);
121 
122   void Finish(HControlInstruction* last);
123   void FinishExit(HControlInstruction* instruction);
124   void Goto(HBasicBlock* block, bool drop_extra = false);
125 
126   int PredecessorIndexOf(HBasicBlock* predecessor) const;
AddSimulate(int ast_id)127   void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
128   void AssignCommonDominator(HBasicBlock* other);
129   void AssignLoopSuccessorDominators();
130 
FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses)131   void FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses) {
132     FinishExit(CreateDeoptimize(has_uses));
133   }
134 
135   // Add the inlined function exit sequence, adding an HLeaveInlined
136   // instruction and updating the bailout environment.
137   void AddLeaveInlined(HValue* return_value,
138                        HBasicBlock* target,
139                        bool drop_extra = false);
140 
141   // If a target block is tagged as an inline function return, all
142   // predecessors should contain the inlined exit sequence:
143   //
144   // LeaveInlined
145   // Simulate (caller's environment)
146   // Goto (target block)
IsInlineReturnTarget()147   bool IsInlineReturnTarget() const { return is_inline_return_target_; }
MarkAsInlineReturnTarget()148   void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
149 
IsDeoptimizing()150   bool IsDeoptimizing() const { return is_deoptimizing_; }
MarkAsDeoptimizing()151   void MarkAsDeoptimizing() { is_deoptimizing_ = true; }
152 
IsLoopSuccessorDominator()153   bool IsLoopSuccessorDominator() const {
154     return dominates_loop_successors_;
155   }
MarkAsLoopSuccessorDominator()156   void MarkAsLoopSuccessorDominator() {
157     dominates_loop_successors_ = true;
158   }
159 
160   inline Zone* zone();
161 
162 #ifdef DEBUG
163   void Verify();
164 #endif
165 
166  private:
167   void RegisterPredecessor(HBasicBlock* pred);
168   void AddDominatedBlock(HBasicBlock* block);
169 
170   HSimulate* CreateSimulate(int ast_id);
171   HDeoptimize* CreateDeoptimize(HDeoptimize::UseEnvironment has_uses);
172 
173   int block_id_;
174   HGraph* graph_;
175   ZoneList<HPhi*> phis_;
176   HInstruction* first_;
177   HInstruction* last_;
178   HControlInstruction* end_;
179   HLoopInformation* loop_information_;
180   ZoneList<HBasicBlock*> predecessors_;
181   HBasicBlock* dominator_;
182   ZoneList<HBasicBlock*> dominated_blocks_;
183   HEnvironment* last_environment_;
184   // Outgoing parameter count at block exit, set during lithium translation.
185   int argument_count_;
186   // Instruction indices into the lithium code stream.
187   int first_instruction_index_;
188   int last_instruction_index_;
189   ZoneList<int> deleted_phis_;
190   HBasicBlock* parent_loop_header_;
191   bool is_inline_return_target_;
192   bool is_deoptimizing_;
193   bool dominates_loop_successors_;
194 };
195 
196 
197 class HPredecessorIterator BASE_EMBEDDED {
198  public:
HPredecessorIterator(HBasicBlock * block)199   explicit HPredecessorIterator(HBasicBlock* block)
200       : predecessor_list_(block->predecessors()), current_(0) { }
201 
Done()202   bool Done() { return current_ >= predecessor_list_->length(); }
Current()203   HBasicBlock* Current() { return predecessor_list_->at(current_); }
Advance()204   void Advance() { current_++; }
205 
206  private:
207   const ZoneList<HBasicBlock*>* predecessor_list_;
208   int current_;
209 };
210 
211 
212 class HLoopInformation: public ZoneObject {
213  public:
HLoopInformation(HBasicBlock * loop_header)214   explicit HLoopInformation(HBasicBlock* loop_header)
215       : back_edges_(4),
216         loop_header_(loop_header),
217         blocks_(8),
218         stack_check_(NULL) {
219     blocks_.Add(loop_header);
220   }
~HLoopInformation()221   virtual ~HLoopInformation() {}
222 
back_edges()223   const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
blocks()224   const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
loop_header()225   HBasicBlock* loop_header() const { return loop_header_; }
226   HBasicBlock* GetLastBackEdge() const;
227   void RegisterBackEdge(HBasicBlock* block);
228 
stack_check()229   HStackCheck* stack_check() const { return stack_check_; }
set_stack_check(HStackCheck * stack_check)230   void set_stack_check(HStackCheck* stack_check) {
231     stack_check_ = stack_check;
232   }
233 
234  private:
235   void AddBlock(HBasicBlock* block);
236 
237   ZoneList<HBasicBlock*> back_edges_;
238   HBasicBlock* loop_header_;
239   ZoneList<HBasicBlock*> blocks_;
240   HStackCheck* stack_check_;
241 };
242 
243 
244 class HGraph: public ZoneObject {
245  public:
246   explicit HGraph(CompilationInfo* info);
247 
isolate()248   Isolate* isolate() { return isolate_; }
zone()249   Zone* zone() { return isolate_->zone(); }
250 
blocks()251   const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
phi_list()252   const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
entry_block()253   HBasicBlock* entry_block() const { return entry_block_; }
start_environment()254   HEnvironment* start_environment() const { return start_environment_; }
255 
256   void InitializeInferredTypes();
257   void InsertTypeConversions();
258   void InsertRepresentationChanges();
259   void MarkDeoptimizeOnUndefined();
260   void ComputeMinusZeroChecks();
261   bool ProcessArgumentsObject();
262   void EliminateRedundantPhis();
263   void EliminateUnreachablePhis();
264   void Canonicalize();
265   void OrderBlocks();
266   void AssignDominators();
267   void ReplaceCheckedValues();
268   void PropagateDeoptimizingMark();
269 
270   // Returns false if there are phi-uses of the arguments-object
271   // which are not supported by the optimizing compiler.
272   bool CheckArgumentsPhiUses();
273 
274   // Returns false if there are phi-uses of an uninitialized const
275   // which are not supported by the optimizing compiler.
276   bool CheckConstPhiUses();
277 
278   void CollectPhis();
279 
280   Handle<Code> Compile(CompilationInfo* info);
281 
set_undefined_constant(HConstant * constant)282   void set_undefined_constant(HConstant* constant) {
283     undefined_constant_.set(constant);
284   }
GetConstantUndefined()285   HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
286   HConstant* GetConstant1();
287   HConstant* GetConstantMinus1();
288   HConstant* GetConstantTrue();
289   HConstant* GetConstantFalse();
290   HConstant* GetConstantHole();
291 
292   HBasicBlock* CreateBasicBlock();
GetArgumentsObject()293   HArgumentsObject* GetArgumentsObject() const {
294     return arguments_object_.get();
295   }
296 
SetArgumentsObject(HArgumentsObject * object)297   void SetArgumentsObject(HArgumentsObject* object) {
298     arguments_object_.set(object);
299   }
300 
GetMaximumValueID()301   int GetMaximumValueID() const { return values_.length(); }
GetNextBlockID()302   int GetNextBlockID() { return next_block_id_++; }
GetNextValueID(HValue * value)303   int GetNextValueID(HValue* value) {
304     values_.Add(value);
305     return values_.length() - 1;
306   }
LookupValue(int id)307   HValue* LookupValue(int id) const {
308     if (id >= 0 && id < values_.length()) return values_[id];
309     return NULL;
310   }
311 
312 #ifdef DEBUG
313   void Verify(bool do_full_verify) const;
314 #endif
315 
has_osr_loop_entry()316   bool has_osr_loop_entry() {
317     return osr_loop_entry_.is_set();
318   }
319 
osr_loop_entry()320   HBasicBlock* osr_loop_entry() {
321     return osr_loop_entry_.get();
322   }
323 
set_osr_loop_entry(HBasicBlock * entry)324   void set_osr_loop_entry(HBasicBlock* entry) {
325     osr_loop_entry_.set(entry);
326   }
327 
osr_values()328   ZoneList<HUnknownOSRValue*>* osr_values() {
329     return osr_values_.get();
330   }
331 
set_osr_values(ZoneList<HUnknownOSRValue * > * values)332   void set_osr_values(ZoneList<HUnknownOSRValue*>* values) {
333     osr_values_.set(values);
334   }
335 
336  private:
337   void Postorder(HBasicBlock* block,
338                  BitVector* visited,
339                  ZoneList<HBasicBlock*>* order,
340                  HBasicBlock* loop_header);
341   void PostorderLoopBlocks(HLoopInformation* loop,
342                            BitVector* visited,
343                            ZoneList<HBasicBlock*>* order,
344                            HBasicBlock* loop_header);
345   HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
346                          Object* value);
347 
348   void MarkAsDeoptimizingRecursively(HBasicBlock* block);
349   void InsertTypeConversions(HInstruction* instr);
350   void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
351   void RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi);
352   void InsertRepresentationChangeForUse(HValue* value,
353                                         HValue* use_value,
354                                         int use_index,
355                                         Representation to);
356   void InsertRepresentationChangesForValue(HValue* value);
357   void InferTypes(ZoneList<HValue*>* worklist);
358   void InitializeInferredTypes(int from_inclusive, int to_inclusive);
359   void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
360 
361   Isolate* isolate_;
362   int next_block_id_;
363   HBasicBlock* entry_block_;
364   HEnvironment* start_environment_;
365   ZoneList<HBasicBlock*> blocks_;
366   ZoneList<HValue*> values_;
367   ZoneList<HPhi*>* phi_list_;
368   SetOncePointer<HConstant> undefined_constant_;
369   SetOncePointer<HConstant> constant_1_;
370   SetOncePointer<HConstant> constant_minus1_;
371   SetOncePointer<HConstant> constant_true_;
372   SetOncePointer<HConstant> constant_false_;
373   SetOncePointer<HConstant> constant_hole_;
374   SetOncePointer<HArgumentsObject> arguments_object_;
375 
376   SetOncePointer<HBasicBlock> osr_loop_entry_;
377   SetOncePointer<ZoneList<HUnknownOSRValue*> > osr_values_;
378 
379   DISALLOW_COPY_AND_ASSIGN(HGraph);
380 };
381 
382 
zone()383 Zone* HBasicBlock::zone() { return graph_->zone(); }
384 
385 
386 // Type of stack frame an environment might refer to.
387 enum FrameType { JS_FUNCTION, JS_CONSTRUCT, ARGUMENTS_ADAPTOR };
388 
389 
390 class HEnvironment: public ZoneObject {
391  public:
392   HEnvironment(HEnvironment* outer,
393                Scope* scope,
394                Handle<JSFunction> closure);
395 
DiscardInlined(bool drop_extra)396   HEnvironment* DiscardInlined(bool drop_extra) {
397     HEnvironment* outer = outer_;
398     while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
399     if (drop_extra) outer->Drop(1);
400     return outer;
401   }
402 
arguments_environment()403   HEnvironment* arguments_environment() {
404     return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
405   }
406 
407   // Simple accessors.
closure()408   Handle<JSFunction> closure() const { return closure_; }
values()409   const ZoneList<HValue*>* values() const { return &values_; }
assigned_variables()410   const ZoneList<int>* assigned_variables() const {
411     return &assigned_variables_;
412   }
frame_type()413   FrameType frame_type() const { return frame_type_; }
parameter_count()414   int parameter_count() const { return parameter_count_; }
specials_count()415   int specials_count() const { return specials_count_; }
local_count()416   int local_count() const { return local_count_; }
outer()417   HEnvironment* outer() const { return outer_; }
pop_count()418   int pop_count() const { return pop_count_; }
push_count()419   int push_count() const { return push_count_; }
420 
ast_id()421   int ast_id() const { return ast_id_; }
set_ast_id(int id)422   void set_ast_id(int id) { ast_id_ = id; }
423 
length()424   int length() const { return values_.length(); }
is_special_index(int i)425   bool is_special_index(int i) const {
426     return i >= parameter_count() && i < parameter_count() + specials_count();
427   }
428 
first_expression_index()429   int first_expression_index() const {
430     return parameter_count() + specials_count() + local_count();
431   }
432 
Bind(Variable * variable,HValue * value)433   void Bind(Variable* variable, HValue* value) {
434     Bind(IndexFor(variable), value);
435   }
436 
437   void Bind(int index, HValue* value);
438 
BindContext(HValue * value)439   void BindContext(HValue* value) {
440     Bind(parameter_count(), value);
441   }
442 
Lookup(Variable * variable)443   HValue* Lookup(Variable* variable) const {
444     return Lookup(IndexFor(variable));
445   }
446 
Lookup(int index)447   HValue* Lookup(int index) const {
448     HValue* result = values_[index];
449     ASSERT(result != NULL);
450     return result;
451   }
452 
LookupContext()453   HValue* LookupContext() const {
454     // Return first special.
455     return Lookup(parameter_count());
456   }
457 
Push(HValue * value)458   void Push(HValue* value) {
459     ASSERT(value != NULL);
460     ++push_count_;
461     values_.Add(value);
462   }
463 
Pop()464   HValue* Pop() {
465     ASSERT(!ExpressionStackIsEmpty());
466     if (push_count_ > 0) {
467       --push_count_;
468     } else {
469       ++pop_count_;
470     }
471     return values_.RemoveLast();
472   }
473 
474   void Drop(int count);
475 
Top()476   HValue* Top() const { return ExpressionStackAt(0); }
477 
478   bool ExpressionStackIsEmpty() const;
479 
ExpressionStackAt(int index_from_top)480   HValue* ExpressionStackAt(int index_from_top) const {
481     int index = length() - index_from_top - 1;
482     ASSERT(HasExpressionAt(index));
483     return values_[index];
484   }
485 
486   void SetExpressionStackAt(int index_from_top, HValue* value);
487 
488   HEnvironment* Copy() const;
489   HEnvironment* CopyWithoutHistory() const;
490   HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
491 
492   // Create an "inlined version" of this environment, where the original
493   // environment is the outer environment but the top expression stack
494   // elements are moved to an inner environment as parameters.
495   HEnvironment* CopyForInlining(Handle<JSFunction> target,
496                                 int arguments,
497                                 FunctionLiteral* function,
498                                 HConstant* undefined,
499                                 CallKind call_kind,
500                                 bool is_construct) const;
501 
502   void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
503 
ClearHistory()504   void ClearHistory() {
505     pop_count_ = 0;
506     push_count_ = 0;
507     assigned_variables_.Rewind(0);
508   }
509 
SetValueAt(int index,HValue * value)510   void SetValueAt(int index, HValue* value) {
511     ASSERT(index < length());
512     values_[index] = value;
513   }
514 
515   void PrintTo(StringStream* stream);
516   void PrintToStd();
517 
518  private:
519   explicit HEnvironment(const HEnvironment* other);
520 
521   HEnvironment(HEnvironment* outer,
522                Handle<JSFunction> closure,
523                FrameType frame_type,
524                int arguments);
525 
526   // Create an artificial stub environment (e.g. for argument adaptor or
527   // constructor stub).
528   HEnvironment* CreateStubEnvironment(HEnvironment* outer,
529                                       Handle<JSFunction> target,
530                                       FrameType frame_type,
531                                       int arguments) const;
532 
533   // True if index is included in the expression stack part of the environment.
534   bool HasExpressionAt(int index) const;
535 
536   void Initialize(int parameter_count, int local_count, int stack_height);
537   void Initialize(const HEnvironment* other);
538 
539   // Map a variable to an environment index.  Parameter indices are shifted
540   // by 1 (receiver is parameter index -1 but environment index 0).
541   // Stack-allocated local indices are shifted by the number of parameters.
IndexFor(Variable * variable)542   int IndexFor(Variable* variable) const {
543     ASSERT(variable->IsStackAllocated());
544     int shift = variable->IsParameter()
545         ? 1
546         : parameter_count_ + specials_count_;
547     return variable->index() + shift;
548   }
549 
550   Handle<JSFunction> closure_;
551   // Value array [parameters] [specials] [locals] [temporaries].
552   ZoneList<HValue*> values_;
553   ZoneList<int> assigned_variables_;
554   FrameType frame_type_;
555   int parameter_count_;
556   int specials_count_;
557   int local_count_;
558   HEnvironment* outer_;
559   int pop_count_;
560   int push_count_;
561   int ast_id_;
562 };
563 
564 
565 class HGraphBuilder;
566 
567 enum ArgumentsAllowedFlag {
568   ARGUMENTS_NOT_ALLOWED,
569   ARGUMENTS_ALLOWED
570 };
571 
572 // This class is not BASE_EMBEDDED because our inlining implementation uses
573 // new and delete.
574 class AstContext {
575  public:
IsEffect()576   bool IsEffect() const { return kind_ == Expression::kEffect; }
IsValue()577   bool IsValue() const { return kind_ == Expression::kValue; }
IsTest()578   bool IsTest() const { return kind_ == Expression::kTest; }
579 
580   // 'Fill' this context with a hydrogen value.  The value is assumed to
581   // have already been inserted in the instruction stream (or not need to
582   // be, e.g., HPhi).  Call this function in tail position in the Visit
583   // functions for expressions.
584   virtual void ReturnValue(HValue* value) = 0;
585 
586   // Add a hydrogen instruction to the instruction stream (recording an
587   // environment simulation if necessary) and then fill this context with
588   // the instruction as value.
589   virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
590 
591   // Finishes the current basic block and materialize a boolean for
592   // value context, nothing for effect, generate a branch for test context.
593   // Call this function in tail position in the Visit functions for
594   // expressions.
595   virtual void ReturnControl(HControlInstruction* instr, int ast_id) = 0;
596 
set_for_typeof(bool for_typeof)597   void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
is_for_typeof()598   bool is_for_typeof() { return for_typeof_; }
599 
600  protected:
601   AstContext(HGraphBuilder* owner, Expression::Context kind);
602   virtual ~AstContext();
603 
owner()604   HGraphBuilder* owner() const { return owner_; }
605 
606   inline Zone* zone();
607 
608   // We want to be able to assert, in a context-specific way, that the stack
609   // height makes sense when the context is filled.
610 #ifdef DEBUG
611   int original_length_;
612 #endif
613 
614  private:
615   HGraphBuilder* owner_;
616   Expression::Context kind_;
617   AstContext* outer_;
618   bool for_typeof_;
619 };
620 
621 
622 class EffectContext: public AstContext {
623  public:
EffectContext(HGraphBuilder * owner)624   explicit EffectContext(HGraphBuilder* owner)
625       : AstContext(owner, Expression::kEffect) {
626   }
627   virtual ~EffectContext();
628 
629   virtual void ReturnValue(HValue* value);
630   virtual void ReturnInstruction(HInstruction* instr, int ast_id);
631   virtual void ReturnControl(HControlInstruction* instr, int ast_id);
632 };
633 
634 
635 class ValueContext: public AstContext {
636  public:
ValueContext(HGraphBuilder * owner,ArgumentsAllowedFlag flag)637   explicit ValueContext(HGraphBuilder* owner, ArgumentsAllowedFlag flag)
638       : AstContext(owner, Expression::kValue), flag_(flag) {
639   }
640   virtual ~ValueContext();
641 
642   virtual void ReturnValue(HValue* value);
643   virtual void ReturnInstruction(HInstruction* instr, int ast_id);
644   virtual void ReturnControl(HControlInstruction* instr, int ast_id);
645 
arguments_allowed()646   bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
647 
648  private:
649   ArgumentsAllowedFlag flag_;
650 };
651 
652 
653 class TestContext: public AstContext {
654  public:
TestContext(HGraphBuilder * owner,Expression * condition,HBasicBlock * if_true,HBasicBlock * if_false)655   TestContext(HGraphBuilder* owner,
656               Expression* condition,
657               HBasicBlock* if_true,
658               HBasicBlock* if_false)
659       : AstContext(owner, Expression::kTest),
660         condition_(condition),
661         if_true_(if_true),
662         if_false_(if_false) {
663   }
664 
665   virtual void ReturnValue(HValue* value);
666   virtual void ReturnInstruction(HInstruction* instr, int ast_id);
667   virtual void ReturnControl(HControlInstruction* instr, int ast_id);
668 
cast(AstContext * context)669   static TestContext* cast(AstContext* context) {
670     ASSERT(context->IsTest());
671     return reinterpret_cast<TestContext*>(context);
672   }
673 
condition()674   Expression* condition() const { return condition_; }
if_true()675   HBasicBlock* if_true() const { return if_true_; }
if_false()676   HBasicBlock* if_false() const { return if_false_; }
677 
678  private:
679   // Build the shared core part of the translation unpacking a value into
680   // control flow.
681   void BuildBranch(HValue* value);
682 
683   Expression* condition_;
684   HBasicBlock* if_true_;
685   HBasicBlock* if_false_;
686 };
687 
688 
689 enum ReturnHandlingFlag {
690   NORMAL_RETURN,
691   DROP_EXTRA_ON_RETURN,
692   CONSTRUCT_CALL_RETURN
693 };
694 
695 
696 class FunctionState {
697  public:
698   FunctionState(HGraphBuilder* owner,
699                 CompilationInfo* info,
700                 TypeFeedbackOracle* oracle,
701                 ReturnHandlingFlag return_handling);
702   ~FunctionState();
703 
compilation_info()704   CompilationInfo* compilation_info() { return compilation_info_; }
oracle()705   TypeFeedbackOracle* oracle() { return oracle_; }
call_context()706   AstContext* call_context() { return call_context_; }
drop_extra()707   bool drop_extra() { return return_handling_ == DROP_EXTRA_ON_RETURN; }
is_construct()708   bool is_construct() { return return_handling_ == CONSTRUCT_CALL_RETURN; }
function_return()709   HBasicBlock* function_return() { return function_return_; }
test_context()710   TestContext* test_context() { return test_context_; }
ClearInlinedTestContext()711   void ClearInlinedTestContext() {
712     delete test_context_;
713     test_context_ = NULL;
714   }
715 
outer()716   FunctionState* outer() { return outer_; }
717 
718  private:
719   HGraphBuilder* owner_;
720 
721   CompilationInfo* compilation_info_;
722   TypeFeedbackOracle* oracle_;
723 
724   // During function inlining, expression context of the call being
725   // inlined. NULL when not inlining.
726   AstContext* call_context_;
727 
728   // Indicate whether we have to perform special handling on return from
729   // inlined functions.
730   // - DROP_EXTRA_ON_RETURN: Drop an extra value from the environment.
731   // - CONSTRUCT_CALL_RETURN: Either use allocated receiver or return value.
732   ReturnHandlingFlag return_handling_;
733 
734   // When inlining in an effect or value context, this is the return block.
735   // It is NULL otherwise.  When inlining in a test context, there are a
736   // pair of return blocks in the context.  When not inlining, there is no
737   // local return point.
738   HBasicBlock* function_return_;
739 
740   // When inlining a call in a test context, a context containing a pair of
741   // return blocks.  NULL in all other cases.
742   TestContext* test_context_;
743 
744   FunctionState* outer_;
745 };
746 
747 
748 class HGraphBuilder: public AstVisitor {
749  public:
750   enum BreakType { BREAK, CONTINUE };
751   enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH };
752 
753   // A class encapsulating (lazily-allocated) break and continue blocks for
754   // a breakable statement.  Separated from BreakAndContinueScope so that it
755   // can have a separate lifetime.
756   class BreakAndContinueInfo BASE_EMBEDDED {
757    public:
758     explicit BreakAndContinueInfo(BreakableStatement* target,
759                                   int drop_extra = 0)
target_(target)760         : target_(target),
761           break_block_(NULL),
762           continue_block_(NULL),
763           drop_extra_(drop_extra) {
764     }
765 
target()766     BreakableStatement* target() { return target_; }
break_block()767     HBasicBlock* break_block() { return break_block_; }
set_break_block(HBasicBlock * block)768     void set_break_block(HBasicBlock* block) { break_block_ = block; }
continue_block()769     HBasicBlock* continue_block() { return continue_block_; }
set_continue_block(HBasicBlock * block)770     void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
drop_extra()771     int drop_extra() { return drop_extra_; }
772 
773    private:
774     BreakableStatement* target_;
775     HBasicBlock* break_block_;
776     HBasicBlock* continue_block_;
777     int drop_extra_;
778   };
779 
780   // A helper class to maintain a stack of current BreakAndContinueInfo
781   // structures mirroring BreakableStatement nesting.
782   class BreakAndContinueScope BASE_EMBEDDED {
783    public:
BreakAndContinueScope(BreakAndContinueInfo * info,HGraphBuilder * owner)784     BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
785         : info_(info), owner_(owner), next_(owner->break_scope()) {
786       owner->set_break_scope(this);
787     }
788 
~BreakAndContinueScope()789     ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
790 
info()791     BreakAndContinueInfo* info() { return info_; }
owner()792     HGraphBuilder* owner() { return owner_; }
next()793     BreakAndContinueScope* next() { return next_; }
794 
795     // Search the break stack for a break or continue target.
796     HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra);
797 
798    private:
799     BreakAndContinueInfo* info_;
800     HGraphBuilder* owner_;
801     BreakAndContinueScope* next_;
802   };
803 
804   HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle);
805 
806   HGraph* CreateGraph();
807 
808   // Simple accessors.
graph()809   HGraph* graph() const { return graph_; }
break_scope()810   BreakAndContinueScope* break_scope() const { return break_scope_; }
set_break_scope(BreakAndContinueScope * head)811   void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
812 
current_block()813   HBasicBlock* current_block() const { return current_block_; }
set_current_block(HBasicBlock * block)814   void set_current_block(HBasicBlock* block) { current_block_ = block; }
environment()815   HEnvironment* environment() const {
816     return current_block()->last_environment();
817   }
818 
inline_bailout()819   bool inline_bailout() { return inline_bailout_; }
820 
821   // Adding instructions.
822   HInstruction* AddInstruction(HInstruction* instr);
823   void AddSimulate(int ast_id);
824 
825   // Bailout environment manipulation.
Push(HValue * value)826   void Push(HValue* value) { environment()->Push(value); }
Pop()827   HValue* Pop() { return environment()->Pop(); }
828 
829   void Bailout(const char* reason);
830 
831   HBasicBlock* CreateJoin(HBasicBlock* first,
832                           HBasicBlock* second,
833                           int join_id);
834 
oracle()835   TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
836 
function_state()837   FunctionState* function_state() const { return function_state_; }
838 
839   void VisitDeclarations(ZoneList<Declaration*>* declarations);
840 
841  private:
842   // Type of a member function that generates inline code for a native function.
843   typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
844 
845   // Forward declarations for inner scope classes.
846   class SubgraphScope;
847 
848   static const InlineFunctionGenerator kInlineFunctionGenerators[];
849 
850   static const int kMaxCallPolymorphism = 4;
851   static const int kMaxLoadPolymorphism = 4;
852   static const int kMaxStorePolymorphism = 4;
853 
854   static const int kMaxInlinedNodes = 196;
855   static const int kMaxInlinedSize = 196;
856   static const int kMaxSourceSize = 600;
857 
858   // Even in the 'unlimited' case we have to have some limit in order not to
859   // overflow the stack.
860   static const int kUnlimitedMaxInlinedNodes = 1000;
861   static const int kUnlimitedMaxInlinedSize = 1000;
862   static const int kUnlimitedMaxSourceSize = 600;
863 
864   // Simple accessors.
set_function_state(FunctionState * state)865   void set_function_state(FunctionState* state) { function_state_ = state; }
866 
ast_context()867   AstContext* ast_context() const { return ast_context_; }
set_ast_context(AstContext * context)868   void set_ast_context(AstContext* context) { ast_context_ = context; }
869 
870   // Accessors forwarded to the function state.
info()871   CompilationInfo* info() const {
872     return function_state()->compilation_info();
873   }
call_context()874   AstContext* call_context() const {
875     return function_state()->call_context();
876   }
function_return()877   HBasicBlock* function_return() const {
878     return function_state()->function_return();
879   }
inlined_test_context()880   TestContext* inlined_test_context() const {
881     return function_state()->test_context();
882   }
ClearInlinedTestContext()883   void ClearInlinedTestContext() {
884     function_state()->ClearInlinedTestContext();
885   }
function_strict_mode_flag()886   StrictModeFlag function_strict_mode_flag() {
887     return function_state()->compilation_info()->is_classic_mode()
888         ? kNonStrictMode : kStrictMode;
889   }
890 
891   // Generators for inline runtime functions.
892 #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize)      \
893   void Generate##Name(CallRuntime* call);
894 
895   INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
896   INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
897 #undef INLINE_FUNCTION_GENERATOR_DECLARATION
898 
899   void HandleDeclaration(VariableProxy* proxy,
900                          VariableMode mode,
901                          FunctionLiteral* function,
902                          int* global_count);
903 
904   void VisitDelete(UnaryOperation* expr);
905   void VisitVoid(UnaryOperation* expr);
906   void VisitTypeof(UnaryOperation* expr);
907   void VisitAdd(UnaryOperation* expr);
908   void VisitSub(UnaryOperation* expr);
909   void VisitBitNot(UnaryOperation* expr);
910   void VisitNot(UnaryOperation* expr);
911 
912   void VisitComma(BinaryOperation* expr);
913   void VisitLogicalExpression(BinaryOperation* expr);
914   void VisitArithmeticExpression(BinaryOperation* expr);
915 
916   bool PreProcessOsrEntry(IterationStatement* statement);
917   // True iff. we are compiling for OSR and the statement is the entry.
918   bool HasOsrEntryAt(IterationStatement* statement);
919   void VisitLoopBody(IterationStatement* stmt,
920                      HBasicBlock* loop_entry,
921                      BreakAndContinueInfo* break_info);
922 
923   // Create a back edge in the flow graph.  body_exit is the predecessor
924   // block and loop_entry is the successor block.  loop_successor is the
925   // block where control flow exits the loop normally (e.g., via failure of
926   // the condition) and break_block is the block where control flow breaks
927   // from the loop.  All blocks except loop_entry can be NULL.  The return
928   // value is the new successor block which is the join of loop_successor
929   // and break_block, or NULL.
930   HBasicBlock* CreateLoop(IterationStatement* statement,
931                           HBasicBlock* loop_entry,
932                           HBasicBlock* body_exit,
933                           HBasicBlock* loop_successor,
934                           HBasicBlock* break_block);
935 
936   HBasicBlock* JoinContinue(IterationStatement* statement,
937                             HBasicBlock* exit_block,
938                             HBasicBlock* continue_block);
939 
Top()940   HValue* Top() const { return environment()->Top(); }
Drop(int n)941   void Drop(int n) { environment()->Drop(n); }
Bind(Variable * var,HValue * value)942   void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
943 
944   // The value of the arguments object is allowed in some but not most value
945   // contexts.  (It's allowed in all effect contexts and disallowed in all
946   // test contexts.)
947   void VisitForValue(Expression* expr,
948                      ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
949   void VisitForTypeOf(Expression* expr);
950   void VisitForEffect(Expression* expr);
951   void VisitForControl(Expression* expr,
952                        HBasicBlock* true_block,
953                        HBasicBlock* false_block);
954 
955   // Visit an argument subexpression and emit a push to the outgoing
956   // arguments.  Returns the hydrogen value that was pushed.
957   HValue* VisitArgument(Expression* expr);
958 
959   void VisitArgumentList(ZoneList<Expression*>* arguments);
960 
961   // Visit a list of expressions from left to right, each in a value context.
962   void VisitExpressions(ZoneList<Expression*>* exprs);
963 
964   void AddPhi(HPhi* phi);
965 
966   void PushAndAdd(HInstruction* instr);
967 
968   // Remove the arguments from the bailout environment and emit instructions
969   // to push them as outgoing parameters.
970   template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
971 
972   void TraceRepresentation(Token::Value op,
973                            TypeInfo info,
974                            HValue* value,
975                            Representation rep);
976   static Representation ToRepresentation(TypeInfo info);
977 
978   void SetUpScope(Scope* scope);
979   virtual void VisitStatements(ZoneList<Statement*>* statements);
980 
981 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
982   AST_NODE_LIST(DECLARE_VISIT)
983 #undef DECLARE_VISIT
984 
985   HBasicBlock* CreateBasicBlock(HEnvironment* env);
986   HBasicBlock* CreateLoopHeaderBlock();
987 
988   // Helpers for flow graph construction.
989   enum GlobalPropertyAccess {
990     kUseCell,
991     kUseGeneric
992   };
993   GlobalPropertyAccess LookupGlobalProperty(Variable* var,
994                                             LookupResult* lookup,
995                                             bool is_store);
996 
997   bool TryArgumentsAccess(Property* expr);
998 
999   // Try to optimize fun.apply(receiver, arguments) pattern.
1000   bool TryCallApply(Call* expr);
1001 
1002   bool TryInline(CallKind call_kind,
1003                  Handle<JSFunction> target,
1004                  ZoneList<Expression*>* arguments,
1005                  HValue* receiver,
1006                  int ast_id,
1007                  int return_id,
1008                  ReturnHandlingFlag return_handling);
1009 
1010   bool TryInlineCall(Call* expr, bool drop_extra = false);
1011   bool TryInlineConstruct(CallNew* expr, HValue* receiver);
1012   bool TryInlineBuiltinMethodCall(Call* expr,
1013                                   HValue* receiver,
1014                                   Handle<Map> receiver_map,
1015                                   CheckType check_type);
1016   bool TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra);
1017 
1018   // If --trace-inlining, print a line of the inlining trace.  Inlining
1019   // succeeded if the reason string is NULL and failed if there is a
1020   // non-NULL reason string.
1021   void TraceInline(Handle<JSFunction> target,
1022                    Handle<JSFunction> caller,
1023                    const char* failure_reason);
1024 
1025   void HandleGlobalVariableAssignment(Variable* var,
1026                                       HValue* value,
1027                                       int position,
1028                                       int ast_id);
1029 
1030   void HandlePropertyAssignment(Assignment* expr);
1031   void HandleCompoundAssignment(Assignment* expr);
1032   void HandlePolymorphicStoreNamedField(Assignment* expr,
1033                                         HValue* object,
1034                                         HValue* value,
1035                                         SmallMapList* types,
1036                                         Handle<String> name);
1037   void HandlePolymorphicCallNamed(Call* expr,
1038                                   HValue* receiver,
1039                                   SmallMapList* types,
1040                                   Handle<String> name);
1041   void HandleLiteralCompareTypeof(CompareOperation* expr,
1042                                   HTypeof* typeof_expr,
1043                                   Handle<String> check);
1044   void HandleLiteralCompareNil(CompareOperation* expr,
1045                                HValue* value,
1046                                NilValue nil);
1047 
1048   HStringCharCodeAt* BuildStringCharCodeAt(HValue* context,
1049                                            HValue* string,
1050                                            HValue* index);
1051   HInstruction* BuildBinaryOperation(BinaryOperation* expr,
1052                                      HValue* left,
1053                                      HValue* right);
1054   HInstruction* BuildIncrement(bool returns_original_input,
1055                                CountOperation* expr);
1056   HLoadNamedField* BuildLoadNamedField(HValue* object,
1057                                        Property* expr,
1058                                        Handle<Map> type,
1059                                        LookupResult* result,
1060                                        bool smi_and_map_check);
1061   HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
1062   HInstruction* BuildLoadKeyedGeneric(HValue* object,
1063                                       HValue* key);
1064   HInstruction* BuildExternalArrayElementAccess(
1065       HValue* external_elements,
1066       HValue* checked_key,
1067       HValue* val,
1068       ElementsKind elements_kind,
1069       bool is_store);
1070   HInstruction* BuildFastElementAccess(HValue* elements,
1071                                        HValue* checked_key,
1072                                        HValue* val,
1073                                        ElementsKind elements_kind,
1074                                        bool is_store);
1075 
1076   HInstruction* BuildMonomorphicElementAccess(HValue* object,
1077                                               HValue* key,
1078                                               HValue* val,
1079                                               Handle<Map> map,
1080                                               bool is_store);
1081   HValue* HandlePolymorphicElementAccess(HValue* object,
1082                                          HValue* key,
1083                                          HValue* val,
1084                                          Expression* prop,
1085                                          int ast_id,
1086                                          int position,
1087                                          bool is_store,
1088                                          bool* has_side_effects);
1089 
1090   HValue* HandleKeyedElementAccess(HValue* obj,
1091                                    HValue* key,
1092                                    HValue* val,
1093                                    Expression* expr,
1094                                    int ast_id,
1095                                    int position,
1096                                    bool is_store,
1097                                    bool* has_side_effects);
1098 
1099   HInstruction* BuildLoadNamed(HValue* object,
1100                                Property* prop,
1101                                Handle<Map> map,
1102                                Handle<String> name);
1103   HInstruction* BuildStoreNamed(HValue* object,
1104                                 HValue* value,
1105                                 Expression* expr);
1106   HInstruction* BuildStoreNamed(HValue* object,
1107                                 HValue* value,
1108                                 ObjectLiteral::Property* prop);
1109   HInstruction* BuildStoreNamedField(HValue* object,
1110                                      Handle<String> name,
1111                                      HValue* value,
1112                                      Handle<Map> type,
1113                                      LookupResult* lookup,
1114                                      bool smi_and_map_check);
1115   HInstruction* BuildStoreNamedGeneric(HValue* object,
1116                                        Handle<String> name,
1117                                        HValue* value);
1118   HInstruction* BuildStoreKeyedGeneric(HValue* object,
1119                                        HValue* key,
1120                                        HValue* value);
1121 
1122   HValue* BuildContextChainWalk(Variable* var);
1123 
1124   void AddCheckConstantFunction(Call* expr,
1125                                 HValue* receiver,
1126                                 Handle<Map> receiver_map,
1127                                 bool smi_and_map_check);
1128 
zone()1129   Zone* zone() { return zone_; }
1130 
1131   // The translation state of the currently-being-translated function.
1132   FunctionState* function_state_;
1133 
1134   // The base of the function state stack.
1135   FunctionState initial_function_state_;
1136 
1137   // Expression context of the currently visited subexpression. NULL when
1138   // visiting statements.
1139   AstContext* ast_context_;
1140 
1141   // A stack of breakable statements entered.
1142   BreakAndContinueScope* break_scope_;
1143 
1144   HGraph* graph_;
1145   HBasicBlock* current_block_;
1146 
1147   int inlined_count_;
1148 
1149   Zone* zone_;
1150 
1151   bool inline_bailout_;
1152 
1153   friend class FunctionState;  // Pushes and pops the state stack.
1154   friend class AstContext;  // Pushes and pops the AST context stack.
1155 
1156   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
1157 };
1158 
1159 
zone()1160 Zone* AstContext::zone() { return owner_->zone(); }
1161 
1162 
1163 class HValueMap: public ZoneObject {
1164  public:
HValueMap()1165   HValueMap()
1166       : array_size_(0),
1167         lists_size_(0),
1168         count_(0),
1169         present_flags_(0),
1170         array_(NULL),
1171         lists_(NULL),
1172         free_list_head_(kNil) {
1173     ResizeLists(kInitialSize);
1174     Resize(kInitialSize);
1175   }
1176 
1177   void Kill(GVNFlagSet flags);
1178 
Add(HValue * value)1179   void Add(HValue* value) {
1180     present_flags_.Add(value->gvn_flags());
1181     Insert(value);
1182   }
1183 
1184   HValue* Lookup(HValue* value) const;
1185 
Copy(Zone * zone)1186   HValueMap* Copy(Zone* zone) const {
1187     return new(zone) HValueMap(zone, this);
1188   }
1189 
IsEmpty()1190   bool IsEmpty() const { return count_ == 0; }
1191 
1192  private:
1193   // A linked list of HValue* values.  Stored in arrays.
1194   struct HValueMapListElement {
1195     HValue* value;
1196     int next;  // Index in the array of the next list element.
1197   };
1198   static const int kNil = -1;  // The end of a linked list
1199 
1200   // Must be a power of 2.
1201   static const int kInitialSize = 16;
1202 
1203   HValueMap(Zone* zone, const HValueMap* other);
1204 
1205   void Resize(int new_size);
1206   void ResizeLists(int new_size);
1207   void Insert(HValue* value);
Bound(uint32_t value)1208   uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
1209 
1210   int array_size_;
1211   int lists_size_;
1212   int count_;  // The number of values stored in the HValueMap.
1213   GVNFlagSet present_flags_;  // All flags that are in any value in the
1214                               // HValueMap.
1215   HValueMapListElement* array_;  // Primary store - contains the first value
1216   // with a given hash.  Colliding elements are stored in linked lists.
1217   HValueMapListElement* lists_;  // The linked lists containing hash collisions.
1218   int free_list_head_;  // Unused elements in lists_ are on the free list.
1219 };
1220 
1221 
1222 class HStatistics: public Malloced {
1223  public:
1224   void Initialize(CompilationInfo* info);
1225   void Print();
1226   void SaveTiming(const char* name, int64_t ticks, unsigned size);
Instance()1227   static HStatistics* Instance() {
1228     static SetOncePointer<HStatistics> instance;
1229     if (!instance.is_set()) {
1230       instance.set(new HStatistics());
1231     }
1232     return instance.get();
1233   }
1234 
1235  private:
HStatistics()1236   HStatistics()
1237       : timing_(5),
1238         names_(5),
1239         sizes_(5),
1240         total_(0),
1241         total_size_(0),
1242         full_code_gen_(0),
1243         source_size_(0) { }
1244 
1245   List<int64_t> timing_;
1246   List<const char*> names_;
1247   List<unsigned> sizes_;
1248   int64_t total_;
1249   unsigned total_size_;
1250   int64_t full_code_gen_;
1251   double source_size_;
1252 };
1253 
1254 
1255 class HPhase BASE_EMBEDDED {
1256  public:
1257   static const char* const kFullCodeGen;
1258   static const char* const kTotal;
1259 
HPhase(const char * name)1260   explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
HPhase(const char * name,HGraph * graph)1261   HPhase(const char* name, HGraph* graph) {
1262     Begin(name, graph, NULL, NULL);
1263   }
HPhase(const char * name,LChunk * chunk)1264   HPhase(const char* name, LChunk* chunk) {
1265     Begin(name, NULL, chunk, NULL);
1266   }
HPhase(const char * name,LAllocator * allocator)1267   HPhase(const char* name, LAllocator* allocator) {
1268     Begin(name, NULL, NULL, allocator);
1269   }
1270 
~HPhase()1271   ~HPhase() {
1272     End();
1273   }
1274 
1275  private:
1276   void Begin(const char* name,
1277              HGraph* graph,
1278              LChunk* chunk,
1279              LAllocator* allocator);
1280   void End() const;
1281 
1282   int64_t start_;
1283   const char* name_;
1284   HGraph* graph_;
1285   LChunk* chunk_;
1286   LAllocator* allocator_;
1287   unsigned start_allocation_size_;
1288 };
1289 
1290 
1291 class HTracer: public Malloced {
1292  public:
1293   void TraceCompilation(FunctionLiteral* function);
1294   void TraceHydrogen(const char* name, HGraph* graph);
1295   void TraceLithium(const char* name, LChunk* chunk);
1296   void TraceLiveRanges(const char* name, LAllocator* allocator);
1297 
Instance()1298   static HTracer* Instance() {
1299     static SetOncePointer<HTracer> instance;
1300     if (!instance.is_set()) {
1301       instance.set(new HTracer("hydrogen.cfg"));
1302     }
1303     return instance.get();
1304   }
1305 
1306  private:
1307   class Tag BASE_EMBEDDED {
1308    public:
Tag(HTracer * tracer,const char * name)1309     Tag(HTracer* tracer, const char* name) {
1310       name_ = name;
1311       tracer_ = tracer;
1312       tracer->PrintIndent();
1313       tracer->trace_.Add("begin_%s\n", name);
1314       tracer->indent_++;
1315     }
1316 
~Tag()1317     ~Tag() {
1318       tracer_->indent_--;
1319       tracer_->PrintIndent();
1320       tracer_->trace_.Add("end_%s\n", name_);
1321       ASSERT(tracer_->indent_ >= 0);
1322       tracer_->FlushToFile();
1323     }
1324 
1325    private:
1326     HTracer* tracer_;
1327     const char* name_;
1328   };
1329 
HTracer(const char * filename)1330   explicit HTracer(const char* filename)
1331       : filename_(filename), trace_(&string_allocator_), indent_(0) {
1332     WriteChars(filename, "", 0, false);
1333   }
1334 
1335   void TraceLiveRange(LiveRange* range, const char* type);
1336   void Trace(const char* name, HGraph* graph, LChunk* chunk);
1337   void FlushToFile();
1338 
PrintEmptyProperty(const char * name)1339   void PrintEmptyProperty(const char* name) {
1340     PrintIndent();
1341     trace_.Add("%s\n", name);
1342   }
1343 
PrintStringProperty(const char * name,const char * value)1344   void PrintStringProperty(const char* name, const char* value) {
1345     PrintIndent();
1346     trace_.Add("%s \"%s\"\n", name, value);
1347   }
1348 
PrintLongProperty(const char * name,int64_t value)1349   void PrintLongProperty(const char* name, int64_t value) {
1350     PrintIndent();
1351     trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1352   }
1353 
PrintBlockProperty(const char * name,int block_id)1354   void PrintBlockProperty(const char* name, int block_id) {
1355     PrintIndent();
1356     trace_.Add("%s \"B%d\"\n", name, block_id);
1357   }
1358 
PrintIntProperty(const char * name,int value)1359   void PrintIntProperty(const char* name, int value) {
1360     PrintIndent();
1361     trace_.Add("%s %d\n", name, value);
1362   }
1363 
PrintIndent()1364   void PrintIndent() {
1365     for (int i = 0; i < indent_; i++) {
1366       trace_.Add("  ");
1367     }
1368   }
1369 
1370   const char* filename_;
1371   HeapStringAllocator string_allocator_;
1372   StringStream trace_;
1373   int indent_;
1374 };
1375 
1376 
1377 } }  // namespace v8::internal
1378 
1379 #endif  // V8_HYDROGEN_H_
1380