| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 void HBasicBlock::AddPhi(HPhi* phi) { | 85 void HBasicBlock::AddPhi(HPhi* phi) { |
| 86 ASSERT(!IsStartBlock()); | 86 ASSERT(!IsStartBlock()); |
| 87 phis_.Add(phi); | 87 phis_.Add(phi); |
| 88 phi->SetBlock(this); | 88 phi->SetBlock(this); |
| 89 } | 89 } |
| 90 | 90 |
| 91 | 91 |
| 92 void HBasicBlock::RemovePhi(HPhi* phi) { | 92 void HBasicBlock::RemovePhi(HPhi* phi) { |
| 93 ASSERT(phi->block() == this); | 93 ASSERT(phi->block() == this); |
| 94 ASSERT(phis_.Contains(phi)); | 94 ASSERT(phis_.Contains(phi)); |
| 95 ASSERT(phi->HasNoUses()); | 95 ASSERT(phi->HasNoUses() || !phi->is_live()); |
| 96 phi->ClearOperands(); | 96 phi->ClearOperands(); |
| 97 phis_.RemoveElement(phi); | 97 phis_.RemoveElement(phi); |
| 98 phi->SetBlock(NULL); | 98 phi->SetBlock(NULL); |
| 99 } | 99 } |
| 100 | 100 |
| 101 | 101 |
| 102 void HBasicBlock::AddInstruction(HInstruction* instr) { | 102 void HBasicBlock::AddInstruction(HInstruction* instr) { |
| 103 ASSERT(!IsStartBlock() || !IsFinished()); | 103 ASSERT(!IsStartBlock() || !IsFinished()); |
| 104 ASSERT(!instr->IsLinked()); | 104 ASSERT(!instr->IsLinked()); |
| 105 ASSERT(!IsFinished()); | 105 ASSERT(!IsFinished()); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 if (end->FirstSuccessor() != NULL) { | 143 if (end->FirstSuccessor() != NULL) { |
| 144 end->FirstSuccessor()->RegisterPredecessor(this); | 144 end->FirstSuccessor()->RegisterPredecessor(this); |
| 145 if (end->SecondSuccessor() != NULL) { | 145 if (end->SecondSuccessor() != NULL) { |
| 146 end->SecondSuccessor()->RegisterPredecessor(this); | 146 end->SecondSuccessor()->RegisterPredecessor(this); |
| 147 } | 147 } |
| 148 } | 148 } |
| 149 } | 149 } |
| 150 | 150 |
| 151 | 151 |
| 152 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) { | 152 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) { |
| 153 if (block->IsInlineReturnTarget()) { |
| 154 AddInstruction(new HLeaveInlined); |
| 155 last_environment_ = last_environment()->outer(); |
| 156 } |
| 153 AddSimulate(AstNode::kNoNumber); | 157 AddSimulate(AstNode::kNoNumber); |
| 154 HGoto* instr = new HGoto(block); | 158 HGoto* instr = new HGoto(block); |
| 155 instr->set_include_stack_check(include_stack_check); | 159 instr->set_include_stack_check(include_stack_check); |
| 156 Finish(instr); | 160 Finish(instr); |
| 157 } | 161 } |
| 158 | 162 |
| 159 | 163 |
| 164 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 165 ASSERT(target->IsInlineReturnTarget()); |
| 166 ASSERT(return_value != NULL); |
| 167 AddInstruction(new HLeaveInlined); |
| 168 last_environment_ = last_environment()->outer(); |
| 169 last_environment()->Push(return_value); |
| 170 AddSimulate(AstNode::kNoNumber); |
| 171 HGoto* instr = new HGoto(target); |
| 172 Finish(instr); |
| 173 } |
| 174 |
| 175 |
| 160 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { | 176 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { |
| 161 ASSERT(!HasEnvironment()); | 177 ASSERT(!HasEnvironment()); |
| 162 ASSERT(first() == NULL); | 178 ASSERT(first() == NULL); |
| 163 UpdateEnvironment(env); | 179 UpdateEnvironment(env); |
| 164 } | 180 } |
| 165 | 181 |
| 166 | 182 |
| 167 void HBasicBlock::SetJoinId(int id) { | 183 void HBasicBlock::SetJoinId(int id) { |
| 168 int length = predecessors_.length(); | 184 int length = predecessors_.length(); |
| 169 ASSERT(length > 0); | 185 ASSERT(length > 0); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 UNREACHABLE(); | 295 UNREACHABLE(); |
| 280 return -1; | 296 return -1; |
| 281 } | 297 } |
| 282 | 298 |
| 283 | 299 |
| 284 #ifdef DEBUG | 300 #ifdef DEBUG |
| 285 void HBasicBlock::Verify() { | 301 void HBasicBlock::Verify() { |
| 286 // Check that every block is finished. | 302 // Check that every block is finished. |
| 287 ASSERT(IsFinished()); | 303 ASSERT(IsFinished()); |
| 288 ASSERT(block_id() >= 0); | 304 ASSERT(block_id() >= 0); |
| 305 |
| 306 // Check that the incoming edges are in edge split form. |
| 307 if (predecessors_.length() > 1) { |
| 308 for (int i = 0; i < predecessors_.length(); ++i) { |
| 309 ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL); |
| 310 } |
| 311 } |
| 289 } | 312 } |
| 290 #endif | 313 #endif |
| 291 | 314 |
| 292 | 315 |
| 293 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { | 316 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { |
| 294 this->back_edges_.Add(block); | 317 this->back_edges_.Add(block); |
| 295 AddBlock(block); | 318 AddBlock(block); |
| 296 } | 319 } |
| 297 | 320 |
| 298 | 321 |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 HConstant* HGraph::GetConstantTrue() { | 498 HConstant* HGraph::GetConstantTrue() { |
| 476 return GetConstant(&constant_true_, Heap::true_value()); | 499 return GetConstant(&constant_true_, Heap::true_value()); |
| 477 } | 500 } |
| 478 | 501 |
| 479 | 502 |
| 480 HConstant* HGraph::GetConstantFalse() { | 503 HConstant* HGraph::GetConstantFalse() { |
| 481 return GetConstant(&constant_false_, Heap::false_value()); | 504 return GetConstant(&constant_false_, Heap::false_value()); |
| 482 } | 505 } |
| 483 | 506 |
| 484 | 507 |
| 485 void HSubgraph::AppendOptional(HSubgraph* graph, | 508 HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first, |
| 486 bool on_true_branch, | 509 HBasicBlock* second, |
| 487 HValue* value) { | 510 int join_id) { |
| 488 ASSERT(HasExit() && graph->HasExit()); | 511 if (first == NULL) { |
| 489 HBasicBlock* other_block = graph_->CreateBasicBlock(); | 512 return second; |
| 490 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 513 } else if (second == NULL) { |
| 491 | 514 return first; |
| 492 HTest* test = on_true_branch | 515 } else { |
| 493 ? new HTest(value, graph->entry_block(), other_block) | |
| 494 : new HTest(value, other_block, graph->entry_block()); | |
| 495 exit_block_->Finish(test); | |
| 496 other_block->Goto(join_block); | |
| 497 graph->exit_block()->Goto(join_block); | |
| 498 exit_block_ = join_block; | |
| 499 } | |
| 500 | |
| 501 | |
| 502 void HSubgraph::AppendJoin(HSubgraph* then_graph, | |
| 503 HSubgraph* else_graph, | |
| 504 AstNode* node) { | |
| 505 if (then_graph->HasExit() && else_graph->HasExit()) { | |
| 506 // We need to merge, create new merge block. | |
| 507 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 516 HBasicBlock* join_block = graph_->CreateBasicBlock(); |
| 508 then_graph->exit_block()->Goto(join_block); | 517 first->Goto(join_block); |
| 509 else_graph->exit_block()->Goto(join_block); | 518 second->Goto(join_block); |
| 510 join_block->SetJoinId(node->id()); | 519 join_block->SetJoinId(join_id); |
| 511 exit_block_ = join_block; | 520 return join_block; |
| 512 } else if (then_graph->HasExit()) { | |
| 513 exit_block_ = then_graph->exit_block_; | |
| 514 } else if (else_graph->HasExit()) { | |
| 515 exit_block_ = else_graph->exit_block_; | |
| 516 } else { | |
| 517 exit_block_ = NULL; | |
| 518 } | 521 } |
| 519 } | 522 } |
| 520 | 523 |
| 521 | 524 |
| 522 void HSubgraph::ResolveContinue(IterationStatement* statement) { | 525 HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement, |
| 523 HBasicBlock* continue_block = BundleContinue(statement); | 526 HBasicBlock* exit_block, |
| 527 HBasicBlock* continue_block) { |
| 524 if (continue_block != NULL) { | 528 if (continue_block != NULL) { |
| 525 exit_block_ = JoinBlocks(exit_block(), | 529 if (exit_block != NULL) exit_block->Goto(continue_block); |
| 526 continue_block, | 530 continue_block->SetJoinId(statement->ContinueId()); |
| 527 statement->ContinueId()); | 531 return continue_block; |
| 528 } | 532 } |
| 533 return exit_block; |
| 529 } | 534 } |
| 530 | 535 |
| 531 | 536 |
| 532 HBasicBlock* HSubgraph::BundleBreak(BreakableStatement* statement) { | 537 HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement, |
| 533 return BundleBreakContinue(statement, false, statement->ExitId()); | 538 HBasicBlock* loop_entry, |
| 539 HBasicBlock* body_exit, |
| 540 HBasicBlock* loop_successor, |
| 541 HBasicBlock* break_block) { |
| 542 if (body_exit != NULL) body_exit->Goto(loop_entry, true); |
| 543 loop_entry->PostProcessLoopHeader(statement); |
| 544 if (break_block != NULL) { |
| 545 if (loop_successor != NULL) loop_successor->Goto(break_block); |
| 546 break_block->SetJoinId(statement->ExitId()); |
| 547 return break_block; |
| 548 } |
| 549 return loop_successor; |
| 534 } | 550 } |
| 535 | 551 |
| 536 | 552 |
| 537 HBasicBlock* HSubgraph::BundleContinue(IterationStatement* statement) { | 553 void HBasicBlock::FinishExit(HControlInstruction* instruction) { |
| 538 return BundleBreakContinue(statement, true, statement->ContinueId()); | 554 Finish(instruction); |
| 539 } | 555 ClearEnvironment(); |
| 540 | |
| 541 | |
| 542 HBasicBlock* HSubgraph::BundleBreakContinue(BreakableStatement* statement, | |
| 543 bool is_continue, | |
| 544 int join_id) { | |
| 545 HBasicBlock* result = NULL; | |
| 546 const ZoneList<BreakContinueInfo*>* infos = break_continue_info(); | |
| 547 for (int i = 0; i < infos->length(); ++i) { | |
| 548 BreakContinueInfo* info = infos->at(i); | |
| 549 if (info->is_continue() == is_continue && | |
| 550 info->target() == statement && | |
| 551 !info->IsResolved()) { | |
| 552 if (result == NULL) { | |
| 553 result = graph_->CreateBasicBlock(); | |
| 554 } | |
| 555 info->block()->Goto(result); | |
| 556 info->Resolve(); | |
| 557 } | |
| 558 } | |
| 559 | |
| 560 if (result != NULL) result->SetJoinId(join_id); | |
| 561 | |
| 562 return result; | |
| 563 } | |
| 564 | |
| 565 | |
| 566 HBasicBlock* HSubgraph::JoinBlocks(HBasicBlock* a, HBasicBlock* b, int id) { | |
| 567 if (a == NULL) return b; | |
| 568 if (b == NULL) return a; | |
| 569 HBasicBlock* target = graph_->CreateBasicBlock(); | |
| 570 a->Goto(target); | |
| 571 b->Goto(target); | |
| 572 target->SetJoinId(id); | |
| 573 return target; | |
| 574 } | |
| 575 | |
| 576 | |
| 577 void HSubgraph::AppendEndless(HSubgraph* body, IterationStatement* statement) { | |
| 578 ConnectExitTo(body->entry_block()); | |
| 579 body->ResolveContinue(statement); | |
| 580 body->ConnectExitTo(body->entry_block(), true); | |
| 581 exit_block_ = body->BundleBreak(statement); | |
| 582 body->entry_block()->PostProcessLoopHeader(statement); | |
| 583 } | |
| 584 | |
| 585 | |
| 586 void HSubgraph::AppendDoWhile(HSubgraph* body, | |
| 587 IterationStatement* statement, | |
| 588 HSubgraph* go_back, | |
| 589 HSubgraph* exit) { | |
| 590 ConnectExitTo(body->entry_block()); | |
| 591 go_back->ConnectExitTo(body->entry_block(), true); | |
| 592 | |
| 593 HBasicBlock* break_block = body->BundleBreak(statement); | |
| 594 exit_block_ = | |
| 595 JoinBlocks(exit->exit_block(), break_block, statement->ExitId()); | |
| 596 body->entry_block()->PostProcessLoopHeader(statement); | |
| 597 } | |
| 598 | |
| 599 | |
| 600 void HSubgraph::AppendWhile(HSubgraph* condition, | |
| 601 HSubgraph* body, | |
| 602 IterationStatement* statement, | |
| 603 HSubgraph* continue_subgraph, | |
| 604 HSubgraph* exit) { | |
| 605 ConnectExitTo(condition->entry_block()); | |
| 606 | |
| 607 HBasicBlock* break_block = body->BundleBreak(statement); | |
| 608 exit_block_ = | |
| 609 JoinBlocks(exit->exit_block(), break_block, statement->ExitId()); | |
| 610 | |
| 611 if (continue_subgraph != NULL) { | |
| 612 body->ConnectExitTo(continue_subgraph->entry_block(), true); | |
| 613 continue_subgraph->entry_block()->SetJoinId(statement->EntryId()); | |
| 614 exit_block_ = JoinBlocks(exit_block_, | |
| 615 continue_subgraph->exit_block(), | |
| 616 statement->ExitId()); | |
| 617 } else { | |
| 618 body->ConnectExitTo(condition->entry_block(), true); | |
| 619 } | |
| 620 condition->entry_block()->PostProcessLoopHeader(statement); | |
| 621 } | |
| 622 | |
| 623 | |
| 624 void HSubgraph::Append(HSubgraph* next, BreakableStatement* stmt) { | |
| 625 exit_block_->Goto(next->entry_block()); | |
| 626 exit_block_ = next->exit_block_; | |
| 627 | |
| 628 if (stmt != NULL) { | |
| 629 next->entry_block()->SetJoinId(stmt->EntryId()); | |
| 630 HBasicBlock* break_block = next->BundleBreak(stmt); | |
| 631 exit_block_ = JoinBlocks(exit_block(), break_block, stmt->ExitId()); | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 | |
| 636 void HSubgraph::FinishExit(HControlInstruction* instruction) { | |
| 637 ASSERT(HasExit()); | |
| 638 exit_block_->Finish(instruction); | |
| 639 exit_block_->ClearEnvironment(); | |
| 640 exit_block_ = NULL; | |
| 641 } | |
| 642 | |
| 643 | |
| 644 void HSubgraph::FinishBreakContinue(BreakableStatement* target, | |
| 645 bool is_continue) { | |
| 646 ASSERT(!exit_block_->IsFinished()); | |
| 647 BreakContinueInfo* info = new BreakContinueInfo(target, exit_block_, | |
| 648 is_continue); | |
| 649 break_continue_info_.Add(info); | |
| 650 exit_block_ = NULL; | |
| 651 } | 556 } |
| 652 | 557 |
| 653 | 558 |
| 654 HGraph::HGraph(CompilationInfo* info) | 559 HGraph::HGraph(CompilationInfo* info) |
| 655 : HSubgraph(this), | 560 : next_block_id_(0), |
| 656 next_block_id_(0), | 561 entry_block_(NULL), |
| 657 info_(info), | |
| 658 blocks_(8), | 562 blocks_(8), |
| 659 values_(16), | 563 values_(16), |
| 660 phi_list_(NULL) { | 564 phi_list_(NULL) { |
| 661 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); | 565 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); |
| 662 start_environment_->set_ast_id(info->function()->id()); | 566 start_environment_->set_ast_id(info->function()->id()); |
| 567 entry_block_ = CreateBasicBlock(); |
| 568 entry_block_->SetInitialEnvironment(start_environment_); |
| 663 } | 569 } |
| 664 | 570 |
| 665 | 571 |
| 666 bool HGraph::AllowCodeMotion() const { | 572 Handle<Code> HGraph::Compile(CompilationInfo* info) { |
| 667 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; | |
| 668 } | |
| 669 | |
| 670 | |
| 671 Handle<Code> HGraph::Compile() { | |
| 672 int values = GetMaximumValueID(); | 573 int values = GetMaximumValueID(); |
| 673 if (values > LAllocator::max_initial_value_ids()) { | 574 if (values > LAllocator::max_initial_value_ids()) { |
| 674 if (FLAG_trace_bailout) PrintF("Function is too big\n"); | 575 if (FLAG_trace_bailout) PrintF("Function is too big\n"); |
| 675 return Handle<Code>::null(); | 576 return Handle<Code>::null(); |
| 676 } | 577 } |
| 677 | 578 |
| 678 LAllocator allocator(values, this); | 579 LAllocator allocator(values, this); |
| 679 LChunkBuilder builder(this, &allocator); | 580 LChunkBuilder builder(info, this, &allocator); |
| 680 LChunk* chunk = builder.Build(); | 581 LChunk* chunk = builder.Build(); |
| 681 if (chunk == NULL) return Handle<Code>::null(); | 582 if (chunk == NULL) return Handle<Code>::null(); |
| 682 | 583 |
| 683 if (!FLAG_alloc_lithium) return Handle<Code>::null(); | 584 if (!FLAG_alloc_lithium) return Handle<Code>::null(); |
| 684 | 585 |
| 685 allocator.Allocate(chunk); | 586 allocator.Allocate(chunk); |
| 686 | 587 |
| 687 if (!FLAG_use_lithium) return Handle<Code>::null(); | 588 if (!FLAG_use_lithium) return Handle<Code>::null(); |
| 688 | 589 |
| 689 MacroAssembler assembler(NULL, 0); | 590 MacroAssembler assembler(NULL, 0); |
| 690 LCodeGen generator(chunk, &assembler, info()); | 591 LCodeGen generator(chunk, &assembler, info); |
| 691 | 592 |
| 692 if (FLAG_eliminate_empty_blocks) { | 593 if (FLAG_eliminate_empty_blocks) { |
| 693 chunk->MarkEmptyBlocks(); | 594 chunk->MarkEmptyBlocks(); |
| 694 } | 595 } |
| 695 | 596 |
| 696 if (generator.GenerateCode()) { | 597 if (generator.GenerateCode()) { |
| 697 if (FLAG_trace_codegen) { | 598 if (FLAG_trace_codegen) { |
| 698 PrintF("Crankshaft Compiler - "); | 599 PrintF("Crankshaft Compiler - "); |
| 699 } | 600 } |
| 700 CodeGenerator::MakeCodePrologue(info()); | 601 CodeGenerator::MakeCodePrologue(info); |
| 701 Code::Flags flags = | 602 Code::Flags flags = |
| 702 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP); | 603 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP); |
| 703 Handle<Code> code = | 604 Handle<Code> code = |
| 704 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info()); | 605 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info); |
| 705 generator.FinishCode(code); | 606 generator.FinishCode(code); |
| 706 CodeGenerator::PrintCode(code, info()); | 607 CodeGenerator::PrintCode(code, info); |
| 707 return code; | 608 return code; |
| 708 } | 609 } |
| 709 return Handle<Code>::null(); | 610 return Handle<Code>::null(); |
| 710 } | 611 } |
| 711 | 612 |
| 712 | 613 |
| 713 HBasicBlock* HGraph::CreateBasicBlock() { | 614 HBasicBlock* HGraph::CreateBasicBlock() { |
| 714 HBasicBlock* result = new HBasicBlock(this); | 615 HBasicBlock* result = new HBasicBlock(this); |
| 715 blocks_.Add(result); | 616 blocks_.Add(result); |
| 716 return result; | 617 return result; |
| 717 } | 618 } |
| 718 | 619 |
| 719 | 620 |
| 720 void HGraph::Canonicalize() { | 621 void HGraph::Canonicalize() { |
| 622 if (!FLAG_use_canonicalizing) return; |
| 721 HPhase phase("Canonicalize", this); | 623 HPhase phase("Canonicalize", this); |
| 722 if (FLAG_use_canonicalizing) { | 624 for (int i = 0; i < blocks()->length(); ++i) { |
| 723 for (int i = 0; i < blocks()->length(); ++i) { | 625 HInstruction* instr = blocks()->at(i)->first(); |
| 724 HBasicBlock* b = blocks()->at(i); | 626 while (instr != NULL) { |
| 725 for (HInstruction* insn = b->first(); insn != NULL; insn = insn->next()) { | 627 HValue* value = instr->Canonicalize(); |
| 726 HValue* value = insn->Canonicalize(); | 628 if (value != instr) instr->ReplaceAndDelete(value); |
| 727 if (value != insn) { | 629 instr = instr->next(); |
| 728 if (value != NULL) { | |
| 729 insn->ReplaceAndDelete(value); | |
| 730 } else { | |
| 731 insn->Delete(); | |
| 732 } | |
| 733 } | |
| 734 } | |
| 735 } | 630 } |
| 736 } | 631 } |
| 737 } | 632 } |
| 738 | 633 |
| 739 | 634 |
| 740 void HGraph::OrderBlocks() { | 635 void HGraph::OrderBlocks() { |
| 741 HPhase phase("Block ordering"); | 636 HPhase phase("Block ordering"); |
| 742 BitVector visited(blocks_.length()); | 637 BitVector visited(blocks_.length()); |
| 743 | 638 |
| 744 ZoneList<HBasicBlock*> reverse_result(8); | 639 ZoneList<HBasicBlock*> reverse_result(8); |
| 745 HBasicBlock* start = blocks_[0]; | 640 HBasicBlock* start = blocks_[0]; |
| 746 Postorder(start, &visited, &reverse_result, NULL); | 641 Postorder(start, &visited, &reverse_result, NULL); |
| 747 | 642 |
| 748 blocks_.Clear(); | 643 blocks_.Rewind(0); |
| 749 int index = 0; | 644 int index = 0; |
| 750 for (int i = reverse_result.length() - 1; i >= 0; --i) { | 645 for (int i = reverse_result.length() - 1; i >= 0; --i) { |
| 751 HBasicBlock* b = reverse_result[i]; | 646 HBasicBlock* b = reverse_result[i]; |
| 752 blocks_.Add(b); | 647 blocks_.Add(b); |
| 753 b->set_block_id(index++); | 648 b->set_block_id(index++); |
| 754 } | 649 } |
| 755 } | 650 } |
| 756 | 651 |
| 757 | 652 |
| 758 void HGraph::PostorderLoopBlocks(HLoopInformation* loop, | 653 void HGraph::PostorderLoopBlocks(HLoopInformation* loop, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 } else { | 698 } else { |
| 804 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) { | 699 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) { |
| 805 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); | 700 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); |
| 806 } | 701 } |
| 807 } | 702 } |
| 808 } | 703 } |
| 809 } | 704 } |
| 810 | 705 |
| 811 | 706 |
| 812 void HGraph::EliminateRedundantPhis() { | 707 void HGraph::EliminateRedundantPhis() { |
| 813 HPhase phase("Phi elimination", this); | 708 HPhase phase("Redundant phi elimination", this); |
| 814 ZoneList<HValue*> uses_to_replace(2); | |
| 815 | 709 |
| 816 // Worklist of phis that can potentially be eliminated. Initialized | 710 // Worklist of phis that can potentially be eliminated. Initialized |
| 817 // with all phi nodes. When elimination of a phi node modifies | 711 // with all phi nodes. When elimination of a phi node modifies |
| 818 // another phi node the modified phi node is added to the worklist. | 712 // another phi node the modified phi node is added to the worklist. |
| 819 ZoneList<HPhi*> worklist(blocks_.length()); | 713 ZoneList<HPhi*> worklist(blocks_.length()); |
| 820 for (int i = 0; i < blocks_.length(); ++i) { | 714 for (int i = 0; i < blocks_.length(); ++i) { |
| 821 worklist.AddAll(*blocks_[i]->phis()); | 715 worklist.AddAll(*blocks_[i]->phis()); |
| 822 } | 716 } |
| 823 | 717 |
| 824 while (!worklist.is_empty()) { | 718 while (!worklist.is_empty()) { |
| 825 HPhi* phi = worklist.RemoveLast(); | 719 HPhi* phi = worklist.RemoveLast(); |
| 826 HBasicBlock* block = phi->block(); | 720 HBasicBlock* block = phi->block(); |
| 827 | 721 |
| 828 // Skip phi node if it was already replaced. | 722 // Skip phi node if it was already replaced. |
| 829 if (block == NULL) continue; | 723 if (block == NULL) continue; |
| 830 | 724 |
| 831 // Get replacement value if phi is redundant. | 725 // Get replacement value if phi is redundant. |
| 832 HValue* value = phi->GetRedundantReplacement(); | 726 HValue* value = phi->GetRedundantReplacement(); |
| 833 | 727 |
| 834 if (value != NULL) { | 728 if (value != NULL) { |
| 835 // Iterate through uses finding the ones that should be | 729 // Iterate through uses finding the ones that should be |
| 836 // replaced. | 730 // replaced. |
| 837 const ZoneList<HValue*>* uses = phi->uses(); | 731 ZoneList<HValue*>* uses = phi->uses(); |
| 838 for (int i = 0; i < uses->length(); ++i) { | 732 while (!uses->is_empty()) { |
| 839 HValue* use = uses->at(i); | 733 HValue* use = uses->RemoveLast(); |
| 840 if (!use->block()->IsStartBlock()) { | 734 if (use != NULL) { |
| 841 uses_to_replace.Add(use); | 735 phi->ReplaceAtUse(use, value); |
| 736 if (use->IsPhi()) worklist.Add(HPhi::cast(use)); |
| 842 } | 737 } |
| 843 } | 738 } |
| 844 // Replace the uses and add phis modified to the work list. | |
| 845 for (int i = 0; i < uses_to_replace.length(); ++i) { | |
| 846 HValue* use = uses_to_replace[i]; | |
| 847 phi->ReplaceAtUse(use, value); | |
| 848 if (use->IsPhi()) worklist.Add(HPhi::cast(use)); | |
| 849 } | |
| 850 uses_to_replace.Rewind(0); | |
| 851 block->RemovePhi(phi); | 739 block->RemovePhi(phi); |
| 852 } else if (FLAG_eliminate_dead_phis && phi->HasNoUses() && | 740 } |
| 853 !phi->IsReceiver()) { | 741 } |
| 742 } |
| 743 |
| 744 |
| 745 void HGraph::EliminateUnreachablePhis() { |
| 746 HPhase phase("Unreachable phi elimination", this); |
| 747 |
| 748 // Initialize worklist. |
| 749 ZoneList<HPhi*> phi_list(blocks_.length()); |
| 750 ZoneList<HPhi*> worklist(blocks_.length()); |
| 751 for (int i = 0; i < blocks_.length(); ++i) { |
| 752 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { |
| 753 HPhi* phi = blocks_[i]->phis()->at(j); |
| 754 phi_list.Add(phi); |
| 854 // We can't eliminate phis in the receiver position in the environment | 755 // We can't eliminate phis in the receiver position in the environment |
| 855 // because in case of throwing an error we need this value to | 756 // because in case of throwing an error we need this value to |
| 856 // construct a stack trace. | 757 // construct a stack trace. |
| 758 if (phi->HasRealUses() || phi->IsReceiver()) { |
| 759 phi->set_is_live(true); |
| 760 worklist.Add(phi); |
| 761 } |
| 762 } |
| 763 } |
| 764 |
| 765 // Iteratively mark live phis. |
| 766 while (!worklist.is_empty()) { |
| 767 HPhi* phi = worklist.RemoveLast(); |
| 768 for (int i = 0; i < phi->OperandCount(); i++) { |
| 769 HValue* operand = phi->OperandAt(i); |
| 770 if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) { |
| 771 HPhi::cast(operand)->set_is_live(true); |
| 772 worklist.Add(HPhi::cast(operand)); |
| 773 } |
| 774 } |
| 775 } |
| 776 |
| 777 // Remove unreachable phis. |
| 778 for (int i = 0; i < phi_list.length(); i++) { |
| 779 HPhi* phi = phi_list[i]; |
| 780 if (!phi->is_live()) { |
| 781 HBasicBlock* block = phi->block(); |
| 857 block->RemovePhi(phi); | 782 block->RemovePhi(phi); |
| 858 block->RecordDeletedPhi(phi->merged_index()); | 783 block->RecordDeletedPhi(phi->merged_index()); |
| 859 } | 784 } |
| 860 } | 785 } |
| 861 } | 786 } |
| 862 | 787 |
| 863 | 788 |
| 864 bool HGraph::CollectPhis() { | 789 bool HGraph::CollectPhis() { |
| 865 const ZoneList<HBasicBlock*>* blocks = graph_->blocks(); | 790 int block_count = blocks_.length(); |
| 866 phi_list_ = new ZoneList<HPhi*>(blocks->length()); | 791 phi_list_ = new ZoneList<HPhi*>(block_count); |
| 867 for (int i = 0; i < blocks->length(); ++i) { | 792 for (int i = 0; i < block_count; ++i) { |
| 868 for (int j = 0; j < blocks->at(i)->phis()->length(); j++) { | 793 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
| 869 HPhi* phi = blocks->at(i)->phis()->at(j); | 794 HPhi* phi = blocks_[i]->phis()->at(j); |
| 870 phi_list_->Add(phi); | 795 phi_list_->Add(phi); |
| 871 // We don't support phi uses of arguments for now. | 796 // We don't support phi uses of arguments for now. |
| 872 if (phi->CheckFlag(HValue::kIsArguments)) return false; | 797 if (phi->CheckFlag(HValue::kIsArguments)) return false; |
| 873 } | 798 } |
| 874 } | 799 } |
| 875 return true; | 800 return true; |
| 876 } | 801 } |
| 877 | 802 |
| 878 | 803 |
| 879 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { | 804 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 } | 893 } |
| 969 | 894 |
| 970 RollBackTo(last_changed_range); | 895 RollBackTo(last_changed_range); |
| 971 } | 896 } |
| 972 | 897 |
| 973 | 898 |
| 974 void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) { | 899 void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) { |
| 975 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); | 900 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); |
| 976 if (test->value()->IsCompare()) { | 901 if (test->value()->IsCompare()) { |
| 977 HCompare* compare = HCompare::cast(test->value()); | 902 HCompare* compare = HCompare::cast(test->value()); |
| 978 Token::Value op = compare->token(); | 903 if (compare->GetInputRepresentation().IsInteger32()) { |
| 979 if (test->SecondSuccessor() == dest) { | 904 Token::Value op = compare->token(); |
| 980 op = Token::NegateCompareOp(op); | 905 if (test->SecondSuccessor() == dest) { |
| 906 op = Token::NegateCompareOp(op); |
| 907 } |
| 908 Token::Value inverted_op = Token::InvertCompareOp(op); |
| 909 InferControlFlowRange(op, compare->left(), compare->right()); |
| 910 InferControlFlowRange(inverted_op, compare->right(), compare->left()); |
| 981 } | 911 } |
| 982 Token::Value inverted_op = Token::InvertCompareOp(op); | |
| 983 InferControlFlowRange(op, compare->left(), compare->right()); | |
| 984 InferControlFlowRange(inverted_op, compare->right(), compare->left()); | |
| 985 } | 912 } |
| 986 } | 913 } |
| 987 | 914 |
| 988 | 915 |
| 989 // We know that value [op] other. Use this information to update the range on | 916 // We know that value [op] other. Use this information to update the range on |
| 990 // value. | 917 // value. |
| 991 void HRangeAnalysis::InferControlFlowRange(Token::Value op, | 918 void HRangeAnalysis::InferControlFlowRange(Token::Value op, |
| 992 HValue* value, | 919 HValue* value, |
| 993 HValue* other) { | 920 HValue* other) { |
| 994 Range* range = other->range(); | 921 Range temp_range; |
| 995 if (range == NULL) range = new Range(); | 922 Range* range = other->range() != NULL ? other->range() : &temp_range; |
| 996 Range* new_range = NULL; | 923 Range* new_range = NULL; |
| 997 | 924 |
| 998 TraceRange("Control flow range infer %d %s %d\n", | 925 TraceRange("Control flow range infer %d %s %d\n", |
| 999 value->id(), | 926 value->id(), |
| 1000 Token::Name(op), | 927 Token::Name(op), |
| 1001 other->id()); | 928 other->id()); |
| 1002 | 929 |
| 1003 if (op == Token::EQ || op == Token::EQ_STRICT) { | 930 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 1004 // The same range has to apply for value. | 931 // The same range has to apply for value. |
| 1005 new_range = range->Copy(); | 932 new_range = range->Copy(); |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1293 HGoto::cast(instr)->set_include_stack_check(false); | 1220 HGoto::cast(instr)->set_include_stack_check(false); |
| 1294 return; | 1221 return; |
| 1295 } | 1222 } |
| 1296 instr = instr->next(); | 1223 instr = instr->next(); |
| 1297 } | 1224 } |
| 1298 } | 1225 } |
| 1299 | 1226 |
| 1300 | 1227 |
| 1301 class HGlobalValueNumberer BASE_EMBEDDED { | 1228 class HGlobalValueNumberer BASE_EMBEDDED { |
| 1302 public: | 1229 public: |
| 1303 explicit HGlobalValueNumberer(HGraph* graph) | 1230 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) |
| 1304 : graph_(graph), | 1231 : graph_(graph), |
| 1232 info_(info), |
| 1305 block_side_effects_(graph_->blocks()->length()), | 1233 block_side_effects_(graph_->blocks()->length()), |
| 1306 loop_side_effects_(graph_->blocks()->length()) { | 1234 loop_side_effects_(graph_->blocks()->length()) { |
| 1307 ASSERT(Heap::allow_allocation(false)); | 1235 ASSERT(Heap::allow_allocation(false)); |
| 1308 block_side_effects_.AddBlock(0, graph_->blocks()->length()); | 1236 block_side_effects_.AddBlock(0, graph_->blocks()->length()); |
| 1309 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); | 1237 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); |
| 1310 } | 1238 } |
| 1311 ~HGlobalValueNumberer() { | 1239 ~HGlobalValueNumberer() { |
| 1312 ASSERT(!Heap::allow_allocation(true)); | 1240 ASSERT(!Heap::allow_allocation(true)); |
| 1313 } | 1241 } |
| 1314 | 1242 |
| 1315 void Analyze(); | 1243 void Analyze(); |
| 1316 | 1244 |
| 1317 private: | 1245 private: |
| 1318 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); | 1246 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); |
| 1319 void ComputeBlockSideEffects(); | 1247 void ComputeBlockSideEffects(); |
| 1320 void LoopInvariantCodeMotion(); | 1248 void LoopInvariantCodeMotion(); |
| 1321 void ProcessLoopBlock(HBasicBlock* block, | 1249 void ProcessLoopBlock(HBasicBlock* block, |
| 1322 HBasicBlock* before_loop, | 1250 HBasicBlock* before_loop, |
| 1323 int loop_kills); | 1251 int loop_kills); |
| 1252 bool AllowCodeMotion(); |
| 1324 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); | 1253 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); |
| 1325 | 1254 |
| 1255 HGraph* graph() { return graph_; } |
| 1256 CompilationInfo* info() { return info_; } |
| 1257 |
| 1326 HGraph* graph_; | 1258 HGraph* graph_; |
| 1259 CompilationInfo* info_; |
| 1327 | 1260 |
| 1328 // A map of block IDs to their side effects. | 1261 // A map of block IDs to their side effects. |
| 1329 ZoneList<int> block_side_effects_; | 1262 ZoneList<int> block_side_effects_; |
| 1330 | 1263 |
| 1331 // A map of loop header block IDs to their loop's side effects. | 1264 // A map of loop header block IDs to their loop's side effects. |
| 1332 ZoneList<int> loop_side_effects_; | 1265 ZoneList<int> loop_side_effects_; |
| 1333 }; | 1266 }; |
| 1334 | 1267 |
| 1335 | 1268 |
| 1336 void HGlobalValueNumberer::Analyze() { | 1269 void HGlobalValueNumberer::Analyze() { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1417 // Move the instruction out of the loop. | 1350 // Move the instruction out of the loop. |
| 1418 instr->Unlink(); | 1351 instr->Unlink(); |
| 1419 instr->InsertBefore(pre_header->end()); | 1352 instr->InsertBefore(pre_header->end()); |
| 1420 } | 1353 } |
| 1421 } | 1354 } |
| 1422 instr = next; | 1355 instr = next; |
| 1423 } | 1356 } |
| 1424 } | 1357 } |
| 1425 | 1358 |
| 1426 | 1359 |
| 1360 bool HGlobalValueNumberer::AllowCodeMotion() { |
| 1361 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; |
| 1362 } |
| 1363 |
| 1364 |
| 1427 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, | 1365 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, |
| 1428 HBasicBlock* loop_header) { | 1366 HBasicBlock* loop_header) { |
| 1429 // If we've disabled code motion, don't move any instructions. | 1367 // If we've disabled code motion, don't move any instructions. |
| 1430 if (!graph_->AllowCodeMotion()) return false; | 1368 if (!AllowCodeMotion()) return false; |
| 1431 | 1369 |
| 1432 // If --aggressive-loop-invariant-motion, move everything except change | 1370 // If --aggressive-loop-invariant-motion, move everything except change |
| 1433 // instructions. | 1371 // instructions. |
| 1434 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { | 1372 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { |
| 1435 return true; | 1373 return true; |
| 1436 } | 1374 } |
| 1437 | 1375 |
| 1438 // Otherwise only move instructions that postdominate the loop header | 1376 // Otherwise only move instructions that postdominate the loop header |
| 1439 // (i.e. are always executed inside the loop). This is to avoid | 1377 // (i.e. are always executed inside the loop). This is to avoid |
| 1440 // unnecessary deoptimizations assuming the loop is executed at least | 1378 // unnecessary deoptimizations assuming the loop is executed at least |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1480 TraceGVN("Instruction %d kills\n", instr->id()); | 1418 TraceGVN("Instruction %d kills\n", instr->id()); |
| 1481 } else if (instr->CheckFlag(HValue::kUseGVN)) { | 1419 } else if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1482 HValue* other = map->Lookup(instr); | 1420 HValue* other = map->Lookup(instr); |
| 1483 if (other != NULL) { | 1421 if (other != NULL) { |
| 1484 ASSERT(instr->Equals(other) && other->Equals(instr)); | 1422 ASSERT(instr->Equals(other) && other->Equals(instr)); |
| 1485 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", | 1423 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", |
| 1486 instr->id(), | 1424 instr->id(), |
| 1487 instr->Mnemonic(), | 1425 instr->Mnemonic(), |
| 1488 other->id(), | 1426 other->id(), |
| 1489 other->Mnemonic()); | 1427 other->Mnemonic()); |
| 1490 instr->ReplaceValue(other); | 1428 instr->ReplaceAndDelete(other); |
| 1491 instr->Delete(); | |
| 1492 } else { | 1429 } else { |
| 1493 map->Add(instr); | 1430 map->Add(instr); |
| 1494 } | 1431 } |
| 1495 } | 1432 } |
| 1496 instr = next; | 1433 instr = next; |
| 1497 } | 1434 } |
| 1498 | 1435 |
| 1499 // Recursively continue analysis for all immediately dominated blocks. | 1436 // Recursively continue analysis for all immediately dominated blocks. |
| 1500 int length = block->dominated_blocks()->length(); | 1437 int length = block->dominated_blocks()->length(); |
| 1501 for (int i = 0; i < length; ++i) { | 1438 for (int i = 0; i < length; ++i) { |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1781 PropagateMinusZeroChecks(div->right(), visited); | 1718 PropagateMinusZeroChecks(div->right(), visited); |
| 1782 } | 1719 } |
| 1783 | 1720 |
| 1784 current = current->EnsureAndPropagateNotMinusZero(visited); | 1721 current = current->EnsureAndPropagateNotMinusZero(visited); |
| 1785 } | 1722 } |
| 1786 } | 1723 } |
| 1787 | 1724 |
| 1788 | 1725 |
| 1789 void HGraph::InsertRepresentationChangeForUse(HValue* value, | 1726 void HGraph::InsertRepresentationChangeForUse(HValue* value, |
| 1790 HValue* use, | 1727 HValue* use, |
| 1791 Representation to, | 1728 Representation to) { |
| 1792 bool is_truncating) { | |
| 1793 // Insert the representation change right before its use. For phi-uses we | 1729 // Insert the representation change right before its use. For phi-uses we |
| 1794 // insert at the end of the corresponding predecessor. | 1730 // insert at the end of the corresponding predecessor. |
| 1795 HInstruction* next = NULL; | 1731 HInstruction* next = NULL; |
| 1796 if (use->IsPhi()) { | 1732 if (use->IsPhi()) { |
| 1797 int index = 0; | 1733 int index = 0; |
| 1798 while (use->OperandAt(index) != value) ++index; | 1734 while (use->OperandAt(index) != value) ++index; |
| 1799 next = use->block()->predecessors()->at(index)->end(); | 1735 next = use->block()->predecessors()->at(index)->end(); |
| 1800 } else { | 1736 } else { |
| 1801 next = HInstruction::cast(use); | 1737 next = HInstruction::cast(use); |
| 1802 } | 1738 } |
| 1803 | 1739 |
| 1804 // For constants we try to make the representation change at compile | 1740 // For constants we try to make the representation change at compile |
| 1805 // time. When a representation change is not possible without loss of | 1741 // time. When a representation change is not possible without loss of |
| 1806 // information we treat constants like normal instructions and insert the | 1742 // information we treat constants like normal instructions and insert the |
| 1807 // change instructions for them. | 1743 // change instructions for them. |
| 1808 HInstruction* new_value = NULL; | 1744 HInstruction* new_value = NULL; |
| 1745 bool is_truncating = use->CheckFlag(HValue::kTruncatingToInt32); |
| 1809 if (value->IsConstant()) { | 1746 if (value->IsConstant()) { |
| 1810 HConstant* constant = HConstant::cast(value); | 1747 HConstant* constant = HConstant::cast(value); |
| 1811 // Try to create a new copy of the constant with the new representation. | 1748 // Try to create a new copy of the constant with the new representation. |
| 1812 new_value = is_truncating | 1749 new_value = is_truncating |
| 1813 ? constant->CopyToTruncatedInt32() | 1750 ? constant->CopyToTruncatedInt32() |
| 1814 : constant->CopyToRepresentation(to); | 1751 : constant->CopyToRepresentation(to); |
| 1815 } | 1752 } |
| 1816 | 1753 |
| 1817 if (new_value == NULL) { | 1754 if (new_value == NULL) { |
| 1818 new_value = new HChange(value, value->representation(), to); | 1755 new_value = new HChange(value, value->representation(), to, is_truncating); |
| 1819 } | 1756 } |
| 1820 | 1757 |
| 1821 new_value->InsertBefore(next); | 1758 new_value->InsertBefore(next); |
| 1822 value->ReplaceFirstAtUse(use, new_value, to); | 1759 value->ReplaceFirstAtUse(use, new_value, to); |
| 1823 } | 1760 } |
| 1824 | 1761 |
| 1825 | 1762 |
| 1826 int CompareConversionUses(HValue* a, | 1763 int CompareConversionUses(HValue* a, |
| 1827 HValue* b, | 1764 HValue* b, |
| 1828 Representation a_rep, | 1765 Representation a_rep, |
| 1829 Representation b_rep) { | 1766 Representation b_rep) { |
| 1830 if (a_rep.kind() > b_rep.kind()) { | 1767 if (a_rep.kind() > b_rep.kind()) { |
| 1831 // Make sure specializations are separated in the result array. | 1768 // Make sure specializations are separated in the result array. |
| 1832 return 1; | 1769 return 1; |
| 1833 } | 1770 } |
| 1834 // Put truncating conversions before non-truncating conversions. | 1771 // Put truncating conversions before non-truncating conversions. |
| 1835 bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32); | 1772 bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32); |
| 1836 bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32); | 1773 bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32); |
| 1837 if (a_truncate != b_truncate) { | 1774 if (a_truncate != b_truncate) { |
| 1838 return a_truncate ? -1 : 1; | 1775 return a_truncate ? -1 : 1; |
| 1839 } | 1776 } |
| 1840 // Sort by increasing block ID. | 1777 // Sort by increasing block ID. |
| 1841 return a->block()->block_id() - b->block()->block_id(); | 1778 return a->block()->block_id() - b->block()->block_id(); |
| 1842 } | 1779 } |
| 1843 | 1780 |
| 1844 | 1781 |
| 1845 void HGraph::InsertRepresentationChanges(HValue* current) { | 1782 void HGraph::InsertRepresentationChangesForValue( |
| 1783 HValue* current, |
| 1784 ZoneList<HValue*>* to_convert, |
| 1785 ZoneList<Representation>* to_convert_reps) { |
| 1846 Representation r = current->representation(); | 1786 Representation r = current->representation(); |
| 1847 if (r.IsNone()) return; | 1787 if (r.IsNone()) return; |
| 1848 if (current->uses()->length() == 0) return; | 1788 if (current->uses()->length() == 0) return; |
| 1849 | 1789 |
| 1850 // Collect the representation changes in a sorted list. This allows | 1790 // Collect the representation changes in a sorted list. This allows |
| 1851 // us to avoid duplicate changes without searching the list. | 1791 // us to avoid duplicate changes without searching the list. |
| 1852 ZoneList<HValue*> to_convert(2); | 1792 ASSERT(to_convert->is_empty()); |
| 1853 ZoneList<Representation> to_convert_reps(2); | 1793 ASSERT(to_convert_reps->is_empty()); |
| 1854 for (int i = 0; i < current->uses()->length(); ++i) { | 1794 for (int i = 0; i < current->uses()->length(); ++i) { |
| 1855 HValue* use = current->uses()->at(i); | 1795 HValue* use = current->uses()->at(i); |
| 1856 // The occurrences index means the index within the operand array of "use" | 1796 // The occurrences index means the index within the operand array of "use" |
| 1857 // at which "current" is used. While iterating through the use array we | 1797 // at which "current" is used. While iterating through the use array we |
| 1858 // also have to iterate over the different occurrence indices. | 1798 // also have to iterate over the different occurrence indices. |
| 1859 int occurrence_index = 0; | 1799 int occurrence_index = 0; |
| 1860 if (use->UsesMultipleTimes(current)) { | 1800 if (use->UsesMultipleTimes(current)) { |
| 1861 occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1); | 1801 occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1); |
| 1862 if (FLAG_trace_representation) { | 1802 if (FLAG_trace_representation) { |
| 1863 PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n", | 1803 PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n", |
| 1864 current->id(), | 1804 current->id(), |
| 1865 use->id(), | 1805 use->id(), |
| 1866 occurrence_index); | 1806 occurrence_index); |
| 1867 } | 1807 } |
| 1868 } | 1808 } |
| 1869 int operand_index = use->LookupOperandIndex(occurrence_index, current); | 1809 int operand_index = use->LookupOperandIndex(occurrence_index, current); |
| 1870 Representation req = use->RequiredInputRepresentation(operand_index); | 1810 Representation req = use->RequiredInputRepresentation(operand_index); |
| 1871 if (req.IsNone() || req.Equals(r)) continue; | 1811 if (req.IsNone() || req.Equals(r)) continue; |
| 1872 int index = 0; | 1812 int index = 0; |
| 1873 while (to_convert.length() > index && | 1813 while (index < to_convert->length() && |
| 1874 CompareConversionUses(to_convert[index], | 1814 CompareConversionUses(to_convert->at(index), |
| 1875 use, | 1815 use, |
| 1876 to_convert_reps[index], | 1816 to_convert_reps->at(index), |
| 1877 req) < 0) { | 1817 req) < 0) { |
| 1878 ++index; | 1818 ++index; |
| 1879 } | 1819 } |
| 1880 if (FLAG_trace_representation) { | 1820 if (FLAG_trace_representation) { |
| 1881 PrintF("Inserting a representation change to %s of %d for use at %d\n", | 1821 PrintF("Inserting a representation change to %s of %d for use at %d\n", |
| 1882 req.Mnemonic(), | 1822 req.Mnemonic(), |
| 1883 current->id(), | 1823 current->id(), |
| 1884 use->id()); | 1824 use->id()); |
| 1885 } | 1825 } |
| 1886 to_convert.InsertAt(index, use); | 1826 to_convert->InsertAt(index, use); |
| 1887 to_convert_reps.InsertAt(index, req); | 1827 to_convert_reps->InsertAt(index, req); |
| 1888 } | 1828 } |
| 1889 | 1829 |
| 1890 for (int i = 0; i < to_convert.length(); ++i) { | 1830 for (int i = 0; i < to_convert->length(); ++i) { |
| 1891 HValue* use = to_convert[i]; | 1831 HValue* use = to_convert->at(i); |
| 1892 Representation r_to = to_convert_reps[i]; | 1832 Representation r_to = to_convert_reps->at(i); |
| 1893 bool is_truncating = use->CheckFlag(HValue::kTruncatingToInt32); | 1833 InsertRepresentationChangeForUse(current, use, r_to); |
| 1894 InsertRepresentationChangeForUse(current, use, r_to, is_truncating); | |
| 1895 } | 1834 } |
| 1896 | 1835 |
| 1897 if (current->uses()->is_empty()) { | 1836 if (current->uses()->is_empty()) { |
| 1898 ASSERT(current->IsConstant()); | 1837 ASSERT(current->IsConstant()); |
| 1899 current->Delete(); | 1838 current->Delete(); |
| 1900 } | 1839 } |
| 1840 to_convert->Rewind(0); |
| 1841 to_convert_reps->Rewind(0); |
| 1901 } | 1842 } |
| 1902 | 1843 |
| 1903 | 1844 |
| 1904 void HGraph::InsertRepresentationChanges() { | 1845 void HGraph::InsertRepresentationChanges() { |
| 1905 HPhase phase("Insert representation changes", this); | 1846 HPhase phase("Insert representation changes", this); |
| 1906 | 1847 |
| 1907 | 1848 |
| 1908 // Compute truncation flag for phis: Initially assume that all | 1849 // Compute truncation flag for phis: Initially assume that all |
| 1909 // int32-phis allow truncation and iteratively remove the ones that | 1850 // int32-phis allow truncation and iteratively remove the ones that |
| 1910 // are used in an operation that does not allow a truncating | 1851 // are used in an operation that does not allow a truncating |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1926 HValue* use = phi->uses()->at(j); | 1867 HValue* use = phi->uses()->at(j); |
| 1927 if (!use->CheckFlag(HValue::kTruncatingToInt32)) { | 1868 if (!use->CheckFlag(HValue::kTruncatingToInt32)) { |
| 1928 phi->ClearFlag(HValue::kTruncatingToInt32); | 1869 phi->ClearFlag(HValue::kTruncatingToInt32); |
| 1929 change = true; | 1870 change = true; |
| 1930 break; | 1871 break; |
| 1931 } | 1872 } |
| 1932 } | 1873 } |
| 1933 } | 1874 } |
| 1934 } | 1875 } |
| 1935 | 1876 |
| 1877 ZoneList<HValue*> value_list(4); |
| 1878 ZoneList<Representation> rep_list(4); |
| 1936 for (int i = 0; i < blocks_.length(); ++i) { | 1879 for (int i = 0; i < blocks_.length(); ++i) { |
| 1937 // Process phi instructions first. | 1880 // Process phi instructions first. |
| 1938 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { | 1881 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { |
| 1939 HPhi* phi = blocks_[i]->phis()->at(j); | 1882 HPhi* phi = blocks_[i]->phis()->at(j); |
| 1940 InsertRepresentationChanges(phi); | 1883 InsertRepresentationChangesForValue(phi, &value_list, &rep_list); |
| 1941 } | 1884 } |
| 1942 | 1885 |
| 1943 // Process normal instructions. | 1886 // Process normal instructions. |
| 1944 HInstruction* current = blocks_[i]->first(); | 1887 HInstruction* current = blocks_[i]->first(); |
| 1945 while (current != NULL) { | 1888 while (current != NULL) { |
| 1946 InsertRepresentationChanges(current); | 1889 InsertRepresentationChangesForValue(current, &value_list, &rep_list); |
| 1947 current = current->next(); | 1890 current = current->next(); |
| 1948 } | 1891 } |
| 1949 } | 1892 } |
| 1950 } | 1893 } |
| 1951 | 1894 |
| 1952 | 1895 |
| 1953 void HGraph::ComputeMinusZeroChecks() { | 1896 void HGraph::ComputeMinusZeroChecks() { |
| 1954 BitVector visited(GetMaximumValueID()); | 1897 BitVector visited(GetMaximumValueID()); |
| 1955 for (int i = 0; i < blocks_.length(); ++i) { | 1898 for (int i = 0; i < blocks_.length(); ++i) { |
| 1956 for (HInstruction* current = blocks_[i]->first(); | 1899 for (HInstruction* current = blocks_[i]->first(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1967 ASSERT(visited.IsEmpty()); | 1910 ASSERT(visited.IsEmpty()); |
| 1968 PropagateMinusZeroChecks(change->value(), &visited); | 1911 PropagateMinusZeroChecks(change->value(), &visited); |
| 1969 visited.Clear(); | 1912 visited.Clear(); |
| 1970 } | 1913 } |
| 1971 } | 1914 } |
| 1972 } | 1915 } |
| 1973 } | 1916 } |
| 1974 } | 1917 } |
| 1975 | 1918 |
| 1976 | 1919 |
| 1920 // Implementation of utility class to encapsulate the translation state for |
| 1921 // a (possibly inlined) function. |
| 1922 FunctionState::FunctionState(HGraphBuilder* owner, |
| 1923 CompilationInfo* info, |
| 1924 TypeFeedbackOracle* oracle) |
| 1925 : owner_(owner), |
| 1926 compilation_info_(info), |
| 1927 oracle_(oracle), |
| 1928 call_context_(NULL), |
| 1929 function_return_(NULL), |
| 1930 test_context_(NULL), |
| 1931 outer_(owner->function_state()) { |
| 1932 if (outer_ != NULL) { |
| 1933 // State for an inline function. |
| 1934 if (owner->ast_context()->IsTest()) { |
| 1935 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
| 1936 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
| 1937 if_true->MarkAsInlineReturnTarget(); |
| 1938 if_false->MarkAsInlineReturnTarget(); |
| 1939 // The AstContext constructor pushed on the context stack. This newed |
| 1940 // instance is the reason that AstContext can't be BASE_EMBEDDED. |
| 1941 test_context_ = new TestContext(owner, if_true, if_false); |
| 1942 } else { |
| 1943 function_return_ = owner->graph()->CreateBasicBlock(); |
| 1944 function_return()->MarkAsInlineReturnTarget(); |
| 1945 } |
| 1946 // Set this after possibly allocating a new TestContext above. |
| 1947 call_context_ = owner->ast_context(); |
| 1948 } |
| 1949 |
| 1950 // Push on the state stack. |
| 1951 owner->set_function_state(this); |
| 1952 } |
| 1953 |
| 1954 |
| 1955 FunctionState::~FunctionState() { |
| 1956 delete test_context_; |
| 1957 owner_->set_function_state(outer_); |
| 1958 } |
| 1959 |
| 1960 |
| 1977 // Implementation of utility classes to represent an expression's context in | 1961 // Implementation of utility classes to represent an expression's context in |
| 1978 // the AST. | 1962 // the AST. |
| 1979 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 1963 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
| 1980 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { | 1964 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { |
| 1981 owner->set_ast_context(this); // Push. | 1965 owner->set_ast_context(this); // Push. |
| 1982 #ifdef DEBUG | 1966 #ifdef DEBUG |
| 1983 original_length_ = owner->environment()->length(); | 1967 original_length_ = owner->environment()->length(); |
| 1984 #endif | 1968 #endif |
| 1985 } | 1969 } |
| 1986 | 1970 |
| 1987 | 1971 |
| 1988 AstContext::~AstContext() { | 1972 AstContext::~AstContext() { |
| 1989 owner_->set_ast_context(outer_); // Pop. | 1973 owner_->set_ast_context(outer_); // Pop. |
| 1990 } | 1974 } |
| 1991 | 1975 |
| 1992 | 1976 |
| 1993 EffectContext::~EffectContext() { | 1977 EffectContext::~EffectContext() { |
| 1994 ASSERT(owner()->HasStackOverflow() || | 1978 ASSERT(owner()->HasStackOverflow() || |
| 1995 !owner()->subgraph()->HasExit() || | 1979 owner()->current_block() == NULL || |
| 1996 owner()->environment()->length() == original_length_); | 1980 owner()->environment()->length() == original_length_); |
| 1997 } | 1981 } |
| 1998 | 1982 |
| 1999 | 1983 |
| 2000 ValueContext::~ValueContext() { | 1984 ValueContext::~ValueContext() { |
| 2001 ASSERT(owner()->HasStackOverflow() || | 1985 ASSERT(owner()->HasStackOverflow() || |
| 2002 !owner()->subgraph()->HasExit() || | 1986 owner()->current_block() == NULL || |
| 2003 owner()->environment()->length() == original_length_ + 1); | 1987 owner()->environment()->length() == original_length_ + 1); |
| 2004 } | 1988 } |
| 2005 | 1989 |
| 2006 | 1990 |
| 2007 void EffectContext::ReturnValue(HValue* value) { | 1991 void EffectContext::ReturnValue(HValue* value) { |
| 2008 // The value is simply ignored. | 1992 // The value is simply ignored. |
| 2009 } | 1993 } |
| 2010 | 1994 |
| 2011 | 1995 |
| 2012 void ValueContext::ReturnValue(HValue* value) { | 1996 void ValueContext::ReturnValue(HValue* value) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2050 | 2034 |
| 2051 void TestContext::BuildBranch(HValue* value) { | 2035 void TestContext::BuildBranch(HValue* value) { |
| 2052 // We expect the graph to be in edge-split form: there is no edge that | 2036 // We expect the graph to be in edge-split form: there is no edge that |
| 2053 // connects a branch node to a join node. We conservatively ensure that | 2037 // connects a branch node to a join node. We conservatively ensure that |
| 2054 // property by always adding an empty block on the outgoing edges of this | 2038 // property by always adding an empty block on the outgoing edges of this |
| 2055 // branch. | 2039 // branch. |
| 2056 HGraphBuilder* builder = owner(); | 2040 HGraphBuilder* builder = owner(); |
| 2057 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2041 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2058 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2042 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2059 HTest* test = new HTest(value, empty_true, empty_false); | 2043 HTest* test = new HTest(value, empty_true, empty_false); |
| 2060 builder->CurrentBlock()->Finish(test); | 2044 builder->current_block()->Finish(test); |
| 2061 | 2045 |
| 2062 HValue* const no_return_value = NULL; | 2046 empty_true->Goto(if_true(), false); |
| 2063 HBasicBlock* true_target = if_true(); | 2047 empty_false->Goto(if_false(), false); |
| 2064 if (true_target->IsInlineReturnTarget()) { | 2048 builder->set_current_block(NULL); |
| 2065 empty_true->AddLeaveInlined(no_return_value, true_target); | |
| 2066 } else { | |
| 2067 empty_true->Goto(true_target); | |
| 2068 } | |
| 2069 | |
| 2070 HBasicBlock* false_target = if_false(); | |
| 2071 if (false_target->IsInlineReturnTarget()) { | |
| 2072 empty_false->AddLeaveInlined(no_return_value, false_target); | |
| 2073 } else { | |
| 2074 empty_false->Goto(false_target); | |
| 2075 } | |
| 2076 builder->subgraph()->set_exit_block(NULL); | |
| 2077 } | 2049 } |
| 2078 | 2050 |
| 2079 | 2051 |
| 2080 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2052 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 2081 #define BAILOUT(reason) \ | 2053 #define BAILOUT(reason) \ |
| 2082 do { \ | 2054 do { \ |
| 2083 Bailout(reason); \ | 2055 Bailout(reason); \ |
| 2084 return; \ | 2056 return; \ |
| 2085 } while (false) | 2057 } while (false) |
| 2086 | 2058 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2105 } while (false) | 2077 } while (false) |
| 2106 | 2078 |
| 2107 | 2079 |
| 2108 #define VISIT_FOR_CONTROL(expr, true_block, false_block) \ | 2080 #define VISIT_FOR_CONTROL(expr, true_block, false_block) \ |
| 2109 do { \ | 2081 do { \ |
| 2110 VisitForControl(expr, true_block, false_block); \ | 2082 VisitForControl(expr, true_block, false_block); \ |
| 2111 if (HasStackOverflow()) return; \ | 2083 if (HasStackOverflow()) return; \ |
| 2112 } while (false) | 2084 } while (false) |
| 2113 | 2085 |
| 2114 | 2086 |
| 2115 // 'thing' could be an expression, statement, or list of statements. | |
| 2116 #define ADD_TO_SUBGRAPH(graph, thing) \ | |
| 2117 do { \ | |
| 2118 AddToSubgraph(graph, thing); \ | |
| 2119 if (HasStackOverflow()) return; \ | |
| 2120 } while (false) | |
| 2121 | |
| 2122 | |
| 2123 class HGraphBuilder::SubgraphScope BASE_EMBEDDED { | |
| 2124 public: | |
| 2125 SubgraphScope(HGraphBuilder* builder, HSubgraph* new_subgraph) | |
| 2126 : builder_(builder) { | |
| 2127 old_subgraph_ = builder_->current_subgraph_; | |
| 2128 subgraph_ = new_subgraph; | |
| 2129 builder_->current_subgraph_ = subgraph_; | |
| 2130 } | |
| 2131 | |
| 2132 ~SubgraphScope() { | |
| 2133 old_subgraph_->AddBreakContinueInfo(subgraph_); | |
| 2134 builder_->current_subgraph_ = old_subgraph_; | |
| 2135 } | |
| 2136 | |
| 2137 HSubgraph* subgraph() const { return subgraph_; } | |
| 2138 | |
| 2139 private: | |
| 2140 HGraphBuilder* builder_; | |
| 2141 HSubgraph* old_subgraph_; | |
| 2142 HSubgraph* subgraph_; | |
| 2143 }; | |
| 2144 | |
| 2145 | |
| 2146 void HGraphBuilder::Bailout(const char* reason) { | 2087 void HGraphBuilder::Bailout(const char* reason) { |
| 2147 if (FLAG_trace_bailout) { | 2088 if (FLAG_trace_bailout) { |
| 2148 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); | 2089 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); |
| 2149 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *debug_name, reason); | 2090 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason); |
| 2150 } | 2091 } |
| 2151 SetStackOverflow(); | 2092 SetStackOverflow(); |
| 2152 } | 2093 } |
| 2153 | 2094 |
| 2154 | 2095 |
| 2155 void HGraphBuilder::VisitForEffect(Expression* expr) { | 2096 void HGraphBuilder::VisitForEffect(Expression* expr) { |
| 2156 EffectContext for_effect(this); | 2097 EffectContext for_effect(this); |
| 2157 Visit(expr); | 2098 Visit(expr); |
| 2158 } | 2099 } |
| 2159 | 2100 |
| 2160 | 2101 |
| 2161 void HGraphBuilder::VisitForValue(Expression* expr) { | 2102 void HGraphBuilder::VisitForValue(Expression* expr) { |
| 2162 ValueContext for_value(this); | 2103 ValueContext for_value(this); |
| 2163 Visit(expr); | 2104 Visit(expr); |
| 2164 } | 2105 } |
| 2165 | 2106 |
| 2166 | 2107 |
| 2167 void HGraphBuilder::VisitForControl(Expression* expr, | 2108 void HGraphBuilder::VisitForControl(Expression* expr, |
| 2168 HBasicBlock* true_block, | 2109 HBasicBlock* true_block, |
| 2169 HBasicBlock* false_block) { | 2110 HBasicBlock* false_block) { |
| 2170 TestContext for_test(this, true_block, false_block); | 2111 TestContext for_test(this, true_block, false_block); |
| 2171 Visit(expr); | 2112 Visit(expr); |
| 2172 } | 2113 } |
| 2173 | 2114 |
| 2174 | 2115 |
| 2175 void HGraphBuilder::VisitArgument(Expression* expr) { | 2116 void HGraphBuilder::VisitArgument(Expression* expr) { |
| 2176 VisitForValue(expr); | 2117 VISIT_FOR_VALUE(expr); |
| 2118 Push(AddInstruction(new HPushArgument(Pop()))); |
| 2177 } | 2119 } |
| 2178 | 2120 |
| 2179 | 2121 |
| 2180 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { | 2122 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { |
| 2181 for (int i = 0; i < arguments->length(); i++) { | 2123 for (int i = 0; i < arguments->length(); i++) { |
| 2182 VisitArgument(arguments->at(i)); | 2124 VisitArgument(arguments->at(i)); |
| 2183 if (HasStackOverflow() || !current_subgraph_->HasExit()) return; | 2125 if (HasStackOverflow() || current_block() == NULL) return; |
| 2184 } | 2126 } |
| 2185 } | 2127 } |
| 2186 | 2128 |
| 2187 | 2129 |
| 2188 HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { | 2130 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { |
| 2189 ASSERT(current_subgraph_ == NULL); | 2131 for (int i = 0; i < exprs->length(); ++i) { |
| 2190 graph_ = new HGraph(info); | 2132 VISIT_FOR_VALUE(exprs->at(i)); |
| 2133 } |
| 2134 } |
| 2135 |
| 2136 |
| 2137 HGraph* HGraphBuilder::CreateGraph() { |
| 2138 graph_ = new HGraph(info()); |
| 2139 if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info()); |
| 2191 | 2140 |
| 2192 { | 2141 { |
| 2193 HPhase phase("Block building"); | 2142 HPhase phase("Block building"); |
| 2194 graph_->Initialize(CreateBasicBlock(graph_->start_environment())); | 2143 current_block_ = graph()->entry_block(); |
| 2195 current_subgraph_ = graph_; | |
| 2196 | 2144 |
| 2197 Scope* scope = info->scope(); | 2145 Scope* scope = info()->scope(); |
| 2146 if (scope->HasIllegalRedeclaration()) { |
| 2147 Bailout("function with illegal redeclaration"); |
| 2148 return NULL; |
| 2149 } |
| 2198 SetupScope(scope); | 2150 SetupScope(scope); |
| 2199 VisitDeclarations(scope->declarations()); | 2151 VisitDeclarations(scope->declarations()); |
| 2200 | |
| 2201 AddInstruction(new HStackCheck()); | 2152 AddInstruction(new HStackCheck()); |
| 2202 | 2153 |
| 2203 ZoneList<Statement*>* stmts = info->function()->body(); | 2154 // Add an edge to the body entry. This is warty: the graph's start |
| 2204 HSubgraph* body = CreateGotoSubgraph(environment()); | 2155 // environment will be used by the Lithium translation as the initial |
| 2205 AddToSubgraph(body, stmts); | 2156 // environment on graph entry, but it has now been mutated by the |
| 2157 // Hydrogen translation of the instructions in the start block. This |
| 2158 // environment uses values which have not been defined yet. These |
| 2159 // Hydrogen instructions will then be replayed by the Lithium |
| 2160 // translation, so they cannot have an environment effect. The edge to |
| 2161 // the body's entry block (along with some special logic for the start |
| 2162 // block in HInstruction::InsertAfter) seals the start block from |
| 2163 // getting unwanted instructions inserted. |
| 2164 // |
| 2165 // TODO(kmillikin): Fix this. Stop mutating the initial environment. |
| 2166 // Make the Hydrogen instructions in the initial block into Hydrogen |
| 2167 // values (but not instructions), present in the initial environment and |
| 2168 // not replayed by the Lithium translation. |
| 2169 HEnvironment* initial_env = environment()->CopyWithoutHistory(); |
| 2170 HBasicBlock* body_entry = CreateBasicBlock(initial_env); |
| 2171 current_block()->Goto(body_entry); |
| 2172 body_entry->SetJoinId(info()->function()->id()); |
| 2173 set_current_block(body_entry); |
| 2174 VisitStatements(info()->function()->body()); |
| 2206 if (HasStackOverflow()) return NULL; | 2175 if (HasStackOverflow()) return NULL; |
| 2207 current_subgraph_->Append(body, NULL); | |
| 2208 body->entry_block()->SetJoinId(info->function()->id()); | |
| 2209 | 2176 |
| 2210 if (graph_->HasExit()) { | 2177 if (current_block() != NULL) { |
| 2211 graph_->FinishExit(new HReturn(graph_->GetConstantUndefined())); | 2178 HReturn* instr = new HReturn(graph()->GetConstantUndefined()); |
| 2179 current_block()->FinishExit(instr); |
| 2180 set_current_block(NULL); |
| 2212 } | 2181 } |
| 2213 } | 2182 } |
| 2214 | 2183 |
| 2215 graph_->OrderBlocks(); | 2184 graph()->OrderBlocks(); |
| 2216 graph_->AssignDominators(); | 2185 graph()->AssignDominators(); |
| 2217 graph_->EliminateRedundantPhis(); | 2186 graph()->EliminateRedundantPhis(); |
| 2218 if (!graph_->CollectPhis()) { | 2187 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); |
| 2188 if (!graph()->CollectPhis()) { |
| 2219 Bailout("Phi-use of arguments object"); | 2189 Bailout("Phi-use of arguments object"); |
| 2220 return NULL; | 2190 return NULL; |
| 2221 } | 2191 } |
| 2222 | 2192 |
| 2223 HInferRepresentation rep(graph_); | 2193 HInferRepresentation rep(graph()); |
| 2224 rep.Analyze(); | 2194 rep.Analyze(); |
| 2225 | 2195 |
| 2226 if (FLAG_use_range) { | 2196 if (FLAG_use_range) { |
| 2227 HRangeAnalysis rangeAnalysis(graph_); | 2197 HRangeAnalysis rangeAnalysis(graph()); |
| 2228 rangeAnalysis.Analyze(); | 2198 rangeAnalysis.Analyze(); |
| 2229 } | 2199 } |
| 2230 | 2200 |
| 2231 graph_->InitializeInferredTypes(); | 2201 graph()->InitializeInferredTypes(); |
| 2232 graph_->Canonicalize(); | 2202 graph()->Canonicalize(); |
| 2233 graph_->InsertRepresentationChanges(); | 2203 graph()->InsertRepresentationChanges(); |
| 2234 graph_->ComputeMinusZeroChecks(); | 2204 graph()->ComputeMinusZeroChecks(); |
| 2235 | 2205 |
| 2236 // Eliminate redundant stack checks on backwards branches. | 2206 // Eliminate redundant stack checks on backwards branches. |
| 2237 HStackCheckEliminator sce(graph_); | 2207 HStackCheckEliminator sce(graph()); |
| 2238 sce.Process(); | 2208 sce.Process(); |
| 2239 | 2209 |
| 2240 // Perform common subexpression elimination and loop-invariant code motion. | 2210 // Perform common subexpression elimination and loop-invariant code motion. |
| 2241 if (FLAG_use_gvn) { | 2211 if (FLAG_use_gvn) { |
| 2242 HPhase phase("Global value numbering", graph_); | 2212 HPhase phase("Global value numbering", graph()); |
| 2243 HGlobalValueNumberer gvn(graph_); | 2213 HGlobalValueNumberer gvn(graph(), info()); |
| 2244 gvn.Analyze(); | 2214 gvn.Analyze(); |
| 2245 } | 2215 } |
| 2246 | 2216 |
| 2247 return graph_; | 2217 return graph(); |
| 2248 } | |
| 2249 | |
| 2250 | |
| 2251 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) { | |
| 2252 SubgraphScope scope(this, graph); | |
| 2253 Visit(stmt); | |
| 2254 } | |
| 2255 | |
| 2256 | |
| 2257 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { | |
| 2258 SubgraphScope scope(this, graph); | |
| 2259 VisitForValue(expr); | |
| 2260 } | |
| 2261 | |
| 2262 | |
| 2263 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, | |
| 2264 ZoneList<Statement*>* stmts) { | |
| 2265 SubgraphScope scope(this, graph); | |
| 2266 VisitStatements(stmts); | |
| 2267 } | 2218 } |
| 2268 | 2219 |
| 2269 | 2220 |
| 2270 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { | 2221 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
| 2271 ASSERT(current_subgraph_->HasExit()); | 2222 ASSERT(current_block() != NULL); |
| 2272 current_subgraph_->exit_block()->AddInstruction(instr); | 2223 current_block()->AddInstruction(instr); |
| 2273 return instr; | 2224 return instr; |
| 2274 } | 2225 } |
| 2275 | 2226 |
| 2276 | 2227 |
| 2277 void HGraphBuilder::AddSimulate(int id) { | 2228 void HGraphBuilder::AddSimulate(int id) { |
| 2278 ASSERT(current_subgraph_->HasExit()); | 2229 ASSERT(current_block() != NULL); |
| 2279 current_subgraph_->exit_block()->AddSimulate(id); | 2230 current_block()->AddSimulate(id); |
| 2280 } | 2231 } |
| 2281 | 2232 |
| 2282 | 2233 |
| 2283 void HGraphBuilder::AddPhi(HPhi* instr) { | 2234 void HGraphBuilder::AddPhi(HPhi* instr) { |
| 2284 ASSERT(current_subgraph_->HasExit()); | 2235 ASSERT(current_block() != NULL); |
| 2285 current_subgraph_->exit_block()->AddPhi(instr); | 2236 current_block()->AddPhi(instr); |
| 2286 } | 2237 } |
| 2287 | 2238 |
| 2288 | 2239 |
| 2289 void HGraphBuilder::PushAndAdd(HInstruction* instr) { | 2240 void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
| 2290 Push(instr); | 2241 Push(instr); |
| 2291 AddInstruction(instr); | 2242 AddInstruction(instr); |
| 2292 } | 2243 } |
| 2293 | 2244 |
| 2294 | 2245 |
| 2295 void HGraphBuilder::PreProcessCall(HCall* call) { | 2246 template <int V> |
| 2247 HInstruction* HGraphBuilder::PreProcessCall(HCall<V>* call) { |
| 2296 int count = call->argument_count(); | 2248 int count = call->argument_count(); |
| 2297 ZoneList<HValue*> arguments(count); | 2249 ZoneList<HValue*> arguments(count); |
| 2298 for (int i = 0; i < count; ++i) { | 2250 for (int i = 0; i < count; ++i) { |
| 2299 arguments.Add(Pop()); | 2251 arguments.Add(Pop()); |
| 2300 } | 2252 } |
| 2301 | 2253 |
| 2302 while (!arguments.is_empty()) { | 2254 while (!arguments.is_empty()) { |
| 2303 AddInstruction(new HPushArgument(arguments.RemoveLast())); | 2255 AddInstruction(new HPushArgument(arguments.RemoveLast())); |
| 2304 } | 2256 } |
| 2257 return call; |
| 2305 } | 2258 } |
| 2306 | 2259 |
| 2307 | 2260 |
| 2308 void HGraphBuilder::SetupScope(Scope* scope) { | 2261 void HGraphBuilder::SetupScope(Scope* scope) { |
| 2309 // We don't yet handle the function name for named function expressions. | 2262 // We don't yet handle the function name for named function expressions. |
| 2310 if (scope->function() != NULL) BAILOUT("named function expression"); | 2263 if (scope->function() != NULL) BAILOUT("named function expression"); |
| 2311 | 2264 |
| 2312 // We can't handle heap-allocated locals. | |
| 2313 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); | |
| 2314 | |
| 2315 HConstant* undefined_constant = | 2265 HConstant* undefined_constant = |
| 2316 new HConstant(Factory::undefined_value(), Representation::Tagged()); | 2266 new HConstant(Factory::undefined_value(), Representation::Tagged()); |
| 2317 AddInstruction(undefined_constant); | 2267 AddInstruction(undefined_constant); |
| 2318 graph_->set_undefined_constant(undefined_constant); | 2268 graph_->set_undefined_constant(undefined_constant); |
| 2319 | 2269 |
| 2320 // Set the initial values of parameters including "this". "This" has | 2270 // Set the initial values of parameters including "this". "This" has |
| 2321 // parameter index 0. | 2271 // parameter index 0. |
| 2322 int count = scope->num_parameters() + 1; | 2272 int count = scope->num_parameters() + 1; |
| 2323 for (int i = 0; i < count; ++i) { | 2273 for (int i = 0; i < count; ++i) { |
| 2324 HInstruction* parameter = AddInstruction(new HParameter(i)); | 2274 HInstruction* parameter = AddInstruction(new HParameter(i)); |
| 2325 environment()->Bind(i, parameter); | 2275 environment()->Bind(i, parameter); |
| 2326 } | 2276 } |
| 2327 | 2277 |
| 2328 // Set the initial values of stack-allocated locals. | 2278 // Set the initial values of stack-allocated locals. |
| 2329 for (int i = count; i < environment()->length(); ++i) { | 2279 for (int i = count; i < environment()->length(); ++i) { |
| 2330 environment()->Bind(i, undefined_constant); | 2280 environment()->Bind(i, undefined_constant); |
| 2331 } | 2281 } |
| 2332 | 2282 |
| 2333 // Handle the arguments and arguments shadow variables specially (they do | 2283 // Handle the arguments and arguments shadow variables specially (they do |
| 2334 // not have declarations). | 2284 // not have declarations). |
| 2335 if (scope->arguments() != NULL) { | 2285 if (scope->arguments() != NULL) { |
| 2286 if (!scope->arguments()->IsStackAllocated() || |
| 2287 (scope->arguments_shadow() != NULL && |
| 2288 !scope->arguments_shadow()->IsStackAllocated())) { |
| 2289 BAILOUT("context-allocated arguments"); |
| 2290 } |
| 2336 HArgumentsObject* object = new HArgumentsObject; | 2291 HArgumentsObject* object = new HArgumentsObject; |
| 2337 AddInstruction(object); | 2292 AddInstruction(object); |
| 2338 graph()->SetArgumentsObject(object); | 2293 graph()->SetArgumentsObject(object); |
| 2339 environment()->Bind(scope->arguments(), object); | 2294 environment()->Bind(scope->arguments(), object); |
| 2340 environment()->Bind(scope->arguments_shadow(), object); | 2295 if (scope->arguments_shadow() != NULL) { |
| 2296 environment()->Bind(scope->arguments_shadow(), object); |
| 2297 } |
| 2341 } | 2298 } |
| 2342 } | 2299 } |
| 2343 | 2300 |
| 2344 | 2301 |
| 2345 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { | 2302 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { |
| 2346 for (int i = 0; i < statements->length(); i++) { | 2303 for (int i = 0; i < statements->length(); i++) { |
| 2347 Visit(statements->at(i)); | 2304 Visit(statements->at(i)); |
| 2348 if (HasStackOverflow() || !current_subgraph_->HasExit()) break; | 2305 if (HasStackOverflow() || current_block() == NULL) break; |
| 2349 } | 2306 } |
| 2350 } | 2307 } |
| 2351 | 2308 |
| 2352 | 2309 |
| 2353 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { | 2310 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| 2354 HBasicBlock* b = graph()->CreateBasicBlock(); | 2311 HBasicBlock* b = graph()->CreateBasicBlock(); |
| 2355 b->SetInitialEnvironment(env); | 2312 b->SetInitialEnvironment(env); |
| 2356 return b; | 2313 return b; |
| 2357 } | 2314 } |
| 2358 | 2315 |
| 2359 | 2316 |
| 2360 HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer, | 2317 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
| 2361 Handle<JSFunction> target, | 2318 HBasicBlock* header = graph()->CreateBasicBlock(); |
| 2362 FunctionLiteral* function) { | 2319 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| 2363 HConstant* undefined = graph()->GetConstantUndefined(); | 2320 header->SetInitialEnvironment(entry_env); |
| 2364 HEnvironment* inner = | 2321 header->AttachLoopInformation(); |
| 2365 outer->CopyForInlining(target, function, true, undefined); | 2322 return header; |
| 2366 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2367 subgraph->Initialize(CreateBasicBlock(inner)); | |
| 2368 return subgraph; | |
| 2369 } | |
| 2370 | |
| 2371 | |
| 2372 HSubgraph* HGraphBuilder::CreateGotoSubgraph(HEnvironment* env) { | |
| 2373 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2374 HEnvironment* new_env = env->CopyWithoutHistory(); | |
| 2375 subgraph->Initialize(CreateBasicBlock(new_env)); | |
| 2376 return subgraph; | |
| 2377 } | |
| 2378 | |
| 2379 | |
| 2380 HSubgraph* HGraphBuilder::CreateEmptySubgraph() { | |
| 2381 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2382 subgraph->Initialize(graph()->CreateBasicBlock()); | |
| 2383 return subgraph; | |
| 2384 } | |
| 2385 | |
| 2386 | |
| 2387 HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) { | |
| 2388 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2389 HEnvironment* new_env = env->Copy(); | |
| 2390 subgraph->Initialize(CreateBasicBlock(new_env)); | |
| 2391 return subgraph; | |
| 2392 } | |
| 2393 | |
| 2394 | |
| 2395 HSubgraph* HGraphBuilder::CreateLoopHeaderSubgraph(HEnvironment* env) { | |
| 2396 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2397 HBasicBlock* block = graph()->CreateBasicBlock(); | |
| 2398 HEnvironment* new_env = env->CopyAsLoopHeader(block); | |
| 2399 block->SetInitialEnvironment(new_env); | |
| 2400 subgraph->Initialize(block); | |
| 2401 subgraph->entry_block()->AttachLoopInformation(); | |
| 2402 return subgraph; | |
| 2403 } | 2323 } |
| 2404 | 2324 |
| 2405 | 2325 |
| 2406 void HGraphBuilder::VisitBlock(Block* stmt) { | 2326 void HGraphBuilder::VisitBlock(Block* stmt) { |
| 2407 if (stmt->labels() != NULL) { | 2327 BreakAndContinueInfo break_info(stmt); |
| 2408 HSubgraph* block_graph = CreateGotoSubgraph(environment()); | 2328 { BreakAndContinueScope push(&break_info, this); |
| 2409 ADD_TO_SUBGRAPH(block_graph, stmt->statements()); | |
| 2410 current_subgraph_->Append(block_graph, stmt); | |
| 2411 } else { | |
| 2412 VisitStatements(stmt->statements()); | 2329 VisitStatements(stmt->statements()); |
| 2330 CHECK_BAILOUT; |
| 2331 } |
| 2332 HBasicBlock* break_block = break_info.break_block(); |
| 2333 if (break_block != NULL) { |
| 2334 if (current_block() != NULL) current_block()->Goto(break_block); |
| 2335 break_block->SetJoinId(stmt->ExitId()); |
| 2336 set_current_block(break_block); |
| 2413 } | 2337 } |
| 2414 } | 2338 } |
| 2415 | 2339 |
| 2416 | 2340 |
| 2417 void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { | 2341 void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 2418 VisitForEffect(stmt->expression()); | 2342 VisitForEffect(stmt->expression()); |
| 2419 } | 2343 } |
| 2420 | 2344 |
| 2421 | 2345 |
| 2422 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { | 2346 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { |
| 2423 } | 2347 } |
| 2424 | 2348 |
| 2425 | 2349 |
| 2426 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { | 2350 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { |
| 2427 if (stmt->condition()->ToBooleanIsTrue()) { | 2351 if (stmt->condition()->ToBooleanIsTrue()) { |
| 2428 AddSimulate(stmt->ThenId()); | 2352 AddSimulate(stmt->ThenId()); |
| 2429 Visit(stmt->then_statement()); | 2353 Visit(stmt->then_statement()); |
| 2430 } else if (stmt->condition()->ToBooleanIsFalse()) { | 2354 } else if (stmt->condition()->ToBooleanIsFalse()) { |
| 2431 AddSimulate(stmt->ElseId()); | 2355 AddSimulate(stmt->ElseId()); |
| 2432 Visit(stmt->else_statement()); | 2356 Visit(stmt->else_statement()); |
| 2433 } else { | 2357 } else { |
| 2434 HSubgraph* then_graph = CreateEmptySubgraph(); | 2358 HBasicBlock* cond_true = graph()->CreateBasicBlock(); |
| 2435 HSubgraph* else_graph = CreateEmptySubgraph(); | 2359 HBasicBlock* cond_false = graph()->CreateBasicBlock(); |
| 2436 VISIT_FOR_CONTROL(stmt->condition(), | 2360 VISIT_FOR_CONTROL(stmt->condition(), cond_true, cond_false); |
| 2437 then_graph->entry_block(), | 2361 cond_true->SetJoinId(stmt->ThenId()); |
| 2438 else_graph->entry_block()); | 2362 cond_false->SetJoinId(stmt->ElseId()); |
| 2439 | 2363 |
| 2440 then_graph->entry_block()->SetJoinId(stmt->ThenId()); | 2364 set_current_block(cond_true); |
| 2441 ADD_TO_SUBGRAPH(then_graph, stmt->then_statement()); | 2365 Visit(stmt->then_statement()); |
| 2366 CHECK_BAILOUT; |
| 2367 HBasicBlock* other = current_block(); |
| 2442 | 2368 |
| 2443 else_graph->entry_block()->SetJoinId(stmt->ElseId()); | 2369 set_current_block(cond_false); |
| 2444 ADD_TO_SUBGRAPH(else_graph, stmt->else_statement()); | 2370 Visit(stmt->else_statement()); |
| 2371 CHECK_BAILOUT; |
| 2445 | 2372 |
| 2446 current_subgraph_->AppendJoin(then_graph, else_graph, stmt); | 2373 HBasicBlock* join = CreateJoin(other, current_block(), stmt->id()); |
| 2374 set_current_block(join); |
| 2447 } | 2375 } |
| 2448 } | 2376 } |
| 2449 | 2377 |
| 2450 | 2378 |
| 2379 HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get( |
| 2380 BreakableStatement* stmt, |
| 2381 BreakType type) { |
| 2382 BreakAndContinueScope* current = this; |
| 2383 while (current != NULL && current->info()->target() != stmt) { |
| 2384 current = current->next(); |
| 2385 } |
| 2386 ASSERT(current != NULL); // Always found (unless stack is malformed). |
| 2387 HBasicBlock* block = NULL; |
| 2388 switch (type) { |
| 2389 case BREAK: |
| 2390 block = current->info()->break_block(); |
| 2391 if (block == NULL) { |
| 2392 block = current->owner()->graph()->CreateBasicBlock(); |
| 2393 current->info()->set_break_block(block); |
| 2394 } |
| 2395 break; |
| 2396 |
| 2397 case CONTINUE: |
| 2398 block = current->info()->continue_block(); |
| 2399 if (block == NULL) { |
| 2400 block = current->owner()->graph()->CreateBasicBlock(); |
| 2401 current->info()->set_continue_block(block); |
| 2402 } |
| 2403 break; |
| 2404 } |
| 2405 |
| 2406 return block; |
| 2407 } |
| 2408 |
| 2409 |
| 2451 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { | 2410 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
| 2452 current_subgraph_->FinishBreakContinue(stmt->target(), true); | 2411 HBasicBlock* continue_block = break_scope()->Get(stmt->target(), CONTINUE); |
| 2412 current_block()->Goto(continue_block); |
| 2413 set_current_block(NULL); |
| 2453 } | 2414 } |
| 2454 | 2415 |
| 2455 | 2416 |
| 2456 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { | 2417 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { |
| 2457 current_subgraph_->FinishBreakContinue(stmt->target(), false); | 2418 HBasicBlock* break_block = break_scope()->Get(stmt->target(), BREAK); |
| 2419 current_block()->Goto(break_block); |
| 2420 set_current_block(NULL); |
| 2458 } | 2421 } |
| 2459 | 2422 |
| 2460 | 2423 |
| 2461 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 2424 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
| 2462 AstContext* context = call_context(); | 2425 AstContext* context = call_context(); |
| 2463 if (context == NULL) { | 2426 if (context == NULL) { |
| 2464 // Not an inlined return, so an actual one. | 2427 // Not an inlined return, so an actual one. |
| 2465 VISIT_FOR_VALUE(stmt->expression()); | 2428 VISIT_FOR_VALUE(stmt->expression()); |
| 2466 HValue* result = environment()->Pop(); | 2429 HValue* result = environment()->Pop(); |
| 2467 subgraph()->FinishExit(new HReturn(result)); | 2430 current_block()->FinishExit(new HReturn(result)); |
| 2431 set_current_block(NULL); |
| 2468 } else { | 2432 } else { |
| 2469 // Return from an inlined function, visit the subexpression in the | 2433 // Return from an inlined function, visit the subexpression in the |
| 2470 // expression context of the call. | 2434 // expression context of the call. |
| 2471 if (context->IsTest()) { | 2435 if (context->IsTest()) { |
| 2472 TestContext* test = TestContext::cast(context); | 2436 TestContext* test = TestContext::cast(context); |
| 2473 VisitForControl(stmt->expression(), | 2437 VisitForControl(stmt->expression(), |
| 2474 test->if_true(), | 2438 test->if_true(), |
| 2475 test->if_false()); | 2439 test->if_false()); |
| 2440 } else if (context->IsEffect()) { |
| 2441 VISIT_FOR_EFFECT(stmt->expression()); |
| 2442 current_block()->Goto(function_return(), false); |
| 2476 } else { | 2443 } else { |
| 2477 HValue* return_value = NULL; | 2444 ASSERT(context->IsValue()); |
| 2478 if (context->IsEffect()) { | 2445 VISIT_FOR_VALUE(stmt->expression()); |
| 2479 VISIT_FOR_EFFECT(stmt->expression()); | 2446 HValue* return_value = environment()->Pop(); |
| 2480 return_value = graph()->GetConstantUndefined(); | 2447 current_block()->AddLeaveInlined(return_value, function_return()); |
| 2481 } else { | |
| 2482 ASSERT(context->IsValue()); | |
| 2483 VISIT_FOR_VALUE(stmt->expression()); | |
| 2484 return_value = environment()->Pop(); | |
| 2485 } | |
| 2486 subgraph()->exit_block()->AddLeaveInlined(return_value, | |
| 2487 function_return_); | |
| 2488 subgraph()->set_exit_block(NULL); | |
| 2489 } | 2448 } |
| 2449 set_current_block(NULL); |
| 2490 } | 2450 } |
| 2491 } | 2451 } |
| 2492 | 2452 |
| 2493 | 2453 |
| 2494 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | 2454 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { |
| 2495 BAILOUT("WithEnterStatement"); | 2455 BAILOUT("WithEnterStatement"); |
| 2496 } | 2456 } |
| 2497 | 2457 |
| 2498 | 2458 |
| 2499 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | 2459 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { |
| 2500 BAILOUT("WithExitStatement"); | 2460 BAILOUT("WithExitStatement"); |
| 2501 } | 2461 } |
| 2502 | 2462 |
| 2503 | 2463 |
| 2504 HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph, | |
| 2505 HValue* switch_value, | |
| 2506 CaseClause* clause) { | |
| 2507 AddToSubgraph(subgraph, clause->label()); | |
| 2508 if (HasStackOverflow()) return NULL; | |
| 2509 HValue* clause_value = subgraph->environment()->Pop(); | |
| 2510 HCompare* compare = new HCompare(switch_value, | |
| 2511 clause_value, | |
| 2512 Token::EQ_STRICT); | |
| 2513 compare->SetInputRepresentation(Representation::Integer32()); | |
| 2514 subgraph->exit_block()->AddInstruction(compare); | |
| 2515 return compare; | |
| 2516 } | |
| 2517 | |
| 2518 | |
| 2519 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2464 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 2465 // We only optimize switch statements with smi-literal smi comparisons, |
| 2466 // with a bounded number of clauses. |
| 2467 const int kCaseClauseLimit = 128; |
| 2468 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 2469 int clause_count = clauses->length(); |
| 2470 if (clause_count > kCaseClauseLimit) { |
| 2471 BAILOUT("SwitchStatement: too many clauses"); |
| 2472 } |
| 2473 |
| 2520 VISIT_FOR_VALUE(stmt->tag()); | 2474 VISIT_FOR_VALUE(stmt->tag()); |
| 2521 // TODO(3168478): simulate added for tag should be enough. | 2475 HValue* tag_value = Pop(); |
| 2522 AddSimulate(stmt->EntryId()); | 2476 HBasicBlock* first_test_block = current_block(); |
| 2523 HValue* switch_value = Pop(); | 2477 |
| 2524 | 2478 // 1. Build all the tests, with dangling true branches. Unconditionally |
| 2525 ZoneList<CaseClause*>* clauses = stmt->cases(); | 2479 // deoptimize if we encounter a non-smi comparison. |
| 2526 int num_clauses = clauses->length(); | 2480 for (int i = 0; i < clause_count; ++i) { |
| 2527 if (num_clauses == 0) return; | |
| 2528 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); | |
| 2529 | |
| 2530 int num_smi_clauses = num_clauses; | |
| 2531 for (int i = 0; i < num_clauses; i++) { | |
| 2532 CaseClause* clause = clauses->at(i); | 2481 CaseClause* clause = clauses->at(i); |
| 2533 if (clause->is_default()) continue; | 2482 if (clause->is_default()) continue; |
| 2534 clause->RecordTypeFeedback(oracle()); | |
| 2535 if (!clause->IsSmiCompare()) { | |
| 2536 if (i == 0) BAILOUT("SwitchStatement: no smi compares"); | |
| 2537 // We will deoptimize if the first non-smi compare is reached. | |
| 2538 num_smi_clauses = i; | |
| 2539 break; | |
| 2540 } | |
| 2541 if (!clause->label()->IsSmiLiteral()) { | 2483 if (!clause->label()->IsSmiLiteral()) { |
| 2542 BAILOUT("SwitchStatement: non-literal switch label"); | 2484 BAILOUT("SwitchStatement: non-literal switch label"); |
| 2543 } | 2485 } |
| 2544 } | 2486 |
| 2545 | 2487 // Unconditionally deoptimize on the first non-smi compare. |
| 2546 // The single exit block of the whole switch statement. | 2488 clause->RecordTypeFeedback(oracle()); |
| 2547 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); | 2489 if (!clause->IsSmiCompare()) { |
| 2548 | 2490 if (current_block() == first_test_block) { |
| 2549 // Build a series of empty subgraphs for the comparisons. | 2491 // If the first test is the one that deopts and if the tag value is |
| 2550 // The default clause does not have a comparison subgraph. | 2492 // a phi, we need to have some use of that phi to prevent phi |
| 2551 ZoneList<HSubgraph*> compare_graphs(num_smi_clauses); | 2493 // elimination from removing it. This HSimulate is such a use. |
| 2552 for (int i = 0; i < num_smi_clauses; i++) { | 2494 Push(tag_value); |
| 2553 if (clauses->at(i)->is_default()) { | 2495 AddSimulate(stmt->EntryId()); |
| 2554 compare_graphs.Add(NULL); | 2496 Drop(1); |
| 2555 } else { | 2497 } |
| 2556 compare_graphs.Add(CreateEmptySubgraph()); | 2498 current_block()->Finish(new HDeoptimize()); |
| 2499 set_current_block(NULL); |
| 2500 break; |
| 2557 } | 2501 } |
| 2558 } | 2502 |
| 2559 | 2503 // Otherwise generate a compare and branch. |
| 2560 HSubgraph* prev_graph = current_subgraph_; | 2504 VISIT_FOR_VALUE(clause->label()); |
| 2561 HCompare* prev_compare_inst = NULL; | 2505 HValue* label_value = Pop(); |
| 2562 for (int i = 0; i < num_smi_clauses; i++) { | 2506 HCompare* compare = new HCompare(tag_value, label_value, Token::EQ_STRICT); |
| 2563 CaseClause* clause = clauses->at(i); | 2507 compare->SetInputRepresentation(Representation::Integer32()); |
| 2564 if (clause->is_default()) continue; | 2508 ASSERT(!compare->HasSideEffects()); |
| 2565 | 2509 AddInstruction(compare); |
| 2566 // Finish the previous graph by connecting it to the current. | 2510 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| 2567 HSubgraph* subgraph = compare_graphs.at(i); | 2511 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| 2568 if (prev_compare_inst == NULL) { | 2512 HTest* branch = new HTest(compare, body_block, next_test_block); |
| 2569 ASSERT(prev_graph == current_subgraph_); | 2513 current_block()->Finish(branch); |
| 2570 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | 2514 set_current_block(next_test_block); |
| 2571 } else { | 2515 } |
| 2572 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2516 |
| 2573 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, | 2517 // Save the current block to use for the default or to join with the |
| 2574 empty, | 2518 // exit. This block is NULL if we deoptimized. |
| 2575 subgraph->entry_block())); | 2519 HBasicBlock* last_block = current_block(); |
| 2520 |
| 2521 // 2. Loop over the clauses and the linked list of tests in lockstep, |
| 2522 // translating the clause bodies. |
| 2523 HBasicBlock* curr_test_block = first_test_block; |
| 2524 HBasicBlock* fall_through_block = NULL; |
| 2525 BreakAndContinueInfo break_info(stmt); |
| 2526 { BreakAndContinueScope push(&break_info, this); |
| 2527 for (int i = 0; i < clause_count; ++i) { |
| 2528 CaseClause* clause = clauses->at(i); |
| 2529 |
| 2530 // Identify the block where normal (non-fall-through) control flow |
| 2531 // goes to. |
| 2532 HBasicBlock* normal_block = NULL; |
| 2533 if (clause->is_default() && last_block != NULL) { |
| 2534 normal_block = last_block; |
| 2535 last_block = NULL; // Cleared to indicate we've handled it. |
| 2536 } else if (!curr_test_block->end()->IsDeoptimize()) { |
| 2537 normal_block = curr_test_block->end()->FirstSuccessor(); |
| 2538 curr_test_block = curr_test_block->end()->SecondSuccessor(); |
| 2539 } |
| 2540 |
| 2541 // Identify a block to emit the body into. |
| 2542 if (normal_block == NULL) { |
| 2543 if (fall_through_block == NULL) { |
| 2544 // (a) Unreachable. |
| 2545 if (clause->is_default()) { |
| 2546 continue; // Might still be reachable clause bodies. |
| 2547 } else { |
| 2548 break; |
| 2549 } |
| 2550 } else { |
| 2551 // (b) Reachable only as fall through. |
| 2552 set_current_block(fall_through_block); |
| 2553 } |
| 2554 } else if (fall_through_block == NULL) { |
| 2555 // (c) Reachable only normally. |
| 2556 set_current_block(normal_block); |
| 2557 } else { |
| 2558 // (d) Reachable both ways. |
| 2559 HBasicBlock* join = CreateJoin(fall_through_block, |
| 2560 normal_block, |
| 2561 clause->EntryId()); |
| 2562 set_current_block(join); |
| 2563 } |
| 2564 |
| 2565 VisitStatements(clause->statements()); |
| 2566 CHECK_BAILOUT; |
| 2567 fall_through_block = current_block(); |
| 2576 } | 2568 } |
| 2577 | 2569 } |
| 2578 // Build instructions for current subgraph. | 2570 |
| 2579 ASSERT(clause->IsSmiCompare()); | 2571 // Create an up-to-3-way join. Use the break block if it exists since |
| 2580 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | 2572 // it's already a join block. |
| 2581 if (HasStackOverflow()) return; | 2573 HBasicBlock* break_block = break_info.break_block(); |
| 2582 | 2574 if (break_block == NULL) { |
| 2583 prev_graph = subgraph; | 2575 set_current_block(CreateJoin(fall_through_block, |
| 2584 } | 2576 last_block, |
| 2585 | 2577 stmt->ExitId())); |
| 2586 // Finish last comparison if there was at least one comparison. | |
| 2587 // last_false_block is the (empty) false-block of the last comparison. If | |
| 2588 // there are no comparisons at all (a single default clause), it is just | |
| 2589 // the last block of the current subgraph. | |
| 2590 HBasicBlock* last_false_block = current_subgraph_->exit_block(); | |
| 2591 if (prev_graph != current_subgraph_) { | |
| 2592 last_false_block = graph()->CreateBasicBlock(); | |
| 2593 HBasicBlock* empty = graph()->CreateBasicBlock(); | |
| 2594 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, | |
| 2595 empty, | |
| 2596 last_false_block)); | |
| 2597 } | |
| 2598 | |
| 2599 // If we have a non-smi compare clause, we deoptimize after trying | |
| 2600 // all the previous compares. | |
| 2601 if (num_smi_clauses < num_clauses) { | |
| 2602 last_false_block->Finish(new HDeoptimize); | |
| 2603 } | |
| 2604 | |
| 2605 // Build statement blocks, connect them to their comparison block and | |
| 2606 // to the previous statement block, if there is a fall-through. | |
| 2607 HSubgraph* previous_subgraph = NULL; | |
| 2608 for (int i = 0; i < num_clauses; i++) { | |
| 2609 CaseClause* clause = clauses->at(i); | |
| 2610 // Subgraph for the statements of the clause is only created when | |
| 2611 // it's reachable either from the corresponding compare or as a | |
| 2612 // fall-through from previous statements. | |
| 2613 HSubgraph* subgraph = NULL; | |
| 2614 | |
| 2615 if (i < num_smi_clauses) { | |
| 2616 if (clause->is_default()) { | |
| 2617 if (!last_false_block->IsFinished()) { | |
| 2618 // Default clause: Connect it to the last false block. | |
| 2619 subgraph = CreateEmptySubgraph(); | |
| 2620 last_false_block->Finish(new HGoto(subgraph->entry_block())); | |
| 2621 } | |
| 2622 } else { | |
| 2623 ASSERT(clause->IsSmiCompare()); | |
| 2624 // Connect with the corresponding comparison. | |
| 2625 subgraph = CreateEmptySubgraph(); | |
| 2626 HBasicBlock* empty = | |
| 2627 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); | |
| 2628 empty->Finish(new HGoto(subgraph->entry_block())); | |
| 2629 } | |
| 2630 } | |
| 2631 | |
| 2632 // Check for fall-through from previous statement block. | |
| 2633 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { | |
| 2634 if (subgraph == NULL) subgraph = CreateEmptySubgraph(); | |
| 2635 previous_subgraph->exit_block()-> | |
| 2636 Finish(new HGoto(subgraph->entry_block())); | |
| 2637 } | |
| 2638 | |
| 2639 if (subgraph != NULL) { | |
| 2640 ADD_TO_SUBGRAPH(subgraph, clause->statements()); | |
| 2641 HBasicBlock* break_block = subgraph->BundleBreak(stmt); | |
| 2642 if (break_block != NULL) { | |
| 2643 break_block->Finish(new HGoto(single_exit_block)); | |
| 2644 } | |
| 2645 } | |
| 2646 | |
| 2647 previous_subgraph = subgraph; | |
| 2648 } | |
| 2649 | |
| 2650 // If the last statement block has a fall-through, connect it to the | |
| 2651 // single exit block. | |
| 2652 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { | |
| 2653 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); | |
| 2654 } | |
| 2655 | |
| 2656 // If there is no default clause finish the last comparison's false target. | |
| 2657 if (!last_false_block->IsFinished()) { | |
| 2658 last_false_block->Finish(new HGoto(single_exit_block)); | |
| 2659 } | |
| 2660 | |
| 2661 if (single_exit_block->HasPredecessor()) { | |
| 2662 current_subgraph_->set_exit_block(single_exit_block); | |
| 2663 } else { | 2578 } else { |
| 2664 current_subgraph_->set_exit_block(NULL); | 2579 if (fall_through_block != NULL) fall_through_block->Goto(break_block); |
| 2665 } | 2580 if (last_block != NULL) last_block->Goto(break_block); |
| 2666 } | 2581 break_block->SetJoinId(stmt->ExitId()); |
| 2667 | 2582 set_current_block(break_block); |
| 2668 bool HGraph::HasOsrEntryAt(IterationStatement* statement) { | 2583 } |
| 2584 } |
| 2585 |
| 2586 |
| 2587 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { |
| 2669 return statement->OsrEntryId() == info()->osr_ast_id(); | 2588 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2670 } | 2589 } |
| 2671 | 2590 |
| 2672 | 2591 |
| 2673 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { | 2592 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { |
| 2674 if (!graph()->HasOsrEntryAt(statement)) return; | 2593 if (!HasOsrEntryAt(statement)) return; |
| 2675 | 2594 |
| 2676 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2595 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2677 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2596 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 2678 HValue* true_value = graph()->GetConstantTrue(); | 2597 HValue* true_value = graph()->GetConstantTrue(); |
| 2679 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); | 2598 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); |
| 2680 exit_block()->Finish(test); | 2599 current_block()->Finish(test); |
| 2681 | 2600 |
| 2682 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2601 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2683 non_osr_entry->Goto(loop_predecessor); | 2602 non_osr_entry->Goto(loop_predecessor); |
| 2684 | 2603 |
| 2604 set_current_block(osr_entry); |
| 2685 int osr_entry_id = statement->OsrEntryId(); | 2605 int osr_entry_id = statement->OsrEntryId(); |
| 2686 // We want the correct environment at the OsrEntry instruction. Build | 2606 // We want the correct environment at the OsrEntry instruction. Build |
| 2687 // it explicitly. The expression stack should be empty. | 2607 // it explicitly. The expression stack should be empty. |
| 2688 int count = osr_entry->last_environment()->length(); | 2608 int count = environment()->length(); |
| 2689 ASSERT(count == (osr_entry->last_environment()->parameter_count() + | 2609 ASSERT(count == |
| 2690 osr_entry->last_environment()->local_count())); | 2610 (environment()->parameter_count() + environment()->local_count())); |
| 2691 for (int i = 0; i < count; ++i) { | 2611 for (int i = 0; i < count; ++i) { |
| 2692 HUnknownOSRValue* unknown = new HUnknownOSRValue; | 2612 HUnknownOSRValue* unknown = new HUnknownOSRValue; |
| 2693 osr_entry->AddInstruction(unknown); | 2613 AddInstruction(unknown); |
| 2694 osr_entry->last_environment()->Bind(i, unknown); | 2614 environment()->Bind(i, unknown); |
| 2695 } | 2615 } |
| 2696 | 2616 |
| 2697 osr_entry->AddSimulate(osr_entry_id); | 2617 AddSimulate(osr_entry_id); |
| 2698 osr_entry->AddInstruction(new HOsrEntry(osr_entry_id)); | 2618 AddInstruction(new HOsrEntry(osr_entry_id)); |
| 2699 osr_entry->Goto(loop_predecessor); | 2619 current_block()->Goto(loop_predecessor); |
| 2700 loop_predecessor->SetJoinId(statement->EntryId()); | 2620 loop_predecessor->SetJoinId(statement->EntryId()); |
| 2701 set_exit_block(loop_predecessor); | 2621 set_current_block(loop_predecessor); |
| 2702 } | 2622 } |
| 2703 | 2623 |
| 2704 | 2624 |
| 2705 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { | 2625 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 2706 ASSERT(subgraph()->HasExit()); | 2626 ASSERT(current_block() != NULL); |
| 2707 subgraph()->PreProcessOsrEntry(stmt); | 2627 PreProcessOsrEntry(stmt); |
| 2708 | 2628 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2709 HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment()); | 2629 current_block()->Goto(loop_entry, false); |
| 2710 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2630 set_current_block(loop_entry); |
| 2711 body_graph->ResolveContinue(stmt); | 2631 |
| 2712 | 2632 BreakAndContinueInfo break_info(stmt); |
| 2713 if (!body_graph->HasExit() || stmt->cond()->ToBooleanIsTrue()) { | 2633 { BreakAndContinueScope push(&break_info, this); |
| 2714 current_subgraph_->AppendEndless(body_graph, stmt); | 2634 Visit(stmt->body()); |
| 2715 } else { | 2635 CHECK_BAILOUT; |
| 2716 HSubgraph* go_back = CreateEmptySubgraph(); | 2636 } |
| 2717 HSubgraph* exit = CreateEmptySubgraph(); | 2637 HBasicBlock* body_exit = |
| 2718 { | 2638 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2719 SubgraphScope scope(this, body_graph); | 2639 HBasicBlock* loop_successor = NULL; |
| 2720 VISIT_FOR_CONTROL(stmt->cond(), | 2640 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) { |
| 2721 go_back->entry_block(), | 2641 set_current_block(body_exit); |
| 2722 exit->entry_block()); | 2642 // The block for a true condition, the actual predecessor block of the |
| 2723 go_back->entry_block()->SetJoinId(stmt->BackEdgeId()); | 2643 // back edge. |
| 2724 exit->entry_block()->SetJoinId(stmt->ExitId()); | 2644 body_exit = graph()->CreateBasicBlock(); |
| 2725 } | 2645 loop_successor = graph()->CreateBasicBlock(); |
| 2726 current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit); | 2646 VISIT_FOR_CONTROL(stmt->cond(), body_exit, loop_successor); |
| 2727 } | 2647 body_exit->SetJoinId(stmt->BackEdgeId()); |
| 2728 } | 2648 loop_successor->SetJoinId(stmt->ExitId()); |
| 2729 | 2649 } |
| 2730 | 2650 HBasicBlock* loop_exit = CreateLoop(stmt, |
| 2731 bool HGraphBuilder::ShouldPeel(HSubgraph* cond, HSubgraph* body) { | 2651 loop_entry, |
| 2732 return FLAG_use_peeling; | 2652 body_exit, |
| 2653 loop_successor, |
| 2654 break_info.break_block()); |
| 2655 set_current_block(loop_exit); |
| 2733 } | 2656 } |
| 2734 | 2657 |
| 2735 | 2658 |
| 2736 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { | 2659 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { |
| 2737 ASSERT(subgraph()->HasExit()); | 2660 ASSERT(current_block() != NULL); |
| 2738 subgraph()->PreProcessOsrEntry(stmt); | 2661 PreProcessOsrEntry(stmt); |
| 2739 | 2662 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2740 HSubgraph* cond_graph = NULL; | 2663 current_block()->Goto(loop_entry, false); |
| 2741 HSubgraph* body_graph = NULL; | 2664 set_current_block(loop_entry); |
| 2742 HSubgraph* exit_graph = NULL; | 2665 |
| 2743 | 2666 // If the condition is constant true, do not generate a branch. |
| 2744 // If the condition is constant true, do not generate a condition subgraph. | 2667 HBasicBlock* loop_successor = NULL; |
| 2745 if (stmt->cond()->ToBooleanIsTrue()) { | 2668 if (!stmt->cond()->ToBooleanIsTrue()) { |
| 2746 body_graph = CreateLoopHeaderSubgraph(environment()); | 2669 HBasicBlock* body_entry = graph()->CreateBasicBlock(); |
| 2747 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2670 loop_successor = graph()->CreateBasicBlock(); |
| 2748 } else { | 2671 VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor); |
| 2749 cond_graph = CreateLoopHeaderSubgraph(environment()); | 2672 body_entry->SetJoinId(stmt->BodyId()); |
| 2750 body_graph = CreateEmptySubgraph(); | 2673 loop_successor->SetJoinId(stmt->ExitId()); |
| 2751 exit_graph = CreateEmptySubgraph(); | 2674 set_current_block(body_entry); |
| 2752 { | 2675 } |
| 2753 SubgraphScope scope(this, cond_graph); | 2676 |
| 2754 VISIT_FOR_CONTROL(stmt->cond(), | 2677 BreakAndContinueInfo break_info(stmt); |
| 2755 body_graph->entry_block(), | 2678 { BreakAndContinueScope push(&break_info, this); |
| 2756 exit_graph->entry_block()); | 2679 Visit(stmt->body()); |
| 2757 body_graph->entry_block()->SetJoinId(stmt->BodyId()); | 2680 CHECK_BAILOUT; |
| 2758 exit_graph->entry_block()->SetJoinId(stmt->ExitId()); | 2681 } |
| 2759 } | 2682 HBasicBlock* body_exit = |
| 2760 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2683 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2761 } | 2684 HBasicBlock* loop_exit = CreateLoop(stmt, |
| 2762 | 2685 loop_entry, |
| 2763 body_graph->ResolveContinue(stmt); | 2686 body_exit, |
| 2764 | 2687 loop_successor, |
| 2765 if (cond_graph != NULL) { | 2688 break_info.break_block()); |
| 2766 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph); | 2689 set_current_block(loop_exit); |
| 2767 } else { | |
| 2768 // TODO(fschneider): Implement peeling for endless loops as well. | |
| 2769 current_subgraph_->AppendEndless(body_graph, stmt); | |
| 2770 } | |
| 2771 } | |
| 2772 | |
| 2773 | |
| 2774 void HGraphBuilder::AppendPeeledWhile(IterationStatement* stmt, | |
| 2775 HSubgraph* cond_graph, | |
| 2776 HSubgraph* body_graph, | |
| 2777 HSubgraph* exit_graph) { | |
| 2778 HSubgraph* loop = NULL; | |
| 2779 if (body_graph->HasExit() && stmt != peeled_statement_ && | |
| 2780 ShouldPeel(cond_graph, body_graph)) { | |
| 2781 // Save the last peeled iteration statement to prevent infinite recursion. | |
| 2782 IterationStatement* outer_peeled_statement = peeled_statement_; | |
| 2783 peeled_statement_ = stmt; | |
| 2784 loop = CreateGotoSubgraph(body_graph->environment()); | |
| 2785 ADD_TO_SUBGRAPH(loop, stmt); | |
| 2786 peeled_statement_ = outer_peeled_statement; | |
| 2787 } | |
| 2788 current_subgraph_->AppendWhile(cond_graph, body_graph, stmt, loop, | |
| 2789 exit_graph); | |
| 2790 } | 2690 } |
| 2791 | 2691 |
| 2792 | 2692 |
| 2793 void HGraphBuilder::VisitForStatement(ForStatement* stmt) { | 2693 void HGraphBuilder::VisitForStatement(ForStatement* stmt) { |
| 2794 // Only visit the init statement in the peeled part of the loop. | 2694 if (stmt->init() != NULL) { |
| 2795 if (stmt->init() != NULL && peeled_statement_ != stmt) { | |
| 2796 Visit(stmt->init()); | 2695 Visit(stmt->init()); |
| 2797 CHECK_BAILOUT; | 2696 CHECK_BAILOUT; |
| 2798 } | 2697 } |
| 2799 ASSERT(subgraph()->HasExit()); | 2698 ASSERT(current_block() != NULL); |
| 2800 subgraph()->PreProcessOsrEntry(stmt); | 2699 PreProcessOsrEntry(stmt); |
| 2801 | 2700 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2802 HSubgraph* cond_graph = NULL; | 2701 current_block()->Goto(loop_entry, false); |
| 2803 HSubgraph* body_graph = NULL; | 2702 set_current_block(loop_entry); |
| 2804 HSubgraph* exit_graph = NULL; | 2703 |
| 2704 HBasicBlock* loop_successor = NULL; |
| 2805 if (stmt->cond() != NULL) { | 2705 if (stmt->cond() != NULL) { |
| 2806 cond_graph = CreateLoopHeaderSubgraph(environment()); | 2706 HBasicBlock* body_entry = graph()->CreateBasicBlock(); |
| 2807 body_graph = CreateEmptySubgraph(); | 2707 loop_successor = graph()->CreateBasicBlock(); |
| 2808 exit_graph = CreateEmptySubgraph(); | 2708 VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor); |
| 2809 { | 2709 body_entry->SetJoinId(stmt->BodyId()); |
| 2810 SubgraphScope scope(this, cond_graph); | 2710 loop_successor->SetJoinId(stmt->ExitId()); |
| 2811 VISIT_FOR_CONTROL(stmt->cond(), | 2711 set_current_block(body_entry); |
| 2812 body_graph->entry_block(), | 2712 } |
| 2813 exit_graph->entry_block()); | 2713 |
| 2814 body_graph->entry_block()->SetJoinId(stmt->BodyId()); | 2714 BreakAndContinueInfo break_info(stmt); |
| 2815 exit_graph->entry_block()->SetJoinId(stmt->ExitId()); | 2715 { BreakAndContinueScope push(&break_info, this); |
| 2816 } | 2716 Visit(stmt->body()); |
| 2817 } else { | 2717 CHECK_BAILOUT; |
| 2818 body_graph = CreateLoopHeaderSubgraph(environment()); | 2718 } |
| 2819 } | 2719 HBasicBlock* body_exit = |
| 2820 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2720 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2821 | 2721 |
| 2822 HSubgraph* next_graph = NULL; | 2722 if (stmt->next() != NULL && body_exit != NULL) { |
| 2823 body_graph->ResolveContinue(stmt); | 2723 set_current_block(body_exit); |
| 2824 | 2724 Visit(stmt->next()); |
| 2825 if (stmt->next() != NULL && body_graph->HasExit()) { | 2725 CHECK_BAILOUT; |
| 2826 next_graph = CreateGotoSubgraph(body_graph->environment()); | 2726 body_exit = current_block(); |
| 2827 ADD_TO_SUBGRAPH(next_graph, stmt->next()); | 2727 } |
| 2828 body_graph->Append(next_graph, NULL); | 2728 |
| 2829 next_graph->entry_block()->SetJoinId(stmt->ContinueId()); | 2729 HBasicBlock* loop_exit = CreateLoop(stmt, |
| 2830 } | 2730 loop_entry, |
| 2831 | 2731 body_exit, |
| 2832 if (cond_graph != NULL) { | 2732 loop_successor, |
| 2833 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph); | 2733 break_info.break_block()); |
| 2834 } else { | 2734 set_current_block(loop_exit); |
| 2835 current_subgraph_->AppendEndless(body_graph, stmt); | 2735 } |
| 2836 } | 2736 |
| 2837 } | 2737 |
| 2838 | |
| 2839 | |
| 2840 void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { | 2738 void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
| 2841 BAILOUT("ForInStatement"); | 2739 BAILOUT("ForInStatement"); |
| 2842 } | 2740 } |
| 2843 | 2741 |
| 2844 | 2742 |
| 2845 void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { | 2743 void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 2846 BAILOUT("TryCatchStatement"); | 2744 BAILOUT("TryCatchStatement"); |
| 2847 } | 2745 } |
| 2848 | 2746 |
| 2849 | 2747 |
| 2850 void HGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 2748 void HGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
| 2851 BAILOUT("TryFinallyStatement"); | 2749 BAILOUT("TryFinallyStatement"); |
| 2852 } | 2750 } |
| 2853 | 2751 |
| 2854 | 2752 |
| 2855 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | 2753 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 2856 BAILOUT("DebuggerStatement"); | 2754 BAILOUT("DebuggerStatement"); |
| 2857 } | 2755 } |
| 2858 | 2756 |
| 2859 | 2757 |
| 2860 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { | 2758 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 2861 Handle<SharedFunctionInfo> shared_info = | 2759 Handle<SharedFunctionInfo> shared_info = |
| 2862 Compiler::BuildFunctionInfo(expr, graph_->info()->script()); | 2760 Compiler::BuildFunctionInfo(expr, info()->script()); |
| 2863 CHECK_BAILOUT; | 2761 CHECK_BAILOUT; |
| 2864 HFunctionLiteral* instr = | 2762 HFunctionLiteral* instr = |
| 2865 new HFunctionLiteral(shared_info, expr->pretenure()); | 2763 new HFunctionLiteral(shared_info, expr->pretenure()); |
| 2866 ast_context()->ReturnInstruction(instr, expr->id()); | 2764 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2867 } | 2765 } |
| 2868 | 2766 |
| 2869 | 2767 |
| 2870 void HGraphBuilder::VisitSharedFunctionInfoLiteral( | 2768 void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
| 2871 SharedFunctionInfoLiteral* expr) { | 2769 SharedFunctionInfoLiteral* expr) { |
| 2872 BAILOUT("SharedFunctionInfoLiteral"); | 2770 BAILOUT("SharedFunctionInfoLiteral"); |
| 2873 } | 2771 } |
| 2874 | 2772 |
| 2875 | 2773 |
| 2876 void HGraphBuilder::VisitConditional(Conditional* expr) { | 2774 void HGraphBuilder::VisitConditional(Conditional* expr) { |
| 2877 HSubgraph* then_graph = CreateEmptySubgraph(); | 2775 HBasicBlock* cond_true = graph()->CreateBasicBlock(); |
| 2878 HSubgraph* else_graph = CreateEmptySubgraph(); | 2776 HBasicBlock* cond_false = graph()->CreateBasicBlock(); |
| 2879 VISIT_FOR_CONTROL(expr->condition(), | 2777 VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false); |
| 2880 then_graph->entry_block(), | 2778 cond_true->SetJoinId(expr->ThenId()); |
| 2881 else_graph->entry_block()); | 2779 cond_false->SetJoinId(expr->ElseId()); |
| 2882 | 2780 |
| 2883 then_graph->entry_block()->SetJoinId(expr->ThenId()); | 2781 // Visit the true and false subexpressions in the same AST context as the |
| 2884 ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); | 2782 // whole expression. |
| 2783 set_current_block(cond_true); |
| 2784 Visit(expr->then_expression()); |
| 2785 CHECK_BAILOUT; |
| 2786 HBasicBlock* other = current_block(); |
| 2885 | 2787 |
| 2886 else_graph->entry_block()->SetJoinId(expr->ElseId()); | 2788 set_current_block(cond_false); |
| 2887 ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); | 2789 Visit(expr->else_expression()); |
| 2790 CHECK_BAILOUT; |
| 2888 | 2791 |
| 2889 current_subgraph_->AppendJoin(then_graph, else_graph, expr); | 2792 if (!ast_context()->IsTest()) { |
| 2890 ast_context()->ReturnValue(Pop()); | 2793 HBasicBlock* join = CreateJoin(other, current_block(), expr->id()); |
| 2794 set_current_block(join); |
| 2795 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 2796 } |
| 2891 } | 2797 } |
| 2892 | 2798 |
| 2893 | 2799 |
| 2894 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, | 2800 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
| 2895 LookupResult* lookup, | 2801 LookupResult* lookup, |
| 2896 bool is_store) { | 2802 bool is_store) { |
| 2897 if (var->is_this()) { | 2803 if (var->is_this()) { |
| 2898 BAILOUT("global this reference"); | 2804 BAILOUT("global this reference"); |
| 2899 } | 2805 } |
| 2900 if (!graph()->info()->has_global_object()) { | 2806 if (!info()->has_global_object()) { |
| 2901 BAILOUT("no global object to optimize VariableProxy"); | 2807 BAILOUT("no global object to optimize VariableProxy"); |
| 2902 } | 2808 } |
| 2903 Handle<GlobalObject> global(graph()->info()->global_object()); | 2809 Handle<GlobalObject> global(info()->global_object()); |
| 2904 global->Lookup(*var->name(), lookup); | 2810 global->Lookup(*var->name(), lookup); |
| 2905 if (!lookup->IsProperty()) { | 2811 if (!lookup->IsProperty()) { |
| 2906 BAILOUT("global variable cell not yet introduced"); | 2812 BAILOUT("global variable cell not yet introduced"); |
| 2907 } | 2813 } |
| 2908 if (lookup->type() != NORMAL) { | 2814 if (lookup->type() != NORMAL) { |
| 2909 BAILOUT("global variable has accessors"); | 2815 BAILOUT("global variable has accessors"); |
| 2910 } | 2816 } |
| 2911 if (is_store && lookup->IsReadOnly()) { | 2817 if (is_store && lookup->IsReadOnly()) { |
| 2912 BAILOUT("read-only global variable"); | 2818 BAILOUT("read-only global variable"); |
| 2913 } | 2819 } |
| 2914 if (lookup->holder() != *global) { | 2820 if (lookup->holder() != *global) { |
| 2915 BAILOUT("global property on prototype of global object"); | 2821 BAILOUT("global property on prototype of global object"); |
| 2916 } | 2822 } |
| 2917 } | 2823 } |
| 2918 | 2824 |
| 2919 | 2825 |
| 2920 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { | 2826 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { |
| 2921 ASSERT(var->IsContextSlot()); | 2827 ASSERT(var->IsContextSlot()); |
| 2922 HInstruction* context = new HContext; | 2828 HInstruction* context = new HContext; |
| 2923 AddInstruction(context); | 2829 AddInstruction(context); |
| 2924 int length = graph()->info()->scope()->ContextChainLength(var->scope()); | 2830 int length = info()->scope()->ContextChainLength(var->scope()); |
| 2925 while (length-- > 0) { | 2831 while (length-- > 0) { |
| 2926 context = new HOuterContext(context); | 2832 context = new HOuterContext(context); |
| 2927 AddInstruction(context); | 2833 AddInstruction(context); |
| 2928 } | 2834 } |
| 2929 return context; | 2835 return context; |
| 2930 } | 2836 } |
| 2931 | 2837 |
| 2932 | 2838 |
| 2933 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 2839 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2934 Variable* variable = expr->AsVariable(); | 2840 Variable* variable = expr->AsVariable(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2945 } | 2851 } |
| 2946 HValue* context = BuildContextChainWalk(variable); | 2852 HValue* context = BuildContextChainWalk(variable); |
| 2947 int index = variable->AsSlot()->index(); | 2853 int index = variable->AsSlot()->index(); |
| 2948 HLoadContextSlot* instr = new HLoadContextSlot(context, index); | 2854 HLoadContextSlot* instr = new HLoadContextSlot(context, index); |
| 2949 ast_context()->ReturnInstruction(instr, expr->id()); | 2855 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2950 } else if (variable->is_global()) { | 2856 } else if (variable->is_global()) { |
| 2951 LookupResult lookup; | 2857 LookupResult lookup; |
| 2952 LookupGlobalPropertyCell(variable, &lookup, false); | 2858 LookupGlobalPropertyCell(variable, &lookup, false); |
| 2953 CHECK_BAILOUT; | 2859 CHECK_BAILOUT; |
| 2954 | 2860 |
| 2955 Handle<GlobalObject> global(graph()->info()->global_object()); | 2861 Handle<GlobalObject> global(info()->global_object()); |
| 2956 // TODO(3039103): Handle global property load through an IC call when access | 2862 // TODO(3039103): Handle global property load through an IC call when access |
| 2957 // checks are enabled. | 2863 // checks are enabled. |
| 2958 if (global->IsAccessCheckNeeded()) { | 2864 if (global->IsAccessCheckNeeded()) { |
| 2959 BAILOUT("global object requires access check"); | 2865 BAILOUT("global object requires access check"); |
| 2960 } | 2866 } |
| 2961 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 2867 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 2962 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 2868 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 2963 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); | 2869 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); |
| 2964 ast_context()->ReturnInstruction(instr, expr->id()); | 2870 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2965 } else { | 2871 } else { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3071 } | 2977 } |
| 3072 ast_context()->ReturnValue(Pop()); | 2978 ast_context()->ReturnValue(Pop()); |
| 3073 } | 2979 } |
| 3074 | 2980 |
| 3075 | 2981 |
| 3076 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 2982 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 3077 BAILOUT("CatchExtensionObject"); | 2983 BAILOUT("CatchExtensionObject"); |
| 3078 } | 2984 } |
| 3079 | 2985 |
| 3080 | 2986 |
| 3081 HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver, | |
| 3082 ZoneMapList* maps, | |
| 3083 ZoneList<HSubgraph*>* body_graphs, | |
| 3084 HSubgraph* default_graph, | |
| 3085 int join_id) { | |
| 3086 ASSERT(maps->length() == body_graphs->length()); | |
| 3087 HBasicBlock* join_block = graph()->CreateBasicBlock(); | |
| 3088 AddInstruction(new HCheckNonSmi(receiver)); | |
| 3089 | |
| 3090 for (int i = 0; i < maps->length(); ++i) { | |
| 3091 // Build the branches, connect all the target subgraphs to the join | |
| 3092 // block. Use the default as a target of the last branch. | |
| 3093 HSubgraph* if_true = body_graphs->at(i); | |
| 3094 HSubgraph* if_false = (i == maps->length() - 1) | |
| 3095 ? default_graph | |
| 3096 : CreateBranchSubgraph(environment()); | |
| 3097 HCompareMap* compare = | |
| 3098 new HCompareMap(receiver, | |
| 3099 maps->at(i), | |
| 3100 if_true->entry_block(), | |
| 3101 if_false->entry_block()); | |
| 3102 subgraph()->exit_block()->Finish(compare); | |
| 3103 | |
| 3104 if (if_true->HasExit()) { | |
| 3105 // In an effect context the value of the type switch is not needed. | |
| 3106 // There is no need to merge it at the join block only to discard it. | |
| 3107 if (ast_context()->IsEffect()) { | |
| 3108 if_true->exit_block()->last_environment()->Drop(1); | |
| 3109 } | |
| 3110 if_true->exit_block()->Goto(join_block); | |
| 3111 } | |
| 3112 | |
| 3113 subgraph()->set_exit_block(if_false->exit_block()); | |
| 3114 } | |
| 3115 | |
| 3116 // Connect the default if necessary. | |
| 3117 if (subgraph()->HasExit()) { | |
| 3118 if (ast_context()->IsEffect()) { | |
| 3119 environment()->Drop(1); | |
| 3120 } | |
| 3121 subgraph()->exit_block()->Goto(join_block); | |
| 3122 } | |
| 3123 | |
| 3124 if (join_block->predecessors()->is_empty()) return NULL; | |
| 3125 join_block->SetJoinId(join_id); | |
| 3126 return join_block; | |
| 3127 } | |
| 3128 | |
| 3129 | |
| 3130 // Sets the lookup result and returns true if the store can be inlined. | 2987 // Sets the lookup result and returns true if the store can be inlined. |
| 3131 static bool ComputeStoredField(Handle<Map> type, | 2988 static bool ComputeStoredField(Handle<Map> type, |
| 3132 Handle<String> name, | 2989 Handle<String> name, |
| 3133 LookupResult* lookup) { | 2990 LookupResult* lookup) { |
| 3134 type->LookupInDescriptors(NULL, *name, lookup); | 2991 type->LookupInDescriptors(NULL, *name, lookup); |
| 3135 if (!lookup->IsPropertyOrTransition()) return false; | 2992 if (!lookup->IsPropertyOrTransition()) return false; |
| 3136 if (lookup->type() == FIELD) return true; | 2993 if (lookup->type() == FIELD) return true; |
| 3137 return (lookup->type() == MAP_TRANSITION) && | 2994 return (lookup->type() == MAP_TRANSITION) && |
| 3138 (type->unused_property_fields() > 0); | 2995 (type->unused_property_fields() > 0); |
| 3139 } | 2996 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3215 true) // Needs smi and map check. | 3072 true) // Needs smi and map check. |
| 3216 : BuildStoreNamedGeneric(object, name, value); | 3073 : BuildStoreNamedGeneric(object, name, value); |
| 3217 } | 3074 } |
| 3218 | 3075 |
| 3219 | 3076 |
| 3220 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, | 3077 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
| 3221 HValue* object, | 3078 HValue* object, |
| 3222 HValue* value, | 3079 HValue* value, |
| 3223 ZoneMapList* types, | 3080 ZoneMapList* types, |
| 3224 Handle<String> name) { | 3081 Handle<String> name) { |
| 3225 int number_of_types = Min(types->length(), kMaxStorePolymorphism); | 3082 // TODO(ager): We should recognize when the prototype chains for different |
| 3226 ZoneMapList maps(number_of_types); | 3083 // maps are identical. In that case we can avoid repeatedly generating the |
| 3227 ZoneList<HSubgraph*> subgraphs(number_of_types); | 3084 // same prototype map checks. |
| 3228 bool needs_generic = (types->length() > kMaxStorePolymorphism); | 3085 int count = 0; |
| 3229 | 3086 HBasicBlock* join = NULL; |
| 3230 // Build subgraphs for each of the specific maps. | 3087 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
| 3231 // | |
| 3232 // TODO(ager): We should recognize when the prototype chains for | |
| 3233 // different maps are identical. In that case we can avoid | |
| 3234 // repeatedly generating the same prototype map checks. | |
| 3235 for (int i = 0; i < number_of_types; ++i) { | |
| 3236 Handle<Map> map = types->at(i); | 3088 Handle<Map> map = types->at(i); |
| 3237 LookupResult lookup; | 3089 LookupResult lookup; |
| 3238 if (ComputeStoredField(map, name, &lookup)) { | 3090 if (ComputeStoredField(map, name, &lookup)) { |
| 3239 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3091 if (count == 0) { |
| 3240 SubgraphScope scope(this, subgraph); | 3092 AddInstruction(new HCheckNonSmi(object)); // Only needed once. |
| 3093 join = graph()->CreateBasicBlock(); |
| 3094 } |
| 3095 ++count; |
| 3096 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3097 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3098 HCompareMap* compare = new HCompareMap(object, map, if_true, if_false); |
| 3099 current_block()->Finish(compare); |
| 3100 |
| 3101 set_current_block(if_true); |
| 3241 HInstruction* instr = | 3102 HInstruction* instr = |
| 3242 BuildStoreNamedField(object, name, value, map, &lookup, false); | 3103 BuildStoreNamedField(object, name, value, map, &lookup, false); |
| 3243 Push(value); | |
| 3244 instr->set_position(expr->position()); | 3104 instr->set_position(expr->position()); |
| 3105 // Goto will add the HSimulate for the store. |
| 3245 AddInstruction(instr); | 3106 AddInstruction(instr); |
| 3246 maps.Add(map); | 3107 if (!ast_context()->IsEffect()) Push(value); |
| 3247 subgraphs.Add(subgraph); | 3108 current_block()->Goto(join); |
| 3248 } else { | 3109 |
| 3249 needs_generic = true; | 3110 set_current_block(if_false); |
| 3250 } | 3111 } |
| 3251 } | 3112 } |
| 3252 | 3113 |
| 3253 // If none of the properties were named fields we generate a | 3114 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3254 // generic store. | 3115 // know about and do not want to handle ones we've never seen. Otherwise |
| 3255 if (maps.length() == 0) { | 3116 // use a generic IC. |
| 3117 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3118 current_block()->FinishExit(new HDeoptimize); |
| 3119 } else { |
| 3256 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3120 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3257 Push(value); | |
| 3258 instr->set_position(expr->position()); | 3121 instr->set_position(expr->position()); |
| 3259 AddInstruction(instr); | 3122 AddInstruction(instr); |
| 3260 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3123 |
| 3261 ast_context()->ReturnValue(Pop()); | 3124 if (join != NULL) { |
| 3262 } else { | 3125 if (!ast_context()->IsEffect()) Push(value); |
| 3263 // Build subgraph for generic store through IC. | 3126 current_block()->Goto(join); |
| 3264 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | 3127 } else { |
| 3265 { SubgraphScope scope(this, default_graph); | 3128 // The HSimulate for the store should not see the stored value in |
| 3266 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3129 // effect contexts (it is not materialized at expr->id() in the |
| 3267 default_graph->FinishExit(new HDeoptimize()); | 3130 // unoptimized code). |
| 3268 } else { | 3131 if (instr->HasSideEffects()) { |
| 3269 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3132 if (ast_context()->IsEffect()) { |
| 3270 Push(value); | 3133 AddSimulate(expr->id()); |
| 3271 instr->set_position(expr->position()); | 3134 } else { |
| 3272 AddInstruction(instr); | 3135 Push(value); |
| 3136 AddSimulate(expr->id()); |
| 3137 Drop(1); |
| 3138 } |
| 3273 } | 3139 } |
| 3274 } | 3140 ast_context()->ReturnValue(value); |
| 3275 | 3141 return; |
| 3276 HBasicBlock* new_exit_block = | |
| 3277 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); | |
| 3278 subgraph()->set_exit_block(new_exit_block); | |
| 3279 // In an effect context, we did not materialized the value in the | |
| 3280 // predecessor environments so there's no need to handle it here. | |
| 3281 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { | |
| 3282 ast_context()->ReturnValue(Pop()); | |
| 3283 } | 3142 } |
| 3284 } | 3143 } |
| 3144 |
| 3145 ASSERT(join != NULL); |
| 3146 join->SetJoinId(expr->id()); |
| 3147 set_current_block(join); |
| 3148 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 3285 } | 3149 } |
| 3286 | 3150 |
| 3287 | 3151 |
| 3288 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3152 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3289 Property* prop = expr->target()->AsProperty(); | 3153 Property* prop = expr->target()->AsProperty(); |
| 3290 ASSERT(prop != NULL); | 3154 ASSERT(prop != NULL); |
| 3291 expr->RecordTypeFeedback(oracle()); | 3155 expr->RecordTypeFeedback(oracle()); |
| 3292 VISIT_FOR_VALUE(prop->obj()); | 3156 VISIT_FOR_VALUE(prop->obj()); |
| 3293 | 3157 |
| 3294 HValue* value = NULL; | 3158 HValue* value = NULL; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3319 } | 3183 } |
| 3320 | 3184 |
| 3321 } else { | 3185 } else { |
| 3322 // Keyed store. | 3186 // Keyed store. |
| 3323 VISIT_FOR_VALUE(prop->key()); | 3187 VISIT_FOR_VALUE(prop->key()); |
| 3324 VISIT_FOR_VALUE(expr->value()); | 3188 VISIT_FOR_VALUE(expr->value()); |
| 3325 value = Pop(); | 3189 value = Pop(); |
| 3326 HValue* key = Pop(); | 3190 HValue* key = Pop(); |
| 3327 HValue* object = Pop(); | 3191 HValue* object = Pop(); |
| 3328 | 3192 |
| 3329 bool is_fast_elements = expr->IsMonomorphic() && | 3193 if (expr->IsMonomorphic()) { |
| 3330 expr->GetMonomorphicReceiverType()->has_fast_elements(); | 3194 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); |
| 3331 | 3195 // An object has either fast elements or external array elements, but |
| 3332 instr = is_fast_elements | 3196 // never both. Pixel array maps that are assigned to pixel array elements |
| 3333 ? BuildStoreKeyedFastElement(object, key, value, expr) | 3197 // are always created with the fast elements flag cleared. |
| 3334 : BuildStoreKeyedGeneric(object, key, value); | 3198 if (receiver_type->has_external_array_elements()) { |
| 3199 if (expr->GetExternalArrayType() == kExternalPixelArray) { |
| 3200 instr = BuildStoreKeyedPixelArrayElement(object, key, value, expr); |
| 3201 } |
| 3202 } else if (receiver_type->has_fast_elements()) { |
| 3203 instr = BuildStoreKeyedFastElement(object, key, value, expr); |
| 3204 } |
| 3205 } |
| 3206 if (instr == NULL) { |
| 3207 instr = BuildStoreKeyedGeneric(object, key, value); |
| 3208 } |
| 3335 } | 3209 } |
| 3336 | 3210 |
| 3337 Push(value); | 3211 Push(value); |
| 3338 instr->set_position(expr->position()); | 3212 instr->set_position(expr->position()); |
| 3339 AddInstruction(instr); | 3213 AddInstruction(instr); |
| 3340 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3214 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3341 ast_context()->ReturnValue(Pop()); | 3215 ast_context()->ReturnValue(Pop()); |
| 3342 } | 3216 } |
| 3343 | 3217 |
| 3344 | 3218 |
| 3345 // Because not every expression has a position and there is not common | 3219 // Because not every expression has a position and there is not common |
| 3346 // superclass of Assignment and CountOperation, we cannot just pass the | 3220 // superclass of Assignment and CountOperation, we cannot just pass the |
| 3347 // owning expression instead of position and ast_id separately. | 3221 // owning expression instead of position and ast_id separately. |
| 3348 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, | 3222 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
| 3349 HValue* value, | 3223 HValue* value, |
| 3350 int position, | 3224 int position, |
| 3351 int ast_id) { | 3225 int ast_id) { |
| 3352 LookupResult lookup; | 3226 LookupResult lookup; |
| 3353 LookupGlobalPropertyCell(var, &lookup, true); | 3227 LookupGlobalPropertyCell(var, &lookup, true); |
| 3354 CHECK_BAILOUT; | 3228 CHECK_BAILOUT; |
| 3355 | 3229 |
| 3356 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3230 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 3357 Handle<GlobalObject> global(graph()->info()->global_object()); | 3231 Handle<GlobalObject> global(info()->global_object()); |
| 3358 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3232 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3359 HInstruction* instr = new HStoreGlobal(value, cell, check_hole); | 3233 HInstruction* instr = new HStoreGlobal(value, cell, check_hole); |
| 3360 instr->set_position(position); | 3234 instr->set_position(position); |
| 3361 AddInstruction(instr); | 3235 AddInstruction(instr); |
| 3362 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3236 if (instr->HasSideEffects()) AddSimulate(ast_id); |
| 3363 } | 3237 } |
| 3364 | 3238 |
| 3365 | 3239 |
| 3366 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3240 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
| 3367 Expression* target = expr->target(); | 3241 Expression* target = expr->target(); |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3536 // assignments, count operations, or for-in. Consequently throw can | 3410 // assignments, count operations, or for-in. Consequently throw can |
| 3537 // currently only occur in an effect context. | 3411 // currently only occur in an effect context. |
| 3538 ASSERT(ast_context()->IsEffect()); | 3412 ASSERT(ast_context()->IsEffect()); |
| 3539 VISIT_FOR_VALUE(expr->exception()); | 3413 VISIT_FOR_VALUE(expr->exception()); |
| 3540 | 3414 |
| 3541 HValue* value = environment()->Pop(); | 3415 HValue* value = environment()->Pop(); |
| 3542 HThrow* instr = new HThrow(value); | 3416 HThrow* instr = new HThrow(value); |
| 3543 instr->set_position(expr->position()); | 3417 instr->set_position(expr->position()); |
| 3544 AddInstruction(instr); | 3418 AddInstruction(instr); |
| 3545 AddSimulate(expr->id()); | 3419 AddSimulate(expr->id()); |
| 3546 current_subgraph_->FinishExit(new HAbnormalExit); | 3420 current_block()->FinishExit(new HAbnormalExit); |
| 3421 set_current_block(NULL); |
| 3547 } | 3422 } |
| 3548 | 3423 |
| 3549 | 3424 |
| 3550 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3425 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
| 3551 HValue* object, | 3426 HValue* object, |
| 3552 ZoneMapList* types, | 3427 ZoneMapList* types, |
| 3553 Handle<String> name) { | 3428 Handle<String> name) { |
| 3554 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); | 3429 // TODO(ager): We should recognize when the prototype chains for different |
| 3555 ZoneMapList maps(number_of_types); | 3430 // maps are identical. In that case we can avoid repeatedly generating the |
| 3556 ZoneList<HSubgraph*> subgraphs(number_of_types); | 3431 // same prototype map checks. |
| 3557 bool needs_generic = (types->length() > kMaxLoadPolymorphism); | 3432 int count = 0; |
| 3558 | 3433 HBasicBlock* join = NULL; |
| 3559 // Build subgraphs for each of the specific maps. | 3434 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 3560 // | |
| 3561 // TODO(ager): We should recognize when the prototype chains for | |
| 3562 // different maps are identical. In that case we can avoid | |
| 3563 // repeatedly generating the same prototype map checks. | |
| 3564 for (int i = 0; i < number_of_types; ++i) { | |
| 3565 Handle<Map> map = types->at(i); | 3435 Handle<Map> map = types->at(i); |
| 3566 LookupResult lookup; | 3436 LookupResult lookup; |
| 3567 map->LookupInDescriptors(NULL, *name, &lookup); | 3437 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3568 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3438 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3569 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3439 if (count == 0) { |
| 3570 SubgraphScope scope(this, subgraph); | 3440 AddInstruction(new HCheckNonSmi(object)); // Only needed once. |
| 3441 join = graph()->CreateBasicBlock(); |
| 3442 } |
| 3443 ++count; |
| 3444 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3445 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3446 HCompareMap* compare = new HCompareMap(object, map, if_true, if_false); |
| 3447 current_block()->Finish(compare); |
| 3448 |
| 3449 set_current_block(if_true); |
| 3571 HLoadNamedField* instr = | 3450 HLoadNamedField* instr = |
| 3572 BuildLoadNamedField(object, expr, map, &lookup, false); | 3451 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3573 instr->set_position(expr->position()); | 3452 instr->set_position(expr->position()); |
| 3574 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. | 3453 instr->ClearFlag(HValue::kUseGVN); |
| 3575 PushAndAdd(instr); | 3454 AddInstruction(instr); |
| 3576 maps.Add(map); | 3455 if (!ast_context()->IsEffect()) Push(instr); |
| 3577 subgraphs.Add(subgraph); | 3456 current_block()->Goto(join); |
| 3578 } else { | 3457 |
| 3579 needs_generic = true; | 3458 set_current_block(if_false); |
| 3580 } | 3459 } |
| 3581 } | 3460 } |
| 3582 | 3461 |
| 3583 // If none of the properties were named fields we generate a | 3462 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3584 // generic load. | 3463 // know about and do not want to handle ones we've never seen. Otherwise |
| 3585 if (maps.length() == 0) { | 3464 // use a generic IC. |
| 3465 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3466 current_block()->FinishExit(new HDeoptimize); |
| 3467 } else { |
| 3586 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3468 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3587 instr->set_position(expr->position()); | 3469 instr->set_position(expr->position()); |
| 3588 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 3589 } else { | |
| 3590 // Build subgraph for generic load through IC. | |
| 3591 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | |
| 3592 { SubgraphScope scope(this, default_graph); | |
| 3593 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3594 default_graph->FinishExit(new HDeoptimize()); | |
| 3595 } else { | |
| 3596 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | |
| 3597 instr->set_position(expr->position()); | |
| 3598 PushAndAdd(instr); | |
| 3599 } | |
| 3600 } | |
| 3601 | 3470 |
| 3602 HBasicBlock* new_exit_block = | 3471 if (join != NULL) { |
| 3603 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); | 3472 AddInstruction(instr); |
| 3604 subgraph()->set_exit_block(new_exit_block); | 3473 if (!ast_context()->IsEffect()) Push(instr); |
| 3605 // In an effect context, we did not materialized the value in the | 3474 current_block()->Goto(join); |
| 3606 // predecessor environments so there's no need to handle it here. | 3475 } else { |
| 3607 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { | 3476 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3608 ast_context()->ReturnValue(Pop()); | 3477 return; |
| 3609 } | 3478 } |
| 3610 } | 3479 } |
| 3480 |
| 3481 ASSERT(join != NULL); |
| 3482 join->SetJoinId(expr->id()); |
| 3483 set_current_block(join); |
| 3484 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 3611 } | 3485 } |
| 3612 | 3486 |
| 3613 | 3487 |
| 3614 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3488 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3615 Property* expr, | 3489 Property* expr, |
| 3616 Handle<Map> type, | 3490 Handle<Map> type, |
| 3617 LookupResult* lookup, | 3491 LookupResult* lookup, |
| 3618 bool smi_and_map_check) { | 3492 bool smi_and_map_check) { |
| 3619 if (smi_and_map_check) { | 3493 if (smi_and_map_check) { |
| 3620 AddInstruction(new HCheckNonSmi(object)); | 3494 AddInstruction(new HCheckNonSmi(object)); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3700 } | 3574 } |
| 3701 | 3575 |
| 3702 | 3576 |
| 3703 HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object, | 3577 HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object, |
| 3704 HValue* key, | 3578 HValue* key, |
| 3705 Property* expr) { | 3579 Property* expr) { |
| 3706 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3580 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); |
| 3707 AddInstruction(new HCheckNonSmi(object)); | 3581 AddInstruction(new HCheckNonSmi(object)); |
| 3708 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3582 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3709 ASSERT(!map->has_fast_elements()); | 3583 ASSERT(!map->has_fast_elements()); |
| 3710 ASSERT(map->has_pixel_array_elements()); | 3584 ASSERT(map->has_external_array_elements()); |
| 3711 AddInstruction(new HCheckMap(object, map)); | 3585 AddInstruction(new HCheckMap(object, map)); |
| 3712 HLoadElements* elements = new HLoadElements(object); | 3586 HLoadElements* elements = new HLoadElements(object); |
| 3713 AddInstruction(elements); | 3587 AddInstruction(elements); |
| 3714 HInstruction* length = AddInstruction(new HPixelArrayLength(elements)); | 3588 HInstruction* length = new HExternalArrayLength(elements); |
| 3589 AddInstruction(length); |
| 3715 AddInstruction(new HBoundsCheck(key, length)); | 3590 AddInstruction(new HBoundsCheck(key, length)); |
| 3716 HLoadPixelArrayExternalPointer* external_elements = | 3591 HLoadExternalArrayPointer* external_elements = |
| 3717 new HLoadPixelArrayExternalPointer(elements); | 3592 new HLoadExternalArrayPointer(elements); |
| 3718 AddInstruction(external_elements); | 3593 AddInstruction(external_elements); |
| 3719 HLoadPixelArrayElement* pixel_array_value = | 3594 HLoadPixelArrayElement* pixel_array_value = |
| 3720 new HLoadPixelArrayElement(external_elements, key); | 3595 new HLoadPixelArrayElement(external_elements, key); |
| 3721 return pixel_array_value; | 3596 return pixel_array_value; |
| 3722 } | 3597 } |
| 3723 | 3598 |
| 3724 | 3599 |
| 3725 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 3600 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
| 3726 HValue* key, | 3601 HValue* key, |
| 3727 HValue* value) { | 3602 HValue* value) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3747 if (is_array) { | 3622 if (is_array) { |
| 3748 length = AddInstruction(new HJSArrayLength(object)); | 3623 length = AddInstruction(new HJSArrayLength(object)); |
| 3749 } else { | 3624 } else { |
| 3750 length = AddInstruction(new HFixedArrayLength(elements)); | 3625 length = AddInstruction(new HFixedArrayLength(elements)); |
| 3751 } | 3626 } |
| 3752 AddInstruction(new HBoundsCheck(key, length)); | 3627 AddInstruction(new HBoundsCheck(key, length)); |
| 3753 return new HStoreKeyedFastElement(elements, key, val); | 3628 return new HStoreKeyedFastElement(elements, key, val); |
| 3754 } | 3629 } |
| 3755 | 3630 |
| 3756 | 3631 |
| 3632 HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement( |
| 3633 HValue* object, |
| 3634 HValue* key, |
| 3635 HValue* val, |
| 3636 Expression* expr) { |
| 3637 ASSERT(expr->IsMonomorphic()); |
| 3638 AddInstruction(new HCheckNonSmi(object)); |
| 3639 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3640 ASSERT(!map->has_fast_elements()); |
| 3641 ASSERT(map->has_external_array_elements()); |
| 3642 AddInstruction(new HCheckMap(object, map)); |
| 3643 HLoadElements* elements = new HLoadElements(object); |
| 3644 AddInstruction(elements); |
| 3645 HInstruction* length = AddInstruction(new HExternalArrayLength(elements)); |
| 3646 AddInstruction(new HBoundsCheck(key, length)); |
| 3647 HLoadExternalArrayPointer* external_elements = |
| 3648 new HLoadExternalArrayPointer(elements); |
| 3649 AddInstruction(external_elements); |
| 3650 return new HStorePixelArrayElement(external_elements, key, val); |
| 3651 } |
| 3652 |
| 3653 |
| 3757 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 3654 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
| 3758 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 3655 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
| 3759 if (proxy == NULL) return false; | 3656 if (proxy == NULL) return false; |
| 3760 if (!proxy->var()->IsStackAllocated()) return false; | 3657 if (!proxy->var()->IsStackAllocated()) return false; |
| 3761 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 3658 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
| 3762 return false; | 3659 return false; |
| 3763 } | 3660 } |
| 3764 | 3661 |
| 3765 HInstruction* result = NULL; | 3662 HInstruction* result = NULL; |
| 3766 if (expr->key()->IsPropertyName()) { | 3663 if (expr->key()->IsPropertyName()) { |
| 3767 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 3664 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3768 if (!name->IsEqualTo(CStrVector("length"))) return false; | 3665 if (!name->IsEqualTo(CStrVector("length"))) return false; |
| 3769 HInstruction* elements = AddInstruction(new HArgumentsElements); | 3666 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 3770 result = new HArgumentsLength(elements); | 3667 result = new HArgumentsLength(elements); |
| 3771 } else { | 3668 } else { |
| 3669 Push(graph()->GetArgumentsObject()); |
| 3772 VisitForValue(expr->key()); | 3670 VisitForValue(expr->key()); |
| 3773 if (HasStackOverflow()) return false; | 3671 if (HasStackOverflow()) return false; |
| 3774 HValue* key = Pop(); | 3672 HValue* key = Pop(); |
| 3673 Drop(1); // Arguments object. |
| 3775 HInstruction* elements = AddInstruction(new HArgumentsElements); | 3674 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 3776 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 3675 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 3777 AddInstruction(new HBoundsCheck(key, length)); | 3676 AddInstruction(new HBoundsCheck(key, length)); |
| 3778 result = new HAccessArgumentsAt(elements, length, key); | 3677 result = new HAccessArgumentsAt(elements, length, key); |
| 3779 } | 3678 } |
| 3780 ast_context()->ReturnInstruction(result, expr->id()); | 3679 ast_context()->ReturnInstruction(result, expr->id()); |
| 3781 return true; | 3680 return true; |
| 3782 } | 3681 } |
| 3783 | 3682 |
| 3784 | 3683 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3797 AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); | 3696 AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); |
| 3798 instr = new HJSArrayLength(array); | 3697 instr = new HJSArrayLength(array); |
| 3799 | 3698 |
| 3800 } else if (expr->IsStringLength()) { | 3699 } else if (expr->IsStringLength()) { |
| 3801 HValue* string = Pop(); | 3700 HValue* string = Pop(); |
| 3802 AddInstruction(new HCheckNonSmi(string)); | 3701 AddInstruction(new HCheckNonSmi(string)); |
| 3803 AddInstruction(new HCheckInstanceType(string, | 3702 AddInstruction(new HCheckInstanceType(string, |
| 3804 FIRST_STRING_TYPE, | 3703 FIRST_STRING_TYPE, |
| 3805 LAST_STRING_TYPE)); | 3704 LAST_STRING_TYPE)); |
| 3806 instr = new HStringLength(string); | 3705 instr = new HStringLength(string); |
| 3706 } else if (expr->IsStringAccess()) { |
| 3707 VISIT_FOR_VALUE(expr->key()); |
| 3708 HValue* index = Pop(); |
| 3709 HValue* string = Pop(); |
| 3710 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); |
| 3711 AddInstruction(char_code); |
| 3712 instr = new HStringCharFromCode(char_code); |
| 3807 | 3713 |
| 3808 } else if (expr->IsFunctionPrototype()) { | 3714 } else if (expr->IsFunctionPrototype()) { |
| 3809 HValue* function = Pop(); | 3715 HValue* function = Pop(); |
| 3810 AddInstruction(new HCheckNonSmi(function)); | 3716 AddInstruction(new HCheckNonSmi(function)); |
| 3811 instr = new HLoadFunctionPrototype(function); | 3717 instr = new HLoadFunctionPrototype(function); |
| 3812 | 3718 |
| 3813 } else if (expr->key()->IsPropertyName()) { | 3719 } else if (expr->key()->IsPropertyName()) { |
| 3814 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 3720 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3815 ZoneMapList* types = expr->GetReceiverTypes(); | 3721 ZoneMapList* types = expr->GetReceiverTypes(); |
| 3816 | 3722 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3829 VISIT_FOR_VALUE(expr->key()); | 3735 VISIT_FOR_VALUE(expr->key()); |
| 3830 | 3736 |
| 3831 HValue* key = Pop(); | 3737 HValue* key = Pop(); |
| 3832 HValue* obj = Pop(); | 3738 HValue* obj = Pop(); |
| 3833 | 3739 |
| 3834 if (expr->IsMonomorphic()) { | 3740 if (expr->IsMonomorphic()) { |
| 3835 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); | 3741 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); |
| 3836 // An object has either fast elements or pixel array elements, but never | 3742 // An object has either fast elements or pixel array elements, but never |
| 3837 // both. Pixel array maps that are assigned to pixel array elements are | 3743 // both. Pixel array maps that are assigned to pixel array elements are |
| 3838 // always created with the fast elements flag cleared. | 3744 // always created with the fast elements flag cleared. |
| 3839 if (receiver_type->has_pixel_array_elements()) { | 3745 if (receiver_type->has_external_array_elements()) { |
| 3840 instr = BuildLoadKeyedPixelArrayElement(obj, key, expr); | 3746 if (expr->GetExternalArrayType() == kExternalPixelArray) { |
| 3747 instr = BuildLoadKeyedPixelArrayElement(obj, key, expr); |
| 3748 } |
| 3841 } else if (receiver_type->has_fast_elements()) { | 3749 } else if (receiver_type->has_fast_elements()) { |
| 3842 instr = BuildLoadKeyedFastElement(obj, key, expr); | 3750 instr = BuildLoadKeyedFastElement(obj, key, expr); |
| 3843 } | 3751 } |
| 3844 } | 3752 } |
| 3845 if (instr == NULL) { | 3753 if (instr == NULL) { |
| 3846 instr = BuildLoadKeyedGeneric(obj, key); | 3754 instr = BuildLoadKeyedGeneric(obj, key); |
| 3847 } | 3755 } |
| 3848 } | 3756 } |
| 3849 instr->set_position(expr->position()); | 3757 instr->set_position(expr->position()); |
| 3850 ast_context()->ReturnInstruction(instr, expr->id()); | 3758 ast_context()->ReturnInstruction(instr, expr->id()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3867 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), | 3775 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), |
| 3868 expr->holder())); | 3776 expr->holder())); |
| 3869 } | 3777 } |
| 3870 } | 3778 } |
| 3871 | 3779 |
| 3872 | 3780 |
| 3873 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 3781 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
| 3874 HValue* receiver, | 3782 HValue* receiver, |
| 3875 ZoneMapList* types, | 3783 ZoneMapList* types, |
| 3876 Handle<String> name) { | 3784 Handle<String> name) { |
| 3877 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | |
| 3878 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | |
| 3879 ZoneMapList maps(number_of_types); | |
| 3880 ZoneList<HSubgraph*> subgraphs(number_of_types); | |
| 3881 bool needs_generic = (types->length() > kMaxCallPolymorphism); | |
| 3882 | |
| 3883 // Build subgraphs for each of the specific maps. | |
| 3884 // | |
| 3885 // TODO(ager): We should recognize when the prototype chains for different | 3785 // TODO(ager): We should recognize when the prototype chains for different |
| 3886 // maps are identical. In that case we can avoid repeatedly generating the | 3786 // maps are identical. In that case we can avoid repeatedly generating the |
| 3887 // same prototype map checks. | 3787 // same prototype map checks. |
| 3888 for (int i = 0; i < number_of_types; ++i) { | 3788 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 3789 int count = 0; |
| 3790 HBasicBlock* join = NULL; |
| 3791 for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) { |
| 3889 Handle<Map> map = types->at(i); | 3792 Handle<Map> map = types->at(i); |
| 3890 if (expr->ComputeTarget(map, name)) { | 3793 if (expr->ComputeTarget(map, name)) { |
| 3891 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3794 if (count == 0) { |
| 3892 SubgraphScope scope(this, subgraph); | 3795 AddInstruction(new HCheckNonSmi(receiver)); // Only needed once. |
| 3796 join = graph()->CreateBasicBlock(); |
| 3797 } |
| 3798 ++count; |
| 3799 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3800 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3801 HCompareMap* compare = new HCompareMap(receiver, map, if_true, if_false); |
| 3802 current_block()->Finish(compare); |
| 3803 |
| 3804 set_current_block(if_true); |
| 3893 AddCheckConstantFunction(expr, receiver, map, false); | 3805 AddCheckConstantFunction(expr, receiver, map, false); |
| 3894 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 3806 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 3895 PrintF("Trying to inline the polymorphic call to %s\n", | 3807 PrintF("Trying to inline the polymorphic call to %s\n", |
| 3896 *name->ToCString()); | 3808 *name->ToCString()); |
| 3897 } | 3809 } |
| 3898 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { | 3810 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { |
| 3899 // Check for bailout, as trying to inline might fail due to bailout | 3811 // Check for bailout, as trying to inline might fail due to bailout |
| 3900 // during hydrogen processing. | 3812 // during hydrogen processing. |
| 3901 CHECK_BAILOUT; | 3813 CHECK_BAILOUT; |
| 3902 HCall* call = new HCallConstantFunction(expr->target(), argument_count); | 3814 HCallConstantFunction* call = |
| 3815 new HCallConstantFunction(expr->target(), argument_count); |
| 3903 call->set_position(expr->position()); | 3816 call->set_position(expr->position()); |
| 3904 PreProcessCall(call); | 3817 PreProcessCall(call); |
| 3905 PushAndAdd(call); | 3818 AddInstruction(call); |
| 3819 if (!ast_context()->IsEffect()) Push(call); |
| 3906 } | 3820 } |
| 3907 maps.Add(map); | 3821 |
| 3908 subgraphs.Add(subgraph); | 3822 if (current_block() != NULL) current_block()->Goto(join); |
| 3909 } else { | 3823 set_current_block(if_false); |
| 3910 needs_generic = true; | |
| 3911 } | 3824 } |
| 3912 } | 3825 } |
| 3913 | 3826 |
| 3914 // If we couldn't compute the target for any of the maps just perform an | 3827 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3915 // IC call. | 3828 // know about and do not want to handle ones we've never seen. Otherwise |
| 3916 if (maps.length() == 0) { | 3829 // use a generic IC. |
| 3830 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3831 current_block()->FinishExit(new HDeoptimize); |
| 3832 } else { |
| 3917 HContext* context = new HContext; | 3833 HContext* context = new HContext; |
| 3918 AddInstruction(context); | 3834 AddInstruction(context); |
| 3919 HCall* call = new HCallNamed(context, name, argument_count); | 3835 HCallNamed* call = new HCallNamed(context, name, argument_count); |
| 3920 call->set_position(expr->position()); | 3836 call->set_position(expr->position()); |
| 3921 PreProcessCall(call); | 3837 PreProcessCall(call); |
| 3922 ast_context()->ReturnInstruction(call, expr->id()); | 3838 |
| 3923 } else { | 3839 if (join != NULL) { |
| 3924 // Build subgraph for generic call through IC. | 3840 AddInstruction(call); |
| 3925 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | 3841 if (!ast_context()->IsEffect()) Push(call); |
| 3926 { SubgraphScope scope(this, default_graph); | 3842 current_block()->Goto(join); |
| 3927 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3843 } else { |
| 3928 default_graph->FinishExit(new HDeoptimize()); | 3844 ast_context()->ReturnInstruction(call, expr->id()); |
| 3929 } else { | 3845 return; |
| 3930 HContext* context = new HContext; | |
| 3931 AddInstruction(context); | |
| 3932 HCall* call = new HCallNamed(context, name, argument_count); | |
| 3933 call->set_position(expr->position()); | |
| 3934 PreProcessCall(call); | |
| 3935 PushAndAdd(call); | |
| 3936 } | |
| 3937 } | 3846 } |
| 3847 } |
| 3938 | 3848 |
| 3939 HBasicBlock* new_exit_block = | 3849 // We assume that control flow is always live after an expression. So |
| 3940 BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id()); | 3850 // even without predecessors to the join block, we set it as the exit |
| 3941 subgraph()->set_exit_block(new_exit_block); | 3851 // block and continue by adding instructions there. |
| 3942 // In an effect context, we did not materialized the value in the | 3852 ASSERT(join != NULL); |
| 3943 // predecessor environments so there's no need to handle it here. | 3853 set_current_block(join); |
| 3944 if (new_exit_block != NULL && !ast_context()->IsEffect()) { | 3854 if (join->HasPredecessor()) { |
| 3945 ast_context()->ReturnValue(Pop()); | 3855 join->SetJoinId(expr->id()); |
| 3856 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 3857 } |
| 3858 } |
| 3859 |
| 3860 |
| 3861 void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) { |
| 3862 if (FLAG_trace_inlining) { |
| 3863 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); |
| 3864 SmartPointer<char> caller = |
| 3865 info()->function()->debug_name()->ToCString(); |
| 3866 if (reason == NULL) { |
| 3867 PrintF("Inlined %s called from %s.\n", *callee, *caller); |
| 3868 } else { |
| 3869 PrintF("Did not inline %s called from %s (%s).\n", |
| 3870 *callee, *caller, reason); |
| 3946 } | 3871 } |
| 3947 } | 3872 } |
| 3948 } | 3873 } |
| 3949 | 3874 |
| 3950 | |
| 3951 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | |
| 3952 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); | |
| 3953 SmartPointer<char> caller = | |
| 3954 graph()->info()->function()->debug_name()->ToCString(); | |
| 3955 if (result) { | |
| 3956 PrintF("Inlined %s called from %s.\n", *callee, *caller); | |
| 3957 } else { | |
| 3958 PrintF("Do not inline %s called from %s.\n", *callee, *caller); | |
| 3959 } | |
| 3960 } | |
| 3961 | |
| 3962 | 3875 |
| 3963 bool HGraphBuilder::TryInline(Call* expr) { | 3876 bool HGraphBuilder::TryInline(Call* expr) { |
| 3964 if (!FLAG_use_inlining) return false; | 3877 if (!FLAG_use_inlining) return false; |
| 3965 | 3878 |
| 3966 // Precondition: call is monomorphic and we have found a target with the | 3879 // Precondition: call is monomorphic and we have found a target with the |
| 3967 // appropriate arity. | 3880 // appropriate arity. |
| 3968 Handle<JSFunction> target = expr->target(); | 3881 Handle<JSFunction> target = expr->target(); |
| 3969 | 3882 |
| 3970 // Do a quick check on source code length to avoid parsing large | 3883 // Do a quick check on source code length to avoid parsing large |
| 3971 // inlining candidates. | 3884 // inlining candidates. |
| 3972 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { | 3885 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { |
| 3973 if (FLAG_trace_inlining) TraceInline(target, false); | 3886 TraceInline(target, "target text too big"); |
| 3974 return false; | 3887 return false; |
| 3975 } | 3888 } |
| 3976 | 3889 |
| 3977 // Target must be inlineable. | 3890 // Target must be inlineable. |
| 3978 if (!target->IsInlineable()) return false; | 3891 if (!target->IsInlineable()) { |
| 3892 TraceInline(target, "target not inlineable"); |
| 3893 return false; |
| 3894 } |
| 3979 | 3895 |
| 3980 // No context change required. | 3896 // No context change required. |
| 3981 CompilationInfo* outer_info = graph()->info(); | 3897 CompilationInfo* outer_info = info(); |
| 3982 if (target->context() != outer_info->closure()->context() || | 3898 if (target->context() != outer_info->closure()->context() || |
| 3983 outer_info->scope()->contains_with() || | 3899 outer_info->scope()->contains_with() || |
| 3984 outer_info->scope()->num_heap_slots() > 0) { | 3900 outer_info->scope()->num_heap_slots() > 0) { |
| 3901 TraceInline(target, "target requires context change"); |
| 3985 return false; | 3902 return false; |
| 3986 } | 3903 } |
| 3987 | 3904 |
| 3988 // Don't inline deeper than two calls. | 3905 // Don't inline deeper than two calls. |
| 3989 HEnvironment* env = environment(); | 3906 HEnvironment* env = environment(); |
| 3990 if (env->outer() != NULL && env->outer()->outer() != NULL) return false; | 3907 if (env->outer() != NULL && env->outer()->outer() != NULL) { |
| 3908 TraceInline(target, "inline depth limit reached"); |
| 3909 return false; |
| 3910 } |
| 3991 | 3911 |
| 3992 // Don't inline recursive functions. | 3912 // Don't inline recursive functions. |
| 3993 if (target->shared() == outer_info->closure()->shared()) return false; | 3913 if (target->shared() == outer_info->closure()->shared()) { |
| 3914 TraceInline(target, "target is recursive"); |
| 3915 return false; |
| 3916 } |
| 3994 | 3917 |
| 3995 // We don't want to add more than a certain number of nodes from inlining. | 3918 // We don't want to add more than a certain number of nodes from inlining. |
| 3996 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { | 3919 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { |
| 3997 if (FLAG_trace_inlining) TraceInline(target, false); | 3920 TraceInline(target, "cumulative AST node limit reached"); |
| 3998 return false; | 3921 return false; |
| 3999 } | 3922 } |
| 4000 | 3923 |
| 4001 int count_before = AstNode::Count(); | 3924 int count_before = AstNode::Count(); |
| 4002 | 3925 |
| 4003 // Parse and allocate variables. | 3926 // Parse and allocate variables. |
| 4004 CompilationInfo inner_info(target); | 3927 CompilationInfo target_info(target); |
| 4005 if (!ParserApi::Parse(&inner_info) || | 3928 if (!ParserApi::Parse(&target_info) || |
| 4006 !Scope::Analyze(&inner_info)) { | 3929 !Scope::Analyze(&target_info)) { |
| 4007 if (Top::has_pending_exception()) { | 3930 if (Top::has_pending_exception()) { |
| 3931 // Parse or scope error, never optimize this function. |
| 4008 SetStackOverflow(); | 3932 SetStackOverflow(); |
| 3933 target->shared()->set_optimization_disabled(true); |
| 4009 } | 3934 } |
| 3935 TraceInline(target, "parse failure"); |
| 4010 return false; | 3936 return false; |
| 4011 } | 3937 } |
| 4012 FunctionLiteral* function = inner_info.function(); | 3938 |
| 3939 if (target_info.scope()->num_heap_slots() > 0) { |
| 3940 TraceInline(target, "target has context-allocated variables"); |
| 3941 return false; |
| 3942 } |
| 3943 FunctionLiteral* function = target_info.function(); |
| 4013 | 3944 |
| 4014 // Count the number of AST nodes added by inlining this call. | 3945 // Count the number of AST nodes added by inlining this call. |
| 4015 int nodes_added = AstNode::Count() - count_before; | 3946 int nodes_added = AstNode::Count() - count_before; |
| 4016 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | 3947 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { |
| 4017 if (FLAG_trace_inlining) TraceInline(target, false); | 3948 TraceInline(target, "target AST is too large"); |
| 4018 return false; | 3949 return false; |
| 4019 } | 3950 } |
| 4020 | 3951 |
| 4021 // Check if we can handle all declarations in the inlined functions. | 3952 // Check if we can handle all declarations in the inlined functions. |
| 4022 VisitDeclarations(inner_info.scope()->declarations()); | 3953 VisitDeclarations(target_info.scope()->declarations()); |
| 4023 if (HasStackOverflow()) { | 3954 if (HasStackOverflow()) { |
| 3955 TraceInline(target, "target has non-trivial declaration"); |
| 4024 ClearStackOverflow(); | 3956 ClearStackOverflow(); |
| 4025 return false; | 3957 return false; |
| 4026 } | 3958 } |
| 4027 | 3959 |
| 4028 // Don't inline functions that uses the arguments object or that | 3960 // Don't inline functions that uses the arguments object or that |
| 4029 // have a mismatching number of parameters. | 3961 // have a mismatching number of parameters. |
| 4030 Handle<SharedFunctionInfo> shared(target->shared()); | 3962 Handle<SharedFunctionInfo> target_shared(target->shared()); |
| 4031 int arity = expr->arguments()->length(); | 3963 int arity = expr->arguments()->length(); |
| 4032 if (function->scope()->arguments() != NULL || | 3964 if (function->scope()->arguments() != NULL || |
| 4033 arity != shared->formal_parameter_count()) { | 3965 arity != target_shared->formal_parameter_count()) { |
| 3966 TraceInline(target, "target requires special argument handling"); |
| 4034 return false; | 3967 return false; |
| 4035 } | 3968 } |
| 4036 | 3969 |
| 4037 // All statements in the body must be inlineable. | 3970 // All statements in the body must be inlineable. |
| 4038 for (int i = 0, count = function->body()->length(); i < count; ++i) { | 3971 for (int i = 0, count = function->body()->length(); i < count; ++i) { |
| 4039 if (!function->body()->at(i)->IsInlineable()) return false; | 3972 if (!function->body()->at(i)->IsInlineable()) { |
| 3973 TraceInline(target, "target contains unsupported syntax"); |
| 3974 return false; |
| 3975 } |
| 4040 } | 3976 } |
| 4041 | 3977 |
| 4042 // Generate the deoptimization data for the unoptimized version of | 3978 // Generate the deoptimization data for the unoptimized version of |
| 4043 // the target function if we don't already have it. | 3979 // the target function if we don't already have it. |
| 4044 if (!shared->has_deoptimization_support()) { | 3980 if (!target_shared->has_deoptimization_support()) { |
| 4045 // Note that we compile here using the same AST that we will use for | 3981 // Note that we compile here using the same AST that we will use for |
| 4046 // generating the optimized inline code. | 3982 // generating the optimized inline code. |
| 4047 inner_info.EnableDeoptimizationSupport(); | 3983 target_info.EnableDeoptimizationSupport(); |
| 4048 if (!FullCodeGenerator::MakeCode(&inner_info)) return false; | 3984 if (!FullCodeGenerator::MakeCode(&target_info)) { |
| 4049 shared->EnableDeoptimizationSupport(*inner_info.code()); | 3985 TraceInline(target, "could not generate deoptimization info"); |
| 4050 Compiler::RecordFunctionCompilation( | 3986 return false; |
| 4051 Logger::FUNCTION_TAG, | 3987 } |
| 4052 Handle<String>(shared->DebugName()), | 3988 target_shared->EnableDeoptimizationSupport(*target_info.code()); |
| 4053 shared->start_position(), | 3989 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, |
| 4054 &inner_info); | 3990 &target_info, |
| 3991 target_shared); |
| 4055 } | 3992 } |
| 4056 | 3993 |
| 3994 // ---------------------------------------------------------------- |
| 4057 // Save the pending call context and type feedback oracle. Set up new ones | 3995 // Save the pending call context and type feedback oracle. Set up new ones |
| 4058 // for the inlined function. | 3996 // for the inlined function. |
| 4059 ASSERT(shared->has_deoptimization_support()); | 3997 ASSERT(target_shared->has_deoptimization_support()); |
| 4060 AstContext* saved_call_context = call_context(); | 3998 TypeFeedbackOracle target_oracle( |
| 4061 HBasicBlock* saved_function_return = function_return(); | 3999 Handle<Code>(target_shared->code()), |
| 4062 TypeFeedbackOracle* saved_oracle = oracle(); | 4000 Handle<Context>(target->context()->global_context())); |
| 4063 // On-stack replacement cannot target inlined functions. Since we don't | 4001 FunctionState target_state(this, &target_info, &target_oracle); |
| 4064 // use a separate CompilationInfo structure for the inlined function, we | |
| 4065 // save and restore the AST ID in the original compilation info. | |
| 4066 int saved_osr_ast_id = graph()->info()->osr_ast_id(); | |
| 4067 | 4002 |
| 4068 TestContext* test_context = NULL; | 4003 HConstant* undefined = graph()->GetConstantUndefined(); |
| 4069 if (ast_context()->IsTest()) { | 4004 HEnvironment* inner_env = |
| 4070 // Inlined body is treated as if it occurs in an 'inlined' call context | 4005 environment()->CopyForInlining(target, function, true, undefined); |
| 4071 // with true and false blocks that will forward to the real ones. | 4006 HBasicBlock* body_entry = CreateBasicBlock(inner_env); |
| 4072 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4007 current_block()->Goto(body_entry); |
| 4073 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
| 4074 if_true->MarkAsInlineReturnTarget(); | |
| 4075 if_false->MarkAsInlineReturnTarget(); | |
| 4076 // AstContext constructor pushes on the context stack. | |
| 4077 test_context = new TestContext(this, if_true, if_false); | |
| 4078 function_return_ = NULL; | |
| 4079 } else { | |
| 4080 // Inlined body is treated as if it occurs in the original call context. | |
| 4081 function_return_ = graph()->CreateBasicBlock(); | |
| 4082 function_return_->MarkAsInlineReturnTarget(); | |
| 4083 } | |
| 4084 call_context_ = ast_context(); | |
| 4085 TypeFeedbackOracle new_oracle( | |
| 4086 Handle<Code>(shared->code()), | |
| 4087 Handle<Context>(target->context()->global_context())); | |
| 4088 oracle_ = &new_oracle; | |
| 4089 graph()->info()->SetOsrAstId(AstNode::kNoNumber); | |
| 4090 | 4008 |
| 4091 HSubgraph* body = CreateInlinedSubgraph(env, target, function); | 4009 body_entry->SetJoinId(expr->ReturnId()); |
| 4092 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); | 4010 set_current_block(body_entry); |
| 4093 AddToSubgraph(body, function->body()); | 4011 AddInstruction(new HEnterInlined(target, function)); |
| 4012 VisitStatements(function->body()); |
| 4094 if (HasStackOverflow()) { | 4013 if (HasStackOverflow()) { |
| 4095 // Bail out if the inline function did, as we cannot residualize a call | 4014 // Bail out if the inline function did, as we cannot residualize a call |
| 4096 // instead. | 4015 // instead. |
| 4097 delete test_context; | 4016 TraceInline(target, "inline graph construction failed"); |
| 4098 call_context_ = saved_call_context; | |
| 4099 function_return_ = saved_function_return; | |
| 4100 oracle_ = saved_oracle; | |
| 4101 graph()->info()->SetOsrAstId(saved_osr_ast_id); | |
| 4102 return false; | 4017 return false; |
| 4103 } | 4018 } |
| 4104 | 4019 |
| 4105 // Update inlined nodes count. | 4020 // Update inlined nodes count. |
| 4106 inlined_count_ += nodes_added; | 4021 inlined_count_ += nodes_added; |
| 4107 | 4022 |
| 4108 if (FLAG_trace_inlining) TraceInline(target, true); | 4023 TraceInline(target, NULL); |
| 4109 | 4024 |
| 4110 if (body->HasExit()) { | 4025 if (current_block() != NULL) { |
| 4111 // Add a return of undefined if control can fall off the body. In a | 4026 // Add a return of undefined if control can fall off the body. In a |
| 4112 // test context, undefined is false. | 4027 // test context, undefined is false. |
| 4113 HValue* return_value = graph()->GetConstantUndefined(); | 4028 if (inlined_test_context() == NULL) { |
| 4114 if (test_context == NULL) { | 4029 ASSERT(function_return() != NULL); |
| 4115 ASSERT(function_return_ != NULL); | 4030 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
| 4116 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4031 if (call_context()->IsEffect()) { |
| 4032 current_block()->Goto(function_return(), false); |
| 4033 } else { |
| 4034 current_block()->AddLeaveInlined(undefined, function_return()); |
| 4035 } |
| 4117 } else { | 4036 } else { |
| 4118 // The graph builder assumes control can reach both branches of a | 4037 // The graph builder assumes control can reach both branches of a |
| 4119 // test, so we materialize the undefined value and test it rather than | 4038 // test, so we materialize the undefined value and test it rather than |
| 4120 // simply jumping to the false target. | 4039 // simply jumping to the false target. |
| 4121 // | 4040 // |
| 4122 // TODO(3168478): refactor to avoid this. | 4041 // TODO(3168478): refactor to avoid this. |
| 4123 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4042 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 4124 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4043 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 4125 HTest* test = new HTest(return_value, empty_true, empty_false); | 4044 HTest* test = new HTest(undefined, empty_true, empty_false); |
| 4126 body->exit_block()->Finish(test); | 4045 current_block()->Finish(test); |
| 4127 | 4046 |
| 4128 HValue* const no_return_value = NULL; | 4047 empty_true->Goto(inlined_test_context()->if_true(), false); |
| 4129 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); | 4048 empty_false->Goto(inlined_test_context()->if_false(), false); |
| 4130 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); | |
| 4131 } | 4049 } |
| 4132 body->set_exit_block(NULL); | |
| 4133 } | 4050 } |
| 4134 | 4051 |
| 4135 // Record the environment at the inlined function call. | |
| 4136 AddSimulate(expr->ReturnId()); | |
| 4137 | |
| 4138 // Jump to the function entry (without re-recording the environment). | |
| 4139 subgraph()->exit_block()->Finish(new HGoto(body->entry_block())); | |
| 4140 | |
| 4141 // Fix up the function exits. | 4052 // Fix up the function exits. |
| 4142 if (test_context != NULL) { | 4053 if (inlined_test_context() != NULL) { |
| 4143 HBasicBlock* if_true = test_context->if_true(); | 4054 HBasicBlock* if_true = inlined_test_context()->if_true(); |
| 4144 HBasicBlock* if_false = test_context->if_false(); | 4055 HBasicBlock* if_false = inlined_test_context()->if_false(); |
| 4145 if_true->SetJoinId(expr->id()); | 4056 if_true->SetJoinId(expr->id()); |
| 4146 if_false->SetJoinId(expr->id()); | 4057 if_false->SetJoinId(expr->id()); |
| 4147 ASSERT(ast_context() == test_context); | 4058 ASSERT(ast_context() == inlined_test_context()); |
| 4148 delete test_context; // Destructor pops from expression context stack. | 4059 // Pop the return test context from the expression context stack. |
| 4060 ClearInlinedTestContext(); |
| 4149 | 4061 |
| 4150 // Forward to the real test context. | 4062 // Forward to the real test context. |
| 4151 HValue* const no_return_value = NULL; | |
| 4152 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4063 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 4153 if (true_target->IsInlineReturnTarget()) { | |
| 4154 if_true->AddLeaveInlined(no_return_value, true_target); | |
| 4155 } else { | |
| 4156 if_true->Goto(true_target); | |
| 4157 } | |
| 4158 | |
| 4159 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4064 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 4160 if (false_target->IsInlineReturnTarget()) { | 4065 if_true->Goto(true_target, false); |
| 4161 if_false->AddLeaveInlined(no_return_value, false_target); | 4066 if_false->Goto(false_target, false); |
| 4162 } else { | |
| 4163 if_false->Goto(false_target); | |
| 4164 } | |
| 4165 | 4067 |
| 4166 // TODO(kmillikin): Come up with a better way to handle this. It is too | 4068 // TODO(kmillikin): Come up with a better way to handle this. It is too |
| 4167 // subtle. NULL here indicates that the enclosing context has no control | 4069 // subtle. NULL here indicates that the enclosing context has no control |
| 4168 // flow to handle. | 4070 // flow to handle. |
| 4169 subgraph()->set_exit_block(NULL); | 4071 set_current_block(NULL); |
| 4170 | 4072 |
| 4171 } else { | 4073 } else { |
| 4172 function_return_->SetJoinId(expr->id()); | 4074 function_return()->SetJoinId(expr->id()); |
| 4173 subgraph()->set_exit_block(function_return_); | 4075 set_current_block(function_return()); |
| 4174 } | 4076 } |
| 4175 | 4077 |
| 4176 call_context_ = saved_call_context; | |
| 4177 function_return_ = saved_function_return; | |
| 4178 oracle_ = saved_oracle; | |
| 4179 graph()->info()->SetOsrAstId(saved_osr_ast_id); | |
| 4180 | |
| 4181 return true; | 4078 return true; |
| 4182 } | 4079 } |
| 4183 | 4080 |
| 4184 | 4081 |
| 4185 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | |
| 4186 ASSERT(target->IsInlineReturnTarget()); | |
| 4187 AddInstruction(new HLeaveInlined); | |
| 4188 HEnvironment* outer = last_environment()->outer(); | |
| 4189 if (return_value != NULL) outer->Push(return_value); | |
| 4190 UpdateEnvironment(outer); | |
| 4191 Goto(target); | |
| 4192 } | |
| 4193 | |
| 4194 | |
| 4195 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, | 4082 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 4196 HValue* receiver, | 4083 HValue* receiver, |
| 4197 Handle<Map> receiver_map, | 4084 Handle<Map> receiver_map, |
| 4198 CheckType check_type) { | 4085 CheckType check_type) { |
| 4199 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | 4086 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| 4200 // Try to inline calls like Math.* as operations in the calling function. | 4087 // Try to inline calls like Math.* as operations in the calling function. |
| 4201 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 4088 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 4202 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4089 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4203 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4090 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4204 switch (id) { | 4091 switch (id) { |
| 4205 case kStringCharCodeAt: | 4092 case kStringCharCodeAt: |
| 4093 case kStringCharAt: |
| 4206 if (argument_count == 2 && check_type == STRING_CHECK) { | 4094 if (argument_count == 2 && check_type == STRING_CHECK) { |
| 4207 HValue* index = Pop(); | 4095 HValue* index = Pop(); |
| 4208 HValue* string = Pop(); | 4096 HValue* string = Pop(); |
| 4209 ASSERT(!expr->holder().is_null()); | 4097 ASSERT(!expr->holder().is_null()); |
| 4210 AddInstruction(new HCheckPrototypeMaps( | 4098 AddInstruction(new HCheckPrototypeMaps( |
| 4211 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), | 4099 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), |
| 4212 expr->holder())); | 4100 expr->holder())); |
| 4213 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); | 4101 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); |
| 4102 if (id == kStringCharCodeAt) { |
| 4103 ast_context()->ReturnInstruction(char_code, expr->id()); |
| 4104 return true; |
| 4105 } |
| 4106 AddInstruction(char_code); |
| 4107 HStringCharFromCode* result = new HStringCharFromCode(char_code); |
| 4214 ast_context()->ReturnInstruction(result, expr->id()); | 4108 ast_context()->ReturnInstruction(result, expr->id()); |
| 4215 return true; | 4109 return true; |
| 4216 } | 4110 } |
| 4217 break; | 4111 break; |
| 4218 case kMathRound: | 4112 case kMathRound: |
| 4219 case kMathFloor: | 4113 case kMathFloor: |
| 4220 case kMathAbs: | 4114 case kMathAbs: |
| 4221 case kMathSqrt: | 4115 case kMathSqrt: |
| 4222 case kMathLog: | 4116 case kMathLog: |
| 4223 case kMathSin: | 4117 case kMathSin: |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4278 } | 4172 } |
| 4279 return false; | 4173 return false; |
| 4280 } | 4174 } |
| 4281 | 4175 |
| 4282 | 4176 |
| 4283 bool HGraphBuilder::TryCallApply(Call* expr) { | 4177 bool HGraphBuilder::TryCallApply(Call* expr) { |
| 4284 Expression* callee = expr->expression(); | 4178 Expression* callee = expr->expression(); |
| 4285 Property* prop = callee->AsProperty(); | 4179 Property* prop = callee->AsProperty(); |
| 4286 ASSERT(prop != NULL); | 4180 ASSERT(prop != NULL); |
| 4287 | 4181 |
| 4288 if (graph()->info()->scope()->arguments() == NULL) return false; | 4182 if (info()->scope()->arguments() == NULL) return false; |
| 4289 | 4183 |
| 4290 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4184 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4291 if (!name->IsEqualTo(CStrVector("apply"))) return false; | 4185 if (!name->IsEqualTo(CStrVector("apply"))) return false; |
| 4292 | 4186 |
| 4293 ZoneList<Expression*>* args = expr->arguments(); | 4187 ZoneList<Expression*>* args = expr->arguments(); |
| 4294 if (args->length() != 2) return false; | 4188 if (args->length() != 2) return false; |
| 4295 | 4189 |
| 4296 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 4190 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 4297 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 4191 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 4298 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 4192 HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 4325 static bool HasCustomCallGenerator(Handle<JSFunction> function) { | 4219 static bool HasCustomCallGenerator(Handle<JSFunction> function) { |
| 4326 SharedFunctionInfo* info = function->shared(); | 4220 SharedFunctionInfo* info = function->shared(); |
| 4327 return info->HasBuiltinFunctionId() && | 4221 return info->HasBuiltinFunctionId() && |
| 4328 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); | 4222 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); |
| 4329 } | 4223 } |
| 4330 | 4224 |
| 4331 | 4225 |
| 4332 void HGraphBuilder::VisitCall(Call* expr) { | 4226 void HGraphBuilder::VisitCall(Call* expr) { |
| 4333 Expression* callee = expr->expression(); | 4227 Expression* callee = expr->expression(); |
| 4334 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4228 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4335 HCall* call = NULL; | 4229 HInstruction* call = NULL; |
| 4336 | 4230 |
| 4337 Property* prop = callee->AsProperty(); | 4231 Property* prop = callee->AsProperty(); |
| 4338 if (prop != NULL) { | 4232 if (prop != NULL) { |
| 4339 if (!prop->key()->IsPropertyName()) { | 4233 if (!prop->key()->IsPropertyName()) { |
| 4340 // Keyed function call. | 4234 // Keyed function call. |
| 4341 VisitArgument(prop->obj()); | 4235 VISIT_FOR_VALUE(prop->obj()); |
| 4342 CHECK_BAILOUT; | |
| 4343 | 4236 |
| 4344 VISIT_FOR_VALUE(prop->key()); | 4237 VISIT_FOR_VALUE(prop->key()); |
| 4345 // Push receiver and key like the non-optimized code generator expects it. | 4238 // Push receiver and key like the non-optimized code generator expects it. |
| 4346 HValue* key = Pop(); | 4239 HValue* key = Pop(); |
| 4347 HValue* receiver = Pop(); | 4240 HValue* receiver = Pop(); |
| 4348 Push(key); | 4241 Push(key); |
| 4349 Push(receiver); | 4242 Push(receiver); |
| 4350 | 4243 |
| 4351 VisitArgumentList(expr->arguments()); | 4244 VisitExpressions(expr->arguments()); |
| 4352 CHECK_BAILOUT; | 4245 CHECK_BAILOUT; |
| 4353 | 4246 |
| 4354 HContext* context = new HContext; | 4247 HContext* context = new HContext; |
| 4355 AddInstruction(context); | 4248 AddInstruction(context); |
| 4356 call = new HCallKeyed(context, key, argument_count); | 4249 call = PreProcessCall(new HCallKeyed(context, key, argument_count)); |
| 4357 call->set_position(expr->position()); | 4250 call->set_position(expr->position()); |
| 4358 PreProcessCall(call); | |
| 4359 Drop(1); // Key. | 4251 Drop(1); // Key. |
| 4360 ast_context()->ReturnInstruction(call, expr->id()); | 4252 ast_context()->ReturnInstruction(call, expr->id()); |
| 4361 return; | 4253 return; |
| 4362 } | 4254 } |
| 4363 | 4255 |
| 4364 // Named function call. | 4256 // Named function call. |
| 4365 expr->RecordTypeFeedback(oracle()); | 4257 expr->RecordTypeFeedback(oracle()); |
| 4366 | 4258 |
| 4367 if (TryCallApply(expr)) return; | 4259 if (TryCallApply(expr)) return; |
| 4368 CHECK_BAILOUT; | 4260 CHECK_BAILOUT; |
| 4369 | 4261 |
| 4370 VisitArgument(prop->obj()); | 4262 VISIT_FOR_VALUE(prop->obj()); |
| 4371 CHECK_BAILOUT; | 4263 VisitExpressions(expr->arguments()); |
| 4372 VisitArgumentList(expr->arguments()); | |
| 4373 CHECK_BAILOUT; | 4264 CHECK_BAILOUT; |
| 4374 | 4265 |
| 4375 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4266 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4376 | 4267 |
| 4377 expr->RecordTypeFeedback(oracle()); | 4268 expr->RecordTypeFeedback(oracle()); |
| 4378 ZoneMapList* types = expr->GetReceiverTypes(); | 4269 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4379 | 4270 |
| 4380 HValue* receiver = | 4271 HValue* receiver = |
| 4381 environment()->ExpressionStackAt(expr->arguments()->length()); | 4272 environment()->ExpressionStackAt(expr->arguments()->length()); |
| 4382 if (expr->IsMonomorphic()) { | 4273 if (expr->IsMonomorphic()) { |
| 4383 Handle<Map> receiver_map = | 4274 Handle<Map> receiver_map = |
| 4384 (types == NULL) ? Handle<Map>::null() : types->first(); | 4275 (types == NULL) ? Handle<Map>::null() : types->first(); |
| 4385 if (TryInlineBuiltinFunction(expr, | 4276 if (TryInlineBuiltinFunction(expr, |
| 4386 receiver, | 4277 receiver, |
| 4387 receiver_map, | 4278 receiver_map, |
| 4388 expr->check_type())) { | 4279 expr->check_type())) { |
| 4389 return; | 4280 return; |
| 4390 } | 4281 } |
| 4391 | 4282 |
| 4392 if (HasCustomCallGenerator(expr->target()) || | 4283 if (HasCustomCallGenerator(expr->target()) || |
| 4284 CallOptimization(*expr->target()).is_simple_api_call() || |
| 4393 expr->check_type() != RECEIVER_MAP_CHECK) { | 4285 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 4394 // When the target has a custom call IC generator, use the IC, | 4286 // When the target has a custom call IC generator, use the IC, |
| 4395 // because it is likely to generate better code. Also use the | 4287 // because it is likely to generate better code. Similarly, we |
| 4396 // IC when a primitive receiver check is required. | 4288 // generate better call stubs for some API functions. |
| 4289 // Also use the IC when a primitive receiver check is required. |
| 4397 HContext* context = new HContext; | 4290 HContext* context = new HContext; |
| 4398 AddInstruction(context); | 4291 AddInstruction(context); |
| 4399 call = new HCallNamed(context, name, argument_count); | 4292 call = PreProcessCall(new HCallNamed(context, name, argument_count)); |
| 4400 } else { | 4293 } else { |
| 4401 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 4294 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4402 | 4295 |
| 4403 if (TryInline(expr)) { | 4296 if (TryInline(expr)) { |
| 4404 if (subgraph()->HasExit()) { | |
| 4405 HValue* return_value = Pop(); | |
| 4406 // If we inlined a function in a test context then we need to emit | |
| 4407 // a simulate here to shadow the ones at the end of the | |
| 4408 // predecessor blocks. Those environments contain the return | |
| 4409 // value on top and do not correspond to any actual state of the | |
| 4410 // unoptimized code. | |
| 4411 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4412 ast_context()->ReturnValue(return_value); | |
| 4413 } | |
| 4414 return; | 4297 return; |
| 4415 } else { | 4298 } else { |
| 4416 // Check for bailout, as the TryInline call in the if condition above | 4299 // Check for bailout, as the TryInline call in the if condition above |
| 4417 // might return false due to bailout during hydrogen processing. | 4300 // might return false due to bailout during hydrogen processing. |
| 4418 CHECK_BAILOUT; | 4301 CHECK_BAILOUT; |
| 4419 call = new HCallConstantFunction(expr->target(), argument_count); | 4302 call = PreProcessCall(new HCallConstantFunction(expr->target(), |
| 4303 argument_count)); |
| 4420 } | 4304 } |
| 4421 } | 4305 } |
| 4422 } else if (types != NULL && types->length() > 1) { | 4306 } else if (types != NULL && types->length() > 1) { |
| 4423 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 4307 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4424 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4308 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4425 return; | 4309 return; |
| 4426 | 4310 |
| 4427 } else { | 4311 } else { |
| 4428 HContext* context = new HContext; | 4312 HContext* context = new HContext; |
| 4429 AddInstruction(context); | 4313 AddInstruction(context); |
| 4430 call = new HCallNamed(context, name, argument_count); | 4314 call = PreProcessCall(new HCallNamed(context, name, argument_count)); |
| 4431 } | 4315 } |
| 4432 | 4316 |
| 4433 } else { | 4317 } else { |
| 4434 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4318 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4435 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4319 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); |
| 4436 | 4320 |
| 4437 if (!global_call) { | 4321 if (!global_call) { |
| 4438 ++argument_count; | 4322 ++argument_count; |
| 4439 VisitArgument(expr->expression()); | 4323 VISIT_FOR_VALUE(expr->expression()); |
| 4440 CHECK_BAILOUT; | |
| 4441 } | 4324 } |
| 4442 | 4325 |
| 4443 if (global_call) { | 4326 if (global_call) { |
| 4327 bool known_global_function = false; |
| 4444 // If there is a global property cell for the name at compile time and | 4328 // If there is a global property cell for the name at compile time and |
| 4445 // access check is not enabled we assume that the function will not change | 4329 // access check is not enabled we assume that the function will not change |
| 4446 // and generate optimized code for calling the function. | 4330 // and generate optimized code for calling the function. |
| 4447 CompilationInfo* info = graph()->info(); | 4331 if (info()->has_global_object() && |
| 4448 bool known_global_function = info->has_global_object() && | 4332 !info()->global_object()->IsAccessCheckNeeded()) { |
| 4449 !info->global_object()->IsAccessCheckNeeded() && | 4333 Handle<GlobalObject> global(info()->global_object()); |
| 4450 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), | 4334 known_global_function = expr->ComputeGlobalTarget(global, var->name()); |
| 4451 var->name()); | 4335 } |
| 4452 if (known_global_function) { | 4336 if (known_global_function) { |
| 4453 // Push the global object instead of the global receiver because | 4337 // Push the global object instead of the global receiver because |
| 4454 // code generated by the full code generator expects it. | 4338 // code generated by the full code generator expects it. |
| 4455 HContext* context = new HContext; | 4339 HContext* context = new HContext; |
| 4456 HGlobalObject* global_object = new HGlobalObject(context); | 4340 HGlobalObject* global_object = new HGlobalObject(context); |
| 4457 AddInstruction(context); | 4341 AddInstruction(context); |
| 4458 PushAndAdd(global_object); | 4342 PushAndAdd(global_object); |
| 4459 VisitArgumentList(expr->arguments()); | 4343 VisitExpressions(expr->arguments()); |
| 4460 CHECK_BAILOUT; | 4344 CHECK_BAILOUT; |
| 4461 | 4345 |
| 4462 VISIT_FOR_VALUE(expr->expression()); | 4346 VISIT_FOR_VALUE(expr->expression()); |
| 4463 HValue* function = Pop(); | 4347 HValue* function = Pop(); |
| 4464 AddInstruction(new HCheckFunction(function, expr->target())); | 4348 AddInstruction(new HCheckFunction(function, expr->target())); |
| 4465 | 4349 |
| 4466 // Replace the global object with the global receiver. | 4350 // Replace the global object with the global receiver. |
| 4467 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); | 4351 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); |
| 4468 // Index of the receiver from the top of the expression stack. | 4352 // Index of the receiver from the top of the expression stack. |
| 4469 const int receiver_index = argument_count - 1; | 4353 const int receiver_index = argument_count - 1; |
| 4470 AddInstruction(global_receiver); | 4354 AddInstruction(global_receiver); |
| 4471 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4355 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 4472 IsGlobalObject()); | 4356 IsGlobalObject()); |
| 4473 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4357 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 4474 | 4358 |
| 4475 if (TryInline(expr)) { | 4359 if (TryInline(expr)) { |
| 4476 if (subgraph()->HasExit()) { | |
| 4477 HValue* return_value = Pop(); | |
| 4478 // If we inlined a function in a test context then we need to | |
| 4479 // emit a simulate here to shadow the ones at the end of the | |
| 4480 // predecessor blocks. Those environments contain the return | |
| 4481 // value on top and do not correspond to any actual state of the | |
| 4482 // unoptimized code. | |
| 4483 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4484 ast_context()->ReturnValue(return_value); | |
| 4485 } | |
| 4486 return; | 4360 return; |
| 4487 } | 4361 } |
| 4488 // Check for bailout, as trying to inline might fail due to bailout | 4362 // Check for bailout, as trying to inline might fail due to bailout |
| 4489 // during hydrogen processing. | 4363 // during hydrogen processing. |
| 4490 CHECK_BAILOUT; | 4364 CHECK_BAILOUT; |
| 4491 | 4365 |
| 4492 call = new HCallKnownGlobal(expr->target(), argument_count); | 4366 call = PreProcessCall(new HCallKnownGlobal(expr->target(), |
| 4367 argument_count)); |
| 4493 } else { | 4368 } else { |
| 4494 HContext* context = new HContext; | 4369 HContext* context = new HContext; |
| 4495 AddInstruction(context); | 4370 AddInstruction(context); |
| 4496 PushAndAdd(new HGlobalObject(context)); | 4371 PushAndAdd(new HGlobalObject(context)); |
| 4497 VisitArgumentList(expr->arguments()); | 4372 VisitExpressions(expr->arguments()); |
| 4498 CHECK_BAILOUT; | 4373 CHECK_BAILOUT; |
| 4499 | 4374 |
| 4500 call = new HCallGlobal(context, var->name(), argument_count); | 4375 call = PreProcessCall(new HCallGlobal(context, |
| 4376 var->name(), |
| 4377 argument_count)); |
| 4501 } | 4378 } |
| 4502 | 4379 |
| 4503 } else { | 4380 } else { |
| 4504 HContext* context = new HContext; | 4381 HContext* context = new HContext; |
| 4505 HGlobalObject* global_object = new HGlobalObject(context); | 4382 HGlobalObject* global_object = new HGlobalObject(context); |
| 4506 AddInstruction(context); | 4383 AddInstruction(context); |
| 4507 AddInstruction(global_object); | 4384 AddInstruction(global_object); |
| 4508 PushAndAdd(new HGlobalReceiver(global_object)); | 4385 PushAndAdd(new HGlobalReceiver(global_object)); |
| 4509 VisitArgumentList(expr->arguments()); | 4386 VisitExpressions(expr->arguments()); |
| 4510 CHECK_BAILOUT; | 4387 CHECK_BAILOUT; |
| 4511 | 4388 |
| 4512 call = new HCallFunction(context, argument_count); | 4389 call = PreProcessCall(new HCallFunction(context, argument_count)); |
| 4513 } | 4390 } |
| 4514 } | 4391 } |
| 4515 | 4392 |
| 4516 call->set_position(expr->position()); | 4393 call->set_position(expr->position()); |
| 4517 PreProcessCall(call); | |
| 4518 ast_context()->ReturnInstruction(call, expr->id()); | 4394 ast_context()->ReturnInstruction(call, expr->id()); |
| 4519 } | 4395 } |
| 4520 | 4396 |
| 4521 | 4397 |
| 4522 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 4398 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 4523 // The constructor function is also used as the receiver argument to the | 4399 // The constructor function is also used as the receiver argument to the |
| 4524 // JS construct call builtin. | 4400 // JS construct call builtin. |
| 4525 VisitArgument(expr->expression()); | 4401 VISIT_FOR_VALUE(expr->expression()); |
| 4526 CHECK_BAILOUT; | 4402 VisitExpressions(expr->arguments()); |
| 4527 VisitArgumentList(expr->arguments()); | |
| 4528 CHECK_BAILOUT; | 4403 CHECK_BAILOUT; |
| 4529 | 4404 |
| 4530 HContext* context = new HContext; | 4405 HContext* context = new HContext; |
| 4531 AddInstruction(context); | 4406 AddInstruction(context); |
| 4532 | 4407 |
| 4533 // The constructor is both an operand to the instruction and an argument | 4408 // The constructor is both an operand to the instruction and an argument |
| 4534 // to the construct call. | 4409 // to the construct call. |
| 4535 int arg_count = expr->arguments()->length() + 1; // Plus constructor. | 4410 int arg_count = expr->arguments()->length() + 1; // Plus constructor. |
| 4536 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1); | 4411 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1); |
| 4537 HCall* call = new HCallNew(context, constructor, arg_count); | 4412 HCallNew* call = new HCallNew(context, constructor, arg_count); |
| 4538 call->set_position(expr->position()); | 4413 call->set_position(expr->position()); |
| 4539 PreProcessCall(call); | 4414 PreProcessCall(call); |
| 4540 ast_context()->ReturnInstruction(call, expr->id()); | 4415 ast_context()->ReturnInstruction(call, expr->id()); |
| 4541 } | 4416 } |
| 4542 | 4417 |
| 4543 | 4418 |
| 4544 // Support for generating inlined runtime functions. | 4419 // Support for generating inlined runtime functions. |
| 4545 | 4420 |
| 4546 // Lookup table for generators for runtime calls that are generated inline. | 4421 // Lookup table for generators for runtime calls that are generated inline. |
| 4547 // Elements of the table are member pointers to functions of HGraphBuilder. | 4422 // Elements of the table are member pointers to functions of HGraphBuilder. |
| 4548 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 4423 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 4549 &HGraphBuilder::Generate##Name, | 4424 &HGraphBuilder::Generate##Name, |
| 4550 | 4425 |
| 4551 const HGraphBuilder::InlineFunctionGenerator | 4426 const HGraphBuilder::InlineFunctionGenerator |
| 4552 HGraphBuilder::kInlineFunctionGenerators[] = { | 4427 HGraphBuilder::kInlineFunctionGenerators[] = { |
| 4553 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 4428 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 4554 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 4429 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 4555 }; | 4430 }; |
| 4556 #undef INLINE_FUNCTION_GENERATOR_ADDRESS | 4431 #undef INLINE_FUNCTION_GENERATOR_ADDRESS |
| 4557 | 4432 |
| 4558 | 4433 |
| 4559 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { | 4434 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 4560 Handle<String> name = expr->name(); | 4435 if (expr->is_jsruntime()) { |
| 4561 if (name->IsEqualTo(CStrVector("_Log"))) { | 4436 BAILOUT("call to a JavaScript runtime function"); |
| 4562 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | |
| 4563 return; | |
| 4564 } | 4437 } |
| 4565 | 4438 |
| 4566 Runtime::Function* function = expr->function(); | 4439 Runtime::Function* function = expr->function(); |
| 4567 if (expr->is_jsruntime()) { | |
| 4568 BAILOUT("call to a JavaScript runtime function"); | |
| 4569 } | |
| 4570 ASSERT(function != NULL); | 4440 ASSERT(function != NULL); |
| 4571 | |
| 4572 VisitArgumentList(expr->arguments()); | |
| 4573 CHECK_BAILOUT; | |
| 4574 | |
| 4575 int argument_count = expr->arguments()->length(); | |
| 4576 if (function->intrinsic_type == Runtime::INLINE) { | 4441 if (function->intrinsic_type == Runtime::INLINE) { |
| 4577 ASSERT(name->length() > 0); | 4442 ASSERT(expr->name()->length() > 0); |
| 4578 ASSERT(name->Get(0) == '_'); | 4443 ASSERT(expr->name()->Get(0) == '_'); |
| 4579 // Call to an inline function. | 4444 // Call to an inline function. |
| 4580 int lookup_index = static_cast<int>(function->function_id) - | 4445 int lookup_index = static_cast<int>(function->function_id) - |
| 4581 static_cast<int>(Runtime::kFirstInlineFunction); | 4446 static_cast<int>(Runtime::kFirstInlineFunction); |
| 4582 ASSERT(lookup_index >= 0); | 4447 ASSERT(lookup_index >= 0); |
| 4583 ASSERT(static_cast<size_t>(lookup_index) < | 4448 ASSERT(static_cast<size_t>(lookup_index) < |
| 4584 ARRAY_SIZE(kInlineFunctionGenerators)); | 4449 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 4585 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 4450 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| 4586 | 4451 |
| 4587 // Call the inline code generator using the pointer-to-member. | 4452 // Call the inline code generator using the pointer-to-member. |
| 4588 (this->*generator)(argument_count, expr->id()); | 4453 (this->*generator)(expr); |
| 4589 } else { | 4454 } else { |
| 4590 ASSERT(function->intrinsic_type == Runtime::RUNTIME); | 4455 ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
| 4591 HCall* call = new HCallRuntime(name, expr->function(), argument_count); | 4456 VisitArgumentList(expr->arguments()); |
| 4457 CHECK_BAILOUT; |
| 4458 |
| 4459 Handle<String> name = expr->name(); |
| 4460 int argument_count = expr->arguments()->length(); |
| 4461 HCallRuntime* call = new HCallRuntime(name, function, argument_count); |
| 4592 call->set_position(RelocInfo::kNoPosition); | 4462 call->set_position(RelocInfo::kNoPosition); |
| 4593 PreProcessCall(call); | 4463 Drop(argument_count); |
| 4594 ast_context()->ReturnInstruction(call, expr->id()); | 4464 ast_context()->ReturnInstruction(call, expr->id()); |
| 4595 } | 4465 } |
| 4596 } | 4466 } |
| 4597 | 4467 |
| 4598 | 4468 |
| 4599 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4469 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4600 Token::Value op = expr->op(); | 4470 Token::Value op = expr->op(); |
| 4601 if (op == Token::VOID) { | 4471 if (op == Token::VOID) { |
| 4602 VISIT_FOR_EFFECT(expr->expression()); | 4472 VISIT_FOR_EFFECT(expr->expression()); |
| 4603 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 4473 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 4633 BAILOUT("delete with global variable"); | 4503 BAILOUT("delete with global variable"); |
| 4634 } else { | 4504 } else { |
| 4635 BAILOUT("delete with non-global variable"); | 4505 BAILOUT("delete with non-global variable"); |
| 4636 } | 4506 } |
| 4637 } else if (op == Token::NOT) { | 4507 } else if (op == Token::NOT) { |
| 4638 if (ast_context()->IsTest()) { | 4508 if (ast_context()->IsTest()) { |
| 4639 TestContext* context = TestContext::cast(ast_context()); | 4509 TestContext* context = TestContext::cast(ast_context()); |
| 4640 VisitForControl(expr->expression(), | 4510 VisitForControl(expr->expression(), |
| 4641 context->if_false(), | 4511 context->if_false(), |
| 4642 context->if_true()); | 4512 context->if_true()); |
| 4513 } else if (ast_context()->IsValue()) { |
| 4514 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); |
| 4515 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); |
| 4516 VISIT_FOR_CONTROL(expr->expression(), |
| 4517 materialize_false, |
| 4518 materialize_true); |
| 4519 materialize_false->SetJoinId(expr->expression()->id()); |
| 4520 materialize_true->SetJoinId(expr->expression()->id()); |
| 4521 |
| 4522 set_current_block(materialize_false); |
| 4523 Push(graph()->GetConstantFalse()); |
| 4524 set_current_block(materialize_true); |
| 4525 Push(graph()->GetConstantTrue()); |
| 4526 |
| 4527 HBasicBlock* join = |
| 4528 CreateJoin(materialize_false, materialize_true, expr->id()); |
| 4529 set_current_block(join); |
| 4530 ast_context()->ReturnValue(Pop()); |
| 4643 } else { | 4531 } else { |
| 4644 HSubgraph* true_graph = CreateEmptySubgraph(); | 4532 ASSERT(ast_context()->IsEffect()); |
| 4645 HSubgraph* false_graph = CreateEmptySubgraph(); | 4533 VisitForEffect(expr->expression()); |
| 4646 VISIT_FOR_CONTROL(expr->expression(), | 4534 } |
| 4647 false_graph->entry_block(), | |
| 4648 true_graph->entry_block()); | |
| 4649 true_graph->entry_block()->SetJoinId(expr->expression()->id()); | |
| 4650 true_graph->environment()->Push(graph_->GetConstantTrue()); | |
| 4651 | 4535 |
| 4652 false_graph->entry_block()->SetJoinId(expr->expression()->id()); | |
| 4653 false_graph->environment()->Push(graph_->GetConstantFalse()); | |
| 4654 | |
| 4655 current_subgraph_->AppendJoin(true_graph, false_graph, expr); | |
| 4656 ast_context()->ReturnValue(Pop()); | |
| 4657 } | |
| 4658 } else if (op == Token::BIT_NOT || op == Token::SUB) { | 4536 } else if (op == Token::BIT_NOT || op == Token::SUB) { |
| 4659 VISIT_FOR_VALUE(expr->expression()); | 4537 VISIT_FOR_VALUE(expr->expression()); |
| 4660 HValue* value = Pop(); | 4538 HValue* value = Pop(); |
| 4661 HInstruction* instr = NULL; | 4539 HInstruction* instr = NULL; |
| 4662 switch (op) { | 4540 switch (op) { |
| 4663 case Token::BIT_NOT: | 4541 case Token::BIT_NOT: |
| 4664 instr = new HBitNot(value); | 4542 instr = new HBitNot(value); |
| 4665 break; | 4543 break; |
| 4666 case Token::SUB: | 4544 case Token::SUB: |
| 4667 instr = new HMul(graph_->GetConstantMinus1(), value); | 4545 instr = new HMul(graph_->GetConstantMinus1(), value); |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4936 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 4814 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 4937 if (is_logical_and) { | 4815 if (is_logical_and) { |
| 4938 VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false()); | 4816 VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false()); |
| 4939 } else { | 4817 } else { |
| 4940 VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right); | 4818 VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right); |
| 4941 } | 4819 } |
| 4942 eval_right->SetJoinId(expr->RightId()); | 4820 eval_right->SetJoinId(expr->RightId()); |
| 4943 | 4821 |
| 4944 // Translate right subexpression by visiting it in the same AST | 4822 // Translate right subexpression by visiting it in the same AST |
| 4945 // context as the entire expression. | 4823 // context as the entire expression. |
| 4946 subgraph()->set_exit_block(eval_right); | 4824 set_current_block(eval_right); |
| 4947 Visit(expr->right()); | 4825 Visit(expr->right()); |
| 4948 | 4826 |
| 4827 } else if (ast_context()->IsValue()) { |
| 4828 VISIT_FOR_VALUE(expr->left()); |
| 4829 ASSERT(current_block() != NULL); |
| 4830 |
| 4831 // We need an extra block to maintain edge-split form. |
| 4832 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 4833 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 4834 HTest* test = is_logical_and |
| 4835 ? new HTest(Top(), eval_right, empty_block) |
| 4836 : new HTest(Top(), empty_block, eval_right); |
| 4837 current_block()->Finish(test); |
| 4838 |
| 4839 set_current_block(eval_right); |
| 4840 Drop(1); // Value of the left subexpression. |
| 4841 VISIT_FOR_VALUE(expr->right()); |
| 4842 |
| 4843 HBasicBlock* join_block = |
| 4844 CreateJoin(empty_block, current_block(), expr->id()); |
| 4845 set_current_block(join_block); |
| 4846 ast_context()->ReturnValue(Pop()); |
| 4847 |
| 4949 } else { | 4848 } else { |
| 4950 VISIT_FOR_VALUE(expr->left()); | 4849 ASSERT(ast_context()->IsEffect()); |
| 4951 ASSERT(current_subgraph_->HasExit()); | 4850 // In an effect context, we don't need the value of the left |
| 4851 // subexpression, only its control flow and side effects. We need an |
| 4852 // extra block to maintain edge-split form. |
| 4853 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 4854 HBasicBlock* right_block = graph()->CreateBasicBlock(); |
| 4855 HBasicBlock* join_block = graph()->CreateBasicBlock(); |
| 4856 if (is_logical_and) { |
| 4857 VISIT_FOR_CONTROL(expr->left(), right_block, empty_block); |
| 4858 } else { |
| 4859 VISIT_FOR_CONTROL(expr->left(), empty_block, right_block); |
| 4860 } |
| 4861 // TODO(kmillikin): Find a way to fix this. It's ugly that there are |
| 4862 // actually two empty blocks (one here and one inserted by |
| 4863 // TestContext::BuildBranch, and that they both have an HSimulate |
| 4864 // though the second one is not a merge node, and that we really have |
| 4865 // no good AST ID to put on that first HSimulate. |
| 4866 empty_block->SetJoinId(expr->id()); |
| 4867 right_block->SetJoinId(expr->RightId()); |
| 4868 set_current_block(right_block); |
| 4869 VISIT_FOR_EFFECT(expr->right()); |
| 4952 | 4870 |
| 4953 HValue* left = Top(); | 4871 empty_block->Goto(join_block); |
| 4954 HEnvironment* environment_copy = environment()->Copy(); | 4872 current_block()->Goto(join_block); |
| 4955 environment_copy->Pop(); | 4873 join_block->SetJoinId(expr->id()); |
| 4956 HSubgraph* right_subgraph; | 4874 set_current_block(join_block); |
| 4957 right_subgraph = CreateBranchSubgraph(environment_copy); | 4875 // We did not materialize any value in the predecessor environments, |
| 4958 ADD_TO_SUBGRAPH(right_subgraph, expr->right()); | 4876 // so there is no need to handle it here. |
| 4959 current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); | |
| 4960 current_subgraph_->exit_block()->SetJoinId(expr->id()); | |
| 4961 ast_context()->ReturnValue(Pop()); | |
| 4962 } | 4877 } |
| 4963 | 4878 |
| 4964 } else { | 4879 } else { |
| 4965 VISIT_FOR_VALUE(expr->left()); | 4880 VISIT_FOR_VALUE(expr->left()); |
| 4966 VISIT_FOR_VALUE(expr->right()); | 4881 VISIT_FOR_VALUE(expr->right()); |
| 4967 | 4882 |
| 4968 HValue* right = Pop(); | 4883 HValue* right = Pop(); |
| 4969 HValue* left = Pop(); | 4884 HValue* left = Pop(); |
| 4970 HInstruction* instr = BuildBinaryOperation(expr, left, right); | 4885 HInstruction* instr = BuildBinaryOperation(expr, left, right); |
| 4971 instr->set_position(expr->position()); | 4886 instr->set_position(expr->position()); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5029 return; | 4944 return; |
| 5030 } | 4945 } |
| 5031 | 4946 |
| 5032 VISIT_FOR_VALUE(expr->left()); | 4947 VISIT_FOR_VALUE(expr->left()); |
| 5033 VISIT_FOR_VALUE(expr->right()); | 4948 VISIT_FOR_VALUE(expr->right()); |
| 5034 | 4949 |
| 5035 HValue* right = Pop(); | 4950 HValue* right = Pop(); |
| 5036 HValue* left = Pop(); | 4951 HValue* left = Pop(); |
| 5037 Token::Value op = expr->op(); | 4952 Token::Value op = expr->op(); |
| 5038 | 4953 |
| 5039 TypeInfo info = oracle()->CompareType(expr); | 4954 TypeInfo type_info = oracle()->CompareType(expr); |
| 5040 HInstruction* instr = NULL; | 4955 HInstruction* instr = NULL; |
| 5041 if (op == Token::INSTANCEOF) { | 4956 if (op == Token::INSTANCEOF) { |
| 5042 // Check to see if the rhs of the instanceof is a global function not | 4957 // Check to see if the rhs of the instanceof is a global function not |
| 5043 // residing in new space. If it is we assume that the function will stay the | 4958 // residing in new space. If it is we assume that the function will stay the |
| 5044 // same. | 4959 // same. |
| 5045 Handle<JSFunction> target = Handle<JSFunction>::null(); | 4960 Handle<JSFunction> target = Handle<JSFunction>::null(); |
| 5046 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); | 4961 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); |
| 5047 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); | 4962 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); |
| 5048 CompilationInfo* info = graph()->info(); | |
| 5049 if (global_function && | 4963 if (global_function && |
| 5050 info->has_global_object() && | 4964 info()->has_global_object() && |
| 5051 !info->global_object()->IsAccessCheckNeeded()) { | 4965 !info()->global_object()->IsAccessCheckNeeded()) { |
| 5052 Handle<String> name = var->name(); | 4966 Handle<String> name = var->name(); |
| 5053 Handle<GlobalObject> global(info->global_object()); | 4967 Handle<GlobalObject> global(info()->global_object()); |
| 5054 LookupResult lookup; | 4968 LookupResult lookup; |
| 5055 global->Lookup(*name, &lookup); | 4969 global->Lookup(*name, &lookup); |
| 5056 if (lookup.IsProperty() && | 4970 if (lookup.IsProperty() && |
| 5057 lookup.type() == NORMAL && | 4971 lookup.type() == NORMAL && |
| 5058 lookup.GetValue()->IsJSFunction()) { | 4972 lookup.GetValue()->IsJSFunction()) { |
| 5059 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); | 4973 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
| 5060 // If the function is in new space we assume it's more likely to | 4974 // If the function is in new space we assume it's more likely to |
| 5061 // change and thus prefer the general IC code. | 4975 // change and thus prefer the general IC code. |
| 5062 if (!Heap::InNewSpace(*candidate)) { | 4976 if (!Heap::InNewSpace(*candidate)) { |
| 5063 target = candidate; | 4977 target = candidate; |
| 5064 } | 4978 } |
| 5065 } | 4979 } |
| 5066 } | 4980 } |
| 5067 | 4981 |
| 5068 // If the target is not null we have found a known global function that is | 4982 // If the target is not null we have found a known global function that is |
| 5069 // assumed to stay the same for this instanceof. | 4983 // assumed to stay the same for this instanceof. |
| 5070 if (target.is_null()) { | 4984 if (target.is_null()) { |
| 5071 HContext* context = new HContext; | 4985 HContext* context = new HContext; |
| 5072 AddInstruction(context); | 4986 AddInstruction(context); |
| 5073 instr = new HInstanceOf(context, left, right); | 4987 instr = new HInstanceOf(context, left, right); |
| 5074 } else { | 4988 } else { |
| 5075 AddInstruction(new HCheckFunction(right, target)); | 4989 AddInstruction(new HCheckFunction(right, target)); |
| 5076 instr = new HInstanceOfKnownGlobal(left, target); | 4990 instr = new HInstanceOfKnownGlobal(left, target); |
| 5077 } | 4991 } |
| 5078 } else if (op == Token::IN) { | 4992 } else if (op == Token::IN) { |
| 5079 BAILOUT("Unsupported comparison: in"); | 4993 BAILOUT("Unsupported comparison: in"); |
| 5080 } else if (info.IsNonPrimitive()) { | 4994 } else if (type_info.IsNonPrimitive()) { |
| 5081 switch (op) { | 4995 switch (op) { |
| 5082 case Token::EQ: | 4996 case Token::EQ: |
| 5083 case Token::EQ_STRICT: { | 4997 case Token::EQ_STRICT: { |
| 5084 AddInstruction(new HCheckNonSmi(left)); | 4998 AddInstruction(new HCheckNonSmi(left)); |
| 5085 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); | 4999 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); |
| 5086 AddInstruction(new HCheckNonSmi(right)); | 5000 AddInstruction(new HCheckNonSmi(right)); |
| 5087 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); | 5001 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); |
| 5088 instr = new HCompareJSObjectEq(left, right); | 5002 instr = new HCompareJSObjectEq(left, right); |
| 5089 break; | 5003 break; |
| 5090 } | 5004 } |
| 5091 default: | 5005 default: |
| 5092 BAILOUT("Unsupported non-primitive compare"); | 5006 BAILOUT("Unsupported non-primitive compare"); |
| 5093 break; | 5007 break; |
| 5094 } | 5008 } |
| 5095 } else { | 5009 } else { |
| 5096 HCompare* compare = new HCompare(left, right, op); | 5010 HCompare* compare = new HCompare(left, right, op); |
| 5097 Representation r = ToRepresentation(info); | 5011 Representation r = ToRepresentation(type_info); |
| 5098 compare->SetInputRepresentation(r); | 5012 compare->SetInputRepresentation(r); |
| 5099 instr = compare; | 5013 instr = compare; |
| 5100 } | 5014 } |
| 5101 instr->set_position(expr->position()); | 5015 instr->set_position(expr->position()); |
| 5102 ast_context()->ReturnInstruction(instr, expr->id()); | 5016 ast_context()->ReturnInstruction(instr, expr->id()); |
| 5103 } | 5017 } |
| 5104 | 5018 |
| 5105 | 5019 |
| 5106 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { | 5020 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { |
| 5107 VISIT_FOR_VALUE(expr->expression()); | 5021 VISIT_FOR_VALUE(expr->expression()); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 5128 (slot != NULL && slot->type() == Slot::LOOKUP) || | 5042 (slot != NULL && slot->type() == Slot::LOOKUP) || |
| 5129 decl->mode() == Variable::CONST || | 5043 decl->mode() == Variable::CONST || |
| 5130 decl->fun() != NULL) { | 5044 decl->fun() != NULL) { |
| 5131 BAILOUT("unsupported declaration"); | 5045 BAILOUT("unsupported declaration"); |
| 5132 } | 5046 } |
| 5133 } | 5047 } |
| 5134 | 5048 |
| 5135 | 5049 |
| 5136 // Generators for inline runtime functions. | 5050 // Generators for inline runtime functions. |
| 5137 // Support for types. | 5051 // Support for types. |
| 5138 void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) { | 5052 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { |
| 5139 ASSERT(argument_count == 1); | 5053 ASSERT(call->arguments()->length() == 1); |
| 5054 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5140 HValue* value = Pop(); | 5055 HValue* value = Pop(); |
| 5141 HIsSmi* result = new HIsSmi(value); | 5056 HIsSmi* result = new HIsSmi(value); |
| 5142 ast_context()->ReturnInstruction(result, ast_id); | 5057 ast_context()->ReturnInstruction(result, call->id()); |
| 5143 } | 5058 } |
| 5144 | 5059 |
| 5145 | 5060 |
| 5146 void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) { | 5061 void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { |
| 5147 ASSERT(argument_count == 1); | 5062 ASSERT(call->arguments()->length() == 1); |
| 5063 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5148 HValue* value = Pop(); | 5064 HValue* value = Pop(); |
| 5149 HHasInstanceType* result = | 5065 HHasInstanceType* result = |
| 5150 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); | 5066 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); |
| 5151 ast_context()->ReturnInstruction(result, ast_id); | 5067 ast_context()->ReturnInstruction(result, call->id()); |
| 5152 } | 5068 } |
| 5153 | 5069 |
| 5154 | 5070 |
| 5155 void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) { | 5071 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { |
| 5156 ASSERT(argument_count == 1); | 5072 ASSERT(call->arguments()->length() == 1); |
| 5073 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5157 HValue* value = Pop(); | 5074 HValue* value = Pop(); |
| 5158 HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); | 5075 HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); |
| 5159 ast_context()->ReturnInstruction(result, ast_id); | 5076 ast_context()->ReturnInstruction(result, call->id()); |
| 5160 } | 5077 } |
| 5161 | 5078 |
| 5162 | 5079 |
| 5163 void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count, | 5080 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { |
| 5164 int ast_id) { | 5081 ASSERT(call->arguments()->length() == 1); |
| 5165 ASSERT(argument_count == 1); | 5082 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5166 HValue* value = Pop(); | 5083 HValue* value = Pop(); |
| 5167 HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); | 5084 HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); |
| 5168 ast_context()->ReturnInstruction(result, ast_id); | 5085 ast_context()->ReturnInstruction(result, call->id()); |
| 5169 } | 5086 } |
| 5170 | 5087 |
| 5171 | 5088 |
| 5172 void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) { | 5089 void HGraphBuilder::GenerateIsArray(CallRuntime* call) { |
| 5173 ASSERT(argument_count == 1); | 5090 ASSERT(call->arguments()->length() == 1); |
| 5091 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5174 HValue* value = Pop(); | 5092 HValue* value = Pop(); |
| 5175 HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); | 5093 HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); |
| 5176 ast_context()->ReturnInstruction(result, ast_id); | 5094 ast_context()->ReturnInstruction(result, call->id()); |
| 5177 } | 5095 } |
| 5178 | 5096 |
| 5179 | 5097 |
| 5180 void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { | 5098 void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) { |
| 5181 ASSERT(argument_count == 1); | 5099 ASSERT(call->arguments()->length() == 1); |
| 5100 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5182 HValue* value = Pop(); | 5101 HValue* value = Pop(); |
| 5183 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); | 5102 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); |
| 5184 ast_context()->ReturnInstruction(result, ast_id); | 5103 ast_context()->ReturnInstruction(result, call->id()); |
| 5185 } | 5104 } |
| 5186 | 5105 |
| 5187 | 5106 |
| 5188 void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { | 5107 void HGraphBuilder::GenerateIsObject(CallRuntime* call) { |
| 5189 ASSERT(argument_count == 1); | 5108 ASSERT(call->arguments()->length() == 1); |
| 5190 | 5109 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5191 HValue* value = Pop(); | 5110 HValue* value = Pop(); |
| 5192 HIsObject* test = new HIsObject(value); | 5111 HIsObject* test = new HIsObject(value); |
| 5193 ast_context()->ReturnInstruction(test, ast_id); | 5112 ast_context()->ReturnInstruction(test, call->id()); |
| 5194 } | 5113 } |
| 5195 | 5114 |
| 5196 | 5115 |
| 5197 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, | 5116 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { |
| 5198 int ast_id) { | |
| 5199 BAILOUT("inlined runtime function: IsNonNegativeSmi"); | 5117 BAILOUT("inlined runtime function: IsNonNegativeSmi"); |
| 5200 } | 5118 } |
| 5201 | 5119 |
| 5202 | 5120 |
| 5203 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, | 5121 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { |
| 5204 int ast_id) { | |
| 5205 BAILOUT("inlined runtime function: IsUndetectableObject"); | 5122 BAILOUT("inlined runtime function: IsUndetectableObject"); |
| 5206 } | 5123 } |
| 5207 | 5124 |
| 5208 | 5125 |
| 5209 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 5126 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 5210 int argument_count, | 5127 CallRuntime* call) { |
| 5211 int ast_id) { | |
| 5212 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 5128 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 5213 } | 5129 } |
| 5214 | 5130 |
| 5215 | 5131 |
| 5216 // Support for construct call checks. | 5132 // Support for construct call checks. |
| 5217 void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { | 5133 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { |
| 5218 ASSERT(argument_count == 0); | 5134 ASSERT(call->arguments()->length() == 0); |
| 5219 ast_context()->ReturnInstruction(new HIsConstructCall, ast_id); | 5135 ast_context()->ReturnInstruction(new HIsConstructCall, call->id()); |
| 5220 } | 5136 } |
| 5221 | 5137 |
| 5222 | 5138 |
| 5223 // Support for arguments.length and arguments[?]. | 5139 // Support for arguments.length and arguments[?]. |
| 5224 void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { | 5140 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
| 5225 ASSERT(argument_count == 0); | 5141 ASSERT(call->arguments()->length() == 0); |
| 5226 HInstruction* elements = AddInstruction(new HArgumentsElements); | 5142 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 5227 HArgumentsLength* result = new HArgumentsLength(elements); | 5143 HArgumentsLength* result = new HArgumentsLength(elements); |
| 5228 ast_context()->ReturnInstruction(result, ast_id); | 5144 ast_context()->ReturnInstruction(result, call->id()); |
| 5229 } | 5145 } |
| 5230 | 5146 |
| 5231 | 5147 |
| 5232 void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) { | 5148 void HGraphBuilder::GenerateArguments(CallRuntime* call) { |
| 5233 ASSERT(argument_count == 1); | 5149 ASSERT(call->arguments()->length() == 1); |
| 5150 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5234 HValue* index = Pop(); | 5151 HValue* index = Pop(); |
| 5235 HInstruction* elements = AddInstruction(new HArgumentsElements); | 5152 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 5236 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 5153 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 5237 HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); | 5154 HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); |
| 5238 ast_context()->ReturnInstruction(result, ast_id); | 5155 ast_context()->ReturnInstruction(result, call->id()); |
| 5239 } | 5156 } |
| 5240 | 5157 |
| 5241 | 5158 |
| 5242 // Support for accessing the class and value fields of an object. | 5159 // Support for accessing the class and value fields of an object. |
| 5243 void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) { | 5160 void HGraphBuilder::GenerateClassOf(CallRuntime* call) { |
| 5244 // The special form detected by IsClassOfTest is detected before we get here | 5161 // The special form detected by IsClassOfTest is detected before we get here |
| 5245 // and does not cause a bailout. | 5162 // and does not cause a bailout. |
| 5246 BAILOUT("inlined runtime function: ClassOf"); | 5163 BAILOUT("inlined runtime function: ClassOf"); |
| 5247 } | 5164 } |
| 5248 | 5165 |
| 5249 | 5166 |
| 5250 void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) { | 5167 void HGraphBuilder::GenerateValueOf(CallRuntime* call) { |
| 5251 ASSERT(argument_count == 1); | 5168 ASSERT(call->arguments()->length() == 1); |
| 5169 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5252 HValue* value = Pop(); | 5170 HValue* value = Pop(); |
| 5253 HValueOf* result = new HValueOf(value); | 5171 HValueOf* result = new HValueOf(value); |
| 5254 ast_context()->ReturnInstruction(result, ast_id); | 5172 ast_context()->ReturnInstruction(result, call->id()); |
| 5255 } | 5173 } |
| 5256 | 5174 |
| 5257 | 5175 |
| 5258 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { | 5176 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) { |
| 5259 BAILOUT("inlined runtime function: SetValueOf"); | 5177 BAILOUT("inlined runtime function: SetValueOf"); |
| 5260 } | 5178 } |
| 5261 | 5179 |
| 5262 | 5180 |
| 5263 // Fast support for charCodeAt(n). | 5181 // Fast support for charCodeAt(n). |
| 5264 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { | 5182 void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { |
| 5265 ASSERT(argument_count == 2); | 5183 ASSERT(call->arguments()->length() == 2); |
| 5184 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5185 VISIT_FOR_VALUE(call->arguments()->at(1)); |
| 5266 HValue* index = Pop(); | 5186 HValue* index = Pop(); |
| 5267 HValue* string = Pop(); | 5187 HValue* string = Pop(); |
| 5268 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); | 5188 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| 5269 ast_context()->ReturnInstruction(result, ast_id); | 5189 ast_context()->ReturnInstruction(result, call->id()); |
| 5270 } | 5190 } |
| 5271 | 5191 |
| 5272 | 5192 |
| 5273 // Fast support for string.charAt(n) and string[n]. | 5193 // Fast support for string.charAt(n) and string[n]. |
| 5274 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, | 5194 void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) { |
| 5275 int ast_id) { | 5195 ASSERT(call->arguments()->length() == 1); |
| 5276 BAILOUT("inlined runtime function: StringCharFromCode"); | 5196 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5197 HValue* char_code = Pop(); |
| 5198 HStringCharFromCode* result = new HStringCharFromCode(char_code); |
| 5199 ast_context()->ReturnInstruction(result, call->id()); |
| 5277 } | 5200 } |
| 5278 | 5201 |
| 5279 | 5202 |
| 5280 // Fast support for string.charAt(n) and string[n]. | 5203 // Fast support for string.charAt(n) and string[n]. |
| 5281 void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { | 5204 void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) { |
| 5282 ASSERT_EQ(2, argument_count); | 5205 ASSERT(call->arguments()->length() == 2); |
| 5283 HContext* context = new HContext; | 5206 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5284 AddInstruction(context); | 5207 VISIT_FOR_VALUE(call->arguments()->at(1)); |
| 5285 HCallStub* result = | 5208 HValue* index = Pop(); |
| 5286 new HCallStub(context, CodeStub::StringCharAt, argument_count); | 5209 HValue* string = Pop(); |
| 5287 PreProcessCall(result); | 5210 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); |
| 5288 ast_context()->ReturnInstruction(result, ast_id); | 5211 AddInstruction(char_code); |
| 5212 HStringCharFromCode* result = new HStringCharFromCode(char_code); |
| 5213 ast_context()->ReturnInstruction(result, call->id()); |
| 5289 } | 5214 } |
| 5290 | 5215 |
| 5291 | 5216 |
| 5292 // Fast support for object equality testing. | 5217 // Fast support for object equality testing. |
| 5293 void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { | 5218 void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) { |
| 5294 ASSERT(argument_count == 2); | 5219 ASSERT(call->arguments()->length() == 2); |
| 5220 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5221 VISIT_FOR_VALUE(call->arguments()->at(1)); |
| 5295 HValue* right = Pop(); | 5222 HValue* right = Pop(); |
| 5296 HValue* left = Pop(); | 5223 HValue* left = Pop(); |
| 5297 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); | 5224 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); |
| 5298 ast_context()->ReturnInstruction(result, ast_id); | 5225 ast_context()->ReturnInstruction(result, call->id()); |
| 5299 } | 5226 } |
| 5300 | 5227 |
| 5301 | 5228 |
| 5302 void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { | 5229 void HGraphBuilder::GenerateLog(CallRuntime* call) { |
| 5303 UNREACHABLE(); // We caught this in VisitCallRuntime. | 5230 // %_Log is ignored in optimized code. |
| 5231 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 5304 } | 5232 } |
| 5305 | 5233 |
| 5306 | 5234 |
| 5307 // Fast support for Math.random(). | 5235 // Fast support for Math.random(). |
| 5308 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { | 5236 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { |
| 5309 BAILOUT("inlined runtime function: RandomHeapNumber"); | 5237 BAILOUT("inlined runtime function: RandomHeapNumber"); |
| 5310 } | 5238 } |
| 5311 | 5239 |
| 5312 | 5240 |
| 5313 // Fast support for StringAdd. | 5241 // Fast support for StringAdd. |
| 5314 void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { | 5242 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
| 5315 ASSERT_EQ(2, argument_count); | 5243 ASSERT_EQ(2, call->arguments()->length()); |
| 5244 VisitArgumentList(call->arguments()); |
| 5245 CHECK_BAILOUT; |
| 5246 HContext* context = new HContext; |
| 5247 AddInstruction(context); |
| 5248 HCallStub* result = new HCallStub(context, CodeStub::StringAdd, 2); |
| 5249 Drop(2); |
| 5250 ast_context()->ReturnInstruction(result, call->id()); |
| 5251 } |
| 5252 |
| 5253 |
| 5254 // Fast support for SubString. |
| 5255 void HGraphBuilder::GenerateSubString(CallRuntime* call) { |
| 5256 ASSERT_EQ(3, call->arguments()->length()); |
| 5257 VisitArgumentList(call->arguments()); |
| 5258 CHECK_BAILOUT; |
| 5259 HContext* context = new HContext; |
| 5260 AddInstruction(context); |
| 5261 HCallStub* result = new HCallStub(context, CodeStub::SubString, 3); |
| 5262 Drop(3); |
| 5263 ast_context()->ReturnInstruction(result, call->id()); |
| 5264 } |
| 5265 |
| 5266 |
| 5267 // Fast support for StringCompare. |
| 5268 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) { |
| 5269 ASSERT_EQ(2, call->arguments()->length()); |
| 5270 VisitArgumentList(call->arguments()); |
| 5271 CHECK_BAILOUT; |
| 5272 HContext* context = new HContext; |
| 5273 AddInstruction(context); |
| 5274 HCallStub* result = new HCallStub(context, CodeStub::StringCompare, 2); |
| 5275 Drop(2); |
| 5276 ast_context()->ReturnInstruction(result, call->id()); |
| 5277 } |
| 5278 |
| 5279 |
| 5280 // Support for direct calls from JavaScript to native RegExp code. |
| 5281 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) { |
| 5282 ASSERT_EQ(4, call->arguments()->length()); |
| 5283 VisitArgumentList(call->arguments()); |
| 5284 CHECK_BAILOUT; |
| 5285 HContext* context = new HContext; |
| 5286 AddInstruction(context); |
| 5287 HCallStub* result = new HCallStub(context, CodeStub::RegExpExec, 4); |
| 5288 Drop(4); |
| 5289 ast_context()->ReturnInstruction(result, call->id()); |
| 5290 } |
| 5291 |
| 5292 |
| 5293 // Construct a RegExp exec result with two in-object properties. |
| 5294 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { |
| 5295 ASSERT_EQ(3, call->arguments()->length()); |
| 5296 VisitArgumentList(call->arguments()); |
| 5297 CHECK_BAILOUT; |
| 5316 HContext* context = new HContext; | 5298 HContext* context = new HContext; |
| 5317 AddInstruction(context); | 5299 AddInstruction(context); |
| 5318 HCallStub* result = | 5300 HCallStub* result = |
| 5319 new HCallStub(context, CodeStub::StringAdd, argument_count); | 5301 new HCallStub(context, CodeStub::RegExpConstructResult, 3); |
| 5320 PreProcessCall(result); | 5302 Drop(3); |
| 5321 ast_context()->ReturnInstruction(result, ast_id); | 5303 ast_context()->ReturnInstruction(result, call->id()); |
| 5322 } | |
| 5323 | |
| 5324 | |
| 5325 // Fast support for SubString. | |
| 5326 void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { | |
| 5327 ASSERT_EQ(3, argument_count); | |
| 5328 HContext* context = new HContext; | |
| 5329 AddInstruction(context); | |
| 5330 HCallStub* result = | |
| 5331 new HCallStub(context, CodeStub::SubString, argument_count); | |
| 5332 PreProcessCall(result); | |
| 5333 ast_context()->ReturnInstruction(result, ast_id); | |
| 5334 } | |
| 5335 | |
| 5336 | |
| 5337 // Fast support for StringCompare. | |
| 5338 void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { | |
| 5339 ASSERT_EQ(2, argument_count); | |
| 5340 HContext* context = new HContext; | |
| 5341 AddInstruction(context); | |
| 5342 HCallStub* result = | |
| 5343 new HCallStub(context, CodeStub::StringCompare, argument_count); | |
| 5344 PreProcessCall(result); | |
| 5345 ast_context()->ReturnInstruction(result, ast_id); | |
| 5346 } | |
| 5347 | |
| 5348 | |
| 5349 // Support for direct calls from JavaScript to native RegExp code. | |
| 5350 void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { | |
| 5351 ASSERT_EQ(4, argument_count); | |
| 5352 HContext* context = new HContext; | |
| 5353 AddInstruction(context); | |
| 5354 HCallStub* result = | |
| 5355 new HCallStub(context, CodeStub::RegExpExec, argument_count); | |
| 5356 PreProcessCall(result); | |
| 5357 ast_context()->ReturnInstruction(result, ast_id); | |
| 5358 } | |
| 5359 | |
| 5360 | |
| 5361 // Construct a RegExp exec result with two in-object properties. | |
| 5362 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, | |
| 5363 int ast_id) { | |
| 5364 ASSERT_EQ(3, argument_count); | |
| 5365 HContext* context = new HContext; | |
| 5366 AddInstruction(context); | |
| 5367 HCallStub* result = | |
| 5368 new HCallStub(context, CodeStub::RegExpConstructResult, argument_count); | |
| 5369 PreProcessCall(result); | |
| 5370 ast_context()->ReturnInstruction(result, ast_id); | |
| 5371 } | 5304 } |
| 5372 | 5305 |
| 5373 | 5306 |
| 5374 // Support for fast native caches. | 5307 // Support for fast native caches. |
| 5375 void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { | 5308 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) { |
| 5376 BAILOUT("inlined runtime function: GetFromCache"); | 5309 BAILOUT("inlined runtime function: GetFromCache"); |
| 5377 } | 5310 } |
| 5378 | 5311 |
| 5379 | 5312 |
| 5380 // Fast support for number to string. | 5313 // Fast support for number to string. |
| 5381 void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { | 5314 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) { |
| 5382 ASSERT_EQ(1, argument_count); | 5315 ASSERT_EQ(1, call->arguments()->length()); |
| 5383 HContext* context = new HContext; | 5316 VisitArgumentList(call->arguments()); |
| 5384 AddInstruction(context); | 5317 CHECK_BAILOUT; |
| 5385 HCallStub* result = | 5318 HContext* context = new HContext; |
| 5386 new HCallStub(context, CodeStub::NumberToString, argument_count); | 5319 AddInstruction(context); |
| 5387 PreProcessCall(result); | 5320 HCallStub* result = new HCallStub(context, CodeStub::NumberToString, 1); |
| 5388 ast_context()->ReturnInstruction(result, ast_id); | 5321 Drop(1); |
| 5322 ast_context()->ReturnInstruction(result, call->id()); |
| 5389 } | 5323 } |
| 5390 | 5324 |
| 5391 | 5325 |
| 5392 // Fast swapping of elements. Takes three expressions, the object and two | 5326 // Fast swapping of elements. Takes three expressions, the object and two |
| 5393 // indices. This should only be used if the indices are known to be | 5327 // indices. This should only be used if the indices are known to be |
| 5394 // non-negative and within bounds of the elements array at the call site. | 5328 // non-negative and within bounds of the elements array at the call site. |
| 5395 void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { | 5329 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) { |
| 5396 BAILOUT("inlined runtime function: SwapElements"); | 5330 BAILOUT("inlined runtime function: SwapElements"); |
| 5397 } | 5331 } |
| 5398 | 5332 |
| 5399 | 5333 |
| 5400 // Fast call for custom callbacks. | 5334 // Fast call for custom callbacks. |
| 5401 void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) { | 5335 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) { |
| 5402 BAILOUT("inlined runtime function: CallFunction"); | 5336 BAILOUT("inlined runtime function: CallFunction"); |
| 5403 } | 5337 } |
| 5404 | 5338 |
| 5405 | 5339 |
| 5406 // Fast call to math functions. | 5340 // Fast call to math functions. |
| 5407 void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) { | 5341 void HGraphBuilder::GenerateMathPow(CallRuntime* call) { |
| 5408 ASSERT_EQ(2, argument_count); | 5342 ASSERT_EQ(2, call->arguments()->length()); |
| 5343 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5344 VISIT_FOR_VALUE(call->arguments()->at(1)); |
| 5409 HValue* right = Pop(); | 5345 HValue* right = Pop(); |
| 5410 HValue* left = Pop(); | 5346 HValue* left = Pop(); |
| 5411 HPower* result = new HPower(left, right); | 5347 HPower* result = new HPower(left, right); |
| 5412 ast_context()->ReturnInstruction(result, ast_id); | 5348 ast_context()->ReturnInstruction(result, call->id()); |
| 5413 } | 5349 } |
| 5414 | 5350 |
| 5415 | 5351 |
| 5416 void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { | 5352 void HGraphBuilder::GenerateMathSin(CallRuntime* call) { |
| 5417 ASSERT_EQ(1, argument_count); | 5353 ASSERT_EQ(1, call->arguments()->length()); |
| 5418 HContext* context = new HContext; | 5354 VisitArgumentList(call->arguments()); |
| 5419 AddInstruction(context); | 5355 CHECK_BAILOUT; |
| 5420 HCallStub* result = | 5356 HContext* context = new HContext; |
| 5421 new HCallStub(context, CodeStub::TranscendentalCache, argument_count); | 5357 AddInstruction(context); |
| 5358 HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5422 result->set_transcendental_type(TranscendentalCache::SIN); | 5359 result->set_transcendental_type(TranscendentalCache::SIN); |
| 5423 PreProcessCall(result); | 5360 Drop(1); |
| 5424 ast_context()->ReturnInstruction(result, ast_id); | 5361 ast_context()->ReturnInstruction(result, call->id()); |
| 5425 } | 5362 } |
| 5426 | 5363 |
| 5427 | 5364 |
| 5428 void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { | 5365 void HGraphBuilder::GenerateMathCos(CallRuntime* call) { |
| 5429 ASSERT_EQ(1, argument_count); | 5366 ASSERT_EQ(1, call->arguments()->length()); |
| 5430 HContext* context = new HContext; | 5367 VisitArgumentList(call->arguments()); |
| 5431 AddInstruction(context); | 5368 CHECK_BAILOUT; |
| 5432 HCallStub* result = | 5369 HContext* context = new HContext; |
| 5433 new HCallStub(context, CodeStub::TranscendentalCache, argument_count); | 5370 AddInstruction(context); |
| 5371 HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5434 result->set_transcendental_type(TranscendentalCache::COS); | 5372 result->set_transcendental_type(TranscendentalCache::COS); |
| 5435 PreProcessCall(result); | 5373 Drop(1); |
| 5436 ast_context()->ReturnInstruction(result, ast_id); | 5374 ast_context()->ReturnInstruction(result, call->id()); |
| 5437 } | 5375 } |
| 5438 | 5376 |
| 5439 | 5377 |
| 5440 void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { | 5378 void HGraphBuilder::GenerateMathLog(CallRuntime* call) { |
| 5441 ASSERT_EQ(1, argument_count); | 5379 ASSERT_EQ(1, call->arguments()->length()); |
| 5442 HContext* context = new HContext; | 5380 VisitArgumentList(call->arguments()); |
| 5443 AddInstruction(context); | 5381 CHECK_BAILOUT; |
| 5444 HCallStub* result = | 5382 HContext* context = new HContext; |
| 5445 new HCallStub(context, CodeStub::TranscendentalCache, argument_count); | 5383 AddInstruction(context); |
| 5384 HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5446 result->set_transcendental_type(TranscendentalCache::LOG); | 5385 result->set_transcendental_type(TranscendentalCache::LOG); |
| 5447 PreProcessCall(result); | 5386 Drop(1); |
| 5448 ast_context()->ReturnInstruction(result, ast_id); | 5387 ast_context()->ReturnInstruction(result, call->id()); |
| 5449 } | 5388 } |
| 5450 | 5389 |
| 5451 | 5390 |
| 5452 void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { | 5391 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
| 5453 BAILOUT("inlined runtime function: MathSqrt"); | 5392 BAILOUT("inlined runtime function: MathSqrt"); |
| 5454 } | 5393 } |
| 5455 | 5394 |
| 5456 | 5395 |
| 5457 // Check whether two RegExps are equivalent | 5396 // Check whether two RegExps are equivalent |
| 5458 void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count, | 5397 void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { |
| 5459 int ast_id) { | |
| 5460 BAILOUT("inlined runtime function: IsRegExpEquivalent"); | 5398 BAILOUT("inlined runtime function: IsRegExpEquivalent"); |
| 5461 } | 5399 } |
| 5462 | 5400 |
| 5463 | 5401 |
| 5464 void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count, | 5402 void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { |
| 5465 int ast_id) { | 5403 ASSERT(call->arguments()->length() == 1); |
| 5466 BAILOUT("inlined runtime function: GetCachedArrayIndex"); | 5404 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 5467 } | 5405 HValue* value = Pop(); |
| 5468 | 5406 HGetCachedArrayIndex* result = new HGetCachedArrayIndex(value); |
| 5469 | 5407 ast_context()->ReturnInstruction(result, call->id()); |
| 5470 void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count, | 5408 } |
| 5471 int ast_id) { | 5409 |
| 5410 |
| 5411 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { |
| 5472 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); | 5412 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); |
| 5473 } | 5413 } |
| 5474 | 5414 |
| 5475 | 5415 |
| 5476 #undef BAILOUT | 5416 #undef BAILOUT |
| 5477 #undef CHECK_BAILOUT | 5417 #undef CHECK_BAILOUT |
| 5478 #undef VISIT_FOR_EFFECT | 5418 #undef VISIT_FOR_EFFECT |
| 5479 #undef VISIT_FOR_VALUE | 5419 #undef VISIT_FOR_VALUE |
| 5480 #undef ADD_TO_SUBGRAPH | 5420 #undef ADD_TO_SUBGRAPH |
| 5481 | 5421 |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5812 } | 5752 } |
| 5813 } | 5753 } |
| 5814 } | 5754 } |
| 5815 } | 5755 } |
| 5816 | 5756 |
| 5817 | 5757 |
| 5818 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) { | 5758 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) { |
| 5819 Tag tag(this, "intervals"); | 5759 Tag tag(this, "intervals"); |
| 5820 PrintStringProperty("name", name); | 5760 PrintStringProperty("name", name); |
| 5821 | 5761 |
| 5822 const ZoneList<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges(); | 5762 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges(); |
| 5823 for (int i = 0; i < fixed_d->length(); ++i) { | 5763 for (int i = 0; i < fixed_d->length(); ++i) { |
| 5824 TraceLiveRange(fixed_d->at(i), "fixed"); | 5764 TraceLiveRange(fixed_d->at(i), "fixed"); |
| 5825 } | 5765 } |
| 5826 | 5766 |
| 5827 const ZoneList<LiveRange*>* fixed = allocator->fixed_live_ranges(); | 5767 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges(); |
| 5828 for (int i = 0; i < fixed->length(); ++i) { | 5768 for (int i = 0; i < fixed->length(); ++i) { |
| 5829 TraceLiveRange(fixed->at(i), "fixed"); | 5769 TraceLiveRange(fixed->at(i), "fixed"); |
| 5830 } | 5770 } |
| 5831 | 5771 |
| 5832 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges(); | 5772 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges(); |
| 5833 for (int i = 0; i < live_ranges->length(); ++i) { | 5773 for (int i = 0; i < live_ranges->length(); ++i) { |
| 5834 TraceLiveRange(live_ranges->at(i), "object"); | 5774 TraceLiveRange(live_ranges->at(i), "object"); |
| 5835 } | 5775 } |
| 5836 } | 5776 } |
| 5837 | 5777 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 5862 if (range->IsChild()) { | 5802 if (range->IsChild()) { |
| 5863 parent_index = range->parent()->id(); | 5803 parent_index = range->parent()->id(); |
| 5864 } else { | 5804 } else { |
| 5865 parent_index = range->id(); | 5805 parent_index = range->id(); |
| 5866 } | 5806 } |
| 5867 LOperand* op = range->FirstHint(); | 5807 LOperand* op = range->FirstHint(); |
| 5868 int hint_index = -1; | 5808 int hint_index = -1; |
| 5869 if (op != NULL && op->IsUnallocated()) hint_index = op->VirtualRegister(); | 5809 if (op != NULL && op->IsUnallocated()) hint_index = op->VirtualRegister(); |
| 5870 trace_.Add(" %d %d", parent_index, hint_index); | 5810 trace_.Add(" %d %d", parent_index, hint_index); |
| 5871 UseInterval* cur_interval = range->first_interval(); | 5811 UseInterval* cur_interval = range->first_interval(); |
| 5872 while (cur_interval != NULL) { | 5812 while (cur_interval != NULL && range->Covers(cur_interval->start())) { |
| 5873 trace_.Add(" [%d, %d[", | 5813 trace_.Add(" [%d, %d[", |
| 5874 cur_interval->start().Value(), | 5814 cur_interval->start().Value(), |
| 5875 cur_interval->end().Value()); | 5815 cur_interval->end().Value()); |
| 5876 cur_interval = cur_interval->next(); | 5816 cur_interval = cur_interval->next(); |
| 5877 } | 5817 } |
| 5878 | 5818 |
| 5879 UsePosition* current_pos = range->first_pos(); | 5819 UsePosition* current_pos = range->first_pos(); |
| 5880 while (current_pos != NULL) { | 5820 while (current_pos != NULL) { |
| 5881 if (current_pos->RegisterIsBeneficial()) { | 5821 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) { |
| 5882 trace_.Add(" %d M", current_pos->pos().Value()); | 5822 trace_.Add(" %d M", current_pos->pos().Value()); |
| 5883 } | 5823 } |
| 5884 current_pos = current_pos->next(); | 5824 current_pos = current_pos->next(); |
| 5885 } | 5825 } |
| 5886 | 5826 |
| 5887 trace_.Add(" \"\"\n"); | 5827 trace_.Add(" \"\"\n"); |
| 5888 } | 5828 } |
| 5889 } | 5829 } |
| 5890 | 5830 |
| 5891 | 5831 |
| 5892 void HTracer::FlushToFile() { | 5832 void HTracer::FlushToFile() { |
| 5893 AppendChars(filename_, *trace_.ToCString(), trace_.length(), false); | 5833 AppendChars(filename_, *trace_.ToCString(), trace_.length(), false); |
| 5894 trace_.Reset(); | 5834 trace_.Reset(); |
| 5895 } | 5835 } |
| 5896 | 5836 |
| 5897 | 5837 |
| 5838 void HStatistics::Initialize(CompilationInfo* info) { |
| 5839 source_size_ += info->shared_info()->SourceSize(); |
| 5840 } |
| 5841 |
| 5842 |
| 5898 void HStatistics::Print() { | 5843 void HStatistics::Print() { |
| 5899 PrintF("Timing results:\n"); | 5844 PrintF("Timing results:\n"); |
| 5900 int64_t sum = 0; | 5845 int64_t sum = 0; |
| 5901 for (int i = 0; i < timing_.length(); ++i) { | 5846 for (int i = 0; i < timing_.length(); ++i) { |
| 5902 sum += timing_[i]; | 5847 sum += timing_[i]; |
| 5903 } | 5848 } |
| 5904 | 5849 |
| 5905 for (int i = 0; i < names_.length(); ++i) { | 5850 for (int i = 0; i < names_.length(); ++i) { |
| 5906 PrintF("%30s", names_[i]); | 5851 PrintF("%30s", names_[i]); |
| 5907 double ms = static_cast<double>(timing_[i]) / 1000; | 5852 double ms = static_cast<double>(timing_[i]) / 1000; |
| 5908 double percent = static_cast<double>(timing_[i]) * 100 / sum; | 5853 double percent = static_cast<double>(timing_[i]) * 100 / sum; |
| 5909 PrintF(" - %7.3f ms / %4.1f %% ", ms, percent); | 5854 PrintF(" - %7.3f ms / %4.1f %% ", ms, percent); |
| 5910 | 5855 |
| 5911 unsigned size = sizes_[i]; | 5856 unsigned size = sizes_[i]; |
| 5912 double size_percent = static_cast<double>(size) * 100 / total_size_; | 5857 double size_percent = static_cast<double>(size) * 100 / total_size_; |
| 5913 PrintF(" %8u bytes / %4.1f %%\n", size, size_percent); | 5858 PrintF(" %8u bytes / %4.1f %%\n", size, size_percent); |
| 5914 } | 5859 } |
| 5915 PrintF("%30s - %7.3f ms %8u bytes\n", "Sum", | 5860 double source_size_in_kb = static_cast<double>(source_size_) / 1024; |
| 5916 static_cast<double>(sum) / 1000, | 5861 PrintF("%30s - %7.3f ms %7.3f bytes\n", "Sum", |
| 5917 total_size_); | 5862 (static_cast<double>(sum) / 1000) / source_size_in_kb, |
| 5863 total_size_ / source_size_in_kb); |
| 5918 PrintF("---------------------------------------------------------------\n"); | 5864 PrintF("---------------------------------------------------------------\n"); |
| 5919 PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", | 5865 PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", |
| 5920 "Total", | 5866 "Total", |
| 5921 static_cast<double>(total_) / 1000, | 5867 static_cast<double>(total_) / 1000, |
| 5922 static_cast<double>(total_) / full_code_gen_); | 5868 static_cast<double>(total_) / full_code_gen_); |
| 5923 } | 5869 } |
| 5924 | 5870 |
| 5925 | 5871 |
| 5926 void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { | 5872 void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { |
| 5927 if (name == HPhase::kFullCodeGen) { | 5873 if (name == HPhase::kFullCodeGen) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 5952 HGraph* graph, | 5898 HGraph* graph, |
| 5953 LChunk* chunk, | 5899 LChunk* chunk, |
| 5954 LAllocator* allocator) { | 5900 LAllocator* allocator) { |
| 5955 name_ = name; | 5901 name_ = name; |
| 5956 graph_ = graph; | 5902 graph_ = graph; |
| 5957 chunk_ = chunk; | 5903 chunk_ = chunk; |
| 5958 allocator_ = allocator; | 5904 allocator_ = allocator; |
| 5959 if (allocator != NULL && chunk_ == NULL) { | 5905 if (allocator != NULL && chunk_ == NULL) { |
| 5960 chunk_ = allocator->chunk(); | 5906 chunk_ = allocator->chunk(); |
| 5961 } | 5907 } |
| 5962 if (FLAG_time_hydrogen) start_ = OS::Ticks(); | 5908 if (FLAG_hydrogen_stats) start_ = OS::Ticks(); |
| 5963 start_allocation_size_ = Zone::allocation_size_; | 5909 start_allocation_size_ = Zone::allocation_size_; |
| 5964 } | 5910 } |
| 5965 | 5911 |
| 5966 | 5912 |
| 5967 void HPhase::End() const { | 5913 void HPhase::End() const { |
| 5968 if (FLAG_time_hydrogen) { | 5914 if (FLAG_hydrogen_stats) { |
| 5969 int64_t end = OS::Ticks(); | 5915 int64_t end = OS::Ticks(); |
| 5970 unsigned size = Zone::allocation_size_ - start_allocation_size_; | 5916 unsigned size = Zone::allocation_size_ - start_allocation_size_; |
| 5971 HStatistics::Instance()->SaveTiming(name_, end - start_, size); | 5917 HStatistics::Instance()->SaveTiming(name_, end - start_, size); |
| 5972 } | 5918 } |
| 5973 | 5919 |
| 5974 if (FLAG_trace_hydrogen) { | 5920 if (FLAG_trace_hydrogen) { |
| 5975 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); | 5921 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); |
| 5976 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); | 5922 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); |
| 5977 if (allocator_ != NULL) { | 5923 if (allocator_ != NULL) { |
| 5978 HTracer::Instance()->TraceLiveRanges(name_, allocator_); | 5924 HTracer::Instance()->TraceLiveRanges(name_, allocator_); |
| 5979 } | 5925 } |
| 5980 } | 5926 } |
| 5981 | 5927 |
| 5982 #ifdef DEBUG | 5928 #ifdef DEBUG |
| 5983 if (graph_ != NULL) graph_->Verify(); | 5929 if (graph_ != NULL) graph_->Verify(); |
| 5984 if (allocator_ != NULL) allocator_->Verify(); | 5930 if (allocator_ != NULL) allocator_->Verify(); |
| 5985 #endif | 5931 #endif |
| 5986 } | 5932 } |
| 5987 | 5933 |
| 5988 } } // namespace v8::internal | 5934 } } // namespace v8::internal |
| OLD | NEW |