hydrogen.h 45.8 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef V8_HYDROGEN_H_
#define V8_HYDROGEN_H_

#include "v8.h"

33
#include "allocation.h"
34 35 36
#include "ast.h"
#include "compiler.h"
#include "hydrogen-instructions.h"
37
#include "type-info.h"
38 39 40 41 42 43
#include "zone.h"

namespace v8 {
namespace internal {

// Forward declarations.
44
class BitVector;
45
class FunctionState;
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
class HEnvironment;
class HGraph;
class HLoopInformation;
class HTracer;
class LAllocator;
class LChunk;
class LiveRange;


class HBasicBlock: public ZoneObject {
 public:
  explicit HBasicBlock(HGraph* graph);
  virtual ~HBasicBlock() { }

  // Simple accessors.
  int block_id() const { return block_id_; }
  void set_block_id(int id) { block_id_ = id; }
  HGraph* graph() const { return graph_; }
  const ZoneList<HPhi*>* phis() const { return &phis_; }
  HInstruction* first() const { return first_; }
66 67
  HInstruction* last() const { return last_; }
  void set_last(HInstruction* instr) { last_ = instr; }
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
  HInstruction* GetLastInstruction();
  HControlInstruction* end() const { return end_; }
  HLoopInformation* loop_information() const { return loop_information_; }
  const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
  bool HasPredecessor() const { return predecessors_.length() > 0; }
  const ZoneList<HBasicBlock*>* dominated_blocks() const {
    return &dominated_blocks_;
  }
  const ZoneList<int>* deleted_phis() const {
    return &deleted_phis_;
  }
  void RecordDeletedPhi(int merge_index) {
    deleted_phis_.Add(merge_index);
  }
  HBasicBlock* dominator() const { return dominator_; }
  HEnvironment* last_environment() const { return last_environment_; }
  int argument_count() const { return argument_count_; }
  void set_argument_count(int count) { argument_count_ = count; }
  int first_instruction_index() const { return first_instruction_index_; }
  void set_first_instruction_index(int index) {
    first_instruction_index_ = index;
  }
  int last_instruction_index() const { return last_instruction_index_; }
  void set_last_instruction_index(int index) {
    last_instruction_index_ = index;
  }

  void AttachLoopInformation();
  void DetachLoopInformation();
  bool IsLoopHeader() const { return loop_information() != NULL; }
  bool IsStartBlock() const { return block_id() == 0; }
  void PostProcessLoopHeader(IterationStatement* stmt);

  bool IsFinished() const { return end_ != NULL; }
  void AddPhi(HPhi* phi);
  void RemovePhi(HPhi* phi);
  void AddInstruction(HInstruction* instr);
  bool Dominates(HBasicBlock* other) const;
106
  int LoopNestingDepth() const;
107 108 109 110 111

  void SetInitialEnvironment(HEnvironment* env);
  void ClearEnvironment() { last_environment_ = NULL; }
  bool HasEnvironment() const { return last_environment_ != NULL; }
  void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
112
  HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
113 114

  void set_parent_loop_header(HBasicBlock* block) {
115 116
    ASSERT(parent_loop_header_ == NULL);
    parent_loop_header_ = block;
117 118
  }

119
  bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
120

121
  void SetJoinId(int ast_id);
122 123

  void Finish(HControlInstruction* last);
124
  void FinishExit(HControlInstruction* instruction);
125
  void Goto(HBasicBlock* block, FunctionState* state = NULL);
126 127

  int PredecessorIndexOf(HBasicBlock* predecessor) const;
128
  void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
129
  void AssignCommonDominator(HBasicBlock* other);
130
  void AssignLoopSuccessorDominators();
131

132 133
  void FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses) {
    FinishExit(CreateDeoptimize(has_uses));
134 135
  }

136 137
  // Add the inlined function exit sequence, adding an HLeaveInlined
  // instruction and updating the bailout environment.
138 139
  void AddLeaveInlined(HValue* return_value,
                       HBasicBlock* target,
140
                       FunctionState* state = NULL);
141 142 143 144 145 146 147 148 149 150

  // If a target block is tagged as an inline function return, all
  // predecessors should contain the inlined exit sequence:
  //
  // LeaveInlined
  // Simulate (caller's environment)
  // Goto (target block)
  bool IsInlineReturnTarget() const { return is_inline_return_target_; }
  void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }

151 152 153
  bool IsDeoptimizing() const { return is_deoptimizing_; }
  void MarkAsDeoptimizing() { is_deoptimizing_ = true; }

154 155 156 157 158 159 160
  bool IsLoopSuccessorDominator() const {
    return dominates_loop_successors_;
  }
  void MarkAsLoopSuccessorDominator() {
    dominates_loop_successors_ = true;
  }

161 162
  inline Zone* zone();

163 164 165 166 167 168 169 170
#ifdef DEBUG
  void Verify();
#endif

 private:
  void RegisterPredecessor(HBasicBlock* pred);
  void AddDominatedBlock(HBasicBlock* block);

171
  HSimulate* CreateSimulate(int ast_id);
172
  HDeoptimize* CreateDeoptimize(HDeoptimize::UseEnvironment has_uses);
173 174 175 176 177

  int block_id_;
  HGraph* graph_;
  ZoneList<HPhi*> phis_;
  HInstruction* first_;
178
  HInstruction* last_;
179 180 181 182 183 184 185 186 187 188 189 190
  HControlInstruction* end_;
  HLoopInformation* loop_information_;
  ZoneList<HBasicBlock*> predecessors_;
  HBasicBlock* dominator_;
  ZoneList<HBasicBlock*> dominated_blocks_;
  HEnvironment* last_environment_;
  // Outgoing parameter count at block exit, set during lithium translation.
  int argument_count_;
  // Instruction indices into the lithium code stream.
  int first_instruction_index_;
  int last_instruction_index_;
  ZoneList<int> deleted_phis_;
191
  HBasicBlock* parent_loop_header_;
192
  bool is_inline_return_target_;
193
  bool is_deoptimizing_;
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
  bool dominates_loop_successors_;
};


