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
40namespace v8 {
41namespace internal {
42
43// Forward declarations.
44class BitVector;
45class HEnvironment;
46class HGraph;
47class HLoopInformation;
48class HTracer;
49class LAllocator;
50class LChunk;
51class LiveRange;
52
53
54class 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
197class 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
212class 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
244class 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
383Zone* HBasicBlock::zone() { return graph_->zone(); }
384
385
386// Type of stack frame an environment might refer to.
387enum FrameType { JS_FUNCTION, JS_CONSTRUCT, ARGUMENTS_ADAPTOR };
388
389
390class 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
565class HGraphBuilder;
566
567enum 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.
574class 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
622class 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
635class 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
653class 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
689enum ReturnHandlingFlag {
690  NORMAL_RETURN,
691  DROP_EXTRA_ON_RETURN,
692  CONSTRUCT_CALL_RETURN
693};
694
695
696class 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
748class 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
1160Zone* AstContext::zone() { return owner_->zone(); }
1161
1162
1163class 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
1222class 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
1255class 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
1291class 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