1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // 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 "allocation.h" 34 #include "ast.h" 35 #include "compiler.h" 36 #include "hydrogen-instructions.h" 37 #include "type-info.h" 38 #include "zone.h" 39 40 namespace v8 { 41 namespace internal { 42 43 // Forward declarations. 44 class BitVector; 45 class HEnvironment; 46 class HGraph; 47 class HLoopInformation; 48 class HTracer; 49 class LAllocator; 50 class LChunk; 51 class LiveRange; 52 53 54 class HBasicBlock: public ZoneObject { 55 public: 56 explicit HBasicBlock(HGraph* graph); 57 virtual ~HBasicBlock() { } 58 59 // Simple accessors. 60 int block_id() const { return block_id_; } 61 void set_block_id(int id) { block_id_ = id; } 62 HGraph* graph() const { return graph_; } 63 const ZoneList<HPhi*>* phis() const { return &phis_; } 64 HInstruction* first() const { return first_; } 65 HInstruction* last() const { return last_; } 66 void set_last(HInstruction* instr) { last_ = instr; } 67 HInstruction* GetLastInstruction(); 68 HControlInstruction* end() const { return end_; } 69 HLoopInformation* loop_information() const { return loop_information_; } 70 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; } 71 bool HasPredecessor() const { return predecessors_.length() > 0; } 72 const ZoneList<HBasicBlock*>* dominated_blocks() const { 73 return &dominated_blocks_; 74 } 75 const ZoneList<int>* deleted_phis() const { 76 return &deleted_phis_; 77 } 78 void RecordDeletedPhi(int merge_index) { 79 deleted_phis_.Add(merge_index); 80 } 81 HBasicBlock* dominator() const { return dominator_; } 82 HEnvironment* last_environment() const { return last_environment_; } 83 int argument_count() const { return argument_count_; } 84 void set_argument_count(int count) { argument_count_ = count; } 85 int first_instruction_index() const { return first_instruction_index_; } 86 void set_first_instruction_index(int index) { 87 first_instruction_index_ = index; 88 } 89 int last_instruction_index() const { return last_instruction_index_; } 90 void set_last_instruction_index(int index) { 91 last_instruction_index_ = index; 92 } 93 94 void AttachLoopInformation(); 95 void DetachLoopInformation(); 96 bool IsLoopHeader() const { return loop_information() != NULL; } 97 bool IsStartBlock() const { return block_id() == 0; } 98 void PostProcessLoopHeader(IterationStatement* stmt); 99 100 bool IsFinished() const { return end_ != NULL; } 101 void AddPhi(HPhi* phi); 102 void RemovePhi(HPhi* phi); 103 void AddInstruction(HInstruction* instr); 104 bool Dominates(HBasicBlock* other) const; 105 int LoopNestingDepth() const; 106 107 void SetInitialEnvironment(HEnvironment* env); 108 void ClearEnvironment() { last_environment_ = NULL; } 109 bool HasEnvironment() const { return last_environment_ != NULL; } 110 void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; } 111 HBasicBlock* parent_loop_header() const { return parent_loop_header_; } 112 113 void set_parent_loop_header(HBasicBlock* block) { 114 ASSERT(parent_loop_header_ == NULL); 115 parent_loop_header_ = block; 116 } 117 118 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; } 119 120 void SetJoinId(int ast_id); 121 122 void Finish(HControlInstruction* last); 123 void FinishExit(HControlInstruction* instruction); 124 void Goto(HBasicBlock* block, bool drop_extra = false); 125 126 int PredecessorIndexOf(HBasicBlock* predecessor) const; 127 void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); } 128 void AssignCommonDominator(HBasicBlock* other); 129 void AssignLoopSuccessorDominators(); 130 131 void FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses) { 132 FinishExit(CreateDeoptimize(has_uses)); 133 } 134 135 // Add the inlined function exit sequence, adding an HLeaveInlined 136 // instruction and updating the bailout environment. 137 void AddLeaveInlined(HValue* return_value, 138 HBasicBlock* target, 139 bool drop_extra = false); 140 141 // If a target block is tagged as an inline function return, all 142 // predecessors should contain the inlined exit sequence: 143 // 144 // LeaveInlined 145 // Simulate (caller's environment) 146 // Goto (target block) 147 bool IsInlineReturnTarget() const { return is_inline_return_target_; } 148 void MarkAsInlineReturnTarget() { is_inline_return_target_ = true; } 149 150 bool IsDeoptimizing() const { return is_deoptimizing_; } 151 void MarkAsDeoptimizing() { is_deoptimizing_ = true; } 152 153 bool IsLoopSuccessorDominator() const { 154 return dominates_loop_successors_; 155 } 156 void MarkAsLoopSuccessorDominator() { 157 dominates_loop_successors_ = true; 158 } 159 160 inline Zone* zone(); 161 162 #ifdef DEBUG 163 void Verify(); 164 #endif 165 166 private: 167 void RegisterPredecessor(HBasicBlock* pred); 168 void AddDominatedBlock(HBasicBlock* block); 169 170 HSimulate* CreateSimulate(int ast_id); 171 HDeoptimize* CreateDeoptimize(HDeoptimize::UseEnvironment has_uses); 172 173 int block_id_; 174 HGraph* graph_; 175 ZoneList<HPhi*> phis_; 176 HInstruction* first_; 177 HInstruction* last_; 178 HControlInstruction* end_; 179 HLoopInformation* loop_information_; 180 ZoneList<HBasicBlock*> predecessors_; 181 HBasicBlock* dominator_; 182 ZoneList<HBasicBlock*> dominated_blocks_; 183 HEnvironment* last_environment_; 184 // Outgoing parameter count at block exit, set during lithium translation. 185 int argument_count_; 186 // Instruction indices into the lithium code stream. 187 int first_instruction_index_; 188 int last_instruction_index_; 189 ZoneList<int> deleted_phis_; 190 HBasicBlock* parent_loop_header_; 191 bool is_inline_return_target_; 192 bool is_deoptimizing_; 193 bool dominates_loop_successors_; 194 }; 195 196 197 class HPredecessorIterator BASE_EMBEDDED { 198 public: 199 explicit HPredecessorIterator(HBasicBlock* block) 200 : predecessor_list_(block->predecessors()), current_(0) { } 201 202 bool Done() { return current_ >= predecessor_list_->length(); } 203 HBasicBlock* Current() { return predecessor_list_->at(current_); } 204 void Advance() { current_++; } 205 206 private: 207 const ZoneList<HBasicBlock*>* predecessor_list_; 208 int current_; 209 }; 210 211 212 class HLoopInformation: public ZoneObject { 213 public: 214 explicit HLoopInformation(HBasicBlock* loop_header) 215 : back_edges_(4), 216 loop_header_(loop_header), 217 blocks_(8), 218 stack_check_(NULL) { 219 blocks_.Add(loop_header); 220 } 221 virtual ~HLoopInformation() {} 222 223 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; } 224 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } 225 HBasicBlock* loop_header() const { return loop_header_; } 226 HBasicBlock* GetLastBackEdge() const; 227 void RegisterBackEdge(HBasicBlock* block); 228 229 HStackCheck* stack_check() const { return stack_check_; } 230 void set_stack_check(HStackCheck* stack_check) { 231 stack_check_ = stack_check; 232 } 233 234 private: 235 void AddBlock(HBasicBlock* block); 236 237 ZoneList<HBasicBlock*> back_edges_; 238 HBasicBlock* loop_header_; 239 ZoneList<HBasicBlock*> blocks_; 240 HStackCheck* stack_check_; 241 }; 242 243 244 class HGraph: public ZoneObject { 245 public: 246 explicit HGraph(CompilationInfo* info); 247 248 Isolate* isolate() { return isolate_; } 249 Zone* zone() { return isolate_->zone(); } 250 251 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } 252 const ZoneList<HPhi*>* phi_list() const { return phi_list_; } 253 HBasicBlock* entry_block() const { return entry_block_; } 254 HEnvironment* start_environment() const { return start_environment_; } 255 256 void InitializeInferredTypes(); 257 void InsertTypeConversions(); 258 void InsertRepresentationChanges(); 259 void MarkDeoptimizeOnUndefined(); 260 void ComputeMinusZeroChecks(); 261 bool ProcessArgumentsObject(); 262 void EliminateRedundantPhis(); 263 void EliminateUnreachablePhis(); 264 void Canonicalize(); 265 void OrderBlocks(); 266 void AssignDominators(); 267 void ReplaceCheckedValues(); 268 void PropagateDeoptimizingMark(); 269 270 // Returns false if there are phi-uses of the arguments-object 271 // which are not supported by the optimizing compiler. 272 bool CheckArgumentsPhiUses(); 273 274 // Returns false if there are phi-uses of an uninitialized const 275 // which are not supported by the optimizing compiler. 276 bool CheckConstPhiUses(); 277 278 void CollectPhis(); 279 280 Handle<Code> Compile(CompilationInfo* info); 281 282 void set_undefined_constant(HConstant* constant) { 283 undefined_constant_.set(constant); 284 } 285 HConstant* GetConstantUndefined() const { return undefined_constant_.get(); } 286 HConstant* GetConstant1(); 287 HConstant* GetConstantMinus1(); 288 HConstant* GetConstantTrue(); 289 HConstant* GetConstantFalse(); 290 HConstant* GetConstantHole(); 291 292 HBasicBlock* CreateBasicBlock(); 293 HArgumentsObject* GetArgumentsObject() const { 294 return arguments_object_.get(); 295 } 296 297 void SetArgumentsObject(HArgumentsObject* object) { 298 arguments_object_.set(object); 299 } 300 301 int GetMaximumValueID() const { return values_.length(); } 302 int GetNextBlockID() { return next_block_id_++; } 303 int GetNextValueID(HValue* value) { 304 values_.Add(value); 305 return values_.length() - 1; 306 } 307 HValue* LookupValue(int id) const { 308 if (id >= 0 && id < values_.length()) return values_[id]; 309 return NULL; 310 } 311 312 #ifdef DEBUG 313 void Verify(bool do_full_verify) const; 314 #endif 315 316 bool has_osr_loop_entry() { 317 return osr_loop_entry_.is_set(); 318 } 319 320 HBasicBlock* osr_loop_entry() { 321 return osr_loop_entry_.get(); 322 } 323 324 void set_osr_loop_entry(HBasicBlock* entry) { 325 osr_loop_entry_.set(entry); 326 } 327 328 ZoneList<HUnknownOSRValue*>* osr_values() { 329 return osr_values_.get(); 330 } 331 332 void set_osr_values(ZoneList<HUnknownOSRValue*>* values) { 333 osr_values_.set(values); 334 } 335 336 private: 337 void Postorder(HBasicBlock* block, 338 BitVector* visited, 339 ZoneList<HBasicBlock*>* order, 340 HBasicBlock* loop_header); 341 void PostorderLoopBlocks(HLoopInformation* loop, 342 BitVector* visited, 343 ZoneList<HBasicBlock*>* order, 344 HBasicBlock* loop_header); 345 HConstant* GetConstant(SetOncePointer<HConstant>* pointer, 346 Object* value); 347 348 void MarkAsDeoptimizingRecursively(HBasicBlock* block); 349 void InsertTypeConversions(HInstruction* instr); 350 void PropagateMinusZeroChecks(HValue* value, BitVector* visited); 351 void RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi); 352 void InsertRepresentationChangeForUse(HValue* value, 353 HValue* use_value, 354 int use_index, 355 Representation to); 356 void InsertRepresentationChangesForValue(HValue* value); 357 void InferTypes(ZoneList<HValue*>* worklist); 358 void InitializeInferredTypes(int from_inclusive, int to_inclusive); 359 void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor); 360 361 Isolate* isolate_; 362 int next_block_id_; 363 HBasicBlock* entry_block_; 364 HEnvironment* start_environment_; 365 ZoneList<HBasicBlock*> blocks_; 366 ZoneList<HValue*> values_; 367 ZoneList<HPhi*>* phi_list_; 368 SetOncePointer<HConstant> undefined_constant_; 369 SetOncePointer<HConstant> constant_1_; 370 SetOncePointer<HConstant> constant_minus1_; 371 SetOncePointer<HConstant> constant_true_; 372 SetOncePointer<HConstant> constant_false_; 373 SetOncePointer<HConstant> constant_hole_; 374 SetOncePointer<HArgumentsObject> arguments_object_; 375 376 SetOncePointer<HBasicBlock> osr_loop_entry_; 377 SetOncePointer<ZoneList<HUnknownOSRValue*> > osr_values_; 378 379 DISALLOW_COPY_AND_ASSIGN(HGraph); 380 }; 381 382 383 Zone* HBasicBlock::zone() { return graph_->zone(); } 384 385 386 // Type of stack frame an environment might refer to. 387 enum FrameType { JS_FUNCTION, JS_CONSTRUCT, ARGUMENTS_ADAPTOR }; 388 389 390 class HEnvironment: public ZoneObject { 391 public: 392 HEnvironment(HEnvironment* outer, 393 Scope* scope, 394 Handle<JSFunction> closure); 395 396 HEnvironment* DiscardInlined(bool drop_extra) { 397 HEnvironment* outer = outer_; 398 while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_; 399 if (drop_extra) outer->Drop(1); 400 return outer; 401 } 402 403 HEnvironment* arguments_environment() { 404 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this; 405 } 406 407 // Simple accessors. 408 Handle<JSFunction> closure() const { return closure_; } 409 const ZoneList<HValue*>* values() const { return &values_; } 410 const ZoneList<int>* assigned_variables() const { 411 return &assigned_variables_; 412 } 413 FrameType frame_type() const { return frame_type_; } 414 int parameter_count() const { return parameter_count_; } 415 int specials_count() const { return specials_count_; } 416 int local_count() const { return local_count_; } 417 HEnvironment* outer() const { return outer_; } 418 int pop_count() const { return pop_count_; } 419 int push_count() const { return push_count_; } 420 421 int ast_id() const { return ast_id_; } 422 void set_ast_id(int id) { ast_id_ = id; } 423 424 int length() const { return values_.length(); } 425 bool is_special_index(int i) const { 426 return i >= parameter_count() && i < parameter_count() + specials_count(); 427 } 428 429 int first_expression_index() const { 430 return parameter_count() + specials_count() + local_count(); 431 } 432 433 void Bind(Variable* variable, HValue* value) { 434 Bind(IndexFor(variable), value); 435 } 436 437 void Bind(int index, HValue* value); 438 439 void BindContext(HValue* value) { 440 Bind(parameter_count(), value); 441 } 442 443 HValue* Lookup(Variable* variable) const { 444 return Lookup(IndexFor(variable)); 445 } 446 447 HValue* Lookup(int index) const { 448 HValue* result = values_[index]; 449 ASSERT(result != NULL); 450 return result; 451 } 452 453 HValue* LookupContext() const { 454 // Return first special. 455 return Lookup(parameter_count()); 456 } 457 458 void Push(HValue* value) { 459 ASSERT(value != NULL); 460 ++push_count_; 461 values_.Add(value); 462 } 463 464 HValue* Pop() { 465 ASSERT(!ExpressionStackIsEmpty()); 466 if (push_count_ > 0) { 467 --push_count_; 468 } else { 469 ++pop_count_; 470 } 471 return values_.RemoveLast(); 472 } 473 474 void Drop(int count); 475 476 HValue* Top() const { return ExpressionStackAt(0); } 477 478 bool ExpressionStackIsEmpty() const; 479 480 HValue* ExpressionStackAt(int index_from_top) const { 481 int index = length() - index_from_top - 1; 482 ASSERT(HasExpressionAt(index)); 483 return values_[index]; 484 } 485 486 void SetExpressionStackAt(int index_from_top, HValue* value); 487 488 HEnvironment* Copy() const; 489 HEnvironment* CopyWithoutHistory() const; 490 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const; 491 492 // Create an "inlined version" of this environment, where the original 493 // environment is the outer environment but the top expression stack 494 // elements are moved to an inner environment as parameters. 495 HEnvironment* CopyForInlining(Handle<JSFunction> target, 496 int arguments, 497 FunctionLiteral* function, 498 HConstant* undefined, 499 CallKind call_kind, 500 bool is_construct) const; 501 502 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other); 503 504 void ClearHistory() { 505 pop_count_ = 0; 506 push_count_ = 0; 507 assigned_variables_.Rewind(0); 508 } 509 510 void SetValueAt(int index, HValue* value) { 511 ASSERT(index < length()); 512 values_[index] = value; 513 } 514 515 void PrintTo(StringStream* stream); 516 void PrintToStd(); 517 518 private: 519 explicit HEnvironment(const HEnvironment* other); 520 521 HEnvironment(HEnvironment* outer, 522 Handle<JSFunction> closure, 523 FrameType frame_type, 524 int arguments); 525 526 // Create an artificial stub environment (e.g. for argument adaptor or 527 // constructor stub). 528 HEnvironment* CreateStubEnvironment(HEnvironment* outer, 529 Handle<JSFunction> target, 530 FrameType frame_type, 531 int arguments) const; 532 533 // True if index is included in the expression stack part of the environment. 534 bool HasExpressionAt(int index) const; 535 536 void Initialize(int parameter_count, int local_count, int stack_height); 537 void Initialize(const HEnvironment* other); 538 539 // Map a variable to an environment index. Parameter indices are shifted 540 // by 1 (receiver is parameter index -1 but environment index 0). 541 // Stack-allocated local indices are shifted by the number of parameters. 542 int IndexFor(Variable* variable) const { 543 ASSERT(variable->IsStackAllocated()); 544 int shift = variable->IsParameter() 545 ? 1 546 : parameter_count_ + specials_count_; 547 return variable->index() + shift; 548 } 549 550 Handle<JSFunction> closure_; 551 // Value array [parameters] [specials] [locals] [temporaries]. 552 ZoneList<HValue*> values_; 553 ZoneList<int> assigned_variables_; 554 FrameType frame_type_; 555 int parameter_count_; 556 int specials_count_; 557 int local_count_; 558 HEnvironment* outer_; 559 int pop_count_; 560 int push_count_; 561 int ast_id_; 562 }; 563 564 565 class HGraphBuilder; 566 567 enum ArgumentsAllowedFlag { 568 ARGUMENTS_NOT_ALLOWED, 569 ARGUMENTS_ALLOWED 570 }; 571 572 // This class is not BASE_EMBEDDED because our inlining implementation uses 573 // new and delete. 574 class AstContext { 575 public: 576 bool IsEffect() const { return kind_ == Expression::kEffect; } 577 bool IsValue() const { return kind_ == Expression::kValue; } 578 bool IsTest() const { return kind_ == Expression::kTest; } 579 580 // 'Fill' this context with a hydrogen value. The value is assumed to 581 // have already been inserted in the instruction stream (or not need to 582 // be, e.g., HPhi). Call this function in tail position in the Visit 583 // functions for expressions. 584 virtual void ReturnValue(HValue* value) = 0; 585 586 // Add a hydrogen instruction to the instruction stream (recording an 587 // environment simulation if necessary) and then fill this context with 588 // the instruction as value. 589 virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0; 590 591 // Finishes the current basic block and materialize a boolean for 592 // value context, nothing for effect, generate a branch for test context. 593 // Call this function in tail position in the Visit functions for 594 // expressions. 595 virtual void ReturnControl(HControlInstruction* instr, int ast_id) = 0; 596 597 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; } 598 bool is_for_typeof() { return for_typeof_; } 599 600 protected: 601 AstContext(HGraphBuilder* owner, Expression::Context kind); 602 virtual ~AstContext(); 603 604 HGraphBuilder* owner() const { return owner_; } 605 606 inline Zone* zone(); 607 608 // We want to be able to assert, in a context-specific way, that the stack 609 // height makes sense when the context is filled. 610 #ifdef DEBUG 611 int original_length_; 612 #endif 613 614 private: 615 HGraphBuilder* owner_; 616 Expression::Context kind_; 617 AstContext* outer_; 618 bool for_typeof_; 619 }; 620 621 622 class EffectContext: public AstContext { 623 public: 624 explicit EffectContext(HGraphBuilder* owner) 625 : AstContext(owner, Expression::kEffect) { 626 } 627 virtual ~EffectContext(); 628 629 virtual void ReturnValue(HValue* value); 630 virtual void ReturnInstruction(HInstruction* instr, int ast_id); 631 virtual void ReturnControl(HControlInstruction* instr, int ast_id); 632 }; 633 634 635 class ValueContext: public AstContext { 636 public: 637 explicit ValueContext(HGraphBuilder* owner, ArgumentsAllowedFlag flag) 638 : AstContext(owner, Expression::kValue), flag_(flag) { 639 } 640 virtual ~ValueContext(); 641 642 virtual void ReturnValue(HValue* value); 643 virtual void ReturnInstruction(HInstruction* instr, int ast_id); 644 virtual void ReturnControl(HControlInstruction* instr, int ast_id); 645 646 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; } 647 648 private: 649 ArgumentsAllowedFlag flag_; 650 }; 651 652 653 class TestContext: public AstContext { 654 public: 655 TestContext(HGraphBuilder* owner, 656 Expression* condition, 657 HBasicBlock* if_true, 658 HBasicBlock* if_false) 659 : AstContext(owner, Expression::kTest), 660 condition_(condition), 661 if_true_(if_true), 662 if_false_(if_false) { 663 } 664 665 virtual void ReturnValue(HValue* value); 666 virtual void ReturnInstruction(HInstruction* instr, int ast_id); 667 virtual void ReturnControl(HControlInstruction* instr, int ast_id); 668 669 static TestContext* cast(AstContext* context) { 670 ASSERT(context->IsTest()); 671 return reinterpret_cast<TestContext*>(context); 672 } 673 674 Expression* condition() const { return condition_; } 675 HBasicBlock* if_true() const { return if_true_; } 676 HBasicBlock* if_false() const { return if_false_; } 677 678 private: 679 // Build the shared core part of the translation unpacking a value into 680 // control flow. 681 void BuildBranch(HValue* value); 682 683 Expression* condition_; 684 HBasicBlock* if_true_; 685 HBasicBlock* if_false_; 686 }; 687 688 689 enum ReturnHandlingFlag { 690 NORMAL_RETURN, 691 DROP_EXTRA_ON_RETURN, 692 CONSTRUCT_CALL_RETURN 693 }; 694 695 696 class FunctionState { 697 public: 698 FunctionState(HGraphBuilder* owner, 699 CompilationInfo* info, 700 TypeFeedbackOracle* oracle, 701 ReturnHandlingFlag return_handling); 702 ~FunctionState(); 703 704 CompilationInfo* compilation_info() { return compilation_info_; } 705 TypeFeedbackOracle* oracle() { return oracle_; } 706 AstContext* call_context() { return call_context_; } 707 bool drop_extra() { return return_handling_ == DROP_EXTRA_ON_RETURN; } 708 bool is_construct() { return return_handling_ == CONSTRUCT_CALL_RETURN; } 709 HBasicBlock* function_return() { return function_return_; } 710 TestContext* test_context() { return test_context_; } 711 void ClearInlinedTestContext() { 712 delete test_context_; 713 test_context_ = NULL; 714 } 715 716 FunctionState* outer() { return outer_; } 717 718 private: 719 HGraphBuilder* owner_; 720 721 CompilationInfo* compilation_info_; 722 TypeFeedbackOracle* oracle_; 723 724 // During function inlining, expression context of the call being 725 // inlined. NULL when not inlining. 726 AstContext* call_context_; 727 728 // Indicate whether we have to perform special handling on return from 729 // inlined functions. 730 // - DROP_EXTRA_ON_RETURN: Drop an extra value from the environment. 731 // - CONSTRUCT_CALL_RETURN: Either use allocated receiver or return value. 732 ReturnHandlingFlag return_handling_; 733 734 // When inlining in an effect or value context, this is the return block. 735 // It is NULL otherwise. When inlining in a test context, there are a 736 // pair of return blocks in the context. When not inlining, there is no 737 // local return point. 738 HBasicBlock* function_return_; 739 740 // When inlining a call in a test context, a context containing a pair of 741 // return blocks. NULL in all other cases. 742 TestContext* test_context_; 743 744 FunctionState* outer_; 745 }; 746 747 748 class HGraphBuilder: public AstVisitor { 749 public: 750 enum BreakType { BREAK, CONTINUE }; 751 enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH }; 752 753 // A class encapsulating (lazily-allocated) break and continue blocks for 754 // a breakable statement. Separated from BreakAndContinueScope so that it 755 // can have a separate lifetime. 756 class BreakAndContinueInfo BASE_EMBEDDED { 757 public: 758 explicit BreakAndContinueInfo(BreakableStatement* target, 759 int drop_extra = 0) 760 : target_(target), 761 break_block_(NULL), 762 continue_block_(NULL), 763 drop_extra_(drop_extra) { 764 } 765 766 BreakableStatement* target() { return target_; } 767 HBasicBlock* break_block() { return break_block_; } 768 void set_break_block(HBasicBlock* block) { break_block_ = block; } 769 HBasicBlock* continue_block() { return continue_block_; } 770 void set_continue_block(HBasicBlock* block) { continue_block_ = block; } 771 int drop_extra() { return drop_extra_; } 772 773 private: 774 BreakableStatement* target_; 775 HBasicBlock* break_block_; 776 HBasicBlock* continue_block_; 777 int drop_extra_; 778 }; 779 780 // A helper class to maintain a stack of current BreakAndContinueInfo 781 // structures mirroring BreakableStatement nesting. 782 class BreakAndContinueScope BASE_EMBEDDED { 783 public: 784 BreakAndContinueScope(BreakAndContinueInfo* info, HGraphBuilder* owner) 785 : info_(info), owner_(owner), next_(owner->break_scope()) { 786 owner->set_break_scope(this); 787 } 788 789 ~BreakAndContinueScope() { owner_->set_break_scope(next_); } 790 791 BreakAndContinueInfo* info() { return info_; } 792 HGraphBuilder* owner() { return owner_; } 793 BreakAndContinueScope* next() { return next_; } 794 795 // Search the break stack for a break or continue target. 796 HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra); 797 798 private: 799 BreakAndContinueInfo* info_; 800 HGraphBuilder* owner_; 801 BreakAndContinueScope* next_; 802 }; 803 804 HGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle); 805 806 HGraph* CreateGraph(); 807 808 // Simple accessors. 809 HGraph* graph() const { return graph_; } 810 BreakAndContinueScope* break_scope() const { return break_scope_; } 811 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; } 812 813 HBasicBlock* current_block() const { return current_block_; } 814 void set_current_block(HBasicBlock* block) { current_block_ = block; } 815 HEnvironment* environment() const { 816 return current_block()->last_environment(); 817 } 818 819 bool inline_bailout() { return inline_bailout_; } 820 821 // Adding instructions. 822 HInstruction* AddInstruction(HInstruction* instr); 823 void AddSimulate(int ast_id); 824 825 // Bailout environment manipulation. 826 void Push(HValue* value) { environment()->Push(value); } 827 HValue* Pop() { return environment()->Pop(); } 828 829 void Bailout(const char* reason); 830 831 HBasicBlock* CreateJoin(HBasicBlock* first, 832 HBasicBlock* second, 833 int join_id); 834 835 TypeFeedbackOracle* oracle() const { return function_state()->oracle(); } 836 837 FunctionState* function_state() const { return function_state_; } 838 839 void VisitDeclarations(ZoneList<Declaration*>* declarations); 840 841 private: 842 // Type of a member function that generates inline code for a native function. 843 typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call); 844 845 // Forward declarations for inner scope classes. 846 class SubgraphScope; 847 848 static const InlineFunctionGenerator kInlineFunctionGenerators[]; 849 850 static const int kMaxCallPolymorphism = 4; 851 static const int kMaxLoadPolymorphism = 4; 852 static const int kMaxStorePolymorphism = 4; 853 854 static const int kMaxInlinedNodes = 196; 855 static const int kMaxInlinedSize = 196; 856 static const int kMaxSourceSize = 600; 857 858 // Even in the 'unlimited' case we have to have some limit in order not to 859 // overflow the stack. 860 static const int kUnlimitedMaxInlinedNodes = 1000; 861 static const int kUnlimitedMaxInlinedSize = 1000; 862 static const int kUnlimitedMaxSourceSize = 600; 863 864 // Simple accessors. 865 void set_function_state(FunctionState* state) { function_state_ = state; } 866 867 AstContext* ast_context() const { return ast_context_; } 868 void set_ast_context(AstContext* context) { ast_context_ = context; } 869 870 // Accessors forwarded to the function state. 871 CompilationInfo* info() const { 872 return function_state()->compilation_info(); 873 } 874 AstContext* call_context() const { 875 return function_state()->call_context(); 876 } 877 HBasicBlock* function_return() const { 878 return function_state()->function_return(); 879 } 880 TestContext* inlined_test_context() const { 881 return function_state()->test_context(); 882 } 883 void ClearInlinedTestContext() { 884 function_state()->ClearInlinedTestContext(); 885 } 886 StrictModeFlag function_strict_mode_flag() { 887 return function_state()->compilation_info()->is_classic_mode() 888 ? kNonStrictMode : kStrictMode; 889 } 890 891 // Generators for inline runtime functions. 892 #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \ 893 void Generate##Name(CallRuntime* call); 894 895 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) 896 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) 897 #undef INLINE_FUNCTION_GENERATOR_DECLARATION 898 899 void HandleDeclaration(VariableProxy* proxy, 900 VariableMode mode, 901 FunctionLiteral* function, 902 int* global_count); 903 904 void VisitDelete(UnaryOperation* expr); 905 void VisitVoid(UnaryOperation* expr); 906 void VisitTypeof(UnaryOperation* expr); 907 void VisitAdd(UnaryOperation* expr); 908 void VisitSub(UnaryOperation* expr); 909 void VisitBitNot(UnaryOperation* expr); 910 void VisitNot(UnaryOperation* expr); 911 912 void VisitComma(BinaryOperation* expr); 913 void VisitLogicalExpression(BinaryOperation* expr); 914 void VisitArithmeticExpression(BinaryOperation* expr); 915 916 bool PreProcessOsrEntry(IterationStatement* statement); 917 // True iff. we are compiling for OSR and the statement is the entry. 918 bool HasOsrEntryAt(IterationStatement* statement); 919 void VisitLoopBody(IterationStatement* stmt, 920 HBasicBlock* loop_entry, 921 BreakAndContinueInfo* break_info); 922 923 // Create a back edge in the flow graph. body_exit is the predecessor 924 // block and loop_entry is the successor block. loop_successor is the 925 // block where control flow exits the loop normally (e.g., via failure of 926 // the condition) and break_block is the block where control flow breaks 927 // from the loop. All blocks except loop_entry can be NULL. The return 928 // value is the new successor block which is the join of loop_successor 929 // and break_block, or NULL. 930 HBasicBlock* CreateLoop(IterationStatement* statement, 931 HBasicBlock* loop_entry, 932 HBasicBlock* body_exit, 933 HBasicBlock* loop_successor, 934 HBasicBlock* break_block); 935 936 HBasicBlock* JoinContinue(IterationStatement* statement, 937 HBasicBlock* exit_block, 938 HBasicBlock* continue_block); 939 940 HValue* Top() const { return environment()->Top(); } 941 void Drop(int n) { environment()->Drop(n); } 942 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); } 943 944 // The value of the arguments object is allowed in some but not most value 945 // contexts. (It's allowed in all effect contexts and disallowed in all 946 // test contexts.) 947 void VisitForValue(Expression* expr, 948 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED); 949 void VisitForTypeOf(Expression* expr); 950 void VisitForEffect(Expression* expr); 951 void VisitForControl(Expression* expr, 952 HBasicBlock* true_block, 953 HBasicBlock* false_block); 954 955 // Visit an argument subexpression and emit a push to the outgoing 956 // arguments. Returns the hydrogen value that was pushed. 957 HValue* VisitArgument(Expression* expr); 958 959 void VisitArgumentList(ZoneList<Expression*>* arguments); 960 961 // Visit a list of expressions from left to right, each in a value context. 962 void VisitExpressions(ZoneList<Expression*>* exprs); 963 964 void AddPhi(HPhi* phi); 965 966 void PushAndAdd(HInstruction* instr); 967 968 // Remove the arguments from the bailout environment and emit instructions 969 // to push them as outgoing parameters. 970 template <class Instruction> HInstruction* PreProcessCall(Instruction* call); 971 972 void TraceRepresentation(Token::Value op, 973 TypeInfo info, 974 HValue* value, 975 Representation rep); 976 static Representation ToRepresentation(TypeInfo info); 977 978 void SetUpScope(Scope* scope); 979 virtual void VisitStatements(ZoneList<Statement*>* statements); 980 981 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); 982 AST_NODE_LIST(DECLARE_VISIT) 983 #undef DECLARE_VISIT 984 985 HBasicBlock* CreateBasicBlock(HEnvironment* env); 986 HBasicBlock* CreateLoopHeaderBlock(); 987 988 // Helpers for flow graph construction. 989 enum GlobalPropertyAccess { 990 kUseCell, 991 kUseGeneric 992 }; 993 GlobalPropertyAccess LookupGlobalProperty(Variable* var, 994 LookupResult* lookup, 995 bool is_store); 996 997 bool TryArgumentsAccess(Property* expr); 998 999 // Try to optimize fun.apply(receiver, arguments) pattern. 1000 bool TryCallApply(Call* expr); 1001 1002 bool TryInline(CallKind call_kind, 1003 Handle<JSFunction> target, 1004 ZoneList<Expression*>* arguments, 1005 HValue* receiver, 1006 int ast_id, 1007 int return_id, 1008 ReturnHandlingFlag return_handling); 1009 1010 bool TryInlineCall(Call* expr, bool drop_extra = false); 1011 bool TryInlineConstruct(CallNew* expr, HValue* receiver); 1012 bool TryInlineBuiltinMethodCall(Call* expr, 1013 HValue* receiver, 1014 Handle<Map> receiver_map, 1015 CheckType check_type); 1016 bool TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra); 1017 1018 // If --trace-inlining, print a line of the inlining trace. Inlining 1019 // succeeded if the reason string is NULL and failed if there is a 1020 // non-NULL reason string. 1021 void TraceInline(Handle<JSFunction> target, 1022 Handle<JSFunction> caller, 1023 const char* failure_reason); 1024 1025 void HandleGlobalVariableAssignment(Variable* var, 1026 HValue* value, 1027 int position, 1028 int ast_id); 1029 1030 void HandlePropertyAssignment(Assignment* expr); 1031 void HandleCompoundAssignment(Assignment* expr); 1032 void HandlePolymorphicStoreNamedField(Assignment* expr, 1033 HValue* object, 1034 HValue* value, 1035 SmallMapList* types, 1036 Handle<String> name); 1037 void HandlePolymorphicCallNamed(Call* expr, 1038 HValue* receiver, 1039 SmallMapList* types, 1040 Handle<String> name); 1041 void HandleLiteralCompareTypeof(CompareOperation* expr, 1042 HTypeof* typeof_expr, 1043 Handle<String> check); 1044 void HandleLiteralCompareNil(CompareOperation* expr, 1045 HValue* value, 1046 NilValue nil); 1047 1048 HStringCharCodeAt* BuildStringCharCodeAt(HValue* context, 1049 HValue* string, 1050 HValue* index); 1051 HInstruction* BuildBinaryOperation(BinaryOperation* expr, 1052 HValue* left, 1053 HValue* right); 1054 HInstruction* BuildIncrement(bool returns_original_input, 1055 CountOperation* expr); 1056 HLoadNamedField* BuildLoadNamedField(HValue* object, 1057 Property* expr, 1058 Handle<Map> type, 1059 LookupResult* result, 1060 bool smi_and_map_check); 1061 HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr); 1062 HInstruction* BuildLoadKeyedGeneric(HValue* object, 1063 HValue* key); 1064 HInstruction* BuildExternalArrayElementAccess( 1065 HValue* external_elements, 1066 HValue* checked_key, 1067 HValue* val, 1068 ElementsKind elements_kind, 1069 bool is_store); 1070 HInstruction* BuildFastElementAccess(HValue* elements, 1071 HValue* checked_key, 1072 HValue* val, 1073 ElementsKind elements_kind, 1074 bool is_store); 1075 1076 HInstruction* BuildMonomorphicElementAccess(HValue* object, 1077 HValue* key, 1078 HValue* val, 1079 Handle<Map> map, 1080 bool is_store); 1081 HValue* HandlePolymorphicElementAccess(HValue* object, 1082 HValue* key, 1083 HValue* val, 1084 Expression* prop, 1085 int ast_id, 1086 int position, 1087 bool is_store, 1088 bool* has_side_effects); 1089 1090 HValue* HandleKeyedElementAccess(HValue* obj, 1091 HValue* key, 1092 HValue* val, 1093 Expression* expr, 1094 int ast_id, 1095 int position, 1096 bool is_store, 1097 bool* has_side_effects); 1098 1099 HInstruction* BuildLoadNamed(HValue* object, 1100 Property* prop, 1101 Handle<Map> map, 1102 Handle<String> name); 1103 HInstruction* BuildStoreNamed(HValue* object, 1104 HValue* value, 1105 Expression* expr); 1106 HInstruction* BuildStoreNamed(HValue* object, 1107 HValue* value, 1108 ObjectLiteral::Property* prop); 1109 HInstruction* BuildStoreNamedField(HValue* object, 1110 Handle<String> name, 1111 HValue* value, 1112 Handle<Map> type, 1113 LookupResult* lookup, 1114 bool smi_and_map_check); 1115 HInstruction* BuildStoreNamedGeneric(HValue* object, 1116 Handle<String> name, 1117 HValue* value); 1118 HInstruction* BuildStoreKeyedGeneric(HValue* object, 1119 HValue* key, 1120 HValue* value); 1121 1122 HValue* BuildContextChainWalk(Variable* var); 1123 1124 void AddCheckConstantFunction(Call* expr, 1125 HValue* receiver, 1126 Handle<Map> receiver_map, 1127 bool smi_and_map_check); 1128 1129 Zone* zone() { return zone_; } 1130 1131 // The translation state of the currently-being-translated function. 1132 FunctionState* function_state_; 1133 1134 // The base of the function state stack. 1135 FunctionState initial_function_state_; 1136 1137 // Expression context of the currently visited subexpression. NULL when 1138 // visiting statements. 1139 AstContext* ast_context_; 1140 1141 // A stack of breakable statements entered. 1142 BreakAndContinueScope* break_scope_; 1143 1144 HGraph* graph_; 1145 HBasicBlock* current_block_; 1146 1147 int inlined_count_; 1148 1149 Zone* zone_; 1150 1151 bool inline_bailout_; 1152 1153 friend class FunctionState; // Pushes and pops the state stack. 1154 friend class AstContext; // Pushes and pops the AST context stack. 1155 1156 DISALLOW_COPY_AND_ASSIGN(HGraphBuilder); 1157 }; 1158 1159 1160 Zone* AstContext::zone() { return owner_->zone(); } 1161 1162 1163 class HValueMap: public ZoneObject { 1164 public: 1165 HValueMap() 1166 : array_size_(0), 1167 lists_size_(0), 1168 count_(0), 1169 present_flags_(0), 1170 array_(NULL), 1171 lists_(NULL), 1172 free_list_head_(kNil) { 1173 ResizeLists(kInitialSize); 1174 Resize(kInitialSize); 1175 } 1176 1177 void Kill(GVNFlagSet flags); 1178 1179 void Add(HValue* value) { 1180 present_flags_.Add(value->gvn_flags()); 1181 Insert(value); 1182 } 1183 1184 HValue* Lookup(HValue* value) const; 1185 1186 HValueMap* Copy(Zone* zone) const { 1187 return new(zone) HValueMap(zone, this); 1188 } 1189 1190 bool IsEmpty() const { return count_ == 0; } 1191 1192 private: 1193 // A linked list of HValue* values. Stored in arrays. 1194 struct HValueMapListElement { 1195 HValue* value; 1196 int next; // Index in the array of the next list element. 1197 }; 1198 static const int kNil = -1; // The end of a linked list 1199 1200 // Must be a power of 2. 1201 static const int kInitialSize = 16; 1202 1203 HValueMap(Zone* zone, const HValueMap* other); 1204 1205 void Resize(int new_size); 1206 void ResizeLists(int new_size); 1207 void Insert(HValue* value); 1208 uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); } 1209 1210 int array_size_; 1211 int lists_size_; 1212 int count_; // The number of values stored in the HValueMap. 1213 GVNFlagSet present_flags_; // All flags that are in any value in the 1214 // HValueMap. 1215 HValueMapListElement* array_; // Primary store - contains the first value 1216 // with a given hash. Colliding elements are stored in linked lists. 1217 HValueMapListElement* lists_; // The linked lists containing hash collisions. 1218 int free_list_head_; // Unused elements in lists_ are on the free list. 1219 }; 1220 1221 1222 class HStatistics: public Malloced { 1223 public: 1224 void Initialize(CompilationInfo* info); 1225 void Print(); 1226 void SaveTiming(const char* name, int64_t ticks, unsigned size); 1227 static HStatistics* Instance() { 1228 static SetOncePointer<HStatistics> instance; 1229 if (!instance.is_set()) { 1230 instance.set(new HStatistics()); 1231 } 1232 return instance.get(); 1233 } 1234 1235 private: 1236 HStatistics() 1237 : timing_(5), 1238 names_(5), 1239 sizes_(5), 1240 total_(0), 1241 total_size_(0), 1242 full_code_gen_(0), 1243 source_size_(0) { } 1244 1245 List<int64_t> timing_; 1246 List<const char*> names_; 1247 List<unsigned> sizes_; 1248 int64_t total_; 1249 unsigned total_size_; 1250 int64_t full_code_gen_; 1251 double source_size_; 1252 }; 1253 1254 1255 class HPhase BASE_EMBEDDED { 1256 public: 1257 static const char* const kFullCodeGen; 1258 static const char* const kTotal; 1259 1260 explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); } 1261 HPhase(const char* name, HGraph* graph) { 1262 Begin(name, graph, NULL, NULL); 1263 } 1264 HPhase(const char* name, LChunk* chunk) { 1265 Begin(name, NULL, chunk, NULL); 1266 } 1267 HPhase(const char* name, LAllocator* allocator) { 1268 Begin(name, NULL, NULL, allocator); 1269 } 1270 1271 ~HPhase() { 1272 End(); 1273 } 1274 1275 private: 1276 void Begin(const char* name, 1277 HGraph* graph, 1278 LChunk* chunk, 1279 LAllocator* allocator); 1280 void End() const; 1281 1282 int64_t start_; 1283 const char* name_; 1284 HGraph* graph_; 1285 LChunk* chunk_; 1286 LAllocator* allocator_; 1287 unsigned start_allocation_size_; 1288 }; 1289 1290 1291 class HTracer: public Malloced { 1292 public: 1293 void TraceCompilation(FunctionLiteral* function); 1294 void TraceHydrogen(const char* name, HGraph* graph); 1295 void TraceLithium(const char* name, LChunk* chunk); 1296 void TraceLiveRanges(const char* name, LAllocator* allocator); 1297 1298 static HTracer* Instance() { 1299 static SetOncePointer<HTracer> instance; 1300 if (!instance.is_set()) { 1301 instance.set(new HTracer("hydrogen.cfg")); 1302 } 1303 return instance.get(); 1304 } 1305 1306 private: 1307 class Tag BASE_EMBEDDED { 1308 public: 1309 Tag(HTracer* tracer, const char* name) { 1310 name_ = name; 1311 tracer_ = tracer; 1312 tracer->PrintIndent(); 1313 tracer->trace_.Add("begin_%s\n", name); 1314 tracer->indent_++; 1315 } 1316 1317 ~Tag() { 1318 tracer_->indent_--; 1319 tracer_->PrintIndent(); 1320 tracer_->trace_.Add("end_%s\n", name_); 1321 ASSERT(tracer_->indent_ >= 0); 1322 tracer_->FlushToFile(); 1323 } 1324 1325 private: 1326 HTracer* tracer_; 1327 const char* name_; 1328 }; 1329 1330 explicit HTracer(const char* filename) 1331 : filename_(filename), trace_(&string_allocator_), indent_(0) { 1332 WriteChars(filename, "", 0, false); 1333 } 1334 1335 void TraceLiveRange(LiveRange* range, const char* type); 1336 void Trace(const char* name, HGraph* graph, LChunk* chunk); 1337 void FlushToFile(); 1338 1339 void PrintEmptyProperty(const char* name) { 1340 PrintIndent(); 1341 trace_.Add("%s\n", name); 1342 } 1343 1344 void PrintStringProperty(const char* name, const char* value) { 1345 PrintIndent(); 1346 trace_.Add("%s \"%s\"\n", name, value); 1347 } 1348 1349 void PrintLongProperty(const char* name, int64_t value) { 1350 PrintIndent(); 1351 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000)); 1352 } 1353 1354 void PrintBlockProperty(const char* name, int block_id) { 1355 PrintIndent(); 1356 trace_.Add("%s \"B%d\"\n", name, block_id); 1357 } 1358 1359 void PrintIntProperty(const char* name, int value) { 1360 PrintIndent(); 1361 trace_.Add("%s %d\n", name, value); 1362 } 1363 1364 void PrintIndent() { 1365 for (int i = 0; i < indent_; i++) { 1366 trace_.Add(" "); 1367 } 1368 } 1369 1370 const char* filename_; 1371 HeapStringAllocator string_allocator_; 1372 StringStream trace_; 1373 int indent_; 1374 }; 1375 1376 1377 } } // namespace v8::internal 1378 1379 #endif // V8_HYDROGEN_H_ 1380