class HPredecessorIterator BASE_EMBEDDED {
 public:
  explicit HPredecessorIterator(HBasicBlock* block)
      : predecessor_list_(block->predecessors()), current_(0) { }

  bool Done() { return current_ >= predecessor_list_->length(); }
  HBasicBlock* Current() { return predecessor_list_->at(current_); }
  void Advance() { current_++; }

 private:
  const ZoneList<HBasicBlock*>* predecessor_list_;
  int current_;
210 211 212 213 214 215
};


class HLoopInformation: public ZoneObject {
 public:
  explicit HLoopInformation(HBasicBlock* loop_header)
216 217 218 219
      : back_edges_(4),
        loop_header_(loop_header),
        blocks_(8),
        stack_check_(NULL) {
220 221 222 223 224 225 226 227 228 229
    blocks_.Add(loop_header);
  }
  virtual ~HLoopInformation() {}

  const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
  const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
  HBasicBlock* loop_header() const { return loop_header_; }
  HBasicBlock* GetLastBackEdge() const;
  void RegisterBackEdge(HBasicBlock* block);

230 231 232 233 234
  HStackCheck* stack_check() const { return stack_check_; }
  void set_stack_check(HStackCheck* stack_check) {
    stack_check_ = stack_check;
  }

235 236 237 238 239 240
 private:
  void AddBlock(HBasicBlock* block);

  ZoneList<HBasicBlock*> back_edges_;
  HBasicBlock* loop_header_;
  ZoneList<HBasicBlock*> blocks_;
241
  HStackCheck* stack_check_;
242 243
};

244
class BoundsCheckTable;
245
class HGraph: public ZoneObject {
246 247 248
 public:
  explicit HGraph(CompilationInfo* info);

249 250 251
  Isolate* isolate() { return isolate_; }
  Zone* zone() { return isolate_->zone(); }

252 253
  const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
  const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
254
  HBasicBlock* entry_block() const { return entry_block_; }
255 256 257 258 259
  HEnvironment* start_environment() const { return start_environment_; }

  void InitializeInferredTypes();
  void InsertTypeConversions();
  void InsertRepresentationChanges();
260
  void MarkDeoptimizeOnUndefined();
261
  void ComputeMinusZeroChecks();
262 263
  bool ProcessArgumentsObject();
  void EliminateRedundantPhis();
264
  void EliminateUnreachablePhis();
265 266 267
  void Canonicalize();
  void OrderBlocks();
  void AssignDominators();
268
  void ReplaceCheckedValues();
269
  void EliminateRedundantBoundsChecks();
270
  void DehoistSimpleArrayIndexComputations();
271
  void PropagateDeoptimizingMark();
272 273 274

  // Returns false if there are phi-uses of the arguments-object
  // which are not supported by the optimizing compiler.
275
  bool CheckArgumentsPhiUses();
276

277 278 279 280 281
  // Returns false if there are phi-uses of an uninitialized const
  // which are not supported by the optimizing compiler.
  bool CheckConstPhiUses();

  void CollectPhis();
282

283
  Handle<Code> Compile(CompilationInfo* info);
284 285 286 287 288 289 290 291 292

  void set_undefined_constant(HConstant* constant) {
    undefined_constant_.set(constant);
  }
  HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
  HConstant* GetConstant1();
  HConstant* GetConstantMinus1();
  HConstant* GetConstantTrue();
  HConstant* GetConstantFalse();
293
  HConstant* GetConstantHole();
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315

  HBasicBlock* CreateBasicBlock();
  HArgumentsObject* GetArgumentsObject() const {
    return arguments_object_.get();
  }

  void SetArgumentsObject(HArgumentsObject* object) {
    arguments_object_.set(object);
  }

  int GetMaximumValueID() const { return values_.length(); }
  int GetNextBlockID() { return next_block_id_++; }
  int GetNextValueID(HValue* value) {
    values_.Add(value);
    return values_.length() - 1;
  }
  HValue* LookupValue(int id) const {
    if (id >= 0 && id < values_.length()) return values_[id];
    return NULL;
  }

#ifdef DEBUG
316
  void Verify(bool do_full_verify) const;
317 318
#endif

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
  bool has_osr_loop_entry() {
    return osr_loop_entry_.is_set();
  }

  HBasicBlock* osr_loop_entry() {
    return osr_loop_entry_.get();
  }

  void set_osr_loop_entry(HBasicBlock* entry) {
    osr_loop_entry_.set(entry);
  }

  ZoneList<HUnknownOSRValue*>* osr_values() {
    return osr_values_.get();
  }

  void set_osr_values(ZoneList<HUnknownOSRValue*>* values) {
    osr_values_.set(values);
  }

339 340 341 342 343 344 345 346 347 348 349 350
 private:
  void Postorder(HBasicBlock* block,
                 BitVector* visited,
                 ZoneList<HBasicBlock*>* order,
                 HBasicBlock* loop_header);
  void PostorderLoopBlocks(HLoopInformation* loop,
                           BitVector* visited,
                           ZoneList<HBasicBlock*>* order,
                           HBasicBlock* loop_header);
  HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
                         Object* value);

351
  void MarkAsDeoptimizingRecursively(HBasicBlock* block);
352 353
  void InsertTypeConversions(HInstruction* instr);
  void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
354
  void RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi);
355
  void InsertRepresentationChangeForUse(HValue* value,
356 357
                                        HValue* use_value,
                                        int use_index,
358
                                        Representation to);
359
  void InsertRepresentationChangesForValue(HValue* value);
360 361 362
  void InferTypes(ZoneList<HValue*>* worklist);
  void InitializeInferredTypes(int from_inclusive, int to_inclusive);
  void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
363
  void EliminateRedundantBoundsChecks(HBasicBlock* bb, BoundsCheckTable* table);
364

365
  Isolate* isolate_;
366
  int next_block_id_;
367
  HBasicBlock* entry_block_;
