blob: e14799a24c8c388d2404eba0c4dffb696d5388d9 [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
Steve Block44f0eee2011-05-26 01:26:41 +0100127 void FinishExitWithDeoptimization() {
128 FinishExit(CreateDeoptimize());
129 }
130
Ben Murdochb0fe1622011-05-05 13:52:32 +0100131 // Add the inlined function exit sequence, adding an HLeaveInlined
132 // instruction and updating the bailout environment.
133 void AddLeaveInlined(HValue* return_value, HBasicBlock* target);
134
135 // If a target block is tagged as an inline function return, all
136 // predecessors should contain the inlined exit sequence:
137 //
138 // LeaveInlined
139 // Simulate (caller's environment)
140 // Goto (target block)
141 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
142 void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; }
143
Ben Murdochb0fe1622011-05-05 13:52:32 +0100144#ifdef DEBUG
145 void Verify();
146#endif
147
148 private:
149 void RegisterPredecessor(HBasicBlock* pred);
150 void AddDominatedBlock(HBasicBlock* block);
151
152 HSimulate* CreateSimulate(int id);
Steve Block44f0eee2011-05-26 01:26:41 +0100153 HDeoptimize* CreateDeoptimize();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100154
155 int block_id_;
156 HGraph* graph_;
157 ZoneList<HPhi*> phis_;
158 HInstruction* first_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100159 HInstruction* last_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100160 HControlInstruction* end_;
161 HLoopInformation* loop_information_;
162 ZoneList<HBasicBlock*> predecessors_;
163 HBasicBlock* dominator_;
164 ZoneList<HBasicBlock*> dominated_blocks_;
165 HEnvironment* last_environment_;
166 // Outgoing parameter count at block exit, set during lithium translation.
167 int argument_count_;
168 // Instruction indices into the lithium code stream.
169 int first_instruction_index_;
170 int last_instruction_index_;
171 ZoneList<int> deleted_phis_;
Steve Block1e0659c2011-05-24 12:43:12 +0100172 HBasicBlock* parent_loop_header_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100173 bool is_inline_return_target_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100174};
175
176
177class HLoopInformation: public ZoneObject {
178 public:
179 explicit HLoopInformation(HBasicBlock* loop_header)
180 : back_edges_(4), loop_header_(loop_header), blocks_(8) {
181 blocks_.Add(loop_header);
182 }
183 virtual ~HLoopInformation() {}
184
185 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
186 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
187 HBasicBlock* loop_header() const { return loop_header_; }
188 HBasicBlock* GetLastBackEdge() const;
189 void RegisterBackEdge(HBasicBlock* block);
190
191 private:
192 void AddBlock(HBasicBlock* block);
193
194 ZoneList<HBasicBlock*> back_edges_;
195 HBasicBlock* loop_header_;
196 ZoneList<HBasicBlock*> blocks_;
197};
198
199
Steve Block44f0eee2011-05-26 01:26:41 +0100200class HGraph: public ZoneObject {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100201 public:
202 explicit HGraph(CompilationInfo* info);
203
Ben Murdochb0fe1622011-05-05 13:52:32 +0100204 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
205 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
Steve Block44f0eee2011-05-26 01:26:41 +0100206 HBasicBlock* entry_block() const { return entry_block_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100207 HEnvironment* start_environment() const { return start_environment_; }
208
209 void InitializeInferredTypes();
210 void InsertTypeConversions();
211 void InsertRepresentationChanges();
Steve Block1e0659c2011-05-24 12:43:12 +0100212 void ComputeMinusZeroChecks();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100213 bool ProcessArgumentsObject();
214 void EliminateRedundantPhis();
Steve Block44f0eee2011-05-26 01:26:41 +0100215 void EliminateUnreachablePhis();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100216 void Canonicalize();
217 void OrderBlocks();
218 void AssignDominators();
219
220 // Returns false if there are phi-uses of the arguments-object
221 // which are not supported by the optimizing compiler.
222 bool CollectPhis();
223
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100224 Handle<Code> Compile(CompilationInfo* info);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100225
226 void set_undefined_constant(HConstant* constant) {
227 undefined_constant_.set(constant);
228 }
229 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
230 HConstant* GetConstant1();
231 HConstant* GetConstantMinus1();
232 HConstant* GetConstantTrue();
233 HConstant* GetConstantFalse();
234
235 HBasicBlock* CreateBasicBlock();
236 HArgumentsObject* GetArgumentsObject() const {
237 return arguments_object_.get();
238 }
239 bool HasArgumentsObject() const { return arguments_object_.is_set(); }
240
241 void SetArgumentsObject(HArgumentsObject* object) {
242 arguments_object_.set(object);
243 }
244
Ben Murdochb0fe1622011-05-05 13:52:32 +0100245 int GetMaximumValueID() const { return values_.length(); }
246 int GetNextBlockID() { return next_block_id_++; }
247 int GetNextValueID(HValue* value) {
248 values_.Add(value);
249 return values_.length() - 1;
250 }
251 HValue* LookupValue(int id) const {
252 if (id >= 0 && id < values_.length()) return values_[id];
253 return NULL;
254 }
255
256#ifdef DEBUG
257 void Verify() const;
258#endif
259
260 private:
261 void Postorder(HBasicBlock* block,
262 BitVector* visited,
263 ZoneList<HBasicBlock*>* order,
264 HBasicBlock* loop_header);
265 void PostorderLoopBlocks(HLoopInformation* loop,
266 BitVector* visited,
267 ZoneList<HBasicBlock*>* order,
268 HBasicBlock* loop_header);
269 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
270 Object* value);
271
272 void InsertTypeConversions(HInstruction* instr);
273 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
274 void InsertRepresentationChangeForUse(HValue* value,
275 HValue* use,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100276 Representation to);
Steve Block44f0eee2011-05-26 01:26:41 +0100277 void InsertRepresentationChangesForValue(HValue* current,
278 ZoneList<HValue*>* value_list,
279 ZoneList<Representation>* rep_list);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100280 void InferTypes(ZoneList<HValue*>* worklist);
281 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
282 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
283
Steve Block44f0eee2011-05-26 01:26:41 +0100284 Isolate* isolate() { return isolate_; }
285
286 Isolate* isolate_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100287 int next_block_id_;
Steve Block44f0eee2011-05-26 01:26:41 +0100288 HBasicBlock* entry_block_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100289 HEnvironment* start_environment_;
290 ZoneList<HBasicBlock*> blocks_;
291 ZoneList<HValue*> values_;
292 ZoneList<HPhi*>* phi_list_;
293 SetOncePointer<HConstant> undefined_constant_;
294 SetOncePointer<HConstant> constant_1_;
295 SetOncePointer<HConstant> constant_minus1_;
296 SetOncePointer<HConstant> constant_true_;
297 SetOncePointer<HConstant> constant_false_;
298 SetOncePointer<HArgumentsObject> arguments_object_;
299
Ben Murdochb0fe1622011-05-05 13:52:32 +0100300 DISALLOW_COPY_AND_ASSIGN(HGraph);
301};
302
303
304class HEnvironment: public ZoneObject {
305 public:
306 HEnvironment(HEnvironment* outer,
307 Scope* scope,
308 Handle<JSFunction> closure);
309
Steve Block9fac8402011-05-12 15:51:54 +0100310 // Simple accessors.
311 Handle<JSFunction> closure() const { return closure_; }
312 const ZoneList<HValue*>* values() const { return &values_; }
313 const ZoneList<int>* assigned_variables() const {
314 return &assigned_variables_;
315 }
316 int parameter_count() const { return parameter_count_; }
317 int local_count() const { return local_count_; }
318 HEnvironment* outer() const { return outer_; }
319 int pop_count() const { return pop_count_; }
320 int push_count() const { return push_count_; }
321
322 int ast_id() const { return ast_id_; }
323 void set_ast_id(int id) { ast_id_ = id; }
324
325 int length() const { return values_.length(); }
326
Ben Murdochb0fe1622011-05-05 13:52:32 +0100327 void Bind(Variable* variable, HValue* value) {
328 Bind(IndexFor(variable), value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100329 }
330
Steve Block9fac8402011-05-12 15:51:54 +0100331 void Bind(int index, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100332
333 HValue* Lookup(Variable* variable) const {
334 return Lookup(IndexFor(variable));
335 }
Steve Block9fac8402011-05-12 15:51:54 +0100336
Ben Murdochb0fe1622011-05-05 13:52:32 +0100337 HValue* Lookup(int index) const {
338 HValue* result = values_[index];
339 ASSERT(result != NULL);
340 return result;
341 }
342
343 void Push(HValue* value) {
344 ASSERT(value != NULL);
345 ++push_count_;
346 values_.Add(value);
347 }
348
Ben Murdochb0fe1622011-05-05 13:52:32 +0100349 HValue* Pop() {
Steve Block9fac8402011-05-12 15:51:54 +0100350 ASSERT(!ExpressionStackIsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100351 if (push_count_ > 0) {
352 --push_count_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100353 } else {
354 ++pop_count_;
355 }
356 return values_.RemoveLast();
357 }
358
Steve Block9fac8402011-05-12 15:51:54 +0100359 void Drop(int count);
360
361 HValue* Top() const { return ExpressionStackAt(0); }
362
363 HValue* ExpressionStackAt(int index_from_top) const {
364 int index = length() - index_from_top - 1;
365 ASSERT(HasExpressionAt(index));
366 return values_[index];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100367 }
368
Steve Block9fac8402011-05-12 15:51:54 +0100369 void SetExpressionStackAt(int index_from_top, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100370
Ben Murdochb0fe1622011-05-05 13:52:32 +0100371 HEnvironment* Copy() const;
372 HEnvironment* CopyWithoutHistory() const;
373 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
374
375 // Create an "inlined version" of this environment, where the original
376 // environment is the outer environment but the top expression stack
377 // elements are moved to an inner environment as parameters. If
378 // is_speculative, the argument values are expected to be PushArgument
379 // instructions, otherwise they are the actual values.
380 HEnvironment* CopyForInlining(Handle<JSFunction> target,
381 FunctionLiteral* function,
382 bool is_speculative,
383 HConstant* undefined) const;
384
385 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100386
Ben Murdochb0fe1622011-05-05 13:52:32 +0100387 void ClearHistory() {
388 pop_count_ = 0;
389 push_count_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100390 assigned_variables_.Rewind(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100391 }
Steve Block9fac8402011-05-12 15:51:54 +0100392
Ben Murdochb0fe1622011-05-05 13:52:32 +0100393 void SetValueAt(int index, HValue* value) {
Steve Block9fac8402011-05-12 15:51:54 +0100394 ASSERT(index < length());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100395 values_[index] = value;
396 }
397
398 void PrintTo(StringStream* stream);
399 void PrintToStd();
400
401 private:
402 explicit HEnvironment(const HEnvironment* other);
403
Steve Block9fac8402011-05-12 15:51:54 +0100404 // True if index is included in the expression stack part of the environment.
405 bool HasExpressionAt(int index) const;
406
407 bool ExpressionStackIsEmpty() const;
408
Ben Murdochb0fe1622011-05-05 13:52:32 +0100409 void Initialize(int parameter_count, int local_count, int stack_height);
410 void Initialize(const HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100411
412 // Map a variable to an environment index. Parameter indices are shifted
413 // by 1 (receiver is parameter index -1 but environment index 0).
414 // Stack-allocated local indices are shifted by the number of parameters.
415 int IndexFor(Variable* variable) const {
416 Slot* slot = variable->AsSlot();
417 ASSERT(slot != NULL && slot->IsStackAllocated());
418 int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
419 return slot->index() + shift;
420 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100421
422 Handle<JSFunction> closure_;
423 // Value array [parameters] [locals] [temporaries].
424 ZoneList<HValue*> values_;
425 ZoneList<int> assigned_variables_;
426 int parameter_count_;
427 int local_count_;
428 HEnvironment* outer_;
429 int pop_count_;
430 int push_count_;
431 int ast_id_;
432};
433
434
435class HGraphBuilder;
436
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100437// This class is not BASE_EMBEDDED because our inlining implementation uses
438// new and delete.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100439class AstContext {
440 public:
441 bool IsEffect() const { return kind_ == Expression::kEffect; }
442 bool IsValue() const { return kind_ == Expression::kValue; }
443 bool IsTest() const { return kind_ == Expression::kTest; }
444
445 // 'Fill' this context with a hydrogen value. The value is assumed to
446 // have already been inserted in the instruction stream (or not need to
447 // be, e.g., HPhi). Call this function in tail position in the Visit
448 // functions for expressions.
449 virtual void ReturnValue(HValue* value) = 0;
450
451 // Add a hydrogen instruction to the instruction stream (recording an
452 // environment simulation if necessary) and then fill this context with
453 // the instruction as value.
454 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
455
456 protected:
457 AstContext(HGraphBuilder* owner, Expression::Context kind);
458 virtual ~AstContext();
459
460 HGraphBuilder* owner() const { return owner_; }
461
462 // We want to be able to assert, in a context-specific way, that the stack
463 // height makes sense when the context is filled.
464#ifdef DEBUG
Steve Block9fac8402011-05-12 15:51:54 +0100465 int original_length_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100466#endif
467
468 private:
469 HGraphBuilder* owner_;
470 Expression::Context kind_;
471 AstContext* outer_;
472};
473
474
475class EffectContext: public AstContext {
476 public:
477 explicit EffectContext(HGraphBuilder* owner)
478 : AstContext(owner, Expression::kEffect) {
479 }
480 virtual ~EffectContext();
481
482 virtual void ReturnValue(HValue* value);
483 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
484};
485
486
487class ValueContext: public AstContext {
488 public:
489 explicit ValueContext(HGraphBuilder* owner)
490 : AstContext(owner, Expression::kValue) {
491 }
492 virtual ~ValueContext();
493
494 virtual void ReturnValue(HValue* value);
495 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
496};
497
498
499class TestContext: public AstContext {
500 public:
501 TestContext(HGraphBuilder* owner,
502 HBasicBlock* if_true,
503 HBasicBlock* if_false)
504 : AstContext(owner, Expression::kTest),
505 if_true_(if_true),
506 if_false_(if_false) {
507 }
508
509 virtual void ReturnValue(HValue* value);
510 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
511
512 static TestContext* cast(AstContext* context) {
513 ASSERT(context->IsTest());
514 return reinterpret_cast<TestContext*>(context);
515 }
516
517 HBasicBlock* if_true() const { return if_true_; }
518 HBasicBlock* if_false() const { return if_false_; }
519
520 private:
521 // Build the shared core part of the translation unpacking a value into
522 // control flow.
523 void BuildBranch(HValue* value);
524
525 HBasicBlock* if_true_;
526 HBasicBlock* if_false_;
527};
528
529
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100530class FunctionState BASE_EMBEDDED {
531 public:
532 FunctionState(HGraphBuilder* owner,
533 CompilationInfo* info,
534 TypeFeedbackOracle* oracle);
535 ~FunctionState();
536
537 CompilationInfo* compilation_info() { return compilation_info_; }
538 TypeFeedbackOracle* oracle() { return oracle_; }
539 AstContext* call_context() { return call_context_; }
540 HBasicBlock* function_return() { return function_return_; }
541 TestContext* test_context() { return test_context_; }
542 void ClearInlinedTestContext() {
543 delete test_context_;
544 test_context_ = NULL;
545 }
546
547 private:
548 HGraphBuilder* owner_;
549
550 CompilationInfo* compilation_info_;
551 TypeFeedbackOracle* oracle_;
552
553 // During function inlining, expression context of the call being
554 // inlined. NULL when not inlining.
555 AstContext* call_context_;
556
557 // When inlining in an effect of value context, this is the return block.
558 // It is NULL otherwise. When inlining in a test context, there are a
559 // pair of return blocks in the context. When not inlining, there is no
560 // local return point.
561 HBasicBlock* function_return_;
562
563 // When inlining a call in a test context, a context containing a pair of
564 // return blocks. NULL in all other cases.
565 TestContext* test_context_;
566
567 FunctionState* outer_;
568};
569
570
Ben Murdochb0fe1622011-05-05 13:52:32 +0100571class HGraphBuilder: public AstVisitor {
572 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100573 enum BreakType { BREAK, CONTINUE };
574
575 // A class encapsulating (lazily-allocated) break and continue blocks for
576 // a breakable statement. Separated from BreakAndContinueScope so that it
577 // can have a separate lifetime.
578 class BreakAndContinueInfo BASE_EMBEDDED {
579 public:
580 explicit BreakAndContinueInfo(BreakableStatement* target)
581 : target_(target), break_block_(NULL), continue_block_(NULL) {
582 }
583
584 BreakableStatement* target() { return target_; }
585 HBasicBlock* break_block() { return break_block_; }
586 void set_break_block(HBasicBlock* block) { break_block_ = block; }
587 HBasicBlock* continue_block() { return continue_block_; }
588 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
589
590 private:
591 BreakableStatement* target_;
592 HBasicBlock* break_block_;
593 HBasicBlock* continue_block_;
594 };
595
596 // A helper class to maintain a stack of current BreakAndContinueInfo
597 // structures mirroring BreakableStatement nesting.
598 class BreakAndContinueScope BASE_EMBEDDED {
599 public:
600 BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
601 : info_(info), owner_(owner), next_(owner->break_scope()) {
602 owner->set_break_scope(this);
603 }
604
605 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
606
607 BreakAndContinueInfo* info() { return info_; }
608 HGraphBuilder* owner() { return owner_; }
609 BreakAndContinueScope* next() { return next_; }
610
611 // Search the break stack for a break or continue target.
612 HBasicBlock* Get(BreakableStatement* stmt, BreakType type);
613
614 private:
615 BreakAndContinueInfo* info_;
616 HGraphBuilder* owner_;
617 BreakAndContinueScope* next_;
618 };
619
620 HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle)
621 : function_state_(NULL),
622 initial_function_state_(this, info, oracle),
623 ast_context_(NULL),
624 break_scope_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100625 graph_(NULL),
Steve Block44f0eee2011-05-26 01:26:41 +0100626 current_block_(NULL),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100627 inlined_count_(0) {
628 // This is not initialized in the initializer list because the
629 // constructor for the initial state relies on function_state_ == NULL
630 // to know it's the initial state.
631 function_state_= &initial_function_state_;
632 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100633
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100634 HGraph* CreateGraph();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100635
636 // Simple accessors.
637 HGraph* graph() const { return graph_; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100638 BreakAndContinueScope* break_scope() const { return break_scope_; }
639 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100640
Steve Block44f0eee2011-05-26 01:26:41 +0100641 HBasicBlock* current_block() const { return current_block_; }
642 void set_current_block(HBasicBlock* block) { current_block_ = block; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100643 HEnvironment* environment() const {
644 return current_block()->last_environment();
645 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100646
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
655 private:
656 // Type of a member function that generates inline code for a native function.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100657 typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100658
659 // Forward declarations for inner scope classes.
660 class SubgraphScope;
661
662 static const InlineFunctionGenerator kInlineFunctionGenerators[];
663
664 static const int kMaxCallPolymorphism = 4;
665 static const int kMaxLoadPolymorphism = 4;
666 static const int kMaxStorePolymorphism = 4;
667
668 static const int kMaxInlinedNodes = 196;
669 static const int kMaxInlinedSize = 196;
670 static const int kMaxSourceSize = 600;
671
672 // Simple accessors.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100673 FunctionState* function_state() const { return function_state_; }
674 void set_function_state(FunctionState* state) { function_state_ = state; }
675
Ben Murdochb0fe1622011-05-05 13:52:32 +0100676 AstContext* ast_context() const { return ast_context_; }
677 void set_ast_context(AstContext* context) { ast_context_ = context; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100678
679 // Accessors forwarded to the function state.
680 CompilationInfo* info() const {
681 return function_state()->compilation_info();
682 }
683 TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
684
685 AstContext* call_context() const {
686 return function_state()->call_context();
687 }
688 HBasicBlock* function_return() const {
689 return function_state()->function_return();
690 }
691 TestContext* inlined_test_context() const {
692 return function_state()->test_context();
693 }
694 void ClearInlinedTestContext() {
695 function_state()->ClearInlinedTestContext();
696 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100697
698 // Generators for inline runtime functions.
699#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100700 void Generate##Name(CallRuntime* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100701
702 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
703 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
704#undef INLINE_FUNCTION_GENERATOR_DECLARATION
705
706 void Bailout(const char* reason);
707
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100708 void PreProcessOsrEntry(IterationStatement* statement);
709 // True iff. we are compiling for OSR and the statement is the entry.
710 bool HasOsrEntryAt(IterationStatement* statement);
711
712 HBasicBlock* CreateJoin(HBasicBlock* first,
713 HBasicBlock* second,
714 int join_id);
715
716 // Create a back edge in the flow graph. body_exit is the predecessor
717 // block and loop_entry is the successor block. loop_successor is the
718 // block where control flow exits the loop normally (e.g., via failure of
719 // the condition) and break_block is the block where control flow breaks
720 // from the loop. All blocks except loop_entry can be NULL. The return
721 // value is the new successor block which is the join of loop_successor
722 // and break_block, or NULL.
723 HBasicBlock* CreateLoop(IterationStatement* statement,
724 HBasicBlock* loop_entry,
725 HBasicBlock* body_exit,
726 HBasicBlock* loop_successor,
727 HBasicBlock* break_block);
728
729 HBasicBlock* JoinContinue(IterationStatement* statement,
730 HBasicBlock* exit_block,
731 HBasicBlock* continue_block);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100732
Ben Murdochb0fe1622011-05-05 13:52:32 +0100733 HValue* Top() const { return environment()->Top(); }
734 void Drop(int n) { environment()->Drop(n); }
735 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
736
737 void VisitForValue(Expression* expr);
738 void VisitForEffect(Expression* expr);
739 void VisitForControl(Expression* expr,
740 HBasicBlock* true_block,
741 HBasicBlock* false_block);
742
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100743 // Visit an argument subexpression and emit a push to the outgoing
744 // arguments.
Steve Block1e0659c2011-05-24 12:43:12 +0100745 void VisitArgument(Expression* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100746 void VisitArgumentList(ZoneList<Expression*>* arguments);
747
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100748 // Visit a list of expressions from left to right, each in a value context.
749 void VisitExpressions(ZoneList<Expression*>* exprs);
750
Ben Murdochb0fe1622011-05-05 13:52:32 +0100751 void AddPhi(HPhi* phi);
752
753 void PushAndAdd(HInstruction* instr);
754
Ben Murdochb0fe1622011-05-05 13:52:32 +0100755 // Remove the arguments from the bailout environment and emit instructions
756 // to push them as outgoing parameters.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100757 template <int V> HInstruction* PreProcessCall(HCall<V>* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100758
759 void AssumeRepresentation(HValue* value, Representation r);
760 static Representation ToRepresentation(TypeInfo info);
761
762 void SetupScope(Scope* scope);
763 virtual void VisitStatements(ZoneList<Statement*>* statements);
764
765#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
766 AST_NODE_LIST(DECLARE_VISIT)
767#undef DECLARE_VISIT
768
Ben Murdochb0fe1622011-05-05 13:52:32 +0100769 HBasicBlock* CreateBasicBlock(HEnvironment* env);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100770 HBasicBlock* CreateLoopHeaderBlock();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100771
772 // Helpers for flow graph construction.
773 void LookupGlobalPropertyCell(Variable* var,
774 LookupResult* lookup,
775 bool is_store);
776
777 bool TryArgumentsAccess(Property* expr);
778 bool TryCallApply(Call* expr);
779 bool TryInline(Call* expr);
Steve Block1e0659c2011-05-24 12:43:12 +0100780 bool TryInlineBuiltinFunction(Call* expr,
781 HValue* receiver,
782 Handle<Map> receiver_map,
783 CheckType check_type);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100784
785 // If --trace-inlining, print a line of the inlining trace. Inlining
786 // succeeded if the reason string is NULL and failed if there is a
787 // non-NULL reason string.
788 void TraceInline(Handle<JSFunction> target, const char* failure_reason);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100789
790 void HandleGlobalVariableAssignment(Variable* var,
791 HValue* value,
792 int position,
793 int ast_id);
794
795 void HandlePropertyAssignment(Assignment* expr);
796 void HandleCompoundAssignment(Assignment* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100797 void HandlePolymorphicStoreNamedField(Assignment* expr,
798 HValue* object,
799 HValue* value,
800 ZoneMapList* types,
801 Handle<String> name);
802 void HandlePolymorphicCallNamed(Call* expr,
803 HValue* receiver,
804 ZoneMapList* types,
805 Handle<String> name);
806
Steve Block1e0659c2011-05-24 12:43:12 +0100807 HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
808 HValue* index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100809 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
810 HValue* left,
811 HValue* right);
812 HInstruction* BuildIncrement(HValue* value, bool increment);
813 HLoadNamedField* BuildLoadNamedField(HValue* object,
814 Property* expr,
815 Handle<Map> type,
816 LookupResult* result,
817 bool smi_and_map_check);
818 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
819 HInstruction* BuildLoadKeyedFastElement(HValue* object,
820 HValue* key,
821 Property* expr);
Steve Block44f0eee2011-05-26 01:26:41 +0100822 HInstruction* BuildLoadKeyedSpecializedArrayElement(HValue* object,
823 HValue* key,
824 Property* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100825 HInstruction* BuildLoadKeyedGeneric(HValue* object,
826 HValue* key);
827
828 HInstruction* BuildLoadNamed(HValue* object,
829 Property* prop,
830 Handle<Map> map,
831 Handle<String> name);
832 HInstruction* BuildStoreNamed(HValue* object,
833 HValue* value,
834 Expression* expr);
835 HInstruction* BuildStoreNamedField(HValue* object,
836 Handle<String> name,
837 HValue* value,
838 Handle<Map> type,
839 LookupResult* lookup,
840 bool smi_and_map_check);
841 HInstruction* BuildStoreNamedGeneric(HValue* object,
842 Handle<String> name,
843 HValue* value);
844 HInstruction* BuildStoreKeyedGeneric(HValue* object,
845 HValue* key,
846 HValue* value);
847
848 HInstruction* BuildStoreKeyedFastElement(HValue* object,
849 HValue* key,
850 HValue* val,
851 Expression* expr);
852
Steve Block44f0eee2011-05-26 01:26:41 +0100853 HInstruction* BuildStoreKeyedSpecializedArrayElement(
854 HValue* object,
855 HValue* key,
856 HValue* val,
857 Assignment* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100858
Steve Block1e0659c2011-05-24 12:43:12 +0100859 HValue* BuildContextChainWalk(Variable* var);
860
Ben Murdochb0fe1622011-05-05 13:52:32 +0100861 void AddCheckConstantFunction(Call* expr,
862 HValue* receiver,
863 Handle<Map> receiver_map,
864 bool smi_and_map_check);
865
866
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100867 // The translation state of the currently-being-translated function.
868 FunctionState* function_state_;
869
870 // The base of the function state stack.
871 FunctionState initial_function_state_;
872
Ben Murdochb0fe1622011-05-05 13:52:32 +0100873 // Expression context of the currently visited subexpression. NULL when
874 // visiting statements.
875 AstContext* ast_context_;
876
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100877 // A stack of breakable statements entered.
878 BreakAndContinueScope* break_scope_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100879
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100880 HGraph* graph_;
Steve Block44f0eee2011-05-26 01:26:41 +0100881 HBasicBlock* current_block_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100882
883 int inlined_count_;
884
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100885 friend class FunctionState; // Pushes and pops the state stack.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100886 friend class AstContext; // Pushes and pops the AST context stack.
887
888 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
889};
890
891
892class HValueMap: public ZoneObject {
893 public:
894 HValueMap()
895 : array_size_(0),
896 lists_size_(0),
897 count_(0),
898 present_flags_(0),
899 array_(NULL),
900 lists_(NULL),
901 free_list_head_(kNil) {
902 ResizeLists(kInitialSize);
903 Resize(kInitialSize);
904 }
905
906 void Kill(int flags);
907
908 void Add(HValue* value) {
909 present_flags_ |= value->flags();
910 Insert(value);
911 }
912
913 HValue* Lookup(HValue* value) const;
914 HValueMap* Copy() const { return new HValueMap(this); }
915
916 private:
917 // A linked list of HValue* values. Stored in arrays.
918 struct HValueMapListElement {
919 HValue* value;
920 int next; // Index in the array of the next list element.
921 };
922 static const int kNil = -1; // The end of a linked list
923
924 // Must be a power of 2.
925 static const int kInitialSize = 16;
926
927 explicit HValueMap(const HValueMap* other);
928
929 void Resize(int new_size);
930 void ResizeLists(int new_size);
931 void Insert(HValue* value);
932 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
933
934 int array_size_;
935 int lists_size_;
936 int count_; // The number of values stored in the HValueMap.
937 int present_flags_; // All flags that are in any value in the HValueMap.
938 HValueMapListElement* array_; // Primary store - contains the first value
939 // with a given hash. Colliding elements are stored in linked lists.
940 HValueMapListElement* lists_; // The linked lists containing hash collisions.
941 int free_list_head_; // Unused elements in lists_ are on the free list.
942};
943
944
945class HStatistics: public Malloced {
946 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100947 void Initialize(CompilationInfo* info);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100948 void Print();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100949 void SaveTiming(const char* name, int64_t ticks, unsigned size);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100950 static HStatistics* Instance() {
951 static SetOncePointer<HStatistics> instance;
952 if (!instance.is_set()) {
953 instance.set(new HStatistics());
954 }
955 return instance.get();
956 }
957
958 private:
959
Ben Murdochb8e0da22011-05-16 14:20:40 +0100960 HStatistics()
961 : timing_(5),
962 names_(5),
963 sizes_(5),
964 total_(0),
965 total_size_(0),
Steve Block44f0eee2011-05-26 01:26:41 +0100966 full_code_gen_(0),
967 source_size_(0) { }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100968
969 List<int64_t> timing_;
970 List<const char*> names_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100971 List<unsigned> sizes_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100972 int64_t total_;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100973 unsigned total_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100974 int64_t full_code_gen_;
Steve Block44f0eee2011-05-26 01:26:41 +0100975 double source_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100976};
977
978
979class HPhase BASE_EMBEDDED {
980 public:
981 static const char* const kFullCodeGen;
982 static const char* const kTotal;
983
984 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
985 HPhase(const char* name, HGraph* graph) {
986 Begin(name, graph, NULL, NULL);
987 }
988 HPhase(const char* name, LChunk* chunk) {
989 Begin(name, NULL, chunk, NULL);
990 }
991 HPhase(const char* name, LAllocator* allocator) {
992 Begin(name, NULL, NULL, allocator);
993 }
994
995 ~HPhase() {
996 End();
997 }
998
999 private:
1000 void Begin(const char* name,
1001 HGraph* graph,
1002 LChunk* chunk,
1003 LAllocator* allocator);
1004 void End() const;
1005
1006 int64_t start_;
1007 const char* name_;
1008 HGraph* graph_;
1009 LChunk* chunk_;
1010 LAllocator* allocator_;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001011 unsigned start_allocation_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001012};
1013
1014
1015class HTracer: public Malloced {
1016 public:
1017 void TraceCompilation(FunctionLiteral* function);
1018 void TraceHydrogen(const char* name, HGraph* graph);
1019 void TraceLithium(const char* name, LChunk* chunk);
1020 void TraceLiveRanges(const char* name, LAllocator* allocator);
1021
1022 static HTracer* Instance() {
1023 static SetOncePointer<HTracer> instance;
1024 if (!instance.is_set()) {
1025 instance.set(new HTracer("hydrogen.cfg"));
1026 }
1027 return instance.get();
1028 }
1029
1030 private:
1031 class Tag BASE_EMBEDDED {
1032 public:
1033 Tag(HTracer* tracer, const char* name) {
1034 name_ = name;
1035 tracer_ = tracer;
1036 tracer->PrintIndent();
1037 tracer->trace_.Add("begin_%s\n", name);
1038 tracer->indent_++;
1039 }
1040
1041 ~Tag() {
1042 tracer_->indent_--;
1043 tracer_->PrintIndent();
1044 tracer_->trace_.Add("end_%s\n", name_);
1045 ASSERT(tracer_->indent_ >= 0);
1046 tracer_->FlushToFile();
1047 }
1048
1049 private:
1050 HTracer* tracer_;
1051 const char* name_;
1052 };
1053
1054 explicit HTracer(const char* filename)
1055 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1056 WriteChars(filename, "", 0, false);
1057 }
1058
1059 void TraceLiveRange(LiveRange* range, const char* type);
1060 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1061 void FlushToFile();
1062
1063 void PrintEmptyProperty(const char* name) {
1064 PrintIndent();
1065 trace_.Add("%s\n", name);
1066 }
1067
1068 void PrintStringProperty(const char* name, const char* value) {
1069 PrintIndent();
1070 trace_.Add("%s \"%s\"\n", name, value);
1071 }
1072
1073 void PrintLongProperty(const char* name, int64_t value) {
1074 PrintIndent();
1075 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1076 }
1077
1078 void PrintBlockProperty(const char* name, int block_id) {
1079 PrintIndent();
1080 trace_.Add("%s \"B%d\"\n", name, block_id);
1081 }
1082
1083 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1084 PrintIndent();
1085 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1086 }
1087
1088 void PrintIntProperty(const char* name, int value) {
1089 PrintIndent();
1090 trace_.Add("%s %d\n", name, value);
1091 }
1092
1093 void PrintIndent() {
1094 for (int i = 0; i < indent_; i++) {
1095 trace_.Add(" ");
1096 }
1097 }
1098
1099 const char* filename_;
1100 HeapStringAllocator string_allocator_;
1101 StringStream trace_;
1102 int indent_;
1103};
1104
1105
1106} } // namespace v8::internal
1107
1108#endif // V8_HYDROGEN_H_