| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 #include "hydrogen.h" | 29 #include "hydrogen.h" |
| 30 | 30 |
| 31 #include "codegen.h" | 31 #include "codegen.h" |
| 32 #include "full-codegen.h" | 32 #include "full-codegen.h" |
| 33 #include "hashmap.h" | 33 #include "hashmap.h" |
| 34 #include "lithium-allocator.h" | 34 #include "lithium-allocator.h" |
| 35 #include "parser.h" | 35 #include "parser.h" |
| 36 #include "scopeinfo.h" |
| 36 #include "scopes.h" | 37 #include "scopes.h" |
| 37 #include "stub-cache.h" | 38 #include "stub-cache.h" |
| 38 | 39 |
| 39 #if V8_TARGET_ARCH_IA32 | 40 #if V8_TARGET_ARCH_IA32 |
| 40 #include "ia32/lithium-codegen-ia32.h" | 41 #include "ia32/lithium-codegen-ia32.h" |
| 41 #elif V8_TARGET_ARCH_X64 | 42 #elif V8_TARGET_ARCH_X64 |
| 42 #include "x64/lithium-codegen-x64.h" | 43 #include "x64/lithium-codegen-x64.h" |
| 43 #elif V8_TARGET_ARCH_ARM | 44 #elif V8_TARGET_ARCH_ARM |
| 44 #include "arm/lithium-codegen-arm.h" | 45 #include "arm/lithium-codegen-arm.h" |
| 45 #elif V8_TARGET_ARCH_MIPS | 46 #elif V8_TARGET_ARCH_MIPS |
| (...skipping 15 matching lines...) Expand all Loading... |
| 61 loop_information_(NULL), | 62 loop_information_(NULL), |
| 62 predecessors_(2), | 63 predecessors_(2), |
| 63 dominator_(NULL), | 64 dominator_(NULL), |
| 64 dominated_blocks_(4), | 65 dominated_blocks_(4), |
| 65 last_environment_(NULL), | 66 last_environment_(NULL), |
| 66 argument_count_(-1), | 67 argument_count_(-1), |
| 67 first_instruction_index_(-1), | 68 first_instruction_index_(-1), |
| 68 last_instruction_index_(-1), | 69 last_instruction_index_(-1), |
| 69 deleted_phis_(4), | 70 deleted_phis_(4), |
| 70 parent_loop_header_(NULL), | 71 parent_loop_header_(NULL), |
| 71 is_inline_return_target_(false) { | 72 is_inline_return_target_(false), |
| 72 } | 73 is_deoptimizing_(false) { } |
| 73 | 74 |
| 74 | 75 |
| 75 void HBasicBlock::AttachLoopInformation() { | 76 void HBasicBlock::AttachLoopInformation() { |
| 76 ASSERT(!IsLoopHeader()); | 77 ASSERT(!IsLoopHeader()); |
| 77 loop_information_ = new(zone()) HLoopInformation(this); | 78 loop_information_ = new(zone()) HLoopInformation(this); |
| 78 } | 79 } |
| 79 | 80 |
| 80 | 81 |
| 81 void HBasicBlock::DetachLoopInformation() { | 82 void HBasicBlock::DetachLoopInformation() { |
| 82 ASSERT(IsLoopHeader()); | 83 ASSERT(IsLoopHeader()); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length()); | 125 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length()); |
| 125 for (int i = 0; i < environment->length(); i++) { | 126 for (int i = 0; i < environment->length(); i++) { |
| 126 HValue* val = environment->values()->at(i); | 127 HValue* val = environment->values()->at(i); |
| 127 instr->AddEnvironmentValue(val); | 128 instr->AddEnvironmentValue(val); |
| 128 } | 129 } |
| 129 | 130 |
| 130 return instr; | 131 return instr; |
| 131 } | 132 } |
| 132 | 133 |
| 133 | 134 |
| 134 HSimulate* HBasicBlock::CreateSimulate(int id) { | 135 HSimulate* HBasicBlock::CreateSimulate(int ast_id) { |
| 135 ASSERT(HasEnvironment()); | 136 ASSERT(HasEnvironment()); |
| 136 HEnvironment* environment = last_environment(); | 137 HEnvironment* environment = last_environment(); |
| 137 ASSERT(id == AstNode::kNoNumber || | 138 ASSERT(ast_id == AstNode::kNoNumber || |
| 138 environment->closure()->shared()->VerifyBailoutId(id)); | 139 environment->closure()->shared()->VerifyBailoutId(ast_id)); |
| 139 | 140 |
| 140 int push_count = environment->push_count(); | 141 int push_count = environment->push_count(); |
| 141 int pop_count = environment->pop_count(); | 142 int pop_count = environment->pop_count(); |
| 142 | 143 |
| 143 HSimulate* instr = new(zone()) HSimulate(id, pop_count); | 144 HSimulate* instr = new(zone()) HSimulate(ast_id, pop_count); |
| 144 for (int i = push_count - 1; i >= 0; --i) { | 145 for (int i = push_count - 1; i >= 0; --i) { |
| 145 instr->AddPushedValue(environment->ExpressionStackAt(i)); | 146 instr->AddPushedValue(environment->ExpressionStackAt(i)); |
| 146 } | 147 } |
| 147 for (int i = 0; i < environment->assigned_variables()->length(); ++i) { | 148 for (int i = 0; i < environment->assigned_variables()->length(); ++i) { |
| 148 int index = environment->assigned_variables()->at(i); | 149 int index = environment->assigned_variables()->at(i); |
| 149 instr->AddAssignedValue(index, environment->Lookup(index)); | 150 instr->AddAssignedValue(index, environment->Lookup(index)); |
| 150 } | 151 } |
| 151 environment->ClearHistory(); | 152 environment->ClearHistory(); |
| 152 return instr; | 153 return instr; |
| 153 } | 154 } |
| 154 | 155 |
| 155 | 156 |
| 156 void HBasicBlock::Finish(HControlInstruction* end) { | 157 void HBasicBlock::Finish(HControlInstruction* end) { |
| 157 ASSERT(!IsFinished()); | 158 ASSERT(!IsFinished()); |
| 158 AddInstruction(end); | 159 AddInstruction(end); |
| 159 end_ = end; | 160 end_ = end; |
| 160 if (end->FirstSuccessor() != NULL) { | 161 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { |
| 161 end->FirstSuccessor()->RegisterPredecessor(this); | 162 it.Current()->RegisterPredecessor(this); |
| 162 if (end->SecondSuccessor() != NULL) { | |
| 163 end->SecondSuccessor()->RegisterPredecessor(this); | |
| 164 } | |
| 165 } | 163 } |
| 166 } | 164 } |
| 167 | 165 |
| 168 | 166 |
| 169 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) { | 167 void HBasicBlock::Goto(HBasicBlock* block) { |
| 170 if (block->IsInlineReturnTarget()) { | 168 if (block->IsInlineReturnTarget()) { |
| 171 AddInstruction(new(zone()) HLeaveInlined); | 169 AddInstruction(new(zone()) HLeaveInlined); |
| 172 last_environment_ = last_environment()->outer(); | 170 last_environment_ = last_environment()->outer(); |
| 173 } | 171 } |
| 174 AddSimulate(AstNode::kNoNumber); | 172 AddSimulate(AstNode::kNoNumber); |
| 175 HGoto* instr = new(zone()) HGoto(block); | 173 HGoto* instr = new(zone()) HGoto(block); |
| 176 instr->set_include_stack_check(include_stack_check); | |
| 177 Finish(instr); | 174 Finish(instr); |
| 178 } | 175 } |
| 179 | 176 |
| 180 | 177 |
| 181 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 178 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 182 ASSERT(target->IsInlineReturnTarget()); | 179 ASSERT(target->IsInlineReturnTarget()); |
| 183 ASSERT(return_value != NULL); | 180 ASSERT(return_value != NULL); |
| 184 AddInstruction(new(zone()) HLeaveInlined); | 181 AddInstruction(new(zone()) HLeaveInlined); |
| 185 last_environment_ = last_environment()->outer(); | 182 last_environment_ = last_environment()->outer(); |
| 186 last_environment()->Push(return_value); | 183 last_environment()->Push(return_value); |
| 187 AddSimulate(AstNode::kNoNumber); | 184 AddSimulate(AstNode::kNoNumber); |
| 188 HGoto* instr = new(zone()) HGoto(target); | 185 HGoto* instr = new(zone()) HGoto(target); |
| 189 Finish(instr); | 186 Finish(instr); |
| 190 } | 187 } |
| 191 | 188 |
| 192 | 189 |
| 193 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { | 190 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { |
| 194 ASSERT(!HasEnvironment()); | 191 ASSERT(!HasEnvironment()); |
| 195 ASSERT(first() == NULL); | 192 ASSERT(first() == NULL); |
| 196 UpdateEnvironment(env); | 193 UpdateEnvironment(env); |
| 197 } | 194 } |
| 198 | 195 |
| 199 | 196 |
| 200 void HBasicBlock::SetJoinId(int id) { | 197 void HBasicBlock::SetJoinId(int ast_id) { |
| 201 int length = predecessors_.length(); | 198 int length = predecessors_.length(); |
| 202 ASSERT(length > 0); | 199 ASSERT(length > 0); |
| 203 for (int i = 0; i < length; i++) { | 200 for (int i = 0; i < length; i++) { |
| 204 HBasicBlock* predecessor = predecessors_[i]; | 201 HBasicBlock* predecessor = predecessors_[i]; |
| 205 ASSERT(predecessor->end()->IsGoto()); | 202 ASSERT(predecessor->end()->IsGoto()); |
| 206 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); | 203 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); |
| 207 // We only need to verify the ID once. | 204 // We only need to verify the ID once. |
| 208 ASSERT(i != 0 || | 205 ASSERT(i != 0 || |
| 209 predecessor->last_environment()->closure()->shared() | 206 predecessor->last_environment()->closure()->shared() |
| 210 ->VerifyBailoutId(id)); | 207 ->VerifyBailoutId(ast_id)); |
| 211 simulate->set_ast_id(id); | 208 simulate->set_ast_id(ast_id); |
| 212 } | 209 } |
| 213 } | 210 } |
| 214 | 211 |
| 215 | 212 |
| 216 bool HBasicBlock::Dominates(HBasicBlock* other) const { | 213 bool HBasicBlock::Dominates(HBasicBlock* other) const { |
| 217 HBasicBlock* current = other->dominator(); | 214 HBasicBlock* current = other->dominator(); |
| 218 while (current != NULL) { | 215 while (current != NULL) { |
| 219 if (current == this) return true; | 216 if (current == this) return true; |
| 220 current = current->dominator(); | 217 current = current->dominator(); |
| 221 } | 218 } |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 !reachable_.Contains(block->block_id())) { | 391 !reachable_.Contains(block->block_id())) { |
| 395 reachable_.Add(block->block_id()); | 392 reachable_.Add(block->block_id()); |
| 396 stack_.Add(block); | 393 stack_.Add(block); |
| 397 visited_count_++; | 394 visited_count_++; |
| 398 } | 395 } |
| 399 } | 396 } |
| 400 | 397 |
| 401 void Analyze() { | 398 void Analyze() { |
| 402 while (!stack_.is_empty()) { | 399 while (!stack_.is_empty()) { |
| 403 HControlInstruction* end = stack_.RemoveLast()->end(); | 400 HControlInstruction* end = stack_.RemoveLast()->end(); |
| 404 PushBlock(end->FirstSuccessor()); | 401 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { |
| 405 PushBlock(end->SecondSuccessor()); | 402 PushBlock(it.Current()); |
| 403 } |
| 406 } | 404 } |
| 407 } | 405 } |
| 408 | 406 |
| 409 int visited_count_; | 407 int visited_count_; |
| 410 ZoneList<HBasicBlock*> stack_; | 408 ZoneList<HBasicBlock*> stack_; |
| 411 BitVector reachable_; | 409 BitVector reachable_; |
| 412 HBasicBlock* dont_visit_; | 410 HBasicBlock* dont_visit_; |
| 413 }; | 411 }; |
| 414 | 412 |
| 415 | 413 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 514 | 512 |
| 515 HConstant* HGraph::GetConstantTrue() { | 513 HConstant* HGraph::GetConstantTrue() { |
| 516 return GetConstant(&constant_true_, isolate()->heap()->true_value()); | 514 return GetConstant(&constant_true_, isolate()->heap()->true_value()); |
| 517 } | 515 } |
| 518 | 516 |
| 519 | 517 |
| 520 HConstant* HGraph::GetConstantFalse() { | 518 HConstant* HGraph::GetConstantFalse() { |
| 521 return GetConstant(&constant_false_, isolate()->heap()->false_value()); | 519 return GetConstant(&constant_false_, isolate()->heap()->false_value()); |
| 522 } | 520 } |
| 523 | 521 |
| 522 |
| 523 HConstant* HGraph::GetConstantHole() { |
| 524 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); |
| 525 } |
| 526 |
| 527 |
| 524 HGraphBuilder::HGraphBuilder(CompilationInfo* info, | 528 HGraphBuilder::HGraphBuilder(CompilationInfo* info, |
| 525 TypeFeedbackOracle* oracle) | 529 TypeFeedbackOracle* oracle) |
| 526 : function_state_(NULL), | 530 : function_state_(NULL), |
| 527 initial_function_state_(this, info, oracle), | 531 initial_function_state_(this, info, oracle), |
| 528 ast_context_(NULL), | 532 ast_context_(NULL), |
| 529 break_scope_(NULL), | 533 break_scope_(NULL), |
| 530 graph_(NULL), | 534 graph_(NULL), |
| 531 current_block_(NULL), | 535 current_block_(NULL), |
| 532 inlined_count_(0), | 536 inlined_count_(0), |
| 533 zone_(info->isolate()->zone()), | 537 zone_(info->isolate()->zone()), |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 } | 569 } |
| 566 return exit_block; | 570 return exit_block; |
| 567 } | 571 } |
| 568 | 572 |
| 569 | 573 |
| 570 HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement, | 574 HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement, |
| 571 HBasicBlock* loop_entry, | 575 HBasicBlock* loop_entry, |
| 572 HBasicBlock* body_exit, | 576 HBasicBlock* body_exit, |
| 573 HBasicBlock* loop_successor, | 577 HBasicBlock* loop_successor, |
| 574 HBasicBlock* break_block) { | 578 HBasicBlock* break_block) { |
| 575 if (body_exit != NULL) body_exit->Goto(loop_entry, true); | 579 if (body_exit != NULL) body_exit->Goto(loop_entry); |
| 576 loop_entry->PostProcessLoopHeader(statement); | 580 loop_entry->PostProcessLoopHeader(statement); |
| 577 if (break_block != NULL) { | 581 if (break_block != NULL) { |
| 578 if (loop_successor != NULL) loop_successor->Goto(break_block); | 582 if (loop_successor != NULL) loop_successor->Goto(break_block); |
| 579 break_block->SetJoinId(statement->ExitId()); | 583 break_block->SetJoinId(statement->ExitId()); |
| 580 return break_block; | 584 return break_block; |
| 581 } | 585 } |
| 582 return loop_successor; | 586 return loop_successor; |
| 583 } | 587 } |
| 584 | 588 |
| 585 | 589 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 684 } | 688 } |
| 685 } | 689 } |
| 686 | 690 |
| 687 | 691 |
| 688 void HGraph::PostorderLoopBlocks(HLoopInformation* loop, | 692 void HGraph::PostorderLoopBlocks(HLoopInformation* loop, |
| 689 BitVector* visited, | 693 BitVector* visited, |
| 690 ZoneList<HBasicBlock*>* order, | 694 ZoneList<HBasicBlock*>* order, |
| 691 HBasicBlock* loop_header) { | 695 HBasicBlock* loop_header) { |
| 692 for (int i = 0; i < loop->blocks()->length(); ++i) { | 696 for (int i = 0; i < loop->blocks()->length(); ++i) { |
| 693 HBasicBlock* b = loop->blocks()->at(i); | 697 HBasicBlock* b = loop->blocks()->at(i); |
| 694 Postorder(b->end()->SecondSuccessor(), visited, order, loop_header); | 698 for (HSuccessorIterator it(b->end()); !it.Done(); it.Advance()) { |
| 695 Postorder(b->end()->FirstSuccessor(), visited, order, loop_header); | 699 Postorder(it.Current(), visited, order, loop_header); |
| 700 } |
| 696 if (b->IsLoopHeader() && b != loop->loop_header()) { | 701 if (b->IsLoopHeader() && b != loop->loop_header()) { |
| 697 PostorderLoopBlocks(b->loop_information(), visited, order, loop_header); | 702 PostorderLoopBlocks(b->loop_information(), visited, order, loop_header); |
| 698 } | 703 } |
| 699 } | 704 } |
| 700 } | 705 } |
| 701 | 706 |
| 702 | 707 |
| 703 void HGraph::Postorder(HBasicBlock* block, | 708 void HGraph::Postorder(HBasicBlock* block, |
| 704 BitVector* visited, | 709 BitVector* visited, |
| 705 ZoneList<HBasicBlock*>* order, | 710 ZoneList<HBasicBlock*>* order, |
| 706 HBasicBlock* loop_header) { | 711 HBasicBlock* loop_header) { |
| 707 if (block == NULL || visited->Contains(block->block_id())) return; | 712 if (block == NULL || visited->Contains(block->block_id())) return; |
| 708 if (block->parent_loop_header() != loop_header) return; | 713 if (block->parent_loop_header() != loop_header) return; |
| 709 visited->Add(block->block_id()); | 714 visited->Add(block->block_id()); |
| 710 if (block->IsLoopHeader()) { | 715 if (block->IsLoopHeader()) { |
| 711 PostorderLoopBlocks(block->loop_information(), visited, order, loop_header); | 716 PostorderLoopBlocks(block->loop_information(), visited, order, loop_header); |
| 712 Postorder(block->end()->SecondSuccessor(), visited, order, block); | 717 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { |
| 713 Postorder(block->end()->FirstSuccessor(), visited, order, block); | 718 Postorder(it.Current(), visited, order, block); |
| 719 } |
| 714 } else { | 720 } else { |
| 715 Postorder(block->end()->SecondSuccessor(), visited, order, loop_header); | 721 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { |
| 716 Postorder(block->end()->FirstSuccessor(), visited, order, loop_header); | 722 Postorder(it.Current(), visited, order, loop_header); |
| 723 } |
| 717 } | 724 } |
| 718 ASSERT(block->end()->FirstSuccessor() == NULL || | 725 ASSERT(block->end()->FirstSuccessor() == NULL || |
| 719 order->Contains(block->end()->FirstSuccessor()) || | 726 order->Contains(block->end()->FirstSuccessor()) || |
| 720 block->end()->FirstSuccessor()->IsLoopHeader()); | 727 block->end()->FirstSuccessor()->IsLoopHeader()); |
| 721 ASSERT(block->end()->SecondSuccessor() == NULL || | 728 ASSERT(block->end()->SecondSuccessor() == NULL || |
| 722 order->Contains(block->end()->SecondSuccessor()) || | 729 order->Contains(block->end()->SecondSuccessor()) || |
| 723 block->end()->SecondSuccessor()->IsLoopHeader()); | 730 block->end()->SecondSuccessor()->IsLoopHeader()); |
| 724 order->Add(block); | 731 order->Add(block); |
| 725 } | 732 } |
| 726 | 733 |
| 727 | 734 |
| 728 void HGraph::AssignDominators() { | 735 void HGraph::AssignDominators() { |
| 729 HPhase phase("Assign dominators", this); | 736 HPhase phase("Assign dominators", this); |
| 730 for (int i = 0; i < blocks_.length(); ++i) { | 737 for (int i = 0; i < blocks_.length(); ++i) { |
| 731 if (blocks_[i]->IsLoopHeader()) { | 738 if (blocks_[i]->IsLoopHeader()) { |
| 732 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first()); | 739 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first()); |
| 733 } else { | 740 } else { |
| 734 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) { | 741 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) { |
| 735 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); | 742 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); |
| 736 } | 743 } |
| 737 } | 744 } |
| 738 } | 745 } |
| 746 |
| 747 // Propagate flag marking blocks containing unconditional deoptimize. |
| 748 MarkAsDeoptimizingRecursively(entry_block()); |
| 739 } | 749 } |
| 740 | 750 |
| 741 | 751 |
| 752 // Mark all blocks that are dominated by an unconditional deoptimize. |
| 753 void HGraph::MarkAsDeoptimizingRecursively(HBasicBlock* block) { |
| 754 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { |
| 755 HBasicBlock* dominated = block->dominated_blocks()->at(i); |
| 756 if (block->IsDeoptimizing()) dominated->MarkAsDeoptimizing(); |
| 757 MarkAsDeoptimizingRecursively(dominated); |
| 758 } |
| 759 } |
| 760 |
| 742 void HGraph::EliminateRedundantPhis() { | 761 void HGraph::EliminateRedundantPhis() { |
| 743 HPhase phase("Redundant phi elimination", this); | 762 HPhase phase("Redundant phi elimination", this); |
| 744 | 763 |
| 745 // Worklist of phis that can potentially be eliminated. Initialized with | 764 // Worklist of phis that can potentially be eliminated. Initialized with |
| 746 // all phi nodes. When elimination of a phi node modifies another phi node | 765 // all phi nodes. When elimination of a phi node modifies another phi node |
| 747 // the modified phi node is added to the worklist. | 766 // the modified phi node is added to the worklist. |
| 748 ZoneList<HPhi*> worklist(blocks_.length()); | 767 ZoneList<HPhi*> worklist(blocks_.length()); |
| 749 for (int i = 0; i < blocks_.length(); ++i) { | 768 for (int i = 0; i < blocks_.length(); ++i) { |
| 750 worklist.AddAll(*blocks_[i]->phis()); | 769 worklist.AddAll(*blocks_[i]->phis()); |
| 751 } | 770 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 819 | 838 |
| 820 bool HGraph::CollectPhis() { | 839 bool HGraph::CollectPhis() { |
| 821 int block_count = blocks_.length(); | 840 int block_count = blocks_.length(); |
| 822 phi_list_ = new ZoneList<HPhi*>(block_count); | 841 phi_list_ = new ZoneList<HPhi*>(block_count); |
| 823 for (int i = 0; i < block_count; ++i) { | 842 for (int i = 0; i < block_count; ++i) { |
| 824 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { | 843 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
| 825 HPhi* phi = blocks_[i]->phis()->at(j); | 844 HPhi* phi = blocks_[i]->phis()->at(j); |
| 826 phi_list_->Add(phi); | 845 phi_list_->Add(phi); |
| 827 // We don't support phi uses of arguments for now. | 846 // We don't support phi uses of arguments for now. |
| 828 if (phi->CheckFlag(HValue::kIsArguments)) return false; | 847 if (phi->CheckFlag(HValue::kIsArguments)) return false; |
| 848 // Check for the hole value (from an uninitialized const). |
| 849 for (int k = 0; k < phi->OperandCount(); k++) { |
| 850 if (phi->OperandAt(k) == GetConstantHole()) return false; |
| 851 } |
| 829 } | 852 } |
| 830 } | 853 } |
| 831 return true; | 854 return true; |
| 832 } | 855 } |
| 833 | 856 |
| 834 | 857 |
| 835 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { | 858 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { |
| 836 BitVector in_worklist(GetMaximumValueID()); | 859 BitVector in_worklist(GetMaximumValueID()); |
| 837 for (int i = 0; i < worklist->length(); ++i) { | 860 for (int i = 0; i < worklist->length(); ++i) { |
| 838 ASSERT(!in_worklist.Contains(worklist->at(i)->id())); | 861 ASSERT(!in_worklist.Contains(worklist->at(i)->id())); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 857 | 880 |
| 858 class HRangeAnalysis BASE_EMBEDDED { | 881 class HRangeAnalysis BASE_EMBEDDED { |
| 859 public: | 882 public: |
| 860 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} | 883 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} |
| 861 | 884 |
| 862 void Analyze(); | 885 void Analyze(); |
| 863 | 886 |
| 864 private: | 887 private: |
| 865 void TraceRange(const char* msg, ...); | 888 void TraceRange(const char* msg, ...); |
| 866 void Analyze(HBasicBlock* block); | 889 void Analyze(HBasicBlock* block); |
| 867 void InferControlFlowRange(HTest* test, HBasicBlock* dest); | 890 void InferControlFlowRange(HCompareIDAndBranch* test, HBasicBlock* dest); |
| 868 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other); | 891 void UpdateControlFlowRange(Token::Value op, HValue* value, HValue* other); |
| 869 void InferPhiRange(HPhi* phi); | |
| 870 void InferRange(HValue* value); | 892 void InferRange(HValue* value); |
| 871 void RollBackTo(int index); | 893 void RollBackTo(int index); |
| 872 void AddRange(HValue* value, Range* range); | 894 void AddRange(HValue* value, Range* range); |
| 873 | 895 |
| 874 HGraph* graph_; | 896 HGraph* graph_; |
| 875 ZoneList<HValue*> changed_ranges_; | 897 ZoneList<HValue*> changed_ranges_; |
| 876 }; | 898 }; |
| 877 | 899 |
| 878 | 900 |
| 879 void HRangeAnalysis::TraceRange(const char* msg, ...) { | 901 void HRangeAnalysis::TraceRange(const char* msg, ...) { |
| 880 if (FLAG_trace_range) { | 902 if (FLAG_trace_range) { |
| 881 va_list arguments; | 903 va_list arguments; |
| 882 va_start(arguments, msg); | 904 va_start(arguments, msg); |
| 883 OS::VPrint(msg, arguments); | 905 OS::VPrint(msg, arguments); |
| 884 va_end(arguments); | 906 va_end(arguments); |
| 885 } | 907 } |
| 886 } | 908 } |
| 887 | 909 |
| 888 | 910 |
| 889 void HRangeAnalysis::Analyze() { | 911 void HRangeAnalysis::Analyze() { |
| 890 HPhase phase("Range analysis", graph_); | 912 HPhase phase("Range analysis", graph_); |
| 891 Analyze(graph_->blocks()->at(0)); | 913 Analyze(graph_->entry_block()); |
| 892 } | 914 } |
| 893 | 915 |
| 894 | 916 |
| 895 void HRangeAnalysis::Analyze(HBasicBlock* block) { | 917 void HRangeAnalysis::Analyze(HBasicBlock* block) { |
| 896 TraceRange("Analyzing block B%d\n", block->block_id()); | 918 TraceRange("Analyzing block B%d\n", block->block_id()); |
| 897 | 919 |
| 898 int last_changed_range = changed_ranges_.length() - 1; | 920 int last_changed_range = changed_ranges_.length() - 1; |
| 899 | 921 |
| 900 // Infer range based on control flow. | 922 // Infer range based on control flow. |
| 901 if (block->predecessors()->length() == 1) { | 923 if (block->predecessors()->length() == 1) { |
| 902 HBasicBlock* pred = block->predecessors()->first(); | 924 HBasicBlock* pred = block->predecessors()->first(); |
| 903 if (pred->end()->IsTest()) { | 925 if (pred->end()->IsCompareIDAndBranch()) { |
| 904 InferControlFlowRange(HTest::cast(pred->end()), block); | 926 InferControlFlowRange(HCompareIDAndBranch::cast(pred->end()), block); |
| 905 } | 927 } |
| 906 } | 928 } |
| 907 | 929 |
| 908 // Process phi instructions. | 930 // Process phi instructions. |
| 909 for (int i = 0; i < block->phis()->length(); ++i) { | 931 for (int i = 0; i < block->phis()->length(); ++i) { |
| 910 HPhi* phi = block->phis()->at(i); | 932 HPhi* phi = block->phis()->at(i); |
| 911 InferPhiRange(phi); | 933 InferRange(phi); |
| 912 } | 934 } |
| 913 | 935 |
| 914 // Go through all instructions of the current block. | 936 // Go through all instructions of the current block. |
| 915 HInstruction* instr = block->first(); | 937 HInstruction* instr = block->first(); |
| 916 while (instr != block->end()) { | 938 while (instr != block->end()) { |
| 917 InferRange(instr); | 939 InferRange(instr); |
| 918 instr = instr->next(); | 940 instr = instr->next(); |
| 919 } | 941 } |
| 920 | 942 |
| 921 // Continue analysis in all dominated blocks. | 943 // Continue analysis in all dominated blocks. |
| 922 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { | 944 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { |
| 923 Analyze(block->dominated_blocks()->at(i)); | 945 Analyze(block->dominated_blocks()->at(i)); |
| 924 } | 946 } |
| 925 | 947 |
| 926 RollBackTo(last_changed_range); | 948 RollBackTo(last_changed_range); |
| 927 } | 949 } |
| 928 | 950 |
| 929 | 951 |
| 930 void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) { | 952 void HRangeAnalysis::InferControlFlowRange(HCompareIDAndBranch* test, |
| 953 HBasicBlock* dest) { |
| 931 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); | 954 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); |
| 932 if (test->value()->IsCompare()) { | 955 if (test->GetInputRepresentation().IsInteger32()) { |
| 933 HCompare* compare = HCompare::cast(test->value()); | 956 Token::Value op = test->token(); |
| 934 if (compare->GetInputRepresentation().IsInteger32()) { | 957 if (test->SecondSuccessor() == dest) { |
| 935 Token::Value op = compare->token(); | 958 op = Token::NegateCompareOp(op); |
| 936 if (test->SecondSuccessor() == dest) { | |
| 937 op = Token::NegateCompareOp(op); | |
| 938 } | |
| 939 Token::Value inverted_op = Token::InvertCompareOp(op); | |
| 940 InferControlFlowRange(op, compare->left(), compare->right()); | |
| 941 InferControlFlowRange(inverted_op, compare->right(), compare->left()); | |
| 942 } | 959 } |
| 960 Token::Value inverted_op = Token::InvertCompareOp(op); |
| 961 UpdateControlFlowRange(op, test->left(), test->right()); |
| 962 UpdateControlFlowRange(inverted_op, test->right(), test->left()); |
| 943 } | 963 } |
| 944 } | 964 } |
| 945 | 965 |
| 946 | 966 |
| 947 // We know that value [op] other. Use this information to update the range on | 967 // We know that value [op] other. Use this information to update the range on |
| 948 // value. | 968 // value. |
| 949 void HRangeAnalysis::InferControlFlowRange(Token::Value op, | 969 void HRangeAnalysis::UpdateControlFlowRange(Token::Value op, |
| 950 HValue* value, | 970 HValue* value, |
| 951 HValue* other) { | 971 HValue* other) { |
| 952 Range temp_range; | 972 Range temp_range; |
| 953 Range* range = other->range() != NULL ? other->range() : &temp_range; | 973 Range* range = other->range() != NULL ? other->range() : &temp_range; |
| 954 Range* new_range = NULL; | 974 Range* new_range = NULL; |
| 955 | 975 |
| 956 TraceRange("Control flow range infer %d %s %d\n", | 976 TraceRange("Control flow range infer %d %s %d\n", |
| 957 value->id(), | 977 value->id(), |
| 958 Token::Name(op), | 978 Token::Name(op), |
| 959 other->id()); | 979 other->id()); |
| 960 | 980 |
| 961 if (op == Token::EQ || op == Token::EQ_STRICT) { | 981 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 972 new_range->AddConstant(1); | 992 new_range->AddConstant(1); |
| 973 } | 993 } |
| 974 } | 994 } |
| 975 | 995 |
| 976 if (new_range != NULL && !new_range->IsMostGeneric()) { | 996 if (new_range != NULL && !new_range->IsMostGeneric()) { |
| 977 AddRange(value, new_range); | 997 AddRange(value, new_range); |
| 978 } | 998 } |
| 979 } | 999 } |
| 980 | 1000 |
| 981 | 1001 |
| 982 void HRangeAnalysis::InferPhiRange(HPhi* phi) { | |
| 983 // TODO(twuerthinger): Infer loop phi ranges. | |
| 984 InferRange(phi); | |
| 985 } | |
| 986 | |
| 987 | |
| 988 void HRangeAnalysis::InferRange(HValue* value) { | 1002 void HRangeAnalysis::InferRange(HValue* value) { |
| 989 ASSERT(!value->HasRange()); | 1003 ASSERT(!value->HasRange()); |
| 990 if (!value->representation().IsNone()) { | 1004 if (!value->representation().IsNone()) { |
| 991 value->ComputeInitialRange(); | 1005 value->ComputeInitialRange(); |
| 992 Range* range = value->range(); | 1006 Range* range = value->range(); |
| 993 TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n", | 1007 TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n", |
| 994 value->id(), | 1008 value->id(), |
| 995 value->Mnemonic(), | 1009 value->Mnemonic(), |
| 996 range->lower(), | 1010 range->lower(), |
| 997 range->upper()); | 1011 range->upper()); |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1204 } | 1218 } |
| 1205 | 1219 |
| 1206 | 1220 |
| 1207 class HStackCheckEliminator BASE_EMBEDDED { | 1221 class HStackCheckEliminator BASE_EMBEDDED { |
| 1208 public: | 1222 public: |
| 1209 explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { } | 1223 explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { } |
| 1210 | 1224 |
| 1211 void Process(); | 1225 void Process(); |
| 1212 | 1226 |
| 1213 private: | 1227 private: |
| 1214 void RemoveStackCheck(HBasicBlock* block); | |
| 1215 | |
| 1216 HGraph* graph_; | 1228 HGraph* graph_; |
| 1217 }; | 1229 }; |
| 1218 | 1230 |
| 1219 | 1231 |
| 1220 void HStackCheckEliminator::Process() { | 1232 void HStackCheckEliminator::Process() { |
| 1221 // For each loop block walk the dominator tree from the backwards branch to | 1233 // For each loop block walk the dominator tree from the backwards branch to |
| 1222 // the loop header. If a call instruction is encountered the backwards branch | 1234 // the loop header. If a call instruction is encountered the backwards branch |
| 1223 // is dominated by a call and the stack check in the backwards branch can be | 1235 // is dominated by a call and the stack check in the backwards branch can be |
| 1224 // removed. | 1236 // removed. |
| 1225 for (int i = 0; i < graph_->blocks()->length(); i++) { | 1237 for (int i = 0; i < graph_->blocks()->length(); i++) { |
| 1226 HBasicBlock* block = graph_->blocks()->at(i); | 1238 HBasicBlock* block = graph_->blocks()->at(i); |
| 1227 if (block->IsLoopHeader()) { | 1239 if (block->IsLoopHeader()) { |
| 1228 HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge(); | 1240 HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge(); |
| 1229 HBasicBlock* dominator = back_edge; | 1241 HBasicBlock* dominator = back_edge; |
| 1230 bool back_edge_dominated_by_call = false; | 1242 while (true) { |
| 1231 while (dominator != block && !back_edge_dominated_by_call) { | |
| 1232 HInstruction* instr = dominator->first(); | 1243 HInstruction* instr = dominator->first(); |
| 1233 while (instr != NULL && !back_edge_dominated_by_call) { | 1244 while (instr != NULL) { |
| 1234 if (instr->IsCall()) { | 1245 if (instr->IsCall()) { |
| 1235 RemoveStackCheck(back_edge); | 1246 block->loop_information()->stack_check()->Eliminate(); |
| 1236 back_edge_dominated_by_call = true; | 1247 break; |
| 1237 } | 1248 } |
| 1238 instr = instr->next(); | 1249 instr = instr->next(); |
| 1239 } | 1250 } |
| 1251 |
| 1252 // Done when the loop header is processed. |
| 1253 if (dominator == block) break; |
| 1254 |
| 1255 // Move up the dominator tree. |
| 1240 dominator = dominator->dominator(); | 1256 dominator = dominator->dominator(); |
| 1241 } | 1257 } |
| 1242 } | 1258 } |
| 1243 } | 1259 } |
| 1244 } | 1260 } |
| 1245 | 1261 |
| 1246 | 1262 |
| 1247 void HStackCheckEliminator::RemoveStackCheck(HBasicBlock* block) { | |
| 1248 HInstruction* instr = block->first(); | |
| 1249 while (instr != NULL) { | |
| 1250 if (instr->IsGoto()) { | |
| 1251 HGoto::cast(instr)->set_include_stack_check(false); | |
| 1252 return; | |
| 1253 } | |
| 1254 instr = instr->next(); | |
| 1255 } | |
| 1256 } | |
| 1257 | |
| 1258 | |
| 1259 // Simple sparse set with O(1) add, contains, and clear. | 1263 // Simple sparse set with O(1) add, contains, and clear. |
| 1260 class SparseSet { | 1264 class SparseSet { |
| 1261 public: | 1265 public: |
| 1262 SparseSet(Zone* zone, int capacity) | 1266 SparseSet(Zone* zone, int capacity) |
| 1263 : capacity_(capacity), | 1267 : capacity_(capacity), |
| 1264 length_(0), | 1268 length_(0), |
| 1265 dense_(zone->NewArray<int>(capacity)), | 1269 dense_(zone->NewArray<int>(capacity)), |
| 1266 sparse_(zone->NewArray<int>(capacity)) {} | 1270 sparse_(zone->NewArray<int>(capacity)) { |
| 1271 #ifndef NVALGRIND |
| 1272 // Initialize the sparse array to make valgrind happy. |
| 1273 memset(sparse_, 0, sizeof(sparse_[0]) * capacity); |
| 1274 #endif |
| 1275 } |
| 1267 | 1276 |
| 1268 bool Contains(int n) const { | 1277 bool Contains(int n) const { |
| 1269 ASSERT(0 <= n && n < capacity_); | 1278 ASSERT(0 <= n && n < capacity_); |
| 1270 int d = sparse_[n]; | 1279 int d = sparse_[n]; |
| 1271 return 0 <= d && d < length_ && dense_[d] == n; | 1280 return 0 <= d && d < length_ && dense_[d] == n; |
| 1272 } | 1281 } |
| 1273 | 1282 |
| 1274 bool Add(int n) { | 1283 bool Add(int n) { |
| 1275 if (Contains(n)) return false; | 1284 if (Contains(n)) return false; |
| 1276 dense_[length_] = n; | 1285 dense_[length_] = n; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1339 SparseSet visited_on_paths_; | 1348 SparseSet visited_on_paths_; |
| 1340 }; | 1349 }; |
| 1341 | 1350 |
| 1342 | 1351 |
| 1343 void HGlobalValueNumberer::Analyze() { | 1352 void HGlobalValueNumberer::Analyze() { |
| 1344 ComputeBlockSideEffects(); | 1353 ComputeBlockSideEffects(); |
| 1345 if (FLAG_loop_invariant_code_motion) { | 1354 if (FLAG_loop_invariant_code_motion) { |
| 1346 LoopInvariantCodeMotion(); | 1355 LoopInvariantCodeMotion(); |
| 1347 } | 1356 } |
| 1348 HValueMap* map = new(zone()) HValueMap(); | 1357 HValueMap* map = new(zone()) HValueMap(); |
| 1349 AnalyzeBlock(graph_->blocks()->at(0), map); | 1358 AnalyzeBlock(graph_->entry_block(), map); |
| 1350 } | 1359 } |
| 1351 | 1360 |
| 1352 | 1361 |
| 1353 void HGlobalValueNumberer::ComputeBlockSideEffects() { | 1362 void HGlobalValueNumberer::ComputeBlockSideEffects() { |
| 1354 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | 1363 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { |
| 1355 // Compute side effects for the block. | 1364 // Compute side effects for the block. |
| 1356 HBasicBlock* block = graph_->blocks()->at(i); | 1365 HBasicBlock* block = graph_->blocks()->at(i); |
| 1357 HInstruction* instr = block->first(); | 1366 HInstruction* instr = block->first(); |
| 1358 int id = block->block_id(); | 1367 int id = block->block_id(); |
| 1359 int side_effects = 0; | 1368 int side_effects = 0; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1431 } | 1440 } |
| 1432 | 1441 |
| 1433 | 1442 |
| 1434 bool HGlobalValueNumberer::AllowCodeMotion() { | 1443 bool HGlobalValueNumberer::AllowCodeMotion() { |
| 1435 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; | 1444 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; |
| 1436 } | 1445 } |
| 1437 | 1446 |
| 1438 | 1447 |
| 1439 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, | 1448 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, |
| 1440 HBasicBlock* loop_header) { | 1449 HBasicBlock* loop_header) { |
| 1441 // If we've disabled code motion, don't move any instructions. | 1450 // If we've disabled code motion or we're in a block that unconditionally |
| 1442 if (!AllowCodeMotion()) return false; | 1451 // deoptimizes, don't move any instructions. |
| 1443 | 1452 return AllowCodeMotion() && !instr->block()->IsDeoptimizing(); |
| 1444 // If --aggressive-loop-invariant-motion, move everything except change | |
| 1445 // instructions. | |
| 1446 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { | |
| 1447 return true; | |
| 1448 } | |
| 1449 | |
| 1450 // Otherwise only move instructions that postdominate the loop header | |
| 1451 // (i.e. are always executed inside the loop). This is to avoid | |
| 1452 // unnecessary deoptimizations assuming the loop is executed at least | |
| 1453 // once. TODO(fschneider): Better type feedback should give us | |
| 1454 // information about code that was never executed. | |
| 1455 HBasicBlock* block = instr->block(); | |
| 1456 bool result = true; | |
| 1457 if (block != loop_header) { | |
| 1458 for (int i = 1; i < loop_header->predecessors()->length(); ++i) { | |
| 1459 bool found = false; | |
| 1460 HBasicBlock* pred = loop_header->predecessors()->at(i); | |
| 1461 while (pred != loop_header) { | |
| 1462 if (pred == block) found = true; | |
| 1463 pred = pred->dominator(); | |
| 1464 } | |
| 1465 if (!found) { | |
| 1466 result = false; | |
| 1467 break; | |
| 1468 } | |
| 1469 } | |
| 1470 } | |
| 1471 return result; | |
| 1472 } | 1453 } |
| 1473 | 1454 |
| 1474 | 1455 |
| 1475 int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( | 1456 int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( |
| 1476 HBasicBlock* dominator, HBasicBlock* dominated) { | 1457 HBasicBlock* dominator, HBasicBlock* dominated) { |
| 1477 int side_effects = 0; | 1458 int side_effects = 0; |
| 1478 for (int i = 0; i < dominated->predecessors()->length(); ++i) { | 1459 for (int i = 0; i < dominated->predecessors()->length(); ++i) { |
| 1479 HBasicBlock* block = dominated->predecessors()->at(i); | 1460 HBasicBlock* block = dominated->predecessors()->at(i); |
| 1480 if (dominator->block_id() < block->block_id() && | 1461 if (dominator->block_id() < block->block_id() && |
| 1481 block->block_id() < dominated->block_id() && | 1462 block->block_id() < dominated->block_id() && |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1834 } else { | 1815 } else { |
| 1835 next = HInstruction::cast(use_value); | 1816 next = HInstruction::cast(use_value); |
| 1836 } | 1817 } |
| 1837 | 1818 |
| 1838 // For constants we try to make the representation change at compile | 1819 // For constants we try to make the representation change at compile |
| 1839 // time. When a representation change is not possible without loss of | 1820 // time. When a representation change is not possible without loss of |
| 1840 // information we treat constants like normal instructions and insert the | 1821 // information we treat constants like normal instructions and insert the |
| 1841 // change instructions for them. | 1822 // change instructions for them. |
| 1842 HInstruction* new_value = NULL; | 1823 HInstruction* new_value = NULL; |
| 1843 bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32); | 1824 bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32); |
| 1825 bool deoptimize_on_undefined = |
| 1826 use_value->CheckFlag(HValue::kDeoptimizeOnUndefined); |
| 1844 if (value->IsConstant()) { | 1827 if (value->IsConstant()) { |
| 1845 HConstant* constant = HConstant::cast(value); | 1828 HConstant* constant = HConstant::cast(value); |
| 1846 // Try to create a new copy of the constant with the new representation. | 1829 // Try to create a new copy of the constant with the new representation. |
| 1847 new_value = is_truncating | 1830 new_value = is_truncating |
| 1848 ? constant->CopyToTruncatedInt32() | 1831 ? constant->CopyToTruncatedInt32() |
| 1849 : constant->CopyToRepresentation(to); | 1832 : constant->CopyToRepresentation(to); |
| 1850 } | 1833 } |
| 1851 | 1834 |
| 1852 if (new_value == NULL) { | 1835 if (new_value == NULL) { |
| 1853 new_value = | 1836 new_value = new(zone()) HChange(value, value->representation(), to, |
| 1854 new(zone()) HChange(value, value->representation(), to, is_truncating); | 1837 is_truncating, deoptimize_on_undefined); |
| 1855 } | 1838 } |
| 1856 | 1839 |
| 1857 new_value->InsertBefore(next); | 1840 new_value->InsertBefore(next); |
| 1858 use_value->SetOperandAt(use_index, new_value); | 1841 use_value->SetOperandAt(use_index, new_value); |
| 1859 } | 1842 } |
| 1860 | 1843 |
| 1861 | 1844 |
| 1862 void HGraph::InsertRepresentationChangesForValue(HValue* value) { | 1845 void HGraph::InsertRepresentationChangesForValue(HValue* value) { |
| 1863 Representation r = value->representation(); | 1846 Representation r = value->representation(); |
| 1864 if (r.IsNone()) return; | 1847 if (r.IsNone()) return; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1926 // Process normal instructions. | 1909 // Process normal instructions. |
| 1927 HInstruction* current = blocks_[i]->first(); | 1910 HInstruction* current = blocks_[i]->first(); |
| 1928 while (current != NULL) { | 1911 while (current != NULL) { |
| 1929 InsertRepresentationChangesForValue(current); | 1912 InsertRepresentationChangesForValue(current); |
| 1930 current = current->next(); | 1913 current = current->next(); |
| 1931 } | 1914 } |
| 1932 } | 1915 } |
| 1933 } | 1916 } |
| 1934 | 1917 |
| 1935 | 1918 |
| 1919 void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) { |
| 1920 if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return; |
| 1921 phi->SetFlag(HValue::kDeoptimizeOnUndefined); |
| 1922 for (int i = 0; i < phi->OperandCount(); ++i) { |
| 1923 HValue* input = phi->OperandAt(i); |
| 1924 if (input->IsPhi()) { |
| 1925 RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input)); |
| 1926 } |
| 1927 } |
| 1928 } |
| 1929 |
| 1930 |
| 1931 void HGraph::MarkDeoptimizeOnUndefined() { |
| 1932 HPhase phase("MarkDeoptimizeOnUndefined", this); |
| 1933 // Compute DeoptimizeOnUndefined flag for phis. |
| 1934 // Any phi that can reach a use with DeoptimizeOnUndefined set must |
| 1935 // have DeoptimizeOnUndefined set. Currently only HCompareIDAndBranch, with |
| 1936 // double input representation, has this flag set. |
| 1937 // The flag is used by HChange tagged->double, which must deoptimize |
| 1938 // if one of its uses has this flag set. |
| 1939 for (int i = 0; i < phi_list()->length(); i++) { |
| 1940 HPhi* phi = phi_list()->at(i); |
| 1941 if (phi->representation().IsDouble()) { |
| 1942 for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { |
| 1943 if (it.value()->CheckFlag(HValue::kDeoptimizeOnUndefined)) { |
| 1944 RecursivelyMarkPhiDeoptimizeOnUndefined(phi); |
| 1945 break; |
| 1946 } |
| 1947 } |
| 1948 } |
| 1949 } |
| 1950 } |
| 1951 |
| 1952 |
| 1936 void HGraph::ComputeMinusZeroChecks() { | 1953 void HGraph::ComputeMinusZeroChecks() { |
| 1937 BitVector visited(GetMaximumValueID()); | 1954 BitVector visited(GetMaximumValueID()); |
| 1938 for (int i = 0; i < blocks_.length(); ++i) { | 1955 for (int i = 0; i < blocks_.length(); ++i) { |
| 1939 for (HInstruction* current = blocks_[i]->first(); | 1956 for (HInstruction* current = blocks_[i]->first(); |
| 1940 current != NULL; | 1957 current != NULL; |
| 1941 current = current->next()) { | 1958 current = current->next()) { |
| 1942 if (current->IsChange()) { | 1959 if (current->IsChange()) { |
| 1943 HChange* change = HChange::cast(current); | 1960 HChange* change = HChange::cast(current); |
| 1944 // Propagate flags for negative zero checks upwards from conversions | 1961 // Propagate flags for negative zero checks upwards from conversions |
| 1945 // int32-to-tagged and int32-to-double. | 1962 // int32-to-tagged and int32-to-double. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1969 function_return_(NULL), | 1986 function_return_(NULL), |
| 1970 test_context_(NULL), | 1987 test_context_(NULL), |
| 1971 outer_(owner->function_state()) { | 1988 outer_(owner->function_state()) { |
| 1972 if (outer_ != NULL) { | 1989 if (outer_ != NULL) { |
| 1973 // State for an inline function. | 1990 // State for an inline function. |
| 1974 if (owner->ast_context()->IsTest()) { | 1991 if (owner->ast_context()->IsTest()) { |
| 1975 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 1992 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
| 1976 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 1993 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
| 1977 if_true->MarkAsInlineReturnTarget(); | 1994 if_true->MarkAsInlineReturnTarget(); |
| 1978 if_false->MarkAsInlineReturnTarget(); | 1995 if_false->MarkAsInlineReturnTarget(); |
| 1996 Expression* cond = TestContext::cast(owner->ast_context())->condition(); |
| 1979 // The AstContext constructor pushed on the context stack. This newed | 1997 // The AstContext constructor pushed on the context stack. This newed |
| 1980 // instance is the reason that AstContext can't be BASE_EMBEDDED. | 1998 // instance is the reason that AstContext can't be BASE_EMBEDDED. |
| 1981 test_context_ = new TestContext(owner, if_true, if_false); | 1999 test_context_ = new TestContext(owner, cond, if_true, if_false); |
| 1982 } else { | 2000 } else { |
| 1983 function_return_ = owner->graph()->CreateBasicBlock(); | 2001 function_return_ = owner->graph()->CreateBasicBlock(); |
| 1984 function_return()->MarkAsInlineReturnTarget(); | 2002 function_return()->MarkAsInlineReturnTarget(); |
| 1985 } | 2003 } |
| 1986 // Set this after possibly allocating a new TestContext above. | 2004 // Set this after possibly allocating a new TestContext above. |
| 1987 call_context_ = owner->ast_context(); | 2005 call_context_ = owner->ast_context(); |
| 1988 } | 2006 } |
| 1989 | 2007 |
| 1990 // Push on the state stack. | 2008 // Push on the state stack. |
| 1991 owner->set_function_state(this); | 2009 owner->set_function_state(this); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2045 owner()->Push(value); | 2063 owner()->Push(value); |
| 2046 } | 2064 } |
| 2047 | 2065 |
| 2048 | 2066 |
| 2049 void TestContext::ReturnValue(HValue* value) { | 2067 void TestContext::ReturnValue(HValue* value) { |
| 2050 BuildBranch(value); | 2068 BuildBranch(value); |
| 2051 } | 2069 } |
| 2052 | 2070 |
| 2053 | 2071 |
| 2054 void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) { | 2072 void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
| 2073 ASSERT(!instr->IsControlInstruction()); |
| 2055 owner()->AddInstruction(instr); | 2074 owner()->AddInstruction(instr); |
| 2056 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); | 2075 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); |
| 2057 } | 2076 } |
| 2058 | 2077 |
| 2059 | 2078 |
| 2079 void EffectContext::ReturnControl(HControlInstruction* instr, int ast_id) { |
| 2080 ASSERT(!instr->HasSideEffects()); |
| 2081 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); |
| 2082 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); |
| 2083 instr->SetSuccessorAt(0, empty_true); |
| 2084 instr->SetSuccessorAt(1, empty_false); |
| 2085 owner()->current_block()->Finish(instr); |
| 2086 HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id); |
| 2087 owner()->set_current_block(join); |
| 2088 } |
| 2089 |
| 2090 |
| 2060 void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) { | 2091 void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
| 2092 ASSERT(!instr->IsControlInstruction()); |
| 2061 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { | 2093 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { |
| 2062 owner()->Bailout("bad value context for arguments object value"); | 2094 return owner()->Bailout("bad value context for arguments object value"); |
| 2063 } | 2095 } |
| 2064 owner()->AddInstruction(instr); | 2096 owner()->AddInstruction(instr); |
| 2065 owner()->Push(instr); | 2097 owner()->Push(instr); |
| 2066 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); | 2098 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); |
| 2067 } | 2099 } |
| 2068 | 2100 |
| 2069 | 2101 |
| 2102 void ValueContext::ReturnControl(HControlInstruction* instr, int ast_id) { |
| 2103 ASSERT(!instr->HasSideEffects()); |
| 2104 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { |
| 2105 return owner()->Bailout("bad value context for arguments object value"); |
| 2106 } |
| 2107 HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock(); |
| 2108 HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock(); |
| 2109 instr->SetSuccessorAt(0, materialize_true); |
| 2110 instr->SetSuccessorAt(1, materialize_false); |
| 2111 owner()->current_block()->Finish(instr); |
| 2112 owner()->set_current_block(materialize_true); |
| 2113 owner()->Push(owner()->graph()->GetConstantTrue()); |
| 2114 owner()->set_current_block(materialize_false); |
| 2115 owner()->Push(owner()->graph()->GetConstantFalse()); |
| 2116 HBasicBlock* join = |
| 2117 owner()->CreateJoin(materialize_true, materialize_false, ast_id); |
| 2118 owner()->set_current_block(join); |
| 2119 } |
| 2120 |
| 2121 |
| 2070 void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) { | 2122 void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
| 2123 ASSERT(!instr->IsControlInstruction()); |
| 2071 HGraphBuilder* builder = owner(); | 2124 HGraphBuilder* builder = owner(); |
| 2072 builder->AddInstruction(instr); | 2125 builder->AddInstruction(instr); |
| 2073 // We expect a simulate after every expression with side effects, though | 2126 // We expect a simulate after every expression with side effects, though |
| 2074 // this one isn't actually needed (and wouldn't work if it were targeted). | 2127 // this one isn't actually needed (and wouldn't work if it were targeted). |
| 2075 if (instr->HasSideEffects()) { | 2128 if (instr->HasSideEffects()) { |
| 2076 builder->Push(instr); | 2129 builder->Push(instr); |
| 2077 builder->AddSimulate(ast_id); | 2130 builder->AddSimulate(ast_id); |
| 2078 builder->Pop(); | 2131 builder->Pop(); |
| 2079 } | 2132 } |
| 2080 BuildBranch(instr); | 2133 BuildBranch(instr); |
| 2081 } | 2134 } |
| 2082 | 2135 |
| 2083 | 2136 |
| 2137 void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { |
| 2138 ASSERT(!instr->HasSideEffects()); |
| 2139 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); |
| 2140 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); |
| 2141 instr->SetSuccessorAt(0, empty_true); |
| 2142 instr->SetSuccessorAt(1, empty_false); |
| 2143 owner()->current_block()->Finish(instr); |
| 2144 empty_true->Goto(if_true()); |
| 2145 empty_false->Goto(if_false()); |
| 2146 owner()->set_current_block(NULL); |
| 2147 } |
| 2148 |
| 2149 |
| 2084 void TestContext::BuildBranch(HValue* value) { | 2150 void TestContext::BuildBranch(HValue* value) { |
| 2085 // We expect the graph to be in edge-split form: there is no edge that | 2151 // We expect the graph to be in edge-split form: there is no edge that |
| 2086 // connects a branch node to a join node. We conservatively ensure that | 2152 // connects a branch node to a join node. We conservatively ensure that |
| 2087 // property by always adding an empty block on the outgoing edges of this | 2153 // property by always adding an empty block on the outgoing edges of this |
| 2088 // branch. | 2154 // branch. |
| 2089 HGraphBuilder* builder = owner(); | 2155 HGraphBuilder* builder = owner(); |
| 2090 if (value->CheckFlag(HValue::kIsArguments)) { | 2156 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { |
| 2091 builder->Bailout("arguments object value in a test context"); | 2157 builder->Bailout("arguments object value in a test context"); |
| 2092 } | 2158 } |
| 2093 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2159 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2094 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2160 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2095 HTest* test = new(zone()) HTest(value, empty_true, empty_false); | 2161 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false); |
| 2096 builder->current_block()->Finish(test); | 2162 builder->current_block()->Finish(test); |
| 2097 | 2163 |
| 2098 empty_true->Goto(if_true(), false); | 2164 empty_true->Goto(if_true()); |
| 2099 empty_false->Goto(if_false(), false); | 2165 empty_false->Goto(if_false()); |
| 2100 builder->set_current_block(NULL); | 2166 builder->set_current_block(NULL); |
| 2101 } | 2167 } |
| 2102 | 2168 |
| 2103 | 2169 |
| 2104 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2170 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 2105 #define CHECK_BAILOUT(call) \ | 2171 #define CHECK_BAILOUT(call) \ |
| 2106 do { \ | 2172 do { \ |
| 2107 call; \ | 2173 call; \ |
| 2108 if (HasStackOverflow()) return; \ | 2174 if (HasStackOverflow()) return; \ |
| 2109 } while (false) | 2175 } while (false) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2141 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); | 2207 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); |
| 2142 for_value.set_for_typeof(true); | 2208 for_value.set_for_typeof(true); |
| 2143 Visit(expr); | 2209 Visit(expr); |
| 2144 } | 2210 } |
| 2145 | 2211 |
| 2146 | 2212 |
| 2147 | 2213 |
| 2148 void HGraphBuilder::VisitForControl(Expression* expr, | 2214 void HGraphBuilder::VisitForControl(Expression* expr, |
| 2149 HBasicBlock* true_block, | 2215 HBasicBlock* true_block, |
| 2150 HBasicBlock* false_block) { | 2216 HBasicBlock* false_block) { |
| 2151 TestContext for_test(this, true_block, false_block); | 2217 TestContext for_test(this, expr, true_block, false_block); |
| 2152 Visit(expr); | 2218 Visit(expr); |
| 2153 } | 2219 } |
| 2154 | 2220 |
| 2155 | 2221 |
| 2156 void HGraphBuilder::VisitArgument(Expression* expr) { | 2222 HValue* HGraphBuilder::VisitArgument(Expression* expr) { |
| 2157 CHECK_ALIVE(VisitForValue(expr)); | 2223 VisitForValue(expr); |
| 2158 Push(AddInstruction(new(zone()) HPushArgument(Pop()))); | 2224 if (HasStackOverflow() || current_block() == NULL) return NULL; |
| 2225 HValue* value = Pop(); |
| 2226 Push(AddInstruction(new(zone()) HPushArgument(value))); |
| 2227 return value; |
| 2159 } | 2228 } |
| 2160 | 2229 |
| 2161 | 2230 |
| 2162 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { | 2231 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { |
| 2163 for (int i = 0; i < arguments->length(); i++) { | 2232 for (int i = 0; i < arguments->length(); i++) { |
| 2164 CHECK_ALIVE(VisitArgument(arguments->at(i))); | 2233 CHECK_ALIVE(VisitArgument(arguments->at(i))); |
| 2165 } | 2234 } |
| 2166 } | 2235 } |
| 2167 | 2236 |
| 2168 | 2237 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2181 HPhase phase("Block building"); | 2250 HPhase phase("Block building"); |
| 2182 current_block_ = graph()->entry_block(); | 2251 current_block_ = graph()->entry_block(); |
| 2183 | 2252 |
| 2184 Scope* scope = info()->scope(); | 2253 Scope* scope = info()->scope(); |
| 2185 if (scope->HasIllegalRedeclaration()) { | 2254 if (scope->HasIllegalRedeclaration()) { |
| 2186 Bailout("function with illegal redeclaration"); | 2255 Bailout("function with illegal redeclaration"); |
| 2187 return NULL; | 2256 return NULL; |
| 2188 } | 2257 } |
| 2189 SetupScope(scope); | 2258 SetupScope(scope); |
| 2190 VisitDeclarations(scope->declarations()); | 2259 VisitDeclarations(scope->declarations()); |
| 2191 AddInstruction(new(zone()) HStackCheck()); | 2260 HValue* context = environment()->LookupContext(); |
| 2261 AddInstruction( |
| 2262 new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry)); |
| 2192 | 2263 |
| 2193 // Add an edge to the body entry. This is warty: the graph's start | 2264 // Add an edge to the body entry. This is warty: the graph's start |
| 2194 // environment will be used by the Lithium translation as the initial | 2265 // environment will be used by the Lithium translation as the initial |
| 2195 // environment on graph entry, but it has now been mutated by the | 2266 // environment on graph entry, but it has now been mutated by the |
| 2196 // Hydrogen translation of the instructions in the start block. This | 2267 // Hydrogen translation of the instructions in the start block. This |
| 2197 // environment uses values which have not been defined yet. These | 2268 // environment uses values which have not been defined yet. These |
| 2198 // Hydrogen instructions will then be replayed by the Lithium | 2269 // Hydrogen instructions will then be replayed by the Lithium |
| 2199 // translation, so they cannot have an environment effect. The edge to | 2270 // translation, so they cannot have an environment effect. The edge to |
| 2200 // the body's entry block (along with some special logic for the start | 2271 // the body's entry block (along with some special logic for the start |
| 2201 // block in HInstruction::InsertAfter) seals the start block from | 2272 // block in HInstruction::InsertAfter) seals the start block from |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2218 current_block()->FinishExit(instr); | 2289 current_block()->FinishExit(instr); |
| 2219 set_current_block(NULL); | 2290 set_current_block(NULL); |
| 2220 } | 2291 } |
| 2221 } | 2292 } |
| 2222 | 2293 |
| 2223 graph()->OrderBlocks(); | 2294 graph()->OrderBlocks(); |
| 2224 graph()->AssignDominators(); | 2295 graph()->AssignDominators(); |
| 2225 graph()->EliminateRedundantPhis(); | 2296 graph()->EliminateRedundantPhis(); |
| 2226 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); | 2297 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); |
| 2227 if (!graph()->CollectPhis()) { | 2298 if (!graph()->CollectPhis()) { |
| 2228 Bailout("Phi-use of arguments object"); | 2299 Bailout("Unsupported phi-use"); |
| 2229 return NULL; | 2300 return NULL; |
| 2230 } | 2301 } |
| 2231 | 2302 |
| 2232 HInferRepresentation rep(graph()); | 2303 HInferRepresentation rep(graph()); |
| 2233 rep.Analyze(); | 2304 rep.Analyze(); |
| 2234 | 2305 |
| 2235 if (FLAG_use_range) { | 2306 if (FLAG_use_range) { |
| 2236 HRangeAnalysis rangeAnalysis(graph()); | 2307 HRangeAnalysis rangeAnalysis(graph()); |
| 2237 rangeAnalysis.Analyze(); | 2308 rangeAnalysis.Analyze(); |
| 2238 } | 2309 } |
| 2239 | 2310 |
| 2240 graph()->InitializeInferredTypes(); | 2311 graph()->InitializeInferredTypes(); |
| 2241 graph()->Canonicalize(); | 2312 graph()->Canonicalize(); |
| 2313 graph()->MarkDeoptimizeOnUndefined(); |
| 2242 graph()->InsertRepresentationChanges(); | 2314 graph()->InsertRepresentationChanges(); |
| 2243 graph()->ComputeMinusZeroChecks(); | 2315 graph()->ComputeMinusZeroChecks(); |
| 2244 | 2316 |
| 2245 // Eliminate redundant stack checks on backwards branches. | 2317 // Eliminate redundant stack checks on backwards branches. |
| 2246 HStackCheckEliminator sce(graph()); | 2318 HStackCheckEliminator sce(graph()); |
| 2247 sce.Process(); | 2319 sce.Process(); |
| 2248 | 2320 |
| 2249 // Perform common subexpression elimination and loop-invariant code motion. | 2321 // Perform common subexpression elimination and loop-invariant code motion. |
| 2250 if (FLAG_use_gvn) { | 2322 if (FLAG_use_gvn) { |
| 2251 HPhase phase("Global value numbering", graph()); | 2323 HPhase phase("Global value numbering", graph()); |
| 2252 HGlobalValueNumberer gvn(graph(), info()); | 2324 HGlobalValueNumberer gvn(graph(), info()); |
| 2253 gvn.Analyze(); | 2325 gvn.Analyze(); |
| 2254 } | 2326 } |
| 2255 | 2327 |
| 2328 // Replace the results of check instructions with the original value, if the |
| 2329 // result is used. This is safe now, since we don't do code motion after this |
| 2330 // point. It enables better register allocation since the value produced by |
| 2331 // check instructions is really a copy of the original value. |
| 2332 graph()->ReplaceCheckedValues(); |
| 2333 |
| 2256 return graph(); | 2334 return graph(); |
| 2257 } | 2335 } |
| 2258 | 2336 |
| 2259 | 2337 |
| 2338 void HGraph::ReplaceCheckedValues() { |
| 2339 HPhase phase("Replace checked values", this); |
| 2340 for (int i = 0; i < blocks()->length(); ++i) { |
| 2341 HInstruction* instr = blocks()->at(i)->first(); |
| 2342 while (instr != NULL) { |
| 2343 if (instr->IsBoundsCheck()) { |
| 2344 // Replace all uses of the checked value with the original input. |
| 2345 ASSERT(instr->UseCount() > 0); |
| 2346 instr->ReplaceAllUsesWith(HBoundsCheck::cast(instr)->index()); |
| 2347 } |
| 2348 instr = instr->next(); |
| 2349 } |
| 2350 } |
| 2351 } |
| 2352 |
| 2353 |
| 2260 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { | 2354 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
| 2261 ASSERT(current_block() != NULL); | 2355 ASSERT(current_block() != NULL); |
| 2262 current_block()->AddInstruction(instr); | 2356 current_block()->AddInstruction(instr); |
| 2263 return instr; | 2357 return instr; |
| 2264 } | 2358 } |
| 2265 | 2359 |
| 2266 | 2360 |
| 2267 void HGraphBuilder::AddSimulate(int id) { | 2361 void HGraphBuilder::AddSimulate(int ast_id) { |
| 2268 ASSERT(current_block() != NULL); | 2362 ASSERT(current_block() != NULL); |
| 2269 current_block()->AddSimulate(id); | 2363 current_block()->AddSimulate(ast_id); |
| 2270 } | 2364 } |
| 2271 | 2365 |
| 2272 | 2366 |
| 2273 void HGraphBuilder::AddPhi(HPhi* instr) { | 2367 void HGraphBuilder::AddPhi(HPhi* instr) { |
| 2274 ASSERT(current_block() != NULL); | 2368 ASSERT(current_block() != NULL); |
| 2275 current_block()->AddPhi(instr); | 2369 current_block()->AddPhi(instr); |
| 2276 } | 2370 } |
| 2277 | 2371 |
| 2278 | 2372 |
| 2279 void HGraphBuilder::PushAndAdd(HInstruction* instr) { | 2373 void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2291 } | 2385 } |
| 2292 | 2386 |
| 2293 while (!arguments.is_empty()) { | 2387 while (!arguments.is_empty()) { |
| 2294 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast())); | 2388 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast())); |
| 2295 } | 2389 } |
| 2296 return call; | 2390 return call; |
| 2297 } | 2391 } |
| 2298 | 2392 |
| 2299 | 2393 |
| 2300 void HGraphBuilder::SetupScope(Scope* scope) { | 2394 void HGraphBuilder::SetupScope(Scope* scope) { |
| 2301 // We don't yet handle the function name for named function expressions. | |
| 2302 if (scope->function() != NULL) return Bailout("named function expression"); | |
| 2303 | |
| 2304 HConstant* undefined_constant = new(zone()) HConstant( | 2395 HConstant* undefined_constant = new(zone()) HConstant( |
| 2305 isolate()->factory()->undefined_value(), Representation::Tagged()); | 2396 isolate()->factory()->undefined_value(), Representation::Tagged()); |
| 2306 AddInstruction(undefined_constant); | 2397 AddInstruction(undefined_constant); |
| 2307 graph_->set_undefined_constant(undefined_constant); | 2398 graph_->set_undefined_constant(undefined_constant); |
| 2308 | 2399 |
| 2309 // Set the initial values of parameters including "this". "This" has | 2400 // Set the initial values of parameters including "this". "This" has |
| 2310 // parameter index 0. | 2401 // parameter index 0. |
| 2311 ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count()); | 2402 ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count()); |
| 2312 | 2403 |
| 2313 for (int i = 0; i < environment()->parameter_count(); ++i) { | 2404 for (int i = 0; i < environment()->parameter_count(); ++i) { |
| 2314 HInstruction* parameter = AddInstruction(new(zone()) HParameter(i)); | 2405 HInstruction* parameter = AddInstruction(new(zone()) HParameter(i)); |
| 2315 environment()->Bind(i, parameter); | 2406 environment()->Bind(i, parameter); |
| 2316 } | 2407 } |
| 2317 | 2408 |
| 2318 // First special is HContext. | 2409 // First special is HContext. |
| 2319 HInstruction* context = AddInstruction(new(zone()) HContext); | 2410 HInstruction* context = AddInstruction(new(zone()) HContext); |
| 2320 environment()->BindContext(context); | 2411 environment()->BindContext(context); |
| 2321 | 2412 |
| 2322 // Initialize specials and locals to undefined. | 2413 // Initialize specials and locals to undefined. |
| 2323 for (int i = environment()->parameter_count() + 1; | 2414 for (int i = environment()->parameter_count() + 1; |
| 2324 i < environment()->length(); | 2415 i < environment()->length(); |
| 2325 ++i) { | 2416 ++i) { |
| 2326 environment()->Bind(i, undefined_constant); | 2417 environment()->Bind(i, undefined_constant); |
| 2327 } | 2418 } |
| 2328 | 2419 |
| 2329 // Handle the arguments and arguments shadow variables specially (they do | 2420 // Handle the arguments and arguments shadow variables specially (they do |
| 2330 // not have declarations). | 2421 // not have declarations). |
| 2331 if (scope->arguments() != NULL) { | 2422 if (scope->arguments() != NULL) { |
| 2332 if (!scope->arguments()->IsStackAllocated() || | 2423 if (!scope->arguments()->IsStackAllocated()) { |
| 2333 (scope->arguments_shadow() != NULL && | |
| 2334 !scope->arguments_shadow()->IsStackAllocated())) { | |
| 2335 return Bailout("context-allocated arguments"); | 2424 return Bailout("context-allocated arguments"); |
| 2336 } | 2425 } |
| 2337 HArgumentsObject* object = new(zone()) HArgumentsObject; | 2426 HArgumentsObject* object = new(zone()) HArgumentsObject; |
| 2338 AddInstruction(object); | 2427 AddInstruction(object); |
| 2339 graph()->SetArgumentsObject(object); | 2428 graph()->SetArgumentsObject(object); |
| 2340 environment()->Bind(scope->arguments(), object); | 2429 environment()->Bind(scope->arguments(), object); |
| 2341 if (scope->arguments_shadow() != NULL) { | |
| 2342 environment()->Bind(scope->arguments_shadow(), object); | |
| 2343 } | |
| 2344 } | 2430 } |
| 2345 } | 2431 } |
| 2346 | 2432 |
| 2347 | 2433 |
| 2348 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { | 2434 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { |
| 2349 for (int i = 0; i < statements->length(); i++) { | 2435 for (int i = 0; i < statements->length(); i++) { |
| 2350 CHECK_ALIVE(Visit(statements->at(i))); | 2436 CHECK_ALIVE(Visit(statements->at(i))); |
| 2351 } | 2437 } |
| 2352 } | 2438 } |
| 2353 | 2439 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2426 | 2512 |
| 2427 if (cond_false->HasPredecessor()) { | 2513 if (cond_false->HasPredecessor()) { |
| 2428 cond_false->SetJoinId(stmt->ElseId()); | 2514 cond_false->SetJoinId(stmt->ElseId()); |
| 2429 set_current_block(cond_false); | 2515 set_current_block(cond_false); |
| 2430 CHECK_BAILOUT(Visit(stmt->else_statement())); | 2516 CHECK_BAILOUT(Visit(stmt->else_statement())); |
| 2431 cond_false = current_block(); | 2517 cond_false = current_block(); |
| 2432 } else { | 2518 } else { |
| 2433 cond_false = NULL; | 2519 cond_false = NULL; |
| 2434 } | 2520 } |
| 2435 | 2521 |
| 2436 HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->id()); | 2522 HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId()); |
| 2437 set_current_block(join); | 2523 set_current_block(join); |
| 2438 } | 2524 } |
| 2439 } | 2525 } |
| 2440 | 2526 |
| 2441 | 2527 |
| 2442 HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get( | 2528 HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get( |
| 2443 BreakableStatement* stmt, | 2529 BreakableStatement* stmt, |
| 2444 BreakType type) { | 2530 BreakType type) { |
| 2445 BreakAndContinueScope* current = this; | 2531 BreakAndContinueScope* current = this; |
| 2446 while (current != NULL && current->info()->target() != stmt) { | 2532 while (current != NULL && current->info()->target() != stmt) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2504 } else { | 2590 } else { |
| 2505 // Return from an inlined function, visit the subexpression in the | 2591 // Return from an inlined function, visit the subexpression in the |
| 2506 // expression context of the call. | 2592 // expression context of the call. |
| 2507 if (context->IsTest()) { | 2593 if (context->IsTest()) { |
| 2508 TestContext* test = TestContext::cast(context); | 2594 TestContext* test = TestContext::cast(context); |
| 2509 VisitForControl(stmt->expression(), | 2595 VisitForControl(stmt->expression(), |
| 2510 test->if_true(), | 2596 test->if_true(), |
| 2511 test->if_false()); | 2597 test->if_false()); |
| 2512 } else if (context->IsEffect()) { | 2598 } else if (context->IsEffect()) { |
| 2513 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2599 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
| 2514 current_block()->Goto(function_return(), false); | 2600 current_block()->Goto(function_return()); |
| 2515 } else { | 2601 } else { |
| 2516 ASSERT(context->IsValue()); | 2602 ASSERT(context->IsValue()); |
| 2517 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2603 CHECK_ALIVE(VisitForValue(stmt->expression())); |
| 2518 HValue* return_value = environment()->Pop(); | 2604 HValue* return_value = environment()->Pop(); |
| 2519 current_block()->AddLeaveInlined(return_value, function_return()); | 2605 current_block()->AddLeaveInlined(return_value, function_return()); |
| 2520 } | 2606 } |
| 2521 set_current_block(NULL); | 2607 set_current_block(NULL); |
| 2522 } | 2608 } |
| 2523 } | 2609 } |
| 2524 | 2610 |
| 2525 | 2611 |
| 2526 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | 2612 void HGraphBuilder::VisitEnterWithContextStatement( |
| 2613 EnterWithContextStatement* stmt) { |
| 2527 ASSERT(!HasStackOverflow()); | 2614 ASSERT(!HasStackOverflow()); |
| 2528 ASSERT(current_block() != NULL); | 2615 ASSERT(current_block() != NULL); |
| 2529 ASSERT(current_block()->HasPredecessor()); | 2616 ASSERT(current_block()->HasPredecessor()); |
| 2530 return Bailout("WithEnterStatement"); | 2617 return Bailout("EnterWithContextStatement"); |
| 2531 } | 2618 } |
| 2532 | 2619 |
| 2533 | 2620 |
| 2534 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | 2621 void HGraphBuilder::VisitExitContextStatement(ExitContextStatement* stmt) { |
| 2535 ASSERT(!HasStackOverflow()); | 2622 ASSERT(!HasStackOverflow()); |
| 2536 ASSERT(current_block() != NULL); | 2623 ASSERT(current_block() != NULL); |
| 2537 ASSERT(current_block()->HasPredecessor()); | 2624 ASSERT(current_block()->HasPredecessor()); |
| 2538 return Bailout("WithExitStatement"); | 2625 return Bailout("ExitContextStatement"); |
| 2539 } | 2626 } |
| 2540 | 2627 |
| 2541 | 2628 |
| 2542 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2629 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 2543 ASSERT(!HasStackOverflow()); | 2630 ASSERT(!HasStackOverflow()); |
| 2544 ASSERT(current_block() != NULL); | 2631 ASSERT(current_block() != NULL); |
| 2545 ASSERT(current_block()->HasPredecessor()); | 2632 ASSERT(current_block()->HasPredecessor()); |
| 2546 // We only optimize switch statements with smi-literal smi comparisons, | 2633 // We only optimize switch statements with smi-literal smi comparisons, |
| 2547 // with a bounded number of clauses. | 2634 // with a bounded number of clauses. |
| 2548 const int kCaseClauseLimit = 128; | 2635 const int kCaseClauseLimit = 128; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2572 // Finish with deoptimize and add uses of enviroment values to | 2659 // Finish with deoptimize and add uses of enviroment values to |
| 2573 // account for invisible uses. | 2660 // account for invisible uses. |
| 2574 current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll); | 2661 current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll); |
| 2575 set_current_block(NULL); | 2662 set_current_block(NULL); |
| 2576 break; | 2663 break; |
| 2577 } | 2664 } |
| 2578 | 2665 |
| 2579 // Otherwise generate a compare and branch. | 2666 // Otherwise generate a compare and branch. |
| 2580 CHECK_ALIVE(VisitForValue(clause->label())); | 2667 CHECK_ALIVE(VisitForValue(clause->label())); |
| 2581 HValue* label_value = Pop(); | 2668 HValue* label_value = Pop(); |
| 2582 HCompare* compare = | 2669 HCompareIDAndBranch* compare = |
| 2583 new(zone()) HCompare(tag_value, label_value, Token::EQ_STRICT); | 2670 new(zone()) HCompareIDAndBranch(tag_value, |
| 2671 label_value, |
| 2672 Token::EQ_STRICT); |
| 2584 compare->SetInputRepresentation(Representation::Integer32()); | 2673 compare->SetInputRepresentation(Representation::Integer32()); |
| 2585 ASSERT(!compare->HasSideEffects()); | |
| 2586 AddInstruction(compare); | |
| 2587 HBasicBlock* body_block = graph()->CreateBasicBlock(); | 2674 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| 2588 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | 2675 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| 2589 HTest* branch = new(zone()) HTest(compare, body_block, next_test_block); | 2676 compare->SetSuccessorAt(0, body_block); |
| 2590 current_block()->Finish(branch); | 2677 compare->SetSuccessorAt(1, next_test_block); |
| 2678 current_block()->Finish(compare); |
| 2591 set_current_block(next_test_block); | 2679 set_current_block(next_test_block); |
| 2592 } | 2680 } |
| 2593 | 2681 |
| 2594 // Save the current block to use for the default or to join with the | 2682 // Save the current block to use for the default or to join with the |
| 2595 // exit. This block is NULL if we deoptimized. | 2683 // exit. This block is NULL if we deoptimized. |
| 2596 HBasicBlock* last_block = current_block(); | 2684 HBasicBlock* last_block = current_block(); |
| 2597 | 2685 |
| 2598 // 2. Loop over the clauses and the linked list of tests in lockstep, | 2686 // 2. Loop over the clauses and the linked list of tests in lockstep, |
| 2599 // translating the clause bodies. | 2687 // translating the clause bodies. |
| 2600 HBasicBlock* curr_test_block = first_test_block; | 2688 HBasicBlock* curr_test_block = first_test_block; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2666 return statement->OsrEntryId() == info()->osr_ast_id(); | 2754 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2667 } | 2755 } |
| 2668 | 2756 |
| 2669 | 2757 |
| 2670 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { | 2758 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { |
| 2671 if (!HasOsrEntryAt(statement)) return; | 2759 if (!HasOsrEntryAt(statement)) return; |
| 2672 | 2760 |
| 2673 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2761 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2674 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2762 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 2675 HValue* true_value = graph()->GetConstantTrue(); | 2763 HValue* true_value = graph()->GetConstantTrue(); |
| 2676 HTest* test = new(zone()) HTest(true_value, non_osr_entry, osr_entry); | 2764 HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry); |
| 2677 current_block()->Finish(test); | 2765 current_block()->Finish(test); |
| 2678 | 2766 |
| 2679 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2767 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2680 non_osr_entry->Goto(loop_predecessor); | 2768 non_osr_entry->Goto(loop_predecessor); |
| 2681 | 2769 |
| 2682 set_current_block(osr_entry); | 2770 set_current_block(osr_entry); |
| 2683 int osr_entry_id = statement->OsrEntryId(); | 2771 int osr_entry_id = statement->OsrEntryId(); |
| 2684 // We want the correct environment at the OsrEntry instruction. Build | 2772 // We want the correct environment at the OsrEntry instruction. Build |
| 2685 // it explicitly. The expression stack should be empty. | 2773 // it explicitly. The expression stack should be empty. |
| 2686 ASSERT(environment()->ExpressionStackIsEmpty()); | 2774 ASSERT(environment()->ExpressionStackIsEmpty()); |
| 2687 for (int i = 0; i < environment()->length(); ++i) { | 2775 for (int i = 0; i < environment()->length(); ++i) { |
| 2688 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; | 2776 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; |
| 2689 AddInstruction(osr_value); | 2777 AddInstruction(osr_value); |
| 2690 environment()->Bind(i, osr_value); | 2778 environment()->Bind(i, osr_value); |
| 2691 } | 2779 } |
| 2692 | 2780 |
| 2693 AddSimulate(osr_entry_id); | 2781 AddSimulate(osr_entry_id); |
| 2694 AddInstruction(new(zone()) HOsrEntry(osr_entry_id)); | 2782 AddInstruction(new(zone()) HOsrEntry(osr_entry_id)); |
| 2695 HContext* context = new(zone()) HContext; | 2783 HContext* context = new(zone()) HContext; |
| 2696 AddInstruction(context); | 2784 AddInstruction(context); |
| 2697 environment()->BindContext(context); | 2785 environment()->BindContext(context); |
| 2698 current_block()->Goto(loop_predecessor); | 2786 current_block()->Goto(loop_predecessor); |
| 2699 loop_predecessor->SetJoinId(statement->EntryId()); | 2787 loop_predecessor->SetJoinId(statement->EntryId()); |
| 2700 set_current_block(loop_predecessor); | 2788 set_current_block(loop_predecessor); |
| 2701 } | 2789 } |
| 2702 | 2790 |
| 2703 | 2791 |
| 2792 void HGraphBuilder::VisitLoopBody(IterationStatement* stmt, |
| 2793 HBasicBlock* loop_entry, |
| 2794 BreakAndContinueInfo* break_info) { |
| 2795 BreakAndContinueScope push(break_info, this); |
| 2796 AddSimulate(stmt->StackCheckId()); |
| 2797 HValue* context = environment()->LookupContext(); |
| 2798 HStackCheck* stack_check = |
| 2799 new(zone()) HStackCheck(context, HStackCheck::kBackwardsBranch); |
| 2800 AddInstruction(stack_check); |
| 2801 ASSERT(loop_entry->IsLoopHeader()); |
| 2802 loop_entry->loop_information()->set_stack_check(stack_check); |
| 2803 CHECK_BAILOUT(Visit(stmt->body())); |
| 2804 } |
| 2805 |
| 2806 |
| 2704 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { | 2807 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 2705 ASSERT(!HasStackOverflow()); | 2808 ASSERT(!HasStackOverflow()); |
| 2706 ASSERT(current_block() != NULL); | 2809 ASSERT(current_block() != NULL); |
| 2707 ASSERT(current_block()->HasPredecessor()); | 2810 ASSERT(current_block()->HasPredecessor()); |
| 2708 ASSERT(current_block() != NULL); | 2811 ASSERT(current_block() != NULL); |
| 2709 PreProcessOsrEntry(stmt); | 2812 PreProcessOsrEntry(stmt); |
| 2710 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); | 2813 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2711 current_block()->Goto(loop_entry, false); | 2814 current_block()->Goto(loop_entry); |
| 2712 set_current_block(loop_entry); | 2815 set_current_block(loop_entry); |
| 2713 | 2816 |
| 2714 BreakAndContinueInfo break_info(stmt); | 2817 BreakAndContinueInfo break_info(stmt); |
| 2715 { BreakAndContinueScope push(&break_info, this); | 2818 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info)); |
| 2716 CHECK_BAILOUT(Visit(stmt->body())); | |
| 2717 } | |
| 2718 HBasicBlock* body_exit = | 2819 HBasicBlock* body_exit = |
| 2719 JoinContinue(stmt, current_block(), break_info.continue_block()); | 2820 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2720 HBasicBlock* loop_successor = NULL; | 2821 HBasicBlock* loop_successor = NULL; |
| 2721 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) { | 2822 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) { |
| 2722 set_current_block(body_exit); | 2823 set_current_block(body_exit); |
| 2723 // The block for a true condition, the actual predecessor block of the | 2824 // The block for a true condition, the actual predecessor block of the |
| 2724 // back edge. | 2825 // back edge. |
| 2725 body_exit = graph()->CreateBasicBlock(); | 2826 body_exit = graph()->CreateBasicBlock(); |
| 2726 loop_successor = graph()->CreateBasicBlock(); | 2827 loop_successor = graph()->CreateBasicBlock(); |
| 2727 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor)); | 2828 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2745 } | 2846 } |
| 2746 | 2847 |
| 2747 | 2848 |
| 2748 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { | 2849 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { |
| 2749 ASSERT(!HasStackOverflow()); | 2850 ASSERT(!HasStackOverflow()); |
| 2750 ASSERT(current_block() != NULL); | 2851 ASSERT(current_block() != NULL); |
| 2751 ASSERT(current_block()->HasPredecessor()); | 2852 ASSERT(current_block()->HasPredecessor()); |
| 2752 ASSERT(current_block() != NULL); | 2853 ASSERT(current_block() != NULL); |
| 2753 PreProcessOsrEntry(stmt); | 2854 PreProcessOsrEntry(stmt); |
| 2754 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); | 2855 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2755 current_block()->Goto(loop_entry, false); | 2856 current_block()->Goto(loop_entry); |
| 2756 set_current_block(loop_entry); | 2857 set_current_block(loop_entry); |
| 2757 | 2858 |
| 2758 // If the condition is constant true, do not generate a branch. | 2859 // If the condition is constant true, do not generate a branch. |
| 2759 HBasicBlock* loop_successor = NULL; | 2860 HBasicBlock* loop_successor = NULL; |
| 2760 if (!stmt->cond()->ToBooleanIsTrue()) { | 2861 if (!stmt->cond()->ToBooleanIsTrue()) { |
| 2761 HBasicBlock* body_entry = graph()->CreateBasicBlock(); | 2862 HBasicBlock* body_entry = graph()->CreateBasicBlock(); |
| 2762 loop_successor = graph()->CreateBasicBlock(); | 2863 loop_successor = graph()->CreateBasicBlock(); |
| 2763 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor)); | 2864 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor)); |
| 2764 if (body_entry->HasPredecessor()) { | 2865 if (body_entry->HasPredecessor()) { |
| 2765 body_entry->SetJoinId(stmt->BodyId()); | 2866 body_entry->SetJoinId(stmt->BodyId()); |
| 2766 set_current_block(body_entry); | 2867 set_current_block(body_entry); |
| 2767 } | 2868 } |
| 2768 if (loop_successor->HasPredecessor()) { | 2869 if (loop_successor->HasPredecessor()) { |
| 2769 loop_successor->SetJoinId(stmt->ExitId()); | 2870 loop_successor->SetJoinId(stmt->ExitId()); |
| 2770 } else { | 2871 } else { |
| 2771 loop_successor = NULL; | 2872 loop_successor = NULL; |
| 2772 } | 2873 } |
| 2773 } | 2874 } |
| 2774 | 2875 |
| 2775 BreakAndContinueInfo break_info(stmt); | 2876 BreakAndContinueInfo break_info(stmt); |
| 2776 if (current_block() != NULL) { | 2877 if (current_block() != NULL) { |
| 2777 BreakAndContinueScope push(&break_info, this); | 2878 BreakAndContinueScope push(&break_info, this); |
| 2778 CHECK_BAILOUT(Visit(stmt->body())); | 2879 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info)); |
| 2779 } | 2880 } |
| 2780 HBasicBlock* body_exit = | 2881 HBasicBlock* body_exit = |
| 2781 JoinContinue(stmt, current_block(), break_info.continue_block()); | 2882 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2782 HBasicBlock* loop_exit = CreateLoop(stmt, | 2883 HBasicBlock* loop_exit = CreateLoop(stmt, |
| 2783 loop_entry, | 2884 loop_entry, |
| 2784 body_exit, | 2885 body_exit, |
| 2785 loop_successor, | 2886 loop_successor, |
| 2786 break_info.break_block()); | 2887 break_info.break_block()); |
| 2787 set_current_block(loop_exit); | 2888 set_current_block(loop_exit); |
| 2788 } | 2889 } |
| 2789 | 2890 |
| 2790 | 2891 |
| 2791 void HGraphBuilder::VisitForStatement(ForStatement* stmt) { | 2892 void HGraphBuilder::VisitForStatement(ForStatement* stmt) { |
| 2792 ASSERT(!HasStackOverflow()); | 2893 ASSERT(!HasStackOverflow()); |
| 2793 ASSERT(current_block() != NULL); | 2894 ASSERT(current_block() != NULL); |
| 2794 ASSERT(current_block()->HasPredecessor()); | 2895 ASSERT(current_block()->HasPredecessor()); |
| 2795 if (stmt->init() != NULL) { | 2896 if (stmt->init() != NULL) { |
| 2796 CHECK_ALIVE(Visit(stmt->init())); | 2897 CHECK_ALIVE(Visit(stmt->init())); |
| 2797 } | 2898 } |
| 2798 ASSERT(current_block() != NULL); | 2899 ASSERT(current_block() != NULL); |
| 2799 PreProcessOsrEntry(stmt); | 2900 PreProcessOsrEntry(stmt); |
| 2800 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); | 2901 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); |
| 2801 current_block()->Goto(loop_entry, false); | 2902 current_block()->Goto(loop_entry); |
| 2802 set_current_block(loop_entry); | 2903 set_current_block(loop_entry); |
| 2803 | 2904 |
| 2804 HBasicBlock* loop_successor = NULL; | 2905 HBasicBlock* loop_successor = NULL; |
| 2805 if (stmt->cond() != NULL) { | 2906 if (stmt->cond() != NULL) { |
| 2806 HBasicBlock* body_entry = graph()->CreateBasicBlock(); | 2907 HBasicBlock* body_entry = graph()->CreateBasicBlock(); |
| 2807 loop_successor = graph()->CreateBasicBlock(); | 2908 loop_successor = graph()->CreateBasicBlock(); |
| 2808 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor)); | 2909 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor)); |
| 2809 if (body_entry->HasPredecessor()) { | 2910 if (body_entry->HasPredecessor()) { |
| 2810 body_entry->SetJoinId(stmt->BodyId()); | 2911 body_entry->SetJoinId(stmt->BodyId()); |
| 2811 set_current_block(body_entry); | 2912 set_current_block(body_entry); |
| 2812 } | 2913 } |
| 2813 if (loop_successor->HasPredecessor()) { | 2914 if (loop_successor->HasPredecessor()) { |
| 2814 loop_successor->SetJoinId(stmt->ExitId()); | 2915 loop_successor->SetJoinId(stmt->ExitId()); |
| 2815 } else { | 2916 } else { |
| 2816 loop_successor = NULL; | 2917 loop_successor = NULL; |
| 2817 } | 2918 } |
| 2818 } | 2919 } |
| 2819 | 2920 |
| 2820 BreakAndContinueInfo break_info(stmt); | 2921 BreakAndContinueInfo break_info(stmt); |
| 2821 if (current_block() != NULL) { | 2922 if (current_block() != NULL) { |
| 2822 BreakAndContinueScope push(&break_info, this); | 2923 BreakAndContinueScope push(&break_info, this); |
| 2823 CHECK_BAILOUT(Visit(stmt->body())); | 2924 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info)); |
| 2824 } | 2925 } |
| 2825 HBasicBlock* body_exit = | 2926 HBasicBlock* body_exit = |
| 2826 JoinContinue(stmt, current_block(), break_info.continue_block()); | 2927 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 2827 | 2928 |
| 2828 if (stmt->next() != NULL && body_exit != NULL) { | 2929 if (stmt->next() != NULL && body_exit != NULL) { |
| 2829 set_current_block(body_exit); | 2930 set_current_block(body_exit); |
| 2830 CHECK_BAILOUT(Visit(stmt->next())); | 2931 CHECK_BAILOUT(Visit(stmt->next())); |
| 2831 body_exit = current_block(); | 2932 body_exit = current_block(); |
| 2832 } | 2933 } |
| 2833 | 2934 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2897 ASSERT(current_block() != NULL); | 2998 ASSERT(current_block() != NULL); |
| 2898 ASSERT(current_block()->HasPredecessor()); | 2999 ASSERT(current_block()->HasPredecessor()); |
| 2899 Handle<SharedFunctionInfo> shared_info = | 3000 Handle<SharedFunctionInfo> shared_info = |
| 2900 SearchSharedFunctionInfo(info()->shared_info()->code(), | 3001 SearchSharedFunctionInfo(info()->shared_info()->code(), |
| 2901 expr); | 3002 expr); |
| 2902 if (shared_info.is_null()) { | 3003 if (shared_info.is_null()) { |
| 2903 shared_info = Compiler::BuildFunctionInfo(expr, info()->script()); | 3004 shared_info = Compiler::BuildFunctionInfo(expr, info()->script()); |
| 2904 } | 3005 } |
| 2905 // We also have a stack overflow if the recursive compilation did. | 3006 // We also have a stack overflow if the recursive compilation did. |
| 2906 if (HasStackOverflow()) return; | 3007 if (HasStackOverflow()) return; |
| 3008 HValue* context = environment()->LookupContext(); |
| 2907 HFunctionLiteral* instr = | 3009 HFunctionLiteral* instr = |
| 2908 new(zone()) HFunctionLiteral(shared_info, expr->pretenure()); | 3010 new(zone()) HFunctionLiteral(context, shared_info, expr->pretenure()); |
| 2909 ast_context()->ReturnInstruction(instr, expr->id()); | 3011 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 2910 } | 3012 } |
| 2911 | 3013 |
| 2912 | 3014 |
| 2913 void HGraphBuilder::VisitSharedFunctionInfoLiteral( | 3015 void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
| 2914 SharedFunctionInfoLiteral* expr) { | 3016 SharedFunctionInfoLiteral* expr) { |
| 2915 ASSERT(!HasStackOverflow()); | 3017 ASSERT(!HasStackOverflow()); |
| 2916 ASSERT(current_block() != NULL); | 3018 ASSERT(current_block() != NULL); |
| 2917 ASSERT(current_block()->HasPredecessor()); | 3019 ASSERT(current_block()->HasPredecessor()); |
| 2918 return Bailout("SharedFunctionInfoLiteral"); | 3020 return Bailout("SharedFunctionInfoLiteral"); |
| 2919 } | 3021 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2944 CHECK_BAILOUT(Visit(expr->else_expression())); | 3046 CHECK_BAILOUT(Visit(expr->else_expression())); |
| 2945 cond_false = current_block(); | 3047 cond_false = current_block(); |
| 2946 } else { | 3048 } else { |
| 2947 cond_false = NULL; | 3049 cond_false = NULL; |
| 2948 } | 3050 } |
| 2949 | 3051 |
| 2950 if (!ast_context()->IsTest()) { | 3052 if (!ast_context()->IsTest()) { |
| 2951 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id()); | 3053 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id()); |
| 2952 set_current_block(join); | 3054 set_current_block(join); |
| 2953 if (join != NULL && !ast_context()->IsEffect()) { | 3055 if (join != NULL && !ast_context()->IsEffect()) { |
| 2954 ast_context()->ReturnValue(Pop()); | 3056 return ast_context()->ReturnValue(Pop()); |
| 2955 } | 3057 } |
| 2956 } | 3058 } |
| 2957 } | 3059 } |
| 2958 | 3060 |
| 2959 | 3061 |
| 2960 HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty( | 3062 HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty( |
| 2961 Variable* var, LookupResult* lookup, bool is_store) { | 3063 Variable* var, LookupResult* lookup, bool is_store) { |
| 2962 if (var->is_this() || !info()->has_global_object()) { | 3064 if (var->is_this() || !info()->has_global_object()) { |
| 2963 return kUseGeneric; | 3065 return kUseGeneric; |
| 2964 } | 3066 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2989 | 3091 |
| 2990 | 3092 |
| 2991 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 3093 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2992 ASSERT(!HasStackOverflow()); | 3094 ASSERT(!HasStackOverflow()); |
| 2993 ASSERT(current_block() != NULL); | 3095 ASSERT(current_block() != NULL); |
| 2994 ASSERT(current_block()->HasPredecessor()); | 3096 ASSERT(current_block()->HasPredecessor()); |
| 2995 Variable* variable = expr->AsVariable(); | 3097 Variable* variable = expr->AsVariable(); |
| 2996 if (variable == NULL) { | 3098 if (variable == NULL) { |
| 2997 return Bailout("reference to rewritten variable"); | 3099 return Bailout("reference to rewritten variable"); |
| 2998 } else if (variable->IsStackAllocated()) { | 3100 } else if (variable->IsStackAllocated()) { |
| 2999 ast_context()->ReturnValue(environment()->Lookup(variable)); | 3101 HValue* value = environment()->Lookup(variable); |
| 3102 if (variable->mode() == Variable::CONST && |
| 3103 value == graph()->GetConstantHole()) { |
| 3104 return Bailout("reference to uninitialized const variable"); |
| 3105 } |
| 3106 return ast_context()->ReturnValue(value); |
| 3000 } else if (variable->IsContextSlot()) { | 3107 } else if (variable->IsContextSlot()) { |
| 3001 if (variable->mode() == Variable::CONST) { | 3108 if (variable->mode() == Variable::CONST) { |
| 3002 return Bailout("reference to const context slot"); | 3109 return Bailout("reference to const context slot"); |
| 3003 } | 3110 } |
| 3004 HValue* context = BuildContextChainWalk(variable); | 3111 HValue* context = BuildContextChainWalk(variable); |
| 3005 int index = variable->AsSlot()->index(); | 3112 int index = variable->AsSlot()->index(); |
| 3006 HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index); | 3113 HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index); |
| 3007 ast_context()->ReturnInstruction(instr, expr->id()); | 3114 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3008 } else if (variable->is_global()) { | 3115 } else if (variable->is_global()) { |
| 3009 LookupResult lookup; | 3116 LookupResult lookup; |
| 3010 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false); | 3117 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false); |
| 3011 | 3118 |
| 3012 if (type == kUseCell && | 3119 if (type == kUseCell && |
| 3013 info()->global_object()->IsAccessCheckNeeded()) { | 3120 info()->global_object()->IsAccessCheckNeeded()) { |
| 3014 type = kUseGeneric; | 3121 type = kUseGeneric; |
| 3015 } | 3122 } |
| 3016 | 3123 |
| 3017 if (type == kUseCell) { | 3124 if (type == kUseCell) { |
| 3018 Handle<GlobalObject> global(info()->global_object()); | 3125 Handle<GlobalObject> global(info()->global_object()); |
| 3019 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3126 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3020 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3127 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 3021 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); | 3128 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); |
| 3022 ast_context()->ReturnInstruction(instr, expr->id()); | 3129 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3023 } else { | 3130 } else { |
| 3024 HValue* context = environment()->LookupContext(); | 3131 HValue* context = environment()->LookupContext(); |
| 3025 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 3132 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
| 3026 AddInstruction(global_object); | 3133 AddInstruction(global_object); |
| 3027 HLoadGlobalGeneric* instr = | 3134 HLoadGlobalGeneric* instr = |
| 3028 new(zone()) HLoadGlobalGeneric(context, | 3135 new(zone()) HLoadGlobalGeneric(context, |
| 3029 global_object, | 3136 global_object, |
| 3030 variable->name(), | 3137 variable->name(), |
| 3031 ast_context()->is_for_typeof()); | 3138 ast_context()->is_for_typeof()); |
| 3032 instr->set_position(expr->position()); | 3139 instr->set_position(expr->position()); |
| 3033 ASSERT(instr->HasSideEffects()); | 3140 ASSERT(instr->HasSideEffects()); |
| 3034 ast_context()->ReturnInstruction(instr, expr->id()); | 3141 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3035 } | 3142 } |
| 3036 } else { | 3143 } else { |
| 3037 return Bailout("reference to a variable which requires dynamic lookup"); | 3144 return Bailout("reference to a variable which requires dynamic lookup"); |
| 3038 } | 3145 } |
| 3039 } | 3146 } |
| 3040 | 3147 |
| 3041 | 3148 |
| 3042 void HGraphBuilder::VisitLiteral(Literal* expr) { | 3149 void HGraphBuilder::VisitLiteral(Literal* expr) { |
| 3043 ASSERT(!HasStackOverflow()); | 3150 ASSERT(!HasStackOverflow()); |
| 3044 ASSERT(current_block() != NULL); | 3151 ASSERT(current_block() != NULL); |
| 3045 ASSERT(current_block()->HasPredecessor()); | 3152 ASSERT(current_block()->HasPredecessor()); |
| 3046 HConstant* instr = | 3153 HConstant* instr = |
| 3047 new(zone()) HConstant(expr->handle(), Representation::Tagged()); | 3154 new(zone()) HConstant(expr->handle(), Representation::Tagged()); |
| 3048 ast_context()->ReturnInstruction(instr, expr->id()); | 3155 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3049 } | 3156 } |
| 3050 | 3157 |
| 3051 | 3158 |
| 3052 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { | 3159 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 3053 ASSERT(!HasStackOverflow()); | 3160 ASSERT(!HasStackOverflow()); |
| 3054 ASSERT(current_block() != NULL); | 3161 ASSERT(current_block() != NULL); |
| 3055 ASSERT(current_block()->HasPredecessor()); | 3162 ASSERT(current_block()->HasPredecessor()); |
| 3056 HRegExpLiteral* instr = new(zone()) HRegExpLiteral(expr->pattern(), | 3163 HValue* context = environment()->LookupContext(); |
| 3164 |
| 3165 HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context, |
| 3166 expr->pattern(), |
| 3057 expr->flags(), | 3167 expr->flags(), |
| 3058 expr->literal_index()); | 3168 expr->literal_index()); |
| 3059 ast_context()->ReturnInstruction(instr, expr->id()); | 3169 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3060 } | 3170 } |
| 3061 | 3171 |
| 3062 | 3172 |
| 3063 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | 3173 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 3064 ASSERT(!HasStackOverflow()); | 3174 ASSERT(!HasStackOverflow()); |
| 3065 ASSERT(current_block() != NULL); | 3175 ASSERT(current_block() != NULL); |
| 3066 ASSERT(current_block()->HasPredecessor()); | 3176 ASSERT(current_block()->HasPredecessor()); |
| 3067 HValue* context = environment()->LookupContext(); | 3177 HValue* context = environment()->LookupContext(); |
| 3068 HObjectLiteral* literal = | 3178 HObjectLiteral* literal = |
| 3069 new(zone()) HObjectLiteral(context, | 3179 new(zone()) HObjectLiteral(context, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3119 } | 3229 } |
| 3120 | 3230 |
| 3121 if (expr->has_function()) { | 3231 if (expr->has_function()) { |
| 3122 // Return the result of the transformation to fast properties | 3232 // Return the result of the transformation to fast properties |
| 3123 // instead of the original since this operation changes the map | 3233 // instead of the original since this operation changes the map |
| 3124 // of the object. This makes sure that the original object won't | 3234 // of the object. This makes sure that the original object won't |
| 3125 // be used by other optimized code before it is transformed | 3235 // be used by other optimized code before it is transformed |
| 3126 // (e.g. because of code motion). | 3236 // (e.g. because of code motion). |
| 3127 HToFastProperties* result = new(zone()) HToFastProperties(Pop()); | 3237 HToFastProperties* result = new(zone()) HToFastProperties(Pop()); |
| 3128 AddInstruction(result); | 3238 AddInstruction(result); |
| 3129 ast_context()->ReturnValue(result); | 3239 return ast_context()->ReturnValue(result); |
| 3130 } else { | 3240 } else { |
| 3131 ast_context()->ReturnValue(Pop()); | 3241 return ast_context()->ReturnValue(Pop()); |
| 3132 } | 3242 } |
| 3133 } | 3243 } |
| 3134 | 3244 |
| 3135 | 3245 |
| 3136 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { | 3246 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
| 3137 ASSERT(!HasStackOverflow()); | 3247 ASSERT(!HasStackOverflow()); |
| 3138 ASSERT(current_block() != NULL); | 3248 ASSERT(current_block() != NULL); |
| 3139 ASSERT(current_block()->HasPredecessor()); | 3249 ASSERT(current_block()->HasPredecessor()); |
| 3140 ZoneList<Expression*>* subexprs = expr->values(); | 3250 ZoneList<Expression*>* subexprs = expr->values(); |
| 3141 int length = subexprs->length(); | 3251 int length = subexprs->length(); |
| 3252 HValue* context = environment()->LookupContext(); |
| 3142 | 3253 |
| 3143 HArrayLiteral* literal = new(zone()) HArrayLiteral(expr->constant_elements(), | 3254 HArrayLiteral* literal = new(zone()) HArrayLiteral(context, |
| 3255 expr->constant_elements(), |
| 3144 length, | 3256 length, |
| 3145 expr->literal_index(), | 3257 expr->literal_index(), |
| 3146 expr->depth()); | 3258 expr->depth()); |
| 3147 // The array is expected in the bailout environment during computation | 3259 // The array is expected in the bailout environment during computation |
| 3148 // of the property values and is the value of the entire expression. | 3260 // of the property values and is the value of the entire expression. |
| 3149 PushAndAdd(literal); | 3261 PushAndAdd(literal); |
| 3150 | 3262 |
| 3151 HLoadElements* elements = NULL; | 3263 HLoadElements* elements = NULL; |
| 3152 | 3264 |
| 3153 for (int i = 0; i < length; i++) { | 3265 for (int i = 0; i < length; i++) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3165 elements = new(zone()) HLoadElements(literal); | 3277 elements = new(zone()) HLoadElements(literal); |
| 3166 AddInstruction(elements); | 3278 AddInstruction(elements); |
| 3167 } | 3279 } |
| 3168 | 3280 |
| 3169 HValue* key = AddInstruction( | 3281 HValue* key = AddInstruction( |
| 3170 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), | 3282 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
| 3171 Representation::Integer32())); | 3283 Representation::Integer32())); |
| 3172 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); | 3284 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); |
| 3173 AddSimulate(expr->GetIdForElement(i)); | 3285 AddSimulate(expr->GetIdForElement(i)); |
| 3174 } | 3286 } |
| 3175 ast_context()->ReturnValue(Pop()); | 3287 return ast_context()->ReturnValue(Pop()); |
| 3176 } | |
| 3177 | |
| 3178 | |
| 3179 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | |
| 3180 ASSERT(!HasStackOverflow()); | |
| 3181 ASSERT(current_block() != NULL); | |
| 3182 ASSERT(current_block()->HasPredecessor()); | |
| 3183 return Bailout("CatchExtensionObject"); | |
| 3184 } | 3288 } |
| 3185 | 3289 |
| 3186 | 3290 |
| 3187 // Sets the lookup result and returns true if the store can be inlined. | 3291 // Sets the lookup result and returns true if the store can be inlined. |
| 3188 static bool ComputeStoredField(Handle<Map> type, | 3292 static bool ComputeStoredField(Handle<Map> type, |
| 3189 Handle<String> name, | 3293 Handle<String> name, |
| 3190 LookupResult* lookup) { | 3294 LookupResult* lookup) { |
| 3191 type->LookupInDescriptors(NULL, *name, lookup); | 3295 type->LookupInDescriptors(NULL, *name, lookup); |
| 3192 if (!lookup->IsPropertyOrTransition()) return false; | 3296 if (!lookup->IsPropertyOrTransition()) return false; |
| 3193 if (lookup->type() == FIELD) return true; | 3297 if (lookup->type() == FIELD) return true; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3335 // unoptimized code). | 3439 // unoptimized code). |
| 3336 if (instr->HasSideEffects()) { | 3440 if (instr->HasSideEffects()) { |
| 3337 if (ast_context()->IsEffect()) { | 3441 if (ast_context()->IsEffect()) { |
| 3338 AddSimulate(expr->id()); | 3442 AddSimulate(expr->id()); |
| 3339 } else { | 3443 } else { |
| 3340 Push(value); | 3444 Push(value); |
| 3341 AddSimulate(expr->id()); | 3445 AddSimulate(expr->id()); |
| 3342 Drop(1); | 3446 Drop(1); |
| 3343 } | 3447 } |
| 3344 } | 3448 } |
| 3345 ast_context()->ReturnValue(value); | 3449 return ast_context()->ReturnValue(value); |
| 3346 return; | |
| 3347 } | 3450 } |
| 3348 } | 3451 } |
| 3349 | 3452 |
| 3350 ASSERT(join != NULL); | 3453 ASSERT(join != NULL); |
| 3351 join->SetJoinId(expr->id()); | 3454 join->SetJoinId(expr->id()); |
| 3352 set_current_block(join); | 3455 set_current_block(join); |
| 3353 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 3456 if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop()); |
| 3354 } | 3457 } |
| 3355 | 3458 |
| 3356 | 3459 |
| 3357 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3460 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3358 Property* prop = expr->target()->AsProperty(); | 3461 Property* prop = expr->target()->AsProperty(); |
| 3359 ASSERT(prop != NULL); | 3462 ASSERT(prop != NULL); |
| 3360 expr->RecordTypeFeedback(oracle()); | 3463 expr->RecordTypeFeedback(oracle()); |
| 3361 CHECK_ALIVE(VisitForValue(prop->obj())); | 3464 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 3362 | 3465 |
| 3363 HValue* value = NULL; | 3466 HValue* value = NULL; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3387 instr = BuildStoreNamedGeneric(object, name, value); | 3490 instr = BuildStoreNamedGeneric(object, name, value); |
| 3388 } | 3491 } |
| 3389 | 3492 |
| 3390 } else { | 3493 } else { |
| 3391 // Keyed store. | 3494 // Keyed store. |
| 3392 CHECK_ALIVE(VisitForValue(prop->key())); | 3495 CHECK_ALIVE(VisitForValue(prop->key())); |
| 3393 CHECK_ALIVE(VisitForValue(expr->value())); | 3496 CHECK_ALIVE(VisitForValue(expr->value())); |
| 3394 value = Pop(); | 3497 value = Pop(); |
| 3395 HValue* key = Pop(); | 3498 HValue* key = Pop(); |
| 3396 HValue* object = Pop(); | 3499 HValue* object = Pop(); |
| 3397 instr = BuildStoreKeyed(object, key, value, expr); | 3500 bool has_side_effects = false; |
| 3501 HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(), |
| 3502 expr->position(), |
| 3503 true, // is_store |
| 3504 &has_side_effects); |
| 3505 Push(value); |
| 3506 ASSERT(has_side_effects); // Stores always have side effects. |
| 3507 AddSimulate(expr->AssignmentId()); |
| 3508 return ast_context()->ReturnValue(Pop()); |
| 3398 } | 3509 } |
| 3399 Push(value); | 3510 Push(value); |
| 3400 instr->set_position(expr->position()); | 3511 instr->set_position(expr->position()); |
| 3401 AddInstruction(instr); | 3512 AddInstruction(instr); |
| 3402 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3513 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3403 ast_context()->ReturnValue(Pop()); | 3514 return ast_context()->ReturnValue(Pop()); |
| 3404 } | 3515 } |
| 3405 | 3516 |
| 3406 | 3517 |
| 3407 // Because not every expression has a position and there is not common | 3518 // Because not every expression has a position and there is not common |
| 3408 // superclass of Assignment and CountOperation, we cannot just pass the | 3519 // superclass of Assignment and CountOperation, we cannot just pass the |
| 3409 // owning expression instead of position and ast_id separately. | 3520 // owning expression instead of position and ast_id separately. |
| 3410 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, | 3521 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
| 3411 HValue* value, | 3522 HValue* value, |
| 3412 int position, | 3523 int position, |
| 3413 int ast_id) { | 3524 int ast_id) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3444 VariableProxy* proxy = target->AsVariableProxy(); | 3555 VariableProxy* proxy = target->AsVariableProxy(); |
| 3445 Variable* var = proxy->AsVariable(); | 3556 Variable* var = proxy->AsVariable(); |
| 3446 Property* prop = target->AsProperty(); | 3557 Property* prop = target->AsProperty(); |
| 3447 ASSERT(var == NULL || prop == NULL); | 3558 ASSERT(var == NULL || prop == NULL); |
| 3448 | 3559 |
| 3449 // We have a second position recorded in the FullCodeGenerator to have | 3560 // We have a second position recorded in the FullCodeGenerator to have |
| 3450 // type feedback for the binary operation. | 3561 // type feedback for the binary operation. |
| 3451 BinaryOperation* operation = expr->binary_operation(); | 3562 BinaryOperation* operation = expr->binary_operation(); |
| 3452 | 3563 |
| 3453 if (var != NULL) { | 3564 if (var != NULL) { |
| 3565 if (var->mode() == Variable::CONST) { |
| 3566 return Bailout("unsupported const compound assignment"); |
| 3567 } |
| 3568 |
| 3454 CHECK_ALIVE(VisitForValue(operation)); | 3569 CHECK_ALIVE(VisitForValue(operation)); |
| 3455 | 3570 |
| 3456 if (var->is_global()) { | 3571 if (var->is_global()) { |
| 3457 HandleGlobalVariableAssignment(var, | 3572 HandleGlobalVariableAssignment(var, |
| 3458 Top(), | 3573 Top(), |
| 3459 expr->position(), | 3574 expr->position(), |
| 3460 expr->AssignmentId()); | 3575 expr->AssignmentId()); |
| 3461 } else if (var->IsStackAllocated()) { | 3576 } else if (var->IsStackAllocated()) { |
| 3462 Bind(var, Top()); | 3577 Bind(var, Top()); |
| 3463 } else if (var->IsContextSlot()) { | 3578 } else if (var->IsContextSlot()) { |
| 3579 // Bail out if we try to mutate a parameter value in a function using |
| 3580 // the arguments object. We do not (yet) correctly handle the |
| 3581 // arguments property of the function. |
| 3582 if (info()->scope()->arguments() != NULL) { |
| 3583 // Parameters will rewrite to context slots. We have no direct way |
| 3584 // to detect that the variable is a parameter. |
| 3585 int count = info()->scope()->num_parameters(); |
| 3586 for (int i = 0; i < count; ++i) { |
| 3587 if (var == info()->scope()->parameter(i)) { |
| 3588 Bailout("assignment to parameter, function uses arguments object"); |
| 3589 } |
| 3590 } |
| 3591 } |
| 3592 |
| 3464 HValue* context = BuildContextChainWalk(var); | 3593 HValue* context = BuildContextChainWalk(var); |
| 3465 int index = var->AsSlot()->index(); | 3594 int index = var->AsSlot()->index(); |
| 3466 HStoreContextSlot* instr = | 3595 HStoreContextSlot* instr = |
| 3467 new(zone()) HStoreContextSlot(context, index, Top()); | 3596 new(zone()) HStoreContextSlot(context, index, Top()); |
| 3468 AddInstruction(instr); | 3597 AddInstruction(instr); |
| 3469 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3598 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3470 } else { | 3599 } else { |
| 3471 return Bailout("compound assignment to lookup slot"); | 3600 return Bailout("compound assignment to lookup slot"); |
| 3472 } | 3601 } |
| 3473 ast_context()->ReturnValue(Pop()); | 3602 return ast_context()->ReturnValue(Pop()); |
| 3474 | 3603 |
| 3475 } else if (prop != NULL) { | 3604 } else if (prop != NULL) { |
| 3476 prop->RecordTypeFeedback(oracle()); | 3605 prop->RecordTypeFeedback(oracle()); |
| 3477 | 3606 |
| 3478 if (prop->key()->IsPropertyName()) { | 3607 if (prop->key()->IsPropertyName()) { |
| 3479 // Named property. | 3608 // Named property. |
| 3480 CHECK_ALIVE(VisitForValue(prop->obj())); | 3609 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 3481 HValue* obj = Top(); | 3610 HValue* obj = Top(); |
| 3482 | 3611 |
| 3483 HInstruction* load = NULL; | 3612 HInstruction* load = NULL; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3498 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 3627 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
| 3499 PushAndAdd(instr); | 3628 PushAndAdd(instr); |
| 3500 if (instr->HasSideEffects()) AddSimulate(operation->id()); | 3629 if (instr->HasSideEffects()) AddSimulate(operation->id()); |
| 3501 | 3630 |
| 3502 HInstruction* store = BuildStoreNamed(obj, instr, prop); | 3631 HInstruction* store = BuildStoreNamed(obj, instr, prop); |
| 3503 AddInstruction(store); | 3632 AddInstruction(store); |
| 3504 // Drop the simulated receiver and value. Return the value. | 3633 // Drop the simulated receiver and value. Return the value. |
| 3505 Drop(2); | 3634 Drop(2); |
| 3506 Push(instr); | 3635 Push(instr); |
| 3507 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3636 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3508 ast_context()->ReturnValue(Pop()); | 3637 return ast_context()->ReturnValue(Pop()); |
| 3509 | 3638 |
| 3510 } else { | 3639 } else { |
| 3511 // Keyed property. | 3640 // Keyed property. |
| 3512 CHECK_ALIVE(VisitForValue(prop->obj())); | 3641 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 3513 CHECK_ALIVE(VisitForValue(prop->key())); | 3642 CHECK_ALIVE(VisitForValue(prop->key())); |
| 3514 HValue* obj = environment()->ExpressionStackAt(1); | 3643 HValue* obj = environment()->ExpressionStackAt(1); |
| 3515 HValue* key = environment()->ExpressionStackAt(0); | 3644 HValue* key = environment()->ExpressionStackAt(0); |
| 3516 | 3645 |
| 3517 HInstruction* load = BuildLoadKeyed(obj, key, prop); | 3646 bool has_side_effects = false; |
| 3518 PushAndAdd(load); | 3647 HValue* load = HandleKeyedElementAccess( |
| 3519 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); | 3648 obj, key, NULL, prop, expr->CompoundLoadId(), RelocInfo::kNoPosition, |
| 3649 false, // is_store |
| 3650 &has_side_effects); |
| 3651 Push(load); |
| 3652 if (has_side_effects) AddSimulate(expr->CompoundLoadId()); |
| 3653 |
| 3520 | 3654 |
| 3521 CHECK_ALIVE(VisitForValue(expr->value())); | 3655 CHECK_ALIVE(VisitForValue(expr->value())); |
| 3522 HValue* right = Pop(); | 3656 HValue* right = Pop(); |
| 3523 HValue* left = Pop(); | 3657 HValue* left = Pop(); |
| 3524 | 3658 |
| 3525 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 3659 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
| 3526 PushAndAdd(instr); | 3660 PushAndAdd(instr); |
| 3527 if (instr->HasSideEffects()) AddSimulate(operation->id()); | 3661 if (instr->HasSideEffects()) AddSimulate(operation->id()); |
| 3528 | 3662 |
| 3529 expr->RecordTypeFeedback(oracle()); | 3663 expr->RecordTypeFeedback(oracle()); |
| 3530 HInstruction* store = BuildStoreKeyed(obj, key, instr, expr); | 3664 HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), |
| 3531 AddInstruction(store); | 3665 RelocInfo::kNoPosition, |
| 3666 true, // is_store |
| 3667 &has_side_effects); |
| 3668 |
| 3532 // Drop the simulated receiver, key, and value. Return the value. | 3669 // Drop the simulated receiver, key, and value. Return the value. |
| 3533 Drop(3); | 3670 Drop(3); |
| 3534 Push(instr); | 3671 Push(instr); |
| 3535 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3672 ASSERT(has_side_effects); // Stores always have side effects. |
| 3536 ast_context()->ReturnValue(Pop()); | 3673 AddSimulate(expr->AssignmentId()); |
| 3674 return ast_context()->ReturnValue(Pop()); |
| 3537 } | 3675 } |
| 3538 | 3676 |
| 3539 } else { | 3677 } else { |
| 3540 return Bailout("invalid lhs in compound assignment"); | 3678 return Bailout("invalid lhs in compound assignment"); |
| 3541 } | 3679 } |
| 3542 } | 3680 } |
| 3543 | 3681 |
| 3544 | 3682 |
| 3545 void HGraphBuilder::VisitAssignment(Assignment* expr) { | 3683 void HGraphBuilder::VisitAssignment(Assignment* expr) { |
| 3546 ASSERT(!HasStackOverflow()); | 3684 ASSERT(!HasStackOverflow()); |
| 3547 ASSERT(current_block() != NULL); | 3685 ASSERT(current_block() != NULL); |
| 3548 ASSERT(current_block()->HasPredecessor()); | 3686 ASSERT(current_block()->HasPredecessor()); |
| 3549 VariableProxy* proxy = expr->target()->AsVariableProxy(); | 3687 VariableProxy* proxy = expr->target()->AsVariableProxy(); |
| 3550 Variable* var = proxy->AsVariable(); | 3688 Variable* var = proxy->AsVariable(); |
| 3551 Property* prop = expr->target()->AsProperty(); | 3689 Property* prop = expr->target()->AsProperty(); |
| 3552 ASSERT(var == NULL || prop == NULL); | 3690 ASSERT(var == NULL || prop == NULL); |
| 3553 | 3691 |
| 3554 if (expr->is_compound()) { | 3692 if (expr->is_compound()) { |
| 3555 HandleCompoundAssignment(expr); | 3693 HandleCompoundAssignment(expr); |
| 3556 return; | 3694 return; |
| 3557 } | 3695 } |
| 3558 | 3696 |
| 3559 if (var != NULL) { | 3697 if (var != NULL) { |
| 3698 if (var->mode() == Variable::CONST) { |
| 3699 if (expr->op() != Token::INIT_CONST) { |
| 3700 return Bailout("non-initializer assignment to const"); |
| 3701 } |
| 3702 if (!var->IsStackAllocated()) { |
| 3703 return Bailout("assignment to const context slot"); |
| 3704 } |
| 3705 // We insert a use of the old value to detect unsupported uses of const |
| 3706 // variables (e.g. initialization inside a loop). |
| 3707 HValue* old_value = environment()->Lookup(var); |
| 3708 AddInstruction(new HUseConst(old_value)); |
| 3709 } |
| 3710 |
| 3560 if (proxy->IsArguments()) return Bailout("assignment to arguments"); | 3711 if (proxy->IsArguments()) return Bailout("assignment to arguments"); |
| 3561 | 3712 |
| 3562 // Handle the assignment. | 3713 // Handle the assignment. |
| 3563 if (var->IsStackAllocated()) { | 3714 if (var->IsStackAllocated()) { |
| 3564 // We do not allow the arguments object to occur in a context where it | 3715 // We do not allow the arguments object to occur in a context where it |
| 3565 // may escape, but assignments to stack-allocated locals are | 3716 // may escape, but assignments to stack-allocated locals are |
| 3566 // permitted. | 3717 // permitted. |
| 3567 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); | 3718 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); |
| 3568 HValue* value = Pop(); | 3719 HValue* value = Pop(); |
| 3569 Bind(var, value); | 3720 Bind(var, value); |
| 3570 ast_context()->ReturnValue(value); | 3721 return ast_context()->ReturnValue(value); |
| 3571 | 3722 |
| 3572 } else if (var->IsContextSlot() && var->mode() != Variable::CONST) { | 3723 } else if (var->IsContextSlot()) { |
| 3724 ASSERT(var->mode() != Variable::CONST); |
| 3725 // Bail out if we try to mutate a parameter value in a function using |
| 3726 // the arguments object. We do not (yet) correctly handle the |
| 3727 // arguments property of the function. |
| 3728 if (info()->scope()->arguments() != NULL) { |
| 3729 // Parameters will rewrite to context slots. We have no direct way |
| 3730 // to detect that the variable is a parameter. |
| 3731 int count = info()->scope()->num_parameters(); |
| 3732 for (int i = 0; i < count; ++i) { |
| 3733 if (var == info()->scope()->parameter(i)) { |
| 3734 Bailout("assignment to parameter, function uses arguments object"); |
| 3735 } |
| 3736 } |
| 3737 } |
| 3738 |
| 3573 CHECK_ALIVE(VisitForValue(expr->value())); | 3739 CHECK_ALIVE(VisitForValue(expr->value())); |
| 3574 HValue* context = BuildContextChainWalk(var); | 3740 HValue* context = BuildContextChainWalk(var); |
| 3575 int index = var->AsSlot()->index(); | 3741 int index = var->AsSlot()->index(); |
| 3576 HStoreContextSlot* instr = | 3742 HStoreContextSlot* instr = |
| 3577 new(zone()) HStoreContextSlot(context, index, Top()); | 3743 new(zone()) HStoreContextSlot(context, index, Top()); |
| 3578 AddInstruction(instr); | 3744 AddInstruction(instr); |
| 3579 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3745 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3580 ast_context()->ReturnValue(Pop()); | 3746 return ast_context()->ReturnValue(Pop()); |
| 3581 | 3747 |
| 3582 } else if (var->is_global()) { | 3748 } else if (var->is_global()) { |
| 3583 CHECK_ALIVE(VisitForValue(expr->value())); | 3749 CHECK_ALIVE(VisitForValue(expr->value())); |
| 3584 HandleGlobalVariableAssignment(var, | 3750 HandleGlobalVariableAssignment(var, |
| 3585 Top(), | 3751 Top(), |
| 3586 expr->position(), | 3752 expr->position(), |
| 3587 expr->AssignmentId()); | 3753 expr->AssignmentId()); |
| 3588 ast_context()->ReturnValue(Pop()); | 3754 return ast_context()->ReturnValue(Pop()); |
| 3589 | 3755 |
| 3590 } else { | 3756 } else { |
| 3591 return Bailout("assignment to LOOKUP or const CONTEXT variable"); | 3757 return Bailout("assignment to LOOKUP or const CONTEXT variable"); |
| 3592 } | 3758 } |
| 3593 | 3759 |
| 3594 } else if (prop != NULL) { | 3760 } else if (prop != NULL) { |
| 3595 HandlePropertyAssignment(expr); | 3761 HandlePropertyAssignment(expr); |
| 3596 } else { | 3762 } else { |
| 3597 return Bailout("invalid left-hand side in assignment"); | 3763 return Bailout("invalid left-hand side in assignment"); |
| 3598 } | 3764 } |
| 3599 } | 3765 } |
| 3600 | 3766 |
| 3601 | 3767 |
| 3602 void HGraphBuilder::VisitThrow(Throw* expr) { | 3768 void HGraphBuilder::VisitThrow(Throw* expr) { |
| 3603 ASSERT(!HasStackOverflow()); | 3769 ASSERT(!HasStackOverflow()); |
| 3604 ASSERT(current_block() != NULL); | 3770 ASSERT(current_block() != NULL); |
| 3605 ASSERT(current_block()->HasPredecessor()); | 3771 ASSERT(current_block()->HasPredecessor()); |
| 3606 // We don't optimize functions with invalid left-hand sides in | 3772 // We don't optimize functions with invalid left-hand sides in |
| 3607 // assignments, count operations, or for-in. Consequently throw can | 3773 // assignments, count operations, or for-in. Consequently throw can |
| 3608 // currently only occur in an effect context. | 3774 // currently only occur in an effect context. |
| 3609 ASSERT(ast_context()->IsEffect()); | 3775 ASSERT(ast_context()->IsEffect()); |
| 3610 CHECK_ALIVE(VisitForValue(expr->exception())); | 3776 CHECK_ALIVE(VisitForValue(expr->exception())); |
| 3611 | 3777 |
| 3778 HValue* context = environment()->LookupContext(); |
| 3612 HValue* value = environment()->Pop(); | 3779 HValue* value = environment()->Pop(); |
| 3613 HThrow* instr = new(zone()) HThrow(value); | 3780 HThrow* instr = new(zone()) HThrow(context, value); |
| 3614 instr->set_position(expr->position()); | 3781 instr->set_position(expr->position()); |
| 3615 AddInstruction(instr); | 3782 AddInstruction(instr); |
| 3616 AddSimulate(expr->id()); | 3783 AddSimulate(expr->id()); |
| 3617 current_block()->FinishExit(new(zone()) HAbnormalExit); | 3784 current_block()->FinishExit(new(zone()) HAbnormalExit); |
| 3618 set_current_block(NULL); | 3785 set_current_block(NULL); |
| 3619 } | 3786 } |
| 3620 | 3787 |
| 3621 | 3788 |
| 3622 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3789 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3623 Property* expr, | 3790 Property* expr, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3675 } | 3842 } |
| 3676 | 3843 |
| 3677 | 3844 |
| 3678 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 3845 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 3679 HValue* key) { | 3846 HValue* key) { |
| 3680 HValue* context = environment()->LookupContext(); | 3847 HValue* context = environment()->LookupContext(); |
| 3681 return new(zone()) HLoadKeyedGeneric(context, object, key); | 3848 return new(zone()) HLoadKeyedGeneric(context, object, key); |
| 3682 } | 3849 } |
| 3683 | 3850 |
| 3684 | 3851 |
| 3685 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, | 3852 HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( |
| 3686 HValue* key, | 3853 HValue* external_elements, |
| 3687 Property* expr) { | 3854 HValue* checked_key, |
| 3688 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3855 HValue* val, |
| 3856 JSObject::ElementsKind elements_kind, |
| 3857 bool is_store) { |
| 3858 if (is_store) { |
| 3859 ASSERT(val != NULL); |
| 3860 switch (elements_kind) { |
| 3861 case JSObject::EXTERNAL_PIXEL_ELEMENTS: { |
| 3862 HClampToUint8* clamp = new(zone()) HClampToUint8(val); |
| 3863 AddInstruction(clamp); |
| 3864 val = clamp; |
| 3865 break; |
| 3866 } |
| 3867 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 3868 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3869 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 3870 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3871 case JSObject::EXTERNAL_INT_ELEMENTS: |
| 3872 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { |
| 3873 HToInt32* floor_val = new(zone()) HToInt32(val); |
| 3874 AddInstruction(floor_val); |
| 3875 val = floor_val; |
| 3876 break; |
| 3877 } |
| 3878 case JSObject::EXTERNAL_FLOAT_ELEMENTS: |
| 3879 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: |
| 3880 break; |
| 3881 case JSObject::FAST_ELEMENTS: |
| 3882 case JSObject::FAST_DOUBLE_ELEMENTS: |
| 3883 case JSObject::DICTIONARY_ELEMENTS: |
| 3884 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS: |
| 3885 UNREACHABLE(); |
| 3886 break; |
| 3887 } |
| 3888 return new(zone()) HStoreKeyedSpecializedArrayElement( |
| 3889 external_elements, checked_key, val, elements_kind); |
| 3890 } else { |
| 3891 return new(zone()) HLoadKeyedSpecializedArrayElement( |
| 3892 external_elements, checked_key, elements_kind); |
| 3893 } |
| 3894 } |
| 3895 |
| 3896 |
| 3897 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
| 3898 HValue* key, |
| 3899 HValue* val, |
| 3900 Expression* expr, |
| 3901 bool is_store) { |
| 3902 ASSERT(expr->IsMonomorphic()); |
| 3903 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3904 if (!map->has_fast_elements() && !map->has_external_array_elements()) { |
| 3905 return is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 3906 : BuildLoadKeyedGeneric(object, key); |
| 3907 } |
| 3689 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3908 AddInstruction(new(zone()) HCheckNonSmi(object)); |
| 3690 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3909 AddInstruction(new(zone()) HCheckMap(object, map)); |
| 3910 HInstruction* elements = new(zone()) HLoadElements(object); |
| 3911 HInstruction* length = NULL; |
| 3912 HInstruction* checked_key = NULL; |
| 3913 if (map->has_external_array_elements()) { |
| 3914 AddInstruction(elements); |
| 3915 length = AddInstruction(new(zone()) HExternalArrayLength(elements)); |
| 3916 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 3917 HLoadExternalArrayPointer* external_elements = |
| 3918 new(zone()) HLoadExternalArrayPointer(elements); |
| 3919 AddInstruction(external_elements); |
| 3920 return BuildExternalArrayElementAccess(external_elements, checked_key, |
| 3921 val, map->elements_kind(), is_store); |
| 3922 } |
| 3691 ASSERT(map->has_fast_elements()); | 3923 ASSERT(map->has_fast_elements()); |
| 3692 AddInstruction(new(zone()) HCheckMap(object, map)); | 3924 if (map->instance_type() == JS_ARRAY_TYPE) { |
| 3693 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | |
| 3694 HLoadElements* elements = new(zone()) HLoadElements(object); | |
| 3695 HInstruction* length = NULL; | |
| 3696 if (is_array) { | |
| 3697 length = AddInstruction(new(zone()) HJSArrayLength(object)); | 3925 length = AddInstruction(new(zone()) HJSArrayLength(object)); |
| 3698 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3926 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 3699 AddInstruction(elements); | 3927 AddInstruction(elements); |
| 3700 } else { | 3928 } else { |
| 3701 AddInstruction(elements); | 3929 AddInstruction(elements); |
| 3702 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | 3930 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); |
| 3703 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3931 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 3704 } | 3932 } |
| 3705 return new(zone()) HLoadKeyedFastElement(elements, key); | 3933 if (is_store) { |
| 3706 } | 3934 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); |
| 3707 | 3935 } else { |
| 3708 | 3936 return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
| 3709 HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement( | 3937 } |
| 3710 HValue* object, | 3938 } |
| 3711 HValue* key, | 3939 |
| 3712 Property* expr) { | 3940 |
| 3713 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3941 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
| 3942 HValue* key, |
| 3943 HValue* val, |
| 3944 Expression* prop, |
| 3945 int ast_id, |
| 3946 int position, |
| 3947 bool is_store, |
| 3948 bool* has_side_effects) { |
| 3949 *has_side_effects = false; |
| 3714 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3950 AddInstruction(new(zone()) HCheckNonSmi(object)); |
| 3715 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3951 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
| 3716 ASSERT(!map->has_fast_elements()); | 3952 ZoneMapList* maps = prop->GetReceiverTypes(); |
| 3717 ASSERT(map->has_external_array_elements()); | 3953 bool todo_external_array = false; |
| 3718 AddInstruction(new(zone()) HCheckMap(object, map)); | 3954 |
| 3719 HLoadElements* elements = new(zone()) HLoadElements(object); | 3955 static const int kNumElementTypes = JSObject::kElementsKindCount; |
| 3720 AddInstruction(elements); | 3956 bool type_todo[kNumElementTypes]; |
| 3721 HInstruction* length = new(zone()) HExternalArrayLength(elements); | 3957 for (int i = 0; i < kNumElementTypes; ++i) { |
| 3722 AddInstruction(length); | 3958 type_todo[i] = false; |
| 3723 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3959 } |
| 3724 HLoadExternalArrayPointer* external_elements = | 3960 |
| 3725 new(zone()) HLoadExternalArrayPointer(elements); | 3961 for (int i = 0; i < maps->length(); ++i) { |
| 3726 AddInstruction(external_elements); | 3962 ASSERT(maps->at(i)->IsMap()); |
| 3727 HLoadKeyedSpecializedArrayElement* pixel_array_value = | 3963 type_todo[maps->at(i)->elements_kind()] = true; |
| 3728 new(zone()) HLoadKeyedSpecializedArrayElement( | 3964 if (maps->at(i)->elements_kind() |
| 3729 external_elements, key, expr->external_array_type()); | 3965 >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
| 3730 return pixel_array_value; | 3966 todo_external_array = true; |
| 3731 } | 3967 } |
| 3732 | 3968 } |
| 3733 | 3969 // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt. |
| 3734 HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj, | 3970 type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false; |
| 3735 HValue* key, | 3971 |
| 3736 Property* prop) { | 3972 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 3737 if (prop->IsMonomorphic()) { | 3973 |
| 3738 Handle<Map> receiver_type(prop->GetMonomorphicReceiverType()); | 3974 HInstruction* elements_kind_instr = |
| 3739 // An object has either fast elements or pixel array elements, but never | 3975 AddInstruction(new(zone()) HElementsKind(object)); |
| 3740 // both. Pixel array maps that are assigned to pixel array elements are | 3976 HInstruction* elements = NULL; |
| 3741 // always created with the fast elements flag cleared. | 3977 HLoadExternalArrayPointer* external_elements = NULL; |
| 3742 if (receiver_type->has_external_array_elements()) { | 3978 HInstruction* checked_key = NULL; |
| 3743 return BuildLoadKeyedSpecializedArrayElement(obj, key, prop); | 3979 |
| 3744 } else if (receiver_type->has_fast_elements()) { | 3980 // FAST_ELEMENTS is assumed to be the first case. |
| 3745 return BuildLoadKeyedFastElement(obj, key, prop); | 3981 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); |
| 3746 } | 3982 |
| 3747 } | 3983 for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS; |
| 3748 return BuildLoadKeyedGeneric(obj, key); | 3984 elements_kind <= JSObject::LAST_ELEMENTS_KIND; |
| 3749 } | 3985 elements_kind = JSObject::ElementsKind(elements_kind + 1)) { |
| 3750 | 3986 // After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we |
| 3751 | 3987 // need to add some code that's executed for all external array cases. |
| 3988 STATIC_ASSERT(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
| 3989 JSObject::LAST_ELEMENTS_KIND); |
| 3990 if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND |
| 3991 && todo_external_array) { |
| 3992 elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 3993 // We need to forcibly prevent some ElementsKind-dependent instructions |
| 3994 // from being hoisted out of any loops they might occur in, because |
| 3995 // the current loop-invariant-code-motion algorithm isn't clever enough |
| 3996 // to deal with them properly. |
| 3997 // There's some performance to be gained by developing a smarter |
| 3998 // solution for this. |
| 3999 elements->ClearFlag(HValue::kUseGVN); |
| 4000 HInstruction* length = |
| 4001 AddInstruction(new(zone()) HExternalArrayLength(elements)); |
| 4002 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4003 external_elements = new(zone()) HLoadExternalArrayPointer(elements); |
| 4004 AddInstruction(external_elements); |
| 4005 } |
| 4006 if (type_todo[elements_kind]) { |
| 4007 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 4008 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 4009 HCompareConstantEqAndBranch* compare = |
| 4010 new(zone()) HCompareConstantEqAndBranch(elements_kind_instr, |
| 4011 elements_kind, |
| 4012 Token::EQ_STRICT); |
| 4013 compare->SetSuccessorAt(0, if_true); |
| 4014 compare->SetSuccessorAt(1, if_false); |
| 4015 current_block()->Finish(compare); |
| 4016 |
| 4017 set_current_block(if_true); |
| 4018 HInstruction* access; |
| 4019 if (elements_kind == JSObject::FAST_ELEMENTS) { |
| 4020 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); |
| 4021 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); |
| 4022 HHasInstanceTypeAndBranch* typecheck = |
| 4023 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); |
| 4024 typecheck->SetSuccessorAt(0, if_jsarray); |
| 4025 typecheck->SetSuccessorAt(1, if_fastobject); |
| 4026 current_block()->Finish(typecheck); |
| 4027 |
| 4028 set_current_block(if_jsarray); |
| 4029 HInstruction* length = new(zone()) HJSArrayLength(object); |
| 4030 AddInstruction(length); |
| 4031 length->ClearFlag(HValue::kUseGVN); |
| 4032 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4033 elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 4034 elements->ClearFlag(HValue::kUseGVN); |
| 4035 if (is_store) { |
| 4036 access = AddInstruction( |
| 4037 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); |
| 4038 } else { |
| 4039 access = AddInstruction( |
| 4040 new(zone()) HLoadKeyedFastElement(elements, checked_key)); |
| 4041 Push(access); |
| 4042 } |
| 4043 *has_side_effects |= access->HasSideEffects(); |
| 4044 if (position != -1) { |
| 4045 access->set_position(position); |
| 4046 } |
| 4047 if_jsarray->Goto(join); |
| 4048 |
| 4049 set_current_block(if_fastobject); |
| 4050 elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 4051 elements->ClearFlag(HValue::kUseGVN); |
| 4052 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); |
| 4053 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4054 if (is_store) { |
| 4055 access = AddInstruction( |
| 4056 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); |
| 4057 } else { |
| 4058 access = AddInstruction( |
| 4059 new(zone()) HLoadKeyedFastElement(elements, checked_key)); |
| 4060 } |
| 4061 } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) { |
| 4062 if (is_store) { |
| 4063 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
| 4064 } else { |
| 4065 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); |
| 4066 } |
| 4067 } else { // External array elements. |
| 4068 access = AddInstruction(BuildExternalArrayElementAccess( |
| 4069 external_elements, checked_key, val, elements_kind, is_store)); |
| 4070 } |
| 4071 *has_side_effects |= access->HasSideEffects(); |
| 4072 access->set_position(position); |
| 4073 if (!is_store) { |
| 4074 Push(access); |
| 4075 } |
| 4076 current_block()->Goto(join); |
| 4077 set_current_block(if_false); |
| 4078 } |
| 4079 } |
| 4080 |
| 4081 // Deopt if none of the cases matched. |
| 4082 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
| 4083 join->SetJoinId(ast_id); |
| 4084 set_current_block(join); |
| 4085 return is_store ? NULL : Pop(); |
| 4086 } |
| 4087 |
| 4088 |
| 4089 HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj, |
| 4090 HValue* key, |
| 4091 HValue* val, |
| 4092 Expression* expr, |
| 4093 int ast_id, |
| 4094 int position, |
| 4095 bool is_store, |
| 4096 bool* has_side_effects) { |
| 4097 ASSERT(!expr->IsPropertyName()); |
| 4098 HInstruction* instr = NULL; |
| 4099 if (expr->IsMonomorphic()) { |
| 4100 instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store); |
| 4101 } else if (expr->GetReceiverTypes() != NULL && |
| 4102 !expr->GetReceiverTypes()->is_empty()) { |
| 4103 return HandlePolymorphicElementAccess( |
| 4104 obj, key, val, expr, ast_id, position, is_store, has_side_effects); |
| 4105 } else { |
| 4106 if (is_store) { |
| 4107 instr = BuildStoreKeyedGeneric(obj, key, val); |
| 4108 } else { |
| 4109 instr = BuildLoadKeyedGeneric(obj, key); |
| 4110 } |
| 4111 } |
| 4112 instr->set_position(position); |
| 4113 AddInstruction(instr); |
| 4114 *has_side_effects = instr->HasSideEffects(); |
| 4115 return instr; |
| 4116 } |
| 4117 |
| 4118 |
| 3752 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 4119 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
| 3753 HValue* key, | 4120 HValue* key, |
| 3754 HValue* value) { | 4121 HValue* value) { |
| 3755 HValue* context = environment()->LookupContext(); | 4122 HValue* context = environment()->LookupContext(); |
| 3756 return new(zone()) HStoreKeyedGeneric( | 4123 return new(zone()) HStoreKeyedGeneric( |
| 3757 context, | 4124 context, |
| 3758 object, | 4125 object, |
| 3759 key, | 4126 key, |
| 3760 value, | 4127 value, |
| 3761 function_strict_mode()); | 4128 function_strict_mode()); |
| 3762 } | 4129 } |
| 3763 | 4130 |
| 3764 | |
| 3765 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, | |
| 3766 HValue* key, | |
| 3767 HValue* val, | |
| 3768 Expression* expr) { | |
| 3769 ASSERT(expr->IsMonomorphic()); | |
| 3770 AddInstruction(new(zone()) HCheckNonSmi(object)); | |
| 3771 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
| 3772 ASSERT(map->has_fast_elements()); | |
| 3773 AddInstruction(new(zone()) HCheckMap(object, map)); | |
| 3774 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | |
| 3775 AddInstruction(new(zone()) HCheckMap( | |
| 3776 elements, isolate()->factory()->fixed_array_map())); | |
| 3777 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | |
| 3778 HInstruction* length = NULL; | |
| 3779 if (is_array) { | |
| 3780 length = AddInstruction(new(zone()) HJSArrayLength(object)); | |
| 3781 } else { | |
| 3782 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | |
| 3783 } | |
| 3784 AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
| 3785 return new(zone()) HStoreKeyedFastElement(elements, key, val); | |
| 3786 } | |
| 3787 | |
| 3788 | |
| 3789 HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement( | |
| 3790 HValue* object, | |
| 3791 HValue* key, | |
| 3792 HValue* val, | |
| 3793 Expression* expr) { | |
| 3794 ASSERT(expr->IsMonomorphic()); | |
| 3795 AddInstruction(new(zone()) HCheckNonSmi(object)); | |
| 3796 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
| 3797 ASSERT(!map->has_fast_elements()); | |
| 3798 ASSERT(map->has_external_array_elements()); | |
| 3799 AddInstruction(new(zone()) HCheckMap(object, map)); | |
| 3800 HLoadElements* elements = new(zone()) HLoadElements(object); | |
| 3801 AddInstruction(elements); | |
| 3802 HInstruction* length = AddInstruction( | |
| 3803 new(zone()) HExternalArrayLength(elements)); | |
| 3804 AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
| 3805 HLoadExternalArrayPointer* external_elements = | |
| 3806 new(zone()) HLoadExternalArrayPointer(elements); | |
| 3807 AddInstruction(external_elements); | |
| 3808 if (expr->external_array_type() == kExternalPixelArray) { | |
| 3809 HClampToUint8* clamp = new(zone()) HClampToUint8(val); | |
| 3810 AddInstruction(clamp); | |
| 3811 val = clamp; | |
| 3812 } | |
| 3813 return new(zone()) HStoreKeyedSpecializedArrayElement( | |
| 3814 external_elements, | |
| 3815 key, | |
| 3816 val, | |
| 3817 expr->external_array_type()); | |
| 3818 } | |
| 3819 | |
| 3820 | |
| 3821 HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object, | |
| 3822 HValue* key, | |
| 3823 HValue* value, | |
| 3824 Expression* expr) { | |
| 3825 if (expr->IsMonomorphic()) { | |
| 3826 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); | |
| 3827 // An object has either fast elements or external array elements, but | |
| 3828 // never both. Pixel array maps that are assigned to pixel array elements | |
| 3829 // are always created with the fast elements flag cleared. | |
| 3830 if (receiver_type->has_external_array_elements()) { | |
| 3831 return BuildStoreKeyedSpecializedArrayElement(object, | |
| 3832 key, | |
| 3833 value, | |
| 3834 expr); | |
| 3835 } else if (receiver_type->has_fast_elements()) { | |
| 3836 return BuildStoreKeyedFastElement(object, key, value, expr); | |
| 3837 } | |
| 3838 } | |
| 3839 return BuildStoreKeyedGeneric(object, key, value); | |
| 3840 } | |
| 3841 | |
| 3842 | |
| 3843 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 4131 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
| 3844 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 4132 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
| 3845 if (proxy == NULL) return false; | 4133 if (proxy == NULL) return false; |
| 3846 if (!proxy->var()->IsStackAllocated()) return false; | 4134 if (!proxy->var()->IsStackAllocated()) return false; |
| 3847 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 4135 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
| 3848 return false; | 4136 return false; |
| 3849 } | 4137 } |
| 3850 | 4138 |
| 4139 // Our implementation of arguments (based on this stack frame or an |
| 4140 // adapter below it) does not work for inlined functions. |
| 4141 if (function_state()->outer() != NULL) { |
| 4142 Bailout("arguments access in inlined function"); |
| 4143 return true; |
| 4144 } |
| 4145 |
| 3851 HInstruction* result = NULL; | 4146 HInstruction* result = NULL; |
| 3852 if (expr->key()->IsPropertyName()) { | 4147 if (expr->key()->IsPropertyName()) { |
| 3853 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 4148 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3854 if (!name->IsEqualTo(CStrVector("length"))) return false; | 4149 if (!name->IsEqualTo(CStrVector("length"))) return false; |
| 3855 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 4150 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
| 3856 result = new(zone()) HArgumentsLength(elements); | 4151 result = new(zone()) HArgumentsLength(elements); |
| 3857 } else { | 4152 } else { |
| 3858 Push(graph()->GetArgumentsObject()); | 4153 Push(graph()->GetArgumentsObject()); |
| 3859 VisitForValue(expr->key()); | 4154 VisitForValue(expr->key()); |
| 3860 if (HasStackOverflow() || current_block() == NULL) return true; | 4155 if (HasStackOverflow() || current_block() == NULL) return true; |
| 3861 HValue* key = Pop(); | 4156 HValue* key = Pop(); |
| 3862 Drop(1); // Arguments object. | 4157 Drop(1); // Arguments object. |
| 3863 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 4158 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
| 3864 HInstruction* length = AddInstruction( | 4159 HInstruction* length = AddInstruction( |
| 3865 new(zone()) HArgumentsLength(elements)); | 4160 new(zone()) HArgumentsLength(elements)); |
| 3866 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4161 HInstruction* checked_key = |
| 3867 result = new(zone()) HAccessArgumentsAt(elements, length, key); | 4162 AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4163 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
| 3868 } | 4164 } |
| 3869 ast_context()->ReturnInstruction(result, expr->id()); | 4165 ast_context()->ReturnInstruction(result, expr->id()); |
| 3870 return true; | 4166 return true; |
| 3871 } | 4167 } |
| 3872 | 4168 |
| 3873 | 4169 |
| 3874 void HGraphBuilder::VisitProperty(Property* expr) { | 4170 void HGraphBuilder::VisitProperty(Property* expr) { |
| 3875 ASSERT(!HasStackOverflow()); | 4171 ASSERT(!HasStackOverflow()); |
| 3876 ASSERT(current_block() != NULL); | 4172 ASSERT(current_block() != NULL); |
| 3877 ASSERT(current_block()->HasPredecessor()); | 4173 ASSERT(current_block()->HasPredecessor()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3890 | 4186 |
| 3891 } else if (expr->IsStringLength()) { | 4187 } else if (expr->IsStringLength()) { |
| 3892 HValue* string = Pop(); | 4188 HValue* string = Pop(); |
| 3893 AddInstruction(new(zone()) HCheckNonSmi(string)); | 4189 AddInstruction(new(zone()) HCheckNonSmi(string)); |
| 3894 AddInstruction(HCheckInstanceType::NewIsString(string)); | 4190 AddInstruction(HCheckInstanceType::NewIsString(string)); |
| 3895 instr = new(zone()) HStringLength(string); | 4191 instr = new(zone()) HStringLength(string); |
| 3896 } else if (expr->IsStringAccess()) { | 4192 } else if (expr->IsStringAccess()) { |
| 3897 CHECK_ALIVE(VisitForValue(expr->key())); | 4193 CHECK_ALIVE(VisitForValue(expr->key())); |
| 3898 HValue* index = Pop(); | 4194 HValue* index = Pop(); |
| 3899 HValue* string = Pop(); | 4195 HValue* string = Pop(); |
| 3900 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); | 4196 HValue* context = environment()->LookupContext(); |
| 4197 HStringCharCodeAt* char_code = |
| 4198 BuildStringCharCodeAt(context, string, index); |
| 3901 AddInstruction(char_code); | 4199 AddInstruction(char_code); |
| 3902 instr = new(zone()) HStringCharFromCode(char_code); | 4200 instr = new(zone()) HStringCharFromCode(context, char_code); |
| 3903 | 4201 |
| 3904 } else if (expr->IsFunctionPrototype()) { | 4202 } else if (expr->IsFunctionPrototype()) { |
| 3905 HValue* function = Pop(); | 4203 HValue* function = Pop(); |
| 3906 AddInstruction(new(zone()) HCheckNonSmi(function)); | 4204 AddInstruction(new(zone()) HCheckNonSmi(function)); |
| 3907 instr = new(zone()) HLoadFunctionPrototype(function); | 4205 instr = new(zone()) HLoadFunctionPrototype(function); |
| 3908 | 4206 |
| 3909 } else if (expr->key()->IsPropertyName()) { | 4207 } else if (expr->key()->IsPropertyName()) { |
| 3910 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 4208 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3911 ZoneMapList* types = expr->GetReceiverTypes(); | 4209 ZoneMapList* types = expr->GetReceiverTypes(); |
| 3912 | 4210 |
| 3913 HValue* obj = Pop(); | 4211 HValue* obj = Pop(); |
| 3914 if (expr->IsMonomorphic()) { | 4212 if (expr->IsMonomorphic()) { |
| 3915 instr = BuildLoadNamed(obj, expr, types->first(), name); | 4213 instr = BuildLoadNamed(obj, expr, types->first(), name); |
| 3916 } else if (types != NULL && types->length() > 1) { | 4214 } else if (types != NULL && types->length() > 1) { |
| 3917 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 4215 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
| 3918 instr = new(zone()) HLoadNamedFieldPolymorphic(obj, types, name); | 4216 HValue* context = environment()->LookupContext(); |
| 4217 instr = new(zone()) HLoadNamedFieldPolymorphic(context, obj, types, name); |
| 3919 } else { | 4218 } else { |
| 3920 instr = BuildLoadNamedGeneric(obj, expr); | 4219 instr = BuildLoadNamedGeneric(obj, expr); |
| 3921 } | 4220 } |
| 3922 | 4221 |
| 3923 } else { | 4222 } else { |
| 3924 CHECK_ALIVE(VisitForValue(expr->key())); | 4223 CHECK_ALIVE(VisitForValue(expr->key())); |
| 3925 | 4224 |
| 3926 HValue* key = Pop(); | 4225 HValue* key = Pop(); |
| 3927 HValue* obj = Pop(); | 4226 HValue* obj = Pop(); |
| 3928 instr = BuildLoadKeyed(obj, key, expr); | 4227 |
| 4228 bool has_side_effects = false; |
| 4229 HValue* load = HandleKeyedElementAccess( |
| 4230 obj, key, NULL, expr, expr->id(), expr->position(), |
| 4231 false, // is_store |
| 4232 &has_side_effects); |
| 4233 if (has_side_effects) { |
| 4234 if (ast_context()->IsEffect()) { |
| 4235 AddSimulate(expr->id()); |
| 4236 } else { |
| 4237 Push(load); |
| 4238 AddSimulate(expr->id()); |
| 4239 Drop(1); |
| 4240 } |
| 4241 } |
| 4242 return ast_context()->ReturnValue(load); |
| 3929 } | 4243 } |
| 3930 instr->set_position(expr->position()); | 4244 instr->set_position(expr->position()); |
| 3931 ast_context()->ReturnInstruction(instr, expr->id()); | 4245 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3932 } | 4246 } |
| 3933 | 4247 |
| 3934 | 4248 |
| 3935 void HGraphBuilder::AddCheckConstantFunction(Call* expr, | 4249 void HGraphBuilder::AddCheckConstantFunction(Call* expr, |
| 3936 HValue* receiver, | 4250 HValue* receiver, |
| 3937 Handle<Map> receiver_map, | 4251 Handle<Map> receiver_map, |
| 3938 bool smi_and_map_check) { | 4252 bool smi_and_map_check) { |
| 3939 // Constant functions have the nice property that the map will change if they | 4253 // Constant functions have the nice property that the map will change if they |
| 3940 // are overwritten. Therefore it is enough to check the map of the holder and | 4254 // are overwritten. Therefore it is enough to check the map of the holder and |
| 3941 // its prototypes. | 4255 // its prototypes. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4009 HValue* context = environment()->LookupContext(); | 4323 HValue* context = environment()->LookupContext(); |
| 4010 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); | 4324 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); |
| 4011 call->set_position(expr->position()); | 4325 call->set_position(expr->position()); |
| 4012 PreProcessCall(call); | 4326 PreProcessCall(call); |
| 4013 | 4327 |
| 4014 if (join != NULL) { | 4328 if (join != NULL) { |
| 4015 AddInstruction(call); | 4329 AddInstruction(call); |
| 4016 if (!ast_context()->IsEffect()) Push(call); | 4330 if (!ast_context()->IsEffect()) Push(call); |
| 4017 current_block()->Goto(join); | 4331 current_block()->Goto(join); |
| 4018 } else { | 4332 } else { |
| 4019 ast_context()->ReturnInstruction(call, expr->id()); | 4333 return ast_context()->ReturnInstruction(call, expr->id()); |
| 4020 return; | |
| 4021 } | 4334 } |
| 4022 } | 4335 } |
| 4023 | 4336 |
| 4024 // We assume that control flow is always live after an expression. So | 4337 // We assume that control flow is always live after an expression. So |
| 4025 // even without predecessors to the join block, we set it as the exit | 4338 // even without predecessors to the join block, we set it as the exit |
| 4026 // block and continue by adding instructions there. | 4339 // block and continue by adding instructions there. |
| 4027 ASSERT(join != NULL); | 4340 ASSERT(join != NULL); |
| 4028 if (join->HasPredecessor()) { | 4341 if (join->HasPredecessor()) { |
| 4029 set_current_block(join); | 4342 set_current_block(join); |
| 4030 join->SetJoinId(expr->id()); | 4343 join->SetJoinId(expr->id()); |
| 4031 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 4344 if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop()); |
| 4032 } else { | 4345 } else { |
| 4033 set_current_block(NULL); | 4346 set_current_block(NULL); |
| 4034 } | 4347 } |
| 4035 } | 4348 } |
| 4036 | 4349 |
| 4037 | 4350 |
| 4038 void HGraphBuilder::TraceInline(Handle<JSFunction> target, | 4351 void HGraphBuilder::TraceInline(Handle<JSFunction> target, |
| 4039 Handle<JSFunction> caller, | 4352 Handle<JSFunction> caller, |
| 4040 const char* reason) { | 4353 const char* reason) { |
| 4041 if (FLAG_trace_inlining) { | 4354 if (FLAG_trace_inlining) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4133 } | 4446 } |
| 4134 FunctionLiteral* function = target_info.function(); | 4447 FunctionLiteral* function = target_info.function(); |
| 4135 | 4448 |
| 4136 // Count the number of AST nodes added by inlining this call. | 4449 // Count the number of AST nodes added by inlining this call. |
| 4137 int nodes_added = AstNode::Count() - count_before; | 4450 int nodes_added = AstNode::Count() - count_before; |
| 4138 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | 4451 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { |
| 4139 TraceInline(target, caller, "target AST is too large"); | 4452 TraceInline(target, caller, "target AST is too large"); |
| 4140 return false; | 4453 return false; |
| 4141 } | 4454 } |
| 4142 | 4455 |
| 4143 // Check if we can handle all declarations in the inlined functions. | |
| 4144 VisitDeclarations(target_info.scope()->declarations()); | |
| 4145 if (HasStackOverflow()) { | |
| 4146 TraceInline(target, caller, "target has non-trivial declaration"); | |
| 4147 ClearStackOverflow(); | |
| 4148 return false; | |
| 4149 } | |
| 4150 | |
| 4151 // Don't inline functions that uses the arguments object or that | 4456 // Don't inline functions that uses the arguments object or that |
| 4152 // have a mismatching number of parameters. | 4457 // have a mismatching number of parameters. |
| 4153 int arity = expr->arguments()->length(); | 4458 int arity = expr->arguments()->length(); |
| 4154 if (function->scope()->arguments() != NULL || | 4459 if (function->scope()->arguments() != NULL || |
| 4155 arity != target_shared->formal_parameter_count()) { | 4460 arity != target_shared->formal_parameter_count()) { |
| 4156 TraceInline(target, caller, "target requires special argument handling"); | 4461 TraceInline(target, caller, "target requires special argument handling"); |
| 4157 return false; | 4462 return false; |
| 4158 } | 4463 } |
| 4159 | 4464 |
| 4465 // All declarations must be inlineable. |
| 4466 ZoneList<Declaration*>* decls = target_info.scope()->declarations(); |
| 4467 int decl_count = decls->length(); |
| 4468 for (int i = 0; i < decl_count; ++i) { |
| 4469 if (!decls->at(i)->IsInlineable()) { |
| 4470 TraceInline(target, caller, "target has non-trivial declaration"); |
| 4471 return false; |
| 4472 } |
| 4473 } |
| 4160 // All statements in the body must be inlineable. | 4474 // All statements in the body must be inlineable. |
| 4161 for (int i = 0, count = function->body()->length(); i < count; ++i) { | 4475 for (int i = 0, count = function->body()->length(); i < count; ++i) { |
| 4162 if (!function->body()->at(i)->IsInlineable()) { | 4476 if (!function->body()->at(i)->IsInlineable()) { |
| 4163 TraceInline(target, caller, "target contains unsupported syntax"); | 4477 TraceInline(target, caller, "target contains unsupported syntax"); |
| 4164 return false; | 4478 return false; |
| 4165 } | 4479 } |
| 4166 } | 4480 } |
| 4167 | 4481 |
| 4168 // Generate the deoptimization data for the unoptimized version of | 4482 // Generate the deoptimization data for the unoptimized version of |
| 4169 // the target function if we don't already have it. | 4483 // the target function if we don't already have it. |
| 4170 if (!target_shared->has_deoptimization_support()) { | 4484 if (!target_shared->has_deoptimization_support()) { |
| 4171 // Note that we compile here using the same AST that we will use for | 4485 // Note that we compile here using the same AST that we will use for |
| 4172 // generating the optimized inline code. | 4486 // generating the optimized inline code. |
| 4173 target_info.EnableDeoptimizationSupport(); | 4487 target_info.EnableDeoptimizationSupport(); |
| 4174 if (!FullCodeGenerator::MakeCode(&target_info)) { | 4488 if (!FullCodeGenerator::MakeCode(&target_info)) { |
| 4175 TraceInline(target, caller, "could not generate deoptimization info"); | 4489 TraceInline(target, caller, "could not generate deoptimization info"); |
| 4176 return false; | 4490 return false; |
| 4177 } | 4491 } |
| 4492 if (target_shared->scope_info() == SerializedScopeInfo::Empty()) { |
| 4493 // The scope info might not have been set if a lazily compiled |
| 4494 // function is inlined before being called for the first time. |
| 4495 Handle<SerializedScopeInfo> target_scope_info = |
| 4496 SerializedScopeInfo::Create(target_info.scope()); |
| 4497 target_shared->set_scope_info(*target_scope_info); |
| 4498 } |
| 4178 target_shared->EnableDeoptimizationSupport(*target_info.code()); | 4499 target_shared->EnableDeoptimizationSupport(*target_info.code()); |
| 4179 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, | 4500 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, |
| 4180 &target_info, | 4501 &target_info, |
| 4181 target_shared); | 4502 target_shared); |
| 4182 } | 4503 } |
| 4183 | 4504 |
| 4184 // ---------------------------------------------------------------- | 4505 // ---------------------------------------------------------------- |
| 4506 // After this point, we've made a decision to inline this function (so |
| 4507 // TryInline should always return true). |
| 4508 |
| 4185 // Save the pending call context and type feedback oracle. Set up new ones | 4509 // Save the pending call context and type feedback oracle. Set up new ones |
| 4186 // for the inlined function. | 4510 // for the inlined function. |
| 4187 ASSERT(target_shared->has_deoptimization_support()); | 4511 ASSERT(target_shared->has_deoptimization_support()); |
| 4188 TypeFeedbackOracle target_oracle( | 4512 TypeFeedbackOracle target_oracle( |
| 4189 Handle<Code>(target_shared->code()), | 4513 Handle<Code>(target_shared->code()), |
| 4190 Handle<Context>(target->context()->global_context())); | 4514 Handle<Context>(target->context()->global_context())); |
| 4191 FunctionState target_state(this, &target_info, &target_oracle); | 4515 FunctionState target_state(this, &target_info, &target_oracle); |
| 4192 | 4516 |
| 4193 HConstant* undefined = graph()->GetConstantUndefined(); | 4517 HConstant* undefined = graph()->GetConstantUndefined(); |
| 4194 HEnvironment* inner_env = | 4518 HEnvironment* inner_env = |
| 4195 environment()->CopyForInlining(target, | 4519 environment()->CopyForInlining(target, |
| 4196 function, | 4520 function, |
| 4197 HEnvironment::HYDROGEN, | |
| 4198 undefined, | 4521 undefined, |
| 4199 call_kind); | 4522 call_kind); |
| 4200 HBasicBlock* body_entry = CreateBasicBlock(inner_env); | 4523 HBasicBlock* body_entry = CreateBasicBlock(inner_env); |
| 4201 current_block()->Goto(body_entry); | 4524 current_block()->Goto(body_entry); |
| 4202 | |
| 4203 body_entry->SetJoinId(expr->ReturnId()); | 4525 body_entry->SetJoinId(expr->ReturnId()); |
| 4204 set_current_block(body_entry); | 4526 set_current_block(body_entry); |
| 4205 AddInstruction(new(zone()) HEnterInlined(target, | 4527 AddInstruction(new(zone()) HEnterInlined(target, |
| 4206 function, | 4528 function, |
| 4207 call_kind)); | 4529 call_kind)); |
| 4530 VisitDeclarations(target_info.scope()->declarations()); |
| 4208 VisitStatements(function->body()); | 4531 VisitStatements(function->body()); |
| 4209 if (HasStackOverflow()) { | 4532 if (HasStackOverflow()) { |
| 4210 // Bail out if the inline function did, as we cannot residualize a call | 4533 // Bail out if the inline function did, as we cannot residualize a call |
| 4211 // instead. | 4534 // instead. |
| 4212 TraceInline(target, caller, "inline graph construction failed"); | 4535 TraceInline(target, caller, "inline graph construction failed"); |
| 4213 target_shared->DisableOptimization(*target); | 4536 target_shared->DisableOptimization(*target); |
| 4214 inline_bailout_ = true; | 4537 inline_bailout_ = true; |
| 4215 return true; | 4538 return true; |
| 4216 } | 4539 } |
| 4217 | 4540 |
| 4218 // Update inlined nodes count. | 4541 // Update inlined nodes count. |
| 4219 inlined_count_ += nodes_added; | 4542 inlined_count_ += nodes_added; |
| 4220 | 4543 |
| 4221 TraceInline(target, caller, NULL); | 4544 TraceInline(target, caller, NULL); |
| 4222 | 4545 |
| 4223 if (current_block() != NULL) { | 4546 if (current_block() != NULL) { |
| 4224 // Add a return of undefined if control can fall off the body. In a | 4547 // Add a return of undefined if control can fall off the body. In a |
| 4225 // test context, undefined is false. | 4548 // test context, undefined is false. |
| 4226 if (inlined_test_context() == NULL) { | 4549 if (inlined_test_context() == NULL) { |
| 4227 ASSERT(function_return() != NULL); | 4550 ASSERT(function_return() != NULL); |
| 4228 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); | 4551 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
| 4229 if (call_context()->IsEffect()) { | 4552 if (call_context()->IsEffect()) { |
| 4230 current_block()->Goto(function_return(), false); | 4553 current_block()->Goto(function_return()); |
| 4231 } else { | 4554 } else { |
| 4232 current_block()->AddLeaveInlined(undefined, function_return()); | 4555 current_block()->AddLeaveInlined(undefined, function_return()); |
| 4233 } | 4556 } |
| 4234 } else { | 4557 } else { |
| 4235 // The graph builder assumes control can reach both branches of a | 4558 // The graph builder assumes control can reach both branches of a |
| 4236 // test, so we materialize the undefined value and test it rather than | 4559 // test, so we materialize the undefined value and test it rather than |
| 4237 // simply jumping to the false target. | 4560 // simply jumping to the false target. |
| 4238 // | 4561 // |
| 4239 // TODO(3168478): refactor to avoid this. | 4562 // TODO(3168478): refactor to avoid this. |
| 4240 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4563 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 4241 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4564 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 4242 HTest* test = new(zone()) HTest(undefined, empty_true, empty_false); | 4565 HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); |
| 4243 current_block()->Finish(test); | 4566 current_block()->Finish(test); |
| 4244 | 4567 |
| 4245 empty_true->Goto(inlined_test_context()->if_true(), false); | 4568 empty_true->Goto(inlined_test_context()->if_true()); |
| 4246 empty_false->Goto(inlined_test_context()->if_false(), false); | 4569 empty_false->Goto(inlined_test_context()->if_false()); |
| 4247 } | 4570 } |
| 4248 } | 4571 } |
| 4249 | 4572 |
| 4250 // Fix up the function exits. | 4573 // Fix up the function exits. |
| 4251 if (inlined_test_context() != NULL) { | 4574 if (inlined_test_context() != NULL) { |
| 4252 HBasicBlock* if_true = inlined_test_context()->if_true(); | 4575 HBasicBlock* if_true = inlined_test_context()->if_true(); |
| 4253 HBasicBlock* if_false = inlined_test_context()->if_false(); | 4576 HBasicBlock* if_false = inlined_test_context()->if_false(); |
| 4254 if_true->SetJoinId(expr->id()); | 4577 |
| 4255 if_false->SetJoinId(expr->id()); | 4578 // Pop the return test context from the expression context stack. |
| 4256 ASSERT(ast_context() == inlined_test_context()); | 4579 ASSERT(ast_context() == inlined_test_context()); |
| 4257 // Pop the return test context from the expression context stack. | |
| 4258 ClearInlinedTestContext(); | 4580 ClearInlinedTestContext(); |
| 4259 | 4581 |
| 4260 // Forward to the real test context. | 4582 // Forward to the real test context. |
| 4261 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4583 if (if_true->HasPredecessor()) { |
| 4262 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4584 if_true->SetJoinId(expr->id()); |
| 4263 if_true->Goto(true_target, false); | 4585 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 4264 if_false->Goto(false_target, false); | 4586 if_true->Goto(true_target); |
| 4265 | 4587 } |
| 4266 // TODO(kmillikin): Come up with a better way to handle this. It is too | 4588 if (if_false->HasPredecessor()) { |
| 4267 // subtle. NULL here indicates that the enclosing context has no control | 4589 if_false->SetJoinId(expr->id()); |
| 4268 // flow to handle. | 4590 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 4591 if_false->Goto(false_target); |
| 4592 } |
| 4269 set_current_block(NULL); | 4593 set_current_block(NULL); |
| 4270 | 4594 |
| 4271 } else if (function_return()->HasPredecessor()) { | 4595 } else if (function_return()->HasPredecessor()) { |
| 4272 function_return()->SetJoinId(expr->id()); | 4596 function_return()->SetJoinId(expr->id()); |
| 4273 set_current_block(function_return()); | 4597 set_current_block(function_return()); |
| 4274 } else { | 4598 } else { |
| 4275 set_current_block(NULL); | 4599 set_current_block(NULL); |
| 4276 } | 4600 } |
| 4277 | 4601 |
| 4278 return true; | 4602 return true; |
| 4279 } | 4603 } |
| 4280 | 4604 |
| 4281 | 4605 |
| 4282 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, | 4606 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 4283 HValue* receiver, | 4607 HValue* receiver, |
| 4284 Handle<Map> receiver_map, | 4608 Handle<Map> receiver_map, |
| 4285 CheckType check_type) { | 4609 CheckType check_type) { |
| 4286 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | 4610 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| 4287 // Try to inline calls like Math.* as operations in the calling function. | 4611 // Try to inline calls like Math.* as operations in the calling function. |
| 4288 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 4612 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 4289 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4613 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4290 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4614 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4291 switch (id) { | 4615 switch (id) { |
| 4292 case kStringCharCodeAt: | 4616 case kStringCharCodeAt: |
| 4293 case kStringCharAt: | 4617 case kStringCharAt: |
| 4294 if (argument_count == 2 && check_type == STRING_CHECK) { | 4618 if (argument_count == 2 && check_type == STRING_CHECK) { |
| 4295 HValue* index = Pop(); | 4619 HValue* index = Pop(); |
| 4296 HValue* string = Pop(); | 4620 HValue* string = Pop(); |
| 4621 HValue* context = environment()->LookupContext(); |
| 4297 ASSERT(!expr->holder().is_null()); | 4622 ASSERT(!expr->holder().is_null()); |
| 4298 AddInstruction(new(zone()) HCheckPrototypeMaps( | 4623 AddInstruction(new(zone()) HCheckPrototypeMaps( |
| 4299 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), | 4624 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), |
| 4300 expr->holder())); | 4625 expr->holder())); |
| 4301 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); | 4626 HStringCharCodeAt* char_code = |
| 4627 BuildStringCharCodeAt(context, string, index); |
| 4302 if (id == kStringCharCodeAt) { | 4628 if (id == kStringCharCodeAt) { |
| 4303 ast_context()->ReturnInstruction(char_code, expr->id()); | 4629 ast_context()->ReturnInstruction(char_code, expr->id()); |
| 4304 return true; | 4630 return true; |
| 4305 } | 4631 } |
| 4306 AddInstruction(char_code); | 4632 AddInstruction(char_code); |
| 4307 HStringCharFromCode* result = | 4633 HStringCharFromCode* result = |
| 4308 new(zone()) HStringCharFromCode(char_code); | 4634 new(zone()) HStringCharFromCode(context, char_code); |
| 4309 ast_context()->ReturnInstruction(result, expr->id()); | 4635 ast_context()->ReturnInstruction(result, expr->id()); |
| 4310 return true; | 4636 return true; |
| 4311 } | 4637 } |
| 4312 break; | 4638 break; |
| 4313 case kMathRound: | 4639 case kMathRound: |
| 4314 case kMathFloor: | 4640 case kMathFloor: |
| 4315 case kMathAbs: | 4641 case kMathAbs: |
| 4316 case kMathSqrt: | 4642 case kMathSqrt: |
| 4317 case kMathLog: | 4643 case kMathLog: |
| 4318 case kMathSin: | 4644 case kMathSin: |
| 4319 case kMathCos: | 4645 case kMathCos: |
| 4320 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 4646 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| 4321 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 4647 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4322 HValue* argument = Pop(); | 4648 HValue* argument = Pop(); |
| 4649 HValue* context = environment()->LookupContext(); |
| 4323 Drop(1); // Receiver. | 4650 Drop(1); // Receiver. |
| 4324 HUnaryMathOperation* op = new(zone()) HUnaryMathOperation(argument, id); | 4651 HUnaryMathOperation* op = |
| 4652 new(zone()) HUnaryMathOperation(context, argument, id); |
| 4325 op->set_position(expr->position()); | 4653 op->set_position(expr->position()); |
| 4326 ast_context()->ReturnInstruction(op, expr->id()); | 4654 ast_context()->ReturnInstruction(op, expr->id()); |
| 4327 return true; | 4655 return true; |
| 4328 } | 4656 } |
| 4329 break; | 4657 break; |
| 4330 case kMathPow: | 4658 case kMathPow: |
| 4331 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 4659 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
| 4332 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 4660 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4333 HValue* right = Pop(); | 4661 HValue* right = Pop(); |
| 4334 HValue* left = Pop(); | 4662 HValue* left = Pop(); |
| 4335 Pop(); // Pop receiver. | 4663 Pop(); // Pop receiver. |
| 4664 HValue* context = environment()->LookupContext(); |
| 4336 HInstruction* result = NULL; | 4665 HInstruction* result = NULL; |
| 4337 // Use sqrt() if exponent is 0.5 or -0.5. | 4666 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4338 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 4667 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4339 double exponent = HConstant::cast(right)->DoubleValue(); | 4668 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4340 if (exponent == 0.5) { | 4669 if (exponent == 0.5) { |
| 4341 result = new(zone()) HUnaryMathOperation(left, kMathPowHalf); | 4670 result = |
| 4671 new(zone()) HUnaryMathOperation(context, left, kMathPowHalf); |
| 4342 } else if (exponent == -0.5) { | 4672 } else if (exponent == -0.5) { |
| 4343 HConstant* double_one = | 4673 HConstant* double_one = |
| 4344 new(zone()) HConstant(Handle<Object>(Smi::FromInt(1)), | 4674 new(zone()) HConstant(Handle<Object>(Smi::FromInt(1)), |
| 4345 Representation::Double()); | 4675 Representation::Double()); |
| 4346 AddInstruction(double_one); | 4676 AddInstruction(double_one); |
| 4347 HUnaryMathOperation* square_root = | 4677 HUnaryMathOperation* square_root = |
| 4348 new(zone()) HUnaryMathOperation(left, kMathPowHalf); | 4678 new(zone()) HUnaryMathOperation(context, left, kMathPowHalf); |
| 4349 AddInstruction(square_root); | 4679 AddInstruction(square_root); |
| 4350 // MathPowHalf doesn't have side effects so there's no need for | 4680 // MathPowHalf doesn't have side effects so there's no need for |
| 4351 // an environment simulation here. | 4681 // an environment simulation here. |
| 4352 ASSERT(!square_root->HasSideEffects()); | 4682 ASSERT(!square_root->HasSideEffects()); |
| 4353 result = new(zone()) HDiv(double_one, square_root); | 4683 result = new(zone()) HDiv(context, double_one, square_root); |
| 4354 } else if (exponent == 2.0) { | 4684 } else if (exponent == 2.0) { |
| 4355 result = new(zone()) HMul(left, left); | 4685 result = new(zone()) HMul(context, left, left); |
| 4356 } | 4686 } |
| 4357 } else if (right->IsConstant() && | 4687 } else if (right->IsConstant() && |
| 4358 HConstant::cast(right)->HasInteger32Value() && | 4688 HConstant::cast(right)->HasInteger32Value() && |
| 4359 HConstant::cast(right)->Integer32Value() == 2) { | 4689 HConstant::cast(right)->Integer32Value() == 2) { |
| 4360 result = new(zone()) HMul(left, left); | 4690 result = new(zone()) HMul(context, left, left); |
| 4361 } | 4691 } |
| 4362 | 4692 |
| 4363 if (result == NULL) { | 4693 if (result == NULL) { |
| 4364 result = new(zone()) HPower(left, right); | 4694 result = new(zone()) HPower(left, right); |
| 4365 } | 4695 } |
| 4366 ast_context()->ReturnInstruction(result, expr->id()); | 4696 ast_context()->ReturnInstruction(result, expr->id()); |
| 4367 return true; | 4697 return true; |
| 4368 } | 4698 } |
| 4369 break; | 4699 break; |
| 4370 default: | 4700 default: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4389 if (args->length() != 2) return false; | 4719 if (args->length() != 2) return false; |
| 4390 | 4720 |
| 4391 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 4721 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 4392 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 4722 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 4393 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 4723 HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
| 4394 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 4724 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 4395 | 4725 |
| 4396 if (!expr->IsMonomorphic() || | 4726 if (!expr->IsMonomorphic() || |
| 4397 expr->check_type() != RECEIVER_MAP_CHECK) return false; | 4727 expr->check_type() != RECEIVER_MAP_CHECK) return false; |
| 4398 | 4728 |
| 4729 // Our implementation of arguments (based on this stack frame or an |
| 4730 // adapter below it) does not work for inlined functions. |
| 4731 if (function_state()->outer() != NULL) { |
| 4732 Bailout("Function.prototype.apply optimization in inlined function"); |
| 4733 return true; |
| 4734 } |
| 4735 |
| 4399 // Found pattern f.apply(receiver, arguments). | 4736 // Found pattern f.apply(receiver, arguments). |
| 4400 VisitForValue(prop->obj()); | 4737 VisitForValue(prop->obj()); |
| 4401 if (HasStackOverflow() || current_block() == NULL) return true; | 4738 if (HasStackOverflow() || current_block() == NULL) return true; |
| 4402 HValue* function = Pop(); | 4739 HValue* function = Pop(); |
| 4403 VisitForValue(args->at(0)); | 4740 VisitForValue(args->at(0)); |
| 4404 if (HasStackOverflow() || current_block() == NULL) return true; | 4741 if (HasStackOverflow() || current_block() == NULL) return true; |
| 4405 HValue* receiver = Pop(); | 4742 HValue* receiver = Pop(); |
| 4406 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 4743 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
| 4407 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); | 4744 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); |
| 4408 AddCheckConstantFunction(expr, | 4745 AddCheckConstantFunction(expr, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4422 ASSERT(current_block() != NULL); | 4759 ASSERT(current_block() != NULL); |
| 4423 ASSERT(current_block()->HasPredecessor()); | 4760 ASSERT(current_block()->HasPredecessor()); |
| 4424 Expression* callee = expr->expression(); | 4761 Expression* callee = expr->expression(); |
| 4425 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4762 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4426 HInstruction* call = NULL; | 4763 HInstruction* call = NULL; |
| 4427 | 4764 |
| 4428 Property* prop = callee->AsProperty(); | 4765 Property* prop = callee->AsProperty(); |
| 4429 if (prop != NULL) { | 4766 if (prop != NULL) { |
| 4430 if (!prop->key()->IsPropertyName()) { | 4767 if (!prop->key()->IsPropertyName()) { |
| 4431 // Keyed function call. | 4768 // Keyed function call. |
| 4432 CHECK_ALIVE(VisitForValue(prop->obj())); | 4769 CHECK_ALIVE(VisitArgument(prop->obj())); |
| 4433 | 4770 |
| 4434 CHECK_ALIVE(VisitForValue(prop->key())); | 4771 CHECK_ALIVE(VisitForValue(prop->key())); |
| 4435 // Push receiver and key like the non-optimized code generator expects it. | 4772 // Push receiver and key like the non-optimized code generator expects it. |
| 4436 HValue* key = Pop(); | 4773 HValue* key = Pop(); |
| 4437 HValue* receiver = Pop(); | 4774 HValue* receiver = Pop(); |
| 4438 Push(key); | 4775 Push(key); |
| 4439 Push(receiver); | 4776 Push(receiver); |
| 4440 | 4777 |
| 4441 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4778 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 4442 | 4779 |
| 4443 HValue* context = environment()->LookupContext(); | 4780 HValue* context = environment()->LookupContext(); |
| 4444 call = PreProcessCall( | 4781 call = new(zone()) HCallKeyed(context, key, argument_count); |
| 4445 new(zone()) HCallKeyed(context, key, argument_count)); | |
| 4446 call->set_position(expr->position()); | 4782 call->set_position(expr->position()); |
| 4447 Drop(1); // Key. | 4783 Drop(argument_count + 1); // 1 is the key. |
| 4448 ast_context()->ReturnInstruction(call, expr->id()); | 4784 return ast_context()->ReturnInstruction(call, expr->id()); |
| 4449 return; | |
| 4450 } | 4785 } |
| 4451 | 4786 |
| 4452 // Named function call. | 4787 // Named function call. |
| 4453 expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD); | 4788 expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD); |
| 4454 | 4789 |
| 4455 if (TryCallApply(expr)) return; | 4790 if (TryCallApply(expr)) return; |
| 4456 | 4791 |
| 4457 CHECK_ALIVE(VisitForValue(prop->obj())); | 4792 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 4458 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4793 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 4459 | 4794 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4497 } else { | 4832 } else { |
| 4498 HValue* context = environment()->LookupContext(); | 4833 HValue* context = environment()->LookupContext(); |
| 4499 call = PreProcessCall( | 4834 call = PreProcessCall( |
| 4500 new(zone()) HCallNamed(context, name, argument_count)); | 4835 new(zone()) HCallNamed(context, name, argument_count)); |
| 4501 } | 4836 } |
| 4502 | 4837 |
| 4503 } else { | 4838 } else { |
| 4504 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4839 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4505 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4840 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); |
| 4506 | 4841 |
| 4507 if (!global_call) { | |
| 4508 ++argument_count; | |
| 4509 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 4510 } | |
| 4511 | |
| 4512 if (global_call) { | 4842 if (global_call) { |
| 4513 bool known_global_function = false; | 4843 bool known_global_function = false; |
| 4514 // If there is a global property cell for the name at compile time and | 4844 // If there is a global property cell for the name at compile time and |
| 4515 // access check is not enabled we assume that the function will not change | 4845 // access check is not enabled we assume that the function will not change |
| 4516 // and generate optimized code for calling the function. | 4846 // and generate optimized code for calling the function. |
| 4517 LookupResult lookup; | 4847 LookupResult lookup; |
| 4518 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 4848 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
| 4519 if (type == kUseCell && | 4849 if (type == kUseCell && |
| 4520 !info()->global_object()->IsAccessCheckNeeded()) { | 4850 !info()->global_object()->IsAccessCheckNeeded()) { |
| 4521 Handle<GlobalObject> global(info()->global_object()); | 4851 Handle<GlobalObject> global(info()->global_object()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 4541 AddInstruction(global_receiver); | 4871 AddInstruction(global_receiver); |
| 4542 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4872 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 4543 IsGlobalObject()); | 4873 IsGlobalObject()); |
| 4544 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4874 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 4545 | 4875 |
| 4546 if (TryInline(expr)) return; | 4876 if (TryInline(expr)) return; |
| 4547 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), | 4877 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), |
| 4548 argument_count)); | 4878 argument_count)); |
| 4549 } else { | 4879 } else { |
| 4550 HValue* context = environment()->LookupContext(); | 4880 HValue* context = environment()->LookupContext(); |
| 4551 PushAndAdd(new(zone()) HGlobalObject(context)); | 4881 HGlobalObject* receiver = new(zone()) HGlobalObject(context); |
| 4552 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4882 AddInstruction(receiver); |
| 4883 PushAndAdd(new(zone()) HPushArgument(receiver)); |
| 4884 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 4553 | 4885 |
| 4554 call = PreProcessCall(new(zone()) HCallGlobal(context, | 4886 call = new(zone()) HCallGlobal(context, var->name(), argument_count); |
| 4555 var->name(), | 4887 Drop(argument_count); |
| 4556 argument_count)); | |
| 4557 } | 4888 } |
| 4558 | 4889 |
| 4559 } else { | 4890 } else { |
| 4891 CHECK_ALIVE(VisitArgument(expr->expression())); |
| 4560 HValue* context = environment()->LookupContext(); | 4892 HValue* context = environment()->LookupContext(); |
| 4561 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 4893 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
| 4894 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); |
| 4562 AddInstruction(global_object); | 4895 AddInstruction(global_object); |
| 4563 PushAndAdd(new(zone()) HGlobalReceiver(global_object)); | 4896 AddInstruction(receiver); |
| 4564 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4897 PushAndAdd(new(zone()) HPushArgument(receiver)); |
| 4898 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 4565 | 4899 |
| 4566 call = PreProcessCall(new(zone()) HCallFunction(context, argument_count)); | 4900 // The function to call is treated as an argument to the call function |
| 4901 // stub. |
| 4902 call = new(zone()) HCallFunction(context, argument_count + 1); |
| 4903 Drop(argument_count + 1); |
| 4567 } | 4904 } |
| 4568 } | 4905 } |
| 4569 | 4906 |
| 4570 call->set_position(expr->position()); | 4907 call->set_position(expr->position()); |
| 4571 ast_context()->ReturnInstruction(call, expr->id()); | 4908 return ast_context()->ReturnInstruction(call, expr->id()); |
| 4572 } | 4909 } |
| 4573 | 4910 |
| 4574 | 4911 |
| 4575 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 4912 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 4576 ASSERT(!HasStackOverflow()); | 4913 ASSERT(!HasStackOverflow()); |
| 4577 ASSERT(current_block() != NULL); | 4914 ASSERT(current_block() != NULL); |
| 4578 ASSERT(current_block()->HasPredecessor()); | 4915 ASSERT(current_block()->HasPredecessor()); |
| 4579 // The constructor function is also used as the receiver argument to the | 4916 // The constructor function is also used as the receiver argument to the |
| 4580 // JS construct call builtin. | 4917 // JS construct call builtin. |
| 4581 CHECK_ALIVE(VisitForValue(expr->expression())); | 4918 HValue* constructor = NULL; |
| 4582 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4919 CHECK_ALIVE(constructor = VisitArgument(expr->expression())); |
| 4920 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 4583 | 4921 |
| 4584 HValue* context = environment()->LookupContext(); | 4922 HValue* context = environment()->LookupContext(); |
| 4585 | 4923 |
| 4586 // The constructor is both an operand to the instruction and an argument | 4924 // The constructor is both an operand to the instruction and an argument |
| 4587 // to the construct call. | 4925 // to the construct call. |
| 4588 int arg_count = expr->arguments()->length() + 1; // Plus constructor. | 4926 int arg_count = expr->arguments()->length() + 1; // Plus constructor. |
| 4589 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1); | |
| 4590 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count); | 4927 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count); |
| 4591 call->set_position(expr->position()); | 4928 call->set_position(expr->position()); |
| 4592 PreProcessCall(call); | 4929 Drop(arg_count); |
| 4593 ast_context()->ReturnInstruction(call, expr->id()); | 4930 return ast_context()->ReturnInstruction(call, expr->id()); |
| 4594 } | 4931 } |
| 4595 | 4932 |
| 4596 | 4933 |
| 4597 // Support for generating inlined runtime functions. | 4934 // Support for generating inlined runtime functions. |
| 4598 | 4935 |
| 4599 // Lookup table for generators for runtime calls that are generated inline. | 4936 // Lookup table for generators for runtime calls that are generated inline. |
| 4600 // Elements of the table are member pointers to functions of HGraphBuilder. | 4937 // Elements of the table are member pointers to functions of HGraphBuilder. |
| 4601 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 4938 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 4602 &HGraphBuilder::Generate##Name, | 4939 &HGraphBuilder::Generate##Name, |
| 4603 | 4940 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 4629 ASSERT(static_cast<size_t>(lookup_index) < | 4966 ASSERT(static_cast<size_t>(lookup_index) < |
| 4630 ARRAY_SIZE(kInlineFunctionGenerators)); | 4967 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 4631 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 4968 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| 4632 | 4969 |
| 4633 // Call the inline code generator using the pointer-to-member. | 4970 // Call the inline code generator using the pointer-to-member. |
| 4634 (this->*generator)(expr); | 4971 (this->*generator)(expr); |
| 4635 } else { | 4972 } else { |
| 4636 ASSERT(function->intrinsic_type == Runtime::RUNTIME); | 4973 ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
| 4637 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 4974 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 4638 | 4975 |
| 4976 HValue* context = environment()->LookupContext(); |
| 4639 Handle<String> name = expr->name(); | 4977 Handle<String> name = expr->name(); |
| 4640 int argument_count = expr->arguments()->length(); | 4978 int argument_count = expr->arguments()->length(); |
| 4641 HCallRuntime* call = | 4979 HCallRuntime* call = |
| 4642 new(zone()) HCallRuntime(name, function, argument_count); | 4980 new(zone()) HCallRuntime(context, name, function, argument_count); |
| 4643 call->set_position(RelocInfo::kNoPosition); | 4981 call->set_position(RelocInfo::kNoPosition); |
| 4644 Drop(argument_count); | 4982 Drop(argument_count); |
| 4645 ast_context()->ReturnInstruction(call, expr->id()); | 4983 return ast_context()->ReturnInstruction(call, expr->id()); |
| 4646 } | 4984 } |
| 4647 } | 4985 } |
| 4648 | 4986 |
| 4649 | 4987 |
| 4650 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4988 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4651 ASSERT(!HasStackOverflow()); | 4989 ASSERT(!HasStackOverflow()); |
| 4652 ASSERT(current_block() != NULL); | 4990 ASSERT(current_block() != NULL); |
| 4653 ASSERT(current_block()->HasPredecessor()); | 4991 ASSERT(current_block()->HasPredecessor()); |
| 4654 switch (expr->op()) { | 4992 switch (expr->op()) { |
| 4655 case Token::DELETE: return VisitDelete(expr); | 4993 case Token::DELETE: return VisitDelete(expr); |
| 4656 case Token::VOID: return VisitVoid(expr); | 4994 case Token::VOID: return VisitVoid(expr); |
| 4657 case Token::TYPEOF: return VisitTypeof(expr); | 4995 case Token::TYPEOF: return VisitTypeof(expr); |
| 4658 case Token::ADD: return VisitAdd(expr); | 4996 case Token::ADD: return VisitAdd(expr); |
| 4659 case Token::SUB: return VisitSub(expr); | 4997 case Token::SUB: return VisitSub(expr); |
| 4660 case Token::BIT_NOT: return VisitBitNot(expr); | 4998 case Token::BIT_NOT: return VisitBitNot(expr); |
| 4661 case Token::NOT: return VisitNot(expr); | 4999 case Token::NOT: return VisitNot(expr); |
| 4662 default: UNREACHABLE(); | 5000 default: UNREACHABLE(); |
| 4663 } | 5001 } |
| 4664 } | 5002 } |
| 4665 | 5003 |
| 4666 void HGraphBuilder::VisitDelete(UnaryOperation* expr) { | 5004 void HGraphBuilder::VisitDelete(UnaryOperation* expr) { |
| 4667 Property* prop = expr->expression()->AsProperty(); | 5005 Property* prop = expr->expression()->AsProperty(); |
| 4668 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 5006 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4669 if (prop == NULL && var == NULL) { | 5007 if (prop == NULL && var == NULL) { |
| 4670 // Result of deleting non-property, non-variable reference is true. | 5008 // Result of deleting non-property, non-variable reference is true. |
| 4671 // Evaluate the subexpression for side effects. | 5009 // Evaluate the subexpression for side effects. |
| 4672 CHECK_ALIVE(VisitForEffect(expr->expression())); | 5010 CHECK_ALIVE(VisitForEffect(expr->expression())); |
| 4673 ast_context()->ReturnValue(graph()->GetConstantTrue()); | 5011 return ast_context()->ReturnValue(graph()->GetConstantTrue()); |
| 4674 } else if (var != NULL && | 5012 } else if (var != NULL && |
| 4675 !var->is_global() && | 5013 !var->is_global() && |
| 4676 var->AsSlot() != NULL && | 5014 var->AsSlot() != NULL && |
| 4677 var->AsSlot()->type() != Slot::LOOKUP) { | 5015 var->AsSlot()->type() != Slot::LOOKUP) { |
| 4678 // Result of deleting non-global, non-dynamic variables is false. | 5016 // Result of deleting non-global, non-dynamic variables is false. |
| 4679 // The subexpression does not have side effects. | 5017 // The subexpression does not have side effects. |
| 4680 ast_context()->ReturnValue(graph()->GetConstantFalse()); | 5018 return ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4681 } else if (prop != NULL) { | 5019 } else if (prop != NULL) { |
| 4682 if (prop->is_synthetic()) { | 5020 if (prop->is_synthetic()) { |
| 4683 // Result of deleting parameters is false, even when they rewrite | 5021 // Result of deleting parameters is false, even when they rewrite |
| 4684 // to accesses on the arguments object. | 5022 // to accesses on the arguments object. |
| 4685 ast_context()->ReturnValue(graph()->GetConstantFalse()); | 5023 return ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4686 } else { | 5024 } else { |
| 4687 CHECK_ALIVE(VisitForValue(prop->obj())); | 5025 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 4688 CHECK_ALIVE(VisitForValue(prop->key())); | 5026 CHECK_ALIVE(VisitForValue(prop->key())); |
| 4689 HValue* key = Pop(); | 5027 HValue* key = Pop(); |
| 4690 HValue* obj = Pop(); | 5028 HValue* obj = Pop(); |
| 4691 HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key); | 5029 HValue* context = environment()->LookupContext(); |
| 4692 ast_context()->ReturnInstruction(instr, expr->id()); | 5030 HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key); |
| 5031 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4693 } | 5032 } |
| 4694 } else if (var->is_global()) { | 5033 } else if (var->is_global()) { |
| 4695 Bailout("delete with global variable"); | 5034 Bailout("delete with global variable"); |
| 4696 } else { | 5035 } else { |
| 4697 Bailout("delete with non-global variable"); | 5036 Bailout("delete with non-global variable"); |
| 4698 } | 5037 } |
| 4699 } | 5038 } |
| 4700 | 5039 |
| 4701 | 5040 |
| 4702 void HGraphBuilder::VisitVoid(UnaryOperation* expr) { | 5041 void HGraphBuilder::VisitVoid(UnaryOperation* expr) { |
| 4703 CHECK_ALIVE(VisitForEffect(expr->expression())); | 5042 CHECK_ALIVE(VisitForEffect(expr->expression())); |
| 4704 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 5043 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4705 } | 5044 } |
| 4706 | 5045 |
| 4707 | 5046 |
| 4708 void HGraphBuilder::VisitTypeof(UnaryOperation* expr) { | 5047 void HGraphBuilder::VisitTypeof(UnaryOperation* expr) { |
| 4709 CHECK_ALIVE(VisitForTypeOf(expr->expression())); | 5048 CHECK_ALIVE(VisitForTypeOf(expr->expression())); |
| 4710 HValue* value = Pop(); | 5049 HValue* value = Pop(); |
| 4711 ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id()); | 5050 HValue* context = environment()->LookupContext(); |
| 5051 HInstruction* instr = new(zone()) HTypeof(context, value); |
| 5052 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4712 } | 5053 } |
| 4713 | 5054 |
| 4714 | 5055 |
| 4715 void HGraphBuilder::VisitAdd(UnaryOperation* expr) { | 5056 void HGraphBuilder::VisitAdd(UnaryOperation* expr) { |
| 4716 CHECK_ALIVE(VisitForValue(expr->expression())); | 5057 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4717 HValue* value = Pop(); | 5058 HValue* value = Pop(); |
| 4718 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstant1()); | 5059 HValue* context = environment()->LookupContext(); |
| 4719 ast_context()->ReturnInstruction(instr, expr->id()); | 5060 HInstruction* instr = |
| 5061 new(zone()) HMul(context, value, graph_->GetConstant1()); |
| 5062 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4720 } | 5063 } |
| 4721 | 5064 |
| 4722 | 5065 |
| 4723 void HGraphBuilder::VisitSub(UnaryOperation* expr) { | 5066 void HGraphBuilder::VisitSub(UnaryOperation* expr) { |
| 4724 CHECK_ALIVE(VisitForValue(expr->expression())); | 5067 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4725 HValue* value = Pop(); | 5068 HValue* value = Pop(); |
| 4726 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstantMinus1()); | 5069 HValue* context = environment()->LookupContext(); |
| 5070 HInstruction* instr = |
| 5071 new(zone()) HMul(context, value, graph_->GetConstantMinus1()); |
| 4727 TypeInfo info = oracle()->UnaryType(expr); | 5072 TypeInfo info = oracle()->UnaryType(expr); |
| 5073 if (info.IsUninitialized()) { |
| 5074 AddInstruction(new(zone()) HSoftDeoptimize); |
| 5075 current_block()->MarkAsDeoptimizing(); |
| 5076 info = TypeInfo::Unknown(); |
| 5077 } |
| 4728 Representation rep = ToRepresentation(info); | 5078 Representation rep = ToRepresentation(info); |
| 4729 TraceRepresentation(expr->op(), info, instr, rep); | 5079 TraceRepresentation(expr->op(), info, instr, rep); |
| 4730 instr->AssumeRepresentation(rep); | 5080 instr->AssumeRepresentation(rep); |
| 4731 ast_context()->ReturnInstruction(instr, expr->id()); | 5081 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4732 } | 5082 } |
| 4733 | 5083 |
| 4734 | 5084 |
| 4735 void HGraphBuilder::VisitBitNot(UnaryOperation* expr) { | 5085 void HGraphBuilder::VisitBitNot(UnaryOperation* expr) { |
| 4736 CHECK_ALIVE(VisitForValue(expr->expression())); | 5086 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4737 HValue* value = Pop(); | 5087 HValue* value = Pop(); |
| 5088 TypeInfo info = oracle()->UnaryType(expr); |
| 5089 if (info.IsUninitialized()) { |
| 5090 AddInstruction(new(zone()) HSoftDeoptimize); |
| 5091 current_block()->MarkAsDeoptimizing(); |
| 5092 } |
| 4738 HInstruction* instr = new(zone()) HBitNot(value); | 5093 HInstruction* instr = new(zone()) HBitNot(value); |
| 4739 ast_context()->ReturnInstruction(instr, expr->id()); | 5094 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4740 } | 5095 } |
| 4741 | 5096 |
| 4742 | 5097 |
| 4743 void HGraphBuilder::VisitNot(UnaryOperation* expr) { | 5098 void HGraphBuilder::VisitNot(UnaryOperation* expr) { |
| 4744 // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. | 5099 // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. |
| 4745 if (ast_context()->IsTest()) { | 5100 if (ast_context()->IsTest()) { |
| 4746 TestContext* context = TestContext::cast(ast_context()); | 5101 TestContext* context = TestContext::cast(ast_context()); |
| 4747 VisitForControl(expr->expression(), | 5102 VisitForControl(expr->expression(), |
| 4748 context->if_false(), | 5103 context->if_false(), |
| 4749 context->if_true()); | 5104 context->if_true()); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 4774 materialize_true->SetJoinId(expr->expression()->id()); | 5129 materialize_true->SetJoinId(expr->expression()->id()); |
| 4775 set_current_block(materialize_true); | 5130 set_current_block(materialize_true); |
| 4776 Push(graph()->GetConstantTrue()); | 5131 Push(graph()->GetConstantTrue()); |
| 4777 } else { | 5132 } else { |
| 4778 materialize_true = NULL; | 5133 materialize_true = NULL; |
| 4779 } | 5134 } |
| 4780 | 5135 |
| 4781 HBasicBlock* join = | 5136 HBasicBlock* join = |
| 4782 CreateJoin(materialize_false, materialize_true, expr->id()); | 5137 CreateJoin(materialize_false, materialize_true, expr->id()); |
| 4783 set_current_block(join); | 5138 set_current_block(join); |
| 4784 if (join != NULL) ast_context()->ReturnValue(Pop()); | 5139 if (join != NULL) return ast_context()->ReturnValue(Pop()); |
| 4785 } | 5140 } |
| 4786 | 5141 |
| 4787 | 5142 |
| 4788 HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input, | 5143 HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input, |
| 4789 CountOperation* expr) { | 5144 CountOperation* expr) { |
| 4790 // The input to the count operation is on top of the expression stack. | 5145 // The input to the count operation is on top of the expression stack. |
| 4791 TypeInfo info = oracle()->IncrementType(expr); | 5146 TypeInfo info = oracle()->IncrementType(expr); |
| 4792 Representation rep = ToRepresentation(info); | 5147 Representation rep = ToRepresentation(info); |
| 4793 if (rep.IsTagged()) { | 5148 if (rep.IsTagged()) { |
| 4794 rep = Representation::Integer32(); | 5149 rep = Representation::Integer32(); |
| 4795 } | 5150 } |
| 4796 | 5151 |
| 4797 if (returns_original_input) { | 5152 if (returns_original_input) { |
| 4798 // We need an explicit HValue representing ToNumber(input). The | 5153 // We need an explicit HValue representing ToNumber(input). The |
| 4799 // actual HChange instruction we need is (sometimes) added in a later | 5154 // actual HChange instruction we need is (sometimes) added in a later |
| 4800 // phase, so it is not available now to be used as an input to HAdd and | 5155 // phase, so it is not available now to be used as an input to HAdd and |
| 4801 // as the return value. | 5156 // as the return value. |
| 4802 HInstruction* number_input = new(zone()) HForceRepresentation(Pop(), rep); | 5157 HInstruction* number_input = new(zone()) HForceRepresentation(Pop(), rep); |
| 4803 AddInstruction(number_input); | 5158 AddInstruction(number_input); |
| 4804 Push(number_input); | 5159 Push(number_input); |
| 4805 } | 5160 } |
| 4806 | 5161 |
| 4807 // The addition has no side effects, so we do not need | 5162 // The addition has no side effects, so we do not need |
| 4808 // to simulate the expression stack after this instruction. | 5163 // to simulate the expression stack after this instruction. |
| 4809 // Any later failures deopt to the load of the input or earlier. | 5164 // Any later failures deopt to the load of the input or earlier. |
| 4810 HConstant* delta = (expr->op() == Token::INC) | 5165 HConstant* delta = (expr->op() == Token::INC) |
| 4811 ? graph_->GetConstant1() | 5166 ? graph_->GetConstant1() |
| 4812 : graph_->GetConstantMinus1(); | 5167 : graph_->GetConstantMinus1(); |
| 4813 HInstruction* instr = new(zone()) HAdd(Top(), delta); | 5168 HValue* context = environment()->LookupContext(); |
| 5169 HInstruction* instr = new(zone()) HAdd(context, Top(), delta); |
| 4814 TraceRepresentation(expr->op(), info, instr, rep); | 5170 TraceRepresentation(expr->op(), info, instr, rep); |
| 4815 instr->AssumeRepresentation(rep); | 5171 instr->AssumeRepresentation(rep); |
| 4816 AddInstruction(instr); | 5172 AddInstruction(instr); |
| 4817 return instr; | 5173 return instr; |
| 4818 } | 5174 } |
| 4819 | 5175 |
| 4820 | 5176 |
| 4821 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { | 5177 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 4822 ASSERT(!HasStackOverflow()); | 5178 ASSERT(!HasStackOverflow()); |
| 4823 ASSERT(current_block() != NULL); | 5179 ASSERT(current_block() != NULL); |
| 4824 ASSERT(current_block()->HasPredecessor()); | 5180 ASSERT(current_block()->HasPredecessor()); |
| 4825 Expression* target = expr->expression(); | 5181 Expression* target = expr->expression(); |
| 4826 VariableProxy* proxy = target->AsVariableProxy(); | 5182 VariableProxy* proxy = target->AsVariableProxy(); |
| 4827 Variable* var = proxy->AsVariable(); | 5183 Variable* var = proxy->AsVariable(); |
| 4828 Property* prop = target->AsProperty(); | 5184 Property* prop = target->AsProperty(); |
| 4829 if (var == NULL && prop == NULL) { | 5185 if (var == NULL && prop == NULL) { |
| 4830 return Bailout("invalid lhs in count operation"); | 5186 return Bailout("invalid lhs in count operation"); |
| 4831 } | 5187 } |
| 4832 | 5188 |
| 4833 // Match the full code generator stack by simulating an extra stack | 5189 // Match the full code generator stack by simulating an extra stack |
| 4834 // element for postfix operations in a non-effect context. The return | 5190 // element for postfix operations in a non-effect context. The return |
| 4835 // value is ToNumber(input). | 5191 // value is ToNumber(input). |
| 4836 bool returns_original_input = | 5192 bool returns_original_input = |
| 4837 expr->is_postfix() && !ast_context()->IsEffect(); | 5193 expr->is_postfix() && !ast_context()->IsEffect(); |
| 4838 HValue* input = NULL; // ToNumber(original_input). | 5194 HValue* input = NULL; // ToNumber(original_input). |
| 4839 HValue* after = NULL; // The result after incrementing or decrementing. | 5195 HValue* after = NULL; // The result after incrementing or decrementing. |
| 4840 | 5196 |
| 4841 if (var != NULL) { | 5197 if (var != NULL) { |
| 5198 if (var->mode() == Variable::CONST) { |
| 5199 return Bailout("unsupported count operation with const"); |
| 5200 } |
| 4842 // Argument of the count operation is a variable, not a property. | 5201 // Argument of the count operation is a variable, not a property. |
| 4843 ASSERT(prop == NULL); | 5202 ASSERT(prop == NULL); |
| 4844 CHECK_ALIVE(VisitForValue(target)); | 5203 CHECK_ALIVE(VisitForValue(target)); |
| 4845 | 5204 |
| 4846 after = BuildIncrement(returns_original_input, expr); | 5205 after = BuildIncrement(returns_original_input, expr); |
| 4847 input = returns_original_input ? Top() : Pop(); | 5206 input = returns_original_input ? Top() : Pop(); |
| 4848 Push(after); | 5207 Push(after); |
| 4849 | 5208 |
| 4850 if (var->is_global()) { | 5209 if (var->is_global()) { |
| 4851 HandleGlobalVariableAssignment(var, | 5210 HandleGlobalVariableAssignment(var, |
| 4852 after, | 5211 after, |
| 4853 expr->position(), | 5212 expr->position(), |
| 4854 expr->AssignmentId()); | 5213 expr->AssignmentId()); |
| 4855 } else if (var->IsStackAllocated()) { | 5214 } else if (var->IsStackAllocated()) { |
| 4856 Bind(var, after); | 5215 Bind(var, after); |
| 4857 } else if (var->IsContextSlot()) { | 5216 } else if (var->IsContextSlot()) { |
| 5217 // Bail out if we try to mutate a parameter value in a function using |
| 5218 // the arguments object. We do not (yet) correctly handle the |
| 5219 // arguments property of the function. |
| 5220 if (info()->scope()->arguments() != NULL) { |
| 5221 // Parameters will rewrite to context slots. We have no direct way |
| 5222 // to detect that the variable is a parameter. |
| 5223 int count = info()->scope()->num_parameters(); |
| 5224 for (int i = 0; i < count; ++i) { |
| 5225 if (var == info()->scope()->parameter(i)) { |
| 5226 Bailout("assignment to parameter, function uses arguments object"); |
| 5227 } |
| 5228 } |
| 5229 } |
| 5230 |
| 4858 HValue* context = BuildContextChainWalk(var); | 5231 HValue* context = BuildContextChainWalk(var); |
| 4859 int index = var->AsSlot()->index(); | 5232 int index = var->AsSlot()->index(); |
| 4860 HStoreContextSlot* instr = | 5233 HStoreContextSlot* instr = |
| 4861 new(zone()) HStoreContextSlot(context, index, after); | 5234 new(zone()) HStoreContextSlot(context, index, after); |
| 4862 AddInstruction(instr); | 5235 AddInstruction(instr); |
| 4863 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 5236 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4864 } else { | 5237 } else { |
| 4865 return Bailout("lookup variable in count operation"); | 5238 return Bailout("lookup variable in count operation"); |
| 4866 } | 5239 } |
| 4867 | 5240 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4903 | 5276 |
| 4904 } else { | 5277 } else { |
| 4905 // Keyed property. | 5278 // Keyed property. |
| 4906 if (returns_original_input) Push(graph_->GetConstantUndefined()); | 5279 if (returns_original_input) Push(graph_->GetConstantUndefined()); |
| 4907 | 5280 |
| 4908 CHECK_ALIVE(VisitForValue(prop->obj())); | 5281 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 4909 CHECK_ALIVE(VisitForValue(prop->key())); | 5282 CHECK_ALIVE(VisitForValue(prop->key())); |
| 4910 HValue* obj = environment()->ExpressionStackAt(1); | 5283 HValue* obj = environment()->ExpressionStackAt(1); |
| 4911 HValue* key = environment()->ExpressionStackAt(0); | 5284 HValue* key = environment()->ExpressionStackAt(0); |
| 4912 | 5285 |
| 4913 HInstruction* load = BuildLoadKeyed(obj, key, prop); | 5286 bool has_side_effects = false; |
| 4914 PushAndAdd(load); | 5287 HValue* load = HandleKeyedElementAccess( |
| 4915 if (load->HasSideEffects()) AddSimulate(expr->CountId()); | 5288 obj, key, NULL, prop, expr->CountId(), RelocInfo::kNoPosition, |
| 5289 false, // is_store |
| 5290 &has_side_effects); |
| 5291 Push(load); |
| 5292 if (has_side_effects) AddSimulate(expr->CountId()); |
| 4916 | 5293 |
| 4917 after = BuildIncrement(returns_original_input, expr); | 5294 after = BuildIncrement(returns_original_input, expr); |
| 4918 input = Pop(); | 5295 input = Pop(); |
| 4919 | 5296 |
| 4920 expr->RecordTypeFeedback(oracle()); | 5297 expr->RecordTypeFeedback(oracle()); |
| 4921 HInstruction* store = BuildStoreKeyed(obj, key, after, expr); | 5298 HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(), |
| 4922 AddInstruction(store); | 5299 RelocInfo::kNoPosition, |
| 5300 true, // is_store |
| 5301 &has_side_effects); |
| 4923 | 5302 |
| 4924 // Drop the key from the bailout environment. Overwrite the receiver | 5303 // Drop the key from the bailout environment. Overwrite the receiver |
| 4925 // with the result of the operation, and the placeholder with the | 5304 // with the result of the operation, and the placeholder with the |
| 4926 // original value if necessary. | 5305 // original value if necessary. |
| 4927 Drop(1); | 5306 Drop(1); |
| 4928 environment()->SetExpressionStackAt(0, after); | 5307 environment()->SetExpressionStackAt(0, after); |
| 4929 if (returns_original_input) environment()->SetExpressionStackAt(1, input); | 5308 if (returns_original_input) environment()->SetExpressionStackAt(1, input); |
| 4930 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 5309 ASSERT(has_side_effects); // Stores always have side effects. |
| 5310 AddSimulate(expr->AssignmentId()); |
| 4931 } | 5311 } |
| 4932 } | 5312 } |
| 4933 | 5313 |
| 4934 Drop(returns_original_input ? 2 : 1); | 5314 Drop(returns_original_input ? 2 : 1); |
| 4935 ast_context()->ReturnValue(expr->is_postfix() ? input : after); | 5315 return ast_context()->ReturnValue(expr->is_postfix() ? input : after); |
| 4936 } | 5316 } |
| 4937 | 5317 |
| 4938 | 5318 |
| 4939 HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left, | 5319 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* context, |
| 4940 HValue* right, | 5320 HValue* string, |
| 4941 Token::Value op) { | |
| 4942 ASSERT(op == Token::EQ || op == Token::EQ_STRICT); | |
| 4943 AddInstruction(new(zone()) HCheckNonSmi(left)); | |
| 4944 AddInstruction(HCheckInstanceType::NewIsSymbol(left)); | |
| 4945 AddInstruction(new(zone()) HCheckNonSmi(right)); | |
| 4946 AddInstruction(HCheckInstanceType::NewIsSymbol(right)); | |
| 4947 return new(zone()) HCompareSymbolEq(left, right, op); | |
| 4948 } | |
| 4949 | |
| 4950 | |
| 4951 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, | |
| 4952 HValue* index) { | 5321 HValue* index) { |
| 4953 AddInstruction(new(zone()) HCheckNonSmi(string)); | 5322 AddInstruction(new(zone()) HCheckNonSmi(string)); |
| 4954 AddInstruction(HCheckInstanceType::NewIsString(string)); | 5323 AddInstruction(HCheckInstanceType::NewIsString(string)); |
| 4955 HStringLength* length = new(zone()) HStringLength(string); | 5324 HStringLength* length = new(zone()) HStringLength(string); |
| 4956 AddInstruction(length); | 5325 AddInstruction(length); |
| 4957 AddInstruction(new(zone()) HBoundsCheck(index, length)); | 5326 HInstruction* checked_index = |
| 4958 return new(zone()) HStringCharCodeAt(string, index); | 5327 AddInstruction(new(zone()) HBoundsCheck(index, length)); |
| 5328 return new(zone()) HStringCharCodeAt(context, string, checked_index); |
| 4959 } | 5329 } |
| 4960 | 5330 |
| 4961 | 5331 |
| 4962 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 5332 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4963 HValue* left, | 5333 HValue* left, |
| 4964 HValue* right) { | 5334 HValue* right) { |
| 5335 HValue* context = environment()->LookupContext(); |
| 4965 TypeInfo info = oracle()->BinaryType(expr); | 5336 TypeInfo info = oracle()->BinaryType(expr); |
| 4966 HInstruction* instr = BuildBinaryOperation(expr->op(), left, right, info); | 5337 if (info.IsUninitialized()) { |
| 5338 AddInstruction(new(zone()) HSoftDeoptimize); |
| 5339 current_block()->MarkAsDeoptimizing(); |
| 5340 info = TypeInfo::Unknown(); |
| 5341 } |
| 5342 HInstruction* instr = NULL; |
| 5343 switch (expr->op()) { |
| 5344 case Token::ADD: |
| 5345 if (info.IsString()) { |
| 5346 AddInstruction(new(zone()) HCheckNonSmi(left)); |
| 5347 AddInstruction(HCheckInstanceType::NewIsString(left)); |
| 5348 AddInstruction(new(zone()) HCheckNonSmi(right)); |
| 5349 AddInstruction(HCheckInstanceType::NewIsString(right)); |
| 5350 instr = new(zone()) HStringAdd(context, left, right); |
| 5351 } else { |
| 5352 instr = new(zone()) HAdd(context, left, right); |
| 5353 } |
| 5354 break; |
| 5355 case Token::SUB: |
| 5356 instr = new(zone()) HSub(context, left, right); |
| 5357 break; |
| 5358 case Token::MUL: |
| 5359 instr = new(zone()) HMul(context, left, right); |
| 5360 break; |
| 5361 case Token::MOD: |
| 5362 instr = new(zone()) HMod(context, left, right); |
| 5363 break; |
| 5364 case Token::DIV: |
| 5365 instr = new(zone()) HDiv(context, left, right); |
| 5366 break; |
| 5367 case Token::BIT_XOR: |
| 5368 instr = new(zone()) HBitXor(context, left, right); |
| 5369 break; |
| 5370 case Token::BIT_AND: |
| 5371 instr = new(zone()) HBitAnd(context, left, right); |
| 5372 break; |
| 5373 case Token::BIT_OR: |
| 5374 instr = new(zone()) HBitOr(context, left, right); |
| 5375 break; |
| 5376 case Token::SAR: |
| 5377 instr = new(zone()) HSar(context, left, right); |
| 5378 break; |
| 5379 case Token::SHR: |
| 5380 instr = new(zone()) HShr(context, left, right); |
| 5381 break; |
| 5382 case Token::SHL: |
| 5383 instr = new(zone()) HShl(context, left, right); |
| 5384 break; |
| 5385 default: |
| 5386 UNREACHABLE(); |
| 5387 } |
| 5388 |
| 4967 // If we hit an uninitialized binary op stub we will get type info | 5389 // If we hit an uninitialized binary op stub we will get type info |
| 4968 // for a smi operation. If one of the operands is a constant string | 5390 // for a smi operation. If one of the operands is a constant string |
| 4969 // do not generate code assuming it is a smi operation. | 5391 // do not generate code assuming it is a smi operation. |
| 4970 if (info.IsSmi() && | 5392 if (info.IsSmi() && |
| 4971 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || | 5393 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || |
| 4972 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { | 5394 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { |
| 4973 return instr; | 5395 return instr; |
| 4974 } | 5396 } |
| 4975 Representation rep = ToRepresentation(info); | 5397 Representation rep = ToRepresentation(info); |
| 4976 // We only generate either int32 or generic tagged bitwise operations. | 5398 // We only generate either int32 or generic tagged bitwise operations. |
| 4977 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { | 5399 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { |
| 4978 rep = Representation::Integer32(); | 5400 rep = Representation::Integer32(); |
| 4979 } | 5401 } |
| 4980 TraceRepresentation(expr->op(), info, instr, rep); | 5402 TraceRepresentation(expr->op(), info, instr, rep); |
| 4981 instr->AssumeRepresentation(rep); | 5403 instr->AssumeRepresentation(rep); |
| 4982 return instr; | 5404 return instr; |
| 4983 } | 5405 } |
| 4984 | 5406 |
| 4985 | 5407 |
| 4986 HInstruction* HGraphBuilder::BuildBinaryOperation( | |
| 4987 Token::Value op, HValue* left, HValue* right, TypeInfo info) { | |
| 4988 switch (op) { | |
| 4989 case Token::ADD: | |
| 4990 if (info.IsString()) { | |
| 4991 AddInstruction(new(zone()) HCheckNonSmi(left)); | |
| 4992 AddInstruction(HCheckInstanceType::NewIsString(left)); | |
| 4993 AddInstruction(new(zone()) HCheckNonSmi(right)); | |
| 4994 AddInstruction(HCheckInstanceType::NewIsString(right)); | |
| 4995 return new(zone()) HStringAdd(left, right); | |
| 4996 } else { | |
| 4997 return new(zone()) HAdd(left, right); | |
| 4998 } | |
| 4999 case Token::SUB: return new(zone()) HSub(left, right); | |
| 5000 case Token::MUL: return new(zone()) HMul(left, right); | |
| 5001 case Token::MOD: return new(zone()) HMod(left, right); | |
| 5002 case Token::DIV: return new(zone()) HDiv(left, right); | |
| 5003 case Token::BIT_XOR: return new(zone()) HBitXor(left, right); | |
| 5004 case Token::BIT_AND: return new(zone()) HBitAnd(left, right); | |
| 5005 case Token::BIT_OR: return new(zone()) HBitOr(left, right); | |
| 5006 case Token::SAR: return new(zone()) HSar(left, right); | |
| 5007 case Token::SHR: return new(zone()) HShr(left, right); | |
| 5008 case Token::SHL: return new(zone()) HShl(left, right); | |
| 5009 default: | |
| 5010 UNREACHABLE(); | |
| 5011 return NULL; | |
| 5012 } | |
| 5013 } | |
| 5014 | |
| 5015 | |
| 5016 // Check for the form (%_ClassOf(foo) === 'BarClass'). | 5408 // Check for the form (%_ClassOf(foo) === 'BarClass'). |
| 5017 static bool IsClassOfTest(CompareOperation* expr) { | 5409 static bool IsClassOfTest(CompareOperation* expr) { |
| 5018 if (expr->op() != Token::EQ_STRICT) return false; | 5410 if (expr->op() != Token::EQ_STRICT) return false; |
| 5019 CallRuntime* call = expr->left()->AsCallRuntime(); | 5411 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 5020 if (call == NULL) return false; | 5412 if (call == NULL) return false; |
| 5021 Literal* literal = expr->right()->AsLiteral(); | 5413 Literal* literal = expr->right()->AsLiteral(); |
| 5022 if (literal == NULL) return false; | 5414 if (literal == NULL) return false; |
| 5023 if (!literal->handle()->IsString()) return false; | 5415 if (!literal->handle()->IsString()) return false; |
| 5024 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; | 5416 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; |
| 5025 ASSERT(call->arguments()->length() == 1); | 5417 ASSERT(call->arguments()->length() == 1); |
| 5026 return true; | 5418 return true; |
| 5027 } | 5419 } |
| 5028 | 5420 |
| 5029 | 5421 |
| 5030 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { | 5422 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
| 5031 ASSERT(!HasStackOverflow()); | 5423 ASSERT(!HasStackOverflow()); |
| 5032 ASSERT(current_block() != NULL); | 5424 ASSERT(current_block() != NULL); |
| 5033 ASSERT(current_block()->HasPredecessor()); | 5425 ASSERT(current_block()->HasPredecessor()); |
| 5034 switch (expr->op()) { | 5426 switch (expr->op()) { |
| 5035 case Token::COMMA: return VisitComma(expr); | 5427 case Token::COMMA: |
| 5036 case Token::OR: return VisitAndOr(expr, false); | 5428 return VisitComma(expr); |
| 5037 case Token::AND: return VisitAndOr(expr, true); | 5429 case Token::OR: |
| 5038 default: return VisitCommon(expr); | 5430 case Token::AND: |
| 5431 return VisitLogicalExpression(expr); |
| 5432 default: |
| 5433 return VisitArithmeticExpression(expr); |
| 5039 } | 5434 } |
| 5040 } | 5435 } |
| 5041 | 5436 |
| 5042 | 5437 |
| 5043 void HGraphBuilder::VisitComma(BinaryOperation* expr) { | 5438 void HGraphBuilder::VisitComma(BinaryOperation* expr) { |
| 5044 CHECK_ALIVE(VisitForEffect(expr->left())); | 5439 CHECK_ALIVE(VisitForEffect(expr->left())); |
| 5045 // Visit the right subexpression in the same AST context as the entire | 5440 // Visit the right subexpression in the same AST context as the entire |
| 5046 // expression. | 5441 // expression. |
| 5047 Visit(expr->right()); | 5442 Visit(expr->right()); |
| 5048 } | 5443 } |
| 5049 | 5444 |
| 5050 | 5445 |
| 5051 void HGraphBuilder::VisitAndOr(BinaryOperation* expr, bool is_logical_and) { | 5446 void HGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { |
| 5447 bool is_logical_and = expr->op() == Token::AND; |
| 5052 if (ast_context()->IsTest()) { | 5448 if (ast_context()->IsTest()) { |
| 5053 TestContext* context = TestContext::cast(ast_context()); | 5449 TestContext* context = TestContext::cast(ast_context()); |
| 5054 // Translate left subexpression. | 5450 // Translate left subexpression. |
| 5055 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 5451 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 5056 if (is_logical_and) { | 5452 if (is_logical_and) { |
| 5057 CHECK_BAILOUT(VisitForControl(expr->left(), | 5453 CHECK_BAILOUT(VisitForControl(expr->left(), |
| 5058 eval_right, | 5454 eval_right, |
| 5059 context->if_false())); | 5455 context->if_false())); |
| 5060 } else { | 5456 } else { |
| 5061 CHECK_BAILOUT(VisitForControl(expr->left(), | 5457 CHECK_BAILOUT(VisitForControl(expr->left(), |
| 5062 context->if_true(), | 5458 context->if_true(), |
| 5063 eval_right)); | 5459 eval_right)); |
| 5064 } | 5460 } |
| 5065 | 5461 |
| 5066 // Translate right subexpression by visiting it in the same AST | 5462 // Translate right subexpression by visiting it in the same AST |
| 5067 // context as the entire expression. | 5463 // context as the entire expression. |
| 5068 if (eval_right->HasPredecessor()) { | 5464 if (eval_right->HasPredecessor()) { |
| 5069 eval_right->SetJoinId(expr->RightId()); | 5465 eval_right->SetJoinId(expr->RightId()); |
| 5070 set_current_block(eval_right); | 5466 set_current_block(eval_right); |
| 5071 Visit(expr->right()); | 5467 Visit(expr->right()); |
| 5072 } | 5468 } |
| 5073 | 5469 |
| 5074 } else if (ast_context()->IsValue()) { | 5470 } else if (ast_context()->IsValue()) { |
| 5075 CHECK_ALIVE(VisitForValue(expr->left())); | 5471 CHECK_ALIVE(VisitForValue(expr->left())); |
| 5076 ASSERT(current_block() != NULL); | 5472 ASSERT(current_block() != NULL); |
| 5077 | 5473 |
| 5078 // We need an extra block to maintain edge-split form. | 5474 // We need an extra block to maintain edge-split form. |
| 5079 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | 5475 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 5080 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 5476 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 5081 HTest* test = is_logical_and | 5477 HBranch* test = is_logical_and |
| 5082 ? new(zone()) HTest(Top(), eval_right, empty_block) | 5478 ? new(zone()) HBranch(Top(), eval_right, empty_block) |
| 5083 : new(zone()) HTest(Top(), empty_block, eval_right); | 5479 : new(zone()) HBranch(Top(), empty_block, eval_right); |
| 5084 current_block()->Finish(test); | 5480 current_block()->Finish(test); |
| 5085 | 5481 |
| 5086 set_current_block(eval_right); | 5482 set_current_block(eval_right); |
| 5087 Drop(1); // Value of the left subexpression. | 5483 Drop(1); // Value of the left subexpression. |
| 5088 CHECK_BAILOUT(VisitForValue(expr->right())); | 5484 CHECK_BAILOUT(VisitForValue(expr->right())); |
| 5089 | 5485 |
| 5090 HBasicBlock* join_block = | 5486 HBasicBlock* join_block = |
| 5091 CreateJoin(empty_block, current_block(), expr->id()); | 5487 CreateJoin(empty_block, current_block(), expr->id()); |
| 5092 set_current_block(join_block); | 5488 set_current_block(join_block); |
| 5093 ast_context()->ReturnValue(Pop()); | 5489 return ast_context()->ReturnValue(Pop()); |
| 5094 | 5490 |
| 5095 } else { | 5491 } else { |
| 5096 ASSERT(ast_context()->IsEffect()); | 5492 ASSERT(ast_context()->IsEffect()); |
| 5097 // In an effect context, we don't need the value of the left subexpression, | 5493 // In an effect context, we don't need the value of the left subexpression, |
| 5098 // only its control flow and side effects. We need an extra block to | 5494 // only its control flow and side effects. We need an extra block to |
| 5099 // maintain edge-split form. | 5495 // maintain edge-split form. |
| 5100 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | 5496 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 5101 HBasicBlock* right_block = graph()->CreateBasicBlock(); | 5497 HBasicBlock* right_block = graph()->CreateBasicBlock(); |
| 5102 if (is_logical_and) { | 5498 if (is_logical_and) { |
| 5103 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block)); | 5499 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block)); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 5128 | 5524 |
| 5129 HBasicBlock* join_block = | 5525 HBasicBlock* join_block = |
| 5130 CreateJoin(empty_block, right_block, expr->id()); | 5526 CreateJoin(empty_block, right_block, expr->id()); |
| 5131 set_current_block(join_block); | 5527 set_current_block(join_block); |
| 5132 // We did not materialize any value in the predecessor environments, | 5528 // We did not materialize any value in the predecessor environments, |
| 5133 // so there is no need to handle it here. | 5529 // so there is no need to handle it here. |
| 5134 } | 5530 } |
| 5135 } | 5531 } |
| 5136 | 5532 |
| 5137 | 5533 |
| 5138 void HGraphBuilder::VisitCommon(BinaryOperation* expr) { | 5534 void HGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { |
| 5139 CHECK_ALIVE(VisitForValue(expr->left())); | 5535 CHECK_ALIVE(VisitForValue(expr->left())); |
| 5140 CHECK_ALIVE(VisitForValue(expr->right())); | 5536 CHECK_ALIVE(VisitForValue(expr->right())); |
| 5141 HValue* right = Pop(); | 5537 HValue* right = Pop(); |
| 5142 HValue* left = Pop(); | 5538 HValue* left = Pop(); |
| 5143 HInstruction* instr = BuildBinaryOperation(expr, left, right); | 5539 HInstruction* instr = BuildBinaryOperation(expr, left, right); |
| 5144 instr->set_position(expr->position()); | 5540 instr->set_position(expr->position()); |
| 5145 ast_context()->ReturnInstruction(instr, expr->id()); | 5541 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 5146 } | 5542 } |
| 5147 | 5543 |
| 5148 | 5544 |
| 5149 void HGraphBuilder::TraceRepresentation(Token::Value op, | 5545 void HGraphBuilder::TraceRepresentation(Token::Value op, |
| 5150 TypeInfo info, | 5546 TypeInfo info, |
| 5151 HValue* value, | 5547 HValue* value, |
| 5152 Representation rep) { | 5548 Representation rep) { |
| 5153 if (!FLAG_trace_representation) return; | 5549 if (!FLAG_trace_representation) return; |
| 5154 // TODO(svenpanne) Under which circumstances are we actually not flexible? | 5550 // TODO(svenpanne) Under which circumstances are we actually not flexible? |
| 5155 // At first glance, this looks a bit weird... | 5551 // At first glance, this looks a bit weird... |
| (...skipping 12 matching lines...) Expand all Loading... |
| 5168 | 5564 |
| 5169 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { | 5565 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { |
| 5170 if (info.IsSmi()) return Representation::Integer32(); | 5566 if (info.IsSmi()) return Representation::Integer32(); |
| 5171 if (info.IsInteger32()) return Representation::Integer32(); | 5567 if (info.IsInteger32()) return Representation::Integer32(); |
| 5172 if (info.IsDouble()) return Representation::Double(); | 5568 if (info.IsDouble()) return Representation::Double(); |
| 5173 if (info.IsNumber()) return Representation::Double(); | 5569 if (info.IsNumber()) return Representation::Double(); |
| 5174 return Representation::Tagged(); | 5570 return Representation::Tagged(); |
| 5175 } | 5571 } |
| 5176 | 5572 |
| 5177 | 5573 |
| 5574 void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* compare_expr, |
| 5575 Expression* expr, |
| 5576 Handle<String> check) { |
| 5577 CHECK_ALIVE(VisitForTypeOf(expr)); |
| 5578 HValue* expr_value = Pop(); |
| 5579 HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(expr_value, check); |
| 5580 instr->set_position(compare_expr->position()); |
| 5581 return ast_context()->ReturnControl(instr, compare_expr->id()); |
| 5582 } |
| 5583 |
| 5584 |
| 5585 void HGraphBuilder::HandleLiteralCompareUndefined( |
| 5586 CompareOperation* compare_expr, Expression* expr) { |
| 5587 CHECK_ALIVE(VisitForValue(expr)); |
| 5588 HValue* lhs = Pop(); |
| 5589 HValue* rhs = graph()->GetConstantUndefined(); |
| 5590 HCompareObjectEqAndBranch* instr = |
| 5591 new(zone()) HCompareObjectEqAndBranch(lhs, rhs); |
| 5592 instr->set_position(compare_expr->position()); |
| 5593 return ast_context()->ReturnControl(instr, compare_expr->id()); |
| 5594 } |
| 5595 |
| 5596 |
| 5178 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 5597 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 5179 ASSERT(!HasStackOverflow()); | 5598 ASSERT(!HasStackOverflow()); |
| 5180 ASSERT(current_block() != NULL); | 5599 ASSERT(current_block() != NULL); |
| 5181 ASSERT(current_block()->HasPredecessor()); | 5600 ASSERT(current_block()->HasPredecessor()); |
| 5182 if (IsClassOfTest(expr)) { | 5601 if (IsClassOfTest(expr)) { |
| 5183 CallRuntime* call = expr->left()->AsCallRuntime(); | 5602 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 5603 ASSERT(call->arguments()->length() == 1); |
| 5184 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5604 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5185 HValue* value = Pop(); | 5605 HValue* value = Pop(); |
| 5186 Literal* literal = expr->right()->AsLiteral(); | 5606 Literal* literal = expr->right()->AsLiteral(); |
| 5187 Handle<String> rhs = Handle<String>::cast(literal->handle()); | 5607 Handle<String> rhs = Handle<String>::cast(literal->handle()); |
| 5188 HInstruction* instr = new(zone()) HClassOfTest(value, rhs); | 5608 HClassOfTestAndBranch* instr = |
| 5609 new(zone()) HClassOfTestAndBranch(value, rhs); |
| 5189 instr->set_position(expr->position()); | 5610 instr->set_position(expr->position()); |
| 5190 ast_context()->ReturnInstruction(instr, expr->id()); | 5611 return ast_context()->ReturnControl(instr, expr->id()); |
| 5612 } |
| 5613 |
| 5614 // Check for special cases that compare against literals. |
| 5615 Expression *sub_expr; |
| 5616 Handle<String> check; |
| 5617 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { |
| 5618 HandleLiteralCompareTypeof(expr, sub_expr, check); |
| 5191 return; | 5619 return; |
| 5192 } | 5620 } |
| 5193 | 5621 |
| 5194 // Check for the pattern: typeof <expression> == <string literal>. | 5622 if (expr->IsLiteralCompareUndefined(&sub_expr)) { |
| 5195 UnaryOperation* left_unary = expr->left()->AsUnaryOperation(); | 5623 HandleLiteralCompareUndefined(expr, sub_expr); |
| 5196 Literal* right_literal = expr->right()->AsLiteral(); | |
| 5197 if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) && | |
| 5198 left_unary != NULL && left_unary->op() == Token::TYPEOF && | |
| 5199 right_literal != NULL && right_literal->handle()->IsString()) { | |
| 5200 CHECK_ALIVE(VisitForTypeOf(left_unary->expression())); | |
| 5201 HValue* left = Pop(); | |
| 5202 HInstruction* instr = new(zone()) HTypeofIs(left, | |
| 5203 Handle<String>::cast(right_literal->handle())); | |
| 5204 instr->set_position(expr->position()); | |
| 5205 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 5206 return; | 5624 return; |
| 5207 } | 5625 } |
| 5208 | 5626 |
| 5627 TypeInfo type_info = oracle()->CompareType(expr); |
| 5628 // Check if this expression was ever executed according to type feedback. |
| 5629 if (type_info.IsUninitialized()) { |
| 5630 AddInstruction(new(zone()) HSoftDeoptimize); |
| 5631 current_block()->MarkAsDeoptimizing(); |
| 5632 type_info = TypeInfo::Unknown(); |
| 5633 } |
| 5634 |
| 5209 CHECK_ALIVE(VisitForValue(expr->left())); | 5635 CHECK_ALIVE(VisitForValue(expr->left())); |
| 5210 CHECK_ALIVE(VisitForValue(expr->right())); | 5636 CHECK_ALIVE(VisitForValue(expr->right())); |
| 5211 | 5637 |
| 5638 HValue* context = environment()->LookupContext(); |
| 5212 HValue* right = Pop(); | 5639 HValue* right = Pop(); |
| 5213 HValue* left = Pop(); | 5640 HValue* left = Pop(); |
| 5214 Token::Value op = expr->op(); | 5641 Token::Value op = expr->op(); |
| 5215 | 5642 |
| 5216 TypeInfo type_info = oracle()->CompareType(expr); | |
| 5217 HInstruction* instr = NULL; | |
| 5218 if (op == Token::INSTANCEOF) { | 5643 if (op == Token::INSTANCEOF) { |
| 5219 // Check to see if the rhs of the instanceof is a global function not | 5644 // Check to see if the rhs of the instanceof is a global function not |
| 5220 // residing in new space. If it is we assume that the function will stay the | 5645 // residing in new space. If it is we assume that the function will stay the |
| 5221 // same. | 5646 // same. |
| 5222 Handle<JSFunction> target = Handle<JSFunction>::null(); | 5647 Handle<JSFunction> target = Handle<JSFunction>::null(); |
| 5223 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); | 5648 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); |
| 5224 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); | 5649 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); |
| 5225 if (global_function && | 5650 if (global_function && |
| 5226 info()->has_global_object() && | 5651 info()->has_global_object() && |
| 5227 !info()->global_object()->IsAccessCheckNeeded()) { | 5652 !info()->global_object()->IsAccessCheckNeeded()) { |
| 5228 Handle<String> name = var->name(); | 5653 Handle<String> name = var->name(); |
| 5229 Handle<GlobalObject> global(info()->global_object()); | 5654 Handle<GlobalObject> global(info()->global_object()); |
| 5230 LookupResult lookup; | 5655 LookupResult lookup; |
| 5231 global->Lookup(*name, &lookup); | 5656 global->Lookup(*name, &lookup); |
| 5232 if (lookup.IsProperty() && | 5657 if (lookup.IsProperty() && |
| 5233 lookup.type() == NORMAL && | 5658 lookup.type() == NORMAL && |
| 5234 lookup.GetValue()->IsJSFunction()) { | 5659 lookup.GetValue()->IsJSFunction()) { |
| 5235 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); | 5660 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
| 5236 // If the function is in new space we assume it's more likely to | 5661 // If the function is in new space we assume it's more likely to |
| 5237 // change and thus prefer the general IC code. | 5662 // change and thus prefer the general IC code. |
| 5238 if (!isolate()->heap()->InNewSpace(*candidate)) { | 5663 if (!isolate()->heap()->InNewSpace(*candidate)) { |
| 5239 target = candidate; | 5664 target = candidate; |
| 5240 } | 5665 } |
| 5241 } | 5666 } |
| 5242 } | 5667 } |
| 5243 | 5668 |
| 5244 // If the target is not null we have found a known global function that is | 5669 // If the target is not null we have found a known global function that is |
| 5245 // assumed to stay the same for this instanceof. | 5670 // assumed to stay the same for this instanceof. |
| 5246 if (target.is_null()) { | 5671 if (target.is_null()) { |
| 5247 HValue* context = environment()->LookupContext(); | 5672 HInstanceOf* result = new(zone()) HInstanceOf(context, left, right); |
| 5248 instr = new(zone()) HInstanceOf(context, left, right); | 5673 result->set_position(expr->position()); |
| 5674 return ast_context()->ReturnInstruction(result, expr->id()); |
| 5249 } else { | 5675 } else { |
| 5250 AddInstruction(new(zone()) HCheckFunction(right, target)); | 5676 AddInstruction(new(zone()) HCheckFunction(right, target)); |
| 5251 instr = new(zone()) HInstanceOfKnownGlobal(left, target); | 5677 HInstanceOfKnownGlobal* result = |
| 5678 new(zone()) HInstanceOfKnownGlobal(context, left, target); |
| 5679 result->set_position(expr->position()); |
| 5680 return ast_context()->ReturnInstruction(result, expr->id()); |
| 5252 } | 5681 } |
| 5253 } else if (op == Token::IN) { | 5682 } else if (op == Token::IN) { |
| 5254 instr = new(zone()) HIn(left, right); | 5683 HIn* result = new(zone()) HIn(context, left, right); |
| 5684 result->set_position(expr->position()); |
| 5685 return ast_context()->ReturnInstruction(result, expr->id()); |
| 5255 } else if (type_info.IsNonPrimitive()) { | 5686 } else if (type_info.IsNonPrimitive()) { |
| 5256 switch (op) { | 5687 switch (op) { |
| 5257 case Token::EQ: | 5688 case Token::EQ: |
| 5258 case Token::EQ_STRICT: { | 5689 case Token::EQ_STRICT: { |
| 5259 AddInstruction(new(zone()) HCheckNonSmi(left)); | 5690 AddInstruction(new(zone()) HCheckNonSmi(left)); |
| 5260 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); | 5691 AddInstruction(HCheckInstanceType::NewIsSpecObject(left)); |
| 5261 AddInstruction(new(zone()) HCheckNonSmi(right)); | 5692 AddInstruction(new(zone()) HCheckNonSmi(right)); |
| 5262 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); | 5693 AddInstruction(HCheckInstanceType::NewIsSpecObject(right)); |
| 5263 instr = new(zone()) HCompareJSObjectEq(left, right); | 5694 HCompareObjectEqAndBranch* result = |
| 5264 break; | 5695 new(zone()) HCompareObjectEqAndBranch(left, right); |
| 5696 result->set_position(expr->position()); |
| 5697 return ast_context()->ReturnControl(result, expr->id()); |
| 5265 } | 5698 } |
| 5266 default: | 5699 default: |
| 5267 return Bailout("Unsupported non-primitive compare"); | 5700 return Bailout("Unsupported non-primitive compare"); |
| 5268 break; | |
| 5269 } | 5701 } |
| 5270 } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) && | 5702 } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) && |
| 5271 (op == Token::EQ || op == Token::EQ_STRICT)) { | 5703 (op == Token::EQ || op == Token::EQ_STRICT)) { |
| 5272 instr = BuildSymbolCompare(left, right, op); | 5704 AddInstruction(new(zone()) HCheckNonSmi(left)); |
| 5705 AddInstruction(HCheckInstanceType::NewIsSymbol(left)); |
| 5706 AddInstruction(new(zone()) HCheckNonSmi(right)); |
| 5707 AddInstruction(HCheckInstanceType::NewIsSymbol(right)); |
| 5708 HCompareObjectEqAndBranch* result = |
| 5709 new(zone()) HCompareObjectEqAndBranch(left, right); |
| 5710 result->set_position(expr->position()); |
| 5711 return ast_context()->ReturnControl(result, expr->id()); |
| 5273 } else { | 5712 } else { |
| 5274 HCompare* compare = new(zone()) HCompare(left, right, op); | |
| 5275 Representation r = ToRepresentation(type_info); | 5713 Representation r = ToRepresentation(type_info); |
| 5276 compare->SetInputRepresentation(r); | 5714 if (r.IsTagged()) { |
| 5277 instr = compare; | 5715 HCompareGeneric* result = |
| 5716 new(zone()) HCompareGeneric(context, left, right, op); |
| 5717 result->set_position(expr->position()); |
| 5718 return ast_context()->ReturnInstruction(result, expr->id()); |
| 5719 } else { |
| 5720 HCompareIDAndBranch* result = |
| 5721 new(zone()) HCompareIDAndBranch(left, right, op); |
| 5722 result->set_position(expr->position()); |
| 5723 result->SetInputRepresentation(r); |
| 5724 return ast_context()->ReturnControl(result, expr->id()); |
| 5725 } |
| 5278 } | 5726 } |
| 5279 instr->set_position(expr->position()); | |
| 5280 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 5281 } | 5727 } |
| 5282 | 5728 |
| 5283 | 5729 |
| 5284 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { | 5730 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { |
| 5285 ASSERT(!HasStackOverflow()); | 5731 ASSERT(!HasStackOverflow()); |
| 5286 ASSERT(current_block() != NULL); | 5732 ASSERT(current_block() != NULL); |
| 5287 ASSERT(current_block()->HasPredecessor()); | 5733 ASSERT(current_block()->HasPredecessor()); |
| 5288 CHECK_ALIVE(VisitForValue(expr->expression())); | 5734 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 5289 | |
| 5290 HValue* value = Pop(); | 5735 HValue* value = Pop(); |
| 5291 HIsNull* compare = new(zone()) HIsNull(value, expr->is_strict()); | 5736 HIsNullAndBranch* instr = |
| 5292 ast_context()->ReturnInstruction(compare, expr->id()); | 5737 new(zone()) HIsNullAndBranch(value, expr->is_strict()); |
| 5738 return ast_context()->ReturnControl(instr, expr->id()); |
| 5293 } | 5739 } |
| 5294 | 5740 |
| 5295 | 5741 |
| 5296 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { | 5742 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
| 5297 ASSERT(!HasStackOverflow()); | 5743 ASSERT(!HasStackOverflow()); |
| 5298 ASSERT(current_block() != NULL); | 5744 ASSERT(current_block() != NULL); |
| 5299 ASSERT(current_block()->HasPredecessor()); | 5745 ASSERT(current_block()->HasPredecessor()); |
| 5300 return Bailout("ThisFunction"); | 5746 HThisFunction* self = new(zone()) HThisFunction; |
| 5747 return ast_context()->ReturnInstruction(self, expr->id()); |
| 5301 } | 5748 } |
| 5302 | 5749 |
| 5303 | 5750 |
| 5304 void HGraphBuilder::VisitDeclaration(Declaration* decl) { | 5751 void HGraphBuilder::VisitDeclaration(Declaration* decl) { |
| 5305 // We allow only declarations that do not require code generation. | 5752 // We support only declarations that do not require code generation. |
| 5306 // The following all require code generation: global variables and | |
| 5307 // functions, variables with slot type LOOKUP, declarations with | |
| 5308 // mode CONST, and functions. | |
| 5309 Variable* var = decl->proxy()->var(); | 5753 Variable* var = decl->proxy()->var(); |
| 5310 Slot* slot = var->AsSlot(); | 5754 if (!var->IsStackAllocated() || decl->fun() != NULL) { |
| 5311 if (var->is_global() || | |
| 5312 (slot != NULL && slot->type() == Slot::LOOKUP) || | |
| 5313 decl->mode() == Variable::CONST || | |
| 5314 decl->fun() != NULL) { | |
| 5315 return Bailout("unsupported declaration"); | 5755 return Bailout("unsupported declaration"); |
| 5316 } | 5756 } |
| 5757 |
| 5758 if (decl->mode() == Variable::CONST) { |
| 5759 ASSERT(var->IsStackAllocated()); |
| 5760 environment()->Bind(var, graph()->GetConstantHole()); |
| 5761 } |
| 5317 } | 5762 } |
| 5318 | 5763 |
| 5319 | 5764 |
| 5320 // Generators for inline runtime functions. | 5765 // Generators for inline runtime functions. |
| 5321 // Support for types. | 5766 // Support for types. |
| 5322 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { | 5767 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { |
| 5323 ASSERT(call->arguments()->length() == 1); | 5768 ASSERT(call->arguments()->length() == 1); |
| 5324 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5769 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5325 HValue* value = Pop(); | 5770 HValue* value = Pop(); |
| 5326 HIsSmi* result = new(zone()) HIsSmi(value); | 5771 HIsSmiAndBranch* result = new(zone()) HIsSmiAndBranch(value); |
| 5327 ast_context()->ReturnInstruction(result, call->id()); | 5772 return ast_context()->ReturnControl(result, call->id()); |
| 5328 } | 5773 } |
| 5329 | 5774 |
| 5330 | 5775 |
| 5331 void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { | 5776 void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { |
| 5332 ASSERT(call->arguments()->length() == 1); | 5777 ASSERT(call->arguments()->length() == 1); |
| 5333 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5778 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5334 HValue* value = Pop(); | 5779 HValue* value = Pop(); |
| 5335 HHasInstanceType* result = | 5780 HHasInstanceTypeAndBranch* result = |
| 5336 new(zone()) HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); | 5781 new(zone()) HHasInstanceTypeAndBranch(value, |
| 5337 ast_context()->ReturnInstruction(result, call->id()); | 5782 FIRST_SPEC_OBJECT_TYPE, |
| 5783 LAST_SPEC_OBJECT_TYPE); |
| 5784 return ast_context()->ReturnControl(result, call->id()); |
| 5338 } | 5785 } |
| 5339 | 5786 |
| 5340 | 5787 |
| 5341 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { | 5788 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { |
| 5342 ASSERT(call->arguments()->length() == 1); | 5789 ASSERT(call->arguments()->length() == 1); |
| 5343 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5790 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5344 HValue* value = Pop(); | 5791 HValue* value = Pop(); |
| 5345 HHasInstanceType* result = | 5792 HHasInstanceTypeAndBranch* result = |
| 5346 new(zone()) HHasInstanceType(value, JS_FUNCTION_TYPE); | 5793 new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE); |
| 5347 ast_context()->ReturnInstruction(result, call->id()); | 5794 return ast_context()->ReturnControl(result, call->id()); |
| 5348 } | 5795 } |
| 5349 | 5796 |
| 5350 | 5797 |
| 5351 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { | 5798 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { |
| 5352 ASSERT(call->arguments()->length() == 1); | 5799 ASSERT(call->arguments()->length() == 1); |
| 5353 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5800 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5354 HValue* value = Pop(); | 5801 HValue* value = Pop(); |
| 5355 HHasCachedArrayIndex* result = new(zone()) HHasCachedArrayIndex(value); | 5802 HHasCachedArrayIndexAndBranch* result = |
| 5356 ast_context()->ReturnInstruction(result, call->id()); | 5803 new(zone()) HHasCachedArrayIndexAndBranch(value); |
| 5804 return ast_context()->ReturnControl(result, call->id()); |
| 5357 } | 5805 } |
| 5358 | 5806 |
| 5359 | 5807 |
| 5360 void HGraphBuilder::GenerateIsArray(CallRuntime* call) { | 5808 void HGraphBuilder::GenerateIsArray(CallRuntime* call) { |
| 5361 ASSERT(call->arguments()->length() == 1); | 5809 ASSERT(call->arguments()->length() == 1); |
| 5362 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5810 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5363 HValue* value = Pop(); | 5811 HValue* value = Pop(); |
| 5364 HHasInstanceType* result = new(zone()) HHasInstanceType(value, JS_ARRAY_TYPE); | 5812 HHasInstanceTypeAndBranch* result = |
| 5365 ast_context()->ReturnInstruction(result, call->id()); | 5813 new(zone()) HHasInstanceTypeAndBranch(value, JS_ARRAY_TYPE); |
| 5814 return ast_context()->ReturnControl(result, call->id()); |
| 5366 } | 5815 } |
| 5367 | 5816 |
| 5368 | 5817 |
| 5369 void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) { | 5818 void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) { |
| 5370 ASSERT(call->arguments()->length() == 1); | 5819 ASSERT(call->arguments()->length() == 1); |
| 5371 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5820 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5372 HValue* value = Pop(); | 5821 HValue* value = Pop(); |
| 5373 HHasInstanceType* result = | 5822 HHasInstanceTypeAndBranch* result = |
| 5374 new(zone()) HHasInstanceType(value, JS_REGEXP_TYPE); | 5823 new(zone()) HHasInstanceTypeAndBranch(value, JS_REGEXP_TYPE); |
| 5375 ast_context()->ReturnInstruction(result, call->id()); | 5824 return ast_context()->ReturnControl(result, call->id()); |
| 5376 } | 5825 } |
| 5377 | 5826 |
| 5378 | 5827 |
| 5379 void HGraphBuilder::GenerateIsObject(CallRuntime* call) { | 5828 void HGraphBuilder::GenerateIsObject(CallRuntime* call) { |
| 5380 ASSERT(call->arguments()->length() == 1); | 5829 ASSERT(call->arguments()->length() == 1); |
| 5381 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5830 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5382 HValue* value = Pop(); | 5831 HValue* value = Pop(); |
| 5383 HIsObject* test = new(zone()) HIsObject(value); | 5832 HIsObjectAndBranch* result = new(zone()) HIsObjectAndBranch(value); |
| 5384 ast_context()->ReturnInstruction(test, call->id()); | 5833 return ast_context()->ReturnControl(result, call->id()); |
| 5385 } | 5834 } |
| 5386 | 5835 |
| 5387 | 5836 |
| 5388 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { | 5837 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { |
| 5389 return Bailout("inlined runtime function: IsNonNegativeSmi"); | 5838 return Bailout("inlined runtime function: IsNonNegativeSmi"); |
| 5390 } | 5839 } |
| 5391 | 5840 |
| 5392 | 5841 |
| 5393 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { | 5842 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { |
| 5394 ASSERT(call->arguments()->length() == 1); | 5843 ASSERT(call->arguments()->length() == 1); |
| 5395 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5844 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5396 HValue* value = Pop(); | 5845 HValue* value = Pop(); |
| 5397 ast_context()->ReturnInstruction(new(zone()) HIsUndetectable(value), | 5846 HIsUndetectableAndBranch* result = |
| 5398 call->id()); | 5847 new(zone()) HIsUndetectableAndBranch(value); |
| 5848 return ast_context()->ReturnControl(result, call->id()); |
| 5399 } | 5849 } |
| 5400 | 5850 |
| 5401 | 5851 |
| 5402 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 5852 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 5403 CallRuntime* call) { | 5853 CallRuntime* call) { |
| 5404 return Bailout( | 5854 return Bailout( |
| 5405 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 5855 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 5406 } | 5856 } |
| 5407 | 5857 |
| 5408 | 5858 |
| 5409 // Support for construct call checks. | 5859 // Support for construct call checks. |
| 5410 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { | 5860 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { |
| 5411 ASSERT(call->arguments()->length() == 0); | 5861 ASSERT(call->arguments()->length() == 0); |
| 5412 if (function_state()->outer() != NULL) { | 5862 if (function_state()->outer() != NULL) { |
| 5413 // We are generating graph for inlined function. Currently | 5863 // We are generating graph for inlined function. Currently |
| 5414 // constructor inlining is not supported and we can just return | 5864 // constructor inlining is not supported and we can just return |
| 5415 // false from %_IsConstructCall(). | 5865 // false from %_IsConstructCall(). |
| 5416 ast_context()->ReturnValue(graph()->GetConstantFalse()); | 5866 return ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 5417 } else { | 5867 } else { |
| 5418 ast_context()->ReturnInstruction(new(zone()) HIsConstructCall, call->id()); | 5868 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, |
| 5869 call->id()); |
| 5419 } | 5870 } |
| 5420 } | 5871 } |
| 5421 | 5872 |
| 5422 | 5873 |
| 5423 // Support for arguments.length and arguments[?]. | 5874 // Support for arguments.length and arguments[?]. |
| 5424 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { | 5875 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
| 5876 // Our implementation of arguments (based on this stack frame or an |
| 5877 // adapter below it) does not work for inlined functions. This runtime |
| 5878 // function is blacklisted by AstNode::IsInlineable. |
| 5879 ASSERT(function_state()->outer() == NULL); |
| 5425 ASSERT(call->arguments()->length() == 0); | 5880 ASSERT(call->arguments()->length() == 0); |
| 5426 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 5881 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
| 5427 HArgumentsLength* result = new(zone()) HArgumentsLength(elements); | 5882 HArgumentsLength* result = new(zone()) HArgumentsLength(elements); |
| 5428 ast_context()->ReturnInstruction(result, call->id()); | 5883 return ast_context()->ReturnInstruction(result, call->id()); |
| 5429 } | 5884 } |
| 5430 | 5885 |
| 5431 | 5886 |
| 5432 void HGraphBuilder::GenerateArguments(CallRuntime* call) { | 5887 void HGraphBuilder::GenerateArguments(CallRuntime* call) { |
| 5888 // Our implementation of arguments (based on this stack frame or an |
| 5889 // adapter below it) does not work for inlined functions. This runtime |
| 5890 // function is blacklisted by AstNode::IsInlineable. |
| 5891 ASSERT(function_state()->outer() == NULL); |
| 5433 ASSERT(call->arguments()->length() == 1); | 5892 ASSERT(call->arguments()->length() == 1); |
| 5434 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5893 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5435 HValue* index = Pop(); | 5894 HValue* index = Pop(); |
| 5436 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); | 5895 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
| 5437 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); | 5896 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); |
| 5438 HAccessArgumentsAt* result = | 5897 HAccessArgumentsAt* result = |
| 5439 new(zone()) HAccessArgumentsAt(elements, length, index); | 5898 new(zone()) HAccessArgumentsAt(elements, length, index); |
| 5440 ast_context()->ReturnInstruction(result, call->id()); | 5899 return ast_context()->ReturnInstruction(result, call->id()); |
| 5441 } | 5900 } |
| 5442 | 5901 |
| 5443 | 5902 |
| 5444 // Support for accessing the class and value fields of an object. | 5903 // Support for accessing the class and value fields of an object. |
| 5445 void HGraphBuilder::GenerateClassOf(CallRuntime* call) { | 5904 void HGraphBuilder::GenerateClassOf(CallRuntime* call) { |
| 5446 // The special form detected by IsClassOfTest is detected before we get here | 5905 // The special form detected by IsClassOfTest is detected before we get here |
| 5447 // and does not cause a bailout. | 5906 // and does not cause a bailout. |
| 5448 return Bailout("inlined runtime function: ClassOf"); | 5907 return Bailout("inlined runtime function: ClassOf"); |
| 5449 } | 5908 } |
| 5450 | 5909 |
| 5451 | 5910 |
| 5452 void HGraphBuilder::GenerateValueOf(CallRuntime* call) { | 5911 void HGraphBuilder::GenerateValueOf(CallRuntime* call) { |
| 5453 ASSERT(call->arguments()->length() == 1); | 5912 ASSERT(call->arguments()->length() == 1); |
| 5454 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5913 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5455 HValue* value = Pop(); | 5914 HValue* value = Pop(); |
| 5456 HValueOf* result = new(zone()) HValueOf(value); | 5915 HValueOf* result = new(zone()) HValueOf(value); |
| 5457 ast_context()->ReturnInstruction(result, call->id()); | 5916 return ast_context()->ReturnInstruction(result, call->id()); |
| 5458 } | 5917 } |
| 5459 | 5918 |
| 5460 | 5919 |
| 5461 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) { | 5920 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) { |
| 5462 return Bailout("inlined runtime function: SetValueOf"); | 5921 return Bailout("inlined runtime function: SetValueOf"); |
| 5463 } | 5922 } |
| 5464 | 5923 |
| 5465 | 5924 |
| 5466 // Fast support for charCodeAt(n). | 5925 // Fast support for charCodeAt(n). |
| 5467 void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { | 5926 void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { |
| 5468 ASSERT(call->arguments()->length() == 2); | 5927 ASSERT(call->arguments()->length() == 2); |
| 5469 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5928 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5470 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 5929 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 5471 HValue* index = Pop(); | 5930 HValue* index = Pop(); |
| 5472 HValue* string = Pop(); | 5931 HValue* string = Pop(); |
| 5473 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); | 5932 HValue* context = environment()->LookupContext(); |
| 5474 ast_context()->ReturnInstruction(result, call->id()); | 5933 HStringCharCodeAt* result = BuildStringCharCodeAt(context, string, index); |
| 5934 return ast_context()->ReturnInstruction(result, call->id()); |
| 5475 } | 5935 } |
| 5476 | 5936 |
| 5477 | 5937 |
| 5478 // Fast support for string.charAt(n) and string[n]. | 5938 // Fast support for string.charAt(n) and string[n]. |
| 5479 void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) { | 5939 void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) { |
| 5480 ASSERT(call->arguments()->length() == 1); | 5940 ASSERT(call->arguments()->length() == 1); |
| 5481 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5941 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5482 HValue* char_code = Pop(); | 5942 HValue* char_code = Pop(); |
| 5483 HStringCharFromCode* result = new(zone()) HStringCharFromCode(char_code); | 5943 HValue* context = environment()->LookupContext(); |
| 5484 ast_context()->ReturnInstruction(result, call->id()); | 5944 HStringCharFromCode* result = |
| 5945 new(zone()) HStringCharFromCode(context, char_code); |
| 5946 return ast_context()->ReturnInstruction(result, call->id()); |
| 5485 } | 5947 } |
| 5486 | 5948 |
| 5487 | 5949 |
| 5488 // Fast support for string.charAt(n) and string[n]. | 5950 // Fast support for string.charAt(n) and string[n]. |
| 5489 void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) { | 5951 void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) { |
| 5490 ASSERT(call->arguments()->length() == 2); | 5952 ASSERT(call->arguments()->length() == 2); |
| 5491 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5953 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5492 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 5954 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 5493 HValue* index = Pop(); | 5955 HValue* index = Pop(); |
| 5494 HValue* string = Pop(); | 5956 HValue* string = Pop(); |
| 5495 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); | 5957 HValue* context = environment()->LookupContext(); |
| 5958 HStringCharCodeAt* char_code = BuildStringCharCodeAt(context, string, index); |
| 5496 AddInstruction(char_code); | 5959 AddInstruction(char_code); |
| 5497 HStringCharFromCode* result = new(zone()) HStringCharFromCode(char_code); | 5960 HStringCharFromCode* result = |
| 5498 ast_context()->ReturnInstruction(result, call->id()); | 5961 new(zone()) HStringCharFromCode(context, char_code); |
| 5962 return ast_context()->ReturnInstruction(result, call->id()); |
| 5499 } | 5963 } |
| 5500 | 5964 |
| 5501 | 5965 |
| 5502 // Fast support for object equality testing. | 5966 // Fast support for object equality testing. |
| 5503 void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) { | 5967 void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) { |
| 5504 ASSERT(call->arguments()->length() == 2); | 5968 ASSERT(call->arguments()->length() == 2); |
| 5505 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5969 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5506 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 5970 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 5507 HValue* right = Pop(); | 5971 HValue* right = Pop(); |
| 5508 HValue* left = Pop(); | 5972 HValue* left = Pop(); |
| 5509 HCompareJSObjectEq* result = new(zone()) HCompareJSObjectEq(left, right); | 5973 HCompareObjectEqAndBranch* result = |
| 5510 ast_context()->ReturnInstruction(result, call->id()); | 5974 new(zone()) HCompareObjectEqAndBranch(left, right); |
| 5975 return ast_context()->ReturnControl(result, call->id()); |
| 5511 } | 5976 } |
| 5512 | 5977 |
| 5513 | 5978 |
| 5514 void HGraphBuilder::GenerateLog(CallRuntime* call) { | 5979 void HGraphBuilder::GenerateLog(CallRuntime* call) { |
| 5515 // %_Log is ignored in optimized code. | 5980 // %_Log is ignored in optimized code. |
| 5516 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 5981 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 5517 } | 5982 } |
| 5518 | 5983 |
| 5519 | 5984 |
| 5520 // Fast support for Math.random(). | 5985 // Fast support for Math.random(). |
| 5521 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { | 5986 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { |
| 5522 return Bailout("inlined runtime function: RandomHeapNumber"); | 5987 return Bailout("inlined runtime function: RandomHeapNumber"); |
| 5523 } | 5988 } |
| 5524 | 5989 |
| 5525 | 5990 |
| 5526 // Fast support for StringAdd. | 5991 // Fast support for StringAdd. |
| 5527 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) { | 5992 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
| 5528 ASSERT_EQ(2, call->arguments()->length()); | 5993 ASSERT_EQ(2, call->arguments()->length()); |
| 5529 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5994 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5530 HValue* context = environment()->LookupContext(); | 5995 HValue* context = environment()->LookupContext(); |
| 5531 HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2); | 5996 HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2); |
| 5532 Drop(2); | 5997 Drop(2); |
| 5533 ast_context()->ReturnInstruction(result, call->id()); | 5998 return ast_context()->ReturnInstruction(result, call->id()); |
| 5534 } | 5999 } |
| 5535 | 6000 |
| 5536 | 6001 |
| 5537 // Fast support for SubString. | 6002 // Fast support for SubString. |
| 5538 void HGraphBuilder::GenerateSubString(CallRuntime* call) { | 6003 void HGraphBuilder::GenerateSubString(CallRuntime* call) { |
| 5539 ASSERT_EQ(3, call->arguments()->length()); | 6004 ASSERT_EQ(3, call->arguments()->length()); |
| 5540 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 6005 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5541 HValue* context = environment()->LookupContext(); | 6006 HValue* context = environment()->LookupContext(); |
| 5542 HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3); | 6007 HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3); |
| 5543 Drop(3); | 6008 Drop(3); |
| 5544 ast_context()->ReturnInstruction(result, call->id()); | 6009 return ast_context()->ReturnInstruction(result, call->id()); |
| 5545 } | 6010 } |
| 5546 | 6011 |
| 5547 | 6012 |
| 5548 // Fast support for StringCompare. | 6013 // Fast support for StringCompare. |
| 5549 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) { | 6014 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) { |
| 5550 ASSERT_EQ(2, call->arguments()->length()); | 6015 ASSERT_EQ(2, call->arguments()->length()); |
| 5551 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 6016 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5552 HValue* context = environment()->LookupContext(); | 6017 HValue* context = environment()->LookupContext(); |
| 5553 HCallStub* result = | 6018 HCallStub* result = |
| 5554 new(zone()) HCallStub(context, CodeStub::StringCompare, 2); | 6019 new(zone()) HCallStub(context, CodeStub::StringCompare, 2); |
| 5555 Drop(2); | 6020 Drop(2); |
| 5556 ast_context()->ReturnInstruction(result, call->id()); | 6021 return ast_context()->ReturnInstruction(result, call->id()); |
| 5557 } | 6022 } |
| 5558 | 6023 |
| 5559 | 6024 |
| 5560 // Support for direct calls from JavaScript to native RegExp code. | 6025 // Support for direct calls from JavaScript to native RegExp code. |
| 5561 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) { | 6026 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) { |
| 5562 ASSERT_EQ(4, call->arguments()->length()); | 6027 ASSERT_EQ(4, call->arguments()->length()); |
| 5563 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 6028 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5564 HValue* context = environment()->LookupContext(); | 6029 HValue* context = environment()->LookupContext(); |
| 5565 HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4); | 6030 HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4); |
| 5566 Drop(4); | 6031 Drop(4); |
| 5567 ast_context()->ReturnInstruction(result, call->id()); | 6032 return ast_context()->ReturnInstruction(result, call->id()); |
| 5568 } | 6033 } |
| 5569 | 6034 |
| 5570 | 6035 |
| 5571 // Construct a RegExp exec result with two in-object properties. | 6036 // Construct a RegExp exec result with two in-object properties. |
| 5572 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { | 6037 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { |
| 5573 ASSERT_EQ(3, call->arguments()->length()); | 6038 ASSERT_EQ(3, call->arguments()->length()); |
| 5574 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 6039 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5575 HValue* context = environment()->LookupContext(); | 6040 HValue* context = environment()->LookupContext(); |
| 5576 HCallStub* result = | 6041 HCallStub* result = |
| 5577 new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3); | 6042 new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3); |
| 5578 Drop(3); | 6043 Drop(3); |
| 5579 ast_context()->ReturnInstruction(result, call->id()); | 6044 return ast_context()->ReturnInstruction(result, call->id()); |
| 5580 } | 6045 } |
| 5581 | 6046 |
| 5582 | 6047 |
| 5583 // Support for fast native caches. | 6048 // Support for fast native caches. |
| 5584 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) { | 6049 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) { |
| 5585 return Bailout("inlined runtime function: GetFromCache"); | 6050 return Bailout("inlined runtime function: GetFromCache"); |
| 5586 } | 6051 } |
| 5587 | 6052 |
| 5588 | 6053 |
| 5589 // Fast support for number to string. | 6054 // Fast support for number to string. |
| 5590 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) { | 6055 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) { |
| 5591 ASSERT_EQ(1, call->arguments()->length()); | 6056 ASSERT_EQ(1, call->arguments()->length()); |
| 5592 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 6057 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5593 HValue* context = environment()->LookupContext(); | 6058 HValue* context = environment()->LookupContext(); |
| 5594 HCallStub* result = | 6059 HCallStub* result = |
| 5595 new(zone()) HCallStub(context, CodeStub::NumberToString, 1); | 6060 new(zone()) HCallStub(context, CodeStub::NumberToString, 1); |
| 5596 Drop(1); | 6061 Drop(1); |
| 5597 ast_context()->ReturnInstruction(result, call->id()); | 6062 return ast_context()->ReturnInstruction(result, call->id()); |
| 5598 } | 6063 } |
| 5599 | 6064 |
| 5600 | 6065 |
| 5601 // Fast swapping of elements. Takes three expressions, the object and two | 6066 // Fast swapping of elements. Takes three expressions, the object and two |
| 5602 // indices. This should only be used if the indices are known to be | 6067 // indices. This should only be used if the indices are known to be |
| 5603 // non-negative and within bounds of the elements array at the call site. | 6068 // non-negative and within bounds of the elements array at the call site. |
| 5604 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) { | 6069 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) { |
| 5605 return Bailout("inlined runtime function: SwapElements"); | 6070 return Bailout("inlined runtime function: SwapElements"); |
| 5606 } | 6071 } |
| 5607 | 6072 |
| 5608 | 6073 |
| 5609 // Fast call for custom callbacks. | 6074 // Fast call for custom callbacks. |
| 5610 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) { | 6075 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) { |
| 5611 // 1 ~ The function to call is not itself an argument to the call. | 6076 // 1 ~ The function to call is not itself an argument to the call. |
| 5612 int arg_count = call->arguments()->length() - 1; | 6077 int arg_count = call->arguments()->length() - 1; |
| 5613 ASSERT(arg_count >= 1); // There's always at least a receiver. | 6078 ASSERT(arg_count >= 1); // There's always at least a receiver. |
| 5614 | 6079 |
| 5615 for (int i = 0; i < arg_count; ++i) { | 6080 for (int i = 0; i < arg_count; ++i) { |
| 5616 CHECK_ALIVE(VisitArgument(call->arguments()->at(i))); | 6081 CHECK_ALIVE(VisitArgument(call->arguments()->at(i))); |
| 5617 } | 6082 } |
| 5618 CHECK_ALIVE(VisitForValue(call->arguments()->last())); | 6083 CHECK_ALIVE(VisitForValue(call->arguments()->last())); |
| 5619 HValue* function = Pop(); | 6084 HValue* function = Pop(); |
| 5620 HValue* context = environment()->LookupContext(); | 6085 HValue* context = environment()->LookupContext(); |
| 5621 HInvokeFunction* result = | 6086 HInvokeFunction* result = |
| 5622 new(zone()) HInvokeFunction(context, function, arg_count); | 6087 new(zone()) HInvokeFunction(context, function, arg_count); |
| 5623 Drop(arg_count); | 6088 Drop(arg_count); |
| 5624 ast_context()->ReturnInstruction(result, call->id()); | 6089 return ast_context()->ReturnInstruction(result, call->id()); |
| 5625 } | 6090 } |
| 5626 | 6091 |
| 5627 | 6092 |
| 5628 // Fast call to math functions. | 6093 // Fast call to math functions. |
| 5629 void HGraphBuilder::GenerateMathPow(CallRuntime* call) { | 6094 void HGraphBuilder::GenerateMathPow(CallRuntime* call) { |
| 5630 ASSERT_EQ(2, call->arguments()->length()); | 6095 ASSERT_EQ(2, call->arguments()->length()); |
| 5631 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 6096 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5632 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 6097 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 5633 HValue* right = Pop(); | 6098 HValue* right = Pop(); |
| 5634 HValue* left = Pop(); | 6099 HValue* left = Pop(); |
| 5635 HPower* result = new(zone()) HPower(left, right); | 6100 HPower* result = new(zone()) HPower(left, right); |
| 5636 ast_context()->ReturnInstruction(result, call->id()); | 6101 return ast_context()->ReturnInstruction(result, call->id()); |
| 5637 } | 6102 } |
| 5638 | 6103 |
| 5639 | 6104 |
| 5640 void HGraphBuilder::GenerateMathSin(CallRuntime* call) { | 6105 void HGraphBuilder::GenerateMathSin(CallRuntime* call) { |
| 5641 ASSERT_EQ(1, call->arguments()->length()); | 6106 ASSERT_EQ(1, call->arguments()->length()); |
| 5642 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 6107 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5643 HValue* context = environment()->LookupContext(); | 6108 HValue* context = environment()->LookupContext(); |
| 5644 HCallStub* result = | 6109 HCallStub* result = |
| 5645 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); | 6110 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5646 result->set_transcendental_type(TranscendentalCache::SIN); | 6111 result->set_transcendental_type(TranscendentalCache::SIN); |
| 5647 Drop(1); | 6112 Drop(1); |
| 5648 ast_context()->ReturnInstruction(result, call->id()); | 6113 return ast_context()->ReturnInstruction(result, call->id()); |
| 5649 } | 6114 } |
| 5650 | 6115 |
| 5651 | 6116 |
| 5652 void HGraphBuilder::GenerateMathCos(CallRuntime* call) { | 6117 void HGraphBuilder::GenerateMathCos(CallRuntime* call) { |
| 5653 ASSERT_EQ(1, call->arguments()->length()); | 6118 ASSERT_EQ(1, call->arguments()->length()); |
| 5654 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 6119 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5655 HValue* context = environment()->LookupContext(); | 6120 HValue* context = environment()->LookupContext(); |
| 5656 HCallStub* result = | 6121 HCallStub* result = |
| 5657 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); | 6122 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5658 result->set_transcendental_type(TranscendentalCache::COS); | 6123 result->set_transcendental_type(TranscendentalCache::COS); |
| 5659 Drop(1); | 6124 Drop(1); |
| 5660 ast_context()->ReturnInstruction(result, call->id()); | 6125 return ast_context()->ReturnInstruction(result, call->id()); |
| 5661 } | 6126 } |
| 5662 | 6127 |
| 5663 | 6128 |
| 5664 void HGraphBuilder::GenerateMathLog(CallRuntime* call) { | 6129 void HGraphBuilder::GenerateMathLog(CallRuntime* call) { |
| 5665 ASSERT_EQ(1, call->arguments()->length()); | 6130 ASSERT_EQ(1, call->arguments()->length()); |
| 5666 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 6131 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5667 HValue* context = environment()->LookupContext(); | 6132 HValue* context = environment()->LookupContext(); |
| 5668 HCallStub* result = | 6133 HCallStub* result = |
| 5669 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); | 6134 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5670 result->set_transcendental_type(TranscendentalCache::LOG); | 6135 result->set_transcendental_type(TranscendentalCache::LOG); |
| 5671 Drop(1); | 6136 Drop(1); |
| 5672 ast_context()->ReturnInstruction(result, call->id()); | 6137 return ast_context()->ReturnInstruction(result, call->id()); |
| 5673 } | 6138 } |
| 5674 | 6139 |
| 5675 | 6140 |
| 5676 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) { | 6141 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
| 5677 return Bailout("inlined runtime function: MathSqrt"); | 6142 return Bailout("inlined runtime function: MathSqrt"); |
| 5678 } | 6143 } |
| 5679 | 6144 |
| 5680 | 6145 |
| 5681 // Check whether two RegExps are equivalent | 6146 // Check whether two RegExps are equivalent |
| 5682 void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { | 6147 void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { |
| 5683 return Bailout("inlined runtime function: IsRegExpEquivalent"); | 6148 return Bailout("inlined runtime function: IsRegExpEquivalent"); |
| 5684 } | 6149 } |
| 5685 | 6150 |
| 5686 | 6151 |
| 5687 void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { | 6152 void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { |
| 5688 ASSERT(call->arguments()->length() == 1); | 6153 ASSERT(call->arguments()->length() == 1); |
| 5689 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 6154 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5690 HValue* value = Pop(); | 6155 HValue* value = Pop(); |
| 5691 HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value); | 6156 HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value); |
| 5692 ast_context()->ReturnInstruction(result, call->id()); | 6157 return ast_context()->ReturnInstruction(result, call->id()); |
| 5693 } | 6158 } |
| 5694 | 6159 |
| 5695 | 6160 |
| 5696 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { | 6161 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { |
| 5697 return Bailout("inlined runtime function: FastAsciiArrayJoin"); | 6162 return Bailout("inlined runtime function: FastAsciiArrayJoin"); |
| 5698 } | 6163 } |
| 5699 | 6164 |
| 5700 | 6165 |
| 6166 void HGraphBuilder::GenerateIsNativeOrStrictMode(CallRuntime* call) { |
| 6167 return Bailout("inlined runtime function: IsNativeOrStrictMode"); |
| 6168 } |
| 6169 |
| 6170 |
| 5701 #undef CHECK_BAILOUT | 6171 #undef CHECK_BAILOUT |
| 5702 #undef CHECK_ALIVE | 6172 #undef CHECK_ALIVE |
| 5703 | 6173 |
| 5704 | 6174 |
| 5705 HEnvironment::HEnvironment(HEnvironment* outer, | 6175 HEnvironment::HEnvironment(HEnvironment* outer, |
| 5706 Scope* scope, | 6176 Scope* scope, |
| 5707 Handle<JSFunction> closure) | 6177 Handle<JSFunction> closure) |
| 5708 : closure_(closure), | 6178 : closure_(closure), |
| 5709 values_(0), | 6179 values_(0), |
| 5710 assigned_variables_(4), | 6180 assigned_variables_(4), |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5853 loop_header->AddPhi(phi); | 6323 loop_header->AddPhi(phi); |
| 5854 } | 6324 } |
| 5855 new_env->ClearHistory(); | 6325 new_env->ClearHistory(); |
| 5856 return new_env; | 6326 return new_env; |
| 5857 } | 6327 } |
| 5858 | 6328 |
| 5859 | 6329 |
| 5860 HEnvironment* HEnvironment::CopyForInlining( | 6330 HEnvironment* HEnvironment::CopyForInlining( |
| 5861 Handle<JSFunction> target, | 6331 Handle<JSFunction> target, |
| 5862 FunctionLiteral* function, | 6332 FunctionLiteral* function, |
| 5863 CompilationPhase compilation_phase, | |
| 5864 HConstant* undefined, | 6333 HConstant* undefined, |
| 5865 CallKind call_kind) const { | 6334 CallKind call_kind) const { |
| 5866 // Outer environment is a copy of this one without the arguments. | 6335 // Outer environment is a copy of this one without the arguments. |
| 5867 int arity = function->scope()->num_parameters(); | 6336 int arity = function->scope()->num_parameters(); |
| 5868 HEnvironment* outer = Copy(); | 6337 HEnvironment* outer = Copy(); |
| 5869 outer->Drop(arity + 1); // Including receiver. | 6338 outer->Drop(arity + 1); // Including receiver. |
| 5870 outer->ClearHistory(); | 6339 outer->ClearHistory(); |
| 5871 Zone* zone = closure()->GetIsolate()->zone(); | 6340 Zone* zone = closure()->GetIsolate()->zone(); |
| 5872 HEnvironment* inner = | 6341 HEnvironment* inner = |
| 5873 new(zone) HEnvironment(outer, function->scope(), target); | 6342 new(zone) HEnvironment(outer, function->scope(), target); |
| 5874 // Get the argument values from the original environment. | 6343 // Get the argument values from the original environment. |
| 5875 if (compilation_phase == HYDROGEN) { | 6344 for (int i = 0; i <= arity; ++i) { // Include receiver. |
| 5876 for (int i = 0; i <= arity; ++i) { // Include receiver. | 6345 HValue* push = ExpressionStackAt(arity - i); |
| 5877 HValue* push = ExpressionStackAt(arity - i); | 6346 inner->SetValueAt(i, push); |
| 5878 inner->SetValueAt(i, push); | |
| 5879 } | |
| 5880 } else { | |
| 5881 ASSERT(compilation_phase == LITHIUM); | |
| 5882 for (int i = 0; i <= arity; ++i) { // Include receiver. | |
| 5883 HValue* push = ExpressionStackAt(arity - i); | |
| 5884 inner->SetValueAt(i, push); | |
| 5885 } | |
| 5886 } | 6347 } |
| 5887 // If the function we are inlining is a strict mode function, pass | 6348 // If the function we are inlining is a strict mode function or a |
| 5888 // undefined as the receiver for function calls (instead of the | 6349 // builtin function, pass undefined as the receiver for function |
| 5889 // global receiver). | 6350 // calls (instead of the global receiver). |
| 5890 if (function->strict_mode() && call_kind == CALL_AS_FUNCTION) { | 6351 if ((target->shared()->native() || function->strict_mode()) && |
| 6352 call_kind == CALL_AS_FUNCTION) { |
| 5891 inner->SetValueAt(0, undefined); | 6353 inner->SetValueAt(0, undefined); |
| 5892 } | 6354 } |
| 5893 inner->SetValueAt(arity + 1, outer->LookupContext()); | 6355 inner->SetValueAt(arity + 1, outer->LookupContext()); |
| 5894 for (int i = arity + 2; i < inner->length(); ++i) { | 6356 for (int i = arity + 2; i < inner->length(); ++i) { |
| 5895 inner->SetValueAt(i, undefined); | 6357 inner->SetValueAt(i, undefined); |
| 5896 } | 6358 } |
| 5897 | 6359 |
| 5898 inner->set_ast_id(AstNode::kFunctionEntryId); | 6360 inner->set_ast_id(AstNode::kFunctionEntryId); |
| 5899 return inner; | 6361 return inner; |
| 5900 } | 6362 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5962 PrintIndent(); | 6424 PrintIndent(); |
| 5963 trace_.Add("predecessors"); | 6425 trace_.Add("predecessors"); |
| 5964 for (int j = 0; j < current->predecessors()->length(); ++j) { | 6426 for (int j = 0; j < current->predecessors()->length(); ++j) { |
| 5965 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id()); | 6427 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id()); |
| 5966 } | 6428 } |
| 5967 trace_.Add("\n"); | 6429 trace_.Add("\n"); |
| 5968 } else { | 6430 } else { |
| 5969 PrintEmptyProperty("predecessors"); | 6431 PrintEmptyProperty("predecessors"); |
| 5970 } | 6432 } |
| 5971 | 6433 |
| 5972 if (current->end() == NULL || current->end()->FirstSuccessor() == NULL) { | 6434 if (current->end()->SuccessorCount() == 0) { |
| 5973 PrintEmptyProperty("successors"); | 6435 PrintEmptyProperty("successors"); |
| 5974 } else if (current->end()->SecondSuccessor() == NULL) { | 6436 } else { |
| 5975 PrintBlockProperty("successors", | 6437 PrintIndent(); |
| 5976 current->end()->FirstSuccessor()->block_id()); | 6438 trace_.Add("successors"); |
| 5977 } else { | 6439 for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) { |
| 5978 PrintBlockProperty("successors", | 6440 trace_.Add(" \"B%d\"", it.Current()->block_id()); |
| 5979 current->end()->FirstSuccessor()->block_id(), | 6441 } |
| 5980 current->end()->SecondSuccessor()->block_id()); | 6442 trace_.Add("\n"); |
| 5981 } | 6443 } |
| 5982 | 6444 |
| 5983 PrintEmptyProperty("xhandlers"); | 6445 PrintEmptyProperty("xhandlers"); |
| 5984 PrintEmptyProperty("flags"); | 6446 PrintEmptyProperty("flags"); |
| 5985 | 6447 |
| 5986 if (current->dominator() != NULL) { | 6448 if (current->dominator() != NULL) { |
| 5987 PrintBlockProperty("dominator", current->dominator()->block_id()); | 6449 PrintBlockProperty("dominator", current->dominator()->block_id()); |
| 5988 } | 6450 } |
| 5989 | 6451 |
| 5990 if (chunk != NULL) { | 6452 if (chunk != NULL) { |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6230 } | 6692 } |
| 6231 } | 6693 } |
| 6232 | 6694 |
| 6233 #ifdef DEBUG | 6695 #ifdef DEBUG |
| 6234 if (graph_ != NULL) graph_->Verify(); | 6696 if (graph_ != NULL) graph_->Verify(); |
| 6235 if (allocator_ != NULL) allocator_->Verify(); | 6697 if (allocator_ != NULL) allocator_->Verify(); |
| 6236 #endif | 6698 #endif |
| 6237 } | 6699 } |
| 6238 | 6700 |
| 6239 } } // namespace v8::internal | 6701 } } // namespace v8::internal |
| OLD | NEW |