368 369 370 371 372 373 374 375 376
  HEnvironment* start_environment_;
  ZoneList<HBasicBlock*> blocks_;
  ZoneList<HValue*> values_;
  ZoneList<HPhi*>* phi_list_;
  SetOncePointer<HConstant> undefined_constant_;
  SetOncePointer<HConstant> constant_1_;
  SetOncePointer<HConstant> constant_minus1_;
  SetOncePointer<HConstant> constant_true_;
  SetOncePointer<HConstant> constant_false_;
377
  SetOncePointer<HConstant> constant_hole_;
378 379
  SetOncePointer<HArgumentsObject> arguments_object_;

380 381 382
  SetOncePointer<HBasicBlock> osr_loop_entry_;
  SetOncePointer<ZoneList<HUnknownOSRValue*> > osr_values_;

383 384 385 386
  DISALLOW_COPY_AND_ASSIGN(HGraph);
};


387 388 389
Zone* HBasicBlock::zone() { return graph_->zone(); }


390 391 392 393
// Type of stack frame an environment might refer to.
enum FrameType { JS_FUNCTION, JS_CONSTRUCT, ARGUMENTS_ADAPTOR };


394 395 396 397 398 399
class HEnvironment: public ZoneObject {
 public:
  HEnvironment(HEnvironment* outer,
               Scope* scope,
               Handle<JSFunction> closure);

400
  HEnvironment* DiscardInlined(bool drop_extra) {
401 402
    HEnvironment* outer = outer_;
    while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
403 404 405 406
    if (drop_extra) outer->Drop(1);
    return outer;
  }

407 408 409 410
  HEnvironment* arguments_environment() {
    return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
  }

411 412 413 414 415 416
  // Simple accessors.
  Handle<JSFunction> closure() const { return closure_; }
  const ZoneList<HValue*>* values() const { return &values_; }
  const ZoneList<int>* assigned_variables() const {
    return &assigned_variables_;
  }
417
  FrameType frame_type() const { return frame_type_; }
418
  int parameter_count() const { return parameter_count_; }
419
  int specials_count() const { return specials_count_; }
420 421 422 423 424 425 426 427 428
  int local_count() const { return local_count_; }
  HEnvironment* outer() const { return outer_; }
  int pop_count() const { return pop_count_; }
  int push_count() const { return push_count_; }

  int ast_id() const { return ast_id_; }
  void set_ast_id(int id) { ast_id_ = id; }

  int length() const { return values_.length(); }
429 430 431
  bool is_special_index(int i) const {
    return i >= parameter_count() && i < parameter_count() + specials_count();
  }
432

433 434 435 436
  int first_expression_index() const {
    return parameter_count() + specials_count() + local_count();
  }

437 438 439 440
  void Bind(Variable* variable, HValue* value) {
    Bind(IndexFor(variable), value);
  }

441
  void Bind(int index, HValue* value);
442

443 444 445 446
  void BindContext(HValue* value) {
    Bind(parameter_count(), value);
  }

447 448 449
  HValue* Lookup(Variable* variable) const {
    return Lookup(IndexFor(variable));
  }
450

451 452 453 454 455 456
  HValue* Lookup(int index) const {
    HValue* result = values_[index];
    ASSERT(result != NULL);
    return result;
  }

457 458 459 460 461
  HValue* LookupContext() const {
    // Return first special.
    return Lookup(parameter_count());
  }

462 463 464 465 466 467 468
  void Push(HValue* value) {
    ASSERT(value != NULL);
    ++push_count_;
    values_.Add(value);
  }

  HValue* Pop() {
469
    ASSERT(!ExpressionStackIsEmpty());
470 471 472 473 474 475 476 477
    if (push_count_ > 0) {
      --push_count_;
    } else {
      ++pop_count_;
    }
    return values_.RemoveLast();
  }

478
  void Drop(int count);
479

480
  HValue* Top() const { return ExpressionStackAt(0); }
481

482 483
  bool ExpressionStackIsEmpty() const;

484 485 486 487
  HValue* ExpressionStackAt(int index_from_top) const {
    int index = length() - index_from_top - 1;
    ASSERT(HasExpressionAt(index));
    return values_[index];
488
  }
489 490 491

  void SetExpressionStackAt(int index_from_top, HValue* value);

492 493 494 495 496 497
  HEnvironment* Copy() const;
  HEnvironment* CopyWithoutHistory() const;
  HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;

  // Create an "inlined version" of this environment, where the original
  // environment is the outer environment but the top expression stack
498
  // elements are moved to an inner environment as parameters.
499
  HEnvironment* CopyForInlining(Handle<JSFunction> target,
500
                                int arguments,
501
                                FunctionLiteral* function,
502
                                HConstant* undefined,
503 504
                                CallKind call_kind,
                                bool is_construct) const;
505 506

  void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
507

508 509 510
  void ClearHistory() {
    pop_count_ = 0;
    push_count_ = 0;
511
    assigned_variables_.Rewind(0);
512
  }
513

514
  void SetValueAt(int index, HValue* value) {
515
    ASSERT(index < length());
516 517 518 519 520 521 522 523 524
    values_[index] = value;
  }

  void PrintTo(StringStream* stream);
  void PrintToStd();

 private:
  explicit HEnvironment(const HEnvironment* other);

525 526 527 528
  HEnvironment(HEnvironment* outer,
               Handle<JSFunction> closure,
               FrameType frame_type,
               int arguments);
529

530 531 532 533 534 535
  // Create an artificial stub environment (e.g. for argument adaptor or
  // constructor stub).
  HEnvironment* CreateStubEnvironment(HEnvironment* outer,
                                      Handle<JSFunction> target,
                                      FrameType frame_type,
                                      int arguments) const;
536

537 538 539
  // True if index is included in the expression stack part of the environment.
  bool HasExpressionAt(int index) const;

540 541
  void Initialize(int parameter_count, int local_count, int stack_height);
  void Initialize(const HEnvironment* other);
542 543 544 545 546

  // Map a variable to an environment index.  Parameter indices are shifted
  // by 1 (receiver is parameter index -1 but environment index 0).
  // Stack-allocated local indices are shifted by the number of parameters.
  int IndexFor(Variable* variable) const {
547 548
    ASSERT(variable->IsStackAllocated());
    int shift = variable->IsParameter()
549 550
        ? 1
        : parameter_count_ + specials_count_;
551
    return variable->index() + shift;
552
  }
553 554

