blob: d8b1cfb6e3346be06da013551c0ee038a1f2be84 [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_; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +010063 HInstruction* last() const { return last_; }
64 void set_last(HInstruction* instr) { last_ = instr; }
Ben Murdochb0fe1622011-05-05 13:52:32 +010065 HInstruction* GetLastInstruction();
66 HControlInstruction* end() const { return end_; }
67 HLoopInformation* loop_information() const { return loop_information_; }
68 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
69 bool HasPredecessor() const { return predecessors_.length() > 0; }
70 const ZoneList<HBasicBlock*>* dominated_blocks() const {
71 return &dominated_blocks_;
72 }
73 const ZoneList<int>* deleted_phis() const {
74 return &deleted_phis_;
75 }
76 void RecordDeletedPhi(int merge_index) {
77 deleted_phis_.Add(merge_index);
78 }
79 HBasicBlock* dominator() const { return dominator_; }
80 HEnvironment* last_environment() const { return last_environment_; }
81 int argument_count() const { return argument_count_; }
82 void set_argument_count(int count) { argument_count_ = count; }
83 int first_instruction_index() const { return first_instruction_index_; }
84 void set_first_instruction_index(int index) {
85 first_instruction_index_ = index;
86 }
87 int last_instruction_index() const { return last_instruction_index_; }
88 void set_last_instruction_index(int index) {
89 last_instruction_index_ = index;
90 }
91
92 void AttachLoopInformation();
93 void DetachLoopInformation();
94 bool IsLoopHeader() const { return loop_information() != NULL; }
95 bool IsStartBlock() const { return block_id() == 0; }
96 void PostProcessLoopHeader(IterationStatement* stmt);
97
98 bool IsFinished() const { return end_ != NULL; }
99 void AddPhi(HPhi* phi);
100 void RemovePhi(HPhi* phi);
101 void AddInstruction(HInstruction* instr);
102 bool Dominates(HBasicBlock* other) const;
103
104 void SetInitialEnvironment(HEnvironment* env);
105 void ClearEnvironment() { last_environment_ = NULL; }
106 bool HasEnvironment() const { return last_environment_ != NULL; }
107 void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; }
Steve Block1e0659c2011-05-24 12:43:12 +0100108 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100109
110 void set_parent_loop_header(HBasicBlock* block) {
Steve Block1e0659c2011-05-24 12:43:12 +0100111 ASSERT(parent_loop_header_ == NULL);
112 parent_loop_header_ = block;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100113 }
114
Steve Block1e0659c2011-05-24 12:43:12 +0100115 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100116
117 void SetJoinId(int id);
118
119 void Finish(HControlInstruction* last);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100120 void FinishExit(HControlInstruction* instruction);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100121 void Goto(HBasicBlock* block, bool include_stack_check = false);
122
123 int PredecessorIndexOf(HBasicBlock* predecessor) const;
124 void AddSimulate(int id) { AddInstruction(CreateSimulate(id)); }
125 void AssignCommonDominator(HBasicBlock* other);
126
127 // Add the inlined function exit sequence, adding an HLeaveInlined
128 // instruction and updating the bailout environment.
129 void AddLeaveInlined(HValue* return_value, HBasicBlock* target);
130
131 // If a target block is tagged as an inline function return, all
132 // predecessors should contain the inlined exit sequence:
133 //
134 // LeaveInlined
135 // Simulate (caller's environment)
136 // Goto (target block)
137 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
138 void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
139
Ben Murdochb0fe1622011-05-05 13:52:32 +0100140#ifdef DEBUG
141 void Verify();
142#endif
143
144 private:
145 void RegisterPredecessor(HBasicBlock* pred);
146 void AddDominatedBlock(HBasicBlock* block);
147
148 HSimulate* CreateSimulate(int id);
149
150 int block_id_;
151 HGraph* graph_;
152 ZoneList<HPhi*> phis_;
153 HInstruction* first_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100154 HInstruction* last_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100155 HControlInstruction* end_;
156 HLoopInformation* loop_information_;
157 ZoneList<HBasicBlock*> predecessors_;
158 HBasicBlock* dominator_;
159 ZoneList<HBasicBlock*> dominated_blocks_;
160 HEnvironment* last_environment_;
161 // Outgoing parameter count at block exit, set during lithium translation.
162 int argument_count_;
163 // Instruction indices into the lithium code stream.
164 int first_instruction_index_;
165 int last_instruction_index_;
166 ZoneList<int> deleted_phis_;
Steve Block1e0659c2011-05-24 12:43:12 +0100167 HBasicBlock* parent_loop_header_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100168 bool is_inline_return_target_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100169};
170
171
172class HLoopInformation: public ZoneObject {
173 public:
174 explicit HLoopInformation(HBasicBlock* loop_header)
175 : back_edges_(4), loop_header_(loop_header), blocks_(8) {
176 blocks_.Add(loop_header);
177 }
178 virtual ~HLoopInformation() {}
179
180 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
181 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
182 HBasicBlock* loop_header() const { return loop_header_; }
183 HBasicBlock* GetLastBackEdge() const;
184 void RegisterBackEdge(HBasicBlock* block);
185
186 private:
187 void AddBlock(HBasicBlock* block);
188
189 ZoneList<HBasicBlock*> back_edges_;
190 HBasicBlock* loop_header_;
191 ZoneList<HBasicBlock*> blocks_;
192};
193
194
195class HSubgraph: public ZoneObject {
196 public:
197 explicit HSubgraph(HGraph* graph)
198 : graph_(graph),
199 entry_block_(NULL),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100200 exit_block_(NULL) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100201 }
202
203 HGraph* graph() const { return graph_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100204 HBasicBlock* entry_block() const { return entry_block_; }
205 HBasicBlock* exit_block() const { return exit_block_; }
206 void set_exit_block(HBasicBlock* block) {
207 exit_block_ = block;
208 }
209
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100210 void Initialize(HBasicBlock* block) {
211 ASSERT(entry_block_ == NULL);
212 entry_block_ = block;
213 exit_block_ = block;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100214 }
215
216 protected:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100217 HGraph* graph_; // The graph this is a subgraph of.
218 HBasicBlock* entry_block_;
219 HBasicBlock* exit_block_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100220};
221
222
223class HGraph: public HSubgraph {
224 public:
225 explicit HGraph(CompilationInfo* info);
226
Ben Murdochb0fe1622011-05-05 13:52:32 +0100227 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
228 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100229 HEnvironment* start_environment() const { return start_environment_; }
230
231 void InitializeInferredTypes();
232 void InsertTypeConversions();
233 void InsertRepresentationChanges();
Steve Block1e0659c2011-05-24 12:43:12 +0100234 void ComputeMinusZeroChecks();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100235 bool ProcessArgumentsObject();
236 void EliminateRedundantPhis();
237 void Canonicalize();
238 void OrderBlocks();
239 void AssignDominators();
240
241 // Returns false if there are phi-uses of the arguments-object
242 // which are not supported by the optimizing compiler.
243 bool CollectPhis();
244
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100245 Handle<Code> Compile(CompilationInfo* info);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100246
247 void set_undefined_constant(HConstant* constant) {
248 undefined_constant_.set(constant);
249 }
250 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
251 HConstant* GetConstant1();
252 HConstant* GetConstantMinus1();
253 HConstant* GetConstantTrue();
254 HConstant* GetConstantFalse();
255
256 HBasicBlock* CreateBasicBlock();
257 HArgumentsObject* GetArgumentsObject() const {
258 return arguments_object_.get();
259 }
260 bool HasArgumentsObject() const { return arguments_object_.is_set(); }
261
262 void SetArgumentsObject(HArgumentsObject* object) {
263 arguments_object_.set(object);
264 }
265
Ben Murdochb0fe1622011-05-05 13:52:32 +0100266 int GetMaximumValueID() const { return values_.length(); }
267 int GetNextBlockID() { return next_block_id_++; }
268 int GetNextValueID(HValue* value) {
269 values_.Add(value);
270 return values_.length() - 1;
271 }
272 HValue* LookupValue(int id) const {
273 if (id >= 0 && id < values_.length()) return values_[id];
274 return NULL;
275 }
276
277#ifdef DEBUG
278 void Verify() const;
279#endif
280
281 private:
282 void Postorder(HBasicBlock* block,
283 BitVector* visited,
284 ZoneList<HBasicBlock*>* order,
285 HBasicBlock* loop_header);
286 void PostorderLoopBlocks(HLoopInformation* loop,
287 BitVector* visited,
288 ZoneList<HBasicBlock*>* order,
289 HBasicBlock* loop_header);
290 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
291 Object* value);
292
293 void InsertTypeConversions(HInstruction* instr);
294 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
295 void InsertRepresentationChangeForUse(HValue* value,
296 HValue* use,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100297 Representation to);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100298 void InsertRepresentationChanges(HValue* current);
299 void InferTypes(ZoneList<HValue*>* worklist);
300 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
301 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
302
303 int next_block_id_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100304 HEnvironment* start_environment_;
305 ZoneList<HBasicBlock*> blocks_;
306 ZoneList<HValue*> values_;
307 ZoneList<HPhi*>* phi_list_;
308 SetOncePointer<HConstant> undefined_constant_;
309 SetOncePointer<HConstant> constant_1_;
310 SetOncePointer<HConstant> constant_minus1_;
311 SetOncePointer<HConstant> constant_true_;
312 SetOncePointer<HConstant> constant_false_;
313 SetOncePointer<HArgumentsObject> arguments_object_;
314
315 friend class HSubgraph;
316
317 DISALLOW_COPY_AND_ASSIGN(HGraph);
318};
319
320
321class HEnvironment: public ZoneObject {
322 public:
323 HEnvironment(HEnvironment* outer,
324 Scope* scope,
325 Handle<JSFunction> closure);
326
Steve Block9fac8402011-05-12 15:51:54 +0100327 // Simple accessors.
328 Handle<JSFunction> closure() const { return closure_; }
329 const ZoneList<HValue*>* values() const { return &values_; }
330 const ZoneList<int>* assigned_variables() const {
331 return &assigned_variables_;
332 }
333 int parameter_count() const { return parameter_count_; }
334 int local_count() const { return local_count_; }
335 HEnvironment* outer() const { return outer_; }
336 int pop_count() const { return pop_count_; }
337 int push_count() const { return push_count_; }
338
339 int ast_id() const { return ast_id_; }
340 void set_ast_id(int id) { ast_id_ = id; }
341
342 int length() const { return values_.length(); }
343
Ben Murdochb0fe1622011-05-05 13:52:32 +0100344 void Bind(Variable* variable, HValue* value) {
345 Bind(IndexFor(variable), value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100346 }
347
Steve Block9fac8402011-05-12 15:51:54 +0100348 void Bind(int index, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100349
350 HValue* Lookup(Variable* variable) const {
351 return Lookup(IndexFor(variable));
352 }
Steve Block9fac8402011-05-12 15:51:54 +0100353
Ben Murdochb0fe1622011-05-05 13:52:32 +0100354 HValue* Lookup(int index) const {
355 HValue* result = values_[index];
356 ASSERT(result != NULL);
357 return result;
358 }
359
360 void Push(HValue* value) {
361 ASSERT(value != NULL);
362 ++push_count_;
363 values_.Add(value);
364 }
365
Ben Murdochb0fe1622011-05-05 13:52:32 +0100366 HValue* Pop() {
Steve Block9fac8402011-05-12 15:51:54 +0100367 ASSERT(!ExpressionStackIsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100368 if (push_count_ > 0) {
369 --push_count_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100370 } else {
371 ++pop_count_;
372 }
373 return values_.RemoveLast();
374 }
375
Steve Block9fac8402011-05-12 15:51:54 +0100376 void Drop(int count);
377
378 HValue* Top() const { return ExpressionStackAt(0); }
379
380 HValue* ExpressionStackAt(int index_from_top) const {
381 int index = length() - index_from_top - 1;
382 ASSERT(HasExpressionAt(index));
383 return values_[index];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100384 }
385
Steve Block9fac8402011-05-12 15:51:54 +0100386 void SetExpressionStackAt(int index_from_top, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100387
Ben Murdochb0fe1622011-05-05 13:52:32 +0100388 HEnvironment* Copy() const;
389 HEnvironment* CopyWithoutHistory() const;
390 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
391
392 // Create an "inlined version" of this environment, where the original
393 // environment is the outer environment but the top expression stack
394 // elements are moved to an inner environment as parameters. If
395 // is_speculative, the argument values are expected to be PushArgument
396 // instructions, otherwise they are the actual values.
397 HEnvironment* CopyForInlining(Handle<JSFunction> target,
398 FunctionLiteral* function,
399 bool is_speculative,
400 HConstant* undefined) const;
401
402 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100403
Ben Murdochb0fe1622011-05-05 13:52:32 +0100404 void ClearHistory() {
405 pop_count_ = 0;
406 push_count_ = 0;
407 assigned_variables_.Clear();
408 }
Steve Block9fac8402011-05-12 15:51:54 +0100409
Ben Murdochb0fe1622011-05-05 13:52:32 +0100410 void SetValueAt(int index, HValue* value) {
Steve Block9fac8402011-05-12 15:51:54 +0100411 ASSERT(index < length());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100412 values_[index] = value;
413 }
414
415 void PrintTo(StringStream* stream);
416 void PrintToStd();
417
418 private:
419 explicit HEnvironment(const HEnvironment* other);
420
Steve Block9fac8402011-05-12 15:51:54 +0100421 // True if index is included in the expression stack part of the environment.
422 bool HasExpressionAt(int index) const;
423
424 bool ExpressionStackIsEmpty() const;
425
Ben Murdochb0fe1622011-05-05 13:52:32 +0100426 void Initialize(int parameter_count, int local_count, int stack_height);
427 void Initialize(const HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100428
429 // Map a variable to an environment index. Parameter indices are shifted
430 // by 1 (receiver is parameter index -1 but environment index 0).
431 // Stack-allocated local indices are shifted by the number of parameters.
432 int IndexFor(Variable* variable) const {
433 Slot* slot = variable->AsSlot();
434 ASSERT(slot != NULL && slot->IsStackAllocated());
435 int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
436 return slot->index() + shift;
437 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100438
439 Handle<JSFunction> closure_;
440 // Value array [parameters] [locals] [temporaries].
441 ZoneList<HValue*> values_;
442 ZoneList<int> assigned_variables_;
443 int parameter_count_;
444 int local_count_;
445 HEnvironment* outer_;
446 int pop_count_;
447 int push_count_;
448 int ast_id_;
449};
450
451
452class HGraphBuilder;
453
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100454// This class is not BASE_EMBEDDED because our inlining implementation uses
455// new and delete.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100456class AstContext {
457 public:
458 bool IsEffect() const { return kind_ == Expression::kEffect; }
459 bool IsValue() const { return kind_ == Expression::kValue; }
460 bool IsTest() const { return kind_ == Expression::kTest; }
461
462 // 'Fill' this context with a hydrogen value. The value is assumed to
463 // have already been inserted in the instruction stream (or not need to
464 // be, e.g., HPhi). Call this function in tail position in the Visit
465 // functions for expressions.
466 virtual void ReturnValue(HValue* value) = 0;
467
468 // Add a hydrogen instruction to the instruction stream (recording an
469 // environment simulation if necessary) and then fill this context with
470 // the instruction as value.
471 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
472
473 protected:
474 AstContext(HGraphBuilder* owner, Expression::Context kind);
475 virtual ~AstContext();
476
477 HGraphBuilder* owner() const { return owner_; }
478
479 // We want to be able to assert, in a context-specific way, that the stack
480 // height makes sense when the context is filled.
481#ifdef DEBUG
Steve Block9fac8402011-05-12 15:51:54 +0100482 int original_length_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100483#endif
484
485 private:
486 HGraphBuilder* owner_;
487 Expression::Context kind_;
488 AstContext* outer_;
489};
490
491
492class EffectContext: public AstContext {
493 public:
494 explicit EffectContext(HGraphBuilder* owner)
495 : AstContext(owner, Expression::kEffect) {
496 }
497 virtual ~EffectContext();
498
499 virtual void ReturnValue(HValue* value);
500 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
501};
502
503
504class ValueContext: public AstContext {
505 public:
506 explicit ValueContext(HGraphBuilder* owner)
507 : AstContext(owner, Expression::kValue) {
508 }
509 virtual ~ValueContext();
510
511 virtual void ReturnValue(HValue* value);
512 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
513};
514
515
516class TestContext: public AstContext {
517 public:
518 TestContext(HGraphBuilder* owner,
519 HBasicBlock* if_true,
520 HBasicBlock* if_false)
521 : AstContext(owner, Expression::kTest),
522 if_true_(if_true),
523 if_false_(if_false) {
524 }
525
526 virtual void ReturnValue(HValue* value);
527 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
528
529 static TestContext* cast(AstContext* context) {
530 ASSERT(context->IsTest());
531 return reinterpret_cast<TestContext*>(context);
532 }
533
534 HBasicBlock* if_true() const { return if_true_; }
535 HBasicBlock* if_false() const { return if_false_; }
536
537 private:
538 // Build the shared core part of the translation unpacking a value into
539 // control flow.
540 void BuildBranch(HValue* value);
541
542 HBasicBlock* if_true_;
543 HBasicBlock* if_false_;
544};
545
546
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100547class FunctionState BASE_EMBEDDED {
548 public:
549 FunctionState(HGraphBuilder* owner,
550 CompilationInfo* info,
551 TypeFeedbackOracle* oracle);
552 ~FunctionState();
553
554 CompilationInfo* compilation_info() { return compilation_info_; }
555 TypeFeedbackOracle* oracle() { return oracle_; }
556 AstContext* call_context() { return call_context_; }
557 HBasicBlock* function_return() { return function_return_; }
558 TestContext* test_context() { return test_context_; }
559 void ClearInlinedTestContext() {
560 delete test_context_;
561 test_context_ = NULL;
562 }
563
564 private:
565 HGraphBuilder* owner_;
566
567 CompilationInfo* compilation_info_;
568 TypeFeedbackOracle* oracle_;
569
570 // During function inlining, expression context of the call being
571 // inlined. NULL when not inlining.
572 AstContext* call_context_;
573
574 // When inlining in an effect of value context, this is the return block.
575 // It is NULL otherwise. When inlining in a test context, there are a
576 // pair of return blocks in the context. When not inlining, there is no
577 // local return point.
578 HBasicBlock* function_return_;
579
580 // When inlining a call in a test context, a context containing a pair of
581 // return blocks. NULL in all other cases.
582 TestContext* test_context_;
583
584 FunctionState* outer_;
585};
586
587
Ben Murdochb0fe1622011-05-05 13:52:32 +0100588class HGraphBuilder: public AstVisitor {
589 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100590 enum BreakType { BREAK, CONTINUE };
591
592 // A class encapsulating (lazily-allocated) break and continue blocks for
593 // a breakable statement. Separated from BreakAndContinueScope so that it
594 // can have a separate lifetime.
595 class BreakAndContinueInfo BASE_EMBEDDED {
596 public:
597 explicit BreakAndContinueInfo(BreakableStatement* target)
598 : target_(target), break_block_(NULL), continue_block_(NULL) {
599 }
600
601 BreakableStatement* target() { return target_; }
602 HBasicBlock* break_block() { return break_block_; }
603 void set_break_block(HBasicBlock* block) { break_block_ = block; }
604 HBasicBlock* continue_block() { return continue_block_; }
605 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
606
607 private:
608 BreakableStatement* target_;
609 HBasicBlock* break_block_;
610 HBasicBlock* continue_block_;
611 };
612
613 // A helper class to maintain a stack of current BreakAndContinueInfo
614 // structures mirroring BreakableStatement nesting.
615 class BreakAndContinueScope BASE_EMBEDDED {
616 public:
617 BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
618 : info_(info), owner_(owner), next_(owner->break_scope()) {
619 owner->set_break_scope(this);
620 }
621
622 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
623
624 BreakAndContinueInfo* info() { return info_; }
625 HGraphBuilder* owner() { return owner_; }
626 BreakAndContinueScope* next() { return next_; }
627
628 // Search the break stack for a break or continue target.
629 HBasicBlock* Get(BreakableStatement* stmt, BreakType type);
630
631 private:
632 BreakAndContinueInfo* info_;
633 HGraphBuilder* owner_;
634 BreakAndContinueScope* next_;
635 };
636
637 HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle)
638 : function_state_(NULL),
639 initial_function_state_(this, info, oracle),
640 ast_context_(NULL),
641 break_scope_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100642 graph_(NULL),
643 current_subgraph_(NULL),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100644 inlined_count_(0) {
645 // This is not initialized in the initializer list because the
646 // constructor for the initial state relies on function_state_ == NULL
647 // to know it's the initial state.
648 function_state_= &initial_function_state_;
649 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100650
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100651 HGraph* CreateGraph();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100652
653 // Simple accessors.
654 HGraph* graph() const { return graph_; }
655 HSubgraph* subgraph() const { return current_subgraph_; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100656 BreakAndContinueScope* break_scope() const { return break_scope_; }
657 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100658
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100659 HBasicBlock* current_block() const { return subgraph()->exit_block(); }
660 void set_current_block(HBasicBlock* block) {
661 subgraph()->set_exit_block(block);
662 }
663 HEnvironment* environment() const {
664 return current_block()->last_environment();
665 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100666
667 // Adding instructions.
668 HInstruction* AddInstruction(HInstruction* instr);
669 void AddSimulate(int id);
670
671 // Bailout environment manipulation.
672 void Push(HValue* value) { environment()->Push(value); }
673 HValue* Pop() { return environment()->Pop(); }
674
675 private:
676 // Type of a member function that generates inline code for a native function.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100677 typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100678
679 // Forward declarations for inner scope classes.
680 class SubgraphScope;
681
682 static const InlineFunctionGenerator kInlineFunctionGenerators[];
683
684 static const int kMaxCallPolymorphism = 4;
685 static const int kMaxLoadPolymorphism = 4;
686 static const int kMaxStorePolymorphism = 4;
687
688 static const int kMaxInlinedNodes = 196;
689 static const int kMaxInlinedSize = 196;
690 static const int kMaxSourceSize = 600;
691
692 // Simple accessors.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100693 FunctionState* function_state() const { return function_state_; }
694 void set_function_state(FunctionState* state) { function_state_ = state; }
695
Ben Murdochb0fe1622011-05-05 13:52:32 +0100696 AstContext* ast_context() const { return ast_context_; }
697 void set_ast_context(AstContext* context) { ast_context_ = context; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100698
699 // Accessors forwarded to the function state.
700 CompilationInfo* info() const {
701 return function_state()->compilation_info();
702 }
703 TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
704
705 AstContext* call_context() const {
706 return function_state()->call_context();
707 }
708 HBasicBlock* function_return() const {
709 return function_state()->function_return();
710 }
711 TestContext* inlined_test_context() const {
712 return function_state()->test_context();
713 }
714 void ClearInlinedTestContext() {
715 function_state()->ClearInlinedTestContext();
716 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100717
718 // Generators for inline runtime functions.
719#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100720 void Generate##Name(CallRuntime* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100721
722 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
723 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
724#undef INLINE_FUNCTION_GENERATOR_DECLARATION
725
726 void Bailout(const char* reason);
727
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100728 void PreProcessOsrEntry(IterationStatement* statement);
729 // True iff. we are compiling for OSR and the statement is the entry.
730 bool HasOsrEntryAt(IterationStatement* statement);
731
732 HBasicBlock* CreateJoin(HBasicBlock* first,
733 HBasicBlock* second,
734 int join_id);
735
736 // Create a back edge in the flow graph. body_exit is the predecessor
737 // block and loop_entry is the successor block. loop_successor is the
738 // block where control flow exits the loop normally (e.g., via failure of
739 // the condition) and break_block is the block where control flow breaks
740 // from the loop. All blocks except loop_entry can be NULL. The return
741 // value is the new successor block which is the join of loop_successor
742 // and break_block, or NULL.
743 HBasicBlock* CreateLoop(IterationStatement* statement,
744 HBasicBlock* loop_entry,
745 HBasicBlock* body_exit,
746 HBasicBlock* loop_successor,
747 HBasicBlock* break_block);
748
749 HBasicBlock* JoinContinue(IterationStatement* statement,
750 HBasicBlock* exit_block,
751 HBasicBlock* continue_block);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100752
753 void AddToSubgraph(HSubgraph* graph, ZoneList<Statement*>* stmts);
754 void AddToSubgraph(HSubgraph* graph, Statement* stmt);
755 void AddToSubgraph(HSubgraph* graph, Expression* expr);
756
757 HValue* Top() const { return environment()->Top(); }
758 void Drop(int n) { environment()->Drop(n); }
759 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
760
761 void VisitForValue(Expression* expr);
762 void VisitForEffect(Expression* expr);
763 void VisitForControl(Expression* expr,
764 HBasicBlock* true_block,
765 HBasicBlock* false_block);
766
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100767 // Visit an argument subexpression and emit a push to the outgoing
768 // arguments.
Steve Block1e0659c2011-05-24 12:43:12 +0100769 void VisitArgument(Expression* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100770 void VisitArgumentList(ZoneList<Expression*>* arguments);
771
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100772 // Visit a list of expressions from left to right, each in a value context.
773 void VisitExpressions(ZoneList<Expression*>* exprs);
774
Ben Murdochb0fe1622011-05-05 13:52:32 +0100775 void AddPhi(HPhi* phi);
776
777 void PushAndAdd(HInstruction* instr);
778
Ben Murdochb0fe1622011-05-05 13:52:32 +0100779 // Remove the arguments from the bailout environment and emit instructions
780 // to push them as outgoing parameters.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100781 template <int V> HInstruction* PreProcessCall(HCall<V>* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100782
783 void AssumeRepresentation(HValue* value, Representation r);
784 static Representation ToRepresentation(TypeInfo info);
785
786 void SetupScope(Scope* scope);
787 virtual void VisitStatements(ZoneList<Statement*>* statements);
788
789#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
790 AST_NODE_LIST(DECLARE_VISIT)
791#undef DECLARE_VISIT
792
Ben Murdochb0fe1622011-05-05 13:52:32 +0100793 HBasicBlock* CreateBasicBlock(HEnvironment* env);
794 HSubgraph* CreateEmptySubgraph();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100795 HSubgraph* CreateBranchSubgraph(HEnvironment* env);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100796 HBasicBlock* CreateLoopHeaderBlock();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100797 HSubgraph* CreateInlinedSubgraph(HEnvironment* outer,
798 Handle<JSFunction> target,
799 FunctionLiteral* function);
800
801 // Helpers for flow graph construction.
802 void LookupGlobalPropertyCell(Variable* var,
803 LookupResult* lookup,
804 bool is_store);
805
806 bool TryArgumentsAccess(Property* expr);
807 bool TryCallApply(Call* expr);
808 bool TryInline(Call* expr);
Steve Block1e0659c2011-05-24 12:43:12 +0100809 bool TryInlineBuiltinFunction(Call* expr,
810 HValue* receiver,
811 Handle<Map> receiver_map,
812 CheckType check_type);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100813
814 // If --trace-inlining, print a line of the inlining trace. Inlining
815 // succeeded if the reason string is NULL and failed if there is a
816 // non-NULL reason string.
817 void TraceInline(Handle<JSFunction> target, const char* failure_reason);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100818
819 void HandleGlobalVariableAssignment(Variable* var,
820 HValue* value,
821 int position,
822 int ast_id);
823
824 void HandlePropertyAssignment(Assignment* expr);
825 void HandleCompoundAssignment(Assignment* expr);
826 void HandlePolymorphicLoadNamedField(Property* expr,
827 HValue* object,
828 ZoneMapList* types,
829 Handle<String> name);
830 void HandlePolymorphicStoreNamedField(Assignment* expr,
831 HValue* object,
832 HValue* value,
833 ZoneMapList* types,
834 Handle<String> name);
835 void HandlePolymorphicCallNamed(Call* expr,
836 HValue* receiver,
837 ZoneMapList* types,
838 Handle<String> name);
839
Steve Block1e0659c2011-05-24 12:43:12 +0100840 HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
841 HValue* index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100842 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
843 HValue* left,
844 HValue* right);
845 HInstruction* BuildIncrement(HValue* value, bool increment);
846 HLoadNamedField* BuildLoadNamedField(HValue* object,
847 Property* expr,
848 Handle<Map> type,
849 LookupResult* result,
850 bool smi_and_map_check);
851 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
852 HInstruction* BuildLoadKeyedFastElement(HValue* object,
853 HValue* key,
854 Property* expr);
Steve Block1e0659c2011-05-24 12:43:12 +0100855 HInstruction* BuildLoadKeyedPixelArrayElement(HValue* object,
856 HValue* key,
857 Property* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100858 HInstruction* BuildLoadKeyedGeneric(HValue* object,
859 HValue* key);
860
861 HInstruction* BuildLoadNamed(HValue* object,
862 Property* prop,
863 Handle<Map> map,
864 Handle<String> name);
865 HInstruction* BuildStoreNamed(HValue* object,
866 HValue* value,
867 Expression* expr);
868 HInstruction* BuildStoreNamedField(HValue* object,
869 Handle<String> name,
870 HValue* value,
871 Handle<Map> type,
872 LookupResult* lookup,
873 bool smi_and_map_check);
874 HInstruction* BuildStoreNamedGeneric(HValue* object,
875 Handle<String> name,
876 HValue* value);
877 HInstruction* BuildStoreKeyedGeneric(HValue* object,
878 HValue* key,
879 HValue* value);
880
881 HInstruction* BuildStoreKeyedFastElement(HValue* object,
882 HValue* key,
883 HValue* val,
884 Expression* expr);
885
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100886 HInstruction* BuildStoreKeyedPixelArrayElement(HValue* object,
887 HValue* key,
888 HValue* val,
889 Expression* expr);
890
Ben Murdochb0fe1622011-05-05 13:52:32 +0100891 HCompare* BuildSwitchCompare(HSubgraph* subgraph,
892 HValue* switch_value,
893 CaseClause* clause);
894
Steve Block1e0659c2011-05-24 12:43:12 +0100895 HValue* BuildContextChainWalk(Variable* var);
896
Ben Murdochb0fe1622011-05-05 13:52:32 +0100897 void AddCheckConstantFunction(Call* expr,
898 HValue* receiver,
899 Handle<Map> receiver_map,
900 bool smi_and_map_check);
901
902
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100903 HBasicBlock* BuildTypeSwitch(HValue* receiver,
904 ZoneMapList* maps,
905 ZoneList<HSubgraph*>* body_graphs,
906 HSubgraph* default_graph,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100907 int join_id);
908
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100909 // The translation state of the currently-being-translated function.
910 FunctionState* function_state_;
911
912 // The base of the function state stack.
913 FunctionState initial_function_state_;
914
Ben Murdochb0fe1622011-05-05 13:52:32 +0100915 // Expression context of the currently visited subexpression. NULL when
916 // visiting statements.
917 AstContext* ast_context_;
918
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100919 // A stack of breakable statements entered.
920 BreakAndContinueScope* break_scope_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100921
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100922 HGraph* graph_;
923 HSubgraph* current_subgraph_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100924
925 int inlined_count_;
926
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100927 friend class FunctionState; // Pushes and pops the state stack.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100928 friend class AstContext; // Pushes and pops the AST context stack.
929
930 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
931};
932
933
934class HValueMap: public ZoneObject {
935 public:
936 HValueMap()
937 : array_size_(0),
938 lists_size_(0),
939 count_(0),
940 present_flags_(0),
941 array_(NULL),
942 lists_(NULL),
943 free_list_head_(kNil) {
944 ResizeLists(kInitialSize);
945 Resize(kInitialSize);
946 }
947
948 void Kill(int flags);
949
950 void Add(HValue* value) {
951 present_flags_ |= value->flags();
952 Insert(value);
953 }
954
955 HValue* Lookup(HValue* value) const;
956 HValueMap* Copy() const { return new HValueMap(this); }
957
958 private:
959 // A linked list of HValue* values. Stored in arrays.
960 struct HValueMapListElement {
961 HValue* value;
962 int next; // Index in the array of the next list element.
963 };
964 static const int kNil = -1; // The end of a linked list
965
966 // Must be a power of 2.
967 static const int kInitialSize = 16;
968
969 explicit HValueMap(const HValueMap* other);
970
971 void Resize(int new_size);
972 void ResizeLists(int new_size);
973 void Insert(HValue* value);
974 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
975
976 int array_size_;
977 int lists_size_;
978 int count_; // The number of values stored in the HValueMap.
979 int present_flags_; // All flags that are in any value in the HValueMap.
980 HValueMapListElement* array_; // Primary store - contains the first value
981 // with a given hash. Colliding elements are stored in linked lists.
982 HValueMapListElement* lists_; // The linked lists containing hash collisions.
983 int free_list_head_; // Unused elements in lists_ are on the free list.
984};
985
986
987class HStatistics: public Malloced {
988 public:
989 void Print();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100990 void SaveTiming(const char* name, int64_t ticks, unsigned size);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100991 static HStatistics* Instance() {
992 static SetOncePointer<HStatistics> instance;
993 if (!instance.is_set()) {
994 instance.set(new HStatistics());
995 }
996 return instance.get();
997 }
998
999 private:
1000
Ben Murdochb8e0da22011-05-16 14:20:40 +01001001 HStatistics()
1002 : timing_(5),
1003 names_(5),
1004 sizes_(5),
1005 total_(0),
1006 total_size_(0),
1007 full_code_gen_(0) { }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001008
1009 List<int64_t> timing_;
1010 List<const char*> names_;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001011 List<unsigned> sizes_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001012 int64_t total_;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001013 unsigned total_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001014 int64_t full_code_gen_;
1015};
1016
1017
1018class HPhase BASE_EMBEDDED {
1019 public:
1020 static const char* const kFullCodeGen;
1021 static const char* const kTotal;
1022
1023 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
1024 HPhase(const char* name, HGraph* graph) {
1025 Begin(name, graph, NULL, NULL);
1026 }
1027 HPhase(const char* name, LChunk* chunk) {
1028 Begin(name, NULL, chunk, NULL);
1029 }
1030 HPhase(const char* name, LAllocator* allocator) {
1031 Begin(name, NULL, NULL, allocator);
1032 }
1033
1034 ~HPhase() {
1035 End();
1036 }
1037
1038 private:
1039 void Begin(const char* name,
1040 HGraph* graph,
1041 LChunk* chunk,
1042 LAllocator* allocator);
1043 void End() const;
1044
1045 int64_t start_;
1046 const char* name_;
1047 HGraph* graph_;
1048 LChunk* chunk_;
1049 LAllocator* allocator_;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001050 unsigned start_allocation_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001051};
1052
1053
1054class HTracer: public Malloced {
1055 public:
1056 void TraceCompilation(FunctionLiteral* function);
1057 void TraceHydrogen(const char* name, HGraph* graph);
1058 void TraceLithium(const char* name, LChunk* chunk);
1059 void TraceLiveRanges(const char* name, LAllocator* allocator);
1060
1061 static HTracer* Instance() {
1062 static SetOncePointer<HTracer> instance;
1063 if (!instance.is_set()) {
1064 instance.set(new HTracer("hydrogen.cfg"));
1065 }
1066 return instance.get();
1067 }
1068
1069 private:
1070 class Tag BASE_EMBEDDED {
1071 public:
1072 Tag(HTracer* tracer, const char* name) {
1073 name_ = name;
1074 tracer_ = tracer;
1075 tracer->PrintIndent();
1076 tracer->trace_.Add("begin_%s\n", name);
1077 tracer->indent_++;
1078 }
1079
1080 ~Tag() {
1081 tracer_->indent_--;
1082 tracer_->PrintIndent();
1083 tracer_->trace_.Add("end_%s\n", name_);
1084 ASSERT(tracer_->indent_ >= 0);
1085 tracer_->FlushToFile();
1086 }
1087
1088 private:
1089 HTracer* tracer_;
1090 const char* name_;
1091 };
1092
1093 explicit HTracer(const char* filename)
1094 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1095 WriteChars(filename, "", 0, false);
1096 }
1097
1098 void TraceLiveRange(LiveRange* range, const char* type);
1099 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1100 void FlushToFile();
1101
1102 void PrintEmptyProperty(const char* name) {
1103 PrintIndent();
1104 trace_.Add("%s\n", name);
1105 }
1106
1107 void PrintStringProperty(const char* name, const char* value) {
1108 PrintIndent();
1109 trace_.Add("%s \"%s\"\n", name, value);
1110 }
1111
1112 void PrintLongProperty(const char* name, int64_t value) {
1113 PrintIndent();
1114 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1115 }
1116
1117 void PrintBlockProperty(const char* name, int block_id) {
1118 PrintIndent();
1119 trace_.Add("%s \"B%d\"\n", name, block_id);
1120 }
1121
1122 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1123 PrintIndent();
1124 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1125 }
1126
1127 void PrintIntProperty(const char* name, int value) {
1128 PrintIndent();
1129 trace_.Add("%s %d\n", name, value);
1130 }
1131
1132 void PrintIndent() {
1133 for (int i = 0; i < indent_; i++) {
1134 trace_.Add(" ");
1135 }
1136 }
1137
1138 const char* filename_;
1139 HeapStringAllocator string_allocator_;
1140 StringStream trace_;
1141 int indent_;
1142};
1143
1144
1145} } // namespace v8::internal
1146
1147#endif // V8_HYDROGEN_H_