1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #ifndef V8_HYDROGEN_H_
29 #define V8_HYDROGEN_H_
30
31 #include "v8.h"
32
33 #include "allocation.h"
34 #include "ast.h"
35 #include "compiler.h"
36 #include "hydrogen-instructions.h"
37 #include "type-info.h"
38 #include "zone.h"
39
40 namespace v8 {
41 namespace internal {
42
43 // Forward declarations.
44 class BitVector;
45 class HEnvironment;
46 class HGraph;
47 class HLoopInformation;
48 class HTracer;
49 class LAllocator;
50 class LChunk;
51 class LiveRange;
52
53
54 class HBasicBlock: public ZoneObject {
55 public:
56 explicit HBasicBlock(HGraph* graph);
~HBasicBlock()57 virtual ~HBasicBlock() { }
58
59 // Simple accessors.
block_id()60 int block_id() const { return block_id_; }
set_block_id(int id)61 void set_block_id(int id) { block_id_ = id; }
graph()62 HGraph* graph() const { return graph_; }
phis()63 const ZoneList<HPhi*>* phis() const { return &phis_; }
first()64 HInstruction* first() const { return first_; }
last()65 HInstruction* last() const { return last_; }
set_last(HInstruction * instr)66 void set_last(HInstruction* instr) { last_ = instr; }
67 HInstruction* GetLastInstruction();
end()68 HControlInstruction* end() const { return end_; }
loop_information()69 HLoopInformation* loop_information() const { return loop_information_; }
predecessors()70 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
HasPredecessor()71 bool HasPredecessor() const { return predecessors_.length() > 0; }
dominated_blocks()72 const ZoneList<HBasicBlock*>* dominated_blocks() const {
73 return &dominated_blocks_;
74 }
deleted_phis()75 const ZoneList<int>* deleted_phis() const {
76 return &deleted_phis_;
77 }
RecordDeletedPhi(int merge_index)78 void RecordDeletedPhi(int merge_index) {
79 deleted_phis_.Add(merge_index);
80 }
dominator()81 HBasicBlock* dominator() const { return dominator_; }
last_environment()82 HEnvironment* last_environment() const { return last_environment_; }
argument_count()83 int argument_count() const { return argument_count_; }
set_argument_count(int count)84 void set_argument_count(int count) { argument_count_ = count; }
first_instruction_index()85 int first_instruction_index() const { return first_instruction_index_; }
set_first_instruction_index(int index)86 void set_first_instruction_index(int index) {
87 first_instruction_index_ = index;
88 }
last_instruction_index()89 int last_instruction_index() const { return last_instruction_index_; }
set_last_instruction_index(int index)90 void set_last_instruction_index(int index) {
91 last_instruction_index_ = index;
92 }
93
94 void AttachLoopInformation();
95 void DetachLoopInformation();
IsLoopHeader()96 bool IsLoopHeader() const { return loop_information() != NULL; }
IsStartBlock()97 bool IsStartBlock() const { return block_id() == 0; }
98 void PostProcessLoopHeader(IterationStatement* stmt);
99
IsFinished()100 bool IsFinished() const { return end_ != NULL; }
101 void AddPhi(HPhi* phi);
102 void RemovePhi(HPhi* phi);
103 void AddInstruction(HInstruction* instr);
104 bool Dominates(HBasicBlock* other) const;
105 int LoopNestingDepth() const;
106
107 void SetInitialEnvironment(HEnvironment* env);
ClearEnvironment()108 void ClearEnvironment() { last_environment_ = NULL; }
HasEnvironment()109 bool HasEnvironment() const { return last_environment_ != NULL; }
UpdateEnvironment(HEnvironment * env)110 void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
parent_loop_header()111 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
112
set_parent_loop_header(HBasicBlock * block)113 void set_parent_loop_header(HBasicBlock* block) {
114 ASSERT(parent_loop_header_ == NULL);
115 parent_loop_header_ = block;
116 }
117
HasParentLoopHeader()118 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
119
120 void SetJoinId(int ast_id);
121
122 void Finish(HControlInstruction* last);
123 void FinishExit(HControlInstruction* instruction);
124 void Goto(HBasicBlock* block, bool drop_extra = false);
125
126 int PredecessorIndexOf(HBasicBlock* predecessor) const;
AddSimulate(int ast_id)127 void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
128 void AssignCommonDominator(HBasicBlock* other);
129 void AssignLoopSuccessorDominators();
130
FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses)131 void FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses) {
132 FinishExit(CreateDeoptimize(has_uses));
133 }
134
135 // Add the inlined function exit sequence, adding an HLeaveInlined
136 // instruction and updating the bailout environment.
137 void AddLeaveInlined(HValue* return_value,
138 HBasicBlock* target,
139 bool drop_extra = false);
140
141 // If a target block is tagged as an inline function return, all
142 // predecessors should contain the inlined exit sequence:
143 //
144 // LeaveInlined
145 // Simulate (caller's environment)
146 // Goto (target block)
IsInlineReturnTarget()147 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
MarkAsInlineReturnTarget()148 void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
149
IsDeoptimizing()150 bool IsDeoptimizing() const { return is_deoptimizing_; }
MarkAsDeoptimizing()151 void MarkAsDeoptimizing() { is_deoptimizing_ = true; }
152
IsLoopSuccessorDominator()153 bool IsLoopSuccessorDominator() const {
154 return dominates_loop_successors_;
155 }
MarkAsLoopSuccessorDominator()156 void MarkAsLoopSuccessorDominator() {
157 dominates_loop_successors_ = true;
158 }
159
160 inline Zone* zone();
161
162 #ifdef DEBUG
163 void Verify();
164 #endif
165
166 private:
167 void RegisterPredecessor(HBasicBlock* pred);
168 void AddDominatedBlock(HBasicBlock* block);
169
170 HSimulate* CreateSimulate(int ast_id);
171 HDeoptimize* CreateDeoptimize(HDeoptimize::UseEnvironment has_uses);
172
173 int block_id_;
174 HGraph* graph_;
175 ZoneList<HPhi*> phis_;
176 HInstruction* first_;
177 HInstruction* last_;
178 HControlInstruction* end_;
179 HLoopInformation* loop_information_;
180 ZoneList<HBasicBlock*> predecessors_;
181 HBasicBlock* dominator_;
182 ZoneList<HBasicBlock*> dominated_blocks_;
183 HEnvironment* last_environment_;
184 // Outgoing parameter count at block exit, set during lithium translation.
185 int argument_count_;
186 // Instruction indices into the lithium code stream.
187 int first_instruction_index_;
188 int last_instruction_index_;
189 ZoneList<int> deleted_phis_;
190 HBasicBlock* parent_loop_header_;
191 bool is_inline_return_target_;
192 bool is_deoptimizing_;
193 bool dominates_loop_successors_;
194 };
195
196
197 class HPredecessorIterator BASE_EMBEDDED {
198 public:
HPredecessorIterator(HBasicBlock * block)199 explicit HPredecessorIterator(HBasicBlock* block)
200 : predecessor_list_(block->predecessors()), current_(0) { }
201
Done()202 bool Done() { return current_ >= predecessor_list_->length(); }
Current()203 HBasicBlock* Current() { return predecessor_list_->at(current_); }
Advance()204 void Advance() { current_++; }
205
206 private:
207 const ZoneList<HBasicBlock*>* predecessor_list_;
208 int current_;
209 };
210
211
212 class HLoopInformation: public ZoneObject {
213 public:
HLoopInformation(HBasicBlock * loop_header)214 explicit HLoopInformation(HBasicBlock* loop_header)
215 : back_edges_(4),
216 loop_header_(loop_header),
217 blocks_(8),
218 stack_check_(NULL) {
219 blocks_.Add(loop_header);
220 }
~HLoopInformation()221 virtual ~HLoopInformation() {}
222
back_edges()223 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
blocks()224 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
loop_header()225 HBasicBlock* loop_header() const { return loop_header_; }
226 HBasicBlock* GetLastBackEdge() const;
227 void RegisterBackEdge(HBasicBlock* block);
228
stack_check()229 HStackCheck* stack_check() const { return stack_check_; }
set_stack_check(HStackCheck * stack_check)230 void set_stack_check(HStackCheck* stack_check) {
231 stack_check_ = stack_check;
232 }
233
234 private:
235 void AddBlock(HBasicBlock* block);
236
237 ZoneList<HBasicBlock*> back_edges_;
238 HBasicBlock* loop_header_;
239 ZoneList<HBasicBlock*> blocks_;
240 HStackCheck* stack_check_;
241 };
242
243
244 class HGraph: public ZoneObject {
245 public:
246 explicit HGraph(CompilationInfo* info);
247
isolate()248 Isolate* isolate() { return isolate_; }
zone()249 Zone* zone() { return isolate_->zone(); }
250
blocks()251 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
phi_list()252 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
entry_block()253 HBasicBlock* entry_block() const { return entry_block_; }
start_environment()254 HEnvironment* start_environment() const { return start_environment_; }
255
256 void InitializeInferredTypes();
257 void InsertTypeConversions();
258 void InsertRepresentationChanges();
259 void MarkDeoptimizeOnUndefined();
260 void ComputeMinusZeroChecks();
261 bool ProcessArgumentsObject();
262 void EliminateRedundantPhis();
263 void EliminateUnreachablePhis();
264 void Canonicalize();
265 void OrderBlocks();
266 void AssignDominators();
267 void ReplaceCheckedValues();
268 void PropagateDeoptimizingMark();
269
270 // Returns false if there are phi-uses of the arguments-object
271 // which are not supported by the optimizing compiler.
272 bool CheckArgumentsPhiUses();
273
274 // Returns false if there are phi-uses of an uninitialized const
275 // which are not supported by the optimizing compiler.
276 bool CheckConstPhiUses();
277
278 void CollectPhis();
279
280 Handle<Code> Compile(CompilationInfo* info);
281
set_undefined_constant(HConstant * constant)282 void set_undefined_constant(HConstant* constant) {
283 undefined_constant_.set(constant);
284 }
GetConstantUndefined()285 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
286 HConstant* GetConstant1();
287 HConstant* GetConstantMinus1();
288 HConstant* GetConstantTrue();
289 HConstant* GetConstantFalse();
290 HConstant* GetConstantHole();
291
292 HBasicBlock* CreateBasicBlock();
GetArgumentsObject()293 HArgumentsObject* GetArgumentsObject() const {
294 return arguments_object_.get();
295 }
296
SetArgumentsObject(HArgumentsObject * object)297 void SetArgumentsObject(HArgumentsObject* object) {
298 arguments_object_.set(object);
299 }
300
GetMaximumValueID()301 int GetMaximumValueID() const { return values_.length(); }
GetNextBlockID()302 int GetNextBlockID() { return next_block_id_++; }
GetNextValueID(HValue * value)303 int GetNextValueID(HValue* value) {
304 values_.Add(value);
305 return values_.length() - 1;
306 }
LookupValue(int id)307 HValue* LookupValue(int id) const {
308 if (id >= 0 && id < values_.length()) return values_[id];
309 return NULL;
310 }
311
312 #ifdef DEBUG
313 void Verify(bool do_full_verify) const;
314 #endif
315
has_osr_loop_entry()316 bool has_osr_loop_entry() {
317 return osr_loop_entry_.is_set();
318 }
319
osr_loop_entry()320 HBasicBlock* osr_loop_entry() {
321 return osr_loop_entry_.get();
322 }
323
set_osr_loop_entry(HBasicBlock * entry)324 void set_osr_loop_entry(HBasicBlock* entry) {
325 osr_loop_entry_.set(entry);
326 }
327
osr_values()328 ZoneList<HUnknownOSRValue*>* osr_values() {
329 return osr_values_.get();
330 }
331
set_osr_values(ZoneList<HUnknownOSRValue * > * values)332 void set_osr_values(ZoneList<HUnknownOSRValue*>* values) {
333 osr_values_.set(values);
334 }
335
336 private:
337 void Postorder(HBasicBlock* block,
338 BitVector* visited,
339 ZoneList<HBasicBlock*>* order,
340 HBasicBlock* loop_header);
341 void PostorderLoopBlocks(HLoopInformation* loop,
342 BitVector* visited,
343 ZoneList<HBasicBlock*>* order,
344 HBasicBlock* loop_header);
345 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
346 Object* value);
347
348 void MarkAsDeoptimizingRecursively(HBasicBlock* block);
349 void InsertTypeConversions(HInstruction* instr);
350 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
351 void RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi);
352 void InsertRepresentationChangeForUse(HValue* value,
353 HValue* use_value,
354 int use_index,
355 Representation to);
356 void InsertRepresentationChangesForValue(HValue* value);
357 void InferTypes(ZoneList<HValue*>* worklist);
358 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
359 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
360
361 Isolate* isolate_;
362 int next_block_id_;
363 HBasicBlock* entry_block_;
364 HEnvironment* start_environment_;
365 ZoneList<HBasicBlock*> blocks_;
366 ZoneList<HValue*> values_;
367 ZoneList<HPhi*>* phi_list_;
368 SetOncePointer<HConstant> undefined_constant_;
369 SetOncePointer<HConstant> constant_1_;
370 SetOncePointer<HConstant> constant_minus1_;
371 SetOncePointer<HConstant> constant_true_;
372 SetOncePointer<HConstant> constant_false_;
373 SetOncePointer<HConstant> constant_hole_;
374 SetOncePointer<HArgumentsObject> arguments_object_;
375
376 SetOncePointer<HBasicBlock> osr_loop_entry_;
377 SetOncePointer<ZoneList<HUnknownOSRValue*> > osr_values_;
378
379 DISALLOW_COPY_AND_ASSIGN(HGraph);
380 };
381
382
zone()383 Zone* HBasicBlock::zone() { return graph_->zone(); }
384
385
386 // Type of stack frame an environment might refer to.
387 enum FrameType { JS_FUNCTION, JS_CONSTRUCT, ARGUMENTS_ADAPTOR };
388
389
390 class HEnvironment: public ZoneObject {
391 public:
392 HEnvironment(HEnvironment* outer,
393 Scope* scope,
394 Handle<JSFunction> closure);
395
DiscardInlined(bool drop_extra)396 HEnvironment* DiscardInlined(bool drop_extra) {
397 HEnvironment* outer = outer_;
398 while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
399 if (drop_extra) outer->Drop(1);
400 return outer;
401 }
402
arguments_environment()403 HEnvironment* arguments_environment() {
404 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
405 }
406
407 // Simple accessors.
closure()408 Handle<JSFunction> closure() const { return closure_; }
values()409 const ZoneList<HValue*>* values() const { return &values_; }
assigned_variables()410 const ZoneList<int>* assigned_variables() const {
411 return &assigned_variables_;
412 }
frame_type()413 FrameType frame_type() const { return frame_type_; }
parameter_count()414 int parameter_count() const { return parameter_count_; }
specials_count()415 int specials_count() const { return specials_count_; }
local_count()416 int local_count() const { return local_count_; }
outer()417 HEnvironment* outer() const { return outer_; }
pop_count()418 int pop_count() const { return pop_count_; }
push_count()419 int push_count() const { return push_count_; }
420
ast_id()421 int ast_id() const { return ast_id_; }
set_ast_id(int id)422 void set_ast_id(int id) { ast_id_ = id; }
423
length()424 int length() const { return values_.length(); }
is_special_index(int i)425 bool is_special_index(int i) const {
426 return i >= parameter_count() && i < parameter_count() + specials_count();
427 }
428
first_expression_index()429 int first_expression_index() const {
430 return parameter_count() + specials_count() + local_count();
431 }
432
Bind(Variable * variable,HValue * value)433 void Bind(Variable* variable, HValue* value) {
434 Bind(IndexFor(variable), value);
435 }
436
437 void Bind(int index, HValue* value);
438
BindContext(HValue * value)439 void BindContext(HValue* value) {
440 Bind(parameter_count(), value);
441 }
442
Lookup(Variable * variable)443 HValue* Lookup(Variable* variable) const {
444 return Lookup(IndexFor(variable));
445 }
446
Lookup(int index)447 HValue* Lookup(int index) const {
448 HValue* result = values_[index];
449 ASSERT(result != NULL);
450 return result;
451 }
452
LookupContext()453 HValue* LookupContext() const {
454 // Return first special.
455 return Lookup(parameter_count());
456 }
457
Push(HValue * value)458 void Push(HValue* value) {
459 ASSERT(value != NULL);
460 ++push_count_;
461 values_.Add(value);
462 }
463
Pop()464 HValue* Pop() {
465 ASSERT(!ExpressionStackIsEmpty());
466 if (push_count_ > 0) {
467 --push_count_;
468 } else {
469 ++pop_count_;
470 }
471 return values_.RemoveLast();
472 }
473
474 void Drop(int count);
475
Top()476 HValue* Top() const { return ExpressionStackAt(0); }
477
478 bool ExpressionStackIsEmpty() const;
479
ExpressionStackAt(int index_from_top)480 HValue* ExpressionStackAt(int index_from_top) const {
481 int index = length() - index_from_top - 1;
482 ASSERT(HasExpressionAt(index));
483 return values_[index];
484 }
485
486 void SetExpressionStackAt(int index_from_top, HValue* value);
487
488 HEnvironment* Copy() const;
489 HEnvironment* CopyWithoutHistory() const;
490 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
491
492 // Create an "inlined version" of this environment, where the original
493 // environment is the outer environment but the top expression stack
494 // elements are moved to an inner environment as parameters.
495 HEnvironment* CopyForInlining(Handle<JSFunction> target,
496 int arguments,
497 FunctionLiteral* function,
498 HConstant* undefined,
499 CallKind call_kind,
500 bool is_construct) const;
501
502 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
503
ClearHistory()504 void ClearHistory() {
505 pop_count_ = 0;
506 push_count_ = 0;
507 assigned_variables_.Rewind(0);
508 }
509
SetValueAt(int index,HValue * value)510 void SetValueAt(int index, HValue* value) {
511 ASSERT(index < length());
512 values_[index] = value;
513 }
514
515 void PrintTo(StringStream* stream);
516 void PrintToStd();
517
518 private:
519 explicit HEnvironment(const HEnvironment* other);
520
521 HEnvironment(HEnvironment* outer,
522 Handle<JSFunction> closure,
523 FrameType frame_type,
524 int arguments);
525
526 // Create an artificial stub environment (e.g. for argument adaptor or
527 // constructor stub).
528 HEnvironment* CreateStubEnvironment(HEnvironment* outer,
529 Handle<JSFunction> target,
530 FrameType frame_type,
531 int arguments) const;
532
533 // True if index is included in the expression stack part of the environment.
534 bool HasExpressionAt(int index) const;
535
536 void Initialize(int parameter_count, int local_count, int stack_height);
537 void Initialize(const HEnvironment* other);
538
539 // Map a variable to an environment index. Parameter indices are shifted
540 // by 1 (receiver is parameter index -1 but environment index 0).
541 // Stack-allocated local indices are shifted by the number of parameters.
IndexFor(Variable * variable)542 int IndexFor(Variable* variable) const {
543 ASSERT(variable->IsStackAllocated());
544 int shift = variable->IsParameter()
545 ? 1
546 : parameter_count_ + specials_count_;
547 return variable->index() + shift;
548 }
549
550 Handle<JSFunction> closure_;
551 // Value array [parameters] [specials] [locals] [temporaries].
552 ZoneList<HValue*> values_;
553 ZoneList<int> assigned_variables_;
554 FrameType frame_type_;
555 int parameter_count_;
556 int specials_count_;
557 int local_count_;
558 HEnvironment* outer_;
559 int pop_count_;
560 int push_count_;
561 int ast_id_;
562 };
563
564
565 class HGraphBuilder;
566
567 enum ArgumentsAllowedFlag {
568 ARGUMENTS_NOT_ALLOWED,
569 ARGUMENTS_ALLOWED
570 };
571
572 // This class is not BASE_EMBEDDED because our inlining implementation uses
573 // new and delete.
574 class AstContext {
575 public:
IsEffect()576 bool IsEffect() const { return kind_ == Expression::kEffect; }
IsValue()577 bool IsValue() const { return kind_ == Expression::kValue; }
IsTest()578 bool IsTest() const { return kind_ == Expression::kTest; }
579
580 // 'Fill' this context with a hydrogen value. The value is assumed to
581 // have already been inserted in the instruction stream (or not need to
582 // be, e.g., HPhi). Call this function in tail position in the Visit
583 // functions for expressions.
584 virtual void ReturnValue(HValue* value) = 0;
585
586 // Add a hydrogen instruction to the instruction stream (recording an
587 // environment simulation if necessary) and then fill this context with
588 // the instruction as value.
589 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
590
591 // Finishes the current basic block and materialize a boolean for
592 // value context, nothing for effect, generate a branch for test context.
593 // Call this function in tail position in the Visit functions for
594 // expressions.
595 virtual void ReturnControl(HControlInstruction* instr, int ast_id) = 0;
596
set_for_typeof(bool for_typeof)597 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
is_for_typeof()598 bool is_for_typeof() { return for_typeof_; }
599
600 protected:
601 AstContext(HGraphBuilder* owner, Expression::Context kind);
602 virtual ~AstContext();
603
owner()604 HGraphBuilder* owner() const { return owner_; }
605
606 inline Zone* zone();
607
608 // We want to be able to assert, in a context-specific way, that the stack
609 // height makes sense when the context is filled.
610 #ifdef DEBUG
611 int original_length_;
612 #endif
613
614 private:
615 HGraphBuilder* owner_;
616 Expression::Context kind_;
617 AstContext* outer_;
618 bool for_typeof_;
619 };
620
621
622 class EffectContext: public AstContext {
623 public:
EffectContext(HGraphBuilder * owner)624 explicit EffectContext(HGraphBuilder* owner)
625 : AstContext(owner, Expression::kEffect) {
626 }
627 virtual ~EffectContext();
628
629 virtual void ReturnValue(HValue* value);
630 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
631 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
632 };
633
634
635 class ValueContext: public AstContext {
636 public:
ValueContext(HGraphBuilder * owner,ArgumentsAllowedFlag flag)637 explicit ValueContext(HGraphBuilder* owner, ArgumentsAllowedFlag flag)
638 : AstContext(owner, Expression::kValue), flag_(flag) {
639 }
640 virtual ~ValueContext();
641
642 virtual void ReturnValue(HValue* value);
643 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
644 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
645
arguments_allowed()646 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
647
648 private:
649 ArgumentsAllowedFlag flag_;
650 };
651
652
653 class TestContext: public AstContext {
654 public:
TestContext(HGraphBuilder * owner,Expression * condition,HBasicBlock * if_true,HBasicBlock * if_false)655 TestContext(HGraphBuilder* owner,
656 Expression* condition,
657 HBasicBlock* if_true,
658 HBasicBlock* if_false)
659 : AstContext(owner, Expression::kTest),
660 condition_(condition),
661 if_true_(if_true),
662 if_false_(if_false) {
663 }
664
665 virtual void ReturnValue(HValue* value);
666 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
667 virtual void ReturnControl(HControlInstruction* instr, int ast_id);
668
cast(AstContext * context)669 static TestContext* cast(AstContext* context) {
670 ASSERT(context->IsTest());
671 return reinterpret_cast<TestContext*>(context);
672 }
673
condition()674 Expression* condition() const { return condition_; }
if_true()675 HBasicBlock* if_true() const { return if_true_; }
if_false()676 HBasicBlock* if_false() const { return if_false_; }
677
678 private:
679 // Build the shared core part of the translation unpacking a value into
680 // control flow.
681 void BuildBranch(HValue* value);
682
683 Expression* condition_;
684 HBasicBlock* if_true_;
685 HBasicBlock* if_false_;
686 };
687
688
689 enum ReturnHandlingFlag {
690 NORMAL_RETURN,
691 DROP_EXTRA_ON_RETURN,
692 CONSTRUCT_CALL_RETURN
693 };
694
695
696 class FunctionState {
697 public:
698 FunctionState(HGraphBuilder* owner,
699 CompilationInfo* info,
700 TypeFeedbackOracle* oracle,
701 ReturnHandlingFlag return_handling);
702 ~FunctionState();
703
compilation_info()704 CompilationInfo* compilation_info() { return compilation_info_; }
oracle()705 TypeFeedbackOracle* oracle() { return oracle_; }
call_context()706 AstContext* call_context() { return call_context_; }
drop_extra()707 bool drop_extra() { return return_handling_ == DROP_EXTRA_ON_RETURN; }
is_construct()708 bool is_construct() { return return_handling_ == CONSTRUCT_CALL_RETURN; }
function_return()709 HBasicBlock* function_return() { return function_return_; }
test_context()710 TestContext* test_context() { return test_context_; }
ClearInlinedTestContext()711 void ClearInlinedTestContext() {
712 delete test_context_;
713 test_context_ = NULL;
714 }
715
outer()716 FunctionState* outer() { return outer_; }
717
718 private:
719 HGraphBuilder* owner_;
720
721 CompilationInfo* compilation_info_;
722 TypeFeedbackOracle* oracle_;
723
724 // During function inlining, expression context of the call being
725 // inlined. NULL when not inlining.
726 AstContext* call_context_;
727
728 // Indicate whether we have to perform special handling on return from
729 // inlined functions.
730 // - DROP_EXTRA_ON_RETURN: Drop an extra value from the environment.
731 // - CONSTRUCT_CALL_RETURN: Either use allocated receiver or return value.
732 ReturnHandlingFlag return_handling_;
733
734 // When inlining in an effect or value context, this is the return block.
735 // It is NULL otherwise. When inlining in a test context, there are a
736 // pair of return blocks in the context. When not inlining, there is no
737 // local return point.
738 HBasicBlock* function_return_;
739
740 // When inlining a call in a test context, a context containing a pair of
741 // return blocks. NULL in all other cases.
742 TestContext* test_context_;
743
744 FunctionState* outer_;
745 };
746
747
748 class HGraphBuilder: public AstVisitor {
749 public:
750 enum BreakType { BREAK, CONTINUE };
751 enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH };
752
753 // A class encapsulating (lazily-allocated) break and continue blocks for
754 // a breakable statement. Separated from BreakAndContinueScope so that it
755 // can have a separate lifetime.
756 class BreakAndContinueInfo BASE_EMBEDDED {
757 public:
758 explicit BreakAndContinueInfo(BreakableStatement* target,
759 int drop_extra = 0)
target_(target)760 : target_(target),
761 break_block_(NULL),
762 continue_block_(NULL),
763 drop_extra_(drop_extra) {
764 }
765
target()766 BreakableStatement* target() { return target_; }
break_block()767 HBasicBlock* break_block() { return break_block_; }
set_break_block(HBasicBlock * block)768 void set_break_block(HBasicBlock* block) { break_block_ = block; }
continue_block()769 HBasicBlock* continue_block() { return continue_block_; }
set_continue_block(HBasicBlock * block)770 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
drop_extra()771 int drop_extra() { return drop_extra_; }
772
773 private:
774 BreakableStatement* target_;
775 HBasicBlock* break_block_;
776 HBasicBlock* continue_block_;
777 int drop_extra_;
778 };
779
780 // A helper class to maintain a stack of current BreakAndContinueInfo
781 // structures mirroring BreakableStatement nesting.
782 class BreakAndContinueScope BASE_EMBEDDED {
783 public:
BreakAndContinueScope(BreakAndContinueInfo * info,HGraphBuilder * owner)784 BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
785 : info_(info), owner_(owner), next_(owner->break_scope()) {
786 owner->set_break_scope(this);
787 }
788
~BreakAndContinueScope()789 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
790
info()791 BreakAndContinueInfo* info() { return info_; }
owner()792 HGraphBuilder* owner() { return owner_; }
next()793 BreakAndContinueScope* next() { return next_; }
794
795 // Search the break stack for a break or continue target.
796 HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra);
797
798 private:
799 BreakAndContinueInfo* info_;
800 HGraphBuilder* owner_;
801 BreakAndContinueScope* next_;
802 };
803
804 HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle);
805
806 HGraph* CreateGraph();
807
808 // Simple accessors.
graph()809 HGraph* graph() const { return graph_; }
break_scope()810 BreakAndContinueScope* break_scope() const { return break_scope_; }
set_break_scope(BreakAndContinueScope * head)811 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
812
current_block()813 HBasicBlock* current_block() const { return current_block_; }
set_current_block(HBasicBlock * block)814 void set_current_block(HBasicBlock* block) { current_block_ = block; }
environment()815 HEnvironment* environment() const {
816 return current_block()->last_environment();
817 }
818
inline_bailout()819 bool inline_bailout() { return inline_bailout_; }
820
821 // Adding instructions.
822 HInstruction* AddInstruction(HInstruction* instr);
823 void AddSimulate(int ast_id);
824
825 // Bailout environment manipulation.
Push(HValue * value)826 void Push(HValue* value) { environment()->Push(value); }
Pop()827 HValue* Pop() { return environment()->Pop(); }
828
829 void Bailout(const char* reason);
830
831 HBasicBlock* CreateJoin(HBasicBlock* first,
832 HBasicBlock* second,
833 int join_id);
834
oracle()835 TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
836
function_state()837 FunctionState* function_state() const { return function_state_; }
838
839 void VisitDeclarations(ZoneList<Declaration*>* declarations);
840
841 private:
842 // Type of a member function that generates inline code for a native function.
843 typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
844
845 // Forward declarations for inner scope classes.
846 class SubgraphScope;
847
848 static const InlineFunctionGenerator kInlineFunctionGenerators[];
849
850 static const int kMaxCallPolymorphism = 4;
851 static const int kMaxLoadPolymorphism = 4;
852 static const int kMaxStorePolymorphism = 4;
853
854 static const int kMaxInlinedNodes = 196;
855 static const int kMaxInlinedSize = 196;
856 static const int kMaxSourceSize = 600;
857
858 // Even in the 'unlimited' case we have to have some limit in order not to
859 // overflow the stack.
860 static const int kUnlimitedMaxInlinedNodes = 1000;
861 static const int kUnlimitedMaxInlinedSize = 1000;
862 static const int kUnlimitedMaxSourceSize = 600;
863
864 // Simple accessors.
set_function_state(FunctionState * state)865 void set_function_state(FunctionState* state) { function_state_ = state; }
866
ast_context()867 AstContext* ast_context() const { return ast_context_; }
set_ast_context(AstContext * context)868 void set_ast_context(AstContext* context) { ast_context_ = context; }
869
870 // Accessors forwarded to the function state.
info()871 CompilationInfo* info() const {
872 return function_state()->compilation_info();
873 }
call_context()874 AstContext* call_context() const {
875 return function_state()->call_context();
876 }
function_return()877 HBasicBlock* function_return() const {
878 return function_state()->function_return();
879 }
inlined_test_context()880 TestContext* inlined_test_context() const {
881 return function_state()->test_context();
882 }
ClearInlinedTestContext()883 void ClearInlinedTestContext() {
884 function_state()->ClearInlinedTestContext();
885 }
function_strict_mode_flag()886 StrictModeFlag function_strict_mode_flag() {
887 return function_state()->compilation_info()->is_classic_mode()
888 ? kNonStrictMode : kStrictMode;
889 }
890
891 // Generators for inline runtime functions.
892 #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
893 void Generate##Name(CallRuntime* call);
894
895 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
896 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
897 #undef INLINE_FUNCTION_GENERATOR_DECLARATION
898
899 void HandleDeclaration(VariableProxy* proxy,
900 VariableMode mode,
901 FunctionLiteral* function,
902 int* global_count);
903
904 void VisitDelete(UnaryOperation* expr);
905 void VisitVoid(UnaryOperation* expr);
906 void VisitTypeof(UnaryOperation* expr);
907 void VisitAdd(UnaryOperation* expr);
908 void VisitSub(UnaryOperation* expr);
909 void VisitBitNot(UnaryOperation* expr);
910 void VisitNot(UnaryOperation* expr);
911
912 void VisitComma(BinaryOperation* expr);
913 void VisitLogicalExpression(BinaryOperation* expr);
914 void VisitArithmeticExpression(BinaryOperation* expr);
915
916 bool PreProcessOsrEntry(IterationStatement* statement);
917 // True iff. we are compiling for OSR and the statement is the entry.
918 bool HasOsrEntryAt(IterationStatement* statement);
919 void VisitLoopBody(IterationStatement* stmt,
920 HBasicBlock* loop_entry,
921 BreakAndContinueInfo* break_info);
922
923 // Create a back edge in the flow graph. body_exit is the predecessor
924 // block and loop_entry is the successor block. loop_successor is the
925 // block where control flow exits the loop normally (e.g., via failure of
926 // the condition) and break_block is the block where control flow breaks
927 // from the loop. All blocks except loop_entry can be NULL. The return
928 // value is the new successor block which is the join of loop_successor
929 // and break_block, or NULL.
930 HBasicBlock* CreateLoop(IterationStatement* statement,
931 HBasicBlock* loop_entry,
932 HBasicBlock* body_exit,
933 HBasicBlock* loop_successor,
934 HBasicBlock* break_block);
935
936 HBasicBlock* JoinContinue(IterationStatement* statement,
937 HBasicBlock* exit_block,
938 HBasicBlock* continue_block);
939
Top()940 HValue* Top() const { return environment()->Top(); }
Drop(int n)941 void Drop(int n) { environment()->Drop(n); }
Bind(Variable * var,HValue * value)942 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
943
944 // The value of the arguments object is allowed in some but not most value
945 // contexts. (It's allowed in all effect contexts and disallowed in all
946 // test contexts.)
947 void VisitForValue(Expression* expr,
948 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
949 void VisitForTypeOf(Expression* expr);
950 void VisitForEffect(Expression* expr);
951 void VisitForControl(Expression* expr,
952 HBasicBlock* true_block,
953 HBasicBlock* false_block);
954
955 // Visit an argument subexpression and emit a push to the outgoing
956 // arguments. Returns the hydrogen value that was pushed.
957 HValue* VisitArgument(Expression* expr);
958
959 void VisitArgumentList(ZoneList<Expression*>* arguments);
960
961 // Visit a list of expressions from left to right, each in a value context.
962 void VisitExpressions(ZoneList<Expression*>* exprs);
963
964 void AddPhi(HPhi* phi);
965
966 void PushAndAdd(HInstruction* instr);
967
968 // Remove the arguments from the bailout environment and emit instructions
969 // to push them as outgoing parameters.
970 template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
971
972 void TraceRepresentation(Token::Value op,
973 TypeInfo info,
974 HValue* value,
975 Representation rep);
976 static Representation ToRepresentation(TypeInfo info);
977
978 void SetUpScope(Scope* scope);
979 virtual void VisitStatements(ZoneList<Statement*>* statements);
980
981 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
982 AST_NODE_LIST(DECLARE_VISIT)
983 #undef DECLARE_VISIT
984
985 HBasicBlock* CreateBasicBlock(HEnvironment* env);
986 HBasicBlock* CreateLoopHeaderBlock();
987
988 // Helpers for flow graph construction.
989 enum GlobalPropertyAccess {
990 kUseCell,
991 kUseGeneric
992 };
993 GlobalPropertyAccess LookupGlobalProperty(Variable* var,
994 LookupResult* lookup,
995 bool is_store);
996
997 bool TryArgumentsAccess(Property* expr);
998
999 // Try to optimize fun.apply(receiver, arguments) pattern.
1000 bool TryCallApply(Call* expr);
1001
1002 bool TryInline(CallKind call_kind,
1003 Handle<JSFunction> target,
1004 ZoneList<Expression*>* arguments,
1005 HValue* receiver,
1006 int ast_id,
1007 int return_id,
1008 ReturnHandlingFlag return_handling);
1009
1010 bool TryInlineCall(Call* expr, bool drop_extra = false);
1011 bool TryInlineConstruct(CallNew* expr, HValue* receiver);
1012 bool TryInlineBuiltinMethodCall(Call* expr,
1013 HValue* receiver,
1014 Handle<Map> receiver_map,
1015 CheckType check_type);
1016 bool TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra);
1017
1018 // If --trace-inlining, print a line of the inlining trace. Inlining
1019 // succeeded if the reason string is NULL and failed if there is a
1020 // non-NULL reason string.
1021 void TraceInline(Handle<JSFunction> target,
1022 Handle<JSFunction> caller,
1023 const char* failure_reason);
1024
1025 void HandleGlobalVariableAssignment(Variable* var,
1026 HValue* value,
1027 int position,
1028 int ast_id);
1029
1030 void HandlePropertyAssignment(Assignment* expr);
1031 void HandleCompoundAssignment(Assignment* expr);
1032 void HandlePolymorphicStoreNamedField(Assignment* expr,
1033 HValue* object,
1034 HValue* value,
1035 SmallMapList* types,
1036 Handle<String> name);
1037 void HandlePolymorphicCallNamed(Call* expr,
1038 HValue* receiver,
1039 SmallMapList* types,
1040 Handle<String> name);
1041 void HandleLiteralCompareTypeof(CompareOperation* expr,
1042 HTypeof* typeof_expr,
1043 Handle<String> check);
1044 void HandleLiteralCompareNil(CompareOperation* expr,
1045 HValue* value,
1046 NilValue nil);
1047
1048 HStringCharCodeAt* BuildStringCharCodeAt(HValue* context,
1049 HValue* string,
1050 HValue* index);
1051 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
1052 HValue* left,
1053 HValue* right);
1054 HInstruction* BuildIncrement(bool returns_original_input,
1055 CountOperation* expr);
1056 HLoadNamedField* BuildLoadNamedField(HValue* object,
1057 Property* expr,
1058 Handle<Map> type,
1059 LookupResult* result,
1060 bool smi_and_map_check);
1061 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
1062 HInstruction* BuildLoadKeyedGeneric(HValue* object,
1063 HValue* key);
1064 HInstruction* BuildExternalArrayElementAccess(
1065 HValue* external_elements,
1066 HValue* checked_key,
1067 HValue* val,
1068 ElementsKind elements_kind,
1069 bool is_store);
1070 HInstruction* BuildFastElementAccess(HValue* elements,
1071 HValue* checked_key,
1072 HValue* val,
1073 ElementsKind elements_kind,
1074 bool is_store);
1075
1076 HInstruction* BuildMonomorphicElementAccess(HValue* object,
1077 HValue* key,
1078 HValue* val,
1079 Handle<Map> map,
1080 bool is_store);
1081 HValue* HandlePolymorphicElementAccess(HValue* object,
1082 HValue* key,
1083 HValue* val,
1084 Expression* prop,
1085 int ast_id,
1086 int position,
1087 bool is_store,
1088 bool* has_side_effects);
1089
1090 HValue* HandleKeyedElementAccess(HValue* obj,
1091 HValue* key,
1092 HValue* val,
1093 Expression* expr,
1094 int ast_id,
1095 int position,
1096 bool is_store,
1097 bool* has_side_effects);
1098
1099 HInstruction* BuildLoadNamed(HValue* object,
1100 Property* prop,
1101 Handle<Map> map,
1102 Handle<String> name);
1103 HInstruction* BuildStoreNamed(HValue* object,
1104 HValue* value,
1105 Expression* expr);
1106 HInstruction* BuildStoreNamed(HValue* object,
1107 HValue* value,
1108 ObjectLiteral::Property* prop);
1109 HInstruction* BuildStoreNamedField(HValue* object,
1110 Handle<String> name,
1111 HValue* value,
1112 Handle<Map> type,
1113 LookupResult* lookup,
1114 bool smi_and_map_check);
1115 HInstruction* BuildStoreNamedGeneric(HValue* object,
1116 Handle<String> name,
1117 HValue* value);
1118 HInstruction* BuildStoreKeyedGeneric(HValue* object,
1119 HValue* key,
1120 HValue* value);
1121
1122 HValue* BuildContextChainWalk(Variable* var);
1123
1124 void AddCheckConstantFunction(Call* expr,
1125 HValue* receiver,
1126 Handle<Map> receiver_map,
1127 bool smi_and_map_check);
1128
zone()1129 Zone* zone() { return zone_; }
1130
1131 // The translation state of the currently-being-translated function.
1132 FunctionState* function_state_;
1133
1134 // The base of the function state stack.
1135 FunctionState initial_function_state_;
1136
1137 // Expression context of the currently visited subexpression. NULL when
1138 // visiting statements.
1139 AstContext* ast_context_;
1140
1141 // A stack of breakable statements entered.
1142 BreakAndContinueScope* break_scope_;
1143
1144 HGraph* graph_;
1145 HBasicBlock* current_block_;
1146
1147 int inlined_count_;
1148
1149 Zone* zone_;
1150
1151 bool inline_bailout_;
1152
1153 friend class FunctionState; // Pushes and pops the state stack.
1154 friend class AstContext; // Pushes and pops the AST context stack.
1155
1156 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
1157 };
1158
1159
zone()1160 Zone* AstContext::zone() { return owner_->zone(); }
1161
1162
1163 class HValueMap: public ZoneObject {
1164 public:
HValueMap()1165 HValueMap()
1166 : array_size_(0),
1167 lists_size_(0),
1168 count_(0),
1169 present_flags_(0),
1170 array_(NULL),
1171 lists_(NULL),
1172 free_list_head_(kNil) {
1173 ResizeLists(kInitialSize);
1174 Resize(kInitialSize);
1175 }
1176
1177 void Kill(GVNFlagSet flags);
1178
Add(HValue * value)1179 void Add(HValue* value) {
1180 present_flags_.Add(value->gvn_flags());
1181 Insert(value);
1182 }
1183
1184 HValue* Lookup(HValue* value) const;
1185
Copy(Zone * zone)1186 HValueMap* Copy(Zone* zone) const {
1187 return new(zone) HValueMap(zone, this);
1188 }
1189
IsEmpty()1190 bool IsEmpty() const { return count_ == 0; }
1191
1192 private:
1193 // A linked list of HValue* values. Stored in arrays.
1194 struct HValueMapListElement {
1195 HValue* value;
1196 int next; // Index in the array of the next list element.
1197 };
1198 static const int kNil = -1; // The end of a linked list
1199
1200 // Must be a power of 2.
1201 static const int kInitialSize = 16;
1202
1203 HValueMap(Zone* zone, const HValueMap* other);
1204
1205 void Resize(int new_size);
1206 void ResizeLists(int new_size);
1207 void Insert(HValue* value);
Bound(uint32_t value)1208 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
1209
1210 int array_size_;
1211 int lists_size_;
1212 int count_; // The number of values stored in the HValueMap.
1213 GVNFlagSet present_flags_; // All flags that are in any value in the
1214 // HValueMap.
1215 HValueMapListElement* array_; // Primary store - contains the first value
1216 // with a given hash. Colliding elements are stored in linked lists.
1217 HValueMapListElement* lists_; // The linked lists containing hash collisions.
1218 int free_list_head_; // Unused elements in lists_ are on the free list.
1219 };
1220
1221
1222 class HStatistics: public Malloced {
1223 public:
1224 void Initialize(CompilationInfo* info);
1225 void Print();
1226 void SaveTiming(const char* name, int64_t ticks, unsigned size);
Instance()1227 static HStatistics* Instance() {
1228 static SetOncePointer<HStatistics> instance;
1229 if (!instance.is_set()) {
1230 instance.set(new HStatistics());
1231 }
1232 return instance.get();
1233 }
1234
1235 private:
HStatistics()1236 HStatistics()
1237 : timing_(5),
1238 names_(5),
1239 sizes_(5),
1240 total_(0),
1241 total_size_(0),
1242 full_code_gen_(0),
1243 source_size_(0) { }
1244
1245 List<int64_t> timing_;
1246 List<const char*> names_;
1247 List<unsigned> sizes_;
1248 int64_t total_;
1249 unsigned total_size_;
1250 int64_t full_code_gen_;
1251 double source_size_;
1252 };
1253
1254
1255 class HPhase BASE_EMBEDDED {
1256 public:
1257 static const char* const kFullCodeGen;
1258 static const char* const kTotal;
1259
HPhase(const char * name)1260 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
HPhase(const char * name,HGraph * graph)1261 HPhase(const char* name, HGraph* graph) {
1262 Begin(name, graph, NULL, NULL);
1263 }
HPhase(const char * name,LChunk * chunk)1264 HPhase(const char* name, LChunk* chunk) {
1265 Begin(name, NULL, chunk, NULL);
1266 }
HPhase(const char * name,LAllocator * allocator)1267 HPhase(const char* name, LAllocator* allocator) {
1268 Begin(name, NULL, NULL, allocator);
1269 }
1270
~HPhase()1271 ~HPhase() {
1272 End();
1273 }
1274
1275 private:
1276 void Begin(const char* name,
1277 HGraph* graph,
1278 LChunk* chunk,
1279 LAllocator* allocator);
1280 void End() const;
1281
1282 int64_t start_;
1283 const char* name_;
1284 HGraph* graph_;
1285 LChunk* chunk_;
1286 LAllocator* allocator_;
1287 unsigned start_allocation_size_;
1288 };
1289
1290
1291 class HTracer: public Malloced {
1292 public:
1293 void TraceCompilation(FunctionLiteral* function);
1294 void TraceHydrogen(const char* name, HGraph* graph);
1295 void TraceLithium(const char* name, LChunk* chunk);
1296 void TraceLiveRanges(const char* name, LAllocator* allocator);
1297
Instance()1298 static HTracer* Instance() {
1299 static SetOncePointer<HTracer> instance;
1300 if (!instance.is_set()) {
1301 instance.set(new HTracer("hydrogen.cfg"));
1302 }
1303 return instance.get();
1304 }
1305
1306 private:
1307 class Tag BASE_EMBEDDED {
1308 public:
Tag(HTracer * tracer,const char * name)1309 Tag(HTracer* tracer, const char* name) {
1310 name_ = name;
1311 tracer_ = tracer;
1312 tracer->PrintIndent();
1313 tracer->trace_.Add("begin_%s\n", name);
1314 tracer->indent_++;
1315 }
1316
~Tag()1317 ~Tag() {
1318 tracer_->indent_--;
1319 tracer_->PrintIndent();
1320 tracer_->trace_.Add("end_%s\n", name_);
1321 ASSERT(tracer_->indent_ >= 0);
1322 tracer_->FlushToFile();
1323 }
1324
1325 private:
1326 HTracer* tracer_;
1327 const char* name_;
1328 };
1329
HTracer(const char * filename)1330 explicit HTracer(const char* filename)
1331 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1332 WriteChars(filename, "", 0, false);
1333 }
1334
1335 void TraceLiveRange(LiveRange* range, const char* type);
1336 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1337 void FlushToFile();
1338
PrintEmptyProperty(const char * name)1339 void PrintEmptyProperty(const char* name) {
1340 PrintIndent();
1341 trace_.Add("%s\n", name);
1342 }
1343
PrintStringProperty(const char * name,const char * value)1344 void PrintStringProperty(const char* name, const char* value) {
1345 PrintIndent();
1346 trace_.Add("%s \"%s\"\n", name, value);
1347 }
1348
PrintLongProperty(const char * name,int64_t value)1349 void PrintLongProperty(const char* name, int64_t value) {
1350 PrintIndent();
1351 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1352 }
1353
PrintBlockProperty(const char * name,int block_id)1354 void PrintBlockProperty(const char* name, int block_id) {
1355 PrintIndent();
1356 trace_.Add("%s \"B%d\"\n", name, block_id);
1357 }
1358
PrintIntProperty(const char * name,int value)1359 void PrintIntProperty(const char* name, int value) {
1360 PrintIndent();
1361 trace_.Add("%s %d\n", name, value);
1362 }
1363
PrintIndent()1364 void PrintIndent() {
1365 for (int i = 0; i < indent_; i++) {
1366 trace_.Add(" ");
1367 }
1368 }
1369
1370 const char* filename_;
1371 HeapStringAllocator string_allocator_;
1372 StringStream trace_;
1373 int indent_;
1374 };
1375
1376
1377 } } // namespace v8::internal
1378
1379 #endif // V8_HYDROGEN_H_
1380