  Handle<JSFunction> closure_;
555
  // Value array [parameters] [specials] [locals] [temporaries].
556 557
  ZoneList<HValue*> values_;
  ZoneList<int> assigned_variables_;
558
  FrameType frame_type_;
559
  int parameter_count_;
560
  int specials_count_;
561 562 563 564 565 566 567 568 569 570
  int local_count_;
  HEnvironment* outer_;
  int pop_count_;
  int push_count_;
  int ast_id_;
};


class HGraphBuilder;

571 572 573 574 575
enum ArgumentsAllowedFlag {
  ARGUMENTS_NOT_ALLOWED,
  ARGUMENTS_ALLOWED
};

576 577
// This class is not BASE_EMBEDDED because our inlining implementation uses
// new and delete.
578 579 580 581 582 583
class AstContext {
 public:
  bool IsEffect() const { return kind_ == Expression::kEffect; }
  bool IsValue() const { return kind_ == Expression::kValue; }
  bool IsTest() const { return kind_ == Expression::kTest; }

584 585 586 587 588 589 590 591 592 593 594
  // 'Fill' this context with a hydrogen value.  The value is assumed to
  // have already been inserted in the instruction stream (or not need to
  // be, e.g., HPhi).  Call this function in tail position in the Visit
  // functions for expressions.
  virtual void ReturnValue(HValue* value) = 0;

  // Add a hydrogen instruction to the instruction stream (recording an
  // environment simulation if necessary) and then fill this context with
  // the instruction as value.
  virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;

595 596 597 598 599 600
  // Finishes the current basic block and materialize a boolean for
  // value context, nothing for effect, generate a branch for test context.
  // Call this function in tail position in the Visit functions for
  // expressions.
  virtual void ReturnControl(HControlInstruction* instr, int ast_id) = 0;

601 602 603
  void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
  bool is_for_typeof() { return for_typeof_; }

604 605 606 607
 protected:
  AstContext(HGraphBuilder* owner, Expression::Context kind);
  virtual ~AstContext();

608 609
  HGraphBuilder* owner() const { return owner_; }

610 611
  inline Zone* zone();

612 613 614
  // We want to be able to assert, in a context-specific way, that the stack
  // height makes sense when the context is filled.
#ifdef DEBUG
615
  int original_length_;
616 617
#endif

618 619 620 621
 private:
  HGraphBuilder* owner_;
  Expression::Context kind_;
  AstContext* outer_;
622
  bool for_typeof_;
623 624 625 626 627 628 629 630
};


class EffectContext: public AstContext {
 public:
  explicit EffectContext(HGraphBuilder* owner)
      : AstContext(owner, Expression::kEffect) {
  }
631 632 633 634
  virtual ~EffectContext();

  virtual void ReturnValue(HValue* value);
  virtual void ReturnInstruction(HInstruction* instr, int ast_id);
635
  virtual void ReturnControl(HControlInstruction* instr, int ast_id);
636 637 638 639 640
};


class ValueContext: public AstContext {
 public:
641 642
  explicit ValueContext(HGraphBuilder* owner, ArgumentsAllowedFlag flag)
      : AstContext(owner, Expression::kValue), flag_(flag) {
643
  }
644 645 646 647
  virtual ~ValueContext();

  virtual void ReturnValue(HValue* value);
  virtual void ReturnInstruction(HInstruction* instr, int ast_id);
648
  virtual void ReturnControl(HControlInstruction* instr, int ast_id);
649 650 651 652 653

  bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }

 private:
  ArgumentsAllowedFlag flag_;
654 655 656 657 658 659
};


class TestContext: public AstContext {
 public:
  TestContext(HGraphBuilder* owner,
660
              Expression* condition,
661
              HBasicBlock* if_true,
662
              HBasicBlock* if_false)
663
      : AstContext(owner, Expression::kTest),
664
        condition_(condition),
665
        if_true_(if_true),
666
        if_false_(if_false) {
667 668
  }

669 670
  virtual void ReturnValue(HValue* value);
  virtual void ReturnInstruction(HInstruction* instr, int ast_id);
671
  virtual void ReturnControl(HControlInstruction* instr, int ast_id);
672

673 674 675 676 677
  static TestContext* cast(AstContext* context) {
    ASSERT(context->IsTest());
    return reinterpret_cast<TestContext*>(context);
  }

678
  Expression* condition() const { return condition_; }
679 680 681 682
  HBasicBlock* if_true() const { return if_true_; }
  HBasicBlock* if_false() const { return if_false_; }

 private:
683 684 685 686
  // Build the shared core part of the translation unpacking a value into
  // control flow.
  void BuildBranch(HValue* value);

687
  Expression* condition_;
688 689 690 691 692
  HBasicBlock* if_true_;
  HBasicBlock* if_false_;
};


693 694 695 696 697 698 699
enum ReturnHandlingFlag {
  NORMAL_RETURN,
  DROP_EXTRA_ON_RETURN,
  CONSTRUCT_CALL_RETURN
};


700
class FunctionState {
701 702 703
 public:
  FunctionState(HGraphBuilder* owner,
                CompilationInfo* info,
704
                TypeFeedbackOracle* oracle,
705
                ReturnHandlingFlag return_handling);
706 707 708 709 710
  ~FunctionState();

  CompilationInfo* compilation_info() { return compilation_info_; }
  TypeFeedbackOracle* oracle() { return oracle_; }
  AstContext* call_context() { return call_context_; }
711 712
  bool drop_extra() { return return_handling_ == DROP_EXTRA_ON_RETURN; }
  bool is_construct() { return return_handling_ == CONSTRUCT_CALL_RETURN; }
713 714 715 716 717 718 719
  HBasicBlock* function_return() { return function_return_; }
  TestContext* test_context() { return test_context_; }
  void ClearInlinedTestContext() {
    delete test_context_;
    test_context_ = NULL;
  }

720 721
  FunctionState* outer() { return outer_; }

722 723 724 725 726 727 728 729 730 731
  HEnterInlined* entry() { return entry_; }
  void set_entry(HEnterInlined* entry) { entry_ = entry; }

