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 "accessors.h" 34 #include "allocation.h" 35 #include "ast.h" 36 #include "compiler.h" 37 #include "hydrogen-instructions.h" 38 #include "zone.h" 39 #include "scopes.h" 40 41 namespace v8 { 42 namespace internal { 43 44 // Forward declarations. 45 class BitVector; 46 class FunctionState; 47 class HEnvironment; 48 class HGraph; 49 class HLoopInformation; 50 class HOsrBuilder; 51 class HTracer; 52 class LAllocator; 53 class LChunk; 54 class LiveRange; 55 56 57 class HBasicBlock V8_FINAL : public ZoneObject { 58 public: 59 explicit HBasicBlock(HGraph* graph); 60 ~HBasicBlock() { } 61 62 // Simple accessors. 63 int block_id() const { return block_id_; } 64 void set_block_id(int id) { block_id_ = id; } 65 HGraph* graph() const { return graph_; } 66 Isolate* isolate() const; 67 const ZoneList<HPhi*>* phis() const { return &phis_; } 68 HInstruction* first() const { return first_; } 69 HInstruction* last() const { return last_; } 70 void set_last(HInstruction* instr) { last_ = instr; } 71 HControlInstruction* end() const { return end_; } 72 HLoopInformation* loop_information() const { return loop_information_; } 73 HLoopInformation* current_loop() const { 74 return IsLoopHeader() ? loop_information() 75 : (parent_loop_header() != NULL 76 ? parent_loop_header()->loop_information() : NULL); 77 } 78 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; } 79 bool HasPredecessor() const { return predecessors_.length() > 0; } 80 const ZoneList<HBasicBlock*>* dominated_blocks() const { 81 return &dominated_blocks_; 82 } 83 const ZoneList<int>* deleted_phis() const { 84 return &deleted_phis_; 85 } 86 void RecordDeletedPhi(int merge_index) { 87 deleted_phis_.Add(merge_index, zone()); 88 } 89 HBasicBlock* dominator() const { return dominator_; } 90 HEnvironment* last_environment() const { return last_environment_; } 91 int argument_count() const { return argument_count_; } 92 void set_argument_count(int count) { argument_count_ = count; } 93 int first_instruction_index() const { return first_instruction_index_; } 94 void set_first_instruction_index(int index) { 95 first_instruction_index_ = index; 96 } 97 int last_instruction_index() const { return last_instruction_index_; } 98 void set_last_instruction_index(int index) { 99 last_instruction_index_ = index; 100 } 101 bool is_osr_entry() { return is_osr_entry_; } 102 void set_osr_entry() { is_osr_entry_ = true; } 103 104 void AttachLoopInformation(); 105 void DetachLoopInformation(); 106 bool IsLoopHeader() const { return loop_information() != NULL; } 107 bool IsStartBlock() const { return block_id() == 0; } 108 void PostProcessLoopHeader(IterationStatement* stmt); 109 110 bool IsFinished() const { return end_ != NULL; } 111 void AddPhi(HPhi* phi); 112 void RemovePhi(HPhi* phi); 113 void AddInstruction(HInstruction* instr, int position); 114 bool Dominates(HBasicBlock* other) const; 115 int LoopNestingDepth() const; 116 117 void SetInitialEnvironment(HEnvironment* env); 118 void ClearEnvironment() { 119 ASSERT(IsFinished()); 120 ASSERT(end()->SuccessorCount() == 0); 121 last_environment_ = NULL; 122 } 123 bool HasEnvironment() const { return last_environment_ != NULL; } 124 void UpdateEnvironment(HEnvironment* env); 125 HBasicBlock* parent_loop_header() const { return parent_loop_header_; } 126 127 void set_parent_loop_header(HBasicBlock* block) { 128 ASSERT(parent_loop_header_ == NULL); 129 parent_loop_header_ = block; 130 } 131 132 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; } 133 134 void SetJoinId(BailoutId ast_id); 135 136 int PredecessorIndexOf(HBasicBlock* predecessor) const; 137 HPhi* AddNewPhi(int merged_index); 138 HSimulate* AddNewSimulate(BailoutId ast_id, 139 int position, 140 RemovableSimulate removable = FIXED_SIMULATE) { 141 HSimulate* instr = CreateSimulate(ast_id, removable); 142 AddInstruction(instr, position); 143 return instr; 144 } 145 void AssignCommonDominator(HBasicBlock* other); 146 void AssignLoopSuccessorDominators(); 147 148 // If a target block is tagged as an inline function return, all 149 // predecessors should contain the inlined exit sequence: 150 // 151 // LeaveInlined 152 // Simulate (caller's environment) 153 // Goto (target block) 154 bool IsInlineReturnTarget() const { return is_inline_return_target_; } 155 void MarkAsInlineReturnTarget(HBasicBlock* inlined_entry_block) { 156 is_inline_return_target_ = true; 157 inlined_entry_block_ = inlined_entry_block; 158 } 159 HBasicBlock* inlined_entry_block() { return inlined_entry_block_; } 160 161 bool IsDeoptimizing() const { 162 return end() != NULL && end()->IsDeoptimize(); 163 } 164 165 void MarkUnreachable(); 166 bool IsUnreachable() const { return !is_reachable_; } 167 bool IsReachable() const { return is_reachable_; } 168 169 bool IsLoopSuccessorDominator() const { 170 return dominates_loop_successors_; 171 } 172 void MarkAsLoopSuccessorDominator() { 173 dominates_loop_successors_ = true; 174 } 175 176 inline Zone* zone() const; 177 178 #ifdef DEBUG 179 void Verify(); 180 #endif 181 182 protected: 183 friend class HGraphBuilder; 184 185 HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable); 186 void Finish(HControlInstruction* last, int position); 187 void FinishExit(HControlInstruction* instruction, int position); 188 void Goto(HBasicBlock* block, 189 int position, 190 FunctionState* state = NULL, 191 bool add_simulate = true); 192 void GotoNoSimulate(HBasicBlock* block, int position) { 193 Goto(block, position, NULL, false); 194 } 195 196 // Add the inlined function exit sequence, adding an HLeaveInlined 197 // instruction and updating the bailout environment. 198 void AddLeaveInlined(HValue* return_value, 199 FunctionState* state, 200 int position); 201 202 private: 203 void RegisterPredecessor(HBasicBlock* pred); 204 void AddDominatedBlock(HBasicBlock* block); 205 206 int block_id_; 207 HGraph* graph_; 208 ZoneList<HPhi*> phis_; 209 HInstruction* first_; 210 HInstruction* last_; 211 HControlInstruction* end_; 212 HLoopInformation* loop_information_; 213 ZoneList<HBasicBlock*> predecessors_; 214 HBasicBlock* dominator_; 215 ZoneList<HBasicBlock*> dominated_blocks_; 216 HEnvironment* last_environment_; 217 // Outgoing parameter count at block exit, set during lithium translation. 218 int argument_count_; 219 // Instruction indices into the lithium code stream. 220 int first_instruction_index_; 221 int last_instruction_index_; 222 ZoneList<int> deleted_phis_; 223 HBasicBlock* parent_loop_header_; 224 // For blocks marked as inline return target: the block with HEnterInlined. 225 HBasicBlock* inlined_entry_block_; 226 bool is_inline_return_target_ : 1; 227 bool is_reachable_ : 1; 228 bool dominates_loop_successors_ : 1; 229 bool is_osr_entry_ : 1; 230 }; 231 232 233 class HPredecessorIterator V8_FINAL BASE_EMBEDDED { 234 public: 235 explicit HPredecessorIterator(HBasicBlock* block) 236 : predecessor_list_(block->predecessors()), current_(0) { } 237 238 bool Done() { return current_ >= predecessor_list_->length(); } 239 HBasicBlock* Current() { return predecessor_list_->at(current_); } 240 void Advance() { current_++; } 241 242 private: 243 const ZoneList<HBasicBlock*>* predecessor_list_; 244 int current_; 245 }; 246 247 248 class HInstructionIterator V8_FINAL BASE_EMBEDDED { 249 public: 250 explicit HInstructionIterator(HBasicBlock* block) 251 : instr_(block->first()) { 252 next_ = Done() ? NULL : instr_->next(); 253 } 254 255 inline bool Done() const { return instr_ == NULL; } 256 inline HInstruction* Current() { return instr_; } 257 inline void Advance() { 258 instr_ = next_; 259 next_ = Done() ? NULL : instr_->next(); 260 } 261 262 private: 263 HInstruction* instr_; 264 HInstruction* next_; 265 }; 266 267 268 class HLoopInformation V8_FINAL : public ZoneObject { 269 public: 270 HLoopInformation(HBasicBlock* loop_header, Zone* zone) 271 : back_edges_(4, zone), 272 loop_header_(loop_header), 273 blocks_(8, zone), 274 stack_check_(NULL) { 275 blocks_.Add(loop_header, zone); 276 } 277 ~HLoopInformation() {} 278 279 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; } 280 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } 281 HBasicBlock* loop_header() const { return loop_header_; } 282 HBasicBlock* GetLastBackEdge() const; 283 void RegisterBackEdge(HBasicBlock* block); 284 285 HStackCheck* stack_check() const { return stack_check_; } 286 void set_stack_check(HStackCheck* stack_check) { 287 stack_check_ = stack_check; 288 } 289 290 bool IsNestedInThisLoop(HLoopInformation* other) { 291 while (other != NULL) { 292 if (other == this) { 293 return true; 294 } 295 other = other->parent_loop(); 296 } 297 return false; 298 } 299 HLoopInformation* parent_loop() { 300 HBasicBlock* parent_header = loop_header()->parent_loop_header(); 301 return parent_header != NULL ? parent_header->loop_information() : NULL; 302 } 303 304 private: 305 void AddBlock(HBasicBlock* block); 306 307 ZoneList<HBasicBlock*> back_edges_; 308 HBasicBlock* loop_header_; 309 ZoneList<HBasicBlock*> blocks_; 310 HStackCheck* stack_check_; 311 }; 312 313 314 class BoundsCheckTable; 315 class InductionVariableBlocksTable; 316 class HGraph V8_FINAL : public ZoneObject { 317 public: 318 explicit HGraph(CompilationInfo* info); 319 320 Isolate* isolate() const { return isolate_; } 321 Zone* zone() const { return zone_; } 322 CompilationInfo* info() const { return info_; } 323 324 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } 325 const ZoneList<HPhi*>* phi_list() const { return phi_list_; } 326 HBasicBlock* entry_block() const { return entry_block_; } 327 HEnvironment* start_environment() const { return start_environment_; } 328 329 void FinalizeUniqueness(); 330 bool ProcessArgumentsObject(); 331 void OrderBlocks(); 332 void AssignDominators(); 333 void RestoreActualValues(); 334 335 // Returns false if there are phi-uses of the arguments-object 336 // which are not supported by the optimizing compiler. 337 bool CheckArgumentsPhiUses(); 338 339 // Returns false if there are phi-uses of an uninitialized const 340 // which are not supported by the optimizing compiler. 341 bool CheckConstPhiUses(); 342 343 void CollectPhis(); 344 345 HConstant* GetConstantUndefined(); 346 HConstant* GetConstant0(); 347 HConstant* GetConstant1(); 348 HConstant* GetConstantMinus1(); 349 HConstant* GetConstantTrue(); 350 HConstant* GetConstantFalse(); 351 HConstant* GetConstantHole(); 352 HConstant* GetConstantNull(); 353 HConstant* GetInvalidContext(); 354 355 bool IsConstantUndefined(HConstant* constant); 356 bool IsConstant0(HConstant* constant); 357 bool IsConstant1(HConstant* constant); 358 bool IsConstantMinus1(HConstant* constant); 359 bool IsConstantTrue(HConstant* constant); 360 bool IsConstantFalse(HConstant* constant); 361 bool IsConstantHole(HConstant* constant); 362 bool IsConstantNull(HConstant* constant); 363 bool IsStandardConstant(HConstant* constant); 364 365 HBasicBlock* CreateBasicBlock(); 366 HArgumentsObject* GetArgumentsObject() const { 367 return arguments_object_.get(); 368 } 369 370 void SetArgumentsObject(HArgumentsObject* object) { 371 arguments_object_.set(object); 372 } 373 374 int GetMaximumValueID() const { return values_.length(); } 375 int GetNextBlockID() { return next_block_id_++; } 376 int GetNextValueID(HValue* value) { 377 ASSERT(!disallow_adding_new_values_); 378 values_.Add(value, zone()); 379 return values_.length() - 1; 380 } 381 HValue* LookupValue(int id) const { 382 if (id >= 0 && id < values_.length()) return values_[id]; 383 return NULL; 384 } 385 void DisallowAddingNewValues() { 386 disallow_adding_new_values_ = true; 387 } 388 389 bool Optimize(BailoutReason* bailout_reason); 390 391 #ifdef DEBUG 392 void Verify(bool do_full_verify) const; 393 #endif 394 395 bool has_osr() { 396 return osr_ != NULL; 397 } 398 399 void set_osr(HOsrBuilder* osr) { 400 osr_ = osr; 401 } 402 403 HOsrBuilder* osr() { 404 return osr_; 405 } 406 407 int update_type_change_checksum(int delta) { 408 type_change_checksum_ += delta; 409 return type_change_checksum_; 410 } 411 412 void update_maximum_environment_size(int environment_size) { 413 if (environment_size > maximum_environment_size_) { 414 maximum_environment_size_ = environment_size; 415 } 416 } 417 int maximum_environment_size() { return maximum_environment_size_; } 418 419 bool use_optimistic_licm() { 420 return use_optimistic_licm_; 421 } 422 423 void set_use_optimistic_licm(bool value) { 424 use_optimistic_licm_ = value; 425 } 426 427 void MarkRecursive() { 428 is_recursive_ = true; 429 } 430 431 bool is_recursive() const { 432 return is_recursive_; 433 } 434 435 void MarkDependsOnEmptyArrayProtoElements() { 436 // Add map dependency if not already added. 437 if (depends_on_empty_array_proto_elements_) return; 438 isolate()->initial_object_prototype()->map()->AddDependentCompilationInfo( 439 DependentCode::kElementsCantBeAddedGroup, info()); 440 isolate()->initial_array_prototype()->map()->AddDependentCompilationInfo( 441 DependentCode::kElementsCantBeAddedGroup, info()); 442 depends_on_empty_array_proto_elements_ = true; 443 } 444 445 bool depends_on_empty_array_proto_elements() { 446 return depends_on_empty_array_proto_elements_; 447 } 448 449 bool has_uint32_instructions() { 450 ASSERT(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); 451 return uint32_instructions_ != NULL; 452 } 453 454 ZoneList<HInstruction*>* uint32_instructions() { 455 ASSERT(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); 456 return uint32_instructions_; 457 } 458 459 void RecordUint32Instruction(HInstruction* instr) { 460 ASSERT(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); 461 if (uint32_instructions_ == NULL) { 462 uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone()); 463 } 464 uint32_instructions_->Add(instr, zone()); 465 } 466 467 void IncrementInNoSideEffectsScope() { no_side_effects_scope_count_++; } 468 void DecrementInNoSideEffectsScope() { no_side_effects_scope_count_--; } 469 bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; } 470 471 private: 472 HConstant* ReinsertConstantIfNecessary(HConstant* constant); 473 HConstant* GetConstant(SetOncePointer<HConstant>* pointer, 474 int32_t integer_value); 475 476 template<class Phase> 477 void Run() { 478 Phase phase(this); 479 phase.Run(); 480 } 481 482 void EliminateRedundantBoundsChecksUsingInductionVariables(); 483 484 Isolate* isolate_; 485 int next_block_id_; 486 HBasicBlock* entry_block_; 487 HEnvironment* start_environment_; 488 ZoneList<HBasicBlock*> blocks_; 489 ZoneList<HValue*> values_; 490 ZoneList<HPhi*>* phi_list_; 491 ZoneList<HInstruction*>* uint32_instructions_; 492 SetOncePointer<HConstant> constant_undefined_; 493 SetOncePointer<HConstant> constant_0_; 494 SetOncePointer<HConstant> constant_1_; 495 SetOncePointer<HConstant> constant_minus1_; 496 SetOncePointer<HConstant> constant_true_; 497 SetOncePointer<HConstant> constant_false_; 498 SetOncePointer<HConstant> constant_the_hole_; 499 SetOncePointer<HConstant> constant_null_; 500 SetOncePointer<HConstant> constant_invalid_context_; 501 SetOncePointer<HArgumentsObject> arguments_object_; 502 503 HOsrBuilder* osr_; 504 505 CompilationInfo* info_; 506 Zone* zone_; 507 508 bool is_recursive_; 509 bool use_optimistic_licm_; 510 bool depends_on_empty_array_proto_elements_; 511 int type_change_checksum_; 512 int maximum_environment_size_; 513 int no_side_effects_scope_count_; 514 bool disallow_adding_new_values_; 515 516 DISALLOW_COPY_AND_ASSIGN(HGraph); 517 }; 518 519 520 Zone* HBasicBlock::zone() const { return graph_->zone(); } 521 522 523 // Type of stack frame an environment might refer to. 524 enum FrameType { 525 JS_FUNCTION, 526 JS_CONSTRUCT, 527 JS_GETTER, 528 JS_SETTER, 529 ARGUMENTS_ADAPTOR, 530 STUB 531 }; 532 533 534 class HEnvironment V8_FINAL : public ZoneObject { 535 public: 536 HEnvironment(HEnvironment* outer, 537 Scope* scope, 538 Handle<JSFunction> closure, 539 Zone* zone); 540 541 HEnvironment(Zone* zone, int parameter_count); 542 543 HEnvironment* arguments_environment() { 544 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this; 545 } 546 547 // Simple accessors. 548 Handle<JSFunction> closure() const { return closure_; } 549 const ZoneList<HValue*>* values() const { return &values_; } 550 const GrowableBitVector* assigned_variables() const { 551 return &assigned_variables_; 552 } 553 FrameType frame_type() const { return frame_type_; } 554 int parameter_count() const { return parameter_count_; } 555 int specials_count() const { return specials_count_; } 556 int local_count() const { return local_count_; } 557 HEnvironment* outer() const { return outer_; } 558 int pop_count() const { return pop_count_; } 559 int push_count() const { return push_count_; } 560 561 BailoutId ast_id() const { return ast_id_; } 562 void set_ast_id(BailoutId id) { ast_id_ = id; } 563 564 HEnterInlined* entry() const { return entry_; } 565 void set_entry(HEnterInlined* entry) { entry_ = entry; } 566 567 int length() const { return values_.length(); } 568 569 int first_expression_index() const { 570 return parameter_count() + specials_count() + local_count(); 571 } 572 573 int first_local_index() const { 574 return parameter_count() + specials_count(); 575 } 576 577 void Bind(Variable* variable, HValue* value) { 578 Bind(IndexFor(variable), value); 579 } 580 581 void Bind(int index, HValue* value); 582 583 void BindContext(HValue* value) { 584 Bind(parameter_count(), value); 585 } 586 587 HValue* Lookup(Variable* variable) const { 588 return Lookup(IndexFor(variable)); 589 } 590 591 HValue* Lookup(int index) const { 592 HValue* result = values_[index]; 593 ASSERT(result != NULL); 594 return result; 595 } 596 597 HValue* context() const { 598 // Return first special. 599 return Lookup(parameter_count()); 600 } 601 602 void Push(HValue* value) { 603 ASSERT(value != NULL); 604 ++push_count_; 605 values_.Add(value, zone()); 606 } 607 608 HValue* Pop() { 609 ASSERT(!ExpressionStackIsEmpty()); 610 if (push_count_ > 0) { 611 --push_count_; 612 } else { 613 ++pop_count_; 614 } 615 return values_.RemoveLast(); 616 } 617 618 void Drop(int count); 619 620 HValue* Top() const { return ExpressionStackAt(0); } 621 622 bool ExpressionStackIsEmpty() const; 623 624 HValue* ExpressionStackAt(int index_from_top) const { 625 int index = length() - index_from_top - 1; 626 ASSERT(HasExpressionAt(index)); 627 return values_[index]; 628 } 629 630 void SetExpressionStackAt(int index_from_top, HValue* value); 631 632 HEnvironment* Copy() const; 633 HEnvironment* CopyWithoutHistory() const; 634 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const; 635 636 // Create an "inlined version" of this environment, where the original 637 // environment is the outer environment but the top expression stack 638 // elements are moved to an inner environment as parameters. 639 HEnvironment* CopyForInlining(Handle<JSFunction> target, 640 int arguments, 641 FunctionLiteral* function, 642 HConstant* undefined, 643 InliningKind inlining_kind, 644 bool undefined_receiver) const; 645 646 static bool UseUndefinedReceiver(Handle<JSFunction> closure, 647 FunctionLiteral* function, 648 CallKind call_kind, 649 InliningKind inlining_kind) { 650 return (closure->shared()->native() || !function->is_classic_mode()) && 651 call_kind == CALL_AS_FUNCTION && inlining_kind != CONSTRUCT_CALL_RETURN; 652 } 653 654 HEnvironment* DiscardInlined(bool drop_extra) { 655 HEnvironment* outer = outer_; 656 while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_; 657 if (drop_extra) outer->Drop(1); 658 return outer; 659 } 660 661 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other); 662 663 void ClearHistory() { 664 pop_count_ = 0; 665 push_count_ = 0; 666 assigned_variables_.Clear(); 667 } 668 669 void SetValueAt(int index, HValue* value) { 670 ASSERT(index < length()); 671 values_[index] = value; 672 } 673 674 // Map a variable to an environment index. Parameter indices are shifted 675 // by 1 (receiver is parameter index -1 but environment index 0). 676 // Stack-allocated local indices are shifted by the number of parameters. 677 int IndexFor(Variable* variable) const { 678 ASSERT(variable->IsStackAllocated()); 679 int shift = variable->IsParameter() 680 ? 1 681 : parameter_count_ + specials_count_; 682 return variable->index() + shift; 683 } 684 685 bool is_local_index(int i) const { 686 return i >= first_local_index() && i < first_expression_index(); 687 } 688 689 bool is_parameter_index(int i) const { 690 return i >= 0 && i < parameter_count(); 691 } 692 693 bool is_special_index(int i) const { 694 return i >= parameter_count() && i < parameter_count() + specials_count(); 695 } 696 697 void PrintTo(StringStream* stream); 698 void PrintToStd(); 699 700 Zone* zone() const { return zone_; } 701 702 private: 703 HEnvironment(const HEnvironment* other, Zone* zone); 704 705 HEnvironment(HEnvironment* outer, 706 Handle<JSFunction> closure, 707 FrameType frame_type, 708 int arguments, 709 Zone* zone); 710 711 // Create an artificial stub environment (e.g. for argument adaptor or 712 // constructor stub). 713 HEnvironment* CreateStubEnvironment(HEnvironment* outer, 714 Handle<JSFunction> target, 715 FrameType frame_type, 716 int arguments) const; 717 718 // True if index is included in the expression stack part of the environment. 719 bool HasExpressionAt(int index) const; 720 721 void Initialize(int parameter_count, int local_count, int stack_height); 722 void Initialize(const HEnvironment* other); 723 724 Handle<JSFunction> closure_; 725 // Value array [parameters] [specials] [locals] [temporaries]. 726 ZoneList<HValue*> values_; 727 GrowableBitVector assigned_variables_; 728 FrameType frame_type_; 729 int parameter_count_; 730 int specials_count_; 731 int local_count_; 732 HEnvironment* outer_; 733 HEnterInlined* entry_; 734 int pop_count_; 735 int push_count_; 736 BailoutId ast_id_; 737 Zone* zone_; 738 }; 739 740 741 class HOptimizedGraphBuilder; 742 743 enum ArgumentsAllowedFlag { 744 ARGUMENTS_NOT_ALLOWED, 745 ARGUMENTS_ALLOWED 746 }; 747 748 749 class HIfContinuation; 750 751 // This class is not BASE_EMBEDDED because our inlining implementation uses 752 // new and delete. 753 class AstContext { 754 public: 755 bool IsEffect() const { return kind_ == Expression::kEffect; } 756 bool IsValue() const { return kind_ == Expression::kValue; } 757 bool IsTest() const { return kind_ == Expression::kTest; } 758 759 // 'Fill' this context with a hydrogen value. The value is assumed to 760 // have already been inserted in the instruction stream (or not need to 761 // be, e.g., HPhi). Call this function in tail position in the Visit 762 // functions for expressions. 763 virtual void ReturnValue(HValue* value) = 0; 764 765 // Add a hydrogen instruction to the instruction stream (recording an 766 // environment simulation if necessary) and then fill this context with 767 // the instruction as value. 768 virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id) = 0; 769 770 // Finishes the current basic block and materialize a boolean for 771 // value context, nothing for effect, generate a branch for test context. 772 // Call this function in tail position in the Visit functions for 773 // expressions. 774 virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id) = 0; 775 776 // Finishes the current basic block and materialize a boolean for 777 // value context, nothing for effect, generate a branch for test context. 778 // Call this function in tail position in the Visit functions for 779 // expressions that use an IfBuilder. 780 virtual void ReturnContinuation(HIfContinuation* continuation, 781 BailoutId ast_id) = 0; 782 783 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; } 784 bool is_for_typeof() { return for_typeof_; } 785 786 protected: 787 AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind); 788 virtual ~AstContext(); 789 790 HOptimizedGraphBuilder* owner() const { return owner_; } 791 792 inline Zone* zone() const; 793 794 // We want to be able to assert, in a context-specific way, that the stack 795 // height makes sense when the context is filled. 796 #ifdef DEBUG 797 int original_length_; 798 #endif 799 800 private: 801 HOptimizedGraphBuilder* owner_; 802 Expression::Context kind_; 803 AstContext* outer_; 804 bool for_typeof_; 805 }; 806 807 808 class EffectContext V8_FINAL : public AstContext { 809 public: 810 explicit EffectContext(HOptimizedGraphBuilder* owner) 811 : AstContext(owner, Expression::kEffect) { 812 } 813 virtual ~EffectContext(); 814 815 virtual void ReturnValue(HValue* value) V8_OVERRIDE; 816 virtual void ReturnInstruction(HInstruction* instr, 817 BailoutId ast_id) V8_OVERRIDE; 818 virtual void ReturnControl(HControlInstruction* instr, 819 BailoutId ast_id) V8_OVERRIDE; 820 virtual void ReturnContinuation(HIfContinuation* continuation, 821 BailoutId ast_id) V8_OVERRIDE; 822 }; 823 824 825 class ValueContext V8_FINAL : public AstContext { 826 public: 827 ValueContext(HOptimizedGraphBuilder* owner, ArgumentsAllowedFlag flag) 828 : AstContext(owner, Expression::kValue), flag_(flag) { 829 } 830 virtual ~ValueContext(); 831 832 virtual void ReturnValue(HValue* value) V8_OVERRIDE; 833 virtual void ReturnInstruction(HInstruction* instr, 834 BailoutId ast_id) V8_OVERRIDE; 835 virtual void ReturnControl(HControlInstruction* instr, 836 BailoutId ast_id) V8_OVERRIDE; 837 virtual void ReturnContinuation(HIfContinuation* continuation, 838 BailoutId ast_id) V8_OVERRIDE; 839 840 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; } 841 842 private: 843 ArgumentsAllowedFlag flag_; 844 }; 845 846 847 class TestContext V8_FINAL : public AstContext { 848 public: 849 TestContext(HOptimizedGraphBuilder* owner, 850 Expression* condition, 851 HBasicBlock* if_true, 852 HBasicBlock* if_false) 853 : AstContext(owner, Expression::kTest), 854 condition_(condition), 855 if_true_(if_true), 856 if_false_(if_false) { 857 } 858 859 virtual void ReturnValue(HValue* value) V8_OVERRIDE; 860 virtual void ReturnInstruction(HInstruction* instr, 861 BailoutId ast_id) V8_OVERRIDE; 862 virtual void ReturnControl(HControlInstruction* instr, 863 BailoutId ast_id) V8_OVERRIDE; 864 virtual void ReturnContinuation(HIfContinuation* continuation, 865 BailoutId ast_id) V8_OVERRIDE; 866 867 static TestContext* cast(AstContext* context) { 868 ASSERT(context->IsTest()); 869 return reinterpret_cast<TestContext*>(context); 870 } 871 872 Expression* condition() const { return condition_; } 873 HBasicBlock* if_true() const { return if_true_; } 874 HBasicBlock* if_false() const { return if_false_; } 875 876 private: 877 // Build the shared core part of the translation unpacking a value into 878 // control flow. 879 void BuildBranch(HValue* value); 880 881 Expression* condition_; 882 HBasicBlock* if_true_; 883 HBasicBlock* if_false_; 884 }; 885 886 887 class FunctionState V8_FINAL { 888 public: 889 FunctionState(HOptimizedGraphBuilder* owner, 890 CompilationInfo* info, 891 InliningKind inlining_kind); 892 ~FunctionState(); 893 894 CompilationInfo* compilation_info() { return compilation_info_; } 895 AstContext* call_context() { return call_context_; } 896 InliningKind inlining_kind() const { return inlining_kind_; } 897 HBasicBlock* function_return() { return function_return_; } 898 TestContext* test_context() { return test_context_; } 899 void ClearInlinedTestContext() { 900 delete test_context_; 901 test_context_ = NULL; 902 } 903 904 FunctionState* outer() { return outer_; } 905 906 HEnterInlined* entry() { return entry_; } 907 void set_entry(HEnterInlined* entry) { entry_ = entry; } 908 909 HArgumentsObject* arguments_object() { return arguments_object_; } 910 void set_arguments_object(HArgumentsObject* arguments_object) { 911 arguments_object_ = arguments_object; 912 } 913 914 HArgumentsElements* arguments_elements() { return arguments_elements_; } 915 void set_arguments_elements(HArgumentsElements* arguments_elements) { 916 arguments_elements_ = arguments_elements; 917 } 918 919 bool arguments_pushed() { return arguments_elements() != NULL; } 920 921 private: 922 HOptimizedGraphBuilder* owner_; 923 924 CompilationInfo* compilation_info_; 925 926 // During function inlining, expression context of the call being 927 // inlined. NULL when not inlining. 928 AstContext* call_context_; 929 930 // The kind of call which is currently being inlined. 931 InliningKind inlining_kind_; 932 933 // When inlining in an effect or value context, this is the return block. 934 // It is NULL otherwise. When inlining in a test context, there are a 935 // pair of return blocks in the context. When not inlining, there is no 936 // local return point. 937 HBasicBlock* function_return_; 938 939 // When inlining a call in a test context, a context containing a pair of 940 // return blocks. NULL in all other cases. 941 TestContext* test_context_; 942 943 // When inlining HEnterInlined instruction corresponding to the function 944 // entry. 945 HEnterInlined* entry_; 946 947 HArgumentsObject* arguments_object_; 948 HArgumentsElements* arguments_elements_; 949 950 FunctionState* outer_; 951 }; 952 953 954 class HIfContinuation V8_FINAL { 955 public: 956 HIfContinuation() 957 : continuation_captured_(false), 958 true_branch_(NULL), 959 false_branch_(NULL) {} 960 HIfContinuation(HBasicBlock* true_branch, 961 HBasicBlock* false_branch) 962 : continuation_captured_(true), true_branch_(true_branch), 963 false_branch_(false_branch) {} 964 ~HIfContinuation() { ASSERT(!continuation_captured_); } 965 966 void Capture(HBasicBlock* true_branch, 967 HBasicBlock* false_branch) { 968 ASSERT(!continuation_captured_); 969 true_branch_ = true_branch; 970 false_branch_ = false_branch; 971 continuation_captured_ = true; 972 } 973 974 void Continue(HBasicBlock** true_branch, 975 HBasicBlock** false_branch) { 976 ASSERT(continuation_captured_); 977 *true_branch = true_branch_; 978 *false_branch = false_branch_; 979 continuation_captured_ = false; 980 } 981 982 bool IsTrueReachable() { return true_branch_ != NULL; } 983 bool IsFalseReachable() { return false_branch_ != NULL; } 984 bool TrueAndFalseReachable() { 985 return IsTrueReachable() || IsFalseReachable(); 986 } 987 988 HBasicBlock* true_branch() const { return true_branch_; } 989 HBasicBlock* false_branch() const { return false_branch_; } 990 991 private: 992 bool continuation_captured_; 993 HBasicBlock* true_branch_; 994 HBasicBlock* false_branch_; 995 }; 996 997 998 class HGraphBuilder { 999 public: 1000 explicit HGraphBuilder(CompilationInfo* info) 1001 : info_(info), 1002 graph_(NULL), 1003 current_block_(NULL), 1004 position_(RelocInfo::kNoPosition) {} 1005 virtual ~HGraphBuilder() {} 1006 1007 HBasicBlock* current_block() const { return current_block_; } 1008 void set_current_block(HBasicBlock* block) { current_block_ = block; } 1009 HEnvironment* environment() const { 1010 return current_block()->last_environment(); 1011 } 1012 Zone* zone() const { return info_->zone(); } 1013 HGraph* graph() const { return graph_; } 1014 Isolate* isolate() const { return graph_->isolate(); } 1015 CompilationInfo* top_info() { return info_; } 1016 1017 HGraph* CreateGraph(); 1018 1019 // Bailout environment manipulation. 1020 void Push(HValue* value) { environment()->Push(value); } 1021 HValue* Pop() { return environment()->Pop(); } 1022 1023 virtual HValue* context() = 0; 1024 1025 // Adding instructions. 1026 HInstruction* AddInstruction(HInstruction* instr); 1027 void FinishCurrentBlock(HControlInstruction* last); 1028 void FinishExitCurrentBlock(HControlInstruction* instruction); 1029 1030 void Goto(HBasicBlock* from, 1031 HBasicBlock* target, 1032 FunctionState* state = NULL, 1033 bool add_simulate = true) { 1034 from->Goto(target, position_, state, add_simulate); 1035 } 1036 void Goto(HBasicBlock* target, 1037 FunctionState* state = NULL, 1038 bool add_simulate = true) { 1039 Goto(current_block(), target, state, add_simulate); 1040 } 1041 void GotoNoSimulate(HBasicBlock* from, HBasicBlock* target) { 1042 Goto(from, target, NULL, false); 1043 } 1044 void GotoNoSimulate(HBasicBlock* target) { 1045 Goto(target, NULL, false); 1046 } 1047 void AddLeaveInlined(HBasicBlock* block, 1048 HValue* return_value, 1049 FunctionState* state) { 1050 block->AddLeaveInlined(return_value, state, position_); 1051 } 1052 void AddLeaveInlined(HValue* return_value, FunctionState* state) { 1053 return AddLeaveInlined(current_block(), return_value, state); 1054 } 1055 1056 template<class I> 1057 HInstruction* NewUncasted() { return I::New(zone(), context()); } 1058 1059 template<class I> 1060 I* New() { return I::New(zone(), context()); } 1061 1062 template<class I> 1063 HInstruction* AddUncasted() { return AddInstruction(NewUncasted<I>());} 1064 1065 template<class I> 1066 I* Add() { return AddInstructionTyped(New<I>());} 1067 1068 template<class I, class P1> 1069 HInstruction* NewUncasted(P1 p1) { 1070 return I::New(zone(), context(), p1); 1071 } 1072 1073 template<class I, class P1> 1074 I* New(P1 p1) { return I::New(zone(), context(), p1); } 1075 1076 template<class I, class P1> 1077 HInstruction* AddUncasted(P1 p1) { 1078 HInstruction* result = AddInstruction(NewUncasted<I>(p1)); 1079 // Specializations must have their parameters properly casted 1080 // to avoid landing here. 1081 ASSERT(!result->IsReturn() && !result->IsSimulate() && 1082 !result->IsDeoptimize()); 1083 return result; 1084 } 1085 1086 template<class I, class P1> 1087 I* Add(P1 p1) { 1088 I* result = AddInstructionTyped(New<I>(p1)); 1089 // Specializations must have their parameters properly casted 1090 // to avoid landing here. 1091 ASSERT(!result->IsReturn() && !result->IsSimulate() && 1092 !result->IsDeoptimize()); 1093 return result; 1094 } 1095 1096 template<class I, class P1, class P2> 1097 HInstruction* NewUncasted(P1 p1, P2 p2) { 1098 return I::New(zone(), context(), p1, p2); 1099 } 1100 1101 template<class I, class P1, class P2> 1102 I* New(P1 p1, P2 p2) { 1103 return I::New(zone(), context(), p1, p2); 1104 } 1105 1106 template<class I, class P1, class P2> 1107 HInstruction* AddUncasted(P1 p1, P2 p2) { 1108 HInstruction* result = AddInstruction(NewUncasted<I>(p1, p2)); 1109 // Specializations must have their parameters properly casted 1110 // to avoid landing here. 1111 ASSERT(!result->IsSimulate()); 1112 return result; 1113 } 1114 1115 template<class I, class P1, class P2> 1116 I* Add(P1 p1, P2 p2) { 1117 I* result = AddInstructionTyped(New<I>(p1, p2)); 1118 // Specializations must have their parameters properly casted 1119 // to avoid landing here. 1120 ASSERT(!result->IsSimulate()); 1121 return result; 1122 } 1123 1124 template<class I, class P1, class P2, class P3> 1125 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3) { 1126 return I::New(zone(), context(), p1, p2, p3); 1127 } 1128 1129 template<class I, class P1, class P2, class P3> 1130 I* New(P1 p1, P2 p2, P3 p3) { 1131 return I::New(zone(), context(), p1, p2, p3); 1132 } 1133 1134 template<class I, class P1, class P2, class P3> 1135 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3) { 1136 return AddInstruction(NewUncasted<I>(p1, p2, p3)); 1137 } 1138 1139 template<class I, class P1, class P2, class P3> 1140 I* Add(P1 p1, P2 p2, P3 p3) { 1141 return AddInstructionTyped(New<I>(p1, p2, p3)); 1142 } 1143 1144 template<class I, class P1, class P2, class P3, class P4> 1145 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4) { 1146 return I::New(zone(), context(), p1, p2, p3, p4); 1147 } 1148 1149 template<class I, class P1, class P2, class P3, class P4> 1150 I* New(P1 p1, P2 p2, P3 p3, P4 p4) { 1151 return I::New(zone(), context(), p1, p2, p3, p4); 1152 } 1153 1154 template<class I, class P1, class P2, class P3, class P4> 1155 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4) { 1156 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4)); 1157 } 1158 1159 template<class I, class P1, class P2, class P3, class P4> 1160 I* Add(P1 p1, P2 p2, P3 p3, P4 p4) { 1161 return AddInstructionTyped(New<I>(p1, p2, p3, p4)); 1162 } 1163 1164 template<class I, class P1, class P2, class P3, class P4, class P5> 1165 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { 1166 return I::New(zone(), context(), p1, p2, p3, p4, p5); 1167 } 1168 1169 template<class I, class P1, class P2, class P3, class P4, class P5> 1170 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { 1171 return I::New(zone(), context(), p1, p2, p3, p4, p5); 1172 } 1173 1174 template<class I, class P1, class P2, class P3, class P4, class P5> 1175 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { 1176 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5)); 1177 } 1178 1179 template<class I, class P1, class P2, class P3, class P4, class P5> 1180 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { 1181 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5)); 1182 } 1183 1184 template<class I, class P1, class P2, class P3, class P4, class P5, class P6> 1185 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { 1186 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6); 1187 } 1188 1189 template<class I, class P1, class P2, class P3, class P4, class P5, class P6> 1190 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { 1191 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6); 1192 } 1193 1194 template<class I, class P1, class P2, class P3, class P4, class P5, class P6> 1195 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { 1196 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6)); 1197 } 1198 1199 template<class I, class P1, class P2, class P3, class P4, class P5, class P6> 1200 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { 1201 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6)); 1202 } 1203 1204 template<class I, class P1, class P2, class P3, class P4, 1205 class P5, class P6, class P7> 1206 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { 1207 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7); 1208 } 1209 1210 template<class I, class P1, class P2, class P3, class P4, 1211 class P5, class P6, class P7> 1212 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { 1213 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7); 1214 } 1215 1216 template<class I, class P1, class P2, class P3, 1217 class P4, class P5, class P6, class P7> 1218 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { 1219 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7)); 1220 } 1221 1222 template<class I, class P1, class P2, class P3, 1223 class P4, class P5, class P6, class P7> 1224 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { 1225 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7)); 1226 } 1227 1228 template<class I, class P1, class P2, class P3, class P4, 1229 class P5, class P6, class P7, class P8> 1230 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, 1231 P5 p5, P6 p6, P7 p7, P8 p8) { 1232 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8); 1233 } 1234 1235 template<class I, class P1, class P2, class P3, class P4, 1236 class P5, class P6, class P7, class P8> 1237 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) { 1238 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8); 1239 } 1240 1241 template<class I, class P1, class P2, class P3, class P4, 1242 class P5, class P6, class P7, class P8> 1243 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, 1244 P5 p5, P6 p6, P7 p7, P8 p8) { 1245 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8)); 1246 } 1247 1248 template<class I, class P1, class P2, class P3, class P4, 1249 class P5, class P6, class P7, class P8> 1250 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) { 1251 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7, p8)); 1252 } 1253 1254 void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE); 1255 1256 int position() const { return position_; } 1257 1258 protected: 1259 virtual bool BuildGraph() = 0; 1260 1261 HBasicBlock* CreateBasicBlock(HEnvironment* env); 1262 HBasicBlock* CreateLoopHeaderBlock(); 1263 1264 HValue* BuildCheckHeapObject(HValue* object); 1265 HValue* BuildCheckMap(HValue* obj, Handle<Map> map); 1266 HValue* BuildCheckString(HValue* string); 1267 HValue* BuildWrapReceiver(HValue* object, HValue* function); 1268 1269 // Building common constructs 1270 HValue* BuildCheckForCapacityGrow(HValue* object, 1271 HValue* elements, 1272 ElementsKind kind, 1273 HValue* length, 1274 HValue* key, 1275 bool is_js_array); 1276 1277 HValue* BuildCopyElementsOnWrite(HValue* object, 1278 HValue* elements, 1279 ElementsKind kind, 1280 HValue* length); 1281 1282 void BuildTransitionElementsKind(HValue* object, 1283 HValue* map, 1284 ElementsKind from_kind, 1285 ElementsKind to_kind, 1286 bool is_jsarray); 1287 1288 HValue* BuildNumberToString(HValue* object, Handle<Type> type); 1289 1290 HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver, 1291 HValue* key); 1292 1293 // Computes the size for a sequential string of the given length and encoding. 1294 HValue* BuildSeqStringSizeFor(HValue* length, 1295 String::Encoding encoding); 1296 // Copies characters from one sequential string to another. 1297 void BuildCopySeqStringChars(HValue* src, 1298 HValue* src_offset, 1299 String::Encoding src_encoding, 1300 HValue* dst, 1301 HValue* dst_offset, 1302 String::Encoding dst_encoding, 1303 HValue* length); 1304 // Both operands are non-empty strings. 1305 HValue* BuildUncheckedStringAdd(HValue* left, 1306 HValue* right, 1307 PretenureFlag pretenure_flag); 1308 // Both operands are strings. 1309 HValue* BuildStringAdd(HValue* left, 1310 HValue* right, 1311 PretenureFlag pretenure_flag); 1312 1313 HInstruction* BuildUncheckedMonomorphicElementAccess( 1314 HValue* checked_object, 1315 HValue* key, 1316 HValue* val, 1317 bool is_js_array, 1318 ElementsKind elements_kind, 1319 bool is_store, 1320 LoadKeyedHoleMode load_mode, 1321 KeyedAccessStoreMode store_mode); 1322 1323 HInstruction* AddElementAccess( 1324 HValue* elements, 1325 HValue* checked_key, 1326 HValue* val, 1327 HValue* dependency, 1328 ElementsKind elements_kind, 1329 bool is_store, 1330 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE); 1331 1332 HLoadNamedField* BuildLoadNamedField(HValue* object, HObjectAccess access); 1333 HInstruction* AddLoadNamedField(HValue* object, HObjectAccess access); 1334 HInstruction* BuildLoadStringLength(HValue* object, HValue* checked_value); 1335 HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map); 1336 HStoreNamedField* AddStoreMapConstantNoWriteBarrier(HValue* object, 1337 Handle<Map> map) { 1338 HStoreNamedField* store_map = AddStoreMapConstant(object, map); 1339 store_map->SkipWriteBarrier(); 1340 return store_map; 1341 } 1342 HLoadNamedField* AddLoadElements(HValue* object); 1343 1344 bool MatchRotateRight(HValue* left, 1345 HValue* right, 1346 HValue** operand, 1347 HValue** shift_amount); 1348 1349 HValue* BuildBinaryOperation(Token::Value op, 1350 HValue* left, 1351 HValue* right, 1352 Handle<Type> left_type, 1353 Handle<Type> right_type, 1354 Handle<Type> result_type, 1355 Maybe<int> fixed_right_arg); 1356 1357 HLoadNamedField* AddLoadFixedArrayLength(HValue *object); 1358 1359 HValue* AddLoadJSBuiltin(Builtins::JavaScript builtin); 1360 1361 HValue* EnforceNumberType(HValue* number, Handle<Type> expected); 1362 HValue* TruncateToNumber(HValue* value, Handle<Type>* expected); 1363 1364 void FinishExitWithHardDeoptimization(const char* reason, 1365 HBasicBlock* continuation); 1366 1367 void AddIncrementCounter(StatsCounter* counter); 1368 1369 class IfBuilder V8_FINAL { 1370 public: 1371 explicit IfBuilder(HGraphBuilder* builder); 1372 IfBuilder(HGraphBuilder* builder, 1373 HIfContinuation* continuation); 1374 1375 ~IfBuilder() { 1376 if (!finished_) End(); 1377 } 1378 1379 template<class Condition> 1380 Condition* If(HValue *p) { 1381 Condition* compare = builder()->New<Condition>(p); 1382 AddCompare(compare); 1383 return compare; 1384 } 1385 1386 template<class Condition, class P2> 1387 Condition* If(HValue* p1, P2 p2) { 1388 Condition* compare = builder()->New<Condition>(p1, p2); 1389 AddCompare(compare); 1390 return compare; 1391 } 1392 1393 template<class Condition, class P2, class P3> 1394 Condition* If(HValue* p1, P2 p2, P3 p3) { 1395 Condition* compare = builder()->New<Condition>(p1, p2, p3); 1396 AddCompare(compare); 1397 return compare; 1398 } 1399 1400 template<class Condition> 1401 Condition* IfNot(HValue* p) { 1402 Condition* compare = If<Condition>(p); 1403 compare->Not(); 1404 return compare; 1405 } 1406 1407 template<class Condition, class P2> 1408 Condition* IfNot(HValue* p1, P2 p2) { 1409 Condition* compare = If<Condition>(p1, p2); 1410 compare->Not(); 1411 return compare; 1412 } 1413 1414 template<class Condition, class P2, class P3> 1415 Condition* IfNot(HValue* p1, P2 p2, P3 p3) { 1416 Condition* compare = If<Condition>(p1, p2, p3); 1417 compare->Not(); 1418 return compare; 1419 } 1420 1421 template<class Condition> 1422 Condition* OrIf(HValue *p) { 1423 Or(); 1424 return If<Condition>(p); 1425 } 1426 1427 template<class Condition, class P2> 1428 Condition* OrIf(HValue* p1, P2 p2) { 1429 Or(); 1430 return If<Condition>(p1, p2); 1431 } 1432 1433 template<class Condition, class P2, class P3> 1434 Condition* OrIf(HValue* p1, P2 p2, P3 p3) { 1435 Or(); 1436 return If<Condition>(p1, p2, p3); 1437 } 1438 1439 template<class Condition> 1440 Condition* AndIf(HValue *p) { 1441 And(); 1442 return If<Condition>(p); 1443 } 1444 1445 template<class Condition, class P2> 1446 Condition* AndIf(HValue* p1, P2 p2) { 1447 And(); 1448 return If<Condition>(p1, p2); 1449 } 1450 1451 template<class Condition, class P2, class P3> 1452 Condition* AndIf(HValue* p1, P2 p2, P3 p3) { 1453 And(); 1454 return If<Condition>(p1, p2, p3); 1455 } 1456 1457 void Or(); 1458 void And(); 1459 1460 // Captures the current state of this IfBuilder in the specified 1461 // continuation and ends this IfBuilder. 1462 void CaptureContinuation(HIfContinuation* continuation); 1463 1464 // Joins the specified continuation from this IfBuilder and ends this 1465 // IfBuilder. This appends a Goto instruction from the true branch of 1466 // this IfBuilder to the true branch of the continuation unless the 1467 // true branch of this IfBuilder is already finished. And vice versa 1468 // for the false branch. 1469 // 1470 // The basic idea is as follows: You have several nested IfBuilder's 1471 // that you want to join based on two possible outcomes (i.e. success 1472 // and failure, or whatever). You can do this easily using this method 1473 // now, for example: 1474 // 1475 // HIfContinuation cont(graph()->CreateBasicBlock(), 1476 // graph()->CreateBasicBlock()); 1477 // ... 1478 // IfBuilder if_whatever(this); 1479 // if_whatever.If<Condition>(arg); 1480 // if_whatever.Then(); 1481 // ... 1482 // if_whatever.Else(); 1483 // ... 1484 // if_whatever.JoinContinuation(&cont); 1485 // ... 1486 // IfBuilder if_something(this); 1487 // if_something.If<Condition>(arg1, arg2); 1488 // if_something.Then(); 1489 // ... 1490 // if_something.Else(); 1491 // ... 1492 // if_something.JoinContinuation(&cont); 1493 // ... 1494 // IfBuilder if_finally(this, &cont); 1495 // if_finally.Then(); 1496 // // continues after then code of if_whatever or if_something. 1497 // ... 1498 // if_finally.Else(); 1499 // // continues after else code of if_whatever or if_something. 1500 // ... 1501 // if_finally.End(); 1502 void JoinContinuation(HIfContinuation* continuation); 1503 1504 void Then(); 1505 void Else(); 1506 void End(); 1507 1508 void Deopt(const char* reason); 1509 void ThenDeopt(const char* reason) { 1510 Then(); 1511 Deopt(reason); 1512 } 1513 void ElseDeopt(const char* reason) { 1514 Else(); 1515 Deopt(reason); 1516 } 1517 1518 void Return(HValue* value); 1519 1520 private: 1521 HControlInstruction* AddCompare(HControlInstruction* compare); 1522 1523 HGraphBuilder* builder() const { return builder_; } 1524 1525 void AddMergeAtJoinBlock(bool deopt); 1526 1527 void Finish(); 1528 void Finish(HBasicBlock** then_continuation, 1529 HBasicBlock** else_continuation); 1530 1531 class MergeAtJoinBlock : public ZoneObject { 1532 public: 1533 MergeAtJoinBlock(HBasicBlock* block, 1534 bool deopt, 1535 MergeAtJoinBlock* next) 1536 : block_(block), 1537 deopt_(deopt), 1538 next_(next) {} 1539 HBasicBlock* block_; 1540 bool deopt_; 1541 MergeAtJoinBlock* next_; 1542 }; 1543 1544 HGraphBuilder* builder_; 1545 bool finished_ : 1; 1546 bool did_then_ : 1; 1547 bool did_else_ : 1; 1548 bool did_else_if_ : 1; 1549 bool did_and_ : 1; 1550 bool did_or_ : 1; 1551 bool captured_ : 1; 1552 bool needs_compare_ : 1; 1553 bool pending_merge_block_ : 1; 1554 HBasicBlock* first_true_block_; 1555 HBasicBlock* first_false_block_; 1556 HBasicBlock* split_edge_merge_block_; 1557 MergeAtJoinBlock* merge_at_join_blocks_; 1558 int normal_merge_at_join_block_count_; 1559 int deopt_merge_at_join_block_count_; 1560 }; 1561 1562 class LoopBuilder V8_FINAL { 1563 public: 1564 enum Direction { 1565 kPreIncrement, 1566 kPostIncrement, 1567 kPreDecrement, 1568 kPostDecrement 1569 }; 1570 1571 LoopBuilder(HGraphBuilder* builder, 1572 HValue* context, 1573 Direction direction); 1574 LoopBuilder(HGraphBuilder* builder, 1575 HValue* context, 1576 Direction direction, 1577 HValue* increment_amount); 1578 1579 ~LoopBuilder() { 1580 ASSERT(finished_); 1581 } 1582 1583 HValue* BeginBody( 1584 HValue* initial, 1585 HValue* terminating, 1586 Token::Value token); 1587 1588 void Break(); 1589 1590 void EndBody(); 1591 1592 private: 1593 Zone* zone() { return builder_->zone(); } 1594 1595 HGraphBuilder* builder_; 1596 HValue* context_; 1597 HValue* increment_amount_; 1598 HInstruction* increment_; 1599 HPhi* phi_; 1600 HBasicBlock* header_block_; 1601 HBasicBlock* body_block_; 1602 HBasicBlock* exit_block_; 1603 HBasicBlock* exit_trampoline_block_; 1604 Direction direction_; 1605 bool finished_; 1606 }; 1607 1608 HValue* BuildNewElementsCapacity(HValue* old_capacity); 1609 1610 void BuildNewSpaceArrayCheck(HValue* length, 1611 ElementsKind kind); 1612 1613 class JSArrayBuilder V8_FINAL { 1614 public: 1615 JSArrayBuilder(HGraphBuilder* builder, 1616 ElementsKind kind, 1617 HValue* allocation_site_payload, 1618 HValue* constructor_function, 1619 AllocationSiteOverrideMode override_mode); 1620 1621 JSArrayBuilder(HGraphBuilder* builder, 1622 ElementsKind kind, 1623 HValue* constructor_function = NULL); 1624 1625 enum FillMode { 1626 DONT_FILL_WITH_HOLE, 1627 FILL_WITH_HOLE 1628 }; 1629 1630 ElementsKind kind() { return kind_; } 1631 1632 HValue* AllocateEmptyArray(); 1633 HValue* AllocateArray(HValue* capacity, HValue* length_field, 1634 FillMode fill_mode = FILL_WITH_HOLE); 1635 HValue* GetElementsLocation() { return elements_location_; } 1636 HValue* EmitMapCode(); 1637 1638 private: 1639 Zone* zone() const { return builder_->zone(); } 1640 int elements_size() const { 1641 return IsFastDoubleElementsKind(kind_) ? kDoubleSize : kPointerSize; 1642 } 1643 HGraphBuilder* builder() { return builder_; } 1644 HGraph* graph() { return builder_->graph(); } 1645 int initial_capacity() { 1646 STATIC_ASSERT(JSArray::kPreallocatedArrayElements > 0); 1647 return JSArray::kPreallocatedArrayElements; 1648 } 1649 1650 HValue* EmitInternalMapCode(); 1651 HValue* EstablishEmptyArrayAllocationSize(); 1652 HValue* EstablishAllocationSize(HValue* length_node); 1653 HValue* AllocateArray(HValue* size_in_bytes, HValue* capacity, 1654 HValue* length_field, 1655 FillMode fill_mode = FILL_WITH_HOLE); 1656 1657 HGraphBuilder* builder_; 1658 ElementsKind kind_; 1659 AllocationSiteMode mode_; 1660 HValue* allocation_site_payload_; 1661 HValue* constructor_function_; 1662 HInnerAllocatedObject* elements_location_; 1663 }; 1664 1665 HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder, 1666 HValue* length_argument); 1667 1668 HValue* BuildAllocateElements(ElementsKind kind, 1669 HValue* capacity); 1670 1671 void BuildInitializeElementsHeader(HValue* elements, 1672 ElementsKind kind, 1673 HValue* capacity); 1674 1675 HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind, 1676 HValue* capacity); 1677 1678 // array must have been allocated with enough room for 1679 // 1) the JSArray, 2) a AllocationMemento if mode requires it, 1680 // 3) a FixedArray or FixedDoubleArray. 1681 // A pointer to the Fixed(Double)Array is returned. 1682 HInnerAllocatedObject* BuildJSArrayHeader(HValue* array, 1683 HValue* array_map, 1684 AllocationSiteMode mode, 1685 ElementsKind elements_kind, 1686 HValue* allocation_site_payload, 1687 HValue* length_field); 1688 1689 HValue* BuildGrowElementsCapacity(HValue* object, 1690 HValue* elements, 1691 ElementsKind kind, 1692 ElementsKind new_kind, 1693 HValue* length, 1694 HValue* new_capacity); 1695 1696 void BuildFillElementsWithHole(HValue* elements, 1697 ElementsKind elements_kind, 1698 HValue* from, 1699 HValue* to); 1700 1701 void BuildCopyElements(HValue* from_elements, 1702 ElementsKind from_elements_kind, 1703 HValue* to_elements, 1704 ElementsKind to_elements_kind, 1705 HValue* length, 1706 HValue* capacity); 1707 1708 HValue* BuildCloneShallowArray(HValue* boilerplate, 1709 HValue* allocation_site, 1710 AllocationSiteMode mode, 1711 ElementsKind kind, 1712 int length); 1713 1714 HValue* BuildElementIndexHash(HValue* index); 1715 1716 void BuildCompareNil( 1717 HValue* value, 1718 Handle<Type> type, 1719 HIfContinuation* continuation); 1720 1721 void BuildCreateAllocationMemento(HValue* previous_object, 1722 HValue* previous_object_size, 1723 HValue* payload); 1724 1725 HInstruction* BuildConstantMapCheck(Handle<JSObject> constant, 1726 CompilationInfo* info); 1727 HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype, 1728 Handle<JSObject> holder); 1729 1730 HInstruction* BuildGetNativeContext(); 1731 HInstruction* BuildGetArrayFunction(); 1732 1733 protected: 1734 void SetSourcePosition(int position) { 1735 ASSERT(position != RelocInfo::kNoPosition); 1736 position_ = position; 1737 } 1738 1739 template <typename ViewClass> 1740 void BuildArrayBufferViewInitialization(HValue* obj, 1741 HValue* buffer, 1742 HValue* byte_offset, 1743 HValue* byte_length); 1744 1745 private: 1746 HGraphBuilder(); 1747 1748 HValue* BuildUncheckedDictionaryElementLoadHelper( 1749 HValue* elements, 1750 HValue* key, 1751 HValue* hash, 1752 HValue* mask, 1753 int current_probe); 1754 1755 void PadEnvironmentForContinuation(HBasicBlock* from, 1756 HBasicBlock* continuation); 1757 1758 template <class I> 1759 I* AddInstructionTyped(I* instr) { 1760 return I::cast(AddInstruction(instr)); 1761 } 1762 1763 CompilationInfo* info_; 1764 HGraph* graph_; 1765 HBasicBlock* current_block_; 1766 int position_; 1767 }; 1768 1769 1770 template<> 1771 inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>( 1772 const char* reason, Deoptimizer::BailoutType type) { 1773 if (type == Deoptimizer::SOFT) { 1774 isolate()->counters()->soft_deopts_requested()->Increment(); 1775 if (FLAG_always_opt) return NULL; 1776 } 1777 if (current_block()->IsDeoptimizing()) return NULL; 1778 HBasicBlock* after_deopt_block = CreateBasicBlock( 1779 current_block()->last_environment()); 1780 HDeoptimize* instr = New<HDeoptimize>(reason, type, after_deopt_block); 1781 if (type == Deoptimizer::SOFT) { 1782 isolate()->counters()->soft_deopts_inserted()->Increment(); 1783 } 1784 FinishCurrentBlock(instr); 1785 set_current_block(after_deopt_block); 1786 return instr; 1787 } 1788 1789 1790 template<> 1791 inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>( 1792 const char* reason, Deoptimizer::BailoutType type) { 1793 return Add<HDeoptimize>(reason, type); 1794 } 1795 1796 1797 template<> 1798 inline HSimulate* HGraphBuilder::Add<HSimulate>( 1799 BailoutId id, 1800 RemovableSimulate removable) { 1801 HSimulate* instr = current_block()->CreateSimulate(id, removable); 1802 AddInstruction(instr); 1803 return instr; 1804 } 1805 1806 1807 template<> 1808 inline HSimulate* HGraphBuilder::Add<HSimulate>( 1809 BailoutId id) { 1810 return Add<HSimulate>(id, FIXED_SIMULATE); 1811 } 1812 1813 1814 template<> 1815 inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(BailoutId id) { 1816 return Add<HSimulate>(id, FIXED_SIMULATE); 1817 } 1818 1819 1820 template<> 1821 inline HReturn* HGraphBuilder::Add<HReturn>(HValue* value) { 1822 int num_parameters = graph()->info()->num_parameters(); 1823 HValue* params = AddUncasted<HConstant>(num_parameters); 1824 HReturn* return_instruction = New<HReturn>(value, params); 1825 FinishExitCurrentBlock(return_instruction); 1826 return return_instruction; 1827 } 1828 1829 1830 template<> 1831 inline HReturn* HGraphBuilder::Add<HReturn>(HConstant* value) { 1832 return Add<HReturn>(static_cast<HValue*>(value)); 1833 } 1834 1835 template<> 1836 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) { 1837 return Add<HReturn>(value); 1838 } 1839 1840 1841 template<> 1842 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HConstant* value) { 1843 return Add<HReturn>(value); 1844 } 1845 1846 1847 template<> 1848 inline HCallRuntime* HGraphBuilder::Add<HCallRuntime>( 1849 Handle<String> name, 1850 const Runtime::Function* c_function, 1851 int argument_count) { 1852 HCallRuntime* instr = New<HCallRuntime>(name, c_function, argument_count); 1853 if (graph()->info()->IsStub()) { 1854 // When compiling code stubs, we don't want to save all double registers 1855 // upon entry to the stub, but instead have the call runtime instruction 1856 // save the double registers only on-demand (in the fallback case). 1857 instr->set_save_doubles(kSaveFPRegs); 1858 } 1859 AddInstruction(instr); 1860 return instr; 1861 } 1862 1863 1864 template<> 1865 inline HInstruction* HGraphBuilder::AddUncasted<HCallRuntime>( 1866 Handle<String> name, 1867 const Runtime::Function* c_function, 1868 int argument_count) { 1869 return Add<HCallRuntime>(name, c_function, argument_count); 1870 } 1871 1872 1873 template<> 1874 inline HContext* HGraphBuilder::New<HContext>() { 1875 return HContext::New(zone()); 1876 } 1877 1878 1879 template<> 1880 inline HInstruction* HGraphBuilder::NewUncasted<HContext>() { 1881 return New<HContext>(); 1882 } 1883 1884 class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { 1885 public: 1886 // A class encapsulating (lazily-allocated) break and continue blocks for 1887 // a breakable statement. Separated from BreakAndContinueScope so that it 1888 // can have a separate lifetime. 1889 class BreakAndContinueInfo V8_FINAL BASE_EMBEDDED { 1890 public: 1891 explicit BreakAndContinueInfo(BreakableStatement* target, 1892 int drop_extra = 0) 1893 : target_(target), 1894 break_block_(NULL), 1895 continue_block_(NULL), 1896 drop_extra_(drop_extra) { 1897 } 1898 1899 BreakableStatement* target() { return target_; } 1900 HBasicBlock* break_block() { return break_block_; } 1901 void set_break_block(HBasicBlock* block) { break_block_ = block; } 1902 HBasicBlock* continue_block() { return continue_block_; } 1903 void set_continue_block(HBasicBlock* block) { continue_block_ = block; } 1904 int drop_extra() { return drop_extra_; } 1905 1906 private: 1907 BreakableStatement* target_; 1908 HBasicBlock* break_block_; 1909 HBasicBlock* continue_block_; 1910 int drop_extra_; 1911 }; 1912 1913 // A helper class to maintain a stack of current BreakAndContinueInfo 1914 // structures mirroring BreakableStatement nesting. 1915 class BreakAndContinueScope V8_FINAL BASE_EMBEDDED { 1916 public: 1917 BreakAndContinueScope(BreakAndContinueInfo* info, 1918 HOptimizedGraphBuilder* owner) 1919 : info_(info), owner_(owner), next_(owner->break_scope()) { 1920 owner->set_break_scope(this); 1921 } 1922 1923 ~BreakAndContinueScope() { owner_->set_break_scope(next_); } 1924 1925 BreakAndContinueInfo* info() { return info_; } 1926 HOptimizedGraphBuilder* owner() { return owner_; } 1927 BreakAndContinueScope* next() { return next_; } 1928 1929 // Search the break stack for a break or continue target. 1930 enum BreakType { BREAK, CONTINUE }; 1931 HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra); 1932 1933 private: 1934 BreakAndContinueInfo* info_; 1935 HOptimizedGraphBuilder* owner_; 1936 BreakAndContinueScope* next_; 1937 }; 1938 1939 explicit HOptimizedGraphBuilder(CompilationInfo* info); 1940 1941 virtual bool BuildGraph() V8_OVERRIDE; 1942 1943 // Simple accessors. 1944 BreakAndContinueScope* break_scope() const { return break_scope_; } 1945 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; } 1946 1947 bool inline_bailout() { return inline_bailout_; } 1948 1949 HValue* context() { return environment()->context(); } 1950 1951 HOsrBuilder* osr() const { return osr_; } 1952 1953 void Bailout(BailoutReason reason); 1954 1955 HBasicBlock* CreateJoin(HBasicBlock* first, 1956 HBasicBlock* second, 1957 BailoutId join_id); 1958 1959 FunctionState* function_state() const { return function_state_; } 1960 1961 void VisitDeclarations(ZoneList<Declaration*>* declarations); 1962 1963 void* operator new(size_t size, Zone* zone) { 1964 return zone->New(static_cast<int>(size)); 1965 } 1966 void operator delete(void* pointer, Zone* zone) { } 1967 void operator delete(void* pointer) { } 1968 1969 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); 1970 1971 protected: 1972 // Type of a member function that generates inline code for a native function. 1973 typedef void (HOptimizedGraphBuilder::*InlineFunctionGenerator) 1974 (CallRuntime* call); 1975 1976 // Forward declarations for inner scope classes. 1977 class SubgraphScope; 1978 1979 static const InlineFunctionGenerator kInlineFunctionGenerators[]; 1980 1981 static const int kMaxCallPolymorphism = 4; 1982 static const int kMaxLoadPolymorphism = 4; 1983 static const int kMaxStorePolymorphism = 4; 1984 1985 // Even in the 'unlimited' case we have to have some limit in order not to 1986 // overflow the stack. 1987 static const int kUnlimitedMaxInlinedSourceSize = 100000; 1988 static const int kUnlimitedMaxInlinedNodes = 10000; 1989 static const int kUnlimitedMaxInlinedNodesCumulative = 10000; 1990 1991 // Maximum depth and total number of elements and properties for literal 1992 // graphs to be considered for fast deep-copying. 1993 static const int kMaxFastLiteralDepth = 3; 1994 static const int kMaxFastLiteralProperties = 8; 1995 1996 // Simple accessors. 1997 void set_function_state(FunctionState* state) { function_state_ = state; } 1998 1999 AstContext* ast_context() const { return ast_context_; } 2000 void set_ast_context(AstContext* context) { ast_context_ = context; } 2001 2002 // Accessors forwarded to the function state. 2003 CompilationInfo* current_info() const { 2004 return function_state()->compilation_info(); 2005 } 2006 AstContext* call_context() const { 2007 return function_state()->call_context(); 2008 } 2009 HBasicBlock* function_return() const { 2010 return function_state()->function_return(); 2011 } 2012 TestContext* inlined_test_context() const { 2013 return function_state()->test_context(); 2014 } 2015 void ClearInlinedTestContext() { 2016 function_state()->ClearInlinedTestContext(); 2017 } 2018 StrictModeFlag function_strict_mode_flag() { 2019 return function_state()->compilation_info()->is_classic_mode() 2020 ? kNonStrictMode : kStrictMode; 2021 } 2022 2023 // Generators for inline runtime functions. 2024 #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \ 2025 void Generate##Name(CallRuntime* call); 2026 2027 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) 2028 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) 2029 #undef INLINE_FUNCTION_GENERATOR_DECLARATION 2030 2031 void VisitDelete(UnaryOperation* expr); 2032 void VisitVoid(UnaryOperation* expr); 2033 void VisitTypeof(UnaryOperation* expr); 2034 void VisitNot(UnaryOperation* expr); 2035 2036 void VisitComma(BinaryOperation* expr); 2037 void VisitLogicalExpression(BinaryOperation* expr); 2038 void VisitArithmeticExpression(BinaryOperation* expr); 2039 2040 bool PreProcessOsrEntry(IterationStatement* statement); 2041 void VisitLoopBody(IterationStatement* stmt, 2042 HBasicBlock* loop_entry, 2043 BreakAndContinueInfo* break_info); 2044 2045 // Create a back edge in the flow graph. body_exit is the predecessor 2046 // block and loop_entry is the successor block. loop_successor is the 2047 // block where control flow exits the loop normally (e.g., via failure of 2048 // the condition) and break_block is the block where control flow breaks 2049 // from the loop. All blocks except loop_entry can be NULL. The return 2050 // value is the new successor block which is the join of loop_successor 2051 // and break_block, or NULL. 2052 HBasicBlock* CreateLoop(IterationStatement* statement, 2053 HBasicBlock* loop_entry, 2054 HBasicBlock* body_exit, 2055 HBasicBlock* loop_successor, 2056 HBasicBlock* break_block); 2057 2058 // Build a loop entry 2059 HBasicBlock* BuildLoopEntry(); 2060 2061 // Builds a loop entry respectful of OSR requirements 2062 HBasicBlock* BuildLoopEntry(IterationStatement* statement); 2063 2064 HBasicBlock* JoinContinue(IterationStatement* statement, 2065 HBasicBlock* exit_block, 2066 HBasicBlock* continue_block); 2067 2068 HValue* Top() const { return environment()->Top(); } 2069 void Drop(int n) { environment()->Drop(n); } 2070 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); } 2071 bool IsEligibleForEnvironmentLivenessAnalysis(Variable* var, 2072 int index, 2073 HValue* value, 2074 HEnvironment* env) { 2075 if (!FLAG_analyze_environment_liveness) return false; 2076 // |this| and |arguments| are always live; zapping parameters isn't 2077 // safe because function.arguments can inspect them at any time. 2078 return !var->is_this() && 2079 !var->is_arguments() && 2080 !value->IsArgumentsObject() && 2081 env->is_local_index(index); 2082 } 2083 void BindIfLive(Variable* var, HValue* value) { 2084 HEnvironment* env = environment(); 2085 int index = env->IndexFor(var); 2086 env->Bind(index, value); 2087 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) { 2088 HEnvironmentMarker* bind = 2089 Add<HEnvironmentMarker>(HEnvironmentMarker::BIND, index); 2090 USE(bind); 2091 #ifdef DEBUG 2092 bind->set_closure(env->closure()); 2093 #endif 2094 } 2095 } 2096 2097 HValue* LookupAndMakeLive(Variable* var) { 2098 HEnvironment* env = environment(); 2099 int index = env->IndexFor(var); 2100 HValue* value = env->Lookup(index); 2101 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) { 2102 HEnvironmentMarker* lookup = 2103 Add<HEnvironmentMarker>(HEnvironmentMarker::LOOKUP, index); 2104 USE(lookup); 2105 #ifdef DEBUG 2106 lookup->set_closure(env->closure()); 2107 #endif 2108 } 2109 return value; 2110 } 2111 2112 // The value of the arguments object is allowed in some but not most value 2113 // contexts. (It's allowed in all effect contexts and disallowed in all 2114 // test contexts.) 2115 void VisitForValue(Expression* expr, 2116 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED); 2117 void VisitForTypeOf(Expression* expr); 2118 void VisitForEffect(Expression* expr); 2119 void VisitForControl(Expression* expr, 2120 HBasicBlock* true_block, 2121 HBasicBlock* false_block); 2122 2123 // Visit an argument subexpression and emit a push to the outgoing arguments. 2124 void VisitArgument(Expression* expr); 2125 2126 void VisitArgumentList(ZoneList<Expression*>* arguments); 2127 2128 // Visit a list of expressions from left to right, each in a value context. 2129 void VisitExpressions(ZoneList<Expression*>* exprs); 2130 2131 // Remove the arguments from the bailout environment and emit instructions 2132 // to push them as outgoing parameters. 2133 template <class Instruction> HInstruction* PreProcessCall(Instruction* call); 2134 2135 void SetUpScope(Scope* scope); 2136 virtual void VisitStatements(ZoneList<Statement*>* statements) V8_OVERRIDE; 2137 2138 #define DECLARE_VISIT(type) virtual void Visit##type(type* node) V8_OVERRIDE; 2139 AST_NODE_LIST(DECLARE_VISIT) 2140 #undef DECLARE_VISIT 2141 2142 private: 2143 // Helpers for flow graph construction. 2144 enum GlobalPropertyAccess { 2145 kUseCell, 2146 kUseGeneric 2147 }; 2148 GlobalPropertyAccess LookupGlobalProperty(Variable* var, 2149 LookupResult* lookup, 2150 bool is_store); 2151 2152 void EnsureArgumentsArePushedForAccess(); 2153 bool TryArgumentsAccess(Property* expr); 2154 2155 // Try to optimize fun.apply(receiver, arguments) pattern. 2156 bool TryCallApply(Call* expr); 2157 2158 int InliningAstSize(Handle<JSFunction> target); 2159 bool TryInline(CallKind call_kind, 2160 Handle<JSFunction> target, 2161 int arguments_count, 2162 HValue* implicit_return_value, 2163 BailoutId ast_id, 2164 BailoutId return_id, 2165 InliningKind inlining_kind); 2166 2167 bool TryInlineCall(Call* expr, bool drop_extra = false); 2168 bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value); 2169 bool TryInlineGetter(Handle<JSFunction> getter, 2170 BailoutId ast_id, 2171 BailoutId return_id); 2172 bool TryInlineSetter(Handle<JSFunction> setter, 2173 BailoutId id, 2174 BailoutId assignment_id, 2175 HValue* implicit_return_value); 2176 bool TryInlineApply(Handle<JSFunction> function, 2177 Call* expr, 2178 int arguments_count); 2179 bool TryInlineBuiltinMethodCall(Call* expr, 2180 HValue* receiver, 2181 Handle<Map> receiver_map, 2182 CheckType check_type); 2183 bool TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra); 2184 2185 // If --trace-inlining, print a line of the inlining trace. Inlining 2186 // succeeded if the reason string is NULL and failed if there is a 2187 // non-NULL reason string. 2188 void TraceInline(Handle<JSFunction> target, 2189 Handle<JSFunction> caller, 2190 const char* failure_reason); 2191 2192 void HandleGlobalVariableAssignment(Variable* var, 2193 HValue* value, 2194 BailoutId ast_id); 2195 2196 void HandlePropertyAssignment(Assignment* expr); 2197 void HandleCompoundAssignment(Assignment* expr); 2198 void HandlePolymorphicLoadNamedField(BailoutId ast_id, 2199 BailoutId return_id, 2200 HValue* object, 2201 SmallMapList* types, 2202 Handle<String> name); 2203 2204 void VisitTypedArrayInitialize(CallRuntime* expr); 2205 2206 bool IsCallNewArrayInlineable(CallNew* expr); 2207 void BuildInlinedCallNewArray(CallNew* expr); 2208 2209 void VisitDataViewInitialize(CallRuntime* expr); 2210 2211 class PropertyAccessInfo { 2212 public: 2213 PropertyAccessInfo(Isolate* isolate, Handle<Map> map, Handle<String> name) 2214 : lookup_(isolate), 2215 map_(map), 2216 name_(name), 2217 access_(HObjectAccess::ForMap()) { } 2218 2219 // Checkes whether this PropertyAccessInfo can be handled as a monomorphic 2220 // load named. It additionally fills in the fields necessary to generate the 2221 // lookup code. 2222 bool CanLoadMonomorphic(); 2223 2224 // Checks whether all types behave uniform when loading name. If all maps 2225 // behave the same, a single monomorphic load instruction can be emitted, 2226 // guarded by a single map-checks instruction that whether the receiver is 2227 // an instance of any of the types. 2228 // This method skips the first type in types, assuming that this 2229 // PropertyAccessInfo is built for types->first(). 2230 bool CanLoadAsMonomorphic(SmallMapList* types); 2231 2232 bool IsJSObjectFieldAccessor() { 2233 int offset; // unused 2234 return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset); 2235 } 2236 2237 bool GetJSObjectFieldAccess(HObjectAccess* access) { 2238 if (IsStringLength()) { 2239 *access = HObjectAccess::ForStringLength(); 2240 return true; 2241 } else if (IsArrayLength()) { 2242 *access = HObjectAccess::ForArrayLength(map_->elements_kind()); 2243 return true; 2244 } else { 2245 int offset; 2246 if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) { 2247 *access = HObjectAccess::ForJSObjectOffset(offset); 2248 return true; 2249 } 2250 return false; 2251 } 2252 } 2253 2254 bool has_holder() { return !holder_.is_null(); } 2255 2256 LookupResult* lookup() { return &lookup_; } 2257 Handle<Map> map() { return map_; } 2258 Handle<JSObject> holder() { return holder_; } 2259 Handle<JSFunction> accessor() { return accessor_; } 2260 Handle<Object> constant() { return constant_; } 2261 HObjectAccess access() { return access_; } 2262 2263 private: 2264 Isolate* isolate() { return lookup_.isolate(); } 2265 2266 bool IsStringLength() { 2267 return map_->instance_type() < FIRST_NONSTRING_TYPE && 2268 name_->Equals(isolate()->heap()->length_string()); 2269 } 2270 2271 bool IsArrayLength() { 2272 return map_->instance_type() == JS_ARRAY_TYPE && 2273 name_->Equals(isolate()->heap()->length_string()); 2274 } 2275 2276 bool LoadResult(Handle<Map> map); 2277 bool LookupDescriptor(); 2278 bool LookupInPrototypes(); 2279 bool IsCompatibleForLoad(PropertyAccessInfo* other); 2280 2281 void GeneralizeRepresentation(Representation r) { 2282 access_ = access_.WithRepresentation( 2283 access_.representation().generalize(r)); 2284 } 2285 2286 LookupResult lookup_; 2287 Handle<Map> map_; 2288 Handle<String> name_; 2289 Handle<JSObject> holder_; 2290 Handle<JSFunction> accessor_; 2291 Handle<Object> constant_; 2292 HObjectAccess access_; 2293 }; 2294 2295 HInstruction* BuildLoadMonomorphic(PropertyAccessInfo* info, 2296 HValue* object, 2297 HInstruction* checked_object, 2298 BailoutId ast_id, 2299 BailoutId return_id, 2300 bool can_inline_accessor = true); 2301 2302 void HandlePolymorphicStoreNamedField(BailoutId assignment_id, 2303 HValue* object, 2304 HValue* value, 2305 SmallMapList* types, 2306 Handle<String> name); 2307 bool TryStorePolymorphicAsMonomorphic(BailoutId assignment_id, 2308 HValue* object, 2309 HValue* value, 2310 SmallMapList* types, 2311 Handle<String> name); 2312 void HandlePolymorphicCallNamed(Call* expr, 2313 HValue* receiver, 2314 SmallMapList* types, 2315 Handle<String> name); 2316 bool TryCallPolymorphicAsMonomorphic(Call* expr, 2317 HValue* receiver, 2318 SmallMapList* types, 2319 Handle<String> name); 2320 void HandleLiteralCompareTypeof(CompareOperation* expr, 2321 Expression* sub_expr, 2322 Handle<String> check); 2323 void HandleLiteralCompareNil(CompareOperation* expr, 2324 Expression* sub_expr, 2325 NilValue nil); 2326 2327 HInstruction* BuildStringCharCodeAt(HValue* string, 2328 HValue* index); 2329 HValue* BuildBinaryOperation(BinaryOperation* expr, 2330 HValue* left, 2331 HValue* right); 2332 HInstruction* BuildIncrement(bool returns_original_input, 2333 CountOperation* expr); 2334 HInstruction* BuildLoadKeyedGeneric(HValue* object, 2335 HValue* key); 2336 2337 HInstruction* TryBuildConsolidatedElementLoad(HValue* object, 2338 HValue* key, 2339 HValue* val, 2340 SmallMapList* maps); 2341 2342 LoadKeyedHoleMode BuildKeyedHoleMode(Handle<Map> map); 2343 2344 HInstruction* BuildMonomorphicElementAccess(HValue* object, 2345 HValue* key, 2346 HValue* val, 2347 HValue* dependency, 2348 Handle<Map> map, 2349 bool is_store, 2350 KeyedAccessStoreMode store_mode); 2351 2352 HValue* HandlePolymorphicElementAccess(HValue* object, 2353 HValue* key, 2354 HValue* val, 2355 SmallMapList* maps, 2356 bool is_store, 2357 KeyedAccessStoreMode store_mode, 2358 bool* has_side_effects); 2359 2360 HValue* HandleKeyedElementAccess(HValue* obj, 2361 HValue* key, 2362 HValue* val, 2363 Expression* expr, 2364 bool is_store, 2365 bool* has_side_effects); 2366 2367 HInstruction* BuildLoadNamedGeneric(HValue* object, 2368 Handle<String> name, 2369 Property* expr); 2370 2371 HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map); 2372 2373 void BuildLoad(Property* property, 2374 BailoutId ast_id); 2375 void PushLoad(Property* property, 2376 HValue* object, 2377 HValue* key); 2378 2379 void BuildStoreForEffect(Expression* expression, 2380 Property* prop, 2381 BailoutId ast_id, 2382 BailoutId return_id, 2383 HValue* object, 2384 HValue* key, 2385 HValue* value); 2386 2387 void BuildStore(Expression* expression, 2388 Property* prop, 2389 BailoutId ast_id, 2390 BailoutId return_id, 2391 bool is_uninitialized = false); 2392 2393 HInstruction* BuildStoreNamedField(HValue* object, 2394 Handle<String> name, 2395 HValue* value, 2396 Handle<Map> map, 2397 LookupResult* lookup); 2398 HInstruction* BuildStoreNamedGeneric(HValue* object, 2399 Handle<String> name, 2400 HValue* value); 2401 HInstruction* BuildStoreNamedMonomorphic(HValue* object, 2402 Handle<String> name, 2403 HValue* value, 2404 Handle<Map> map); 2405 HInstruction* BuildStoreKeyedGeneric(HValue* object, 2406 HValue* key, 2407 HValue* value); 2408 2409 HValue* BuildContextChainWalk(Variable* var); 2410 2411 HInstruction* BuildThisFunction(); 2412 2413 HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object, 2414 AllocationSiteUsageContext* site_context); 2415 2416 void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object, 2417 HInstruction* object); 2418 2419 void BuildInitElementsInObjectHeader(Handle<JSObject> boilerplate_object, 2420 HInstruction* object, 2421 HInstruction* object_elements); 2422 2423 void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object, 2424 HInstruction* object, 2425 AllocationSiteUsageContext* site_context, 2426 PretenureFlag pretenure_flag); 2427 2428 void BuildEmitElements(Handle<JSObject> boilerplate_object, 2429 Handle<FixedArrayBase> elements, 2430 HValue* object_elements, 2431 AllocationSiteUsageContext* site_context); 2432 2433 void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements, 2434 ElementsKind kind, 2435 HValue* object_elements); 2436 2437 void BuildEmitFixedArray(Handle<FixedArrayBase> elements, 2438 ElementsKind kind, 2439 HValue* object_elements, 2440 AllocationSiteUsageContext* site_context); 2441 2442 void AddCheckPrototypeMaps(Handle<JSObject> holder, 2443 Handle<Map> receiver_map); 2444 2445 void AddCheckConstantFunction(Handle<JSObject> holder, 2446 HValue* receiver, 2447 Handle<Map> receiver_map); 2448 2449 // The translation state of the currently-being-translated function. 2450 FunctionState* function_state_; 2451 2452 // The base of the function state stack. 2453 FunctionState initial_function_state_; 2454 2455 // Expression context of the currently visited subexpression. NULL when 2456 // visiting statements. 2457 AstContext* ast_context_; 2458 2459 // A stack of breakable statements entered. 2460 BreakAndContinueScope* break_scope_; 2461 2462 int inlined_count_; 2463 ZoneList<Handle<Object> > globals_; 2464 2465 bool inline_bailout_; 2466 2467 HOsrBuilder* osr_; 2468 2469 friend class FunctionState; // Pushes and pops the state stack. 2470 friend class AstContext; // Pushes and pops the AST context stack. 2471 friend class KeyedLoadFastElementStub; 2472 friend class HOsrBuilder; 2473 2474 DISALLOW_COPY_AND_ASSIGN(HOptimizedGraphBuilder); 2475 }; 2476 2477 2478 Zone* AstContext::zone() const { return owner_->zone(); } 2479 2480 2481 class HStatistics V8_FINAL: public Malloced { 2482 public: 2483 HStatistics() 2484 : times_(5), 2485 names_(5), 2486 sizes_(5), 2487 total_size_(0), 2488 source_size_(0) { } 2489 2490 void Initialize(CompilationInfo* info); 2491 void Print(); 2492 void SaveTiming(const char* name, TimeDelta time, unsigned size); 2493 2494 void IncrementFullCodeGen(TimeDelta full_code_gen) { 2495 full_code_gen_ += full_code_gen; 2496 } 2497 2498 void IncrementSubtotals(TimeDelta create_graph, 2499 TimeDelta optimize_graph, 2500 TimeDelta generate_code) { 2501 create_graph_ += create_graph; 2502 optimize_graph_ += optimize_graph; 2503 generate_code_ += generate_code; 2504 } 2505 2506 private: 2507 List<TimeDelta> times_; 2508 List<const char*> names_; 2509 List<unsigned> sizes_; 2510 TimeDelta create_graph_; 2511 TimeDelta optimize_graph_; 2512 TimeDelta generate_code_; 2513 unsigned total_size_; 2514 TimeDelta full_code_gen_; 2515 double source_size_; 2516 }; 2517 2518 2519 class HPhase : public CompilationPhase { 2520 public: 2521 HPhase(const char* name, HGraph* graph) 2522 : CompilationPhase(name, graph->info()), 2523 graph_(graph) { } 2524 ~HPhase(); 2525 2526 protected: 2527 HGraph* graph() const { return graph_; } 2528 2529 private: 2530 HGraph* graph_; 2531 2532 DISALLOW_COPY_AND_ASSIGN(HPhase); 2533 }; 2534 2535 2536 class HTracer V8_FINAL : public Malloced { 2537 public: 2538 explicit HTracer(int isolate_id) 2539 : trace_(&string_allocator_), indent_(0) { 2540 if (FLAG_trace_hydrogen_file == NULL) { 2541 OS::SNPrintF(filename_, 2542 "hydrogen-%d-%d.cfg", 2543 OS::GetCurrentProcessId(), 2544 isolate_id); 2545 } else { 2546 OS::StrNCpy(filename_, FLAG_trace_hydrogen_file, filename_.length()); 2547 } 2548 WriteChars(filename_.start(), "", 0, false); 2549 } 2550 2551 void TraceCompilation(CompilationInfo* info); 2552 void TraceHydrogen(const char* name, HGraph* graph); 2553 void TraceLithium(const char* name, LChunk* chunk); 2554 void TraceLiveRanges(const char* name, LAllocator* allocator); 2555 2556 private: 2557 class Tag V8_FINAL BASE_EMBEDDED { 2558 public: 2559 Tag(HTracer* tracer, const char* name) { 2560 name_ = name; 2561 tracer_ = tracer; 2562 tracer->PrintIndent(); 2563 tracer->trace_.Add("begin_%s\n", name); 2564 tracer->indent_++; 2565 } 2566 2567 ~Tag() { 2568 tracer_->indent_--; 2569 tracer_->PrintIndent(); 2570 tracer_->trace_.Add("end_%s\n", name_); 2571 ASSERT(tracer_->indent_ >= 0); 2572 tracer_->FlushToFile(); 2573 } 2574 2575 private: 2576 HTracer* tracer_; 2577 const char* name_; 2578 }; 2579 2580 void TraceLiveRange(LiveRange* range, const char* type, Zone* zone); 2581 void Trace(const char* name, HGraph* graph, LChunk* chunk); 2582 void FlushToFile(); 2583 2584 void PrintEmptyProperty(const char* name) { 2585 PrintIndent(); 2586 trace_.Add("%s\n", name); 2587 } 2588 2589 void PrintStringProperty(const char* name, const char* value) { 2590 PrintIndent(); 2591 trace_.Add("%s \"%s\"\n", name, value); 2592 } 2593 2594 void PrintLongProperty(const char* name, int64_t value) { 2595 PrintIndent(); 2596 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000)); 2597 } 2598 2599 void PrintBlockProperty(const char* name, int block_id) { 2600 PrintIndent(); 2601 trace_.Add("%s \"B%d\"\n", name, block_id); 2602 } 2603 2604 void PrintIntProperty(const char* name, int value) { 2605 PrintIndent(); 2606 trace_.Add("%s %d\n", name, value); 2607 } 2608 2609 void PrintIndent() { 2610 for (int i = 0; i < indent_; i++) { 2611 trace_.Add(" "); 2612 } 2613 } 2614 2615 EmbeddedVector<char, 64> filename_; 2616 HeapStringAllocator string_allocator_; 2617 StringStream trace_; 2618 int indent_; 2619 }; 2620 2621 2622 class NoObservableSideEffectsScope V8_FINAL { 2623 public: 2624 explicit NoObservableSideEffectsScope(HGraphBuilder* builder) : 2625 builder_(builder) { 2626 builder_->graph()->IncrementInNoSideEffectsScope(); 2627 } 2628 ~NoObservableSideEffectsScope() { 2629 builder_->graph()->DecrementInNoSideEffectsScope(); 2630 } 2631 2632 private: 2633 HGraphBuilder* builder_; 2634 }; 2635 2636 2637 } } // namespace v8::internal 2638 2639 #endif // V8_HYDROGEN_H_ 2640