blob: 19f898381f02ab63c235ff45d329b5e7e78141a4 [file] [log] [blame]
Ben Murdochb8e0da22011-05-16 14:20:40 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002// 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_; }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100299
300 bool AllowAggressiveOptimizations() const;
301
Ben Murdochb0fe1622011-05-05 13:52:32 +0100302 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
303 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
304 Handle<String> debug_name() const { return info_->function()->debug_name(); }
305 HEnvironment* start_environment() const { return start_environment_; }
306
307 void InitializeInferredTypes();
308 void InsertTypeConversions();
309 void InsertRepresentationChanges();
310 bool ProcessArgumentsObject();
311 void EliminateRedundantPhis();
312 void Canonicalize();
313 void OrderBlocks();
314 void AssignDominators();
315
316 // Returns false if there are phi-uses of the arguments-object
317 // which are not supported by the optimizing compiler.
318 bool CollectPhis();
319
320 Handle<Code> Compile();
321
322 void set_undefined_constant(HConstant* constant) {
323 undefined_constant_.set(constant);
324 }
325 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
326 HConstant* GetConstant1();
327 HConstant* GetConstantMinus1();
328 HConstant* GetConstantTrue();
329 HConstant* GetConstantFalse();
330
331 HBasicBlock* CreateBasicBlock();
332 HArgumentsObject* GetArgumentsObject() const {
333 return arguments_object_.get();
334 }
335 bool HasArgumentsObject() const { return arguments_object_.is_set(); }
336
337 void SetArgumentsObject(HArgumentsObject* object) {
338 arguments_object_.set(object);
339 }
340
341 // True iff. we are compiling for OSR and the statement is the entry.
342 bool HasOsrEntryAt(IterationStatement* statement);
343
344 int GetMaximumValueID() const { return values_.length(); }
345 int GetNextBlockID() { return next_block_id_++; }
346 int GetNextValueID(HValue* value) {
347 values_.Add(value);
348 return values_.length() - 1;
349 }
350 HValue* LookupValue(int id) const {
351 if (id >= 0 && id < values_.length()) return values_[id];
352 return NULL;
353 }
354
355#ifdef DEBUG
356 void Verify() const;
357#endif
358
359 private:
360 void Postorder(HBasicBlock* block,
361 BitVector* visited,
362 ZoneList<HBasicBlock*>* order,
363 HBasicBlock* loop_header);
364 void PostorderLoopBlocks(HLoopInformation* loop,
365 BitVector* visited,
366 ZoneList<HBasicBlock*>* order,
367 HBasicBlock* loop_header);
368 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
369 Object* value);
370
371 void InsertTypeConversions(HInstruction* instr);
372 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
373 void InsertRepresentationChangeForUse(HValue* value,
374 HValue* use,
375 Representation to,
376 bool truncating);
377 void InsertRepresentationChanges(HValue* current);
378 void InferTypes(ZoneList<HValue*>* worklist);
379 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
380 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
381
382 int next_block_id_;
383 CompilationInfo* info_;
384 HEnvironment* start_environment_;
385 ZoneList<HBasicBlock*> blocks_;
386 ZoneList<HValue*> values_;
387 ZoneList<HPhi*>* phi_list_;
388 SetOncePointer<HConstant> undefined_constant_;
389 SetOncePointer<HConstant> constant_1_;
390 SetOncePointer<HConstant> constant_minus1_;
391 SetOncePointer<HConstant> constant_true_;
392 SetOncePointer<HConstant> constant_false_;
393 SetOncePointer<HArgumentsObject> arguments_object_;
394
395 friend class HSubgraph;
396
397 DISALLOW_COPY_AND_ASSIGN(HGraph);
398};
399
400
401class HEnvironment: public ZoneObject {
402 public:
403 HEnvironment(HEnvironment* outer,
404 Scope* scope,
405 Handle<JSFunction> closure);
406
Steve Block9fac8402011-05-12 15:51:54 +0100407 // Simple accessors.
408 Handle<JSFunction> closure() const { return closure_; }
409 const ZoneList<HValue*>* values() const { return &values_; }
410 const ZoneList<int>* assigned_variables() const {
411 return &assigned_variables_;
412 }
413 int parameter_count() const { return parameter_count_; }
414 int local_count() const { return local_count_; }
415 HEnvironment* outer() const { return outer_; }
416 int pop_count() const { return pop_count_; }
417 int push_count() const { return push_count_; }
418
419 int ast_id() const { return ast_id_; }
420 void set_ast_id(int id) { ast_id_ = id; }
421
422 int length() const { return values_.length(); }
423
Ben Murdochb0fe1622011-05-05 13:52:32 +0100424 void Bind(Variable* variable, HValue* value) {
425 Bind(IndexFor(variable), value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100426 }
427
Steve Block9fac8402011-05-12 15:51:54 +0100428 void Bind(int index, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100429
430 HValue* Lookup(Variable* variable) const {
431 return Lookup(IndexFor(variable));
432 }
Steve Block9fac8402011-05-12 15:51:54 +0100433
Ben Murdochb0fe1622011-05-05 13:52:32 +0100434 HValue* Lookup(int index) const {
435 HValue* result = values_[index];
436 ASSERT(result != NULL);
437 return result;
438 }
439
440 void Push(HValue* value) {
441 ASSERT(value != NULL);
442 ++push_count_;
443 values_.Add(value);
444 }
445
Ben Murdochb0fe1622011-05-05 13:52:32 +0100446 HValue* Pop() {
Steve Block9fac8402011-05-12 15:51:54 +0100447 ASSERT(!ExpressionStackIsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100448 if (push_count_ > 0) {
449 --push_count_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100450 } else {
451 ++pop_count_;
452 }
453 return values_.RemoveLast();
454 }
455
Steve Block9fac8402011-05-12 15:51:54 +0100456 void Drop(int count);
457
458 HValue* Top() const { return ExpressionStackAt(0); }
459
460 HValue* ExpressionStackAt(int index_from_top) const {
461 int index = length() - index_from_top - 1;
462 ASSERT(HasExpressionAt(index));
463 return values_[index];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100464 }
465
Steve Block9fac8402011-05-12 15:51:54 +0100466 void SetExpressionStackAt(int index_from_top, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100467
Ben Murdochb0fe1622011-05-05 13:52:32 +0100468 HEnvironment* Copy() const;
469 HEnvironment* CopyWithoutHistory() const;
470 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
471
472 // Create an "inlined version" of this environment, where the original
473 // environment is the outer environment but the top expression stack
474 // elements are moved to an inner environment as parameters. If
475 // is_speculative, the argument values are expected to be PushArgument
476 // instructions, otherwise they are the actual values.
477 HEnvironment* CopyForInlining(Handle<JSFunction> target,
478 FunctionLiteral* function,
479 bool is_speculative,
480 HConstant* undefined) const;
481
482 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100483
Ben Murdochb0fe1622011-05-05 13:52:32 +0100484 void ClearHistory() {
485 pop_count_ = 0;
486 push_count_ = 0;
487 assigned_variables_.Clear();
488 }
Steve Block9fac8402011-05-12 15:51:54 +0100489
Ben Murdochb0fe1622011-05-05 13:52:32 +0100490 void SetValueAt(int index, HValue* value) {
Steve Block9fac8402011-05-12 15:51:54 +0100491 ASSERT(index < length());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100492 values_[index] = value;
493 }
494
495 void PrintTo(StringStream* stream);
496 void PrintToStd();
497
498 private:
499 explicit HEnvironment(const HEnvironment* other);
500
Steve Block9fac8402011-05-12 15:51:54 +0100501 // True if index is included in the expression stack part of the environment.
502 bool HasExpressionAt(int index) const;
503
504 bool ExpressionStackIsEmpty() const;
505
Ben Murdochb0fe1622011-05-05 13:52:32 +0100506 void Initialize(int parameter_count, int local_count, int stack_height);
507 void Initialize(const HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100508
509 // Map a variable to an environment index. Parameter indices are shifted
510 // by 1 (receiver is parameter index -1 but environment index 0).
511 // Stack-allocated local indices are shifted by the number of parameters.
512 int IndexFor(Variable* variable) const {
513 Slot* slot = variable->AsSlot();
514 ASSERT(slot != NULL && slot->IsStackAllocated());
515 int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
516 return slot->index() + shift;
517 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100518
519 Handle<JSFunction> closure_;
520 // Value array [parameters] [locals] [temporaries].
521 ZoneList<HValue*> values_;
522 ZoneList<int> assigned_variables_;
523 int parameter_count_;
524 int local_count_;
525 HEnvironment* outer_;
526 int pop_count_;
527 int push_count_;
528 int ast_id_;
529};
530
531
532class HGraphBuilder;
533
534class AstContext {
535 public:
536 bool IsEffect() const { return kind_ == Expression::kEffect; }
537 bool IsValue() const { return kind_ == Expression::kValue; }
538 bool IsTest() const { return kind_ == Expression::kTest; }
539
540 // 'Fill' this context with a hydrogen value. The value is assumed to
541 // have already been inserted in the instruction stream (or not need to
542 // be, e.g., HPhi). Call this function in tail position in the Visit
543 // functions for expressions.
544 virtual void ReturnValue(HValue* value) = 0;
545
546 // Add a hydrogen instruction to the instruction stream (recording an
547 // environment simulation if necessary) and then fill this context with
548 // the instruction as value.
549 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
550
551 protected:
552 AstContext(HGraphBuilder* owner, Expression::Context kind);
553 virtual ~AstContext();
554
555 HGraphBuilder* owner() const { return owner_; }
556
557 // We want to be able to assert, in a context-specific way, that the stack
558 // height makes sense when the context is filled.
559#ifdef DEBUG
Steve Block9fac8402011-05-12 15:51:54 +0100560 int original_length_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100561#endif
562
563 private:
564 HGraphBuilder* owner_;
565 Expression::Context kind_;
566 AstContext* outer_;
567};
568
569
570class EffectContext: public AstContext {
571 public:
572 explicit EffectContext(HGraphBuilder* owner)
573 : AstContext(owner, Expression::kEffect) {
574 }
575 virtual ~EffectContext();
576
577 virtual void ReturnValue(HValue* value);
578 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
579};
580
581
582class ValueContext: public AstContext {
583 public:
584 explicit ValueContext(HGraphBuilder* owner)
585 : AstContext(owner, Expression::kValue) {
586 }
587 virtual ~ValueContext();
588
589 virtual void ReturnValue(HValue* value);
590 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
591};
592
593
594class TestContext: public AstContext {
595 public:
596 TestContext(HGraphBuilder* owner,
597 HBasicBlock* if_true,
598 HBasicBlock* if_false)
599 : AstContext(owner, Expression::kTest),
600 if_true_(if_true),
601 if_false_(if_false) {
602 }
603
604 virtual void ReturnValue(HValue* value);
605 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
606
607 static TestContext* cast(AstContext* context) {
608 ASSERT(context->IsTest());
609 return reinterpret_cast<TestContext*>(context);
610 }
611
612 HBasicBlock* if_true() const { return if_true_; }
613 HBasicBlock* if_false() const { return if_false_; }
614
615 private:
616 // Build the shared core part of the translation unpacking a value into
617 // control flow.
618 void BuildBranch(HValue* value);
619
620 HBasicBlock* if_true_;
621 HBasicBlock* if_false_;
622};
623
624
625class HGraphBuilder: public AstVisitor {
626 public:
627 explicit HGraphBuilder(TypeFeedbackOracle* oracle)
628 : oracle_(oracle),
629 graph_(NULL),
630 current_subgraph_(NULL),
631 peeled_statement_(NULL),
632 ast_context_(NULL),
633 call_context_(NULL),
634 function_return_(NULL),
635 inlined_count_(0) { }
636
637 HGraph* CreateGraph(CompilationInfo* info);
638
639 // Simple accessors.
640 HGraph* graph() const { return graph_; }
641 HSubgraph* subgraph() const { return current_subgraph_; }
642
643 HEnvironment* environment() const { return subgraph()->environment(); }
644 HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
645
646 // Adding instructions.
647 HInstruction* AddInstruction(HInstruction* instr);
648 void AddSimulate(int id);
649
650 // Bailout environment manipulation.
651 void Push(HValue* value) { environment()->Push(value); }
652 HValue* Pop() { return environment()->Pop(); }
653
654 private:
655 // Type of a member function that generates inline code for a native function.
656 typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count,
657 int ast_id);
658
659 // Forward declarations for inner scope classes.
660 class SubgraphScope;
661
662 static const InlineFunctionGenerator kInlineFunctionGenerators[];
663
664 static const int kMaxCallPolymorphism = 4;
665 static const int kMaxLoadPolymorphism = 4;
666 static const int kMaxStorePolymorphism = 4;
667
668 static const int kMaxInlinedNodes = 196;
669 static const int kMaxInlinedSize = 196;
670 static const int kMaxSourceSize = 600;
671
672 // Simple accessors.
673 TypeFeedbackOracle* oracle() const { return oracle_; }
674 AstContext* ast_context() const { return ast_context_; }
675 void set_ast_context(AstContext* context) { ast_context_ = context; }
676 AstContext* call_context() const { return call_context_; }
677 HBasicBlock* function_return() const { return function_return_; }
678
679 // Generators for inline runtime functions.
680#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
681 void Generate##Name(int argument_count, int ast_id);
682
683 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
684 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
685#undef INLINE_FUNCTION_GENERATOR_DECLARATION
686
687 void Bailout(const char* reason);
688
689 void AppendPeeledWhile(IterationStatement* stmt,
690 HSubgraph* cond_graph,
691 HSubgraph* body_graph,
692 HSubgraph* exit_graph);
693
694 void AddToSubgraph(HSubgraph* graph, ZoneList<Statement*>* stmts);
695 void AddToSubgraph(HSubgraph* graph, Statement* stmt);
696 void AddToSubgraph(HSubgraph* graph, Expression* expr);
697
698 HValue* Top() const { return environment()->Top(); }
699 void Drop(int n) { environment()->Drop(n); }
700 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
701
702 void VisitForValue(Expression* expr);
703 void VisitForEffect(Expression* expr);
704 void VisitForControl(Expression* expr,
705 HBasicBlock* true_block,
706 HBasicBlock* false_block);
707
708 // Visit an argument and wrap it in a PushArgument instruction.
709 HValue* VisitArgument(Expression* expr);
710 void VisitArgumentList(ZoneList<Expression*>* arguments);
711
712 void AddPhi(HPhi* phi);
713
714 void PushAndAdd(HInstruction* instr);
715
716 void PushArgumentsForStubCall(int argument_count);
717
718 // Remove the arguments from the bailout environment and emit instructions
719 // to push them as outgoing parameters.
720 void ProcessCall(HCall* call);
721
722 void AssumeRepresentation(HValue* value, Representation r);
723 static Representation ToRepresentation(TypeInfo info);
724
725 void SetupScope(Scope* scope);
726 virtual void VisitStatements(ZoneList<Statement*>* statements);
727
728#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
729 AST_NODE_LIST(DECLARE_VISIT)
730#undef DECLARE_VISIT
731
732 bool ShouldPeel(HSubgraph* cond, HSubgraph* body);
733
734 HBasicBlock* CreateBasicBlock(HEnvironment* env);
735 HSubgraph* CreateEmptySubgraph();
736 HSubgraph* CreateGotoSubgraph(HEnvironment* env);
737 HSubgraph* CreateBranchSubgraph(HEnvironment* env);
738 HSubgraph* CreateLoopHeaderSubgraph(HEnvironment* env);
739 HSubgraph* CreateInlinedSubgraph(HEnvironment* outer,
740 Handle<JSFunction> target,
741 FunctionLiteral* function);
742
743 // Helpers for flow graph construction.
744 void LookupGlobalPropertyCell(Variable* var,
745 LookupResult* lookup,
746 bool is_store);
747
748 bool TryArgumentsAccess(Property* expr);
749 bool TryCallApply(Call* expr);
750 bool TryInline(Call* expr);
751 bool TryMathFunctionInline(Call* expr);
752 void TraceInline(Handle<JSFunction> target, bool result);
753
754 void HandleGlobalVariableAssignment(Variable* var,
755 HValue* value,
756 int position,
757 int ast_id);
758
759 void HandlePropertyAssignment(Assignment* expr);
760 void HandleCompoundAssignment(Assignment* expr);
761 void HandlePolymorphicLoadNamedField(Property* expr,
762 HValue* object,
763 ZoneMapList* types,
764 Handle<String> name);
765 void HandlePolymorphicStoreNamedField(Assignment* expr,
766 HValue* object,
767 HValue* value,
768 ZoneMapList* types,
769 Handle<String> name);
770 void HandlePolymorphicCallNamed(Call* expr,
771 HValue* receiver,
772 ZoneMapList* types,
773 Handle<String> name);
774
775 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
776 HValue* left,
777 HValue* right);
778 HInstruction* BuildIncrement(HValue* value, bool increment);
779 HLoadNamedField* BuildLoadNamedField(HValue* object,
780 Property* expr,
781 Handle<Map> type,
782 LookupResult* result,
783 bool smi_and_map_check);
784 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
785 HInstruction* BuildLoadKeyedFastElement(HValue* object,
786 HValue* key,
787 Property* expr);
788 HInstruction* BuildLoadKeyedGeneric(HValue* object,
789 HValue* key);
790
791 HInstruction* BuildLoadNamed(HValue* object,
792 Property* prop,
793 Handle<Map> map,
794 Handle<String> name);
795 HInstruction* BuildStoreNamed(HValue* object,
796 HValue* value,
797 Expression* expr);
798 HInstruction* BuildStoreNamedField(HValue* object,
799 Handle<String> name,
800 HValue* value,
801 Handle<Map> type,
802 LookupResult* lookup,
803 bool smi_and_map_check);
804 HInstruction* BuildStoreNamedGeneric(HValue* object,
805 Handle<String> name,
806 HValue* value);
807 HInstruction* BuildStoreKeyedGeneric(HValue* object,
808 HValue* key,
809 HValue* value);
810
811 HInstruction* BuildStoreKeyedFastElement(HValue* object,
812 HValue* key,
813 HValue* val,
814 Expression* expr);
815
816 HCompare* BuildSwitchCompare(HSubgraph* subgraph,
817 HValue* switch_value,
818 CaseClause* clause);
819
820 void AddCheckConstantFunction(Call* expr,
821 HValue* receiver,
822 Handle<Map> receiver_map,
823 bool smi_and_map_check);
824
825
826 HBasicBlock* BuildTypeSwitch(ZoneMapList* maps,
827 ZoneList<HSubgraph*>* subgraphs,
828 HValue* receiver,
829 int join_id);
830
831 TypeFeedbackOracle* oracle_;
832 HGraph* graph_;
833 HSubgraph* current_subgraph_;
834 IterationStatement* peeled_statement_;
835 // Expression context of the currently visited subexpression. NULL when
836 // visiting statements.
837 AstContext* ast_context_;
838
839 // During function inlining, expression context of the call being
840 // inlined. NULL when not inlining.
841 AstContext* call_context_;
842
843 // When inlining a call in an effect or value context, the return
844 // block. NULL otherwise. When inlining a call in a test context, there
845 // are a pair of target blocks in the call context.
846 HBasicBlock* function_return_;
847
848 int inlined_count_;
849
850 friend class AstContext; // Pushes and pops the AST context stack.
851
852 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
853};
854
855
856class HValueMap: public ZoneObject {
857 public:
858 HValueMap()
859 : array_size_(0),
860 lists_size_(0),
861 count_(0),
862 present_flags_(0),
863 array_(NULL),
864 lists_(NULL),
865 free_list_head_(kNil) {
866 ResizeLists(kInitialSize);
867 Resize(kInitialSize);
868 }
869
870 void Kill(int flags);
871
872 void Add(HValue* value) {
873 present_flags_ |= value->flags();
874 Insert(value);
875 }
876
877 HValue* Lookup(HValue* value) const;
878 HValueMap* Copy() const { return new HValueMap(this); }
879
880 private:
881 // A linked list of HValue* values. Stored in arrays.
882 struct HValueMapListElement {
883 HValue* value;
884 int next; // Index in the array of the next list element.
885 };
886 static const int kNil = -1; // The end of a linked list
887
888 // Must be a power of 2.
889 static const int kInitialSize = 16;
890
891 explicit HValueMap(const HValueMap* other);
892
893 void Resize(int new_size);
894 void ResizeLists(int new_size);
895 void Insert(HValue* value);
896 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
897
898 int array_size_;
899 int lists_size_;
900 int count_; // The number of values stored in the HValueMap.
901 int present_flags_; // All flags that are in any value in the HValueMap.
902 HValueMapListElement* array_; // Primary store - contains the first value
903 // with a given hash. Colliding elements are stored in linked lists.
904 HValueMapListElement* lists_; // The linked lists containing hash collisions.
905 int free_list_head_; // Unused elements in lists_ are on the free list.
906};
907
908
909class HStatistics: public Malloced {
910 public:
911 void Print();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100912 void SaveTiming(const char* name, int64_t ticks, unsigned size);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100913 static HStatistics* Instance() {
914 static SetOncePointer<HStatistics> instance;
915 if (!instance.is_set()) {
916 instance.set(new HStatistics());
917 }
918 return instance.get();
919 }
920
921 private:
922
Ben Murdochb8e0da22011-05-16 14:20:40 +0100923 HStatistics()
924 : timing_(5),
925 names_(5),
926 sizes_(5),
927 total_(0),
928 total_size_(0),
929 full_code_gen_(0) { }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100930
931 List<int64_t> timing_;
932 List<const char*> names_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100933 List<unsigned> sizes_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100934 int64_t total_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100935 unsigned total_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100936 int64_t full_code_gen_;
937};
938
939
940class HPhase BASE_EMBEDDED {
941 public:
942 static const char* const kFullCodeGen;
943 static const char* const kTotal;
944
945 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
946 HPhase(const char* name, HGraph* graph) {
947 Begin(name, graph, NULL, NULL);
948 }
949 HPhase(const char* name, LChunk* chunk) {
950 Begin(name, NULL, chunk, NULL);
951 }
952 HPhase(const char* name, LAllocator* allocator) {
953 Begin(name, NULL, NULL, allocator);
954 }
955
956 ~HPhase() {
957 End();
958 }
959
960 private:
961 void Begin(const char* name,
962 HGraph* graph,
963 LChunk* chunk,
964 LAllocator* allocator);
965 void End() const;
966
967 int64_t start_;
968 const char* name_;
969 HGraph* graph_;
970 LChunk* chunk_;
971 LAllocator* allocator_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100972 unsigned start_allocation_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100973};
974
975
976class HTracer: public Malloced {
977 public:
978 void TraceCompilation(FunctionLiteral* function);
979 void TraceHydrogen(const char* name, HGraph* graph);
980 void TraceLithium(const char* name, LChunk* chunk);
981 void TraceLiveRanges(const char* name, LAllocator* allocator);
982
983 static HTracer* Instance() {
984 static SetOncePointer<HTracer> instance;
985 if (!instance.is_set()) {
986 instance.set(new HTracer("hydrogen.cfg"));
987 }
988 return instance.get();
989 }
990
991 private:
992 class Tag BASE_EMBEDDED {
993 public:
994 Tag(HTracer* tracer, const char* name) {
995 name_ = name;
996 tracer_ = tracer;
997 tracer->PrintIndent();
998 tracer->trace_.Add("begin_%s\n", name);
999 tracer->indent_++;
1000 }
1001
1002 ~Tag() {
1003 tracer_->indent_--;
1004 tracer_->PrintIndent();
1005 tracer_->trace_.Add("end_%s\n", name_);
1006 ASSERT(tracer_->indent_ >= 0);
1007 tracer_->FlushToFile();
1008 }
1009
1010 private:
1011 HTracer* tracer_;
1012 const char* name_;
1013 };
1014
1015 explicit HTracer(const char* filename)
1016 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1017 WriteChars(filename, "", 0, false);
1018 }
1019
1020 void TraceLiveRange(LiveRange* range, const char* type);
1021 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1022 void FlushToFile();
1023
1024 void PrintEmptyProperty(const char* name) {
1025 PrintIndent();
1026 trace_.Add("%s\n", name);
1027 }
1028
1029 void PrintStringProperty(const char* name, const char* value) {
1030 PrintIndent();
1031 trace_.Add("%s \"%s\"\n", name, value);
1032 }
1033
1034 void PrintLongProperty(const char* name, int64_t value) {
1035 PrintIndent();
1036 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1037 }
1038
1039 void PrintBlockProperty(const char* name, int block_id) {
1040 PrintIndent();
1041 trace_.Add("%s \"B%d\"\n", name, block_id);
1042 }
1043
1044 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1045 PrintIndent();
1046 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1047 }
1048
1049 void PrintIntProperty(const char* name, int value) {
1050 PrintIndent();
1051 trace_.Add("%s %d\n", name, value);
1052 }
1053
1054 void PrintIndent() {
1055 for (int i = 0; i < indent_; i++) {
1056 trace_.Add(" ");
1057 }
1058 }
1059
1060 const char* filename_;
1061 HeapStringAllocator string_allocator_;
1062 StringStream trace_;
1063 int indent_;
1064};
1065
1066
1067} } // namespace v8::internal
1068
1069#endif // V8_HYDROGEN_H_