  HArgumentsElements* arguments_elements() { return arguments_elements_; }
  void set_arguments_elements(HArgumentsElements* arguments_elements) {
    arguments_elements_ = arguments_elements;
  }

  bool arguments_pushed() { return arguments_elements() != NULL; }

732 733 734 735 736 737 738 739 740 741
 private:
  HGraphBuilder* owner_;

  CompilationInfo* compilation_info_;
  TypeFeedbackOracle* oracle_;

  // During function inlining, expression context of the call being
  // inlined. NULL when not inlining.
  AstContext* call_context_;

742 743 744 745 746
  // Indicate whether we have to perform special handling on return from
  // inlined functions.
  // - DROP_EXTRA_ON_RETURN: Drop an extra value from the environment.
  // - CONSTRUCT_CALL_RETURN: Either use allocated receiver or return value.
  ReturnHandlingFlag return_handling_;
747

748
  // When inlining in an effect or value context, this is the return block.
749 750 751 752 753 754 755 756 757
  // It is NULL otherwise.  When inlining in a test context, there are a
  // pair of return blocks in the context.  When not inlining, there is no
  // local return point.
  HBasicBlock* function_return_;

  // When inlining a call in a test context, a context containing a pair of
  // return blocks.  NULL in all other cases.
  TestContext* test_context_;

758 759 760 761 762 763
  // When inlining HEnterInlined instruction corresponding to the function
  // entry.
  HEnterInlined* entry_;

  HArgumentsElements* arguments_elements_;

764 765 766 767
  FunctionState* outer_;
};


768 769
class HGraphBuilder: public AstVisitor {
 public:
770
  enum BreakType { BREAK, CONTINUE };
771
  enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH };
772 773 774 775 776 777

  // A class encapsulating (lazily-allocated) break and continue blocks for
  // a breakable statement.  Separated from BreakAndContinueScope so that it
  // can have a separate lifetime.
  class BreakAndContinueInfo BASE_EMBEDDED {
   public:
778 779 780 781 782 783
    explicit BreakAndContinueInfo(BreakableStatement* target,
                                  int drop_extra = 0)
        : target_(target),
          break_block_(NULL),
          continue_block_(NULL),
          drop_extra_(drop_extra) {
784 785 786 787 788 789 790
    }

    BreakableStatement* target() { return target_; }
    HBasicBlock* break_block() { return break_block_; }
    void set_break_block(HBasicBlock* block) { break_block_ = block; }
    HBasicBlock* continue_block() { return continue_block_; }
    void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
791
    int drop_extra() { return drop_extra_; }
792 793 794 795 796

   private:
    BreakableStatement* target_;
    HBasicBlock* break_block_;
    HBasicBlock* continue_block_;
797
    int drop_extra_;
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
  };

  // A helper class to maintain a stack of current BreakAndContinueInfo
  // structures mirroring BreakableStatement nesting.
  class BreakAndContinueScope BASE_EMBEDDED {
   public:
    BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
        : info_(info), owner_(owner), next_(owner->break_scope()) {
      owner->set_break_scope(this);
    }

    ~BreakAndContinueScope() { owner_->set_break_scope(next_); }

    BreakAndContinueInfo* info() { return info_; }
    HGraphBuilder* owner() { return owner_; }
    BreakAndContinueScope* next() { return next_; }

    // Search the break stack for a break or continue target.
816
    HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra);
817 818 819 820 821 822 823

   private:
    BreakAndContinueInfo* info_;
    HGraphBuilder* owner_;
    BreakAndContinueScope* next_;
  };

824
  HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle);
825

826
  HGraph* CreateGraph();
827

828 829
  // Simple accessors.
  HGraph* graph() const { return graph_; }
830 831
  BreakAndContinueScope* break_scope() const { return break_scope_; }
  void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
832

833 834
  HBasicBlock* current_block() const { return current_block_; }
  void set_current_block(HBasicBlock* block) { current_block_ = block; }
835 836 837
  HEnvironment* environment() const {
    return current_block()->last_environment();
  }
838

839 840
  bool inline_bailout() { return inline_bailout_; }

841 842
  // Adding instructions.
  HInstruction* AddInstruction(HInstruction* instr);
843
  void AddSimulate(int ast_id);
844 845 846 847 848

  // Bailout environment manipulation.
  void Push(HValue* value) { environment()->Push(value); }
  HValue* Pop() { return environment()->Pop(); }

849 850
  void Bailout(const char* reason);

851 852 853 854
  HBasicBlock* CreateJoin(HBasicBlock* first,
                          HBasicBlock* second,
                          int join_id);

855 856
  TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }

857 858
  FunctionState* function_state() const { return function_state_; }

859 860
  void VisitDeclarations(ZoneList<Declaration*>* declarations);

861 862
 private:
  // Type of a member function that generates inline code for a native function.
863
  typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
864 865 866 867 868 869 870 871 872 873

  // Forward declarations for inner scope classes.
  class SubgraphScope;

  static const InlineFunctionGenerator kInlineFunctionGenerators[];

  static const int kMaxCallPolymorphism = 4;
  static const int kMaxLoadPolymorphism = 4;
  static const int kMaxStorePolymorphism = 4;

874 875
  // Even in the 'unlimited' case we have to have some limit in order not to
  // overflow the stack.
876 877 878
  static const int kUnlimitedMaxInlinedSourceSize = 100000;
  static const int kUnlimitedMaxInlinedNodes = 10000;
  static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
879

880
  // Simple accessors.
881 882
  void set_function_state(FunctionState* state) { function_state_ = state; }

883 884
  AstContext* ast_context() const { return ast_context_; }
  void set_ast_context(AstContext* context) { ast_context_ = context; }
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901

  // Accessors forwarded to the function state.
  CompilationInfo* info() const {
    return function_state()->compilation_info();
  }
  AstContext* call_context() const {
    return function_state()->call_context();
  }
  HBasicBlock* function_return() const {
    return function_state()->function_return();
  }
  TestContext* inlined_test_context() const {
    return function_state()->test_context();
  }
  void ClearInlinedTestContext() {
    function_state()->ClearInlinedTestContext();
  }
