blob: ebabf3d2923d1589f12f82188f665f220dccdb5c [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
404 void Bind(Variable* variable, HValue* value) {
405 Bind(IndexFor(variable), value);
406
407 if (FLAG_trace_environment) {
408 PrintF("Slot index=%d name=%s\n",
409 variable->AsSlot()->index(),
410 *variable->name()->ToCString());
411 }
412 }
413
414 void Bind(int index, HValue* value) {
415 ASSERT(value != NULL);
416 if (!assigned_variables_.Contains(index)) {
417 assigned_variables_.Add(index);
418 }
419 values_[index] = value;
420 }
421
422 HValue* Lookup(Variable* variable) const {
423 return Lookup(IndexFor(variable));
424 }
425 HValue* Lookup(int index) const {
426 HValue* result = values_[index];
427 ASSERT(result != NULL);
428 return result;
429 }
430
431 void Push(HValue* value) {
432 ASSERT(value != NULL);
433 ++push_count_;
434 values_.Add(value);
435 }
436
437 HValue* Top() const { return ExpressionStackAt(0); }
438
439 HValue* ExpressionStackAt(int index_from_top) const {
440 int index = values_.length() - index_from_top - 1;
441 ASSERT(IsExpressionStackIndex(index));
442 return values_[index];
443 }
444
445 void SetExpressionStackAt(int index_from_top, HValue* value) {
446 int index = values_.length() - index_from_top - 1;
447 ASSERT(IsExpressionStackIndex(index));
448 values_[index] = value;
449 }
450
451 HValue* Pop() {
452 ASSERT(!IsExpressionStackEmpty());
453 if (push_count_ > 0) {
454 --push_count_;
455 ASSERT(push_count_ >= 0);
456 } else {
457 ++pop_count_;
458 }
459 return values_.RemoveLast();
460 }
461
462 void Drop(int count) {
463 for (int i = 0; i < count; ++i) {
464 Pop();
465 }
466 }
467
468 Handle<JSFunction> closure() const { return closure_; }
469
470 // ID of the original AST node to identify deoptimization points.
471 int ast_id() const { return ast_id_; }
472 void set_ast_id(int id) { ast_id_ = id; }
473
474 const ZoneList<HValue*>* values() const { return &values_; }
475 const ZoneList<int>* assigned_variables() const {
476 return &assigned_variables_;
477 }
478 int parameter_count() const { return parameter_count_; }
479 int local_count() const { return local_count_; }
480 int push_count() const { return push_count_; }
481 int pop_count() const { return pop_count_; }
482 int total_count() const { return values_.length(); }
483 HEnvironment* outer() const { return outer_; }
484 HEnvironment* Copy() const;
485 HEnvironment* CopyWithoutHistory() const;
486 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
487
488 // Create an "inlined version" of this environment, where the original
489 // environment is the outer environment but the top expression stack
490 // elements are moved to an inner environment as parameters. If
491 // is_speculative, the argument values are expected to be PushArgument
492 // instructions, otherwise they are the actual values.
493 HEnvironment* CopyForInlining(Handle<JSFunction> target,
494 FunctionLiteral* function,
495 bool is_speculative,
496 HConstant* undefined) const;
497
498 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
499 void ClearHistory() {
500 pop_count_ = 0;
501 push_count_ = 0;
502 assigned_variables_.Clear();
503 }
504 void SetValueAt(int index, HValue* value) {
505 ASSERT(index < total_count());
506 values_[index] = value;
507 }
508
509 void PrintTo(StringStream* stream);
510 void PrintToStd();
511
512 private:
513 explicit HEnvironment(const HEnvironment* other);
514
515 bool IsExpressionStackIndex(int index) const {
516 return index >= parameter_count_ + local_count_;
517 }
518 bool IsExpressionStackEmpty() const {
519 int length = values_.length();
520 int first_expression = parameter_count() + local_count();
521 ASSERT(length >= first_expression);
522 return length == first_expression;
523 }
524 void Initialize(int parameter_count, int local_count, int stack_height);
525 void Initialize(const HEnvironment* other);
526 int VariableToIndex(Variable* var);
527 int IndexFor(Variable* variable) const;
528
529 Handle<JSFunction> closure_;
530 // Value array [parameters] [locals] [temporaries].
531 ZoneList<HValue*> values_;
532 ZoneList<int> assigned_variables_;
533 int parameter_count_;
534 int local_count_;
535 HEnvironment* outer_;
536 int pop_count_;
537 int push_count_;
538 int ast_id_;
539};
540
541
542class HGraphBuilder;
543
544class AstContext {
545 public:
546 bool IsEffect() const { return kind_ == Expression::kEffect; }
547 bool IsValue() const { return kind_ == Expression::kValue; }
548 bool IsTest() const { return kind_ == Expression::kTest; }
549
550 // 'Fill' this context with a hydrogen value. The value is assumed to
551 // have already been inserted in the instruction stream (or not need to
552 // be, e.g., HPhi). Call this function in tail position in the Visit
553 // functions for expressions.
554 virtual void ReturnValue(HValue* value) = 0;
555
556 // Add a hydrogen instruction to the instruction stream (recording an
557 // environment simulation if necessary) and then fill this context with
558 // the instruction as value.
559 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
560
561 protected:
562 AstContext(HGraphBuilder* owner, Expression::Context kind);
563 virtual ~AstContext();
564
565 HGraphBuilder* owner() const { return owner_; }
566
567 // We want to be able to assert, in a context-specific way, that the stack
568 // height makes sense when the context is filled.
569#ifdef DEBUG
570 int original_count_;
571#endif
572
573 private:
574 HGraphBuilder* owner_;
575 Expression::Context kind_;
576 AstContext* outer_;
577};
578
579
580class EffectContext: public AstContext {
581 public:
582 explicit EffectContext(HGraphBuilder* owner)
583 : AstContext(owner, Expression::kEffect) {
584 }
585 virtual ~EffectContext();
586
587 virtual void ReturnValue(HValue* value);
588 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
589};
590
591
592class ValueContext: public AstContext {
593 public:
594 explicit ValueContext(HGraphBuilder* owner)
595 : AstContext(owner, Expression::kValue) {
596 }
597 virtual ~ValueContext();
598
599 virtual void ReturnValue(HValue* value);
600 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
601};
602
603
604class TestContext: public AstContext {
605 public:
606 TestContext(HGraphBuilder* owner,
607 HBasicBlock* if_true,
608 HBasicBlock* if_false)
609 : AstContext(owner, Expression::kTest),
610 if_true_(if_true),
611 if_false_(if_false) {
612 }
613
614 virtual void ReturnValue(HValue* value);
615 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
616
617 static TestContext* cast(AstContext* context) {
618 ASSERT(context->IsTest());
619 return reinterpret_cast<TestContext*>(context);
620 }
621
622 HBasicBlock* if_true() const { return if_true_; }
623 HBasicBlock* if_false() const { return if_false_; }
624
625 private:
626 // Build the shared core part of the translation unpacking a value into
627 // control flow.
628 void BuildBranch(HValue* value);
629
630 HBasicBlock* if_true_;
631 HBasicBlock* if_false_;
632};
633
634
635class HGraphBuilder: public AstVisitor {
636 public:
637 explicit HGraphBuilder(TypeFeedbackOracle* oracle)
638 : oracle_(oracle),
639 graph_(NULL),
640 current_subgraph_(NULL),
641 peeled_statement_(NULL),
642 ast_context_(NULL),
643 call_context_(NULL),
644 function_return_(NULL),
645 inlined_count_(0) { }
646
647 HGraph* CreateGraph(CompilationInfo* info);
648
649 // Simple accessors.
650 HGraph* graph() const { return graph_; }
651 HSubgraph* subgraph() const { return current_subgraph_; }
652
653 HEnvironment* environment() const { return subgraph()->environment(); }
654 HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
655
656 // Adding instructions.
657 HInstruction* AddInstruction(HInstruction* instr);
658 void AddSimulate(int id);
659
660 // Bailout environment manipulation.
661 void Push(HValue* value) { environment()->Push(value); }
662 HValue* Pop() { return environment()->Pop(); }
663
664 private:
665 // Type of a member function that generates inline code for a native function.
666 typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count,
667 int ast_id);
668
669 // Forward declarations for inner scope classes.
670 class SubgraphScope;
671
672 static const InlineFunctionGenerator kInlineFunctionGenerators[];
673
674 static const int kMaxCallPolymorphism = 4;
675 static const int kMaxLoadPolymorphism = 4;
676 static const int kMaxStorePolymorphism = 4;
677
678 static const int kMaxInlinedNodes = 196;
679 static const int kMaxInlinedSize = 196;
680 static const int kMaxSourceSize = 600;
681
682 // Simple accessors.
683 TypeFeedbackOracle* oracle() const { return oracle_; }
684 AstContext* ast_context() const { return ast_context_; }
685 void set_ast_context(AstContext* context) { ast_context_ = context; }
686 AstContext* call_context() const { return call_context_; }
687 HBasicBlock* function_return() const { return function_return_; }
688
689 // Generators for inline runtime functions.
690#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
691 void Generate##Name(int argument_count, int ast_id);
692
693 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
694 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
695#undef INLINE_FUNCTION_GENERATOR_DECLARATION
696
697 void Bailout(const char* reason);
698
699 void AppendPeeledWhile(IterationStatement* stmt,
700 HSubgraph* cond_graph,
701 HSubgraph* body_graph,
702 HSubgraph* exit_graph);
703
704 void AddToSubgraph(HSubgraph* graph, ZoneList<Statement*>* stmts);
705 void AddToSubgraph(HSubgraph* graph, Statement* stmt);
706 void AddToSubgraph(HSubgraph* graph, Expression* expr);
707
708 HValue* Top() const { return environment()->Top(); }
709 void Drop(int n) { environment()->Drop(n); }
710 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
711
712 void VisitForValue(Expression* expr);
713 void VisitForEffect(Expression* expr);
714 void VisitForControl(Expression* expr,
715 HBasicBlock* true_block,
716 HBasicBlock* false_block);
717
718 // Visit an argument and wrap it in a PushArgument instruction.
719 HValue* VisitArgument(Expression* expr);
720 void VisitArgumentList(ZoneList<Expression*>* arguments);
721
722 void AddPhi(HPhi* phi);
723
724 void PushAndAdd(HInstruction* instr);
725
726 void PushArgumentsForStubCall(int argument_count);
727
728 // Remove the arguments from the bailout environment and emit instructions
729 // to push them as outgoing parameters.
730 void ProcessCall(HCall* call);
731
732 void AssumeRepresentation(HValue* value, Representation r);
733 static Representation ToRepresentation(TypeInfo info);
734
735 void SetupScope(Scope* scope);
736 virtual void VisitStatements(ZoneList<Statement*>* statements);
737
738#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
739 AST_NODE_LIST(DECLARE_VISIT)
740#undef DECLARE_VISIT
741
742 bool ShouldPeel(HSubgraph* cond, HSubgraph* body);
743
744 HBasicBlock* CreateBasicBlock(HEnvironment* env);
745 HSubgraph* CreateEmptySubgraph();
746 HSubgraph* CreateGotoSubgraph(HEnvironment* env);
747 HSubgraph* CreateBranchSubgraph(HEnvironment* env);
748 HSubgraph* CreateLoopHeaderSubgraph(HEnvironment* env);
749 HSubgraph* CreateInlinedSubgraph(HEnvironment* outer,
750 Handle<JSFunction> target,
751 FunctionLiteral* function);
752
753 // Helpers for flow graph construction.
754 void LookupGlobalPropertyCell(Variable* var,
755 LookupResult* lookup,
756 bool is_store);
757
758 bool TryArgumentsAccess(Property* expr);
759 bool TryCallApply(Call* expr);
760 bool TryInline(Call* expr);
761 bool TryMathFunctionInline(Call* expr);
762 void TraceInline(Handle<JSFunction> target, bool result);
763
764 void HandleGlobalVariableAssignment(Variable* var,
765 HValue* value,
766 int position,
767 int ast_id);
768
769 void HandlePropertyAssignment(Assignment* expr);
770 void HandleCompoundAssignment(Assignment* expr);
771 void HandlePolymorphicLoadNamedField(Property* expr,
772 HValue* object,
773 ZoneMapList* types,
774 Handle<String> name);
775 void HandlePolymorphicStoreNamedField(Assignment* expr,
776 HValue* object,
777 HValue* value,
778 ZoneMapList* types,
779 Handle<String> name);
780 void HandlePolymorphicCallNamed(Call* expr,
781 HValue* receiver,
782 ZoneMapList* types,
783 Handle<String> name);
784
785 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
786 HValue* left,
787 HValue* right);
788 HInstruction* BuildIncrement(HValue* value, bool increment);
789 HLoadNamedField* BuildLoadNamedField(HValue* object,
790 Property* expr,
791 Handle<Map> type,
792 LookupResult* result,
793 bool smi_and_map_check);
794 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
795 HInstruction* BuildLoadKeyedFastElement(HValue* object,
796 HValue* key,
797 Property* expr);
798 HInstruction* BuildLoadKeyedGeneric(HValue* object,
799 HValue* key);
800
801 HInstruction* BuildLoadNamed(HValue* object,
802 Property* prop,
803 Handle<Map> map,
804 Handle<String> name);
805 HInstruction* BuildStoreNamed(HValue* object,
806 HValue* value,
807 Expression* expr);
808 HInstruction* BuildStoreNamedField(HValue* object,
809 Handle<String> name,
810 HValue* value,
811 Handle<Map> type,
812 LookupResult* lookup,
813 bool smi_and_map_check);
814 HInstruction* BuildStoreNamedGeneric(HValue* object,
815 Handle<String> name,
816 HValue* value);
817 HInstruction* BuildStoreKeyedGeneric(HValue* object,
818 HValue* key,
819 HValue* value);
820
821 HInstruction* BuildStoreKeyedFastElement(HValue* object,
822 HValue* key,
823 HValue* val,
824 Expression* expr);
825
826 HCompare* BuildSwitchCompare(HSubgraph* subgraph,
827 HValue* switch_value,
828 CaseClause* clause);
829
830 void AddCheckConstantFunction(Call* expr,
831 HValue* receiver,
832 Handle<Map> receiver_map,
833 bool smi_and_map_check);
834
835
836 HBasicBlock* BuildTypeSwitch(ZoneMapList* maps,
837 ZoneList<HSubgraph*>* subgraphs,
838 HValue* receiver,
839 int join_id);
840
841 TypeFeedbackOracle* oracle_;
842 HGraph* graph_;
843 HSubgraph* current_subgraph_;
844 IterationStatement* peeled_statement_;
845 // Expression context of the currently visited subexpression. NULL when
846 // visiting statements.
847 AstContext* ast_context_;
848
849 // During function inlining, expression context of the call being
850 // inlined. NULL when not inlining.
851 AstContext* call_context_;
852
853 // When inlining a call in an effect or value context, the return
854 // block. NULL otherwise. When inlining a call in a test context, there
855 // are a pair of target blocks in the call context.
856 HBasicBlock* function_return_;
857
858 int inlined_count_;
859
860 friend class AstContext; // Pushes and pops the AST context stack.
861
862 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
863};
864
865
866class HValueMap: public ZoneObject {
867 public:
868 HValueMap()
869 : array_size_(0),
870 lists_size_(0),
871 count_(0),
872 present_flags_(0),
873 array_(NULL),
874 lists_(NULL),
875 free_list_head_(kNil) {
876 ResizeLists(kInitialSize);
877 Resize(kInitialSize);
878 }
879
880 void Kill(int flags);
881
882 void Add(HValue* value) {
883 present_flags_ |= value->flags();
884 Insert(value);
885 }
886
887 HValue* Lookup(HValue* value) const;
888 HValueMap* Copy() const { return new HValueMap(this); }
889
890 private:
891 // A linked list of HValue* values. Stored in arrays.
892 struct HValueMapListElement {
893 HValue* value;
894 int next; // Index in the array of the next list element.
895 };
896 static const int kNil = -1; // The end of a linked list
897
898 // Must be a power of 2.
899 static const int kInitialSize = 16;
900
901 explicit HValueMap(const HValueMap* other);
902
903 void Resize(int new_size);
904 void ResizeLists(int new_size);
905 void Insert(HValue* value);
906 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
907
908 int array_size_;
909 int lists_size_;
910 int count_; // The number of values stored in the HValueMap.
911 int present_flags_; // All flags that are in any value in the HValueMap.
912 HValueMapListElement* array_; // Primary store - contains the first value
913 // with a given hash. Colliding elements are stored in linked lists.
914 HValueMapListElement* lists_; // The linked lists containing hash collisions.
915 int free_list_head_; // Unused elements in lists_ are on the free list.
916};
917
918
919class HStatistics: public Malloced {
920 public:
921 void Print();
922 void SaveTiming(const char* name, int64_t ticks);
923 static HStatistics* Instance() {
924 static SetOncePointer<HStatistics> instance;
925 if (!instance.is_set()) {
926 instance.set(new HStatistics());
927 }
928 return instance.get();
929 }
930
931 private:
932
933 HStatistics() : timing_(5), names_(5), total_(0), full_code_gen_(0) { }
934
935 List<int64_t> timing_;
936 List<const char*> names_;
937 int64_t total_;
938 int64_t full_code_gen_;
939};
940
941
942class HPhase BASE_EMBEDDED {
943 public:
944 static const char* const kFullCodeGen;
945 static const char* const kTotal;
946
947 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
948 HPhase(const char* name, HGraph* graph) {
949 Begin(name, graph, NULL, NULL);
950 }
951 HPhase(const char* name, LChunk* chunk) {
952 Begin(name, NULL, chunk, NULL);
953 }
954 HPhase(const char* name, LAllocator* allocator) {
955 Begin(name, NULL, NULL, allocator);
956 }
957
958 ~HPhase() {
959 End();
960 }
961
962 private:
963 void Begin(const char* name,
964 HGraph* graph,
965 LChunk* chunk,
966 LAllocator* allocator);
967 void End() const;
968
969 int64_t start_;
970 const char* name_;
971 HGraph* graph_;
972 LChunk* chunk_;
973 LAllocator* allocator_;
974};
975
976
977class HTracer: public Malloced {
978 public:
979 void TraceCompilation(FunctionLiteral* function);
980 void TraceHydrogen(const char* name, HGraph* graph);
981 void TraceLithium(const char* name, LChunk* chunk);
982 void TraceLiveRanges(const char* name, LAllocator* allocator);
983
984 static HTracer* Instance() {
985 static SetOncePointer<HTracer> instance;
986 if (!instance.is_set()) {
987 instance.set(new HTracer("hydrogen.cfg"));
988 }
989 return instance.get();
990 }
991
992 private:
993 class Tag BASE_EMBEDDED {
994 public:
995 Tag(HTracer* tracer, const char* name) {
996 name_ = name;
997 tracer_ = tracer;
998 tracer->PrintIndent();
999 tracer->trace_.Add("begin_%s\n", name);
1000 tracer->indent_++;
1001 }
1002
1003 ~Tag() {
1004 tracer_->indent_--;
1005 tracer_->PrintIndent();
1006 tracer_->trace_.Add("end_%s\n", name_);
1007 ASSERT(tracer_->indent_ >= 0);
1008 tracer_->FlushToFile();
1009 }
1010
1011 private:
1012 HTracer* tracer_;
1013 const char* name_;
1014 };
1015
1016 explicit HTracer(const char* filename)
1017 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1018 WriteChars(filename, "", 0, false);
1019 }
1020
1021 void TraceLiveRange(LiveRange* range, const char* type);
1022 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1023 void FlushToFile();
1024
1025 void PrintEmptyProperty(const char* name) {
1026 PrintIndent();
1027 trace_.Add("%s\n", name);
1028 }
1029
1030 void PrintStringProperty(const char* name, const char* value) {
1031 PrintIndent();
1032 trace_.Add("%s \"%s\"\n", name, value);
1033 }
1034
1035 void PrintLongProperty(const char* name, int64_t value) {
1036 PrintIndent();
1037 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1038 }
1039
1040 void PrintBlockProperty(const char* name, int block_id) {
1041 PrintIndent();
1042 trace_.Add("%s \"B%d\"\n", name, block_id);
1043 }
1044
1045 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1046 PrintIndent();
1047 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1048 }
1049
1050 void PrintIntProperty(const char* name, int value) {
1051 PrintIndent();
1052 trace_.Add("%s %d\n", name, value);
1053 }
1054
1055 void PrintIndent() {
1056 for (int i = 0; i < indent_; i++) {
1057 trace_.Add(" ");
1058 }
1059 }
1060
1061 const char* filename_;
1062 HeapStringAllocator string_allocator_;
1063 StringStream trace_;
1064 int indent_;
1065};
1066
1067
1068} } // namespace v8::internal
1069
1070#endif // V8_HYDROGEN_H_