Home | History | Annotate | Download | only in src
      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);
     57   virtual ~HBasicBlock() { }
     58 
     59   // Simple accessors.
     60   int block_id() const { return block_id_; }
     61   void set_block_id(int id) { block_id_ = id; }
     62   HGraph* graph() const { return graph_; }
     63   const ZoneList<HPhi*>* phis() const { return &phis_; }
     64   HInstruction* first() const { return first_; }
     65   HInstruction* last() const { return last_; }
     66   void set_last(HInstruction* instr) { last_ = instr; }
     67   HInstruction* GetLastInstruction();
     68   HControlInstruction* end() const { return end_; }
     69   HLoopInformation* loop_information() const { return loop_information_; }
     70   const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
     71   bool HasPredecessor() const { return predecessors_.length() > 0; }
     72   const ZoneList<HBasicBlock*>* dominated_blocks() const {
     73     return &dominated_blocks_;
     74   }
     75   const ZoneList<int>* deleted_phis() const {
     76     return &deleted_phis_;
     77   }
     78   void RecordDeletedPhi(int merge_index) {
     79     deleted_phis_.Add(merge_index);
     80   }
     81   HBasicBlock* dominator() const { return dominator_; }
     82   HEnvironment* last_environment() const { return last_environment_; }
     83   int argument_count() const { return argument_count_; }
     84   void set_argument_count(int count) { argument_count_ = count; }
     85   int first_instruction_index() const { return first_instruction_index_; }
     86   void set_first_instruction_index(int index) {
     87     first_instruction_index_ = index;
     88   }
     89   int last_instruction_index() const { return last_instruction_index_; }
     90   void set_last_instruction_index(int index) {
     91     last_instruction_index_ = index;
     92   }
     93 
     94   void AttachLoopInformation();
     95   void DetachLoopInformation();
     96   bool IsLoopHeader() const { return loop_information() != NULL; }
     97   bool IsStartBlock() const { return block_id() == 0; }
     98   void PostProcessLoopHeader(IterationStatement* stmt);
     99 
    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);
    108   void ClearEnvironment() { last_environment_ = NULL; }
    109   bool HasEnvironment() const { return last_environment_ != NULL; }
    110   void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
    111   HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
    112 
    113   void set_parent_loop_header(HBasicBlock* block) {
    114     ASSERT(parent_loop_header_ == NULL);
    115     parent_loop_header_ = block;
    116   }
    117 
    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;
    127   void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
    128   void AssignCommonDominator(HBasicBlock* other);
    129   void AssignLoopSuccessorDominators();
    130 
    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)
    147   bool IsInlineReturnTarget() const { return is_inline_return_target_; }
    148   void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
    149 
    150   bool IsDeoptimizing() const { return is_deoptimizing_; }
    151   void MarkAsDeoptimizing() { is_deoptimizing_ = true; }
    152 
    153   bool IsLoopSuccessorDominator() const {
    154     return dominates_loop_successors_;
    155   }
    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:
    199   explicit HPredecessorIterator(HBasicBlock* block)
    200       : predecessor_list_(block->predecessors()), current_(0) { }
    201 
    202   bool Done() { return current_ >= predecessor_list_->length(); }
    203   HBasicBlock* Current() { return predecessor_list_->at(current_); }
    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:
    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   }
    221   virtual ~HLoopInformation() {}
    222 
    223   const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
    224   const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
    225   HBasicBlock* loop_header() const { return loop_header_; }
    226   HBasicBlock* GetLastBackEdge() const;
    227   void RegisterBackEdge(HBasicBlock* block);
    228 
    229   HStackCheck* stack_check() const { return 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 
    248   Isolate* isolate() { return isolate_; }
    249   Zone* zone() { return isolate_->zone(); }
    250 
    251   const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
    252   const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
    253   HBasicBlock* entry_block() const { return entry_block_; }
    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 
    282   void set_undefined_constant(HConstant* constant) {
    283     undefined_constant_.set(constant);
    284   }
    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();
    293   HArgumentsObject* GetArgumentsObject() const {
    294     return arguments_object_.get();
    295   }
    296 
    297   void SetArgumentsObject(HArgumentsObject* object) {
    298     arguments_object_.set(object);
    299   }
    300 
    301   int GetMaximumValueID() const { return values_.length(); }
    302   int GetNextBlockID() { return next_block_id_++; }
    303   int GetNextValueID(HValue* value) {
    304     values_.Add(value);
    305     return values_.length() - 1;
    306   }
    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 
    316   bool has_osr_loop_entry() {
    317     return osr_loop_entry_.is_set();
    318   }
    319 
    320   HBasicBlock* osr_loop_entry() {
    321     return osr_loop_entry_.get();
    322   }
    323 
    324   void set_osr_loop_entry(HBasicBlock* entry) {
    325     osr_loop_entry_.set(entry);
    326   }
    327 
    328   ZoneList<HUnknownOSRValue*>* osr_values() {
    329     return osr_values_.get();
    330   }
    331 
    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 
    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 
    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 
    403   HEnvironment* arguments_environment() {
    404     return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
    405   }
    406 
    407   // Simple accessors.
    408   Handle<JSFunction> closure() const { return closure_; }
    409   const ZoneList<HValue*>* values() const { return &values_; }
    410   const ZoneList<int>* assigned_variables() const {
    411     return &assigned_variables_;
    412   }
    413   FrameType frame_type() const { return frame_type_; }
    414   int parameter_count() const { return parameter_count_; }
    415   int specials_count() const { return specials_count_; }
    416   int local_count() const { return local_count_; }
    417   HEnvironment* outer() const { return outer_; }
    418   int pop_count() const { return pop_count_; }
    419   int push_count() const { return push_count_; }
    420 
    421   int ast_id() const { return ast_id_; }
    422   void set_ast_id(int id) { ast_id_ = id; }
    423 
    424   int length() const { return values_.length(); }
    425   bool is_special_index(int i) const {
    426     return i >= parameter_count() && i < parameter_count() + specials_count();
    427   }
    428 
    429   int first_expression_index() const {
    430     return parameter_count() + specials_count() + local_count();
    431   }
    432 
    433   void Bind(Variable* variable, HValue* value) {
    434     Bind(IndexFor(variable), value);
    435   }
    436 
    437   void Bind(int index, HValue* value);
    438 
    439   void BindContext(HValue* value) {
    440     Bind(parameter_count(), value);
    441   }
    442 
    443   HValue* Lookup(Variable* variable) const {
    444     return Lookup(IndexFor(variable));
    445   }
    446 
    447   HValue* Lookup(int index) const {
    448     HValue* result = values_[index];
    449     ASSERT(result != NULL);
    450     return result;
    451   }
    452 
    453   HValue* LookupContext() const {
    454     // Return first special.
    455     return Lookup(parameter_count());
    456   }
    457 
    458   void Push(HValue* value) {
    459     ASSERT(value != NULL);
    460     ++push_count_;
    461     values_.Add(value);
    462   }
    463 
    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 
    476   HValue* Top() const { return ExpressionStackAt(0); }
    477 
    478   bool ExpressionStackIsEmpty() const;
    479 
    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 
    504   void ClearHistory() {
    505     pop_count_ = 0;
    506     push_count_ = 0;
    507     assigned_variables_.Rewind(0);
    508   }
    509 
    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.
    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:
    576   bool IsEffect() const { return kind_ == Expression::kEffect; }
    577   bool IsValue() const { return kind_ == Expression::kValue; }
    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 
    597   void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
    598   bool is_for_typeof() { return for_typeof_; }
    599 
    600  protected:
    601   AstContext(HGraphBuilder* owner, Expression::Context kind);
    602   virtual ~AstContext();
    603 
    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:
    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:
    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 
    646   bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
    647 
    648  private:
    649   ArgumentsAllowedFlag flag_;
    650 };
    651 
    652 
    653 class TestContext: public AstContext {
    654  public:
    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 
    669   static TestContext* cast(AstContext* context) {
    670     ASSERT(context->IsTest());
    671     return reinterpret_cast<TestContext*>(context);
    672   }
    673 
    674   Expression* condition() const { return condition_; }
    675   HBasicBlock* if_true() const { return if_true_; }
    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 
    704   CompilationInfo* compilation_info() { return compilation_info_; }
    705   TypeFeedbackOracle* oracle() { return oracle_; }
    706   AstContext* call_context() { return call_context_; }
    707   bool drop_extra() { return return_handling_ == DROP_EXTRA_ON_RETURN; }
    708   bool is_construct() { return return_handling_ == CONSTRUCT_CALL_RETURN; }
    709   HBasicBlock* function_return() { return function_return_; }
    710   TestContext* test_context() { return test_context_; }
    711   void ClearInlinedTestContext() {
    712     delete test_context_;
    713     test_context_ = NULL;
    714   }
    715 
    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)
    760         : target_(target),
    761           break_block_(NULL),
    762           continue_block_(NULL),
    763           drop_extra_(drop_extra) {
    764     }
    765 
    766     BreakableStatement* target() { return target_; }
    767     HBasicBlock* break_block() { return break_block_; }
    768     void set_break_block(HBasicBlock* block) { break_block_ = block; }
    769     HBasicBlock* continue_block() { return continue_block_; }
    770     void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
    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:
    784     BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
    785         : info_(info), owner_(owner), next_(owner->break_scope()) {
    786       owner->set_break_scope(this);
    787     }
    788 
    789     ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
    790 
    791     BreakAndContinueInfo* info() { return info_; }
    792     HGraphBuilder* owner() { return owner_; }
    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.
    809   HGraph* graph() const { return graph_; }
    810   BreakAndContinueScope* break_scope() const { return break_scope_; }
    811   void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
    812 
    813   HBasicBlock* current_block() const { return current_block_; }
    814   void set_current_block(HBasicBlock* block) { current_block_ = block; }
    815   HEnvironment* environment() const {
    816     return current_block()->last_environment();
    817   }
    818 
    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.
    826   void Push(HValue* value) { environment()->Push(value); }
    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 
    835   TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
    836 
    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.
    865   void set_function_state(FunctionState* state) { function_state_ = state; }
    866 
    867   AstContext* ast_context() const { return ast_context_; }
    868   void set_ast_context(AstContext* context) { ast_context_ = context; }
    869 
    870   // Accessors forwarded to the function state.
    871   CompilationInfo* info() const {
    872     return function_state()->compilation_info();
    873   }
    874   AstContext* call_context() const {
    875     return function_state()->call_context();
    876   }
    877   HBasicBlock* function_return() const {
    878     return function_state()->function_return();
    879   }
    880   TestContext* inlined_test_context() const {
    881     return function_state()->test_context();
    882   }
    883   void ClearInlinedTestContext() {
    884     function_state()->ClearInlinedTestContext();
    885   }
    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 
    940   HValue* Top() const { return environment()->Top(); }
    941   void Drop(int n) { environment()->Drop(n); }
    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 
   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 
   1160 Zone* AstContext::zone() { return owner_->zone(); }
   1161 
   1162 
   1163 class HValueMap: public ZoneObject {
   1164  public:
   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 
   1179   void Add(HValue* value) {
   1180     present_flags_.Add(value->gvn_flags());
   1181     Insert(value);
   1182   }
   1183 
   1184   HValue* Lookup(HValue* value) const;
   1185 
   1186   HValueMap* Copy(Zone* zone) const {
   1187     return new(zone) HValueMap(zone, this);
   1188   }
   1189 
   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);
   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);
   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:
   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 
   1260   explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
   1261   HPhase(const char* name, HGraph* graph) {
   1262     Begin(name, graph, NULL, NULL);
   1263   }
   1264   HPhase(const char* name, LChunk* chunk) {
   1265     Begin(name, NULL, chunk, NULL);
   1266   }
   1267   HPhase(const char* name, LAllocator* allocator) {
   1268     Begin(name, NULL, NULL, allocator);
   1269   }
   1270 
   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 
   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:
   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 
   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 
   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 
   1339   void PrintEmptyProperty(const char* name) {
   1340     PrintIndent();
   1341     trace_.Add("%s\n", name);
   1342   }
   1343 
   1344   void PrintStringProperty(const char* name, const char* value) {
   1345     PrintIndent();
   1346     trace_.Add("%s \"%s\"\n", name, value);
   1347   }
   1348 
   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 
   1354   void PrintBlockProperty(const char* name, int block_id) {
   1355     PrintIndent();
   1356     trace_.Add("%s \"B%d\"\n", name, block_id);
   1357   }
   1358 
   1359   void PrintIntProperty(const char* name, int value) {
   1360     PrintIndent();
   1361     trace_.Add("%s %d\n", name, value);
   1362   }
   1363 
   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