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