blob: dee78666cb208c0efa645f38ca94a847f407ff5c [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_; }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000063 HInstruction* last() const { return last_; }
64 void set_last(HInstruction* instr) { last_ = instr; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000065 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; }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000108 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000109
110 void set_parent_loop_header(HBasicBlock* block) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000111 ASSERT(parent_loop_header_ == NULL);
112 parent_loop_header_ = block;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000113 }
114
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000115 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000116
117 void SetJoinId(int id);
118
119 void Finish(HControlInstruction* last);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000120 void FinishExit(HControlInstruction* instruction);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000121 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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 void FinishExitWithDeoptimization() {
128 FinishExit(CreateDeoptimize());
129 }
130
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000131 // 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000144#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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000153 HDeoptimize* CreateDeoptimize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000154
155 int block_id_;
156 HGraph* graph_;
157 ZoneList<HPhi*> phis_;
158 HInstruction* first_;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000159 HInstruction* last_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000160 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_;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000172 HBasicBlock* parent_loop_header_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000173 bool is_inline_return_target_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000174};
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
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000200class HGraph: public ZoneObject {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000201 public:
202 explicit HGraph(CompilationInfo* info);
203
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000204 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
205 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000206 HBasicBlock* entry_block() const { return entry_block_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000207 HEnvironment* start_environment() const { return start_environment_; }
208
209 void InitializeInferredTypes();
210 void InsertTypeConversions();
211 void InsertRepresentationChanges();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000212 void ComputeMinusZeroChecks();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000213 bool ProcessArgumentsObject();
214 void EliminateRedundantPhis();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000215 void EliminateUnreachablePhis();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000216 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
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000224 Handle<Code> Compile(CompilationInfo* info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000225
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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000245 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,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000276 Representation to);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000277 void InsertRepresentationChangesForValue(HValue* current,
278 ZoneList<HValue*>* value_list,
279 ZoneList<Representation>* rep_list);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000280 void InferTypes(ZoneList<HValue*>* worklist);
281 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
282 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 Isolate* isolate() { return isolate_; }
285
286 Isolate* isolate_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000287 int next_block_id_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000288 HBasicBlock* entry_block_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000289 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000300 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
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000310 // 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000327 void Bind(Variable* variable, HValue* value) {
328 Bind(IndexFor(variable), value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000329 }
330
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000331 void Bind(int index, HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000332
333 HValue* Lookup(Variable* variable) const {
334 return Lookup(IndexFor(variable));
335 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000336
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000337 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000349 HValue* Pop() {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000350 ASSERT(!ExpressionStackIsEmpty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000351 if (push_count_ > 0) {
352 --push_count_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000353 } else {
354 ++pop_count_;
355 }
356 return values_.RemoveLast();
357 }
358
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000359 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];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000367 }
368
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000369 void SetExpressionStackAt(int index_from_top, HValue* value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000370
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000371 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);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000386
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000387 void ClearHistory() {
388 pop_count_ = 0;
389 push_count_ = 0;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000390 assigned_variables_.Rewind(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000391 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000392
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000393 void SetValueAt(int index, HValue* value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000394 ASSERT(index < length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000395 values_[index] = value;
396 }
397
398 void PrintTo(StringStream* stream);
399 void PrintToStd();
400
401 private:
402 explicit HEnvironment(const HEnvironment* other);
403
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000404 // 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000409 void Initialize(int parameter_count, int local_count, int stack_height);
410 void Initialize(const HEnvironment* other);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000411
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 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000421
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
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000437// This class is not BASE_EMBEDDED because our inlining implementation uses
438// new and delete.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000439class 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
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000445 // '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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000456 protected:
457 AstContext(HGraphBuilder* owner, Expression::Context kind);
458 virtual ~AstContext();
459
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000460 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
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000465 int original_length_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000466#endif
467
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000468 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 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000480 virtual ~EffectContext();
481
482 virtual void ReturnValue(HValue* value);
483 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000484};
485
486
487class ValueContext: public AstContext {
488 public:
489 explicit ValueContext(HGraphBuilder* owner)
490 : AstContext(owner, Expression::kValue) {
491 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000492 virtual ~ValueContext();
493
494 virtual void ReturnValue(HValue* value);
495 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000496};
497
498
499class TestContext: public AstContext {
500 public:
501 TestContext(HGraphBuilder* owner,
502 HBasicBlock* if_true,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000503 HBasicBlock* if_false)
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000504 : AstContext(owner, Expression::kTest),
505 if_true_(if_true),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000506 if_false_(if_false) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000507 }
508
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000509 virtual void ReturnValue(HValue* value);
510 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
511
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000512 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000520 private:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000521 // Build the shared core part of the translation unpacking a value into
522 // control flow.
523 void BuildBranch(HValue* value);
524
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000525 HBasicBlock* if_true_;
526 HBasicBlock* if_false_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000527};
528
529
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000530class 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000571class HGraphBuilder: public AstVisitor {
572 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000573 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
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000620 HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle)
621 : function_state_(NULL),
622 initial_function_state_(this, info, oracle),
623 ast_context_(NULL),
624 break_scope_(NULL),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000625 graph_(NULL),
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000626 current_block_(NULL),
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000627 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_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000632 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000633
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000634 HGraph* CreateGraph();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000635
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000636 // Simple accessors.
637 HGraph* graph() const { return graph_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000638 BreakAndContinueScope* break_scope() const { return break_scope_; }
639 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000640
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000641 HBasicBlock* current_block() const { return current_block_; }
642 void set_current_block(HBasicBlock* block) { current_block_ = block; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000643 HEnvironment* environment() const {
644 return current_block()->last_environment();
645 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000646
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.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000657 typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000658
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.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000673 FunctionState* function_state() const { return function_state_; }
674 void set_function_state(FunctionState* state) { function_state_ = state; }
675
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000676 AstContext* ast_context() const { return ast_context_; }
677 void set_ast_context(AstContext* context) { ast_context_ = context; }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000678
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 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000697
698 // Generators for inline runtime functions.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000699#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000700 void Generate##Name(CallRuntime* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000701
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
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000708 void PreProcessOsrEntry(IterationStatement* statement);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000709 // True iff. we are compiling for OSR and the statement is the entry.
710 bool HasOsrEntryAt(IterationStatement* statement);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000711
712 HBasicBlock* CreateJoin(HBasicBlock* first,
713 HBasicBlock* second,
714 int join_id);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000715
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
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000729 HBasicBlock* JoinContinue(IterationStatement* statement,
730 HBasicBlock* exit_block,
731 HBasicBlock* continue_block);
732
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000733 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,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000741 HBasicBlock* false_block);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000742
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000743 // Visit an argument subexpression and emit a push to the outgoing
744 // arguments.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000745 void VisitArgument(Expression* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000746 void VisitArgumentList(ZoneList<Expression*>* arguments);
747
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000748 // Visit a list of expressions from left to right, each in a value context.
749 void VisitExpressions(ZoneList<Expression*>* exprs);
750
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000751 void AddPhi(HPhi* phi);
752
753 void PushAndAdd(HInstruction* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000754
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000755 // Remove the arguments from the bailout environment and emit instructions
756 // to push them as outgoing parameters.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000757 template <int V> HInstruction* PreProcessCall(HCall<V>* call);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000758
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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000769 HBasicBlock* CreateBasicBlock(HEnvironment* env);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000770 HBasicBlock* CreateLoopHeaderBlock();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000771
772 // Helpers for flow graph construction.
ricow@chromium.org3842d832011-03-17 14:48:24 +0000773 void LookupGlobalPropertyCell(Variable* var,
774 LookupResult* lookup,
775 bool is_store);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000776
777 bool TryArgumentsAccess(Property* expr);
778 bool TryCallApply(Call* expr);
779 bool TryInline(Call* expr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000780 bool TryInlineBuiltinFunction(Call* expr,
781 HValue* receiver,
782 Handle<Map> receiver_map,
783 CheckType check_type);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000784
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);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000789
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000790 void HandleGlobalVariableAssignment(Variable* var,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000791 HValue* value,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000792 int position,
793 int ast_id);
794
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000795 void HandlePropertyAssignment(Assignment* expr);
796 void HandleCompoundAssignment(Assignment* expr);
797 void HandlePolymorphicLoadNamedField(Property* expr,
798 HValue* object,
799 ZoneMapList* types,
800 Handle<String> name);
801 void HandlePolymorphicStoreNamedField(Assignment* expr,
802 HValue* object,
803 HValue* value,
804 ZoneMapList* types,
805 Handle<String> name);
806 void HandlePolymorphicCallNamed(Call* expr,
807 HValue* receiver,
808 ZoneMapList* types,
809 Handle<String> name);
810
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000811 HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
812 HValue* index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000813 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
814 HValue* left,
815 HValue* right);
816 HInstruction* BuildIncrement(HValue* value, bool increment);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000817 HLoadNamedField* BuildLoadNamedField(HValue* object,
818 Property* expr,
819 Handle<Map> type,
820 LookupResult* result,
821 bool smi_and_map_check);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000822 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
823 HInstruction* BuildLoadKeyedFastElement(HValue* object,
824 HValue* key,
825 Property* expr);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000826 HInstruction* BuildLoadKeyedPixelArrayElement(HValue* object,
827 HValue* key,
828 Property* expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000829 HInstruction* BuildLoadKeyedGeneric(HValue* object,
830 HValue* key);
831
832 HInstruction* BuildLoadNamed(HValue* object,
833 Property* prop,
834 Handle<Map> map,
835 Handle<String> name);
836 HInstruction* BuildStoreNamed(HValue* object,
837 HValue* value,
838 Expression* expr);
839 HInstruction* BuildStoreNamedField(HValue* object,
840 Handle<String> name,
841 HValue* value,
842 Handle<Map> type,
843 LookupResult* lookup,
844 bool smi_and_map_check);
845 HInstruction* BuildStoreNamedGeneric(HValue* object,
846 Handle<String> name,
847 HValue* value);
848 HInstruction* BuildStoreKeyedGeneric(HValue* object,
849 HValue* key,
850 HValue* value);
851
852 HInstruction* BuildStoreKeyedFastElement(HValue* object,
853 HValue* key,
854 HValue* val,
855 Expression* expr);
856
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000857 HInstruction* BuildStoreKeyedPixelArrayElement(HValue* object,
858 HValue* key,
859 HValue* val,
860 Expression* expr);
861
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000862 HValue* BuildContextChainWalk(Variable* var);
863
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000864 void AddCheckConstantFunction(Call* expr,
865 HValue* receiver,
866 Handle<Map> receiver_map,
867 bool smi_and_map_check);
868
869
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000870 // The translation state of the currently-being-translated function.
871 FunctionState* function_state_;
872
873 // The base of the function state stack.
874 FunctionState initial_function_state_;
875
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000876 // Expression context of the currently visited subexpression. NULL when
877 // visiting statements.
878 AstContext* ast_context_;
879
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000880 // A stack of breakable statements entered.
881 BreakAndContinueScope* break_scope_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000882
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000883 HGraph* graph_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000884 HBasicBlock* current_block_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000885
886 int inlined_count_;
887
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000888 friend class FunctionState; // Pushes and pops the state stack.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000889 friend class AstContext; // Pushes and pops the AST context stack.
890
891 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
892};
893
894
895class HValueMap: public ZoneObject {
896 public:
897 HValueMap()
898 : array_size_(0),
899 lists_size_(0),
900 count_(0),
901 present_flags_(0),
902 array_(NULL),
903 lists_(NULL),
904 free_list_head_(kNil) {
905 ResizeLists(kInitialSize);
906 Resize(kInitialSize);
907 }
908
909 void Kill(int flags);
910
911 void Add(HValue* value) {
912 present_flags_ |= value->flags();
913 Insert(value);
914 }
915
916 HValue* Lookup(HValue* value) const;
917 HValueMap* Copy() const { return new HValueMap(this); }
918
919 private:
920 // A linked list of HValue* values. Stored in arrays.
921 struct HValueMapListElement {
922 HValue* value;
923 int next; // Index in the array of the next list element.
924 };
925 static const int kNil = -1; // The end of a linked list
926
927 // Must be a power of 2.
928 static const int kInitialSize = 16;
929
930 explicit HValueMap(const HValueMap* other);
931
932 void Resize(int new_size);
933 void ResizeLists(int new_size);
934 void Insert(HValue* value);
935 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
936
937 int array_size_;
938 int lists_size_;
939 int count_; // The number of values stored in the HValueMap.
940 int present_flags_; // All flags that are in any value in the HValueMap.
941 HValueMapListElement* array_; // Primary store - contains the first value
942 // with a given hash. Colliding elements are stored in linked lists.
943 HValueMapListElement* lists_; // The linked lists containing hash collisions.
944 int free_list_head_; // Unused elements in lists_ are on the free list.
945};
946
947
948class HStatistics: public Malloced {
949 public:
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000950 void Initialize(CompilationInfo* info);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000951 void Print();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000952 void SaveTiming(const char* name, int64_t ticks, unsigned size);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000953 static HStatistics* Instance() {
954 static SetOncePointer<HStatistics> instance;
955 if (!instance.is_set()) {
956 instance.set(new HStatistics());
957 }
958 return instance.get();
959 }
960
961 private:
962
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000963 HStatistics()
964 : timing_(5),
965 names_(5),
966 sizes_(5),
967 total_(0),
968 total_size_(0),
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000969 full_code_gen_(0),
970 source_size_(0) { }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000971
972 List<int64_t> timing_;
973 List<const char*> names_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000974 List<unsigned> sizes_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000975 int64_t total_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000976 unsigned total_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000977 int64_t full_code_gen_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000978 double source_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000979};
980
981
982class HPhase BASE_EMBEDDED {
983 public:
984 static const char* const kFullCodeGen;
985 static const char* const kTotal;
986
987 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
988 HPhase(const char* name, HGraph* graph) {
989 Begin(name, graph, NULL, NULL);
990 }
991 HPhase(const char* name, LChunk* chunk) {
992 Begin(name, NULL, chunk, NULL);
993 }
994 HPhase(const char* name, LAllocator* allocator) {
995 Begin(name, NULL, NULL, allocator);
996 }
997
998 ~HPhase() {
999 End();
1000 }
1001
1002 private:
1003 void Begin(const char* name,
1004 HGraph* graph,
1005 LChunk* chunk,
1006 LAllocator* allocator);
1007 void End() const;
1008
1009 int64_t start_;
1010 const char* name_;
1011 HGraph* graph_;
1012 LChunk* chunk_;
1013 LAllocator* allocator_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001014 unsigned start_allocation_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001015};
1016
1017
1018class HTracer: public Malloced {
1019 public:
1020 void TraceCompilation(FunctionLiteral* function);
1021 void TraceHydrogen(const char* name, HGraph* graph);
1022 void TraceLithium(const char* name, LChunk* chunk);
1023 void TraceLiveRanges(const char* name, LAllocator* allocator);
1024
1025 static HTracer* Instance() {
1026 static SetOncePointer<HTracer> instance;
1027 if (!instance.is_set()) {
1028 instance.set(new HTracer("hydrogen.cfg"));
1029 }
1030 return instance.get();
1031 }
1032
1033 private:
1034 class Tag BASE_EMBEDDED {
1035 public:
1036 Tag(HTracer* tracer, const char* name) {
1037 name_ = name;
1038 tracer_ = tracer;
1039 tracer->PrintIndent();
1040 tracer->trace_.Add("begin_%s\n", name);
1041 tracer->indent_++;
1042 }
1043
1044 ~Tag() {
1045 tracer_->indent_--;
1046 tracer_->PrintIndent();
1047 tracer_->trace_.Add("end_%s\n", name_);
1048 ASSERT(tracer_->indent_ >= 0);
1049 tracer_->FlushToFile();
1050 }
1051
1052 private:
1053 HTracer* tracer_;
1054 const char* name_;
1055 };
1056
1057 explicit HTracer(const char* filename)
1058 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1059 WriteChars(filename, "", 0, false);
1060 }
1061
1062 void TraceLiveRange(LiveRange* range, const char* type);
1063 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1064 void FlushToFile();
1065
1066 void PrintEmptyProperty(const char* name) {
1067 PrintIndent();
1068 trace_.Add("%s\n", name);
1069 }
1070
1071 void PrintStringProperty(const char* name, const char* value) {
1072 PrintIndent();
1073 trace_.Add("%s \"%s\"\n", name, value);
1074 }
1075
1076 void PrintLongProperty(const char* name, int64_t value) {
1077 PrintIndent();
1078 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1079 }
1080
1081 void PrintBlockProperty(const char* name, int block_id) {
1082 PrintIndent();
1083 trace_.Add("%s \"B%d\"\n", name, block_id);
1084 }
1085
1086 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1087 PrintIndent();
1088 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1089 }
1090
1091 void PrintIntProperty(const char* name, int value) {
1092 PrintIndent();
1093 trace_.Add("%s %d\n", name, value);
1094 }
1095
1096 void PrintIndent() {
1097 for (int i = 0; i < indent_; i++) {
1098 trace_.Add(" ");
1099 }
1100 }
1101
1102 const char* filename_;
1103 HeapStringAllocator string_allocator_;
1104 StringStream trace_;
1105 int indent_;
1106};
1107
1108
1109} } // namespace v8::internal
1110
1111#endif // V8_HYDROGEN_H_