902
  StrictModeFlag function_strict_mode_flag() {
903 904
    return function_state()->compilation_info()->is_classic_mode()
        ? kNonStrictMode : kStrictMode;
mmaly@chromium.org's avatar
mmaly@chromium.org committed
905
  }
906 907

  // Generators for inline runtime functions.
908
#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize)      \
909
  void Generate##Name(CallRuntime* call);
910 911 912 913 914

  INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
  INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
#undef INLINE_FUNCTION_GENERATOR_DECLARATION

915 916 917 918 919 920 921 922 923
  void VisitDelete(UnaryOperation* expr);
  void VisitVoid(UnaryOperation* expr);
  void VisitTypeof(UnaryOperation* expr);
  void VisitAdd(UnaryOperation* expr);
  void VisitSub(UnaryOperation* expr);
  void VisitBitNot(UnaryOperation* expr);
  void VisitNot(UnaryOperation* expr);

  void VisitComma(BinaryOperation* expr);
924 925
  void VisitLogicalExpression(BinaryOperation* expr);
  void VisitArithmeticExpression(BinaryOperation* expr);
926

927
  bool PreProcessOsrEntry(IterationStatement* statement);
928 929
  // True iff. we are compiling for OSR and the statement is the entry.
  bool HasOsrEntryAt(IterationStatement* statement);
930
  void VisitLoopBody(IterationStatement* stmt,
931 932
                     HBasicBlock* loop_entry,
                     BreakAndContinueInfo* break_info);
933

934 935 936 937 938 939 940 941 942 943 944 945 946
  // Create a back edge in the flow graph.  body_exit is the predecessor
  // block and loop_entry is the successor block.  loop_successor is the
  // block where control flow exits the loop normally (e.g., via failure of
  // the condition) and break_block is the block where control flow breaks
  // from the loop.  All blocks except loop_entry can be NULL.  The return
  // value is the new successor block which is the join of loop_successor
  // and break_block, or NULL.
  HBasicBlock* CreateLoop(IterationStatement* statement,
                          HBasicBlock* loop_entry,
                          HBasicBlock* body_exit,
                          HBasicBlock* loop_successor,
                          HBasicBlock* break_block);

947 948 949 950
  HBasicBlock* JoinContinue(IterationStatement* statement,
                            HBasicBlock* exit_block,
                            HBasicBlock* continue_block);

951 952 953 954
  HValue* Top() const { return environment()->Top(); }
  void Drop(int n) { environment()->Drop(n); }
  void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }

955 956 957 958 959
  // The value of the arguments object is allowed in some but not most value
  // contexts.  (It's allowed in all effect contexts and disallowed in all
  // test contexts.)
  void VisitForValue(Expression* expr,
                     ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
960
  void VisitForTypeOf(Expression* expr);
961 962 963
  void VisitForEffect(Expression* expr);
  void VisitForControl(Expression* expr,
                       HBasicBlock* true_block,
964 965
                       HBasicBlock* false_block);

966
  // Visit an argument subexpression and emit a push to the outgoing
967 968 969
  // arguments.  Returns the hydrogen value that was pushed.
  HValue* VisitArgument(Expression* expr);

970 971
  void VisitArgumentList(ZoneList<Expression*>* arguments);

972 973 974
  // Visit a list of expressions from left to right, each in a value context.
  void VisitExpressions(ZoneList<Expression*>* exprs);

975 976 977 978
  void AddPhi(HPhi* phi);

  void PushAndAdd(HInstruction* instr);

979 980
  // Remove the arguments from the bailout environment and emit instructions
  // to push them as outgoing parameters.
981
  template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
982

983 984 985 986
  void TraceRepresentation(Token::Value op,
                           TypeInfo info,
                           HValue* value,
                           Representation rep);
987 988
  static Representation ToRepresentation(TypeInfo info);

989
  void SetUpScope(Scope* scope);
990 991 992 993 994 995 996
  virtual void VisitStatements(ZoneList<Statement*>* statements);

#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
  AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT

  HBasicBlock* CreateBasicBlock(HEnvironment* env);
997
  HBasicBlock* CreateLoopHeaderBlock();
998 999

  // Helpers for flow graph construction.
1000 1001 1002 1003 1004 1005 1006
  enum GlobalPropertyAccess {
    kUseCell,
    kUseGeneric
  };
  GlobalPropertyAccess LookupGlobalProperty(Variable* var,
                                            LookupResult* lookup,
                                            bool is_store);
1007

1008
  void EnsureArgumentsArePushedForAccess();
1009
  bool TryArgumentsAccess(Property* expr);
1010 1011

  // Try to optimize fun.apply(receiver, arguments) pattern.
1012
  bool TryCallApply(Call* expr);
1013

1014
  int InliningAstSize(Handle<JSFunction> target);
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
  bool TryInline(CallKind call_kind,
                 Handle<JSFunction> target,
                 ZoneList<Expression*>* arguments,
                 HValue* receiver,
                 int ast_id,
                 int return_id,
                 ReturnHandlingFlag return_handling);

  bool TryInlineCall(Call* expr, bool drop_extra = false);
  bool TryInlineConstruct(CallNew* expr, HValue* receiver);
1025
  bool TryInlineBuiltinMethodCall(Call* expr,
1026 1027 1028
                                  HValue* receiver,
                                  Handle<Map> receiver_map,
                                  CheckType check_type);
1029
  bool TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra);
1030 1031 1032 1033

  // If --trace-inlining, print a line of the inlining trace.  Inlining
  // succeeded if the reason string is NULL and failed if there is a
  // non-NULL reason string.
1034 1035 1036
  void TraceInline(Handle<JSFunction> target,
                   Handle<JSFunction> caller,
                   const char* failure_reason);
1037

