blob: 74c119a2f593b9c0a995815ac8eda9f9b16c04d6 [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 Murdoch8b112d22011-06-08 16:22:53 +0100144 inline Zone* zone();
145
Ben Murdochb0fe1622011-05-05 13:52:32 +0100146#ifdef DEBUG
147 void Verify();
148#endif
149
150 private:
151 void RegisterPredecessor(HBasicBlock* pred);
152 void AddDominatedBlock(HBasicBlock* block);
153
154 HSimulate* CreateSimulate(int id);
Steve Block44f0eee2011-05-26 01:26:41 +0100155 HDeoptimize* CreateDeoptimize();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100156
157 int block_id_;
158 HGraph* graph_;
159 ZoneList<HPhi*> phis_;
160 HInstruction* first_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100161 HInstruction* last_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100162 HControlInstruction* end_;
163 HLoopInformation* loop_information_;
164 ZoneList<HBasicBlock*> predecessors_;
165 HBasicBlock* dominator_;
166 ZoneList<HBasicBlock*> dominated_blocks_;
167 HEnvironment* last_environment_;
168 // Outgoing parameter count at block exit, set during lithium translation.
169 int argument_count_;
170 // Instruction indices into the lithium code stream.
171 int first_instruction_index_;
172 int last_instruction_index_;
173 ZoneList<int> deleted_phis_;
Steve Block1e0659c2011-05-24 12:43:12 +0100174 HBasicBlock* parent_loop_header_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100175 bool is_inline_return_target_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100176};
177
178
179class HLoopInformation: public ZoneObject {
180 public:
181 explicit HLoopInformation(HBasicBlock* loop_header)
182 : back_edges_(4), loop_header_(loop_header), blocks_(8) {
183 blocks_.Add(loop_header);
184 }
185 virtual ~HLoopInformation() {}
186
187 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
188 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
189 HBasicBlock* loop_header() const { return loop_header_; }
190 HBasicBlock* GetLastBackEdge() const;
191 void RegisterBackEdge(HBasicBlock* block);
192
193 private:
194 void AddBlock(HBasicBlock* block);
195
196 ZoneList<HBasicBlock*> back_edges_;
197 HBasicBlock* loop_header_;
198 ZoneList<HBasicBlock*> blocks_;
199};
200
201
Steve Block44f0eee2011-05-26 01:26:41 +0100202class HGraph: public ZoneObject {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100203 public:
204 explicit HGraph(CompilationInfo* info);
205
Ben Murdoch8b112d22011-06-08 16:22:53 +0100206 Isolate* isolate() { return isolate_; }
207 Zone* zone() { return isolate_->zone(); }
208
Ben Murdochb0fe1622011-05-05 13:52:32 +0100209 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
210 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
Steve Block44f0eee2011-05-26 01:26:41 +0100211 HBasicBlock* entry_block() const { return entry_block_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100212 HEnvironment* start_environment() const { return start_environment_; }
213
214 void InitializeInferredTypes();
215 void InsertTypeConversions();
216 void InsertRepresentationChanges();
Steve Block1e0659c2011-05-24 12:43:12 +0100217 void ComputeMinusZeroChecks();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100218 bool ProcessArgumentsObject();
219 void EliminateRedundantPhis();
Steve Block44f0eee2011-05-26 01:26:41 +0100220 void EliminateUnreachablePhis();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100221 void Canonicalize();
222 void OrderBlocks();
223 void AssignDominators();
224
225 // Returns false if there are phi-uses of the arguments-object
226 // which are not supported by the optimizing compiler.
227 bool CollectPhis();
228
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100229 Handle<Code> Compile(CompilationInfo* info);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100230
231 void set_undefined_constant(HConstant* constant) {
232 undefined_constant_.set(constant);
233 }
234 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
235 HConstant* GetConstant1();
236 HConstant* GetConstantMinus1();
237 HConstant* GetConstantTrue();
238 HConstant* GetConstantFalse();
239
240 HBasicBlock* CreateBasicBlock();
241 HArgumentsObject* GetArgumentsObject() const {
242 return arguments_object_.get();
243 }
244 bool HasArgumentsObject() const { return arguments_object_.is_set(); }
245
246 void SetArgumentsObject(HArgumentsObject* object) {
247 arguments_object_.set(object);
248 }
249
Ben Murdochb0fe1622011-05-05 13:52:32 +0100250 int GetMaximumValueID() const { return values_.length(); }
251 int GetNextBlockID() { return next_block_id_++; }
252 int GetNextValueID(HValue* value) {
253 values_.Add(value);
254 return values_.length() - 1;
255 }
256 HValue* LookupValue(int id) const {
257 if (id >= 0 && id < values_.length()) return values_[id];
258 return NULL;
259 }
260
261#ifdef DEBUG
262 void Verify() const;
263#endif
264
265 private:
266 void Postorder(HBasicBlock* block,
267 BitVector* visited,
268 ZoneList<HBasicBlock*>* order,
269 HBasicBlock* loop_header);
270 void PostorderLoopBlocks(HLoopInformation* loop,
271 BitVector* visited,
272 ZoneList<HBasicBlock*>* order,
273 HBasicBlock* loop_header);
274 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
275 Object* value);
276
277 void InsertTypeConversions(HInstruction* instr);
278 void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
279 void InsertRepresentationChangeForUse(HValue* value,
280 HValue* use,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100281 Representation to);
Steve Block44f0eee2011-05-26 01:26:41 +0100282 void InsertRepresentationChangesForValue(HValue* current,
283 ZoneList<HValue*>* value_list,
284 ZoneList<Representation>* rep_list);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100285 void InferTypes(ZoneList<HValue*>* worklist);
286 void InitializeInferredTypes(int from_inclusive, int to_inclusive);
287 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
288
Steve Block44f0eee2011-05-26 01:26:41 +0100289 Isolate* isolate_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100290 int next_block_id_;
Steve Block44f0eee2011-05-26 01:26:41 +0100291 HBasicBlock* entry_block_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100292 HEnvironment* start_environment_;
293 ZoneList<HBasicBlock*> blocks_;
294 ZoneList<HValue*> values_;
295 ZoneList<HPhi*>* phi_list_;
296 SetOncePointer<HConstant> undefined_constant_;
297 SetOncePointer<HConstant> constant_1_;
298 SetOncePointer<HConstant> constant_minus1_;
299 SetOncePointer<HConstant> constant_true_;
300 SetOncePointer<HConstant> constant_false_;
301 SetOncePointer<HArgumentsObject> arguments_object_;
302
Ben Murdochb0fe1622011-05-05 13:52:32 +0100303 DISALLOW_COPY_AND_ASSIGN(HGraph);
304};
305
306
Ben Murdoch8b112d22011-06-08 16:22:53 +0100307Zone* HBasicBlock::zone() { return graph_->zone(); }
308
309
Ben Murdochb0fe1622011-05-05 13:52:32 +0100310class HEnvironment: public ZoneObject {
311 public:
312 HEnvironment(HEnvironment* outer,
313 Scope* scope,
314 Handle<JSFunction> closure);
315
Steve Block9fac8402011-05-12 15:51:54 +0100316 // Simple accessors.
317 Handle<JSFunction> closure() const { return closure_; }
318 const ZoneList<HValue*>* values() const { return &values_; }
319 const ZoneList<int>* assigned_variables() const {
320 return &assigned_variables_;
321 }
322 int parameter_count() const { return parameter_count_; }
323 int local_count() const { return local_count_; }
324 HEnvironment* outer() const { return outer_; }
325 int pop_count() const { return pop_count_; }
326 int push_count() const { return push_count_; }
327
328 int ast_id() const { return ast_id_; }
329 void set_ast_id(int id) { ast_id_ = id; }
330
331 int length() const { return values_.length(); }
332
Ben Murdochb0fe1622011-05-05 13:52:32 +0100333 void Bind(Variable* variable, HValue* value) {
334 Bind(IndexFor(variable), value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100335 }
336
Steve Block9fac8402011-05-12 15:51:54 +0100337 void Bind(int index, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100338
339 HValue* Lookup(Variable* variable) const {
340 return Lookup(IndexFor(variable));
341 }
Steve Block9fac8402011-05-12 15:51:54 +0100342
Ben Murdochb0fe1622011-05-05 13:52:32 +0100343 HValue* Lookup(int index) const {
344 HValue* result = values_[index];
345 ASSERT(result != NULL);
346 return result;
347 }
348
349 void Push(HValue* value) {
350 ASSERT(value != NULL);
351 ++push_count_;
352 values_.Add(value);
353 }
354
Ben Murdochb0fe1622011-05-05 13:52:32 +0100355 HValue* Pop() {
Steve Block9fac8402011-05-12 15:51:54 +0100356 ASSERT(!ExpressionStackIsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100357 if (push_count_ > 0) {
358 --push_count_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100359 } else {
360 ++pop_count_;
361 }
362 return values_.RemoveLast();
363 }
364
Steve Block9fac8402011-05-12 15:51:54 +0100365 void Drop(int count);
366
367 HValue* Top() const { return ExpressionStackAt(0); }
368
369 HValue* ExpressionStackAt(int index_from_top) const {
370 int index = length() - index_from_top - 1;
371 ASSERT(HasExpressionAt(index));
372 return values_[index];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100373 }
374
Steve Block9fac8402011-05-12 15:51:54 +0100375 void SetExpressionStackAt(int index_from_top, HValue* value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100376
Ben Murdochb0fe1622011-05-05 13:52:32 +0100377 HEnvironment* Copy() const;
378 HEnvironment* CopyWithoutHistory() const;
379 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
380
381 // Create an "inlined version" of this environment, where the original
382 // environment is the outer environment but the top expression stack
383 // elements are moved to an inner environment as parameters. If
384 // is_speculative, the argument values are expected to be PushArgument
385 // instructions, otherwise they are the actual values.
386 HEnvironment* CopyForInlining(Handle<JSFunction> target,
387 FunctionLiteral* function,
388 bool is_speculative,
389 HConstant* undefined) const;
390
391 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100392
Ben Murdochb0fe1622011-05-05 13:52:32 +0100393 void ClearHistory() {
394 pop_count_ = 0;
395 push_count_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100396 assigned_variables_.Rewind(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100397 }
Steve Block9fac8402011-05-12 15:51:54 +0100398
Ben Murdochb0fe1622011-05-05 13:52:32 +0100399 void SetValueAt(int index, HValue* value) {
Steve Block9fac8402011-05-12 15:51:54 +0100400 ASSERT(index < length());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100401 values_[index] = value;
402 }
403
404 void PrintTo(StringStream* stream);
405 void PrintToStd();
406
407 private:
408 explicit HEnvironment(const HEnvironment* other);
409
Steve Block9fac8402011-05-12 15:51:54 +0100410 // True if index is included in the expression stack part of the environment.
411 bool HasExpressionAt(int index) const;
412
413 bool ExpressionStackIsEmpty() const;
414
Ben Murdochb0fe1622011-05-05 13:52:32 +0100415 void Initialize(int parameter_count, int local_count, int stack_height);
416 void Initialize(const HEnvironment* other);
Steve Block9fac8402011-05-12 15:51:54 +0100417
418 // Map a variable to an environment index. Parameter indices are shifted
419 // by 1 (receiver is parameter index -1 but environment index 0).
420 // Stack-allocated local indices are shifted by the number of parameters.
421 int IndexFor(Variable* variable) const {
422 Slot* slot = variable->AsSlot();
423 ASSERT(slot != NULL && slot->IsStackAllocated());
424 int shift = (slot->type() == Slot::PARAMETER) ? 1 : parameter_count_;
425 return slot->index() + shift;
426 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100427
428 Handle<JSFunction> closure_;
429 // Value array [parameters] [locals] [temporaries].
430 ZoneList<HValue*> values_;
431 ZoneList<int> assigned_variables_;
432 int parameter_count_;
433 int local_count_;
434 HEnvironment* outer_;
435 int pop_count_;
436 int push_count_;
437 int ast_id_;
438};
439
440
441class HGraphBuilder;
442
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100443// This class is not BASE_EMBEDDED because our inlining implementation uses
444// new and delete.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100445class AstContext {
446 public:
447 bool IsEffect() const { return kind_ == Expression::kEffect; }
448 bool IsValue() const { return kind_ == Expression::kValue; }
449 bool IsTest() const { return kind_ == Expression::kTest; }
450
451 // 'Fill' this context with a hydrogen value. The value is assumed to
452 // have already been inserted in the instruction stream (or not need to
453 // be, e.g., HPhi). Call this function in tail position in the Visit
454 // functions for expressions.
455 virtual void ReturnValue(HValue* value) = 0;
456
457 // Add a hydrogen instruction to the instruction stream (recording an
458 // environment simulation if necessary) and then fill this context with
459 // the instruction as value.
460 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
461
Ben Murdoch8b112d22011-06-08 16:22:53 +0100462 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
463 bool is_for_typeof() { return for_typeof_; }
464
Ben Murdochb0fe1622011-05-05 13:52:32 +0100465 protected:
466 AstContext(HGraphBuilder* owner, Expression::Context kind);
467 virtual ~AstContext();
468
469 HGraphBuilder* owner() const { return owner_; }
470
Ben Murdoch8b112d22011-06-08 16:22:53 +0100471 inline Zone* zone();
472
Ben Murdochb0fe1622011-05-05 13:52:32 +0100473 // We want to be able to assert, in a context-specific way, that the stack
474 // height makes sense when the context is filled.
475#ifdef DEBUG
Steve Block9fac8402011-05-12 15:51:54 +0100476 int original_length_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100477#endif
478
479 private:
480 HGraphBuilder* owner_;
481 Expression::Context kind_;
482 AstContext* outer_;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100483 bool for_typeof_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100484};
485
486
487class EffectContext: public AstContext {
488 public:
489 explicit EffectContext(HGraphBuilder* owner)
490 : AstContext(owner, Expression::kEffect) {
491 }
492 virtual ~EffectContext();
493
494 virtual void ReturnValue(HValue* value);
495 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
496};
497
498
499class ValueContext: public AstContext {
500 public:
501 explicit ValueContext(HGraphBuilder* owner)
502 : AstContext(owner, Expression::kValue) {
503 }
504 virtual ~ValueContext();
505
506 virtual void ReturnValue(HValue* value);
507 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
508};
509
510
511class TestContext: public AstContext {
512 public:
513 TestContext(HGraphBuilder* owner,
514 HBasicBlock* if_true,
515 HBasicBlock* if_false)
516 : AstContext(owner, Expression::kTest),
517 if_true_(if_true),
518 if_false_(if_false) {
519 }
520
521 virtual void ReturnValue(HValue* value);
522 virtual void ReturnInstruction(HInstruction* instr, int ast_id);
523
524 static TestContext* cast(AstContext* context) {
525 ASSERT(context->IsTest());
526 return reinterpret_cast<TestContext*>(context);
527 }
528
529 HBasicBlock* if_true() const { return if_true_; }
530 HBasicBlock* if_false() const { return if_false_; }
531
532 private:
533 // Build the shared core part of the translation unpacking a value into
534 // control flow.
535 void BuildBranch(HValue* value);
536
537 HBasicBlock* if_true_;
538 HBasicBlock* if_false_;
539};
540
541
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100542class FunctionState BASE_EMBEDDED {
543 public:
544 FunctionState(HGraphBuilder* owner,
545 CompilationInfo* info,
546 TypeFeedbackOracle* oracle);
547 ~FunctionState();
548
549 CompilationInfo* compilation_info() { return compilation_info_; }
550 TypeFeedbackOracle* oracle() { return oracle_; }
551 AstContext* call_context() { return call_context_; }
552 HBasicBlock* function_return() { return function_return_; }
553 TestContext* test_context() { return test_context_; }
554 void ClearInlinedTestContext() {
555 delete test_context_;
556 test_context_ = NULL;
557 }
558
Ben Murdoch8b112d22011-06-08 16:22:53 +0100559 FunctionState* outer() { return outer_; }
560
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100561 private:
562 HGraphBuilder* owner_;
563
564 CompilationInfo* compilation_info_;
565 TypeFeedbackOracle* oracle_;
566
567 // During function inlining, expression context of the call being
568 // inlined. NULL when not inlining.
569 AstContext* call_context_;
570
571 // When inlining in an effect of value context, this is the return block.
572 // It is NULL otherwise. When inlining in a test context, there are a
573 // pair of return blocks in the context. When not inlining, there is no
574 // local return point.
575 HBasicBlock* function_return_;
576
577 // When inlining a call in a test context, a context containing a pair of
578 // return blocks. NULL in all other cases.
579 TestContext* test_context_;
580
581 FunctionState* outer_;
582};
583
584
Ben Murdochb0fe1622011-05-05 13:52:32 +0100585class HGraphBuilder: public AstVisitor {
586 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100587 enum BreakType { BREAK, CONTINUE };
588
589 // A class encapsulating (lazily-allocated) break and continue blocks for
590 // a breakable statement. Separated from BreakAndContinueScope so that it
591 // can have a separate lifetime.
592 class BreakAndContinueInfo BASE_EMBEDDED {
593 public:
594 explicit BreakAndContinueInfo(BreakableStatement* target)
595 : target_(target), break_block_(NULL), continue_block_(NULL) {
596 }
597
598 BreakableStatement* target() { return target_; }
599 HBasicBlock* break_block() { return break_block_; }
600 void set_break_block(HBasicBlock* block) { break_block_ = block; }
601 HBasicBlock* continue_block() { return continue_block_; }
602 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
603
604 private:
605 BreakableStatement* target_;
606 HBasicBlock* break_block_;
607 HBasicBlock* continue_block_;
608 };
609
610 // A helper class to maintain a stack of current BreakAndContinueInfo
611 // structures mirroring BreakableStatement nesting.
612 class BreakAndContinueScope BASE_EMBEDDED {
613 public:
614 BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner)
615 : info_(info), owner_(owner), next_(owner->break_scope()) {
616 owner->set_break_scope(this);
617 }
618
619 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
620
621 BreakAndContinueInfo* info() { return info_; }
622 HGraphBuilder* owner() { return owner_; }
623 BreakAndContinueScope* next() { return next_; }
624
625 // Search the break stack for a break or continue target.
626 HBasicBlock* Get(BreakableStatement* stmt, BreakType type);
627
628 private:
629 BreakAndContinueInfo* info_;
630 HGraphBuilder* owner_;
631 BreakAndContinueScope* next_;
632 };
633
634 HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle)
635 : function_state_(NULL),
636 initial_function_state_(this, info, oracle),
637 ast_context_(NULL),
638 break_scope_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100639 graph_(NULL),
Steve Block44f0eee2011-05-26 01:26:41 +0100640 current_block_(NULL),
Ben Murdoch8b112d22011-06-08 16:22:53 +0100641 inlined_count_(0),
642 zone_(info->isolate()->zone()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100643 // This is not initialized in the initializer list because the
644 // constructor for the initial state relies on function_state_ == NULL
645 // to know it's the initial state.
646 function_state_= &initial_function_state_;
647 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100648
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100649 HGraph* CreateGraph();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100650
651 // Simple accessors.
652 HGraph* graph() const { return graph_; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100653 BreakAndContinueScope* break_scope() const { return break_scope_; }
654 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100655
Steve Block44f0eee2011-05-26 01:26:41 +0100656 HBasicBlock* current_block() const { return current_block_; }
657 void set_current_block(HBasicBlock* block) { current_block_ = block; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100658 HEnvironment* environment() const {
659 return current_block()->last_environment();
660 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100661
662 // Adding instructions.
663 HInstruction* AddInstruction(HInstruction* instr);
664 void AddSimulate(int id);
665
666 // Bailout environment manipulation.
667 void Push(HValue* value) { environment()->Push(value); }
668 HValue* Pop() { return environment()->Pop(); }
669
670 private:
671 // Type of a member function that generates inline code for a native function.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100672 typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100673
674 // Forward declarations for inner scope classes.
675 class SubgraphScope;
676
677 static const InlineFunctionGenerator kInlineFunctionGenerators[];
678
679 static const int kMaxCallPolymorphism = 4;
680 static const int kMaxLoadPolymorphism = 4;
681 static const int kMaxStorePolymorphism = 4;
682
683 static const int kMaxInlinedNodes = 196;
684 static const int kMaxInlinedSize = 196;
685 static const int kMaxSourceSize = 600;
686
687 // Simple accessors.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100688 FunctionState* function_state() const { return function_state_; }
689 void set_function_state(FunctionState* state) { function_state_ = state; }
690
Ben Murdochb0fe1622011-05-05 13:52:32 +0100691 AstContext* ast_context() const { return ast_context_; }
692 void set_ast_context(AstContext* context) { ast_context_ = context; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100693
694 // Accessors forwarded to the function state.
695 CompilationInfo* info() const {
696 return function_state()->compilation_info();
697 }
698 TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
699
700 AstContext* call_context() const {
701 return function_state()->call_context();
702 }
703 HBasicBlock* function_return() const {
704 return function_state()->function_return();
705 }
706 TestContext* inlined_test_context() const {
707 return function_state()->test_context();
708 }
709 void ClearInlinedTestContext() {
710 function_state()->ClearInlinedTestContext();
711 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100712 bool function_strict_mode() {
713 return function_state()->compilation_info()->is_strict_mode();
714 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100715
716 // Generators for inline runtime functions.
717#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100718 void Generate##Name(CallRuntime* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100719
720 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
721 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
722#undef INLINE_FUNCTION_GENERATOR_DECLARATION
723
724 void Bailout(const char* reason);
725
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100726 void PreProcessOsrEntry(IterationStatement* statement);
727 // True iff. we are compiling for OSR and the statement is the entry.
728 bool HasOsrEntryAt(IterationStatement* statement);
729
730 HBasicBlock* CreateJoin(HBasicBlock* first,
731 HBasicBlock* second,
732 int join_id);
733
734 // Create a back edge in the flow graph. body_exit is the predecessor
735 // block and loop_entry is the successor block. loop_successor is the
736 // block where control flow exits the loop normally (e.g., via failure of
737 // the condition) and break_block is the block where control flow breaks
738 // from the loop. All blocks except loop_entry can be NULL. The return
739 // value is the new successor block which is the join of loop_successor
740 // and break_block, or NULL.
741 HBasicBlock* CreateLoop(IterationStatement* statement,
742 HBasicBlock* loop_entry,
743 HBasicBlock* body_exit,
744 HBasicBlock* loop_successor,
745 HBasicBlock* break_block);
746
747 HBasicBlock* JoinContinue(IterationStatement* statement,
748 HBasicBlock* exit_block,
749 HBasicBlock* continue_block);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100750
Ben Murdochb0fe1622011-05-05 13:52:32 +0100751 HValue* Top() const { return environment()->Top(); }
752 void Drop(int n) { environment()->Drop(n); }
753 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
754
755 void VisitForValue(Expression* expr);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100756 void VisitForTypeOf(Expression* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100757 void VisitForEffect(Expression* expr);
758 void VisitForControl(Expression* expr,
759 HBasicBlock* true_block,
760 HBasicBlock* false_block);
761
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100762 // Visit an argument subexpression and emit a push to the outgoing
763 // arguments.
Steve Block1e0659c2011-05-24 12:43:12 +0100764 void VisitArgument(Expression* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100765 void VisitArgumentList(ZoneList<Expression*>* arguments);
766
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100767 // Visit a list of expressions from left to right, each in a value context.
768 void VisitExpressions(ZoneList<Expression*>* exprs);
769
Ben Murdochb0fe1622011-05-05 13:52:32 +0100770 void AddPhi(HPhi* phi);
771
772 void PushAndAdd(HInstruction* instr);
773
Ben Murdochb0fe1622011-05-05 13:52:32 +0100774 // Remove the arguments from the bailout environment and emit instructions
775 // to push them as outgoing parameters.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100776 template <int V> HInstruction* PreProcessCall(HCall<V>* call);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100777
778 void AssumeRepresentation(HValue* value, Representation r);
779 static Representation ToRepresentation(TypeInfo info);
780
781 void SetupScope(Scope* scope);
782 virtual void VisitStatements(ZoneList<Statement*>* statements);
783
784#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
785 AST_NODE_LIST(DECLARE_VISIT)
786#undef DECLARE_VISIT
787
Ben Murdochb0fe1622011-05-05 13:52:32 +0100788 HBasicBlock* CreateBasicBlock(HEnvironment* env);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100789 HBasicBlock* CreateLoopHeaderBlock();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100790
791 // Helpers for flow graph construction.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100792 enum GlobalPropertyAccess {
793 kUseCell,
794 kUseGeneric
795 };
796 GlobalPropertyAccess LookupGlobalProperty(Variable* var,
797 LookupResult* lookup,
798 bool is_store);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100799
800 bool TryArgumentsAccess(Property* expr);
801 bool TryCallApply(Call* expr);
802 bool TryInline(Call* expr);
Steve Block1e0659c2011-05-24 12:43:12 +0100803 bool TryInlineBuiltinFunction(Call* expr,
804 HValue* receiver,
805 Handle<Map> receiver_map,
806 CheckType check_type);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100807
808 // If --trace-inlining, print a line of the inlining trace. Inlining
809 // succeeded if the reason string is NULL and failed if there is a
810 // non-NULL reason string.
811 void TraceInline(Handle<JSFunction> target, const char* failure_reason);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100812
813 void HandleGlobalVariableAssignment(Variable* var,
814 HValue* value,
815 int position,
816 int ast_id);
817
818 void HandlePropertyAssignment(Assignment* expr);
819 void HandleCompoundAssignment(Assignment* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100820 void HandlePolymorphicStoreNamedField(Assignment* expr,
821 HValue* object,
822 HValue* value,
823 ZoneMapList* types,
824 Handle<String> name);
825 void HandlePolymorphicCallNamed(Call* expr,
826 HValue* receiver,
827 ZoneMapList* types,
828 Handle<String> name);
829
Steve Block1e0659c2011-05-24 12:43:12 +0100830 HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
831 HValue* index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100832 HInstruction* BuildBinaryOperation(BinaryOperation* expr,
833 HValue* left,
834 HValue* right);
835 HInstruction* BuildIncrement(HValue* value, bool increment);
836 HLoadNamedField* BuildLoadNamedField(HValue* object,
837 Property* expr,
838 Handle<Map> type,
839 LookupResult* result,
840 bool smi_and_map_check);
841 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
842 HInstruction* BuildLoadKeyedFastElement(HValue* object,
843 HValue* key,
844 Property* expr);
Steve Block44f0eee2011-05-26 01:26:41 +0100845 HInstruction* BuildLoadKeyedSpecializedArrayElement(HValue* object,
846 HValue* key,
847 Property* expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100848 HInstruction* BuildLoadKeyedGeneric(HValue* object,
849 HValue* key);
850
Ben Murdoch8b112d22011-06-08 16:22:53 +0100851 HInstruction* BuildLoadKeyed(HValue* obj,
852 HValue* key,
853 Property* prop);
854
Ben Murdochb0fe1622011-05-05 13:52:32 +0100855 HInstruction* BuildLoadNamed(HValue* object,
856 Property* prop,
857 Handle<Map> map,
858 Handle<String> name);
859 HInstruction* BuildStoreNamed(HValue* object,
860 HValue* value,
861 Expression* expr);
862 HInstruction* BuildStoreNamedField(HValue* object,
863 Handle<String> name,
864 HValue* value,
865 Handle<Map> type,
866 LookupResult* lookup,
867 bool smi_and_map_check);
868 HInstruction* BuildStoreNamedGeneric(HValue* object,
869 Handle<String> name,
870 HValue* value);
871 HInstruction* BuildStoreKeyedGeneric(HValue* object,
872 HValue* key,
873 HValue* value);
874
875 HInstruction* BuildStoreKeyedFastElement(HValue* object,
876 HValue* key,
877 HValue* val,
878 Expression* expr);
879
Steve Block44f0eee2011-05-26 01:26:41 +0100880 HInstruction* BuildStoreKeyedSpecializedArrayElement(
881 HValue* object,
882 HValue* key,
883 HValue* val,
Ben Murdoch8b112d22011-06-08 16:22:53 +0100884 Expression* expr);
885
886 HInstruction* BuildStoreKeyed(HValue* object,
887 HValue* key,
888 HValue* value,
889 Expression* assignment);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100890
Steve Block1e0659c2011-05-24 12:43:12 +0100891 HValue* BuildContextChainWalk(Variable* var);
892
Ben Murdochb0fe1622011-05-05 13:52:32 +0100893 void AddCheckConstantFunction(Call* expr,
894 HValue* receiver,
895 Handle<Map> receiver_map,
896 bool smi_and_map_check);
897
Ben Murdoch8b112d22011-06-08 16:22:53 +0100898 Zone* zone() { return zone_; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100899
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100900 // The translation state of the currently-being-translated function.
901 FunctionState* function_state_;
902
903 // The base of the function state stack.
904 FunctionState initial_function_state_;
905
Ben Murdochb0fe1622011-05-05 13:52:32 +0100906 // Expression context of the currently visited subexpression. NULL when
907 // visiting statements.
908 AstContext* ast_context_;
909
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100910 // A stack of breakable statements entered.
911 BreakAndContinueScope* break_scope_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100912
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100913 HGraph* graph_;
Steve Block44f0eee2011-05-26 01:26:41 +0100914 HBasicBlock* current_block_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100915
916 int inlined_count_;
917
Ben Murdoch8b112d22011-06-08 16:22:53 +0100918 Zone* zone_;
919
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100920 friend class FunctionState; // Pushes and pops the state stack.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100921 friend class AstContext; // Pushes and pops the AST context stack.
922
923 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
924};
925
926
Ben Murdoch8b112d22011-06-08 16:22:53 +0100927Zone* AstContext::zone() { return owner_->zone(); }
928
929
Ben Murdochb0fe1622011-05-05 13:52:32 +0100930class HValueMap: public ZoneObject {
931 public:
932 HValueMap()
933 : array_size_(0),
934 lists_size_(0),
935 count_(0),
936 present_flags_(0),
937 array_(NULL),
938 lists_(NULL),
939 free_list_head_(kNil) {
940 ResizeLists(kInitialSize);
941 Resize(kInitialSize);
942 }
943
944 void Kill(int flags);
945
946 void Add(HValue* value) {
947 present_flags_ |= value->flags();
948 Insert(value);
949 }
950
951 HValue* Lookup(HValue* value) const;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100952
953 HValueMap* Copy(Zone* zone) const {
954 return new(zone) HValueMap(this);
955 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100956
957 private:
958 // A linked list of HValue* values. Stored in arrays.
959 struct HValueMapListElement {
960 HValue* value;
961 int next; // Index in the array of the next list element.
962 };
963 static const int kNil = -1; // The end of a linked list
964
965 // Must be a power of 2.
966 static const int kInitialSize = 16;
967
968 explicit HValueMap(const HValueMap* other);
969
970 void Resize(int new_size);
971 void ResizeLists(int new_size);
972 void Insert(HValue* value);
973 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); }
974
975 int array_size_;
976 int lists_size_;
977 int count_; // The number of values stored in the HValueMap.
978 int present_flags_; // All flags that are in any value in the HValueMap.
979 HValueMapListElement* array_; // Primary store - contains the first value
980 // with a given hash. Colliding elements are stored in linked lists.
981 HValueMapListElement* lists_; // The linked lists containing hash collisions.
982 int free_list_head_; // Unused elements in lists_ are on the free list.
983};
984
985
986class HStatistics: public Malloced {
987 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100988 void Initialize(CompilationInfo* info);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100989 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),
Steve Block44f0eee2011-05-26 01:26:41 +01001007 full_code_gen_(0),
1008 source_size_(0) { }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001009
1010 List<int64_t> timing_;
1011 List<const char*> names_;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001012 List<unsigned> sizes_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001013 int64_t total_;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001014 unsigned total_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001015 int64_t full_code_gen_;
Steve Block44f0eee2011-05-26 01:26:41 +01001016 double source_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001017};
1018
1019
1020class HPhase BASE_EMBEDDED {
1021 public:
1022 static const char* const kFullCodeGen;
1023 static const char* const kTotal;
1024
1025 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); }
1026 HPhase(const char* name, HGraph* graph) {
1027 Begin(name, graph, NULL, NULL);
1028 }
1029 HPhase(const char* name, LChunk* chunk) {
1030 Begin(name, NULL, chunk, NULL);
1031 }
1032 HPhase(const char* name, LAllocator* allocator) {
1033 Begin(name, NULL, NULL, allocator);
1034 }
1035
1036 ~HPhase() {
1037 End();
1038 }
1039
1040 private:
1041 void Begin(const char* name,
1042 HGraph* graph,
1043 LChunk* chunk,
1044 LAllocator* allocator);
1045 void End() const;
1046
1047 int64_t start_;
1048 const char* name_;
1049 HGraph* graph_;
1050 LChunk* chunk_;
1051 LAllocator* allocator_;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001052 unsigned start_allocation_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001053};
1054
1055
1056class HTracer: public Malloced {
1057 public:
1058 void TraceCompilation(FunctionLiteral* function);
1059 void TraceHydrogen(const char* name, HGraph* graph);
1060 void TraceLithium(const char* name, LChunk* chunk);
1061 void TraceLiveRanges(const char* name, LAllocator* allocator);
1062
1063 static HTracer* Instance() {
1064 static SetOncePointer<HTracer> instance;
1065 if (!instance.is_set()) {
1066 instance.set(new HTracer("hydrogen.cfg"));
1067 }
1068 return instance.get();
1069 }
1070
1071 private:
1072 class Tag BASE_EMBEDDED {
1073 public:
1074 Tag(HTracer* tracer, const char* name) {
1075 name_ = name;
1076 tracer_ = tracer;
1077 tracer->PrintIndent();
1078 tracer->trace_.Add("begin_%s\n", name);
1079 tracer->indent_++;
1080 }
1081
1082 ~Tag() {
1083 tracer_->indent_--;
1084 tracer_->PrintIndent();
1085 tracer_->trace_.Add("end_%s\n", name_);
1086 ASSERT(tracer_->indent_ >= 0);
1087 tracer_->FlushToFile();
1088 }
1089
1090 private:
1091 HTracer* tracer_;
1092 const char* name_;
1093 };
1094
1095 explicit HTracer(const char* filename)
1096 : filename_(filename), trace_(&string_allocator_), indent_(0) {
1097 WriteChars(filename, "", 0, false);
1098 }
1099
1100 void TraceLiveRange(LiveRange* range, const char* type);
1101 void Trace(const char* name, HGraph* graph, LChunk* chunk);
1102 void FlushToFile();
1103
1104 void PrintEmptyProperty(const char* name) {
1105 PrintIndent();
1106 trace_.Add("%s\n", name);
1107 }
1108
1109 void PrintStringProperty(const char* name, const char* value) {
1110 PrintIndent();
1111 trace_.Add("%s \"%s\"\n", name, value);
1112 }
1113
1114 void PrintLongProperty(const char* name, int64_t value) {
1115 PrintIndent();
1116 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
1117 }
1118
1119 void PrintBlockProperty(const char* name, int block_id) {
1120 PrintIndent();
1121 trace_.Add("%s \"B%d\"\n", name, block_id);
1122 }
1123
1124 void PrintBlockProperty(const char* name, int block_id1, int block_id2) {
1125 PrintIndent();
1126 trace_.Add("%s \"B%d\" \"B%d\"\n", name, block_id1, block_id2);
1127 }
1128
1129 void PrintIntProperty(const char* name, int value) {
1130 PrintIndent();
1131 trace_.Add("%s %d\n", name, value);
1132 }
1133
1134 void PrintIndent() {
1135 for (int i = 0; i < indent_; i++) {
1136 trace_.Add(" ");
1137 }
1138 }
1139
1140 const char* filename_;
1141 HeapStringAllocator string_allocator_;
1142 StringStream trace_;
1143 int indent_;
1144};
1145
1146
1147} } // namespace v8::internal
1148
1149#endif // V8_HYDROGEN_H_