Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: src/hydrogen.cc

Issue 6697023: Merge 6800:7180 from the bleeding edge branch to the experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698