1038
  void HandleGlobalVariableAssignment(Variable* var,
1039
                                      HValue* value,
1040 1041 1042
                                      int position,
                                      int ast_id);

1043 1044
  void HandlePropertyAssignment(Assignment* expr);
  void HandleCompoundAssignment(Assignment* expr);
1045 1046 1047 1048
  void HandlePolymorphicLoadNamedField(Property* expr,
                                       HValue* object,
                                       SmallMapList* types,
                                       Handle<String> name);
1049 1050 1051
  void HandlePolymorphicStoreNamedField(Assignment* expr,
                                        HValue* object,
                                        HValue* value,
1052
                                        SmallMapList* types,
1053 1054 1055
                                        Handle<String> name);
  void HandlePolymorphicCallNamed(Call* expr,
                                  HValue* receiver,
1056
                                  SmallMapList* types,
1057
                                  Handle<String> name);
1058
  void HandleLiteralCompareTypeof(CompareOperation* expr,
1059
                                  HTypeof* typeof_expr,
1060
                                  Handle<String> check);
1061
  void HandleLiteralCompareNil(CompareOperation* expr,
1062
                               HValue* value,
1063
                               NilValue nil);
1064

1065 1066
  HStringCharCodeAt* BuildStringCharCodeAt(HValue* context,
                                           HValue* string,
1067
                                           HValue* index);
1068 1069 1070
  HInstruction* BuildBinaryOperation(BinaryOperation* expr,
                                     HValue* left,
                                     HValue* right);
1071
  HInstruction* BuildIncrement(bool returns_original_input,
1072
                               CountOperation* expr);
1073 1074 1075 1076 1077
  HLoadNamedField* BuildLoadNamedField(HValue* object,
                                       Property* expr,
                                       Handle<Map> type,
                                       LookupResult* result,
                                       bool smi_and_map_check);
1078 1079 1080
  HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
  HInstruction* BuildLoadKeyedGeneric(HValue* object,
                                      HValue* key);
1081 1082 1083 1084
  HInstruction* BuildExternalArrayElementAccess(
      HValue* external_elements,
      HValue* checked_key,
      HValue* val,
1085
      ElementsKind elements_kind,
1086
      bool is_store);
1087 1088 1089 1090 1091
  HInstruction* BuildFastElementAccess(HValue* elements,
                                       HValue* checked_key,
                                       HValue* val,
                                       ElementsKind elements_kind,
                                       bool is_store);
1092 1093 1094 1095

  HInstruction* BuildMonomorphicElementAccess(HValue* object,
                                              HValue* key,
                                              HValue* val,
1096
                                              Handle<Map> map,
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
                                              bool is_store);
  HValue* HandlePolymorphicElementAccess(HValue* object,
                                         HValue* key,
                                         HValue* val,
                                         Expression* prop,
                                         int ast_id,
                                         int position,
                                         bool is_store,
                                         bool* has_side_effects);

  HValue* HandleKeyedElementAccess(HValue* obj,
                                   HValue* key,
                                   HValue* val,
                                   Expression* expr,
                                   int ast_id,
                                   int position,
                                   bool is_store,
                                   bool* has_side_effects);
1115

1116 1117 1118 1119 1120 1121 1122
  HInstruction* BuildLoadNamed(HValue* object,
                               Property* prop,
                               Handle<Map> map,
                               Handle<String> name);
  HInstruction* BuildStoreNamed(HValue* object,
                                HValue* value,
                                Expression* expr);
1123 1124 1125
  HInstruction* BuildStoreNamed(HValue* object,
                                HValue* value,
                                ObjectLiteral::Property* prop);
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
  HInstruction* BuildStoreNamedField(HValue* object,
                                     Handle<String> name,
                                     HValue* value,
                                     Handle<Map> type,
                                     LookupResult* lookup,
                                     bool smi_and_map_check);
  HInstruction* BuildStoreNamedGeneric(HValue* object,
                                       Handle<String> name,
                                       HValue* value);
  HInstruction* BuildStoreKeyedGeneric(HValue* object,
                                       HValue* key,
                                       HValue* value);

1139 1140
  HValue* BuildContextChainWalk(Variable* var);

1141 1142 1143 1144 1145
  void AddCheckConstantFunction(Call* expr,
                                HValue* receiver,
                                Handle<Map> receiver_map,
                                bool smi_and_map_check);

1146
  Zone* zone() { return zone_; }
1147

1148 1149 1150 1151 1152 1153
  // The translation state of the currently-being-translated function.
  FunctionState* function_state_;

  // The base of the function state stack.
  FunctionState initial_function_state_;

1154 1155 1156 1157
  // Expression context of the currently visited subexpression. NULL when
  // visiting statements.
  AstContext* ast_context_;

1158 1159
  // A stack of breakable statements entered.
  BreakAndContinueScope* break_scope_;
1160

1161
  HGraph* graph_;
1162
  HBasicBlock* current_block_;
1163 1164

  int inlined_count_;
1165
  ZoneList<Handle<Object> > globals_;
1166

1167 1168
  Zone* zone_;

1169 1170
  bool inline_bailout_;

1171
  friend class FunctionState;  // Pushes and pops the state stack.
1172 1173 1174 1175 1176 1177
  friend class AstContext;  // Pushes and pops the AST context stack.

  DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
};


1178 1179 1180
Zone* AstContext::zone() { return owner_->zone(); }


1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
class HValueMap: public ZoneObject {
 public:
  HValueMap()
      : array_size_(0),
        lists_size_(0),
        count_(0),
        present_flags_(0),
        array_(NULL),
        lists_(NULL),
        free_list_head_(kNil) {
    ResizeLists(kInitialSize);
    Resize(kInitialSize);
  }

1195
  void Kill(GVNFlagSet flags);
1196 1197

  void Add(HValue* value) {
1198
    present_flags_.Add(value->gvn_flags());
1199 1200 1201 1202
    Insert(value);
  }

  HValue* Lookup(HValue* value) const;
1203 1204

