blob: 6f41ee68959e537f176ddaf0dbd6e57ecfe86506 [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; }
Steve Block1e0659c2011-05-24 12:43:12 +0100106 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100107
108 void set_parent_loop_header(HBasicBlock* block) {
Steve Block1e0659c2011-05-24 12:43:12 +0100109 ASSERT(parent_loop_header_ == NULL);
110 parent_loop_header_ = block;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100111 }
112
Steve Block1e0659c2011-05-24 12:43:12 +0100113 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100114
115 void SetJoinId(int id);
116
117 void Finish(HControlInstruction* last);
118 void Goto(HBasicBlock* block, bool include_stack_check = false);
119
120 int PredecessorIndexOf(HBasicBlock* predecessor) const;
121 void AddSimulate(int id) { AddInstruction(CreateSimulate(id)); }
122 void AssignCommonDominator(HBasicBlock* other);
123
124 // Add the inlined function exit sequence, adding an HLeaveInlined
125 // instruction and updating the bailout environment.
126 void AddLeaveInlined(HValue* return_value, HBasicBlock* target);
127
128 // If a target block is tagged as an inline function return, all
129 // predecessors should contain the inlined exit sequence:
130 //
131 // LeaveInlined
132 // Simulate (caller's environment)
133 // Goto (target block)
134 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
135 void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
136
Ben Murdochb0fe1622011-05-05 13:52:32 +0100137#ifdef DEBUG
138 void Verify();
139#endif
140
141 private:
142 void RegisterPredecessor(HBasicBlock* pred);
143 void AddDominatedBlock(HBasicBlock* block);
144
145 HSimulate* CreateSimulate(int id);
146
147 int block_id_;
148 HGraph* graph_;
149 ZoneList<HPhi*> phis_;
150 HInstruction* first_;
151 HInstruction* last_; // Last non-control instruction of the block.
152 HControlInstruction* end_;
153 HLoopInformation* loop_information_;
154 ZoneList<HBasicBlock*> predecessors_;
155 HBasicBlock* dominator_;
156 ZoneList<HBasicBlock*> dominated_blocks_;
157 HEnvironment* last_environment_;
158 // Outgoing parameter count at block exit, set during lithium translation.
159 int argument_count_;
160 // Instruction indices into the lithium code stream.
161 int first_instruction_index_;
162 int last_instruction_index_;
163 ZoneList<int> deleted_phis_;
Steve Block1e0659c2011-05-24 12:43:12 +0100164 HBasicBlock* parent_loop_header_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100165 bool is_inline_return_target_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100166};
167
168
169class HLoopInformation: public ZoneObject {
170 public:
171 explicit HLoopInformation(HBasicBlock* loop_header)
172 : back_edges_(4), loop_header_(loop_header), blocks_(8) {
173 blocks_.Add(loop_header);
174 }
175 virtual ~HLoopInformation() {}
176
177 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
178 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
179 HBasicBlock* loop_header() const { return loop_header_; }
180 HBasicBlock* GetLastBackEdge() const;
181 void RegisterBackEdge(HBasicBlock* block);
182
183 private:
184 void AddBlock(HBasicBlock* block);
185
186 ZoneList<HBasicBlock*> back_edges_;
187 HBasicBlock* loop_header_;
188 ZoneList<HBasicBlock*> blocks_;
189};
190
191
192class HSubgraph: public ZoneObject {
193 public:
194 explicit HSubgraph(HGraph* graph)
195 : graph_(graph),
196 entry_block_(NULL),
197 exit_block_(NULL),
198 break_continue_info_(4) {
199 }
200
201 HGraph* graph() const { return graph_; }
202 HEnvironment* environment() const {
203 ASSERT(HasExit());
204 return exit_block_->last_environment();
205 }
206
207 bool HasExit() const { return exit_block_ != NULL; }
208
209 void PreProcessOsrEntry(IterationStatement* statement);
210
211 void AppendOptional(HSubgraph* graph,
212 bool on_true_branch,
213 HValue* boolean_value);
214 void AppendJoin(HSubgraph* then_graph, HSubgraph* else_graph, AstNode* node);
215 void AppendWhile(HSubgraph* condition,
216 HSubgraph* body,
217 IterationStatement* statement,
218 HSubgraph* continue_subgraph,
219 HSubgraph* exit);
220 void AppendDoWhile(HSubgraph* body,
221 IterationStatement* statement,
222 HSubgraph* go_back,
223 HSubgraph* exit);
224 void AppendEndless(HSubgraph* body, IterationStatement* statement);
225 void Append(HSubgraph* next, BreakableStatement* statement);
226 void ResolveContinue(IterationStatement* statement);
227 HBasicBlock* BundleBreak(BreakableStatement* statement);
228 HBasicBlock* BundleContinue(IterationStatement* statement);
229 HBasicBlock* BundleBreakContinue(BreakableStatement* statement,
230 bool is_continue,
231 int join_id);
232 HBasicBlock* JoinBlocks(HBasicBlock* a, HBasicBlock* b, int id);
233
234 void FinishExit(HControlInstruction* instruction);
235 void FinishBreakContinue(BreakableStatement* target, bool is_continue);
236 void Initialize(HBasicBlock* block) {
237 ASSERT(entry_block_ == NULL);
238 entry_block_ = block;
239 exit_block_ = block;
240 }
241 HBasicBlock* entry_block() const { return entry_block_; }
242 HBasicBlock* exit_block() const { return exit_block_; }
243 void set_exit_block(HBasicBlock* block) {
244 exit_block_ = block;
245 }
246
247 void ConnectExitTo(HBasicBlock* other, bool include_stack_check = false) {
248 if (HasExit()) {
249 exit_block()->Goto(other, include_stack_check);
250 }
251 }
252
253 void AddBreakContinueInfo(HSubgraph* other) {
254 break_continue_info_.AddAll(other->break_continue_info_);
255 }
256
257 protected:
258 class BreakContinueInfo: public ZoneObject {
259 public:
260 BreakContinueInfo(BreakableStatement* target, HBasicBlock* block,
261 bool is_continue)
262 : target_(target), block_(block), continue_(is_continue) {}
263 BreakableStatement* target() const { return target_; }
264 HBasicBlock* block() const { return block_; }
265 bool is_continue() const { return continue_; }
266 bool IsResolved() const { return block_ == NULL; }
267 void Resolve() { block_ = NULL; }
268
269 private:
270 BreakableStatement* target_;
271 HBasicBlock* block_;
272 bool continue_;
273 };
274
275 const ZoneList<BreakContinueInfo*>* break_continue_info() const {
276 return &break_continue_info_;
277 }
278
279 HGraph* graph_; // The graph this is a subgraph of.
280 HBasicBlock* entry_block_;
281 HBasicBlock* exit_block_;
282
283 private:
284 ZoneList<BreakContinueInfo*> break_continue_info_;
285};
286
287
288class HGraph: public HSubgraph {
289 public:
290 explicit HGraph(CompilationInfo* info);
291
292 CompilationInfo* info() const { return info_; }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100293
Steve Block1e0659c2011-05-24 12:43:12 +0100294 bool AllowCodeMotion() const;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100295
Ben Murdochb0fe1622011-05-05 13:52:32 +0100296 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
297 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
298 Handle<String> debug_name() const { return info_->function()->debug_name(); }
299 HEnvironment* start_environment() const { return start_environment_; }
300
301 void InitializeInferredTypes();
302 void InsertTypeConversions();
303 void InsertRepresentationChanges();
Steve Block1e0659c2011-05-24 12:43:12 +0100304 void ComputeMinusZeroChecks();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100305 bool ProcessArgumentsObject();
306 void EliminateRedundantPhis();
307 void Canonicalize();
308 void OrderBlocks();
309 void AssignDominators();
310
311 // Returns false if there are phi-uses of the arguments-object
312 // which are not supported by the optimizing compiler.
313 bool CollectPhis();
314
315 Handle<Code> Compile();
316
317 void set_undefined_constant(HConstant* constant) {
318 undefined_constant_.set(constant);
319 }
320 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
321 HConstant* GetConstant1();
322 HConstant* GetConstantMinus1();
323 HConstant* GetConstantTrue();
324 HConstant* GetConstantFalse();
325
326 HBasicBlock* CreateBasicBlock();
327 HArgumentsObject* GetArgumentsObject() const {
328 return arguments_object_.get();
329 }
330 bool HasArgumentsObject() const { return arguments_object_.is_set(); }
331
332 void SetArgumentsObject(HArgumentsObject* object) {
333 arguments_object_.set(object);
334 }
335
336 // True iff. we are compiling for OSR and the statement is the entry.
337 bool HasOsrEntryAt(IterationStatement* statement);
338
339 int GetMaximumValueID() const { return values_.length(); }
340 int GetNextBlockID() { return next_block_id_++; }
341 int GetNextValueID(HValue* value) {
342 values_.Add(value);
343 return values_.length() - 1;
344 }
345 HValue* LookupValue(int id) const {
346 if (id >= 0 && id < values_.length()) return values_[id];
347 return NULL;
348 }
349
350#ifdef DEBUG
351 void Verify() const;
352#endif
353
354 private:
355 void Postorder(HBasicBlock* block,
356 BitVector* visited,
357 ZoneList<HBasicBlock*>* order,
358 HBasicBlock* loop_header);
359 void PostorderLoopBlocks(HLoopInformation* loop,
360 BitVector* visited,
361 ZoneList<HBasicBlock*>* order,
362 HBasicBlock* loop_header);
363 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
364 Object* value);
365
366 void InsertTypeConversions(HInstruction* instr);
367 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
368 void InsertRepresentationChangeForUse(HValue* value,
369 HValue* use,
370 Representation to,
371 bool truncating);
372 void InsertRepresentationChanges(HValue* current);
373 void InferTypes(ZoneList<HValue*>* worklist);
374 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
375 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
376
377 int next_block_id_;
378 CompilationInfo* info_;
379 HEnvironment* start_environment_;
380 ZoneList<HBasicBlock*> blocks_;
381 ZoneList<HValue*> values_;
382 ZoneList<HPhi*>* phi_list_;
383 SetOncePointer<HConstant> undefined_constant_;
384 SetOncePointer<HConstant> constant_1_;
385 SetOncePointer<HConstant> constant_minus1_;
386 SetOncePointer<HConstant> constant_true_;
387 SetOncePointer<HConstant> constant_false_;
388 SetOncePointer<HArgumentsObject> arguments_object_;
389
390 friend class HSubgraph;
391
392 DISALLOW_COPY_AND_ASSIGN(HGraph);
393};
394
395
396class HEnvironment: public ZoneObject {
397 public:
398 HEnvironment(HEnvironment* outer,
399 Scope* scope,
400 Handle<JSFunction> closure);
401
Steve Block9fac8402011-05-12 15:51:54 +0100402 // Simple accessors.
403 Handle<JSFunction> closure() const { return closure_; }
404 const ZoneList<HValue*>* values() const { return &values_; }
405 const ZoneList<int>* assigned_variables() const {
406 return &assigned_variables_;
407 }
408 int parameter_count() const { return parameter_count_; }
409 int local_count() const { return local_count_; }
410 HEnvironment* outer() const { return outer_; }
411 int pop_count() const { return pop_count_; }
412 int push_count() const { return push_count_; }
413
414 int ast_id() const { return ast_id_; }
415 void set_ast_id(int id) { ast_id_ = id; }
416
417 int length() const { return values_.length(); }
418
Ben Murdochb0fe1622011-05-05 13:52:32 +0100419 void Bind(Variable* variable, HValue* value) {
420 Bind(IndexFor(variable), value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100421 }
422
Steve Block9fac8402011-05-12 15:51:54 +0100423 void Bind(int index, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100424
425 HValue* Lookup(Variable* variable) const {
426 return Lookup(IndexFor(variable));
427 }
Steve Block9fac8402011-05-12 15:51:54 +0100428
Ben Murdochb0fe1622011-05-05 13:52:32 +0100429 HValue* Lookup(int index) const {
430 HValue* result = values_[index];
431 ASSERT(result != NULL);
432 return result;
433 }
434
435 void Push(HValue* value) {
436 ASSERT(value != NULL);
437 ++push_count_;
438 values_.Add(value);
439 }
440
Ben Murdochb0fe1622011-05-05 13:52:32 +0100441 HValue* Pop() {
Steve Block9fac8402011-05-12 15:51:54 +0100442 ASSERT(!ExpressionStackIsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100443 if (push_count_ > 0) {
444 --push_count_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100445 } else {
446 ++pop_count_;
447 }
448 return values_.RemoveLast();
449 }
450
Steve Block9fac8402011-05-12 15:51:54 +0100451 void Drop(int count);
452
453 HValue* Top() const { return ExpressionStackAt(0); }
454
455 HValue* ExpressionStackAt(int index_from_top) const {
456 int index = length() - index_from_top - 1;
457 ASSERT(HasExpressionAt(index));
458 return values_[index];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100459 }
460
Steve Block9fac8402011-05-12 15:51:54 +0100461 void SetExpressionStackAt(int index_from_top, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100462
Ben Murdochb0fe1622011-05-05 13:52:32 +0100463 HEnvironment* Copy() const;
464 HEnvironment* CopyWithoutHistory() const;
465 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
466
467 // Create an "inlined version" of this environment, where the original
468 // environment is the outer environment but the top expression stack
469 // elements are moved to an inner environment as parameters. If
470 // is_speculative, the argument values are expected to be PushArgument
471 // instructions, otherwise they are the actual values.
472 HEnvironment* CopyForInlining(Handle<JSFunction> target,
473 FunctionLiteral* function,
474 bool is_speculative,
475 HConstant* undefined) const;
476
477 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100478
Ben Murdochb0fe1622011-05-05 13:52:32 +0100479 void ClearHistory() {
480 pop_count_ = 0;
481 push_count_ = 0;
482 assigned_variables_.Clear();
483 }
Steve Block9fac8402011-05-12 15:51:54 +0100484
Ben Murdochb0fe1622011-05-05 13:52:32 +0100485 void SetValueAt(int index, HValue* value) {
Steve Block9fac8402011-05-12 15:51:54 +0100486 ASSERT(index < length());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100487 values_[index] = value;
488 }
489
490 void PrintTo(StringStream* stream);
491 void PrintToStd();
492
493 private:
494 explicit HEnvironment(const HEnvironment* other);
495
Steve Block9fac8402011-05-12 15:51:54 +0100496 // True if index is included in the expression stack part of the environment.
497 bool HasExpressionAt(int index) const;
498
499 bool ExpressionStackIsEmpty() const;
500
Ben Murdochb0fe1622011-05-05 13:52:32 +0100501 void Initialize(int parameter_count, int local_count, int stack_height);
502 void Initialize(const HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100503
504 // Map a variable to an environment index. Parameter indices are shifted
505 // by 1 (receiver is parameter index -1 but environment index 0).
506 // Stack-allocated local indices are shifted by the number of parameters.
507 int IndexFor(Variable* variable) const {
508 Slot* slot = variable->AsSlot();
509 ASSERT(slot != NULL && slot->IsStackAllocated());
510 int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
511 return slot->index() + shift;
512 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100513
514 Handle<JSFunction> closure_;
515 // Value array [parameters] [locals] [temporaries].
516 ZoneList<HValue*> values_;
517 ZoneList<int> assigned_variables_;
518 int parameter_count_;
519 int local_count_;
520 HEnvironment* outer_;
521 int pop_count_;
522 int push_count_;
523 int ast_id_;
524};
525
526
527class HGraphBuilder;
528
529class AstContext {
530 public:
531 bool IsEffect() const { return kind_ == Expression::kEffect; }
532 bool IsValue() const { return kind_ == Expression::kValue; }
533 bool IsTest() const { return kind_ == Expression::kTest; }
534
535 // 'Fill' this context with a hydrogen value. The value is assumed to
536 // have already been inserted in the instruction stream (or not need to
537 // be, e.g., HPhi). Call this function in tail position in the Visit
538 // functions for expressions.
539 virtual void ReturnValue(HValue* value) = 0;
540
541 // Add a hydrogen instruction to the instruction stream (recording an
542 // environment simulation if necessary) and then fill this context with
543 // the instruction as value.
544 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
545
546 protected:
547 AstContext(HGraphBuilder* owner, Expression::Context kind);
548 virtual ~AstContext();
549
550 HGraphBuilder* owner() const { return owner_; }
551
552 // We want to be able to assert, in a context-specific way, that the stack
553 // height makes sense when the context is filled.
554#ifdef DEBUG
Steve Block9fac8402011-05-12 15:51:54 +0100555 int original_length_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100556#endif
557
558 private:
559 HGraphBuilder* owner_;
560 Expression::Context kind_;
561 AstContext* outer_;
562};
563
564
565class EffectContext: public AstContext {
566 public:
567 explicit EffectContext(HGraphBuilder* owner)
568 : AstContext(owner, Expression::kEffect) {
569 }
570 virtual ~EffectContext();
571
572 virtual void ReturnValue(HValue* value);
573 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
574};
575
576
577class ValueContext: public AstContext {
578 public:
579 explicit ValueContext(HGraphBuilder* owner)
580 : AstContext(owner, Expression::kValue) {
581 }
582 virtual ~ValueContext();
583
584 virtual void ReturnValue(HValue* value);
585 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
586};
587
588
589class TestContext: public AstContext {
590 public:
591 TestContext(HGraphBuilder* owner,
592 HBasicBlock* if_true,
593 HBasicBlock* if_false)
594 : AstContext(owner, Expression::kTest),
595 if_true_(if_true),
596 if_false_(if_false) {
597 }
598
599 virtual void ReturnValue(HValue* value);
600 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
601
602 static TestContext* cast(AstContext* context) {
603 ASSERT(context->IsTest());
604 return reinterpret_cast<TestContext*>(context);
605 }
606
607 HBasicBlock* if_true() const { return if_true_; }
608 HBasicBlock* if_false() const { return if_false_; }
609
610 private:
611 // Build the shared core part of the translation unpacking a value into
612 // control flow.
613 void BuildBranch(HValue* value);
614
615 HBasicBlock* if_true_;
616 HBasicBlock* if_false_;
617};
618
619
620class HGraphBuilder: public AstVisitor {
621 public:
622 explicit HGraphBuilder(TypeFeedbackOracle* oracle)
623 : oracle_(oracle),
624 graph_(NULL),
625 current_subgraph_(NULL),
626 peeled_statement_(NULL),
627 ast_context_(NULL),
628 call_context_(NULL),
629 function_return_(NULL),
630 inlined_count_(0) { }
631
632 HGraph* CreateGraph(CompilationInfo* info);
633
634 // Simple accessors.
635 HGraph* graph() const { return graph_; }
636 HSubgraph* subgraph() const { return current_subgraph_; }
637
638 HEnvironment* environment() const { return subgraph()->environment(); }
639 HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
640
641 // Adding instructions.
642 HInstruction* AddInstruction(HInstruction* instr);
643 void AddSimulate(int id);
644
645 // Bailout environment manipulation.
646 void Push(HValue* value) { environment()->Push(value); }
647 HValue* Pop() { return environment()->Pop(); }
648
649 private:
650 // Type of a member function that generates inline code for a native function.
651 typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count,
652 int ast_id);
653
654 // Forward declarations for inner scope classes.
655 class SubgraphScope;
656
657 static const InlineFunctionGenerator kInlineFunctionGenerators[];
658
659 static const int kMaxCallPolymorphism = 4;
660 static const int kMaxLoadPolymorphism = 4;
661 static const int kMaxStorePolymorphism = 4;
662
663 static const int kMaxInlinedNodes = 196;
664 static const int kMaxInlinedSize = 196;
665 static const int kMaxSourceSize = 600;
666
667 // Simple accessors.
668 TypeFeedbackOracle* oracle() const { return oracle_; }
669 AstContext* ast_context() const { return ast_context_; }
670 void set_ast_context(AstContext* context) { ast_context_ = context; }
671 AstContext* call_context() const { return call_context_; }
672 HBasicBlock* function_return() const { return function_return_; }
673
674 // Generators for inline runtime functions.
675#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
676 void Generate##Name(int argument_count, int ast_id);
677
678 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
679 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
680#undef INLINE_FUNCTION_GENERATOR_DECLARATION
681
682 void Bailout(const char* reason);
683
684 void AppendPeeledWhile(IterationStatement* stmt,
685 HSubgraph* cond_graph,
686 HSubgraph* body_graph,
687 HSubgraph* exit_graph);
688
689 void AddToSubgraph(HSubgraph* graph, ZoneList<Statement*>* stmts);
690 void AddToSubgraph(HSubgraph* graph, Statement* stmt);
691 void AddToSubgraph(HSubgraph* graph, Expression* expr);
692
693 HValue* Top() const { return environment()->Top(); }
694 void Drop(int n) { environment()->Drop(n); }
695 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
696
697 void VisitForValue(Expression* expr);
698 void VisitForEffect(Expression* expr);
699 void VisitForControl(Expression* expr,
700 HBasicBlock* true_block,
701 HBasicBlock* false_block);
702
Steve Block1e0659c2011-05-24 12:43:12 +0100703 // Visit an argument subexpression.
704 void VisitArgument(Expression* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100705 void VisitArgumentList(ZoneList<Expression*>* arguments);
706
707 void AddPhi(HPhi* phi);
708
709 void PushAndAdd(HInstruction* instr);
710
Ben Murdochb0fe1622011-05-05 13:52:32 +0100711 // Remove the arguments from the bailout environment and emit instructions
712 // to push them as outgoing parameters.
Steve Block1e0659c2011-05-24 12:43:12 +0100713 void PreProcessCall(HCall* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100714
715 void AssumeRepresentation(HValue* value, Representation r);
716 static Representation ToRepresentation(TypeInfo info);
717
718 void SetupScope(Scope* scope);
719 virtual void VisitStatements(ZoneList<Statement*>* statements);
720
721#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
722 AST_NODE_LIST(DECLARE_VISIT)
723#undef DECLARE_VISIT
724
725 bool ShouldPeel(HSubgraph* cond, HSubgraph* body);
726
727 HBasicBlock* CreateBasicBlock(HEnvironment* env);
728 HSubgraph* CreateEmptySubgraph();
729 HSubgraph* CreateGotoSubgraph(HEnvironment* env);
730 HSubgraph* CreateBranchSubgraph(HEnvironment* env);
731 HSubgraph* CreateLoopHeaderSubgraph(HEnvironment* env);
732 HSubgraph* CreateInlinedSubgraph(HEnvironment* outer,
733 Handle<JSFunction> target,
734 FunctionLiteral* function);
735
736 // Helpers for flow graph construction.
737 void LookupGlobalPropertyCell(Variable* var,
738 LookupResult* lookup,
739 bool is_store);
740
741 bool TryArgumentsAccess(Property* expr);
742 bool TryCallApply(Call* expr);
743 bool TryInline(Call* expr);
Steve Block1e0659c2011-05-24 12:43:12 +0100744 bool TryInlineBuiltinFunction(Call* expr,
745 HValue* receiver,
746 Handle<Map> receiver_map,
747 CheckType check_type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100748 void TraceInline(Handle<JSFunction> target, bool result);
749
750 void HandleGlobalVariableAssignment(Variable* var,
751 HValue* value,
752 int position,
753 int ast_id);
754
755 void HandlePropertyAssignment(Assignment* expr);
756 void HandleCompoundAssignment(Assignment* expr);
757 void HandlePolymorphicLoadNamedField(Property* expr,
758 HValue* object,
759 ZoneMapList* types,
760 Handle<String> name);
761 void HandlePolymorphicStoreNamedField(Assignment* expr,
762 HValue* object,
763 HValue* value,
764 ZoneMapList* types,
765 Handle<String> name);
766 void HandlePolymorphicCallNamed(Call* expr,
767 HValue* receiver,
768 ZoneMapList* types,
769 Handle<String> name);
770
Steve Block1e0659c2011-05-24 12:43:12 +0100771 HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
772 HValue* index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100773 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
774 HValue* left,
775 HValue* right);
776 HInstruction* BuildIncrement(HValue* value, bool increment);
777 HLoadNamedField* BuildLoadNamedField(HValue* object,
778 Property* expr,
779 Handle<Map> type,
780 LookupResult* result,
781 bool smi_and_map_check);
782 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
783 HInstruction* BuildLoadKeyedFastElement(HValue* object,
784 HValue* key,
785 Property* expr);
Steve Block1e0659c2011-05-24 12:43:12 +0100786 HInstruction* BuildLoadKeyedPixelArrayElement(HValue* object,
787 HValue* key,
788 Property* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100789 HInstruction* BuildLoadKeyedGeneric(HValue* object,
790 HValue* key);
791
792 HInstruction* BuildLoadNamed(HValue* object,
793 Property* prop,
794 Handle<Map> map,
795 Handle<String> name);
796 HInstruction* BuildStoreNamed(HValue* object,
797 HValue* value,
798 Expression* expr);
799 HInstruction* BuildStoreNamedField(HValue* object,
800 Handle<String> name,
801 HValue* value,
802 Handle<Map> type,
803 LookupResult* lookup,
804 bool smi_and_map_check);
805 HInstruction* BuildStoreNamedGeneric(HValue* object,
806 Handle<String> name,
807 HValue* value);
808 HInstruction* BuildStoreKeyedGeneric(HValue* object,
809 HValue* key,
810 HValue* value);
811
812 HInstruction* BuildStoreKeyedFastElement(HValue* object,
813 HValue* key,
814 HValue* val,
815 Expression* expr);
816
817 HCompare* BuildSwitchCompare(HSubgraph* subgraph,
818 HValue* switch_value,
819 CaseClause* clause);
820
Steve Block1e0659c2011-05-24 12:43:12 +0100821 HValue* BuildContextChainWalk(Variable* var);
822
Ben Murdochb0fe1622011-05-05 13:52:32 +0100823 void AddCheckConstantFunction(Call* expr,
824 HValue* receiver,
825 Handle<Map> receiver_map,
826 bool smi_and_map_check);
827
828
829 HBasicBlock* BuildTypeSwitch(ZoneMapList* maps,
830 ZoneList<HSubgraph*>* subgraphs,
831 HValue* receiver,
832 int join_id);
833
834 TypeFeedbackOracle* oracle_;
835 HGraph* graph_;
836 HSubgraph* current_subgraph_;
837 IterationStatement* peeled_statement_;
838 // Expression context of the currently visited subexpression. NULL when
839 // visiting statements.
840 AstContext* ast_context_;
841
842 // During function inlining, expression context of the call being
843 // inlined. NULL when not inlining.
844 AstContext* call_context_;
845
846 // When inlining a call in an effect or value context, the return
847 // block. NULL otherwise. When inlining a call in a test context, there
848 // are a pair of target blocks in the call context.
849 HBasicBlock* function_return_;
850
851 int inlined_count_;
852
853 friend class AstContext; // Pushes and pops the AST context stack.
854
855 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
856};
857
858
859class HValueMap: public ZoneObject {
860 public:
861 HValueMap()
862 : array_size_(0),
863 lists_size_(0),
864 count_(0),
865 present_flags_(0),
866 array_(NULL),
867 lists_(NULL),
868 free_list_head_(kNil) {
869 ResizeLists(kInitialSize);
870 Resize(kInitialSize);
871 }
872
873 void Kill(int flags);
874
875 void Add(HValue* value) {
876 present_flags_ |= value->flags();
877 Insert(value);
878 }
879
880 HValue* Lookup(HValue* value) const;
881 HValueMap* Copy() const { return new HValueMap(this); }
882
883 private:
884 // A linked list of HValue* values. Stored in arrays.
885 struct HValueMapListElement {
886 HValue* value;
887 int next; // Index in the array of the next list element.
888 };
889 static const int kNil = -1; // The end of a linked list
890
891 // Must be a power of 2.
892 static const int kInitialSize = 16;
893
894 explicit HValueMap(const HValueMap* other);
895
896 void Resize(int new_size);
897 void ResizeLists(int new_size);
898 void Insert(HValue* value);
899 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
900
901 int array_size_;
902 int lists_size_;
903 int count_; // The number of values stored in the HValueMap.
904 int present_flags_; // All flags that are in any value in the HValueMap.
905 HValueMapListElement* array_; // Primary store - contains the first value
906 // with a given hash. Colliding elements are stored in linked lists.
907 HValueMapListElement* lists_; // The linked lists containing hash collisions.
908 int free_list_head_; // Unused elements in lists_ are on the free list.
909};
910
911
912class HStatistics: public Malloced {
913 public:
914 void Print();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100915 void SaveTiming(const char* name, int64_t ticks, unsigned size);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100916 static HStatistics* Instance() {
917 static SetOncePointer<HStatistics> instance;
918 if (!instance.is_set()) {
919 instance.set(new HStatistics());
920 }
921 return instance.get();
922 }
923
924 private:
925
Ben Murdochb8e0da22011-05-16 14:20:40 +0100926 HStatistics()
927 : timing_(5),
928 names_(5),
929 sizes_(5),
930 total_(0),
931 total_size_(0),
932 full_code_gen_(0) { }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100933
934 List<int64_t> timing_;
935 List<const char*> names_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100936 List<unsigned> sizes_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100937 int64_t total_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100938 unsigned total_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100939 int64_t full_code_gen_;
940};
941
942
943class HPhase BASE_EMBEDDED {
944 public:
945 static const char* const kFullCodeGen;
946 static const char* const kTotal;
947
948 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
949 HPhase(const char* name, HGraph* graph) {
950 Begin(name, graph, NULL, NULL);
951 }
952 HPhase(const char* name, LChunk* chunk) {
953 Begin(name, NULL, chunk, NULL);
954 }
955 HPhase(const char* name, LAllocator* allocator) {
956 Begin(name, NULL, NULL, allocator);
957 }
958
959 ~HPhase() {
960 End();
961 }
962
963 private:
964 void Begin(const char* name,
965 HGraph* graph,
966 LChunk* chunk,
967 LAllocator* allocator);
968 void End() const;
969
970 int64_t start_;
971 const char* name_;
972 HGraph* graph_;
973 LChunk* chunk_;
974 LAllocator* allocator_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100975 unsigned start_allocation_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100976};
977
978
979class HTracer: public Malloced {
980 public:
981 void TraceCompilation(FunctionLiteral* function);
982 void TraceHydrogen(const char* name, HGraph* graph);
983 void TraceLithium(const char* name, LChunk* chunk);
984 void TraceLiveRanges(const char* name, LAllocator* allocator);
985
986 static HTracer* Instance() {
987 static SetOncePointer<HTracer> instance;
988 if (!instance.is_set()) {
989 instance.set(new HTracer("hydrogen.cfg"));
990 }
991 return instance.get();
992 }
993
994 private:
995 class Tag BASE_EMBEDDED {
996 public:
997 Tag(HTracer* tracer, const char* name) {
998 name_ = name;
999 tracer_ = tracer;
1000 tracer->PrintIndent();
1001 tracer->trace_.Add("begin_%s\n", name);
1002 tracer->indent_++;
1003 }
1004
1005 ~Tag() {
1006 tracer_->indent_--;
1007 tracer_->PrintIndent();
1008 tracer_->trace_.Add("end_%s\n", name_);
1009 ASSERT(tracer_->indent_ >= 0);
1010 tracer_->FlushToFile();
1011 }
1012
1013 private:
1014 HTracer* tracer_;
1015 const char* name_;
1016 };
1017
1018 explicit HTracer(const char* filename)
1019 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1020 WriteChars(filename, "", 0, false);
1021 }
1022
1023 void TraceLiveRange(LiveRange* range, const char* type);
1024 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1025 void FlushToFile();
1026
1027 void PrintEmptyProperty(const char* name) {
1028 PrintIndent();
1029 trace_.Add("%s\n", name);
1030 }
1031
1032 void PrintStringProperty(const char* name, const char* value) {
1033 PrintIndent();
1034 trace_.Add("%s \"%s\"\n", name, value);
1035 }
1036
1037 void PrintLongProperty(const char* name, int64_t value) {
1038 PrintIndent();
1039 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1040 }
1041
1042 void PrintBlockProperty(const char* name, int block_id) {
1043 PrintIndent();
1044 trace_.Add("%s \"B%d\"\n", name, block_id);
1045 }
1046
1047 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1048 PrintIndent();
1049 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1050 }
1051
1052 void PrintIntProperty(const char* name, int value) {
1053 PrintIndent();
1054 trace_.Add("%s %d\n", name, value);
1055 }
1056
1057 void PrintIndent() {
1058 for (int i = 0; i < indent_; i++) {
1059 trace_.Add(" ");
1060 }
1061 }
1062
1063 const char* filename_;
1064 HeapStringAllocator string_allocator_;
1065 StringStream trace_;
1066 int indent_;
1067};
1068
1069
1070} } // namespace v8::internal
1071
1072#endif // V8_HYDROGEN_H_