hydrogen.h revision 8b112d2025046f85ef7f6be087c6129c872ebad2
1// Copyright 2011 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 "ast.h"
34#include "compiler.h"
35#include "data-flow.h"
36#include "hydrogen-instructions.h"
37#include "zone.h"
38
39namespace v8 {
40namespace internal {
41
42// Forward declarations.
43class HEnvironment;
44class HGraph;
45class HLoopInformation;
46class HTracer;
47class LAllocator;
48class LChunk;
49class LiveRange;
50
51
52class HBasicBlock: public ZoneObject {
53 public:
54  explicit HBasicBlock(HGraph* graph);
55  virtual ~HBasicBlock() { }
56
57  // Simple accessors.
58  int block_id() const { return block_id_; }
59  void set_block_id(int id) { block_id_ = id; }
60  HGraph* graph() const { return graph_; }
61  const ZoneList<HPhi*>* phis() const { return &phis_; }
62  HInstruction* first() const { return first_; }
63  HInstruction* last() const { return last_; }
64  void set_last(HInstruction* instr) { last_ = instr; }
65  HInstruction* GetLastInstruction();
66  HControlInstruction* end() const { return end_; }
67  HLoopInformation* loop_information() const { return loop_information_; }
68  const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
69  bool HasPredecessor() const { return predecessors_.length() > 0; }
70  const ZoneList<HBasicBlock*>* dominated_blocks() const {
71    return &dominated_blocks_;
72  }
73  const ZoneList<int>* deleted_phis() const {
74    return &deleted_phis_;
75  }
76  void RecordDeletedPhi(int merge_index) {
77    deleted_phis_.Add(merge_index);
78  }
79  HBasicBlock* dominator() const { return dominator_; }
80  HEnvironment* last_environment() const { return last_environment_; }
81  int argument_count() const { return argument_count_; }
82  void set_argument_count(int count) { argument_count_ = count; }
83  int first_instruction_index() const { return first_instruction_index_; }
84  void set_first_instruction_index(int index) {
85    first_instruction_index_ = index;
86  }
87  int last_instruction_index() const { return last_instruction_index_; }
88  void set_last_instruction_index(int index) {
89    last_instruction_index_ = index;
90  }
91
92  void AttachLoopInformation();
93  void DetachLoopInformation();
94  bool IsLoopHeader() const { return loop_information() != NULL; }
95  bool IsStartBlock() const { return block_id() == 0; }
96  void PostProcessLoopHeader(IterationStatement* stmt);
97
98  bool IsFinished() const { return end_ != NULL; }
99  void AddPhi(HPhi* phi);
100  void RemovePhi(HPhi* phi);
101  void AddInstruction(HInstruction* instr);
102  bool Dominates(HBasicBlock* other) const;
103
104  void SetInitialEnvironment(HEnvironment* env);
105  void ClearEnvironment() { last_environment_ = NULL; }
106  bool HasEnvironment() const { return last_environment_ != NULL; }
107  void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
108  HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
109
110  void set_parent_loop_header(HBasicBlock* block) {
111    ASSERT(parent_loop_header_ == NULL);
112    parent_loop_header_ = block;
113  }
114
115  bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
116
117  void SetJoinId(int id);
118
119  void Finish(HControlInstruction* last);
120  void FinishExit(HControlInstruction* instruction);
121  void Goto(HBasicBlock* block, bool include_stack_check = false);
122
123  int PredecessorIndexOf(HBasicBlock* predecessor) const;
124  void AddSimulate(int id) { AddInstruction(CreateSimulate(id)); }
125  void AssignCommonDominator(HBasicBlock* other);
126
127  void FinishExitWithDeoptimization() {
128    FinishExit(CreateDeoptimize());
129  }
130
131  // Add the inlined function exit sequence, adding an HLeaveInlined
132  // instruction and updating the bailout environment.
133  void AddLeaveInlined(HValue* return_value, HBasicBlock* target);
134
135  // If a target block is tagged as an inline function return, all
136  // predecessors should contain the inlined exit sequence:
137  //
138  // LeaveInlined
139  // Simulate (caller's environment)
140  // Goto (target block)
141  bool IsInlineReturnTarget() const { return is_inline_return_target_; }
142  void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
143
144  inline Zone* zone();
145
146#ifdef DEBUG
147  void Verify();
148#endif
149
150 private:
151  void RegisterPredecessor(HBasicBlock* pred);
152  void AddDominatedBlock(HBasicBlock* block);
153
154  HSimulate* CreateSimulate(int id);
155  HDeoptimize* CreateDeoptimize();
156
157  int block_id_;
158  HGraph* graph_;
159  ZoneList<HPhi*> phis_;
160  HInstruction* first_;
161  HInstruction* last_;
162  HControlInstruction* end_;
163  HLoopInformation* loop_information_;
164  ZoneList<HBasicBlock*> predecessors_;
165  HBasicBlock* dominator_;
166  ZoneList<HBasicBlock*> dominated_blocks_;
167  HEnvironment* last_environment_;
168  // Outgoing parameter count at block exit, set during lithium translation.
169  int argument_count_;
170  // Instruction indices into the lithium code stream.
171  int first_instruction_index_;
172  int last_instruction_index_;
173  ZoneList<int> deleted_phis_;
174  HBasicBlock* parent_loop_header_;
175  bool is_inline_return_target_;
176};
177
178
179class HLoopInformation: public ZoneObject {
180 public:
181  explicit HLoopInformation(HBasicBlock* loop_header)
182      : back_edges_(4), loop_header_(loop_header), blocks_(8) {
183    blocks_.Add(loop_header);
184  }
185  virtual ~HLoopInformation() {}
186
187  const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
188  const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
189  HBasicBlock* loop_header() const { return loop_header_; }
190  HBasicBlock* GetLastBackEdge() const;
191  void RegisterBackEdge(HBasicBlock* block);
192
193 private:
194  void AddBlock(HBasicBlock* block);
195
196  ZoneList<HBasicBlock*> back_edges_;
197  HBasicBlock* loop_header_;
198  ZoneList<HBasicBlock*> blocks_;
199};
200
201
202class HGraph: public ZoneObject {
203 public:
204  explicit HGraph(CompilationInfo* info);
205
206  Isolate* isolate() { return isolate_; }
207  Zone* zone() { return isolate_->zone(); }
208
209  const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
210  const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
211  HBasicBlock* entry_block() const { return entry_block_; }
212  HEnvironment* start_environment() const { return start_environment_; }
213
214  void InitializeInferredTypes();
215  void InsertTypeConversions();
216  void InsertRepresentationChanges();
217  void ComputeMinusZeroChecks();
218  bool ProcessArgumentsObject();
219  void EliminateRedundantPhis();
220  void EliminateUnreachablePhis();
221  void Canonicalize();
222  void OrderBlocks();
223  void AssignDominators();
224
225  // Returns false if there are phi-uses of the arguments-object
226  // which are not supported by the optimizing compiler.
227  bool CollectPhis();
228
229  Handle<Code> Compile(CompilationInfo* info);
230
231  void set_undefined_constant(HConstant* constant) {
232    undefined_constant_.set(constant);
233  }
234  HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
235  HConstant* GetConstant1();
236  HConstant* GetConstantMinus1();
237  HConstant* GetConstantTrue();
238  HConstant* GetConstantFalse();
239
240  HBasicBlock* CreateBasicBlock();
241  HArgumentsObject* GetArgumentsObject() const {
242    return arguments_object_.get();
243  }
244  bool HasArgumentsObject() const { return arguments_object_.is_set(); }
245
246  void SetArgumentsObject(HArgumentsObject* object) {
247    arguments_object_.set(object);
248  }
249
250  int GetMaximumValueID() const { return values_.length(); }
251  int GetNextBlockID() { return next_block_id_++; }
252  int GetNextValueID(HValue* value) {
253    values_.Add(value);
254    return values_.length() - 1;
255  }
256  HValue* LookupValue(int id) const {
257    if (id >= 0 && id < values_.length()) return values_[id];
258    return NULL;
259  }
260
261#ifdef DEBUG
262  void Verify() const;
263#endif
264
265 private:
266  void Postorder(HBasicBlock* block,
267                 BitVector* visited,
268                 ZoneList<HBasicBlock*>* order,
269                 HBasicBlock* loop_header);
270  void PostorderLoopBlocks(HLoopInformation* loop,
271                           BitVector* visited,
272                           ZoneList<HBasicBlock*>* order,
273                           HBasicBlock* loop_header);
274  HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
275                         Object* value);
276
277  void InsertTypeConversions(HInstruction* instr);
278  void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
279  void InsertRepresentationChangeForUse(HValue* value,
280                                        HValue* use,
281                                        Representation to);
282  void InsertRepresentationChangesForValue(HValue* current,
283                                           ZoneList<HValue*>* value_list,
284                                           ZoneList<Representation>* rep_list);
285  void InferTypes(ZoneList<HValue*>* worklist);
286  void InitializeInferredTypes(int from_inclusive, int to_inclusive);
287  void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
288
289  Isolate* isolate_;
290  int next_block_id_;
291  HBasicBlock* entry_block_;
292  HEnvironment* start_environment_;
293  ZoneList<HBasicBlock*> blocks_;
294  ZoneList<HValue*> values_;
295  ZoneList<HPhi*>* phi_list_;
296  SetOncePointer<HConstant> undefined_constant_;
297  SetOncePointer<HConstant> constant_1_;
298  SetOncePointer<HConstant> constant_minus1_;
299  SetOncePointer<HConstant> constant_true_;
300  SetOncePointer<HConstant> constant_false_;
301  SetOncePointer<HArgumentsObject> arguments_object_;
302
303  DISALLOW_COPY_AND_ASSIGN(HGraph);
304};
305
306
307Zone* HBasicBlock::zone() { return graph_->zone(); }
308
309
310class HEnvironment: public ZoneObject {
311 public:
312  HEnvironment(HEnvironment* outer,
313               Scope* scope,
314               Handle<JSFunction> closure);
315
316  // Simple accessors.
317  Handle<JSFunction> closure() const { return closure_; }
318  const ZoneList<HValue*>* values() const { return &values_; }
319  const ZoneList<int>* assigned_variables() const {
320    return &assigned_variables_;
321  }
322  int parameter_count() const { return parameter_count_; }
323  int local_count() const { return local_count_; }
324  HEnvironment* outer() const { return outer_; }
325  int pop_count() const { return pop_count_; }
326  int push_count() const { return push_count_; }
327
328  int ast_id() const { return ast_id_; }
329  void set_ast_id(int id) { ast_id_ = id; }
330
331  int length() const { return values_.length(); }
332
333  void Bind(Variable* variable, HValue* value) {
334    Bind(IndexFor(variable), value);
335  }
336
337  void Bind(int index, HValue* value);
338
339  HValue* Lookup(Variable* variable) const {
340    return Lookup(IndexFor(variable));
341  }
342
343  HValue* Lookup(int index) const {
344    HValue* result = values_[index];
345    ASSERT(result != NULL);
346    return result;
347  }
348
349  void Push(HValue* value) {
350    ASSERT(value != NULL);
351    ++push_count_;
352    values_.Add(value);
353  }
354
355  HValue* Pop() {
356    ASSERT(!ExpressionStackIsEmpty());
357    if (push_count_ > 0) {
358      --push_count_;
359    } else {
360      ++pop_count_;
361    }
362    return values_.RemoveLast();
363  }
364
365  void Drop(int count);
366
367  HValue* Top() const { return ExpressionStackAt(0); }
368
369  HValue* ExpressionStackAt(int index_from_top) const {
370    int index = length() - index_from_top - 1;
371    ASSERT(HasExpressionAt(index));
372    return values_[index];
373  }
374
375  void SetExpressionStackAt(int index_from_top, HValue* value);
376
377  HEnvironment* Copy() const;
378  HEnvironment* CopyWithoutHistory() const;
379  HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
380
381  // Create an "inlined version" of this environment, where the original
382  // environment is the outer environment but the top expression stack
383  // elements are moved to an inner environment as parameters. If
384  // is_speculative, the argument values are expected to be PushArgument
385  // instructions, otherwise they are the actual values.
386  HEnvironment* CopyForInlining(Handle<JSFunction> target,
387                                FunctionLiteral* function,
388                                bool is_speculative,
389                                HConstant* undefined) const;
390
391  void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
392
393  void ClearHistory() {
394    pop_count_ = 0;
395    push_count_ = 0;
396    assigned_variables_.Rewind(0);
397  }
398
399  void SetValueAt(int index, HValue* value) {
400    ASSERT(index < length());
401    values_[index] = value;
402  }
403
404  void PrintTo(StringStream* stream);
405  void PrintToStd();
406
407 private:
408  explicit HEnvironment(const HEnvironment* other);
409
410  // True if index is included in the expression stack part of the environment.
411  bool HasExpressionAt(int index) const;
412
413  bool ExpressionStackIsEmpty() const;
414
415  void Initialize(int parameter_count, int local_count, int stack_height);
416  void Initialize(const HEnvironment* other);
417
418  // Map a variable to an environment index.  Parameter indices are shifted
419  // by 1 (receiver is parameter index -1 but environment index 0).
420  // Stack-allocated local indices are shifted by the number of parameters.
421  int IndexFor(Variable* variable) const {
422    Slot* slot = variable->AsSlot();
423    ASSERT(slot != NULL && slot->IsStackAllocated());
424    int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
425    return slot->index() + shift;
426  }
427
428  Handle<JSFunction> closure_;
429  // Value array [parameters] [locals] [temporaries].
430  ZoneList<HValue*> values_;
431  ZoneList<int> assigned_variables_;
432  int parameter_count_;
433  int local_count_;
434  HEnvironment* outer_;
435  int pop_count_;
436  int push_count_;
437  int ast_id_;
438};
439
440
441class HGraphBuilder;
442
443// This class is not BASE_EMBEDDED because our inlining implementation uses
444// new and delete.
445class AstContext {
446 public:
447  bool IsEffect() const { return kind_ == Expression::kEffect; }
448  bool IsValue() const { return kind_ == Expression::kValue; }
449  bool IsTest() const { return kind_ == Expression::kTest; }
450
451  // 'Fill' this context with a hydrogen value.  The value is assumed to
452  // have already been inserted in the instruction stream (or not need to
453  // be, e.g., HPhi).  Call this function in tail position in the Visit
454  // functions for expressions.
455  virtual void ReturnValue(HValue* value) = 0;
456
457  // Add a hydrogen instruction to the instruction stream (recording an
458  // environment simulation if necessary) and then fill this context with
459  // the instruction as value.
460  virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
461
462  void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
463  bool is_for_typeof() { return for_typeof_; }
464
465 protected:
466  AstContext(HGraphBuilder* owner, Expression::Context kind);
467  virtual ~AstContext();
468
469  HGraphBuilder* owner() const { return owner_; }
470
471  inline Zone* zone();
472
473  // We want to be able to assert, in a context-specific way, that the stack
474  // height makes sense when the context is filled.
475#ifdef DEBUG
476  int original_length_;
477#endif
478
479 private:
480  HGraphBuilder* owner_;
481  Expression::Context kind_;
482  AstContext* outer_;
483  bool for_typeof_;
484};
485
486
487class EffectContext: public AstContext {
488 public:
489  explicit EffectContext(HGraphBuilder* owner)
490      : AstContext(owner, Expression::kEffect) {
491  }
492  virtual ~EffectContext();
493
494  virtual void ReturnValue(HValue* value);
495  virtual void ReturnInstruction(HInstruction* instr, int ast_id);
496};
497
498
499class ValueContext: public AstContext {
500 public:
501  explicit ValueContext(HGraphBuilder* owner)
502      : AstContext(owner, Expression::kValue) {
503  }
504  virtual ~ValueContext();
505
506  virtual void ReturnValue(HValue* value);
507  virtual void ReturnInstruction(HInstruction* instr, int ast_id);
508};
509
510
511class TestContext: public AstContext {
512 public:
513  TestContext(HGraphBuilder* owner,
514              HBasicBlock* if_true,
515              HBasicBlock* if_false)
516      : AstContext(owner, Expression::kTest),
517        if_true_(if_true),
518        if_false_(if_false) {
519  }
520
521  virtual void ReturnValue(HValue* value);
522  virtual void ReturnInstruction(HInstruction* instr, int ast_id);
523
524  static TestContext* cast(AstContext* context) {
525    ASSERT(context->IsTest());
526    return reinterpret_cast<TestContext*>(context);
527  }
528
529  HBasicBlock* if_true() const { return if_true_; }
530  HBasicBlock* if_false() const { return if_false_; }
531
532 private:
533  // Build the shared core part of the translation unpacking a value into
534  // control flow.
535  void BuildBranch(HValue* value);
536
537  HBasicBlock* if_true_;
538  HBasicBlock* if_false_;
539};
540
541
542class FunctionState BASE_EMBEDDED {
543 public:
544  FunctionState(HGraphBuilder* owner,
545                CompilationInfo* info,
546                TypeFeedbackOracle* oracle);
547  ~FunctionState();
548
549  CompilationInfo* compilation_info() { return compilation_info_; }
550  TypeFeedbackOracle* oracle() { return oracle_; }
551  AstContext* call_context() { return call_context_; }
552  HBasicBlock* function_return() { return function_return_; }
553  TestContext* test_context() { return test_context_; }
554  void ClearInlinedTestContext() {
555    delete test_context_;
556    test_context_ = NULL;
557  }
558
559  FunctionState* outer() { return outer_; }
560
561 private:
562  HGraphBuilder* owner_;
563
564  CompilationInfo* compilation_info_;
565  TypeFeedbackOracle* oracle_;
566
567  // During function inlining, expression context of the call being
568  // inlined. NULL when not inlining.
569  AstContext* call_context_;
570
571  // When inlining in an effect of value context, this is the return block.
572  // It is NULL otherwise.  When inlining in a test context, there are a
573  // pair of return blocks in the context.  When not inlining, there is no
574  // local return point.
575  HBasicBlock* function_return_;
576
577  // When inlining a call in a test context, a context containing a pair of
578  // return blocks.  NULL in all other cases.
579  TestContext* test_context_;
580
581  FunctionState* outer_;
582};
583
584
585class HGraphBuilder: public AstVisitor {
586 public:
587  enum BreakType { BREAK, CONTINUE };
588
589  // A class encapsulating (lazily-allocated) break and continue blocks for
590  // a breakable statement.  Separated from BreakAndContinueScope so that it
591  // can have a separate lifetime.
592  class BreakAndContinueInfo BASE_EMBEDDED {
593   public:
594    explicit BreakAndContinueInfo(BreakableStatement* target)
595      : target_(target), break_block_(NULL), continue_block_(NULL) {
596    }
597
598    BreakableStatement* target() { return target_; }
599    HBasicBlock* break_block() { return break_block_; }
600    void set_break_block(HBasicBlock* block) { break_block_ = block; }
601    HBasicBlock* continue_block() { return continue_block_; }
602    void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
603
604   private:
605    BreakableStatement* target_;
606    HBasicBlock* break_block_;
607    HBasicBlock* continue_block_;
608  };
609
610  // A helper class to maintain a stack of current BreakAndContinueInfo
611  // structures mirroring BreakableStatement nesting.
612  class BreakAndContinueScope BASE_EMBEDDED {
613   public:
614    BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
615        : info_(info), owner_(owner), next_(owner->break_scope()) {
616      owner->set_break_scope(this);
617    }
618
619    ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
620
621    BreakAndContinueInfo* info() { return info_; }
622    HGraphBuilder* owner() { return owner_; }
623    BreakAndContinueScope* next() { return next_; }
624
625    // Search the break stack for a break or continue target.
626    HBasicBlock* Get(BreakableStatement* stmt, BreakType type);
627
628   private:
629    BreakAndContinueInfo* info_;
630    HGraphBuilder* owner_;
631    BreakAndContinueScope* next_;
632  };
633
634  HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle)
635      : function_state_(NULL),
636        initial_function_state_(this, info, oracle),
637        ast_context_(NULL),
638        break_scope_(NULL),
639        graph_(NULL),
640        current_block_(NULL),
641        inlined_count_(0),
642        zone_(info->isolate()->zone()) {
643    // This is not initialized in the initializer list because the
644    // constructor for the initial state relies on function_state_ == NULL
645    // to know it's the initial state.
646    function_state_= &initial_function_state_;
647  }
648
649  HGraph* CreateGraph();
650
651  // Simple accessors.
652  HGraph* graph() const { return graph_; }
653  BreakAndContinueScope* break_scope() const { return break_scope_; }
654  void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
655
656  HBasicBlock* current_block() const { return current_block_; }
657  void set_current_block(HBasicBlock* block) { current_block_ = block; }
658  HEnvironment* environment() const {
659    return current_block()->last_environment();
660  }
661
662  // Adding instructions.
663  HInstruction* AddInstruction(HInstruction* instr);
664  void AddSimulate(int id);
665
666  // Bailout environment manipulation.
667  void Push(HValue* value) { environment()->Push(value); }
668  HValue* Pop() { return environment()->Pop(); }
669
670 private:
671  // Type of a member function that generates inline code for a native function.
672  typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
673
674  // Forward declarations for inner scope classes.
675  class SubgraphScope;
676
677  static const InlineFunctionGenerator kInlineFunctionGenerators[];
678
679  static const int kMaxCallPolymorphism = 4;
680  static const int kMaxLoadPolymorphism = 4;
681  static const int kMaxStorePolymorphism = 4;
682
683  static const int kMaxInlinedNodes = 196;
684  static const int kMaxInlinedSize = 196;
685  static const int kMaxSourceSize = 600;
686
687  // Simple accessors.
688  FunctionState* function_state() const { return function_state_; }
689  void set_function_state(FunctionState* state) { function_state_ = state; }
690
691  AstContext* ast_context() const { return ast_context_; }
692  void set_ast_context(AstContext* context) { ast_context_ = context; }
693
694  // Accessors forwarded to the function state.
695  CompilationInfo* info() const {
696    return function_state()->compilation_info();
697  }
698  TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
699
700  AstContext* call_context() const {
701    return function_state()->call_context();
702  }
703  HBasicBlock* function_return() const {
704    return function_state()->function_return();
705  }
706  TestContext* inlined_test_context() const {
707    return function_state()->test_context();
708  }
709  void ClearInlinedTestContext() {
710    function_state()->ClearInlinedTestContext();
711  }
712  bool function_strict_mode() {
713    return function_state()->compilation_info()->is_strict_mode();
714  }
715
716  // Generators for inline runtime functions.
717#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize)      \
718  void Generate##Name(CallRuntime* call);
719
720  INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
721  INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
722#undef INLINE_FUNCTION_GENERATOR_DECLARATION
723
724  void Bailout(const char* reason);
725
726  void PreProcessOsrEntry(IterationStatement* statement);
727  // True iff. we are compiling for OSR and the statement is the entry.
728  bool HasOsrEntryAt(IterationStatement* statement);
729
730  HBasicBlock* CreateJoin(HBasicBlock* first,
731                          HBasicBlock* second,
732                          int join_id);
733
734  // Create a back edge in the flow graph.  body_exit is the predecessor
735  // block and loop_entry is the successor block.  loop_successor is the
736  // block where control flow exits the loop normally (e.g., via failure of
737  // the condition) and break_block is the block where control flow breaks
738  // from the loop.  All blocks except loop_entry can be NULL.  The return
739  // value is the new successor block which is the join of loop_successor
740  // and break_block, or NULL.
741  HBasicBlock* CreateLoop(IterationStatement* statement,
742                          HBasicBlock* loop_entry,
743                          HBasicBlock* body_exit,
744                          HBasicBlock* loop_successor,
745                          HBasicBlock* break_block);
746
747  HBasicBlock* JoinContinue(IterationStatement* statement,
748                            HBasicBlock* exit_block,
749                            HBasicBlock* continue_block);
750
751  HValue* Top() const { return environment()->Top(); }
752  void Drop(int n) { environment()->Drop(n); }
753  void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
754
755  void VisitForValue(Expression* expr);
756  void VisitForTypeOf(Expression* expr);
757  void VisitForEffect(Expression* expr);
758  void VisitForControl(Expression* expr,
759                       HBasicBlock* true_block,
760                       HBasicBlock* false_block);
761
762  // Visit an argument subexpression and emit a push to the outgoing
763  // arguments.
764  void VisitArgument(Expression* expr);
765  void VisitArgumentList(ZoneList<Expression*>* arguments);
766
767  // Visit a list of expressions from left to right, each in a value context.
768  void VisitExpressions(ZoneList<Expression*>* exprs);
769
770  void AddPhi(HPhi* phi);
771
772  void PushAndAdd(HInstruction* instr);
773
774  // Remove the arguments from the bailout environment and emit instructions
775  // to push them as outgoing parameters.
776  template <int V> HInstruction* PreProcessCall(HCall<V>* call);
777
778  void AssumeRepresentation(HValue* value, Representation r);
779  static Representation ToRepresentation(TypeInfo info);
780
781  void SetupScope(Scope* scope);
782  virtual void VisitStatements(ZoneList<Statement*>* statements);
783
784#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
785  AST_NODE_LIST(DECLARE_VISIT)
786#undef DECLARE_VISIT
787
788  HBasicBlock* CreateBasicBlock(HEnvironment* env);
789  HBasicBlock* CreateLoopHeaderBlock();
790
791  // Helpers for flow graph construction.
792  enum GlobalPropertyAccess {
793    kUseCell,
794    kUseGeneric
795  };
796  GlobalPropertyAccess LookupGlobalProperty(Variable* var,
797                                            LookupResult* lookup,
798                                            bool is_store);
799
800  bool TryArgumentsAccess(Property* expr);
801  bool TryCallApply(Call* expr);
802  bool TryInline(Call* expr);
803  bool TryInlineBuiltinFunction(Call* expr,
804                                HValue* receiver,
805                                Handle<Map> receiver_map,
806                                CheckType check_type);
807
808  // If --trace-inlining, print a line of the inlining trace.  Inlining
809  // succeeded if the reason string is NULL and failed if there is a
810  // non-NULL reason string.
811  void TraceInline(Handle<JSFunction> target, const char* failure_reason);
812
813  void HandleGlobalVariableAssignment(Variable* var,
814                                      HValue* value,
815                                      int position,
816                                      int ast_id);
817
818  void HandlePropertyAssignment(Assignment* expr);
819  void HandleCompoundAssignment(Assignment* expr);
820  void HandlePolymorphicStoreNamedField(Assignment* expr,
821                                        HValue* object,
822                                        HValue* value,
823                                        ZoneMapList* types,
824                                        Handle<String> name);
825  void HandlePolymorphicCallNamed(Call* expr,
826                                  HValue* receiver,
827                                  ZoneMapList* types,
828                                  Handle<String> name);
829
830  HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
831                                           HValue* index);
832  HInstruction* BuildBinaryOperation(BinaryOperation* expr,
833                                     HValue* left,
834                                     HValue* right);
835  HInstruction* BuildIncrement(HValue* value, bool increment);
836  HLoadNamedField* BuildLoadNamedField(HValue* object,
837                                       Property* expr,
838                                       Handle<Map> type,
839                                       LookupResult* result,
840                                       bool smi_and_map_check);
841  HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
842  HInstruction* BuildLoadKeyedFastElement(HValue* object,
843                                          HValue* key,
844                                          Property* expr);
845  HInstruction* BuildLoadKeyedSpecializedArrayElement(HValue* object,
846                                                      HValue* key,
847                                                      Property* expr);
848  HInstruction* BuildLoadKeyedGeneric(HValue* object,
849                                      HValue* key);
850
851  HInstruction* BuildLoadKeyed(HValue* obj,
852                               HValue* key,
853                               Property* prop);
854
855  HInstruction* BuildLoadNamed(HValue* object,
856                               Property* prop,
857                               Handle<Map> map,
858                               Handle<String> name);
859  HInstruction* BuildStoreNamed(HValue* object,
860                                HValue* value,
861                                Expression* expr);
862  HInstruction* BuildStoreNamedField(HValue* object,
863                                     Handle<String> name,
864                                     HValue* value,
865                                     Handle<Map> type,
866                                     LookupResult* lookup,
867                                     bool smi_and_map_check);
868  HInstruction* BuildStoreNamedGeneric(HValue* object,
869                                       Handle<String> name,
870                                       HValue* value);
871  HInstruction* BuildStoreKeyedGeneric(HValue* object,
872                                       HValue* key,
873                                       HValue* value);
874
875  HInstruction* BuildStoreKeyedFastElement(HValue* object,
876                                           HValue* key,
877                                           HValue* val,
878                                           Expression* expr);
879
880  HInstruction* BuildStoreKeyedSpecializedArrayElement(
881      HValue* object,
882      HValue* key,
883      HValue* val,
884      Expression* expr);
885
886  HInstruction* BuildStoreKeyed(HValue* object,
887                                HValue* key,
888                                HValue* value,
889                                Expression* assignment);
890
891  HValue* BuildContextChainWalk(Variable* var);
892
893  void AddCheckConstantFunction(Call* expr,
894                                HValue* receiver,
895                                Handle<Map> receiver_map,
896                                bool smi_and_map_check);
897
898  Zone* zone() { return zone_; }
899
900  // The translation state of the currently-being-translated function.
901  FunctionState* function_state_;
902
903  // The base of the function state stack.
904  FunctionState initial_function_state_;
905
906  // Expression context of the currently visited subexpression. NULL when
907  // visiting statements.
908  AstContext* ast_context_;
909
910  // A stack of breakable statements entered.
911  BreakAndContinueScope* break_scope_;
912
913  HGraph* graph_;
914  HBasicBlock* current_block_;
915
916  int inlined_count_;
917
918  Zone* zone_;
919
920  friend class FunctionState;  // Pushes and pops the state stack.
921  friend class AstContext;  // Pushes and pops the AST context stack.
922
923  DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
924};
925
926
927Zone* AstContext::zone() { return owner_->zone(); }
928
929
930class HValueMap: public ZoneObject {
931 public:
932  HValueMap()
933      : array_size_(0),
934        lists_size_(0),
935        count_(0),
936        present_flags_(0),
937        array_(NULL),
938        lists_(NULL),
939        free_list_head_(kNil) {
940    ResizeLists(kInitialSize);
941    Resize(kInitialSize);
942  }
943
944  void Kill(int flags);
945
946  void Add(HValue* value) {
947    present_flags_ |= value->flags();
948    Insert(value);
949  }
950
951  HValue* Lookup(HValue* value) const;
952
953  HValueMap* Copy(Zone* zone) const {
954    return new(zone) HValueMap(this);
955  }
956
957 private:
958  // A linked list of HValue* values.  Stored in arrays.
959  struct HValueMapListElement {
960    HValue* value;
961    int next;  // Index in the array of the next list element.
962  };
963  static const int kNil = -1;  // The end of a linked list
964
965  // Must be a power of 2.
966  static const int kInitialSize = 16;
967
968  explicit HValueMap(const HValueMap* other);
969
970  void Resize(int new_size);
971  void ResizeLists(int new_size);
972  void Insert(HValue* value);
973  uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
974
975  int array_size_;
976  int lists_size_;
977  int count_;  // The number of values stored in the HValueMap.
978  int present_flags_;  // All flags that are in any value in the HValueMap.
979  HValueMapListElement* array_;  // Primary store - contains the first value
980  // with a given hash.  Colliding elements are stored in linked lists.
981  HValueMapListElement* lists_;  // The linked lists containing hash collisions.
982  int free_list_head_;  // Unused elements in lists_ are on the free list.
983};
984
985
986class HStatistics: public Malloced {
987 public:
988  void Initialize(CompilationInfo* info);
989  void Print();
990  void SaveTiming(const char* name, int64_t ticks, unsigned size);
991  static HStatistics* Instance() {
992    static SetOncePointer<HStatistics> instance;
993    if (!instance.is_set()) {
994      instance.set(new HStatistics());
995    }
996    return instance.get();
997  }
998
999 private:
1000
1001  HStatistics()
1002      : timing_(5),
1003        names_(5),
1004        sizes_(5),
1005        total_(0),
1006        total_size_(0),
1007        full_code_gen_(0),
1008        source_size_(0) { }
1009
1010  List<int64_t> timing_;
1011  List<const char*> names_;
1012  List<unsigned> sizes_;
1013  int64_t total_;
1014  unsigned total_size_;
1015  int64_t full_code_gen_;
1016  double source_size_;
1017};
1018
1019
1020class HPhase BASE_EMBEDDED {
1021 public:
1022  static const char* const kFullCodeGen;
1023  static const char* const kTotal;
1024
1025  explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
1026  HPhase(const char* name, HGraph* graph) {
1027    Begin(name, graph, NULL, NULL);
1028  }
1029  HPhase(const char* name, LChunk* chunk) {
1030    Begin(name, NULL, chunk, NULL);
1031  }
1032  HPhase(const char* name, LAllocator* allocator) {
1033    Begin(name, NULL, NULL, allocator);
1034  }
1035
1036  ~HPhase() {
1037    End();
1038  }
1039
1040 private:
1041  void Begin(const char* name,
1042             HGraph* graph,
1043             LChunk* chunk,
1044             LAllocator* allocator);
1045  void End() const;
1046
1047  int64_t start_;
1048  const char* name_;
1049  HGraph* graph_;
1050  LChunk* chunk_;
1051  LAllocator* allocator_;
1052  unsigned start_allocation_size_;
1053};
1054
1055
1056class HTracer: public Malloced {
1057 public:
1058  void TraceCompilation(FunctionLiteral* function);
1059  void TraceHydrogen(const char* name, HGraph* graph);
1060  void TraceLithium(const char* name, LChunk* chunk);
1061  void TraceLiveRanges(const char* name, LAllocator* allocator);
1062
1063  static HTracer* Instance() {
1064    static SetOncePointer<HTracer> instance;
1065    if (!instance.is_set()) {
1066      instance.set(new HTracer("hydrogen.cfg"));
1067    }
1068    return instance.get();
1069  }
1070
1071 private:
1072  class Tag BASE_EMBEDDED {
1073   public:
1074    Tag(HTracer* tracer, const char* name) {
1075      name_ = name;
1076      tracer_ = tracer;
1077      tracer->PrintIndent();
1078      tracer->trace_.Add("begin_%s\n", name);
1079      tracer->indent_++;
1080    }
1081
1082    ~Tag() {
1083      tracer_->indent_--;
1084      tracer_->PrintIndent();
1085      tracer_->trace_.Add("end_%s\n", name_);
1086      ASSERT(tracer_->indent_ >= 0);
1087      tracer_->FlushToFile();
1088    }
1089
1090   private:
1091    HTracer* tracer_;
1092    const char* name_;
1093  };
1094
1095  explicit HTracer(const char* filename)
1096      : filename_(filename), trace_(&string_allocator_), indent_(0) {
1097    WriteChars(filename, "", 0, false);
1098  }
1099
1100  void TraceLiveRange(LiveRange* range, const char* type);
1101  void Trace(const char* name, HGraph* graph, LChunk* chunk);
1102  void FlushToFile();
1103
1104  void PrintEmptyProperty(const char* name) {
1105    PrintIndent();
1106    trace_.Add("%s\n", name);
1107  }
1108
1109  void PrintStringProperty(const char* name, const char* value) {
1110    PrintIndent();
1111    trace_.Add("%s \"%s\"\n", name, value);
1112  }
1113
1114  void PrintLongProperty(const char* name, int64_t value) {
1115    PrintIndent();
1116    trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1117  }
1118
1119  void PrintBlockProperty(const char* name, int block_id) {
1120    PrintIndent();
1121    trace_.Add("%s \"B%d\"\n", name, block_id);
1122  }
1123
1124  void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1125    PrintIndent();
1126    trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1127  }
1128
1129  void PrintIntProperty(const char* name, int value) {
1130    PrintIndent();
1131    trace_.Add("%s %d\n", name, value);
1132  }
1133
1134  void PrintIndent() {
1135    for (int i = 0; i < indent_; i++) {
1136      trace_.Add("  ");
1137    }
1138  }
1139
1140  const char* filename_;
1141  HeapStringAllocator string_allocator_;
1142  StringStream trace_;
1143  int indent_;
1144};
1145
1146
1147} }  // namespace v8::internal
1148
1149#endif  // V8_HYDROGEN_H_
1150