blob: 0178f3f85b2e74dc79860cbca93b3c0a6547bfd5 [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000139 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_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000171 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_; }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000299
kmillikin@chromium.orgc0cfb562011-01-26 10:44:48 +0000300 bool AllowCodeMotion() const;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000301
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000302 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();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000310 void ComputeMinusZeroChecks();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000311 bool ProcessArgumentsObject();
312 void EliminateRedundantPhis();
313 void Canonicalize();
314 void OrderBlocks();
315 void AssignDominators();
316
317 // Returns false if there are phi-uses of the arguments-object
318 // which are not supported by the optimizing compiler.
319 bool CollectPhis();
320
321 Handle<Code> Compile();
322
323 void set_undefined_constant(HConstant* constant) {
324 undefined_constant_.set(constant);
325 }
326 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
327 HConstant* GetConstant1();
328 HConstant* GetConstantMinus1();
329 HConstant* GetConstantTrue();
330 HConstant* GetConstantFalse();
331
332 HBasicBlock* CreateBasicBlock();
333 HArgumentsObject* GetArgumentsObject() const {
334 return arguments_object_.get();
335 }
336 bool HasArgumentsObject() const { return arguments_object_.is_set(); }
337
338 void SetArgumentsObject(HArgumentsObject* object) {
339 arguments_object_.set(object);
340 }
341
342 // True iff. we are compiling for OSR and the statement is the entry.
343 bool HasOsrEntryAt(IterationStatement* statement);
344
345 int GetMaximumValueID() const { return values_.length(); }
346 int GetNextBlockID() { return next_block_id_++; }
347 int GetNextValueID(HValue* value) {
348 values_.Add(value);
349 return values_.length() - 1;
350 }
351 HValue* LookupValue(int id) const {
352 if (id >= 0 && id < values_.length()) return values_[id];
353 return NULL;
354 }
355
356#ifdef DEBUG
357 void Verify() const;
358#endif
359
360 private:
361 void Postorder(HBasicBlock* block,
362 BitVector* visited,
363 ZoneList<HBasicBlock*>* order,
364 HBasicBlock* loop_header);
365 void PostorderLoopBlocks(HLoopInformation* loop,
366 BitVector* visited,
367 ZoneList<HBasicBlock*>* order,
368 HBasicBlock* loop_header);
369 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
370 Object* value);
371
372 void InsertTypeConversions(HInstruction* instr);
373 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
374 void InsertRepresentationChangeForUse(HValue* value,
375 HValue* use,
376 Representation to,
377 bool truncating);
378 void InsertRepresentationChanges(HValue* current);
379 void InferTypes(ZoneList<HValue*>* worklist);
380 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
381 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
382
383 int next_block_id_;
384 CompilationInfo* info_;
385 HEnvironment* start_environment_;
386 ZoneList<HBasicBlock*> blocks_;
387 ZoneList<HValue*> values_;
388 ZoneList<HPhi*>* phi_list_;
389 SetOncePointer<HConstant> undefined_constant_;
390 SetOncePointer<HConstant> constant_1_;
391 SetOncePointer<HConstant> constant_minus1_;
392 SetOncePointer<HConstant> constant_true_;
393 SetOncePointer<HConstant> constant_false_;
394 SetOncePointer<HArgumentsObject> arguments_object_;
395
396 friend class HSubgraph;
397
398 DISALLOW_COPY_AND_ASSIGN(HGraph);
399};
400
401
402class HEnvironment: public ZoneObject {
403 public:
404 HEnvironment(HEnvironment* outer,
405 Scope* scope,
406 Handle<JSFunction> closure);
407
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000408 // Simple accessors.
409 Handle<JSFunction> closure() const { return closure_; }
410 const ZoneList<HValue*>* values() const { return &values_; }
411 const ZoneList<int>* assigned_variables() const {
412 return &assigned_variables_;
413 }
414 int parameter_count() const { return parameter_count_; }
415 int local_count() const { return local_count_; }
416 HEnvironment* outer() const { return outer_; }
417 int pop_count() const { return pop_count_; }
418 int push_count() const { return push_count_; }
419
420 int ast_id() const { return ast_id_; }
421 void set_ast_id(int id) { ast_id_ = id; }
422
423 int length() const { return values_.length(); }
424
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000425 void Bind(Variable* variable, HValue* value) {
426 Bind(IndexFor(variable), value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000427 }
428
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000429 void Bind(int index, HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000430
431 HValue* Lookup(Variable* variable) const {
432 return Lookup(IndexFor(variable));
433 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000434
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000435 HValue* Lookup(int index) const {
436 HValue* result = values_[index];
437 ASSERT(result != NULL);
438 return result;
439 }
440
441 void Push(HValue* value) {
442 ASSERT(value != NULL);
443 ++push_count_;
444 values_.Add(value);
445 }
446
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000447 HValue* Pop() {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000448 ASSERT(!ExpressionStackIsEmpty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000449 if (push_count_ > 0) {
450 --push_count_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451 } else {
452 ++pop_count_;
453 }
454 return values_.RemoveLast();
455 }
456
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000457 void Drop(int count);
458
459 HValue* Top() const { return ExpressionStackAt(0); }
460
461 HValue* ExpressionStackAt(int index_from_top) const {
462 int index = length() - index_from_top - 1;
463 ASSERT(HasExpressionAt(index));
464 return values_[index];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000465 }
466
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000467 void SetExpressionStackAt(int index_from_top, HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000468
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000469 HEnvironment* Copy() const;
470 HEnvironment* CopyWithoutHistory() const;
471 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
472
473 // Create an "inlined version" of this environment, where the original
474 // environment is the outer environment but the top expression stack
475 // elements are moved to an inner environment as parameters. If
476 // is_speculative, the argument values are expected to be PushArgument
477 // instructions, otherwise they are the actual values.
478 HEnvironment* CopyForInlining(Handle<JSFunction> target,
479 FunctionLiteral* function,
480 bool is_speculative,
481 HConstant* undefined) const;
482
483 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000484
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000485 void ClearHistory() {
486 pop_count_ = 0;
487 push_count_ = 0;
488 assigned_variables_.Clear();
489 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000490
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000491 void SetValueAt(int index, HValue* value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000492 ASSERT(index < length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000493 values_[index] = value;
494 }
495
496 void PrintTo(StringStream* stream);
497 void PrintToStd();
498
499 private:
500 explicit HEnvironment(const HEnvironment* other);
501
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000502 // True if index is included in the expression stack part of the environment.
503 bool HasExpressionAt(int index) const;
504
505 bool ExpressionStackIsEmpty() const;
506
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000507 void Initialize(int parameter_count, int local_count, int stack_height);
508 void Initialize(const HEnvironment* other);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000509
510 // Map a variable to an environment index. Parameter indices are shifted
511 // by 1 (receiver is parameter index -1 but environment index 0).
512 // Stack-allocated local indices are shifted by the number of parameters.
513 int IndexFor(Variable* variable) const {
514 Slot* slot = variable->AsSlot();
515 ASSERT(slot != NULL && slot->IsStackAllocated());
516 int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
517 return slot->index() + shift;
518 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000519
520 Handle<JSFunction> closure_;
521 // Value array [parameters] [locals] [temporaries].
522 ZoneList<HValue*> values_;
523 ZoneList<int> assigned_variables_;
524 int parameter_count_;
525 int local_count_;
526 HEnvironment* outer_;
527 int pop_count_;
528 int push_count_;
529 int ast_id_;
530};
531
532
533class HGraphBuilder;
534
535class AstContext {
536 public:
537 bool IsEffect() const { return kind_ == Expression::kEffect; }
538 bool IsValue() const { return kind_ == Expression::kValue; }
539 bool IsTest() const { return kind_ == Expression::kTest; }
540
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000541 // 'Fill' this context with a hydrogen value. The value is assumed to
542 // have already been inserted in the instruction stream (or not need to
543 // be, e.g., HPhi). Call this function in tail position in the Visit
544 // functions for expressions.
545 virtual void ReturnValue(HValue* value) = 0;
546
547 // Add a hydrogen instruction to the instruction stream (recording an
548 // environment simulation if necessary) and then fill this context with
549 // the instruction as value.
550 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
551
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000552 protected:
553 AstContext(HGraphBuilder* owner, Expression::Context kind);
554 virtual ~AstContext();
555
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000556 HGraphBuilder* owner() const { return owner_; }
557
558 // We want to be able to assert, in a context-specific way, that the stack
559 // height makes sense when the context is filled.
560#ifdef DEBUG
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000561 int original_length_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000562#endif
563
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000564 private:
565 HGraphBuilder* owner_;
566 Expression::Context kind_;
567 AstContext* outer_;
568};
569
570
571class EffectContext: public AstContext {
572 public:
573 explicit EffectContext(HGraphBuilder* owner)
574 : AstContext(owner, Expression::kEffect) {
575 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000576 virtual ~EffectContext();
577
578 virtual void ReturnValue(HValue* value);
579 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000580};
581
582
583class ValueContext: public AstContext {
584 public:
585 explicit ValueContext(HGraphBuilder* owner)
586 : AstContext(owner, Expression::kValue) {
587 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000588 virtual ~ValueContext();
589
590 virtual void ReturnValue(HValue* value);
591 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000592};
593
594
595class TestContext: public AstContext {
596 public:
597 TestContext(HGraphBuilder* owner,
598 HBasicBlock* if_true,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000599 HBasicBlock* if_false)
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000600 : AstContext(owner, Expression::kTest),
601 if_true_(if_true),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000602 if_false_(if_false) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000603 }
604
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000605 virtual void ReturnValue(HValue* value);
606 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
607
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000608 static TestContext* cast(AstContext* context) {
609 ASSERT(context->IsTest());
610 return reinterpret_cast<TestContext*>(context);
611 }
612
613 HBasicBlock* if_true() const { return if_true_; }
614 HBasicBlock* if_false() const { return if_false_; }
615
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000616 private:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000617 // Build the shared core part of the translation unpacking a value into
618 // control flow.
619 void BuildBranch(HValue* value);
620
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000621 HBasicBlock* if_true_;
622 HBasicBlock* if_false_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000623};
624
625
626class HGraphBuilder: public AstVisitor {
627 public:
628 explicit HGraphBuilder(TypeFeedbackOracle* oracle)
629 : oracle_(oracle),
630 graph_(NULL),
631 current_subgraph_(NULL),
632 peeled_statement_(NULL),
633 ast_context_(NULL),
634 call_context_(NULL),
635 function_return_(NULL),
636 inlined_count_(0) { }
637
638 HGraph* CreateGraph(CompilationInfo* info);
639
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000640 // Simple accessors.
641 HGraph* graph() const { return graph_; }
642 HSubgraph* subgraph() const { return current_subgraph_; }
643
644 HEnvironment* environment() const { return subgraph()->environment(); }
645 HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
646
647 // Adding instructions.
648 HInstruction* AddInstruction(HInstruction* instr);
649 void AddSimulate(int id);
650
651 // Bailout environment manipulation.
652 void Push(HValue* value) { environment()->Push(value); }
653 HValue* Pop() { return environment()->Pop(); }
654
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000655 private:
656 // Type of a member function that generates inline code for a native function.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000657 typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count,
658 int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000659
660 // Forward declarations for inner scope classes.
661 class SubgraphScope;
662
663 static const InlineFunctionGenerator kInlineFunctionGenerators[];
664
665 static const int kMaxCallPolymorphism = 4;
666 static const int kMaxLoadPolymorphism = 4;
667 static const int kMaxStorePolymorphism = 4;
668
669 static const int kMaxInlinedNodes = 196;
670 static const int kMaxInlinedSize = 196;
671 static const int kMaxSourceSize = 600;
672
673 // Simple accessors.
674 TypeFeedbackOracle* oracle() const { return oracle_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000675 AstContext* ast_context() const { return ast_context_; }
676 void set_ast_context(AstContext* context) { ast_context_ = context; }
677 AstContext* call_context() const { return call_context_; }
678 HBasicBlock* function_return() const { return function_return_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000679
680 // Generators for inline runtime functions.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000681#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
682 void Generate##Name(int argument_count, int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000683
684 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
685 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
686#undef INLINE_FUNCTION_GENERATOR_DECLARATION
687
688 void Bailout(const char* reason);
689
690 void AppendPeeledWhile(IterationStatement* stmt,
691 HSubgraph* cond_graph,
692 HSubgraph* body_graph,
693 HSubgraph* exit_graph);
694
695 void AddToSubgraph(HSubgraph* graph, ZoneList<Statement*>* stmts);
696 void AddToSubgraph(HSubgraph* graph, Statement* stmt);
697 void AddToSubgraph(HSubgraph* graph, Expression* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000698
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000699 HValue* Top() const { return environment()->Top(); }
700 void Drop(int n) { environment()->Drop(n); }
701 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
702
703 void VisitForValue(Expression* expr);
704 void VisitForEffect(Expression* expr);
705 void VisitForControl(Expression* expr,
706 HBasicBlock* true_block,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000707 HBasicBlock* false_block);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000708
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000709 // Visit an argument and wrap it in a PushArgument instruction.
710 HValue* VisitArgument(Expression* expr);
711 void VisitArgumentList(ZoneList<Expression*>* arguments);
712
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000713 void AddPhi(HPhi* phi);
714
715 void PushAndAdd(HInstruction* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000716
717 void PushArgumentsForStubCall(int argument_count);
718
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000719 // Remove the arguments from the bailout environment and emit instructions
720 // to push them as outgoing parameters.
721 void ProcessCall(HCall* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000722
723 void AssumeRepresentation(HValue* value, Representation r);
724 static Representation ToRepresentation(TypeInfo info);
725
726 void SetupScope(Scope* scope);
727 virtual void VisitStatements(ZoneList<Statement*>* statements);
728
729#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
730 AST_NODE_LIST(DECLARE_VISIT)
731#undef DECLARE_VISIT
732
733 bool ShouldPeel(HSubgraph* cond, HSubgraph* body);
734
735 HBasicBlock* CreateBasicBlock(HEnvironment* env);
736 HSubgraph* CreateEmptySubgraph();
737 HSubgraph* CreateGotoSubgraph(HEnvironment* env);
738 HSubgraph* CreateBranchSubgraph(HEnvironment* env);
739 HSubgraph* CreateLoopHeaderSubgraph(HEnvironment* env);
740 HSubgraph* CreateInlinedSubgraph(HEnvironment* outer,
741 Handle<JSFunction> target,
742 FunctionLiteral* function);
743
744 // Helpers for flow graph construction.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000745 void LookupGlobalPropertyCell(Variable* var,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000746 LookupResult* lookup,
747 bool is_store);
748
749 bool TryArgumentsAccess(Property* expr);
750 bool TryCallApply(Call* expr);
751 bool TryInline(Call* expr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000752 bool TryInlineBuiltinFunction(Call* expr,
753 HValue* receiver,
754 Handle<Map> receiver_map,
755 CheckType check_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000756 void TraceInline(Handle<JSFunction> target, bool result);
757
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000758 void HandleGlobalVariableAssignment(Variable* var,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000759 HValue* value,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000760 int position,
761 int ast_id);
762
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000763 void HandlePropertyAssignment(Assignment* expr);
764 void HandleCompoundAssignment(Assignment* expr);
765 void HandlePolymorphicLoadNamedField(Property* expr,
766 HValue* object,
767 ZoneMapList* types,
768 Handle<String> name);
769 void HandlePolymorphicStoreNamedField(Assignment* expr,
770 HValue* object,
771 HValue* value,
772 ZoneMapList* types,
773 Handle<String> name);
774 void HandlePolymorphicCallNamed(Call* expr,
775 HValue* receiver,
776 ZoneMapList* types,
777 Handle<String> name);
778
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000779 HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
780 HValue* index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000781 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
782 HValue* left,
783 HValue* right);
784 HInstruction* BuildIncrement(HValue* value, bool increment);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000785 HLoadNamedField* BuildLoadNamedField(HValue* object,
786 Property* expr,
787 Handle<Map> type,
788 LookupResult* result,
789 bool smi_and_map_check);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000790 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
791 HInstruction* BuildLoadKeyedFastElement(HValue* object,
792 HValue* key,
793 Property* expr);
794 HInstruction* BuildLoadKeyedGeneric(HValue* object,
795 HValue* key);
796
797 HInstruction* BuildLoadNamed(HValue* object,
798 Property* prop,
799 Handle<Map> map,
800 Handle<String> name);
801 HInstruction* BuildStoreNamed(HValue* object,
802 HValue* value,
803 Expression* expr);
804 HInstruction* BuildStoreNamedField(HValue* object,
805 Handle<String> name,
806 HValue* value,
807 Handle<Map> type,
808 LookupResult* lookup,
809 bool smi_and_map_check);
810 HInstruction* BuildStoreNamedGeneric(HValue* object,
811 Handle<String> name,
812 HValue* value);
813 HInstruction* BuildStoreKeyedGeneric(HValue* object,
814 HValue* key,
815 HValue* value);
816
817 HInstruction* BuildStoreKeyedFastElement(HValue* object,
818 HValue* key,
819 HValue* val,
820 Expression* expr);
821
822 HCompare* BuildSwitchCompare(HSubgraph* subgraph,
823 HValue* switch_value,
824 CaseClause* clause);
825
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000826 HValue* BuildContextChainWalk(Variable* var);
827
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000828 void AddCheckConstantFunction(Call* expr,
829 HValue* receiver,
830 Handle<Map> receiver_map,
831 bool smi_and_map_check);
832
833
834 HBasicBlock* BuildTypeSwitch(ZoneMapList* maps,
835 ZoneList<HSubgraph*>* subgraphs,
836 HValue* receiver,
837 int join_id);
838
839 TypeFeedbackOracle* oracle_;
840 HGraph* graph_;
841 HSubgraph* current_subgraph_;
842 IterationStatement* peeled_statement_;
843 // Expression context of the currently visited subexpression. NULL when
844 // visiting statements.
845 AstContext* ast_context_;
846
847 // During function inlining, expression context of the call being
848 // inlined. NULL when not inlining.
849 AstContext* call_context_;
850
851 // When inlining a call in an effect or value context, the return
852 // block. NULL otherwise. When inlining a call in a test context, there
853 // are a pair of target blocks in the call context.
854 HBasicBlock* function_return_;
855
856 int inlined_count_;
857
858 friend class AstContext; // Pushes and pops the AST context stack.
859
860 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
861};
862
863
864class HValueMap: public ZoneObject {
865 public:
866 HValueMap()
867 : array_size_(0),
868 lists_size_(0),
869 count_(0),
870 present_flags_(0),
871 array_(NULL),
872 lists_(NULL),
873 free_list_head_(kNil) {
874 ResizeLists(kInitialSize);
875 Resize(kInitialSize);
876 }
877
878 void Kill(int flags);
879
880 void Add(HValue* value) {
881 present_flags_ |= value->flags();
882 Insert(value);
883 }
884
885 HValue* Lookup(HValue* value) const;
886 HValueMap* Copy() const { return new HValueMap(this); }
887
888 private:
889 // A linked list of HValue* values. Stored in arrays.
890 struct HValueMapListElement {
891 HValue* value;
892 int next; // Index in the array of the next list element.
893 };
894 static const int kNil = -1; // The end of a linked list
895
896 // Must be a power of 2.
897 static const int kInitialSize = 16;
898
899 explicit HValueMap(const HValueMap* other);
900
901 void Resize(int new_size);
902 void ResizeLists(int new_size);
903 void Insert(HValue* value);
904 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
905
906 int array_size_;
907 int lists_size_;
908 int count_; // The number of values stored in the HValueMap.
909 int present_flags_; // All flags that are in any value in the HValueMap.
910 HValueMapListElement* array_; // Primary store - contains the first value
911 // with a given hash. Colliding elements are stored in linked lists.
912 HValueMapListElement* lists_; // The linked lists containing hash collisions.
913 int free_list_head_; // Unused elements in lists_ are on the free list.
914};
915
916
917class HStatistics: public Malloced {
918 public:
919 void Print();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000920 void SaveTiming(const char* name, int64_t ticks, unsigned size);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000921 static HStatistics* Instance() {
922 static SetOncePointer<HStatistics> instance;
923 if (!instance.is_set()) {
924 instance.set(new HStatistics());
925 }
926 return instance.get();
927 }
928
929 private:
930
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000931 HStatistics()
932 : timing_(5),
933 names_(5),
934 sizes_(5),
935 total_(0),
936 total_size_(0),
937 full_code_gen_(0) { }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000938
939 List<int64_t> timing_;
940 List<const char*> names_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000941 List<unsigned> sizes_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000942 int64_t total_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000943 unsigned total_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000944 int64_t full_code_gen_;
945};
946
947
948class HPhase BASE_EMBEDDED {
949 public:
950 static const char* const kFullCodeGen;
951 static const char* const kTotal;
952
953 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
954 HPhase(const char* name, HGraph* graph) {
955 Begin(name, graph, NULL, NULL);
956 }
957 HPhase(const char* name, LChunk* chunk) {
958 Begin(name, NULL, chunk, NULL);
959 }
960 HPhase(const char* name, LAllocator* allocator) {
961 Begin(name, NULL, NULL, allocator);
962 }
963
964 ~HPhase() {
965 End();
966 }
967
968 private:
969 void Begin(const char* name,
970 HGraph* graph,
971 LChunk* chunk,
972 LAllocator* allocator);
973 void End() const;
974
975 int64_t start_;
976 const char* name_;
977 HGraph* graph_;
978 LChunk* chunk_;
979 LAllocator* allocator_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000980 unsigned start_allocation_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000981};
982
983
984class HTracer: public Malloced {
985 public:
986 void TraceCompilation(FunctionLiteral* function);
987 void TraceHydrogen(const char* name, HGraph* graph);
988 void TraceLithium(const char* name, LChunk* chunk);
989 void TraceLiveRanges(const char* name, LAllocator* allocator);
990
991 static HTracer* Instance() {
992 static SetOncePointer<HTracer> instance;
993 if (!instance.is_set()) {
994 instance.set(new HTracer("hydrogen.cfg"));
995 }
996 return instance.get();
997 }
998
999 private:
1000 class Tag BASE_EMBEDDED {
1001 public:
1002 Tag(HTracer* tracer, const char* name) {
1003 name_ = name;
1004 tracer_ = tracer;
1005 tracer->PrintIndent();
1006 tracer->trace_.Add("begin_%s\n", name);
1007 tracer->indent_++;
1008 }
1009
1010 ~Tag() {
1011 tracer_->indent_--;
1012 tracer_->PrintIndent();
1013 tracer_->trace_.Add("end_%s\n", name_);
1014 ASSERT(tracer_->indent_ >= 0);
1015 tracer_->FlushToFile();
1016 }
1017
1018 private:
1019 HTracer* tracer_;
1020 const char* name_;
1021 };
1022
1023 explicit HTracer(const char* filename)
1024 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1025 WriteChars(filename, "", 0, false);
1026 }
1027
1028 void TraceLiveRange(LiveRange* range, const char* type);
1029 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1030 void FlushToFile();
1031
1032 void PrintEmptyProperty(const char* name) {
1033 PrintIndent();
1034 trace_.Add("%s\n", name);
1035 }
1036
1037 void PrintStringProperty(const char* name, const char* value) {
1038 PrintIndent();
1039 trace_.Add("%s \"%s\"\n", name, value);
1040 }
1041
1042 void PrintLongProperty(const char* name, int64_t value) {
1043 PrintIndent();
1044 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1045 }
1046
1047 void PrintBlockProperty(const char* name, int block_id) {
1048 PrintIndent();
1049 trace_.Add("%s \"B%d\"\n", name, block_id);
1050 }
1051
1052 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1053 PrintIndent();
1054 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1055 }
1056
1057 void PrintIntProperty(const char* name, int value) {
1058 PrintIndent();
1059 trace_.Add("%s %d\n", name, value);
1060 }
1061
1062 void PrintIndent() {
1063 for (int i = 0; i < indent_; i++) {
1064 trace_.Add(" ");
1065 }
1066 }
1067
1068 const char* filename_;
1069 HeapStringAllocator string_allocator_;
1070 StringStream trace_;
1071 int indent_;
1072};
1073
1074
1075} } // namespace v8::internal
1076
1077#endif // V8_HYDROGEN_H_