blob: 872ae98ead2a5c8723b6b2576c6e35d98ab4b6d5 [file] [log] [blame]
Ben Murdochb0fe1622011-05-05 13:52:32 +01001// Copyright 2010 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_HYDROGEN_H_
29#define V8_HYDROGEN_H_
30
31#include "v8.h"
32
33#include "ast.h"
34#include "compiler.h"
35#include "data-flow.h"
36#include "hydrogen-instructions.h"
37#include "zone.h"
38
39namespace v8 {
40namespace internal {
41
42// Forward declarations.
43class HEnvironment;
44class HGraph;
45class HLoopInformation;
46class HTracer;
47class LAllocator;
48class LChunk;
49class LiveRange;
50
51
52class HBasicBlock: public ZoneObject {
53 public:
54 explicit HBasicBlock(HGraph* graph);
55 virtual ~HBasicBlock() { }
56
57 // Simple accessors.
58 int block_id() const { return block_id_; }
59 void set_block_id(int id) { block_id_ = id; }
60 HGraph* graph() const { return graph_; }
61 const ZoneList<HPhi*>* phis() const { return &phis_; }
62 HInstruction* first() const { return first_; }
63 HInstruction* GetLastInstruction();
64 HControlInstruction* end() const { return end_; }
65 HLoopInformation* loop_information() const { return loop_information_; }
66 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
67 bool HasPredecessor() const { return predecessors_.length() > 0; }
68 const ZoneList<HBasicBlock*>* dominated_blocks() const {
69 return &dominated_blocks_;
70 }
71 const ZoneList<int>* deleted_phis() const {
72 return &deleted_phis_;
73 }
74 void RecordDeletedPhi(int merge_index) {
75 deleted_phis_.Add(merge_index);
76 }
77 HBasicBlock* dominator() const { return dominator_; }
78 HEnvironment* last_environment() const { return last_environment_; }
79 int argument_count() const { return argument_count_; }
80 void set_argument_count(int count) { argument_count_ = count; }
81 int first_instruction_index() const { return first_instruction_index_; }
82 void set_first_instruction_index(int index) {
83 first_instruction_index_ = index;
84 }
85 int last_instruction_index() const { return last_instruction_index_; }
86 void set_last_instruction_index(int index) {
87 last_instruction_index_ = index;
88 }
89
90 void AttachLoopInformation();
91 void DetachLoopInformation();
92 bool IsLoopHeader() const { return loop_information() != NULL; }
93 bool IsStartBlock() const { return block_id() == 0; }
94 void PostProcessLoopHeader(IterationStatement* stmt);
95
96 bool IsFinished() const { return end_ != NULL; }
97 void AddPhi(HPhi* phi);
98 void RemovePhi(HPhi* phi);
99 void AddInstruction(HInstruction* instr);
100 bool Dominates(HBasicBlock* other) const;
101
102 void SetInitialEnvironment(HEnvironment* env);
103 void ClearEnvironment() { last_environment_ = NULL; }
104 bool HasEnvironment() const { return last_environment_ != NULL; }
105 void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
106 HBasicBlock* parent_loop_header() const {
107 if (!HasParentLoopHeader()) return NULL;
108 return parent_loop_header_.get();
109 }
110
111 void set_parent_loop_header(HBasicBlock* block) {
112 parent_loop_header_.set(block);
113 }
114
115 bool HasParentLoopHeader() const { return parent_loop_header_.is_set(); }
116
117 void SetJoinId(int id);
118
119 void Finish(HControlInstruction* last);
120 void Goto(HBasicBlock* block, bool include_stack_check = false);
121
122 int PredecessorIndexOf(HBasicBlock* predecessor) const;
123 void AddSimulate(int id) { AddInstruction(CreateSimulate(id)); }
124 void AssignCommonDominator(HBasicBlock* other);
125
126 // Add the inlined function exit sequence, adding an HLeaveInlined
127 // instruction and updating the bailout environment.
128 void AddLeaveInlined(HValue* return_value, HBasicBlock* target);
129
130 // If a target block is tagged as an inline function return, all
131 // predecessors should contain the inlined exit sequence:
132 //
133 // LeaveInlined
134 // Simulate (caller's environment)
135 // Goto (target block)
136 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
137 void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
138
139 Handle<Object> cond() { return cond_; }
140 void set_cond(Handle<Object> value) { cond_ = value; }
141
142#ifdef DEBUG
143 void Verify();
144#endif
145
146 private:
147 void RegisterPredecessor(HBasicBlock* pred);
148 void AddDominatedBlock(HBasicBlock* block);
149
150 HSimulate* CreateSimulate(int id);
151
152 int block_id_;
153 HGraph* graph_;
154 ZoneList<HPhi*> phis_;
155 HInstruction* first_;
156 HInstruction* last_; // Last non-control instruction of the block.
157 HControlInstruction* end_;
158 HLoopInformation* loop_information_;
159 ZoneList<HBasicBlock*> predecessors_;
160 HBasicBlock* dominator_;
161 ZoneList<HBasicBlock*> dominated_blocks_;
162 HEnvironment* last_environment_;
163 // Outgoing parameter count at block exit, set during lithium translation.
164 int argument_count_;
165 // Instruction indices into the lithium code stream.
166 int first_instruction_index_;
167 int last_instruction_index_;
168 ZoneList<int> deleted_phis_;
169 SetOncePointer<HBasicBlock> parent_loop_header_;
170 bool is_inline_return_target_;
171 Handle<Object> cond_;
172};
173
174
175class HLoopInformation: public ZoneObject {
176 public:
177 explicit HLoopInformation(HBasicBlock* loop_header)
178 : back_edges_(4), loop_header_(loop_header), blocks_(8) {
179 blocks_.Add(loop_header);
180 }
181 virtual ~HLoopInformation() {}
182
183 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
184 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
185 HBasicBlock* loop_header() const { return loop_header_; }
186 HBasicBlock* GetLastBackEdge() const;
187 void RegisterBackEdge(HBasicBlock* block);
188
189 private:
190 void AddBlock(HBasicBlock* block);
191
192 ZoneList<HBasicBlock*> back_edges_;
193 HBasicBlock* loop_header_;
194 ZoneList<HBasicBlock*> blocks_;
195};
196
197
198class HSubgraph: public ZoneObject {
199 public:
200 explicit HSubgraph(HGraph* graph)
201 : graph_(graph),
202 entry_block_(NULL),
203 exit_block_(NULL),
204 break_continue_info_(4) {
205 }
206
207 HGraph* graph() const { return graph_; }
208 HEnvironment* environment() const {
209 ASSERT(HasExit());
210 return exit_block_->last_environment();
211 }
212
213 bool HasExit() const { return exit_block_ != NULL; }
214
215 void PreProcessOsrEntry(IterationStatement* statement);
216
217 void AppendOptional(HSubgraph* graph,
218 bool on_true_branch,
219 HValue* boolean_value);
220 void AppendJoin(HSubgraph* then_graph, HSubgraph* else_graph, AstNode* node);
221 void AppendWhile(HSubgraph* condition,
222 HSubgraph* body,
223 IterationStatement* statement,
224 HSubgraph* continue_subgraph,
225 HSubgraph* exit);
226 void AppendDoWhile(HSubgraph* body,
227 IterationStatement* statement,
228 HSubgraph* go_back,
229 HSubgraph* exit);
230 void AppendEndless(HSubgraph* body, IterationStatement* statement);
231 void Append(HSubgraph* next, BreakableStatement* statement);
232 void ResolveContinue(IterationStatement* statement);
233 HBasicBlock* BundleBreak(BreakableStatement* statement);
234 HBasicBlock* BundleContinue(IterationStatement* statement);
235 HBasicBlock* BundleBreakContinue(BreakableStatement* statement,
236 bool is_continue,
237 int join_id);
238 HBasicBlock* JoinBlocks(HBasicBlock* a, HBasicBlock* b, int id);
239
240 void FinishExit(HControlInstruction* instruction);
241 void FinishBreakContinue(BreakableStatement* target, bool is_continue);
242 void Initialize(HBasicBlock* block) {
243 ASSERT(entry_block_ == NULL);
244 entry_block_ = block;
245 exit_block_ = block;
246 }
247 HBasicBlock* entry_block() const { return entry_block_; }
248 HBasicBlock* exit_block() const { return exit_block_; }
249 void set_exit_block(HBasicBlock* block) {
250 exit_block_ = block;
251 }
252
253 void ConnectExitTo(HBasicBlock* other, bool include_stack_check = false) {
254 if (HasExit()) {
255 exit_block()->Goto(other, include_stack_check);
256 }
257 }
258
259 void AddBreakContinueInfo(HSubgraph* other) {
260 break_continue_info_.AddAll(other->break_continue_info_);
261 }
262
263 protected:
264 class BreakContinueInfo: public ZoneObject {
265 public:
266 BreakContinueInfo(BreakableStatement* target, HBasicBlock* block,
267 bool is_continue)
268 : target_(target), block_(block), continue_(is_continue) {}
269 BreakableStatement* target() const { return target_; }
270 HBasicBlock* block() const { return block_; }
271 bool is_continue() const { return continue_; }
272 bool IsResolved() const { return block_ == NULL; }
273 void Resolve() { block_ = NULL; }
274
275 private:
276 BreakableStatement* target_;
277 HBasicBlock* block_;
278 bool continue_;
279 };
280
281 const ZoneList<BreakContinueInfo*>* break_continue_info() const {
282 return &break_continue_info_;
283 }
284
285 HGraph* graph_; // The graph this is a subgraph of.
286 HBasicBlock* entry_block_;
287 HBasicBlock* exit_block_;
288
289 private:
290 ZoneList<BreakContinueInfo*> break_continue_info_;
291};
292
293
294class HGraph: public HSubgraph {
295 public:
296 explicit HGraph(CompilationInfo* info);
297
298 CompilationInfo* info() const { return info_; }
299 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
300 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
301 Handle<String> debug_name() const { return info_->function()->debug_name(); }
302 HEnvironment* start_environment() const { return start_environment_; }
303
304 void InitializeInferredTypes();
305 void InsertTypeConversions();
306 void InsertRepresentationChanges();
307 bool ProcessArgumentsObject();
308 void EliminateRedundantPhis();
309 void Canonicalize();
310 void OrderBlocks();
311 void AssignDominators();
312
313 // Returns false if there are phi-uses of the arguments-object
314 // which are not supported by the optimizing compiler.
315 bool CollectPhis();
316
317 Handle<Code> Compile();
318
319 void set_undefined_constant(HConstant* constant) {
320 undefined_constant_.set(constant);
321 }
322 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
323 HConstant* GetConstant1();
324 HConstant* GetConstantMinus1();
325 HConstant* GetConstantTrue();
326 HConstant* GetConstantFalse();
327
328 HBasicBlock* CreateBasicBlock();
329 HArgumentsObject* GetArgumentsObject() const {
330 return arguments_object_.get();
331 }
332 bool HasArgumentsObject() const { return arguments_object_.is_set(); }
333
334 void SetArgumentsObject(HArgumentsObject* object) {
335 arguments_object_.set(object);
336 }
337
338 // True iff. we are compiling for OSR and the statement is the entry.
339 bool HasOsrEntryAt(IterationStatement* statement);
340
341 int GetMaximumValueID() const { return values_.length(); }
342 int GetNextBlockID() { return next_block_id_++; }
343 int GetNextValueID(HValue* value) {
344 values_.Add(value);
345 return values_.length() - 1;
346 }
347 HValue* LookupValue(int id) const {
348 if (id >= 0 && id < values_.length()) return values_[id];
349 return NULL;
350 }
351
352#ifdef DEBUG
353 void Verify() const;
354#endif
355
356 private:
357 void Postorder(HBasicBlock* block,
358 BitVector* visited,
359 ZoneList<HBasicBlock*>* order,
360 HBasicBlock* loop_header);
361 void PostorderLoopBlocks(HLoopInformation* loop,
362 BitVector* visited,
363 ZoneList<HBasicBlock*>* order,
364 HBasicBlock* loop_header);
365 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
366 Object* value);
367
368 void InsertTypeConversions(HInstruction* instr);
369 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
370 void InsertRepresentationChangeForUse(HValue* value,
371 HValue* use,
372 Representation to,
373 bool truncating);
374 void InsertRepresentationChanges(HValue* current);
375 void InferTypes(ZoneList<HValue*>* worklist);
376 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
377 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
378
379 int next_block_id_;
380 CompilationInfo* info_;
381 HEnvironment* start_environment_;
382 ZoneList<HBasicBlock*> blocks_;
383 ZoneList<HValue*> values_;
384 ZoneList<HPhi*>* phi_list_;
385 SetOncePointer<HConstant> undefined_constant_;
386 SetOncePointer<HConstant> constant_1_;
387 SetOncePointer<HConstant> constant_minus1_;
388 SetOncePointer<HConstant> constant_true_;
389 SetOncePointer<HConstant> constant_false_;
390 SetOncePointer<HArgumentsObject> arguments_object_;
391
392 friend class HSubgraph;
393
394 DISALLOW_COPY_AND_ASSIGN(HGraph);
395};
396
397
398class HEnvironment: public ZoneObject {
399 public:
400 HEnvironment(HEnvironment* outer,
401 Scope* scope,
402 Handle<JSFunction> closure);
403
Steve Block9fac8402011-05-12 15:51:54 +0100404 // Simple accessors.
405 Handle<JSFunction> closure() const { return closure_; }
406 const ZoneList<HValue*>* values() const { return &values_; }
407 const ZoneList<int>* assigned_variables() const {
408 return &assigned_variables_;
409 }
410 int parameter_count() const { return parameter_count_; }
411 int local_count() const { return local_count_; }
412 HEnvironment* outer() const { return outer_; }
413 int pop_count() const { return pop_count_; }
414 int push_count() const { return push_count_; }
415
416 int ast_id() const { return ast_id_; }
417 void set_ast_id(int id) { ast_id_ = id; }
418
419 int length() const { return values_.length(); }
420
Ben Murdochb0fe1622011-05-05 13:52:32 +0100421 void Bind(Variable* variable, HValue* value) {
422 Bind(IndexFor(variable), value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100423 }
424
Steve Block9fac8402011-05-12 15:51:54 +0100425 void Bind(int index, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100426
427 HValue* Lookup(Variable* variable) const {
428 return Lookup(IndexFor(variable));
429 }
Steve Block9fac8402011-05-12 15:51:54 +0100430
Ben Murdochb0fe1622011-05-05 13:52:32 +0100431 HValue* Lookup(int index) const {
432 HValue* result = values_[index];
433 ASSERT(result != NULL);
434 return result;
435 }
436
437 void Push(HValue* value) {
438 ASSERT(value != NULL);
439 ++push_count_;
440 values_.Add(value);
441 }
442
Ben Murdochb0fe1622011-05-05 13:52:32 +0100443 HValue* Pop() {
Steve Block9fac8402011-05-12 15:51:54 +0100444 ASSERT(!ExpressionStackIsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100445 if (push_count_ > 0) {
446 --push_count_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100447 } else {
448 ++pop_count_;
449 }
450 return values_.RemoveLast();
451 }
452
Steve Block9fac8402011-05-12 15:51:54 +0100453 void Drop(int count);
454
455 HValue* Top() const { return ExpressionStackAt(0); }
456
457 HValue* ExpressionStackAt(int index_from_top) const {
458 int index = length() - index_from_top - 1;
459 ASSERT(HasExpressionAt(index));
460 return values_[index];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100461 }
462
Steve Block9fac8402011-05-12 15:51:54 +0100463 void SetExpressionStackAt(int index_from_top, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100464
Ben Murdochb0fe1622011-05-05 13:52:32 +0100465 HEnvironment* Copy() const;
466 HEnvironment* CopyWithoutHistory() const;
467 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
468
469 // Create an "inlined version" of this environment, where the original
470 // environment is the outer environment but the top expression stack
471 // elements are moved to an inner environment as parameters. If
472 // is_speculative, the argument values are expected to be PushArgument
473 // instructions, otherwise they are the actual values.
474 HEnvironment* CopyForInlining(Handle<JSFunction> target,
475 FunctionLiteral* function,
476 bool is_speculative,
477 HConstant* undefined) const;
478
479 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100480
Ben Murdochb0fe1622011-05-05 13:52:32 +0100481 void ClearHistory() {
482 pop_count_ = 0;
483 push_count_ = 0;
484 assigned_variables_.Clear();
485 }
Steve Block9fac8402011-05-12 15:51:54 +0100486
Ben Murdochb0fe1622011-05-05 13:52:32 +0100487 void SetValueAt(int index, HValue* value) {
Steve Block9fac8402011-05-12 15:51:54 +0100488 ASSERT(index < length());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100489 values_[index] = value;
490 }
491
492 void PrintTo(StringStream* stream);
493 void PrintToStd();
494
495 private:
496 explicit HEnvironment(const HEnvironment* other);
497
Steve Block9fac8402011-05-12 15:51:54 +0100498 // True if index is included in the expression stack part of the environment.
499 bool HasExpressionAt(int index) const;
500
501 bool ExpressionStackIsEmpty() const;
502
Ben Murdochb0fe1622011-05-05 13:52:32 +0100503 void Initialize(int parameter_count, int local_count, int stack_height);
504 void Initialize(const HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100505
506 // Map a variable to an environment index. Parameter indices are shifted
507 // by 1 (receiver is parameter index -1 but environment index 0).
508 // Stack-allocated local indices are shifted by the number of parameters.
509 int IndexFor(Variable* variable) const {
510 Slot* slot = variable->AsSlot();
511 ASSERT(slot != NULL && slot->IsStackAllocated());
512 int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
513 return slot->index() + shift;
514 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100515
516 Handle<JSFunction> closure_;
517 // Value array [parameters] [locals] [temporaries].
518 ZoneList<HValue*> values_;
519 ZoneList<int> assigned_variables_;
520 int parameter_count_;
521 int local_count_;
522 HEnvironment* outer_;
523 int pop_count_;
524 int push_count_;
525 int ast_id_;
526};
527
528
529class HGraphBuilder;
530
531class AstContext {
532 public:
533 bool IsEffect() const { return kind_ == Expression::kEffect; }
534 bool IsValue() const { return kind_ == Expression::kValue; }
535 bool IsTest() const { return kind_ == Expression::kTest; }
536
537 // 'Fill' this context with a hydrogen value. The value is assumed to
538 // have already been inserted in the instruction stream (or not need to
539 // be, e.g., HPhi). Call this function in tail position in the Visit
540 // functions for expressions.
541 virtual void ReturnValue(HValue* value) = 0;
542
543 // Add a hydrogen instruction to the instruction stream (recording an
544 // environment simulation if necessary) and then fill this context with
545 // the instruction as value.
546 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
547
548 protected:
549 AstContext(HGraphBuilder* owner, Expression::Context kind);
550 virtual ~AstContext();
551
552 HGraphBuilder* owner() const { return owner_; }
553
554 // We want to be able to assert, in a context-specific way, that the stack
555 // height makes sense when the context is filled.
556#ifdef DEBUG
Steve Block9fac8402011-05-12 15:51:54 +0100557 int original_length_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100558#endif
559
560 private:
561 HGraphBuilder* owner_;
562 Expression::Context kind_;
563 AstContext* outer_;
564};
565
566
567class EffectContext: public AstContext {
568 public:
569 explicit EffectContext(HGraphBuilder* owner)
570 : AstContext(owner, Expression::kEffect) {
571 }
572 virtual ~EffectContext();
573
574 virtual void ReturnValue(HValue* value);
575 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
576};
577
578
579class ValueContext: public AstContext {
580 public:
581 explicit ValueContext(HGraphBuilder* owner)
582 : AstContext(owner, Expression::kValue) {
583 }
584 virtual ~ValueContext();
585
586 virtual void ReturnValue(HValue* value);
587 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
588};
589
590
591class TestContext: public AstContext {
592 public:
593 TestContext(HGraphBuilder* owner,
594 HBasicBlock* if_true,
595 HBasicBlock* if_false)
596 : AstContext(owner, Expression::kTest),
597 if_true_(if_true),
598 if_false_(if_false) {
599 }
600
601 virtual void ReturnValue(HValue* value);
602 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
603
604 static TestContext* cast(AstContext* context) {
605 ASSERT(context->IsTest());
606 return reinterpret_cast<TestContext*>(context);
607 }
608
609 HBasicBlock* if_true() const { return if_true_; }
610 HBasicBlock* if_false() const { return if_false_; }
611
612 private:
613 // Build the shared core part of the translation unpacking a value into
614 // control flow.
615 void BuildBranch(HValue* value);
616
617 HBasicBlock* if_true_;
618 HBasicBlock* if_false_;
619};
620
621
622class HGraphBuilder: public AstVisitor {
623 public:
624 explicit HGraphBuilder(TypeFeedbackOracle* oracle)
625 : oracle_(oracle),
626 graph_(NULL),
627 current_subgraph_(NULL),
628 peeled_statement_(NULL),
629 ast_context_(NULL),
630 call_context_(NULL),
631 function_return_(NULL),
632 inlined_count_(0) { }
633
634 HGraph* CreateGraph(CompilationInfo* info);
635
636 // Simple accessors.
637 HGraph* graph() const { return graph_; }
638 HSubgraph* subgraph() const { return current_subgraph_; }
639
640 HEnvironment* environment() const { return subgraph()->environment(); }
641 HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
642
643 // Adding instructions.
644 HInstruction* AddInstruction(HInstruction* instr);
645 void AddSimulate(int id);
646
647 // Bailout environment manipulation.
648 void Push(HValue* value) { environment()->Push(value); }
649 HValue* Pop() { return environment()->Pop(); }
650
651 private:
652 // Type of a member function that generates inline code for a native function.
653 typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count,
654 int ast_id);
655
656 // Forward declarations for inner scope classes.
657 class SubgraphScope;
658
659 static const InlineFunctionGenerator kInlineFunctionGenerators[];
660
661 static const int kMaxCallPolymorphism = 4;
662 static const int kMaxLoadPolymorphism = 4;
663 static const int kMaxStorePolymorphism = 4;
664
665 static const int kMaxInlinedNodes = 196;
666 static const int kMaxInlinedSize = 196;
667 static const int kMaxSourceSize = 600;
668
669 // Simple accessors.
670 TypeFeedbackOracle* oracle() const { return oracle_; }
671 AstContext* ast_context() const { return ast_context_; }
672 void set_ast_context(AstContext* context) { ast_context_ = context; }
673 AstContext* call_context() const { return call_context_; }
674 HBasicBlock* function_return() const { return function_return_; }
675
676 // Generators for inline runtime functions.
677#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
678 void Generate##Name(int argument_count, int ast_id);
679
680 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
681 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
682#undef INLINE_FUNCTION_GENERATOR_DECLARATION
683
684 void Bailout(const char* reason);
685
686 void AppendPeeledWhile(IterationStatement* stmt,
687 HSubgraph* cond_graph,
688 HSubgraph* body_graph,
689 HSubgraph* exit_graph);
690
691 void AddToSubgraph(HSubgraph* graph, ZoneList<Statement*>* stmts);
692 void AddToSubgraph(HSubgraph* graph, Statement* stmt);
693 void AddToSubgraph(HSubgraph* graph, Expression* expr);
694
695 HValue* Top() const { return environment()->Top(); }
696 void Drop(int n) { environment()->Drop(n); }
697 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
698
699 void VisitForValue(Expression* expr);
700 void VisitForEffect(Expression* expr);
701 void VisitForControl(Expression* expr,
702 HBasicBlock* true_block,
703 HBasicBlock* false_block);
704
705 // Visit an argument and wrap it in a PushArgument instruction.
706 HValue* VisitArgument(Expression* expr);
707 void VisitArgumentList(ZoneList<Expression*>* arguments);
708
709 void AddPhi(HPhi* phi);
710
711 void PushAndAdd(HInstruction* instr);
712
713 void PushArgumentsForStubCall(int argument_count);
714
715 // Remove the arguments from the bailout environment and emit instructions
716 // to push them as outgoing parameters.
717 void ProcessCall(HCall* call);
718
719 void AssumeRepresentation(HValue* value, Representation r);
720 static Representation ToRepresentation(TypeInfo info);
721
722 void SetupScope(Scope* scope);
723 virtual void VisitStatements(ZoneList<Statement*>* statements);
724
725#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
726 AST_NODE_LIST(DECLARE_VISIT)
727#undef DECLARE_VISIT
728
729 bool ShouldPeel(HSubgraph* cond, HSubgraph* body);
730
731 HBasicBlock* CreateBasicBlock(HEnvironment* env);
732 HSubgraph* CreateEmptySubgraph();
733 HSubgraph* CreateGotoSubgraph(HEnvironment* env);
734 HSubgraph* CreateBranchSubgraph(HEnvironment* env);
735 HSubgraph* CreateLoopHeaderSubgraph(HEnvironment* env);
736 HSubgraph* CreateInlinedSubgraph(HEnvironment* outer,
737 Handle<JSFunction> target,
738 FunctionLiteral* function);
739
740 // Helpers for flow graph construction.
741 void LookupGlobalPropertyCell(Variable* var,
742 LookupResult* lookup,
743 bool is_store);
744
745 bool TryArgumentsAccess(Property* expr);
746 bool TryCallApply(Call* expr);
747 bool TryInline(Call* expr);
748 bool TryMathFunctionInline(Call* expr);
749 void TraceInline(Handle<JSFunction> target, bool result);
750
751 void HandleGlobalVariableAssignment(Variable* var,
752 HValue* value,
753 int position,
754 int ast_id);
755
756 void HandlePropertyAssignment(Assignment* expr);
757 void HandleCompoundAssignment(Assignment* expr);
758 void HandlePolymorphicLoadNamedField(Property* expr,
759 HValue* object,
760 ZoneMapList* types,
761 Handle<String> name);
762 void HandlePolymorphicStoreNamedField(Assignment* expr,
763 HValue* object,
764 HValue* value,
765 ZoneMapList* types,
766 Handle<String> name);
767 void HandlePolymorphicCallNamed(Call* expr,
768 HValue* receiver,
769 ZoneMapList* types,
770 Handle<String> name);
771
772 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
773 HValue* left,
774 HValue* right);
775 HInstruction* BuildIncrement(HValue* value, bool increment);
776 HLoadNamedField* BuildLoadNamedField(HValue* object,
777 Property* expr,
778 Handle<Map> type,
779 LookupResult* result,
780 bool smi_and_map_check);
781 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
782 HInstruction* BuildLoadKeyedFastElement(HValue* object,
783 HValue* key,
784 Property* expr);
785 HInstruction* BuildLoadKeyedGeneric(HValue* object,
786 HValue* key);
787
788 HInstruction* BuildLoadNamed(HValue* object,
789 Property* prop,
790 Handle<Map> map,
791 Handle<String> name);
792 HInstruction* BuildStoreNamed(HValue* object,
793 HValue* value,
794 Expression* expr);
795 HInstruction* BuildStoreNamedField(HValue* object,
796 Handle<String> name,
797 HValue* value,
798 Handle<Map> type,
799 LookupResult* lookup,
800 bool smi_and_map_check);
801 HInstruction* BuildStoreNamedGeneric(HValue* object,
802 Handle<String> name,
803 HValue* value);
804 HInstruction* BuildStoreKeyedGeneric(HValue* object,
805 HValue* key,
806 HValue* value);
807
808 HInstruction* BuildStoreKeyedFastElement(HValue* object,
809 HValue* key,
810 HValue* val,
811 Expression* expr);
812
813 HCompare* BuildSwitchCompare(HSubgraph* subgraph,
814 HValue* switch_value,
815 CaseClause* clause);
816
817 void AddCheckConstantFunction(Call* expr,
818 HValue* receiver,
819 Handle<Map> receiver_map,
820 bool smi_and_map_check);
821
822
823 HBasicBlock* BuildTypeSwitch(ZoneMapList* maps,
824 ZoneList<HSubgraph*>* subgraphs,
825 HValue* receiver,
826 int join_id);
827
828 TypeFeedbackOracle* oracle_;
829 HGraph* graph_;
830 HSubgraph* current_subgraph_;
831 IterationStatement* peeled_statement_;
832 // Expression context of the currently visited subexpression. NULL when
833 // visiting statements.
834 AstContext* ast_context_;
835
836 // During function inlining, expression context of the call being
837 // inlined. NULL when not inlining.
838 AstContext* call_context_;
839
840 // When inlining a call in an effect or value context, the return
841 // block. NULL otherwise. When inlining a call in a test context, there
842 // are a pair of target blocks in the call context.
843 HBasicBlock* function_return_;
844
845 int inlined_count_;
846
847 friend class AstContext; // Pushes and pops the AST context stack.
848
849 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
850};
851
852
853class HValueMap: public ZoneObject {
854 public:
855 HValueMap()
856 : array_size_(0),
857 lists_size_(0),
858 count_(0),
859 present_flags_(0),
860 array_(NULL),
861 lists_(NULL),
862 free_list_head_(kNil) {
863 ResizeLists(kInitialSize);
864 Resize(kInitialSize);
865 }
866
867 void Kill(int flags);
868
869 void Add(HValue* value) {
870 present_flags_ |= value->flags();
871 Insert(value);
872 }
873
874 HValue* Lookup(HValue* value) const;
875 HValueMap* Copy() const { return new HValueMap(this); }
876
877 private:
878 // A linked list of HValue* values. Stored in arrays.
879 struct HValueMapListElement {
880 HValue* value;
881 int next; // Index in the array of the next list element.
882 };
883 static const int kNil = -1; // The end of a linked list
884
885 // Must be a power of 2.
886 static const int kInitialSize = 16;
887
888 explicit HValueMap(const HValueMap* other);
889
890 void Resize(int new_size);
891 void ResizeLists(int new_size);
892 void Insert(HValue* value);
893 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
894
895 int array_size_;
896 int lists_size_;
897 int count_; // The number of values stored in the HValueMap.
898 int present_flags_; // All flags that are in any value in the HValueMap.
899 HValueMapListElement* array_; // Primary store - contains the first value
900 // with a given hash. Colliding elements are stored in linked lists.
901 HValueMapListElement* lists_; // The linked lists containing hash collisions.
902 int free_list_head_; // Unused elements in lists_ are on the free list.
903};
904
905
906class HStatistics: public Malloced {
907 public:
908 void Print();
909 void SaveTiming(const char* name, int64_t ticks);
910 static HStatistics* Instance() {
911 static SetOncePointer<HStatistics> instance;
912 if (!instance.is_set()) {
913 instance.set(new HStatistics());
914 }
915 return instance.get();
916 }
917
918 private:
919
920 HStatistics() : timing_(5), names_(5), total_(0), full_code_gen_(0) { }
921
922 List<int64_t> timing_;
923 List<const char*> names_;
924 int64_t total_;
925 int64_t full_code_gen_;
926};
927
928
929class HPhase BASE_EMBEDDED {
930 public:
931 static const char* const kFullCodeGen;
932 static const char* const kTotal;
933
934 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
935 HPhase(const char* name, HGraph* graph) {
936 Begin(name, graph, NULL, NULL);
937 }
938 HPhase(const char* name, LChunk* chunk) {
939 Begin(name, NULL, chunk, NULL);
940 }
941 HPhase(const char* name, LAllocator* allocator) {
942 Begin(name, NULL, NULL, allocator);
943 }
944
945 ~HPhase() {
946 End();
947 }
948
949 private:
950 void Begin(const char* name,
951 HGraph* graph,
952 LChunk* chunk,
953 LAllocator* allocator);
954 void End() const;
955
956 int64_t start_;
957 const char* name_;
958 HGraph* graph_;
959 LChunk* chunk_;
960 LAllocator* allocator_;
961};
962
963
964class HTracer: public Malloced {
965 public:
966 void TraceCompilation(FunctionLiteral* function);
967 void TraceHydrogen(const char* name, HGraph* graph);
968 void TraceLithium(const char* name, LChunk* chunk);
969 void TraceLiveRanges(const char* name, LAllocator* allocator);
970
971 static HTracer* Instance() {
972 static SetOncePointer<HTracer> instance;
973 if (!instance.is_set()) {
974 instance.set(new HTracer("hydrogen.cfg"));
975 }
976 return instance.get();
977 }
978
979 private:
980 class Tag BASE_EMBEDDED {
981 public:
982 Tag(HTracer* tracer, const char* name) {
983 name_ = name;
984 tracer_ = tracer;
985 tracer->PrintIndent();
986 tracer->trace_.Add("begin_%s\n", name);
987 tracer->indent_++;
988 }
989
990 ~Tag() {
991 tracer_->indent_--;
992 tracer_->PrintIndent();
993 tracer_->trace_.Add("end_%s\n", name_);
994 ASSERT(tracer_->indent_ >= 0);
995 tracer_->FlushToFile();
996 }
997
998 private:
999 HTracer* tracer_;
1000 const char* name_;
1001 };
1002
1003 explicit HTracer(const char* filename)
1004 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1005 WriteChars(filename, "", 0, false);
1006 }
1007
1008 void TraceLiveRange(LiveRange* range, const char* type);
1009 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1010 void FlushToFile();
1011
1012 void PrintEmptyProperty(const char* name) {
1013 PrintIndent();
1014 trace_.Add("%s\n", name);
1015 }
1016
1017 void PrintStringProperty(const char* name, const char* value) {
1018 PrintIndent();
1019 trace_.Add("%s \"%s\"\n", name, value);
1020 }
1021
1022 void PrintLongProperty(const char* name, int64_t value) {
1023 PrintIndent();
1024 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1025 }
1026
1027 void PrintBlockProperty(const char* name, int block_id) {
1028 PrintIndent();
1029 trace_.Add("%s \"B%d\"\n", name, block_id);
1030 }
1031
1032 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1033 PrintIndent();
1034 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1035 }
1036
1037 void PrintIntProperty(const char* name, int value) {
1038 PrintIndent();
1039 trace_.Add("%s %d\n", name, value);
1040 }
1041
1042 void PrintIndent() {
1043 for (int i = 0; i < indent_; i++) {
1044 trace_.Add(" ");
1045 }
1046 }
1047
1048 const char* filename_;
1049 HeapStringAllocator string_allocator_;
1050 StringStream trace_;
1051 int indent_;
1052};
1053
1054
1055} } // namespace v8::internal
1056
1057#endif // V8_HYDROGEN_H_