  HValueMap* Copy(Zone* zone) const {
1205
    return new(zone) HValueMap(zone, this);
1206
  }
1207

1208 1209
  bool IsEmpty() const { return count_ == 0; }

1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
 private:
  // A linked list of HValue* values.  Stored in arrays.
  struct HValueMapListElement {
    HValue* value;
    int next;  // Index in the array of the next list element.
  };
  static const int kNil = -1;  // The end of a linked list

  // Must be a power of 2.
  static const int kInitialSize = 16;

1221
  HValueMap(Zone* zone, const HValueMap* other);
1222 1223 1224 1225 1226 1227 1228 1229 1230

  void Resize(int new_size);
  void ResizeLists(int new_size);
  void Insert(HValue* value);
  uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }

  int array_size_;
  int lists_size_;
  int count_;  // The number of values stored in the HValueMap.
1231 1232
  GVNFlagSet present_flags_;  // All flags that are in any value in the
                              // HValueMap.
1233 1234 1235 1236 1237 1238 1239
  HValueMapListElement* array_;  // Primary store - contains the first value
  // with a given hash.  Colliding elements are stored in linked lists.
  HValueMapListElement* lists_;  // The linked lists containing hash collisions.
  int free_list_head_;  // Unused elements in lists_ are on the free list.
};


1240 1241 1242
class HSideEffectMap BASE_EMBEDDED {
 public:
  HSideEffectMap();
1243
  explicit HSideEffectMap(HSideEffectMap* other);
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263

  void Kill(GVNFlagSet flags);

  void Store(GVNFlagSet flags, HInstruction* instr);

  bool IsEmpty() const { return count_ == 0; }

  inline HInstruction* operator[](int i) const {
    ASSERT(0 <= i);
    ASSERT(i < kNumberOfTrackedSideEffects);
    return data_[i];
  }
  inline HInstruction* at(int i) const { return operator[](i); }

 private:
  int count_;
  HInstruction* data_[kNumberOfTrackedSideEffects];
};


1264 1265
class HStatistics: public Malloced {
 public:
1266
  void Initialize(CompilationInfo* info);
1267
  void Print();
1268
  void SaveTiming(const char* name, int64_t ticks, unsigned size);
1269 1270 1271 1272 1273 1274 1275 1276 1277
  static HStatistics* Instance() {
    static SetOncePointer<HStatistics> instance;
    if (!instance.is_set()) {
      instance.set(new HStatistics());
    }
    return instance.get();
  }

 private:
1278 1279 1280 1281 1282 1283
  HStatistics()
      : timing_(5),
        names_(5),
        sizes_(5),
        total_(0),
        total_size_(0),
1284 1285
        full_code_gen_(0),
        source_size_(0) { }
1286 1287 1288

  List<int64_t> timing_;
  List<const char*> names_;
1289
  List<unsigned> sizes_;
1290
  int64_t total_;
1291
  unsigned total_size_;
1292
  int64_t full_code_gen_;
1293
  double source_size_;
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
};


class HPhase BASE_EMBEDDED {
 public:
  static const char* const kFullCodeGen;
  static const char* const kTotal;

  explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
  HPhase(const char* name, HGraph* graph) {
    Begin(name, graph, NULL, NULL);
  }
  HPhase(const char* name, LChunk* chunk) {
    Begin(name, NULL, chunk, NULL);
  }
  HPhase(const char* name, LAllocator* allocator) {
    Begin(name, NULL, NULL, allocator);
  }

  ~HPhase() {
    End();
  }

 private:
  void Begin(const char* name,
             HGraph* graph,
             LChunk* chunk,
             LAllocator* allocator);
  void End() const;

  int64_t start_;
  const char* name_;
  HGraph* graph_;
  LChunk* chunk_;
  LAllocator* allocator_;
1329
  unsigned start_allocation_size_;
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
};


class HTracer: public Malloced {
 public:
  void TraceCompilation(FunctionLiteral* function);
  void TraceHydrogen(const char* name, HGraph* graph);
  void TraceLithium(const char* name, LChunk* chunk);
  void TraceLiveRanges(const char* name, LAllocator* allocator);

  static HTracer* Instance() {
    static SetOncePointer<HTracer> instance;
    if (!instance.is_set()) {
      instance.set(new HTracer("hydrogen.cfg"));
    }
    return instance.get();
  }

 private:
  class Tag BASE_EMBEDDED {
   public:
    Tag(HTracer* tracer, const char* name) {
      name_ = name;
      tracer_ = tracer;
      tracer->PrintIndent();
      tracer->trace_.Add("begin_%s\n", name);
      tracer->indent_++;
    }

    ~Tag() {
      tracer_->indent_--;
      tracer_->PrintIndent();
      tracer_->trace_.Add("end_%s\n", name_);
      ASSERT(tracer_->indent_ >= 0);
      tracer_->FlushToFile();
    }

   private:
    HTracer* tracer_;
    const char* name_;
  };

  explicit HTracer(const char* filename)
      : filename_(filename), trace_(&string_allocator_), indent_(0) {
    WriteChars(filename, "", 0, false);
  }

  void TraceLiveRange(LiveRange* range, const char* type);
  void Trace(const char* name, HGraph* graph, LChunk* chunk);
  void FlushToFile();

  void PrintEmptyProperty(const char* name) {
    PrintIndent();
    trace_.Add("%s\n", name);
  }

  void PrintStringProperty(const char* name, const char* value) {
    PrintIndent();
    trace_.Add("%s \"%s\"\n", name, value);
  }

  void PrintLongProperty(const char* name, int64_t value) {
    PrintIndent();
    trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
  }

  void PrintBlockProperty(const char* name, int block_id) {
    PrintIndent();
    trace_.Add("%s \"B%d\"\n", name, block_id);
  }

  void PrintIntProperty(const char* name, int value) {
    PrintIndent();
    trace_.Add("%s %d\n", name, value);
  }

  void PrintIndent() {
    for (int i = 0; i < indent_; i++) {
      trace_.Add("  ");
    }
  }

  const char* filename_;
  HeapStringAllocator string_allocator_;
  StringStream trace_;
  int indent_;
};


} }  // namespace v8::internal

#endif  // V8_HYDROGEN_H_