| OLD | NEW |
| 1 // Copyright 2010 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 #include "hydrogen.h" | 28 #include "hydrogen.h" |
| 29 | 29 |
| 30 #include "codegen.h" | 30 #include "codegen.h" |
| 31 #include "data-flow.h" | 31 #include "data-flow.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 "scopes.h" | 36 #include "scopes.h" |
| 37 #include "stub-cache.h" |
| 37 | 38 |
| 38 #if V8_TARGET_ARCH_IA32 | 39 #if V8_TARGET_ARCH_IA32 |
| 39 #include "ia32/lithium-codegen-ia32.h" | 40 #include "ia32/lithium-codegen-ia32.h" |
| 40 #elif V8_TARGET_ARCH_X64 | 41 #elif V8_TARGET_ARCH_X64 |
| 41 #include "x64/lithium-codegen-x64.h" | 42 #include "x64/lithium-codegen-x64.h" |
| 42 #elif V8_TARGET_ARCH_ARM | 43 #elif V8_TARGET_ARCH_ARM |
| 43 #include "arm/lithium-codegen-arm.h" | 44 #include "arm/lithium-codegen-arm.h" |
| 44 #else | 45 #else |
| 45 #error Unsupported target architecture. | 46 #error Unsupported target architecture. |
| 46 #endif | 47 #endif |
| (...skipping 10 matching lines...) Expand all Loading... |
| 57 end_(NULL), | 58 end_(NULL), |
| 58 loop_information_(NULL), | 59 loop_information_(NULL), |
| 59 predecessors_(2), | 60 predecessors_(2), |
| 60 dominator_(NULL), | 61 dominator_(NULL), |
| 61 dominated_blocks_(4), | 62 dominated_blocks_(4), |
| 62 last_environment_(NULL), | 63 last_environment_(NULL), |
| 63 argument_count_(-1), | 64 argument_count_(-1), |
| 64 first_instruction_index_(-1), | 65 first_instruction_index_(-1), |
| 65 last_instruction_index_(-1), | 66 last_instruction_index_(-1), |
| 66 deleted_phis_(4), | 67 deleted_phis_(4), |
| 68 parent_loop_header_(NULL), |
| 67 is_inline_return_target_(false) { | 69 is_inline_return_target_(false) { |
| 68 } | 70 } |
| 69 | 71 |
| 70 | 72 |
| 71 void HBasicBlock::AttachLoopInformation() { | 73 void HBasicBlock::AttachLoopInformation() { |
| 72 ASSERT(!IsLoopHeader()); | 74 ASSERT(!IsLoopHeader()); |
| 73 loop_information_ = new HLoopInformation(this); | 75 loop_information_ = new HLoopInformation(this); |
| 74 } | 76 } |
| 75 | 77 |
| 76 | 78 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 97 } | 99 } |
| 98 | 100 |
| 99 | 101 |
| 100 void HBasicBlock::AddInstruction(HInstruction* instr) { | 102 void HBasicBlock::AddInstruction(HInstruction* instr) { |
| 101 ASSERT(!IsStartBlock() || !IsFinished()); | 103 ASSERT(!IsStartBlock() || !IsFinished()); |
| 102 ASSERT(!instr->IsLinked()); | 104 ASSERT(!instr->IsLinked()); |
| 103 ASSERT(!IsFinished()); | 105 ASSERT(!IsFinished()); |
| 104 if (first_ == NULL) { | 106 if (first_ == NULL) { |
| 105 HBlockEntry* entry = new HBlockEntry(); | 107 HBlockEntry* entry = new HBlockEntry(); |
| 106 entry->InitializeAsFirst(this); | 108 entry->InitializeAsFirst(this); |
| 107 first_ = entry; | 109 first_ = last_ = entry; |
| 108 } | 110 } |
| 109 instr->InsertAfter(GetLastInstruction()); | 111 instr->InsertAfter(last_); |
| 110 } | 112 last_ = instr; |
| 111 | |
| 112 | |
| 113 HInstruction* HBasicBlock::GetLastInstruction() { | |
| 114 if (end_ != NULL) return end_->previous(); | |
| 115 if (first_ == NULL) return NULL; | |
| 116 if (last_ == NULL) last_ = first_; | |
| 117 while (last_->next() != NULL) last_ = last_->next(); | |
| 118 return last_; | |
| 119 } | 113 } |
| 120 | 114 |
| 121 | 115 |
| 122 HSimulate* HBasicBlock::CreateSimulate(int id) { | 116 HSimulate* HBasicBlock::CreateSimulate(int id) { |
| 123 ASSERT(HasEnvironment()); | 117 ASSERT(HasEnvironment()); |
| 124 HEnvironment* environment = last_environment(); | 118 HEnvironment* environment = last_environment(); |
| 125 ASSERT(id == AstNode::kNoNumber || | 119 ASSERT(id == AstNode::kNoNumber || |
| 126 environment->closure()->shared()->VerifyBailoutId(id)); | 120 environment->closure()->shared()->VerifyBailoutId(id)); |
| 127 | 121 |
| 128 int push_count = environment->push_count(); | 122 int push_count = environment->push_count(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 UpdateEnvironment(env); | 163 UpdateEnvironment(env); |
| 170 } | 164 } |
| 171 | 165 |
| 172 | 166 |
| 173 void HBasicBlock::SetJoinId(int id) { | 167 void HBasicBlock::SetJoinId(int id) { |
| 174 int length = predecessors_.length(); | 168 int length = predecessors_.length(); |
| 175 ASSERT(length > 0); | 169 ASSERT(length > 0); |
| 176 for (int i = 0; i < length; i++) { | 170 for (int i = 0; i < length; i++) { |
| 177 HBasicBlock* predecessor = predecessors_[i]; | 171 HBasicBlock* predecessor = predecessors_[i]; |
| 178 ASSERT(predecessor->end()->IsGoto()); | 172 ASSERT(predecessor->end()->IsGoto()); |
| 179 HSimulate* simulate = HSimulate::cast(predecessor->GetLastInstruction()); | 173 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); |
| 180 // We only need to verify the ID once. | 174 // We only need to verify the ID once. |
| 181 ASSERT(i != 0 || | 175 ASSERT(i != 0 || |
| 182 predecessor->last_environment()->closure()->shared() | 176 predecessor->last_environment()->closure()->shared() |
| 183 ->VerifyBailoutId(id)); | 177 ->VerifyBailoutId(id)); |
| 184 simulate->set_ast_id(id); | 178 simulate->set_ast_id(id); |
| 185 } | 179 } |
| 186 } | 180 } |
| 187 | 181 |
| 188 | 182 |
| 189 bool HBasicBlock::Dominates(HBasicBlock* other) const { | 183 bool HBasicBlock::Dominates(HBasicBlock* other) const { |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 UNREACHABLE(); | 279 UNREACHABLE(); |
| 286 return -1; | 280 return -1; |
| 287 } | 281 } |
| 288 | 282 |
| 289 | 283 |
| 290 #ifdef DEBUG | 284 #ifdef DEBUG |
| 291 void HBasicBlock::Verify() { | 285 void HBasicBlock::Verify() { |
| 292 // Check that every block is finished. | 286 // Check that every block is finished. |
| 293 ASSERT(IsFinished()); | 287 ASSERT(IsFinished()); |
| 294 ASSERT(block_id() >= 0); | 288 ASSERT(block_id() >= 0); |
| 295 | |
| 296 // Verify that all blocks targetting a branch target, have the same boolean | |
| 297 // value on top of their expression stack. | |
| 298 if (!cond().is_null()) { | |
| 299 ASSERT(predecessors()->length() > 0); | |
| 300 for (int i = 1; i < predecessors()->length(); i++) { | |
| 301 HBasicBlock* pred = predecessors()->at(i); | |
| 302 HValue* top = pred->last_environment()->Top(); | |
| 303 ASSERT(top->IsConstant()); | |
| 304 Object* a = *HConstant::cast(top)->handle(); | |
| 305 Object* b = *cond(); | |
| 306 ASSERT(a == b); | |
| 307 } | |
| 308 } | |
| 309 } | 289 } |
| 310 #endif | 290 #endif |
| 311 | 291 |
| 312 | 292 |
| 313 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { | 293 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { |
| 314 this->back_edges_.Add(block); | 294 this->back_edges_.Add(block); |
| 315 AddBlock(block); | 295 AddBlock(block); |
| 316 } | 296 } |
| 317 | 297 |
| 318 | 298 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 } | 477 } |
| 498 | 478 |
| 499 | 479 |
| 500 HConstant* HGraph::GetConstantFalse() { | 480 HConstant* HGraph::GetConstantFalse() { |
| 501 return GetConstant(&constant_false_, Heap::false_value()); | 481 return GetConstant(&constant_false_, Heap::false_value()); |
| 502 } | 482 } |
| 503 | 483 |
| 504 | 484 |
| 505 void HSubgraph::AppendOptional(HSubgraph* graph, | 485 void HSubgraph::AppendOptional(HSubgraph* graph, |
| 506 bool on_true_branch, | 486 bool on_true_branch, |
| 507 HValue* boolean_value) { | 487 HValue* value) { |
| 508 ASSERT(HasExit() && graph->HasExit()); | 488 ASSERT(HasExit() && graph->HasExit()); |
| 509 HBasicBlock* other_block = graph_->CreateBasicBlock(); | 489 HBasicBlock* other_block = graph_->CreateBasicBlock(); |
| 510 HBasicBlock* join_block = graph_->CreateBasicBlock(); | 490 HBasicBlock* join_block = graph_->CreateBasicBlock(); |
| 511 | 491 |
| 512 HBasicBlock* true_branch = other_block; | 492 HTest* test = on_true_branch |
| 513 HBasicBlock* false_branch = graph->entry_block(); | 493 ? new HTest(value, graph->entry_block(), other_block) |
| 514 if (on_true_branch) { | 494 : new HTest(value, other_block, graph->entry_block()); |
| 515 true_branch = graph->entry_block(); | 495 exit_block_->Finish(test); |
| 516 false_branch = other_block; | |
| 517 } | |
| 518 | |
| 519 exit_block_->Finish(new HBranch(true_branch, false_branch, boolean_value)); | |
| 520 other_block->Goto(join_block); | 496 other_block->Goto(join_block); |
| 521 graph->exit_block()->Goto(join_block); | 497 graph->exit_block()->Goto(join_block); |
| 522 exit_block_ = join_block; | 498 exit_block_ = join_block; |
| 523 } | 499 } |
| 524 | 500 |
| 525 | 501 |
| 526 void HSubgraph::AppendJoin(HSubgraph* then_graph, | 502 void HSubgraph::AppendJoin(HSubgraph* then_graph, |
| 527 HSubgraph* else_graph, | 503 HSubgraph* else_graph, |
| 528 AstNode* node) { | 504 AstNode* node) { |
| 529 if (then_graph->HasExit() && else_graph->HasExit()) { | 505 if (then_graph->HasExit() && else_graph->HasExit()) { |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 680 next_block_id_(0), | 656 next_block_id_(0), |
| 681 info_(info), | 657 info_(info), |
| 682 blocks_(8), | 658 blocks_(8), |
| 683 values_(16), | 659 values_(16), |
| 684 phi_list_(NULL) { | 660 phi_list_(NULL) { |
| 685 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); | 661 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); |
| 686 start_environment_->set_ast_id(info->function()->id()); | 662 start_environment_->set_ast_id(info->function()->id()); |
| 687 } | 663 } |
| 688 | 664 |
| 689 | 665 |
| 666 bool HGraph::AllowCodeMotion() const { |
| 667 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; |
| 668 } |
| 669 |
| 670 |
| 690 Handle<Code> HGraph::Compile() { | 671 Handle<Code> HGraph::Compile() { |
| 691 int values = GetMaximumValueID(); | 672 int values = GetMaximumValueID(); |
| 692 if (values > LAllocator::max_initial_value_ids()) { | 673 if (values > LAllocator::max_initial_value_ids()) { |
| 693 if (FLAG_trace_bailout) PrintF("Function is too big\n"); | 674 if (FLAG_trace_bailout) PrintF("Function is too big\n"); |
| 694 return Handle<Code>::null(); | 675 return Handle<Code>::null(); |
| 695 } | 676 } |
| 696 | 677 |
| 697 LAllocator allocator(values, this); | 678 LAllocator allocator(values, this); |
| 698 LChunkBuilder builder(this, &allocator); | 679 LChunkBuilder builder(this, &allocator); |
| 699 LChunk* chunk = builder.Build(); | 680 LChunk* chunk = builder.Build(); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 861 } | 842 } |
| 862 } | 843 } |
| 863 // Replace the uses and add phis modified to the work list. | 844 // Replace the uses and add phis modified to the work list. |
| 864 for (int i = 0; i < uses_to_replace.length(); ++i) { | 845 for (int i = 0; i < uses_to_replace.length(); ++i) { |
| 865 HValue* use = uses_to_replace[i]; | 846 HValue* use = uses_to_replace[i]; |
| 866 phi->ReplaceAtUse(use, value); | 847 phi->ReplaceAtUse(use, value); |
| 867 if (use->IsPhi()) worklist.Add(HPhi::cast(use)); | 848 if (use->IsPhi()) worklist.Add(HPhi::cast(use)); |
| 868 } | 849 } |
| 869 uses_to_replace.Rewind(0); | 850 uses_to_replace.Rewind(0); |
| 870 block->RemovePhi(phi); | 851 block->RemovePhi(phi); |
| 871 } else if (phi->HasNoUses() && | 852 } else if (FLAG_eliminate_dead_phis && phi->HasNoUses() && |
| 872 !phi->HasReceiverOperand() && | 853 !phi->IsReceiver()) { |
| 873 FLAG_eliminate_dead_phis) { | 854 // We can't eliminate phis in the receiver position in the environment |
| 874 // We can't eliminate phis that have the receiver as an operand | 855 // because in case of throwing an error we need this value to |
| 875 // because in case of throwing an error we need the correct | 856 // construct a stack trace. |
| 876 // receiver value in the environment to construct a corrent | |
| 877 // stack trace. | |
| 878 block->RemovePhi(phi); | 857 block->RemovePhi(phi); |
| 879 block->RecordDeletedPhi(phi->merged_index()); | 858 block->RecordDeletedPhi(phi->merged_index()); |
| 880 } | 859 } |
| 881 } | 860 } |
| 882 } | 861 } |
| 883 | 862 |
| 884 | 863 |
| 885 bool HGraph::CollectPhis() { | 864 bool HGraph::CollectPhis() { |
| 886 const ZoneList<HBasicBlock*>* blocks = graph_->blocks(); | 865 const ZoneList<HBasicBlock*>* blocks = graph_->blocks(); |
| 887 phi_list_ = new ZoneList<HPhi*>(blocks->length()); | 866 phi_list_ = new ZoneList<HPhi*>(blocks->length()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 922 | 901 |
| 923 class HRangeAnalysis BASE_EMBEDDED { | 902 class HRangeAnalysis BASE_EMBEDDED { |
| 924 public: | 903 public: |
| 925 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} | 904 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} |
| 926 | 905 |
| 927 void Analyze(); | 906 void Analyze(); |
| 928 | 907 |
| 929 private: | 908 private: |
| 930 void TraceRange(const char* msg, ...); | 909 void TraceRange(const char* msg, ...); |
| 931 void Analyze(HBasicBlock* block); | 910 void Analyze(HBasicBlock* block); |
| 932 void InferControlFlowRange(HBranch* branch, HBasicBlock* dest); | 911 void InferControlFlowRange(HTest* test, HBasicBlock* dest); |
| 933 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other); | 912 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other); |
| 934 void InferPhiRange(HPhi* phi); | 913 void InferPhiRange(HPhi* phi); |
| 935 void InferRange(HValue* value); | 914 void InferRange(HValue* value); |
| 936 void RollBackTo(int index); | 915 void RollBackTo(int index); |
| 937 void AddRange(HValue* value, Range* range); | 916 void AddRange(HValue* value, Range* range); |
| 938 | 917 |
| 939 HGraph* graph_; | 918 HGraph* graph_; |
| 940 ZoneList<HValue*> changed_ranges_; | 919 ZoneList<HValue*> changed_ranges_; |
| 941 }; | 920 }; |
| 942 | 921 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 958 | 937 |
| 959 | 938 |
| 960 void HRangeAnalysis::Analyze(HBasicBlock* block) { | 939 void HRangeAnalysis::Analyze(HBasicBlock* block) { |
| 961 TraceRange("Analyzing block B%d\n", block->block_id()); | 940 TraceRange("Analyzing block B%d\n", block->block_id()); |
| 962 | 941 |
| 963 int last_changed_range = changed_ranges_.length() - 1; | 942 int last_changed_range = changed_ranges_.length() - 1; |
| 964 | 943 |
| 965 // Infer range based on control flow. | 944 // Infer range based on control flow. |
| 966 if (block->predecessors()->length() == 1) { | 945 if (block->predecessors()->length() == 1) { |
| 967 HBasicBlock* pred = block->predecessors()->first(); | 946 HBasicBlock* pred = block->predecessors()->first(); |
| 968 if (pred->end()->IsBranch()) { | 947 if (pred->end()->IsTest()) { |
| 969 InferControlFlowRange(HBranch::cast(pred->end()), block); | 948 InferControlFlowRange(HTest::cast(pred->end()), block); |
| 970 } | 949 } |
| 971 } | 950 } |
| 972 | 951 |
| 973 // Process phi instructions. | 952 // Process phi instructions. |
| 974 for (int i = 0; i < block->phis()->length(); ++i) { | 953 for (int i = 0; i < block->phis()->length(); ++i) { |
| 975 HPhi* phi = block->phis()->at(i); | 954 HPhi* phi = block->phis()->at(i); |
| 976 InferPhiRange(phi); | 955 InferPhiRange(phi); |
| 977 } | 956 } |
| 978 | 957 |
| 979 // Go through all instructions of the current block. | 958 // Go through all instructions of the current block. |
| 980 HInstruction* instr = block->first(); | 959 HInstruction* instr = block->first(); |
| 981 while (instr != block->end()) { | 960 while (instr != block->end()) { |
| 982 InferRange(instr); | 961 InferRange(instr); |
| 983 instr = instr->next(); | 962 instr = instr->next(); |
| 984 } | 963 } |
| 985 | 964 |
| 986 // Continue analysis in all dominated blocks. | 965 // Continue analysis in all dominated blocks. |
| 987 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { | 966 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { |
| 988 Analyze(block->dominated_blocks()->at(i)); | 967 Analyze(block->dominated_blocks()->at(i)); |
| 989 } | 968 } |
| 990 | 969 |
| 991 RollBackTo(last_changed_range); | 970 RollBackTo(last_changed_range); |
| 992 } | 971 } |
| 993 | 972 |
| 994 | 973 |
| 995 void HRangeAnalysis::InferControlFlowRange(HBranch* branch, HBasicBlock* dest) { | 974 void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) { |
| 996 ASSERT(branch->FirstSuccessor() == dest || branch->SecondSuccessor() == dest); | 975 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); |
| 997 ASSERT(branch->FirstSuccessor() != dest || branch->SecondSuccessor() != dest); | 976 if (test->value()->IsCompare()) { |
| 998 | 977 HCompare* compare = HCompare::cast(test->value()); |
| 999 if (branch->value()->IsCompare()) { | |
| 1000 HCompare* compare = HCompare::cast(branch->value()); | |
| 1001 Token::Value op = compare->token(); | 978 Token::Value op = compare->token(); |
| 1002 if (branch->SecondSuccessor() == dest) { | 979 if (test->SecondSuccessor() == dest) { |
| 1003 op = Token::NegateCompareOp(op); | 980 op = Token::NegateCompareOp(op); |
| 1004 } | 981 } |
| 1005 Token::Value inverted_op = Token::InvertCompareOp(op); | 982 Token::Value inverted_op = Token::InvertCompareOp(op); |
| 1006 InferControlFlowRange(op, compare->left(), compare->right()); | 983 InferControlFlowRange(op, compare->left(), compare->right()); |
| 1007 InferControlFlowRange(inverted_op, compare->right(), compare->left()); | 984 InferControlFlowRange(inverted_op, compare->right(), compare->left()); |
| 1008 } | 985 } |
| 1009 } | 986 } |
| 1010 | 987 |
| 1011 | 988 |
| 1012 // We know that value [op] other. Use this information to update the range on | 989 // We know that value [op] other. Use this information to update the range on |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1439 TraceGVN("Found loop invariant instruction %d\n", instr->id()); | 1416 TraceGVN("Found loop invariant instruction %d\n", instr->id()); |
| 1440 // Move the instruction out of the loop. | 1417 // Move the instruction out of the loop. |
| 1441 instr->Unlink(); | 1418 instr->Unlink(); |
| 1442 instr->InsertBefore(pre_header->end()); | 1419 instr->InsertBefore(pre_header->end()); |
| 1443 } | 1420 } |
| 1444 } | 1421 } |
| 1445 instr = next; | 1422 instr = next; |
| 1446 } | 1423 } |
| 1447 } | 1424 } |
| 1448 | 1425 |
| 1449 // Only move instructions that postdominate the loop header (i.e. are | 1426 |
| 1450 // always executed inside the loop). This is to avoid unnecessary | |
| 1451 // deoptimizations assuming the loop is executed at least once. | |
| 1452 // TODO(fschneider): Better type feedback should give us information | |
| 1453 // about code that was never executed. | |
| 1454 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, | 1427 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, |
| 1455 HBasicBlock* loop_header) { | 1428 HBasicBlock* loop_header) { |
| 1456 if (!instr->IsChange() && | 1429 // If we've disabled code motion, don't move any instructions. |
| 1457 FLAG_aggressive_loop_invariant_motion) return true; | 1430 if (!graph_->AllowCodeMotion()) return false; |
| 1431 |
| 1432 // If --aggressive-loop-invariant-motion, move everything except change |
| 1433 // instructions. |
| 1434 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { |
| 1435 return true; |
| 1436 } |
| 1437 |
| 1438 // Otherwise only move instructions that postdominate the loop header |
| 1439 // (i.e. are always executed inside the loop). This is to avoid |
| 1440 // unnecessary deoptimizations assuming the loop is executed at least |
| 1441 // once. TODO(fschneider): Better type feedback should give us |
| 1442 // information about code that was never executed. |
| 1458 HBasicBlock* block = instr->block(); | 1443 HBasicBlock* block = instr->block(); |
| 1459 bool result = true; | 1444 bool result = true; |
| 1460 if (block != loop_header) { | 1445 if (block != loop_header) { |
| 1461 for (int i = 1; i < loop_header->predecessors()->length(); ++i) { | 1446 for (int i = 1; i < loop_header->predecessors()->length(); ++i) { |
| 1462 bool found = false; | 1447 bool found = false; |
| 1463 HBasicBlock* pred = loop_header->predecessors()->at(i); | 1448 HBasicBlock* pred = loop_header->predecessors()->at(i); |
| 1464 while (pred != loop_header) { | 1449 while (pred != loop_header) { |
| 1465 if (pred == block) found = true; | 1450 if (pred == block) found = true; |
| 1466 pred = pred->dominator(); | 1451 pred = pred->dominator(); |
| 1467 } | 1452 } |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1798 | 1783 |
| 1799 current = current->EnsureAndPropagateNotMinusZero(visited); | 1784 current = current->EnsureAndPropagateNotMinusZero(visited); |
| 1800 } | 1785 } |
| 1801 } | 1786 } |
| 1802 | 1787 |
| 1803 | 1788 |
| 1804 void HGraph::InsertRepresentationChangeForUse(HValue* value, | 1789 void HGraph::InsertRepresentationChangeForUse(HValue* value, |
| 1805 HValue* use, | 1790 HValue* use, |
| 1806 Representation to, | 1791 Representation to, |
| 1807 bool is_truncating) { | 1792 bool is_truncating) { |
| 1808 // Propagate flags for negative zero checks upwards from conversions | |
| 1809 // int32-to-tagged and int32-to-double. | |
| 1810 Representation from = value->representation(); | |
| 1811 if (from.IsInteger32()) { | |
| 1812 ASSERT(to.IsTagged() || to.IsDouble()); | |
| 1813 BitVector visited(GetMaximumValueID()); | |
| 1814 PropagateMinusZeroChecks(value, &visited); | |
| 1815 } | |
| 1816 | |
| 1817 // Insert the representation change right before its use. For phi-uses we | 1793 // Insert the representation change right before its use. For phi-uses we |
| 1818 // insert at the end of the corresponding predecessor. | 1794 // insert at the end of the corresponding predecessor. |
| 1819 HBasicBlock* insert_block = use->block(); | 1795 HInstruction* next = NULL; |
| 1820 if (use->IsPhi()) { | 1796 if (use->IsPhi()) { |
| 1821 int index = 0; | 1797 int index = 0; |
| 1822 while (use->OperandAt(index) != value) ++index; | 1798 while (use->OperandAt(index) != value) ++index; |
| 1823 insert_block = insert_block->predecessors()->at(index); | 1799 next = use->block()->predecessors()->at(index)->end(); |
| 1800 } else { |
| 1801 next = HInstruction::cast(use); |
| 1824 } | 1802 } |
| 1825 | 1803 |
| 1826 HInstruction* next = (insert_block == use->block()) | |
| 1827 ? HInstruction::cast(use) | |
| 1828 : insert_block->end(); | |
| 1829 | |
| 1830 // For constants we try to make the representation change at compile | 1804 // For constants we try to make the representation change at compile |
| 1831 // time. When a representation change is not possible without loss of | 1805 // time. When a representation change is not possible without loss of |
| 1832 // information we treat constants like normal instructions and insert the | 1806 // information we treat constants like normal instructions and insert the |
| 1833 // change instructions for them. | 1807 // change instructions for them. |
| 1834 HInstruction* new_value = NULL; | 1808 HInstruction* new_value = NULL; |
| 1835 if (value->IsConstant()) { | 1809 if (value->IsConstant()) { |
| 1836 HConstant* constant = HConstant::cast(value); | 1810 HConstant* constant = HConstant::cast(value); |
| 1837 // Try to create a new copy of the constant with the new representation. | 1811 // Try to create a new copy of the constant with the new representation. |
| 1838 new_value = is_truncating | 1812 new_value = is_truncating |
| 1839 ? constant->CopyToTruncatedInt32() | 1813 ? constant->CopyToTruncatedInt32() |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1969 // Process normal instructions. | 1943 // Process normal instructions. |
| 1970 HInstruction* current = blocks_[i]->first(); | 1944 HInstruction* current = blocks_[i]->first(); |
| 1971 while (current != NULL) { | 1945 while (current != NULL) { |
| 1972 InsertRepresentationChanges(current); | 1946 InsertRepresentationChanges(current); |
| 1973 current = current->next(); | 1947 current = current->next(); |
| 1974 } | 1948 } |
| 1975 } | 1949 } |
| 1976 } | 1950 } |
| 1977 | 1951 |
| 1978 | 1952 |
| 1953 void HGraph::ComputeMinusZeroChecks() { |
| 1954 BitVector visited(GetMaximumValueID()); |
| 1955 for (int i = 0; i < blocks_.length(); ++i) { |
| 1956 for (HInstruction* current = blocks_[i]->first(); |
| 1957 current != NULL; |
| 1958 current = current->next()) { |
| 1959 if (current->IsChange()) { |
| 1960 HChange* change = HChange::cast(current); |
| 1961 // Propagate flags for negative zero checks upwards from conversions |
| 1962 // int32-to-tagged and int32-to-double. |
| 1963 Representation from = change->value()->representation(); |
| 1964 ASSERT(from.Equals(change->from())); |
| 1965 if (from.IsInteger32()) { |
| 1966 ASSERT(change->to().IsTagged() || change->to().IsDouble()); |
| 1967 ASSERT(visited.IsEmpty()); |
| 1968 PropagateMinusZeroChecks(change->value(), &visited); |
| 1969 visited.Clear(); |
| 1970 } |
| 1971 } |
| 1972 } |
| 1973 } |
| 1974 } |
| 1975 |
| 1976 |
| 1979 // Implementation of utility classes to represent an expression's context in | 1977 // Implementation of utility classes to represent an expression's context in |
| 1980 // the AST. | 1978 // the AST. |
| 1981 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 1979 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
| 1982 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { | 1980 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { |
| 1983 owner->set_ast_context(this); // Push. | 1981 owner->set_ast_context(this); // Push. |
| 1984 #ifdef DEBUG | 1982 #ifdef DEBUG |
| 1985 original_length_ = owner->environment()->length(); | 1983 original_length_ = owner->environment()->length(); |
| 1986 #endif | 1984 #endif |
| 1987 } | 1985 } |
| 1988 | 1986 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2051 | 2049 |
| 2052 | 2050 |
| 2053 void TestContext::BuildBranch(HValue* value) { | 2051 void TestContext::BuildBranch(HValue* value) { |
| 2054 // We expect the graph to be in edge-split form: there is no edge that | 2052 // We expect the graph to be in edge-split form: there is no edge that |
| 2055 // connects a branch node to a join node. We conservatively ensure that | 2053 // connects a branch node to a join node. We conservatively ensure that |
| 2056 // property by always adding an empty block on the outgoing edges of this | 2054 // property by always adding an empty block on the outgoing edges of this |
| 2057 // branch. | 2055 // branch. |
| 2058 HGraphBuilder* builder = owner(); | 2056 HGraphBuilder* builder = owner(); |
| 2059 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2057 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2060 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2058 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2061 HBranch* branch = new HBranch(empty_true, empty_false, value); | 2059 HTest* test = new HTest(value, empty_true, empty_false); |
| 2062 builder->CurrentBlock()->Finish(branch); | 2060 builder->CurrentBlock()->Finish(test); |
| 2063 | 2061 |
| 2064 HValue* const no_return_value = NULL; | 2062 HValue* const no_return_value = NULL; |
| 2065 HBasicBlock* true_target = if_true(); | 2063 HBasicBlock* true_target = if_true(); |
| 2066 if (true_target->IsInlineReturnTarget()) { | 2064 if (true_target->IsInlineReturnTarget()) { |
| 2067 empty_true->AddLeaveInlined(no_return_value, true_target); | 2065 empty_true->AddLeaveInlined(no_return_value, true_target); |
| 2068 } else { | 2066 } else { |
| 2069 empty_true->Goto(true_target); | 2067 empty_true->Goto(true_target); |
| 2070 } | 2068 } |
| 2071 | 2069 |
| 2072 HBasicBlock* false_target = if_false(); | 2070 HBasicBlock* false_target = if_false(); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2167 | 2165 |
| 2168 | 2166 |
| 2169 void HGraphBuilder::VisitForControl(Expression* expr, | 2167 void HGraphBuilder::VisitForControl(Expression* expr, |
| 2170 HBasicBlock* true_block, | 2168 HBasicBlock* true_block, |
| 2171 HBasicBlock* false_block) { | 2169 HBasicBlock* false_block) { |
| 2172 TestContext for_test(this, true_block, false_block); | 2170 TestContext for_test(this, true_block, false_block); |
| 2173 Visit(expr); | 2171 Visit(expr); |
| 2174 } | 2172 } |
| 2175 | 2173 |
| 2176 | 2174 |
| 2177 HValue* HGraphBuilder::VisitArgument(Expression* expr) { | 2175 void HGraphBuilder::VisitArgument(Expression* expr) { |
| 2178 VisitForValue(expr); | 2176 VisitForValue(expr); |
| 2179 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; | |
| 2180 return environment()->Top(); | |
| 2181 } | 2177 } |
| 2182 | 2178 |
| 2183 | 2179 |
| 2184 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { | 2180 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { |
| 2185 for (int i = 0; i < arguments->length(); i++) { | 2181 for (int i = 0; i < arguments->length(); i++) { |
| 2186 VisitArgument(arguments->at(i)); | 2182 VisitArgument(arguments->at(i)); |
| 2187 if (HasStackOverflow() || !current_subgraph_->HasExit()) return; | 2183 if (HasStackOverflow() || !current_subgraph_->HasExit()) return; |
| 2188 } | 2184 } |
| 2189 } | 2185 } |
| 2190 | 2186 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2228 rep.Analyze(); | 2224 rep.Analyze(); |
| 2229 | 2225 |
| 2230 if (FLAG_use_range) { | 2226 if (FLAG_use_range) { |
| 2231 HRangeAnalysis rangeAnalysis(graph_); | 2227 HRangeAnalysis rangeAnalysis(graph_); |
| 2232 rangeAnalysis.Analyze(); | 2228 rangeAnalysis.Analyze(); |
| 2233 } | 2229 } |
| 2234 | 2230 |
| 2235 graph_->InitializeInferredTypes(); | 2231 graph_->InitializeInferredTypes(); |
| 2236 graph_->Canonicalize(); | 2232 graph_->Canonicalize(); |
| 2237 graph_->InsertRepresentationChanges(); | 2233 graph_->InsertRepresentationChanges(); |
| 2234 graph_->ComputeMinusZeroChecks(); |
| 2238 | 2235 |
| 2239 // Eliminate redundant stack checks on backwards branches. | 2236 // Eliminate redundant stack checks on backwards branches. |
| 2240 HStackCheckEliminator sce(graph_); | 2237 HStackCheckEliminator sce(graph_); |
| 2241 sce.Process(); | 2238 sce.Process(); |
| 2242 | 2239 |
| 2243 // Perform common subexpression elimination and loop-invariant code motion. | 2240 // Perform common subexpression elimination and loop-invariant code motion. |
| 2244 if (FLAG_use_gvn) { | 2241 if (FLAG_use_gvn) { |
| 2245 HPhase phase("Global value numbering", graph_); | 2242 HPhase phase("Global value numbering", graph_); |
| 2246 HGlobalValueNumberer gvn(graph_); | 2243 HGlobalValueNumberer gvn(graph_); |
| 2247 gvn.Analyze(); | 2244 gvn.Analyze(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2288 current_subgraph_->exit_block()->AddPhi(instr); | 2285 current_subgraph_->exit_block()->AddPhi(instr); |
| 2289 } | 2286 } |
| 2290 | 2287 |
| 2291 | 2288 |
| 2292 void HGraphBuilder::PushAndAdd(HInstruction* instr) { | 2289 void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
| 2293 Push(instr); | 2290 Push(instr); |
| 2294 AddInstruction(instr); | 2291 AddInstruction(instr); |
| 2295 } | 2292 } |
| 2296 | 2293 |
| 2297 | 2294 |
| 2298 void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { | 2295 void HGraphBuilder::PreProcessCall(HCall* call) { |
| 2299 const int kMaxStubArguments = 4; | 2296 int count = call->argument_count(); |
| 2300 ASSERT_GE(kMaxStubArguments, argument_count); | 2297 ZoneList<HValue*> arguments(count); |
| 2301 // Push the arguments on the stack. | 2298 for (int i = 0; i < count; ++i) { |
| 2302 HValue* arguments[kMaxStubArguments]; | 2299 arguments.Add(Pop()); |
| 2303 for (int i = argument_count - 1; i >= 0; i--) { | |
| 2304 arguments[i] = Pop(); | |
| 2305 } | 2300 } |
| 2306 for (int i = 0; i < argument_count; i++) { | 2301 |
| 2307 AddInstruction(new HPushArgument(arguments[i])); | 2302 while (!arguments.is_empty()) { |
| 2303 AddInstruction(new HPushArgument(arguments.RemoveLast())); |
| 2308 } | 2304 } |
| 2309 } | 2305 } |
| 2310 | 2306 |
| 2311 | 2307 |
| 2312 void HGraphBuilder::ProcessCall(HCall* call) { | |
| 2313 for (int i = call->argument_count() - 1; i >= 0; --i) { | |
| 2314 HValue* value = Pop(); | |
| 2315 HPushArgument* push = new HPushArgument(value); | |
| 2316 call->SetArgumentAt(i, push); | |
| 2317 } | |
| 2318 | |
| 2319 for (int i = 0; i < call->argument_count(); ++i) { | |
| 2320 AddInstruction(call->PushArgumentAt(i)); | |
| 2321 } | |
| 2322 } | |
| 2323 | |
| 2324 | |
| 2325 void HGraphBuilder::SetupScope(Scope* scope) { | 2308 void HGraphBuilder::SetupScope(Scope* scope) { |
| 2326 // We don't yet handle the function name for named function expressions. | 2309 // We don't yet handle the function name for named function expressions. |
| 2327 if (scope->function() != NULL) BAILOUT("named function expression"); | 2310 if (scope->function() != NULL) BAILOUT("named function expression"); |
| 2328 | 2311 |
| 2329 // We can't handle heap-allocated locals. | 2312 // We can't handle heap-allocated locals. |
| 2330 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); | 2313 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); |
| 2331 | 2314 |
| 2332 HConstant* undefined_constant = | 2315 HConstant* undefined_constant = |
| 2333 new HConstant(Factory::undefined_value(), Representation::Tagged()); | 2316 new HConstant(Factory::undefined_value(), Representation::Tagged()); |
| 2334 AddInstruction(undefined_constant); | 2317 AddInstruction(undefined_constant); |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2580 CaseClause* clause = clauses->at(i); | 2563 CaseClause* clause = clauses->at(i); |
| 2581 if (clause->is_default()) continue; | 2564 if (clause->is_default()) continue; |
| 2582 | 2565 |
| 2583 // Finish the previous graph by connecting it to the current. | 2566 // Finish the previous graph by connecting it to the current. |
| 2584 HSubgraph* subgraph = compare_graphs.at(i); | 2567 HSubgraph* subgraph = compare_graphs.at(i); |
| 2585 if (prev_compare_inst == NULL) { | 2568 if (prev_compare_inst == NULL) { |
| 2586 ASSERT(prev_graph == current_subgraph_); | 2569 ASSERT(prev_graph == current_subgraph_); |
| 2587 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | 2570 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); |
| 2588 } else { | 2571 } else { |
| 2589 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2572 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2590 prev_graph->exit_block()->Finish(new HBranch(empty, | 2573 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, |
| 2591 subgraph->entry_block(), | 2574 empty, |
| 2592 prev_compare_inst)); | 2575 subgraph->entry_block())); |
| 2593 } | 2576 } |
| 2594 | 2577 |
| 2595 // Build instructions for current subgraph. | 2578 // Build instructions for current subgraph. |
| 2596 ASSERT(clause->IsSmiCompare()); | 2579 ASSERT(clause->IsSmiCompare()); |
| 2597 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | 2580 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); |
| 2598 if (HasStackOverflow()) return; | 2581 if (HasStackOverflow()) return; |
| 2599 | 2582 |
| 2600 prev_graph = subgraph; | 2583 prev_graph = subgraph; |
| 2601 } | 2584 } |
| 2602 | 2585 |
| 2603 // Finish last comparison if there was at least one comparison. | 2586 // Finish last comparison if there was at least one comparison. |
| 2604 // last_false_block is the (empty) false-block of the last comparison. If | 2587 // last_false_block is the (empty) false-block of the last comparison. If |
| 2605 // there are no comparisons at all (a single default clause), it is just | 2588 // there are no comparisons at all (a single default clause), it is just |
| 2606 // the last block of the current subgraph. | 2589 // the last block of the current subgraph. |
| 2607 HBasicBlock* last_false_block = current_subgraph_->exit_block(); | 2590 HBasicBlock* last_false_block = current_subgraph_->exit_block(); |
| 2608 if (prev_graph != current_subgraph_) { | 2591 if (prev_graph != current_subgraph_) { |
| 2609 last_false_block = graph()->CreateBasicBlock(); | 2592 last_false_block = graph()->CreateBasicBlock(); |
| 2610 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2593 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2611 prev_graph->exit_block()->Finish(new HBranch(empty, | 2594 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst, |
| 2612 last_false_block, | 2595 empty, |
| 2613 prev_compare_inst)); | 2596 last_false_block)); |
| 2614 } | 2597 } |
| 2615 | 2598 |
| 2616 // If we have a non-smi compare clause, we deoptimize after trying | 2599 // If we have a non-smi compare clause, we deoptimize after trying |
| 2617 // all the previous compares. | 2600 // all the previous compares. |
| 2618 if (num_smi_clauses < num_clauses) { | 2601 if (num_smi_clauses < num_clauses) { |
| 2619 last_false_block->Finish(new HDeoptimize); | 2602 last_false_block->Finish(new HDeoptimize); |
| 2620 } | 2603 } |
| 2621 | 2604 |
| 2622 // Build statement blocks, connect them to their comparison block and | 2605 // Build statement blocks, connect them to their comparison block and |
| 2623 // to the previous statement block, if there is a fall-through. | 2606 // to the previous statement block, if there is a fall-through. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2686 return statement->OsrEntryId() == info()->osr_ast_id(); | 2669 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2687 } | 2670 } |
| 2688 | 2671 |
| 2689 | 2672 |
| 2690 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { | 2673 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) { |
| 2691 if (!graph()->HasOsrEntryAt(statement)) return; | 2674 if (!graph()->HasOsrEntryAt(statement)) return; |
| 2692 | 2675 |
| 2693 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2676 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2694 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2677 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 2695 HValue* true_value = graph()->GetConstantTrue(); | 2678 HValue* true_value = graph()->GetConstantTrue(); |
| 2696 HBranch* branch = new HBranch(non_osr_entry, osr_entry, true_value); | 2679 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); |
| 2697 exit_block()->Finish(branch); | 2680 exit_block()->Finish(test); |
| 2698 | 2681 |
| 2699 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2682 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2700 non_osr_entry->Goto(loop_predecessor); | 2683 non_osr_entry->Goto(loop_predecessor); |
| 2701 | 2684 |
| 2702 int osr_entry_id = statement->OsrEntryId(); | 2685 int osr_entry_id = statement->OsrEntryId(); |
| 2703 // We want the correct environment at the OsrEntry instruction. Build | 2686 // We want the correct environment at the OsrEntry instruction. Build |
| 2704 // it explicitly. The expression stack should be empty. | 2687 // it explicitly. The expression stack should be empty. |
| 2705 int count = osr_entry->last_environment()->length(); | 2688 int count = osr_entry->last_environment()->length(); |
| 2706 ASSERT(count == (osr_entry->last_environment()->parameter_count() + | 2689 ASSERT(count == (osr_entry->last_environment()->parameter_count() + |
| 2707 osr_entry->last_environment()->local_count())); | 2690 osr_entry->last_environment()->local_count())); |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2921 global->Lookup(*var->name(), lookup); | 2904 global->Lookup(*var->name(), lookup); |
| 2922 if (!lookup->IsProperty()) { | 2905 if (!lookup->IsProperty()) { |
| 2923 BAILOUT("global variable cell not yet introduced"); | 2906 BAILOUT("global variable cell not yet introduced"); |
| 2924 } | 2907 } |
| 2925 if (lookup->type() != NORMAL) { | 2908 if (lookup->type() != NORMAL) { |
| 2926 BAILOUT("global variable has accessors"); | 2909 BAILOUT("global variable has accessors"); |
| 2927 } | 2910 } |
| 2928 if (is_store && lookup->IsReadOnly()) { | 2911 if (is_store && lookup->IsReadOnly()) { |
| 2929 BAILOUT("read-only global variable"); | 2912 BAILOUT("read-only global variable"); |
| 2930 } | 2913 } |
| 2914 if (lookup->holder() != *global) { |
| 2915 BAILOUT("global property on prototype of global object"); |
| 2916 } |
| 2917 } |
| 2918 |
| 2919 |
| 2920 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { |
| 2921 ASSERT(var->IsContextSlot()); |
| 2922 HInstruction* context = new HContext; |
| 2923 AddInstruction(context); |
| 2924 int length = graph()->info()->scope()->ContextChainLength(var->scope()); |
| 2925 while (length-- > 0) { |
| 2926 context = new HOuterContext(context); |
| 2927 AddInstruction(context); |
| 2928 } |
| 2929 return context; |
| 2931 } | 2930 } |
| 2932 | 2931 |
| 2933 | 2932 |
| 2934 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 2933 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2935 Variable* variable = expr->AsVariable(); | 2934 Variable* variable = expr->AsVariable(); |
| 2936 if (variable == NULL) { | 2935 if (variable == NULL) { |
| 2937 BAILOUT("reference to rewritten variable"); | 2936 BAILOUT("reference to rewritten variable"); |
| 2938 } else if (variable->IsStackAllocated()) { | 2937 } else if (variable->IsStackAllocated()) { |
| 2939 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { | 2938 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { |
| 2940 BAILOUT("unsupported context for arguments object"); | 2939 BAILOUT("unsupported context for arguments object"); |
| 2941 } | 2940 } |
| 2942 ast_context()->ReturnValue(environment()->Lookup(variable)); | 2941 ast_context()->ReturnValue(environment()->Lookup(variable)); |
| 2942 } else if (variable->IsContextSlot()) { |
| 2943 if (variable->mode() == Variable::CONST) { |
| 2944 BAILOUT("reference to const context slot"); |
| 2945 } |
| 2946 HValue* context = BuildContextChainWalk(variable); |
| 2947 int index = variable->AsSlot()->index(); |
| 2948 HLoadContextSlot* instr = new HLoadContextSlot(context, index); |
| 2949 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2943 } else if (variable->is_global()) { | 2950 } else if (variable->is_global()) { |
| 2944 LookupResult lookup; | 2951 LookupResult lookup; |
| 2945 LookupGlobalPropertyCell(variable, &lookup, false); | 2952 LookupGlobalPropertyCell(variable, &lookup, false); |
| 2946 CHECK_BAILOUT; | 2953 CHECK_BAILOUT; |
| 2947 | 2954 |
| 2948 Handle<GlobalObject> global(graph()->info()->global_object()); | 2955 Handle<GlobalObject> global(graph()->info()->global_object()); |
| 2949 // TODO(3039103): Handle global property load through an IC call when access | 2956 // TODO(3039103): Handle global property load through an IC call when access |
| 2950 // checks are enabled. | 2957 // checks are enabled. |
| 2951 if (global->IsAccessCheckNeeded()) { | 2958 if (global->IsAccessCheckNeeded()) { |
| 2952 BAILOUT("global object requires access check"); | 2959 BAILOUT("global object requires access check"); |
| 2953 } | 2960 } |
| 2954 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 2961 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 2955 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 2962 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 2956 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); | 2963 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); |
| 2957 ast_context()->ReturnInstruction(instr, expr->id()); | 2964 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2958 } else { | 2965 } else { |
| 2959 BAILOUT("reference to non-stack-allocated/non-global variable"); | 2966 BAILOUT("reference to a variable which requires dynamic lookup"); |
| 2960 } | 2967 } |
| 2961 } | 2968 } |
| 2962 | 2969 |
| 2963 | 2970 |
| 2964 void HGraphBuilder::VisitLiteral(Literal* expr) { | 2971 void HGraphBuilder::VisitLiteral(Literal* expr) { |
| 2965 HConstant* instr = new HConstant(expr->handle(), Representation::Tagged()); | 2972 HConstant* instr = new HConstant(expr->handle(), Representation::Tagged()); |
| 2966 ast_context()->ReturnInstruction(instr, expr->id()); | 2973 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2967 } | 2974 } |
| 2968 | 2975 |
| 2969 | 2976 |
| 2970 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { | 2977 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 2971 HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(), | 2978 HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(), |
| 2972 expr->flags(), | 2979 expr->flags(), |
| 2973 expr->literal_index()); | 2980 expr->literal_index()); |
| 2974 ast_context()->ReturnInstruction(instr, expr->id()); | 2981 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2975 } | 2982 } |
| 2976 | 2983 |
| 2977 | 2984 |
| 2978 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | 2985 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 2979 HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(), | 2986 HContext* context = new HContext; |
| 2987 AddInstruction(context); |
| 2988 HObjectLiteral* literal = (new HObjectLiteral(context, |
| 2989 expr->constant_properties(), |
| 2980 expr->fast_elements(), | 2990 expr->fast_elements(), |
| 2981 expr->literal_index(), | 2991 expr->literal_index(), |
| 2982 expr->depth())); | 2992 expr->depth())); |
| 2983 // The object is expected in the bailout environment during computation | 2993 // The object is expected in the bailout environment during computation |
| 2984 // of the property values and is the value of the entire expression. | 2994 // of the property values and is the value of the entire expression. |
| 2985 PushAndAdd(literal); | 2995 PushAndAdd(literal); |
| 2986 | 2996 |
| 2987 expr->CalculateEmitStore(); | 2997 expr->CalculateEmitStore(); |
| 2988 | 2998 |
| 2989 for (int i = 0; i < expr->properties()->length(); i++) { | 2999 for (int i = 0; i < expr->properties()->length(); i++) { |
| 2990 ObjectLiteral::Property* property = expr->properties()->at(i); | 3000 ObjectLiteral::Property* property = expr->properties()->at(i); |
| 2991 if (property->IsCompileTimeValue()) continue; | 3001 if (property->IsCompileTimeValue()) continue; |
| 2992 | 3002 |
| 2993 Literal* key = property->key(); | 3003 Literal* key = property->key(); |
| 2994 Expression* value = property->value(); | 3004 Expression* value = property->value(); |
| 2995 | 3005 |
| 2996 switch (property->kind()) { | 3006 switch (property->kind()) { |
| 2997 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 3007 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 2998 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 3008 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 2999 // Fall through. | 3009 // Fall through. |
| 3000 case ObjectLiteral::Property::COMPUTED: | 3010 case ObjectLiteral::Property::COMPUTED: |
| 3001 if (key->handle()->IsSymbol()) { | 3011 if (key->handle()->IsSymbol()) { |
| 3002 if (property->emit_store()) { | 3012 if (property->emit_store()) { |
| 3003 VISIT_FOR_VALUE(value); | 3013 VISIT_FOR_VALUE(value); |
| 3004 HValue* value = Pop(); | 3014 HValue* value = Pop(); |
| 3005 Handle<String> name = Handle<String>::cast(key->handle()); | 3015 Handle<String> name = Handle<String>::cast(key->handle()); |
| 3006 AddInstruction(new HStoreNamedGeneric(literal, name, value)); | 3016 HStoreNamedGeneric* store = |
| 3017 new HStoreNamedGeneric(context, literal, name, value); |
| 3018 AddInstruction(store); |
| 3007 AddSimulate(key->id()); | 3019 AddSimulate(key->id()); |
| 3008 } else { | 3020 } else { |
| 3009 VISIT_FOR_EFFECT(value); | 3021 VISIT_FOR_EFFECT(value); |
| 3010 } | 3022 } |
| 3011 break; | 3023 break; |
| 3012 } | 3024 } |
| 3013 // Fall through. | 3025 // Fall through. |
| 3014 case ObjectLiteral::Property::PROTOTYPE: | 3026 case ObjectLiteral::Property::PROTOTYPE: |
| 3015 case ObjectLiteral::Property::SETTER: | 3027 case ObjectLiteral::Property::SETTER: |
| 3016 case ObjectLiteral::Property::GETTER: | 3028 case ObjectLiteral::Property::GETTER: |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3059 } | 3071 } |
| 3060 ast_context()->ReturnValue(Pop()); | 3072 ast_context()->ReturnValue(Pop()); |
| 3061 } | 3073 } |
| 3062 | 3074 |
| 3063 | 3075 |
| 3064 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 3076 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 3065 BAILOUT("CatchExtensionObject"); | 3077 BAILOUT("CatchExtensionObject"); |
| 3066 } | 3078 } |
| 3067 | 3079 |
| 3068 | 3080 |
| 3069 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, | 3081 HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver, |
| 3070 ZoneList<HSubgraph*>* subgraphs, | 3082 ZoneMapList* maps, |
| 3071 HValue* receiver, | 3083 ZoneList<HSubgraph*>* body_graphs, |
| 3084 HSubgraph* default_graph, |
| 3072 int join_id) { | 3085 int join_id) { |
| 3073 ASSERT(subgraphs->length() == (maps->length() + 1)); | 3086 ASSERT(maps->length() == body_graphs->length()); |
| 3087 HBasicBlock* join_block = graph()->CreateBasicBlock(); |
| 3088 AddInstruction(new HCheckNonSmi(receiver)); |
| 3074 | 3089 |
| 3075 // Build map compare subgraphs for all but the first map. | 3090 for (int i = 0; i < maps->length(); ++i) { |
| 3076 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1); | 3091 // Build the branches, connect all the target subgraphs to the join |
| 3077 for (int i = maps->length() - 1; i > 0; --i) { | 3092 // block. Use the default as a target of the last branch. |
| 3078 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3093 HSubgraph* if_true = body_graphs->at(i); |
| 3079 SubgraphScope scope(this, subgraph); | 3094 HSubgraph* if_false = (i == maps->length() - 1) |
| 3080 HSubgraph* else_subgraph = | 3095 ? default_graph |
| 3081 (i == (maps->length() - 1)) | 3096 : CreateBranchSubgraph(environment()); |
| 3082 ? subgraphs->last() | 3097 HCompareMap* compare = |
| 3083 : map_compare_subgraphs.last(); | 3098 new HCompareMap(receiver, |
| 3084 current_subgraph_->exit_block()->Finish( | 3099 maps->at(i), |
| 3085 new HCompareMapAndBranch(receiver, | 3100 if_true->entry_block(), |
| 3086 maps->at(i), | 3101 if_false->entry_block()); |
| 3087 subgraphs->at(i)->entry_block(), | 3102 subgraph()->exit_block()->Finish(compare); |
| 3088 else_subgraph->entry_block())); | 3103 |
| 3089 map_compare_subgraphs.Add(subgraph); | 3104 if (if_true->HasExit()) { |
| 3105 // In an effect context the value of the type switch is not needed. |
| 3106 // There is no need to merge it at the join block only to discard it. |
| 3107 if (ast_context()->IsEffect()) { |
| 3108 if_true->exit_block()->last_environment()->Drop(1); |
| 3109 } |
| 3110 if_true->exit_block()->Goto(join_block); |
| 3111 } |
| 3112 |
| 3113 subgraph()->set_exit_block(if_false->exit_block()); |
| 3090 } | 3114 } |
| 3091 | 3115 |
| 3092 // Generate first map check to end the current block. | 3116 // Connect the default if necessary. |
| 3093 AddInstruction(new HCheckNonSmi(receiver)); | 3117 if (subgraph()->HasExit()) { |
| 3094 HSubgraph* else_subgraph = | 3118 if (ast_context()->IsEffect()) { |
| 3095 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last(); | 3119 environment()->Drop(1); |
| 3096 current_subgraph_->exit_block()->Finish( | |
| 3097 new HCompareMapAndBranch(receiver, | |
| 3098 Handle<Map>(maps->first()), | |
| 3099 subgraphs->first()->entry_block(), | |
| 3100 else_subgraph->entry_block())); | |
| 3101 | |
| 3102 // Join all the call subgraphs in a new basic block and make | |
| 3103 // this basic block the current basic block. | |
| 3104 HBasicBlock* join_block = graph_->CreateBasicBlock(); | |
| 3105 for (int i = 0; i < subgraphs->length(); ++i) { | |
| 3106 if (subgraphs->at(i)->HasExit()) { | |
| 3107 subgraphs->at(i)->exit_block()->Goto(join_block); | |
| 3108 } | 3120 } |
| 3121 subgraph()->exit_block()->Goto(join_block); |
| 3109 } | 3122 } |
| 3110 | 3123 |
| 3111 if (join_block->predecessors()->is_empty()) return NULL; | 3124 if (join_block->predecessors()->is_empty()) return NULL; |
| 3112 join_block->SetJoinId(join_id); | 3125 join_block->SetJoinId(join_id); |
| 3113 return join_block; | 3126 return join_block; |
| 3114 } | 3127 } |
| 3115 | 3128 |
| 3116 | 3129 |
| 3117 // Sets the lookup result and returns true if the store can be inlined. | 3130 // Sets the lookup result and returns true if the store can be inlined. |
| 3118 static bool ComputeStoredField(Handle<Map> type, | 3131 static bool ComputeStoredField(Handle<Map> type, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3169 // enable elimination of redundant checks after the transition store. | 3182 // enable elimination of redundant checks after the transition store. |
| 3170 instr->SetFlag(HValue::kChangesMaps); | 3183 instr->SetFlag(HValue::kChangesMaps); |
| 3171 } | 3184 } |
| 3172 return instr; | 3185 return instr; |
| 3173 } | 3186 } |
| 3174 | 3187 |
| 3175 | 3188 |
| 3176 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, | 3189 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, |
| 3177 Handle<String> name, | 3190 Handle<String> name, |
| 3178 HValue* value) { | 3191 HValue* value) { |
| 3179 return new HStoreNamedGeneric(object, name, value); | 3192 HContext* context = new HContext; |
| 3193 AddInstruction(context); |
| 3194 return new HStoreNamedGeneric(context, object, name, value); |
| 3180 } | 3195 } |
| 3181 | 3196 |
| 3182 | 3197 |
| 3183 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, | 3198 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, |
| 3184 HValue* value, | 3199 HValue* value, |
| 3185 Expression* expr) { | 3200 Expression* expr) { |
| 3186 Property* prop = (expr->AsProperty() != NULL) | 3201 Property* prop = (expr->AsProperty() != NULL) |
| 3187 ? expr->AsProperty() | 3202 ? expr->AsProperty() |
| 3188 : expr->AsAssignment()->target()->AsProperty(); | 3203 : expr->AsAssignment()->target()->AsProperty(); |
| 3189 Literal* key = prop->key()->AsLiteral(); | 3204 Literal* key = prop->key()->AsLiteral(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3202 } | 3217 } |
| 3203 | 3218 |
| 3204 | 3219 |
| 3205 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, | 3220 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
| 3206 HValue* object, | 3221 HValue* object, |
| 3207 HValue* value, | 3222 HValue* value, |
| 3208 ZoneMapList* types, | 3223 ZoneMapList* types, |
| 3209 Handle<String> name) { | 3224 Handle<String> name) { |
| 3210 int number_of_types = Min(types->length(), kMaxStorePolymorphism); | 3225 int number_of_types = Min(types->length(), kMaxStorePolymorphism); |
| 3211 ZoneMapList maps(number_of_types); | 3226 ZoneMapList maps(number_of_types); |
| 3212 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3227 ZoneList<HSubgraph*> subgraphs(number_of_types); |
| 3213 bool needs_generic = (types->length() > kMaxStorePolymorphism); | 3228 bool needs_generic = (types->length() > kMaxStorePolymorphism); |
| 3214 | 3229 |
| 3215 // Build subgraphs for each of the specific maps. | 3230 // Build subgraphs for each of the specific maps. |
| 3216 // | 3231 // |
| 3217 // TODO(ager): We should recognize when the prototype chains for | 3232 // TODO(ager): We should recognize when the prototype chains for |
| 3218 // different maps are identical. In that case we can avoid | 3233 // different maps are identical. In that case we can avoid |
| 3219 // repeatedly generating the same prototype map checks. | 3234 // repeatedly generating the same prototype map checks. |
| 3220 for (int i = 0; i < number_of_types; ++i) { | 3235 for (int i = 0; i < number_of_types; ++i) { |
| 3221 Handle<Map> map = types->at(i); | 3236 Handle<Map> map = types->at(i); |
| 3222 LookupResult lookup; | 3237 LookupResult lookup; |
| 3223 if (ComputeStoredField(map, name, &lookup)) { | 3238 if (ComputeStoredField(map, name, &lookup)) { |
| 3224 maps.Add(map); | |
| 3225 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3239 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3226 SubgraphScope scope(this, subgraph); | 3240 SubgraphScope scope(this, subgraph); |
| 3227 HInstruction* instr = | 3241 HInstruction* instr = |
| 3228 BuildStoreNamedField(object, name, value, map, &lookup, false); | 3242 BuildStoreNamedField(object, name, value, map, &lookup, false); |
| 3229 Push(value); | 3243 Push(value); |
| 3230 instr->set_position(expr->position()); | 3244 instr->set_position(expr->position()); |
| 3231 AddInstruction(instr); | 3245 AddInstruction(instr); |
| 3246 maps.Add(map); |
| 3232 subgraphs.Add(subgraph); | 3247 subgraphs.Add(subgraph); |
| 3233 } else { | 3248 } else { |
| 3234 needs_generic = true; | 3249 needs_generic = true; |
| 3235 } | 3250 } |
| 3236 } | 3251 } |
| 3237 | 3252 |
| 3238 // If none of the properties were named fields we generate a | 3253 // If none of the properties were named fields we generate a |
| 3239 // generic store. | 3254 // generic store. |
| 3240 if (maps.length() == 0) { | 3255 if (maps.length() == 0) { |
| 3241 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3256 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3242 Push(value); | 3257 Push(value); |
| 3243 instr->set_position(expr->position()); | 3258 instr->set_position(expr->position()); |
| 3244 AddInstruction(instr); | 3259 AddInstruction(instr); |
| 3245 if (instr->HasSideEffects()) AddSimulate(expr->id()); | 3260 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3261 ast_context()->ReturnValue(Pop()); |
| 3246 } else { | 3262 } else { |
| 3247 // Build subgraph for generic store through IC. | 3263 // Build subgraph for generic store through IC. |
| 3248 { | 3264 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
| 3249 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3265 { SubgraphScope scope(this, default_graph); |
| 3250 SubgraphScope scope(this, subgraph); | |
| 3251 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3266 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3252 subgraph->FinishExit(new HDeoptimize()); | 3267 default_graph->FinishExit(new HDeoptimize()); |
| 3253 } else { | 3268 } else { |
| 3254 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3269 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3255 Push(value); | 3270 Push(value); |
| 3256 instr->set_position(expr->position()); | 3271 instr->set_position(expr->position()); |
| 3257 AddInstruction(instr); | 3272 AddInstruction(instr); |
| 3258 } | 3273 } |
| 3259 subgraphs.Add(subgraph); | |
| 3260 } | 3274 } |
| 3261 | 3275 |
| 3262 HBasicBlock* new_exit_block = | 3276 HBasicBlock* new_exit_block = |
| 3263 BuildTypeSwitch(&maps, &subgraphs, object, expr->AssignmentId()); | 3277 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
| 3264 subgraph()->set_exit_block(new_exit_block); | 3278 subgraph()->set_exit_block(new_exit_block); |
| 3279 // In an effect context, we did not materialized the value in the |
| 3280 // predecessor environments so there's no need to handle it here. |
| 3281 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { |
| 3282 ast_context()->ReturnValue(Pop()); |
| 3283 } |
| 3265 } | 3284 } |
| 3266 | |
| 3267 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | |
| 3268 } | 3285 } |
| 3269 | 3286 |
| 3270 | 3287 |
| 3271 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3288 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3272 Property* prop = expr->target()->AsProperty(); | 3289 Property* prop = expr->target()->AsProperty(); |
| 3273 ASSERT(prop != NULL); | 3290 ASSERT(prop != NULL); |
| 3274 expr->RecordTypeFeedback(oracle()); | 3291 expr->RecordTypeFeedback(oracle()); |
| 3275 VISIT_FOR_VALUE(prop->obj()); | 3292 VISIT_FOR_VALUE(prop->obj()); |
| 3276 | 3293 |
| 3277 HValue* value = NULL; | 3294 HValue* value = NULL; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3291 LookupResult lookup; | 3308 LookupResult lookup; |
| 3292 | 3309 |
| 3293 if (expr->IsMonomorphic()) { | 3310 if (expr->IsMonomorphic()) { |
| 3294 instr = BuildStoreNamed(object, value, expr); | 3311 instr = BuildStoreNamed(object, value, expr); |
| 3295 | 3312 |
| 3296 } else if (types != NULL && types->length() > 1) { | 3313 } else if (types != NULL && types->length() > 1) { |
| 3297 HandlePolymorphicStoreNamedField(expr, object, value, types, name); | 3314 HandlePolymorphicStoreNamedField(expr, object, value, types, name); |
| 3298 return; | 3315 return; |
| 3299 | 3316 |
| 3300 } else { | 3317 } else { |
| 3301 instr = new HStoreNamedGeneric(object, name, value); | 3318 instr = BuildStoreNamedGeneric(object, name, value); |
| 3302 } | 3319 } |
| 3303 | 3320 |
| 3304 } else { | 3321 } else { |
| 3305 // Keyed store. | 3322 // Keyed store. |
| 3306 VISIT_FOR_VALUE(prop->key()); | 3323 VISIT_FOR_VALUE(prop->key()); |
| 3307 VISIT_FOR_VALUE(expr->value()); | 3324 VISIT_FOR_VALUE(expr->value()); |
| 3308 value = Pop(); | 3325 value = Pop(); |
| 3309 HValue* key = Pop(); | 3326 HValue* key = Pop(); |
| 3310 HValue* object = Pop(); | 3327 HValue* object = Pop(); |
| 3311 | 3328 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3329 // superclass of Assignment and CountOperation, we cannot just pass the | 3346 // superclass of Assignment and CountOperation, we cannot just pass the |
| 3330 // owning expression instead of position and ast_id separately. | 3347 // owning expression instead of position and ast_id separately. |
| 3331 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, | 3348 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
| 3332 HValue* value, | 3349 HValue* value, |
| 3333 int position, | 3350 int position, |
| 3334 int ast_id) { | 3351 int ast_id) { |
| 3335 LookupResult lookup; | 3352 LookupResult lookup; |
| 3336 LookupGlobalPropertyCell(var, &lookup, true); | 3353 LookupGlobalPropertyCell(var, &lookup, true); |
| 3337 CHECK_BAILOUT; | 3354 CHECK_BAILOUT; |
| 3338 | 3355 |
| 3356 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 3339 Handle<GlobalObject> global(graph()->info()->global_object()); | 3357 Handle<GlobalObject> global(graph()->info()->global_object()); |
| 3340 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3358 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3341 HInstruction* instr = new HStoreGlobal(value, cell); | 3359 HInstruction* instr = new HStoreGlobal(value, cell, check_hole); |
| 3342 instr->set_position(position); | 3360 instr->set_position(position); |
| 3343 AddInstruction(instr); | 3361 AddInstruction(instr); |
| 3344 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3362 if (instr->HasSideEffects()) AddSimulate(ast_id); |
| 3345 } | 3363 } |
| 3346 | 3364 |
| 3347 | 3365 |
| 3348 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3366 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
| 3349 Expression* target = expr->target(); | 3367 Expression* target = expr->target(); |
| 3350 VariableProxy* proxy = target->AsVariableProxy(); | 3368 VariableProxy* proxy = target->AsVariableProxy(); |
| 3351 Variable* var = proxy->AsVariable(); | 3369 Variable* var = proxy->AsVariable(); |
| 3352 Property* prop = target->AsProperty(); | 3370 Property* prop = target->AsProperty(); |
| 3353 ASSERT(var == NULL || prop == NULL); | 3371 ASSERT(var == NULL || prop == NULL); |
| 3354 | 3372 |
| 3355 // We have a second position recorded in the FullCodeGenerator to have | 3373 // We have a second position recorded in the FullCodeGenerator to have |
| 3356 // type feedback for the binary operation. | 3374 // type feedback for the binary operation. |
| 3357 BinaryOperation* operation = expr->binary_operation(); | 3375 BinaryOperation* operation = expr->binary_operation(); |
| 3358 operation->RecordTypeFeedback(oracle()); | |
| 3359 | 3376 |
| 3360 if (var != NULL) { | 3377 if (var != NULL) { |
| 3361 if (!var->is_global() && !var->IsStackAllocated()) { | |
| 3362 BAILOUT("non-stack/non-global in compound assignment"); | |
| 3363 } | |
| 3364 | |
| 3365 VISIT_FOR_VALUE(operation); | 3378 VISIT_FOR_VALUE(operation); |
| 3366 | 3379 |
| 3367 if (var->is_global()) { | 3380 if (var->is_global()) { |
| 3368 HandleGlobalVariableAssignment(var, | 3381 HandleGlobalVariableAssignment(var, |
| 3369 Top(), | 3382 Top(), |
| 3370 expr->position(), | 3383 expr->position(), |
| 3371 expr->AssignmentId()); | 3384 expr->AssignmentId()); |
| 3385 } else if (var->IsStackAllocated()) { |
| 3386 Bind(var, Top()); |
| 3387 } else if (var->IsContextSlot()) { |
| 3388 HValue* context = BuildContextChainWalk(var); |
| 3389 int index = var->AsSlot()->index(); |
| 3390 HStoreContextSlot* instr = new HStoreContextSlot(context, index, Top()); |
| 3391 AddInstruction(instr); |
| 3392 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3372 } else { | 3393 } else { |
| 3373 Bind(var, Top()); | 3394 BAILOUT("compound assignment to lookup slot"); |
| 3374 } | 3395 } |
| 3375 ast_context()->ReturnValue(Pop()); | 3396 ast_context()->ReturnValue(Pop()); |
| 3376 | 3397 |
| 3377 } else if (prop != NULL) { | 3398 } else if (prop != NULL) { |
| 3378 prop->RecordTypeFeedback(oracle()); | 3399 prop->RecordTypeFeedback(oracle()); |
| 3379 | 3400 |
| 3380 if (prop->key()->IsPropertyName()) { | 3401 if (prop->key()->IsPropertyName()) { |
| 3381 // Named property. | 3402 // Named property. |
| 3382 VISIT_FOR_VALUE(prop->obj()); | 3403 VISIT_FOR_VALUE(prop->obj()); |
| 3383 HValue* obj = Top(); | 3404 HValue* obj = Top(); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 3411 | 3432 |
| 3412 } else { | 3433 } else { |
| 3413 // Keyed property. | 3434 // Keyed property. |
| 3414 VISIT_FOR_VALUE(prop->obj()); | 3435 VISIT_FOR_VALUE(prop->obj()); |
| 3415 VISIT_FOR_VALUE(prop->key()); | 3436 VISIT_FOR_VALUE(prop->key()); |
| 3416 HValue* obj = environment()->ExpressionStackAt(1); | 3437 HValue* obj = environment()->ExpressionStackAt(1); |
| 3417 HValue* key = environment()->ExpressionStackAt(0); | 3438 HValue* key = environment()->ExpressionStackAt(0); |
| 3418 | 3439 |
| 3419 bool is_fast_elements = prop->IsMonomorphic() && | 3440 bool is_fast_elements = prop->IsMonomorphic() && |
| 3420 prop->GetMonomorphicReceiverType()->has_fast_elements(); | 3441 prop->GetMonomorphicReceiverType()->has_fast_elements(); |
| 3421 | |
| 3422 HInstruction* load = is_fast_elements | 3442 HInstruction* load = is_fast_elements |
| 3423 ? BuildLoadKeyedFastElement(obj, key, prop) | 3443 ? BuildLoadKeyedFastElement(obj, key, prop) |
| 3424 : BuildLoadKeyedGeneric(obj, key); | 3444 : BuildLoadKeyedGeneric(obj, key); |
| 3425 PushAndAdd(load); | 3445 PushAndAdd(load); |
| 3426 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); | 3446 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); |
| 3427 | 3447 |
| 3428 VISIT_FOR_VALUE(expr->value()); | 3448 VISIT_FOR_VALUE(expr->value()); |
| 3429 HValue* right = Pop(); | 3449 HValue* right = Pop(); |
| 3430 HValue* left = Pop(); | 3450 HValue* left = Pop(); |
| 3431 | 3451 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3458 | 3478 |
| 3459 if (expr->is_compound()) { | 3479 if (expr->is_compound()) { |
| 3460 HandleCompoundAssignment(expr); | 3480 HandleCompoundAssignment(expr); |
| 3461 return; | 3481 return; |
| 3462 } | 3482 } |
| 3463 | 3483 |
| 3464 if (var != NULL) { | 3484 if (var != NULL) { |
| 3465 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); | 3485 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); |
| 3466 | 3486 |
| 3467 // Handle the assignment. | 3487 // Handle the assignment. |
| 3468 if (var->is_global()) { | 3488 if (var->IsStackAllocated()) { |
| 3489 HValue* value = NULL; |
| 3490 // Handle stack-allocated variables on the right-hand side directly. |
| 3491 // We do not allow the arguments object to occur in a context where it |
| 3492 // may escape, but assignments to stack-allocated locals are |
| 3493 // permitted. Handling such assignments here bypasses the check for |
| 3494 // the arguments object in VisitVariableProxy. |
| 3495 Variable* rhs_var = expr->value()->AsVariableProxy()->AsVariable(); |
| 3496 if (rhs_var != NULL && rhs_var->IsStackAllocated()) { |
| 3497 value = environment()->Lookup(rhs_var); |
| 3498 } else { |
| 3499 VISIT_FOR_VALUE(expr->value()); |
| 3500 value = Pop(); |
| 3501 } |
| 3502 Bind(var, value); |
| 3503 ast_context()->ReturnValue(value); |
| 3504 |
| 3505 } else if (var->IsContextSlot() && var->mode() != Variable::CONST) { |
| 3506 VISIT_FOR_VALUE(expr->value()); |
| 3507 HValue* context = BuildContextChainWalk(var); |
| 3508 int index = var->AsSlot()->index(); |
| 3509 HStoreContextSlot* instr = new HStoreContextSlot(context, index, Top()); |
| 3510 AddInstruction(instr); |
| 3511 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3512 ast_context()->ReturnValue(Pop()); |
| 3513 |
| 3514 } else if (var->is_global()) { |
| 3469 VISIT_FOR_VALUE(expr->value()); | 3515 VISIT_FOR_VALUE(expr->value()); |
| 3470 HandleGlobalVariableAssignment(var, | 3516 HandleGlobalVariableAssignment(var, |
| 3471 Top(), | 3517 Top(), |
| 3472 expr->position(), | 3518 expr->position(), |
| 3473 expr->AssignmentId()); | 3519 expr->AssignmentId()); |
| 3520 ast_context()->ReturnValue(Pop()); |
| 3521 |
| 3474 } else { | 3522 } else { |
| 3475 // We allow reference to the arguments object only in assignemtns | 3523 BAILOUT("assignment to LOOKUP or const CONTEXT variable"); |
| 3476 // to local variables to make sure that the arguments object does | |
| 3477 // not escape and is not modified. | |
| 3478 VariableProxy* rhs = expr->value()->AsVariableProxy(); | |
| 3479 if (rhs != NULL && | |
| 3480 rhs->var()->IsStackAllocated() && | |
| 3481 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { | |
| 3482 Push(environment()->Lookup(rhs->var())); | |
| 3483 } else { | |
| 3484 VISIT_FOR_VALUE(expr->value()); | |
| 3485 } | |
| 3486 Bind(proxy->var(), Top()); | |
| 3487 } | 3524 } |
| 3488 // Return the value. | |
| 3489 ast_context()->ReturnValue(Pop()); | |
| 3490 | 3525 |
| 3491 } else if (prop != NULL) { | 3526 } else if (prop != NULL) { |
| 3492 HandlePropertyAssignment(expr); | 3527 HandlePropertyAssignment(expr); |
| 3493 } else { | 3528 } else { |
| 3494 BAILOUT("unsupported invalid lhs"); | 3529 BAILOUT("invalid left-hand side in assignment"); |
| 3495 } | 3530 } |
| 3496 } | 3531 } |
| 3497 | 3532 |
| 3498 | 3533 |
| 3499 void HGraphBuilder::VisitThrow(Throw* expr) { | 3534 void HGraphBuilder::VisitThrow(Throw* expr) { |
| 3500 // We don't optimize functions with invalid left-hand sides in | 3535 // We don't optimize functions with invalid left-hand sides in |
| 3501 // assignments, count operations, or for-in. Consequently throw can | 3536 // assignments, count operations, or for-in. Consequently throw can |
| 3502 // currently only occur in an effect context. | 3537 // currently only occur in an effect context. |
| 3503 ASSERT(ast_context()->IsEffect()); | 3538 ASSERT(ast_context()->IsEffect()); |
| 3504 VISIT_FOR_VALUE(expr->exception()); | 3539 VISIT_FOR_VALUE(expr->exception()); |
| 3505 | 3540 |
| 3506 HValue* value = environment()->Pop(); | 3541 HValue* value = environment()->Pop(); |
| 3507 HControlInstruction* instr = new HThrow(value); | 3542 HThrow* instr = new HThrow(value); |
| 3508 instr->set_position(expr->position()); | 3543 instr->set_position(expr->position()); |
| 3509 current_subgraph_->FinishExit(instr); | 3544 AddInstruction(instr); |
| 3545 AddSimulate(expr->id()); |
| 3546 current_subgraph_->FinishExit(new HAbnormalExit); |
| 3510 } | 3547 } |
| 3511 | 3548 |
| 3512 | 3549 |
| 3513 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3550 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
| 3514 HValue* object, | 3551 HValue* object, |
| 3515 ZoneMapList* types, | 3552 ZoneMapList* types, |
| 3516 Handle<String> name) { | 3553 Handle<String> name) { |
| 3517 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); | 3554 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); |
| 3518 ZoneMapList maps(number_of_types); | 3555 ZoneMapList maps(number_of_types); |
| 3519 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3556 ZoneList<HSubgraph*> subgraphs(number_of_types); |
| 3520 bool needs_generic = (types->length() > kMaxLoadPolymorphism); | 3557 bool needs_generic = (types->length() > kMaxLoadPolymorphism); |
| 3521 | 3558 |
| 3522 // Build subgraphs for each of the specific maps. | 3559 // Build subgraphs for each of the specific maps. |
| 3523 // | 3560 // |
| 3524 // TODO(ager): We should recognize when the prototype chains for | 3561 // TODO(ager): We should recognize when the prototype chains for |
| 3525 // different maps are identical. In that case we can avoid | 3562 // different maps are identical. In that case we can avoid |
| 3526 // repeatedly generating the same prototype map checks. | 3563 // repeatedly generating the same prototype map checks. |
| 3527 for (int i = 0; i < number_of_types; ++i) { | 3564 for (int i = 0; i < number_of_types; ++i) { |
| 3528 Handle<Map> map = types->at(i); | 3565 Handle<Map> map = types->at(i); |
| 3529 LookupResult lookup; | 3566 LookupResult lookup; |
| 3530 map->LookupInDescriptors(NULL, *name, &lookup); | 3567 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3531 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3568 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3532 maps.Add(map); | |
| 3533 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3569 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3534 SubgraphScope scope(this, subgraph); | 3570 SubgraphScope scope(this, subgraph); |
| 3535 HLoadNamedField* instr = | 3571 HLoadNamedField* instr = |
| 3536 BuildLoadNamedField(object, expr, map, &lookup, false); | 3572 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3537 instr->set_position(expr->position()); | 3573 instr->set_position(expr->position()); |
| 3538 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. | 3574 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. |
| 3539 PushAndAdd(instr); | 3575 PushAndAdd(instr); |
| 3576 maps.Add(map); |
| 3540 subgraphs.Add(subgraph); | 3577 subgraphs.Add(subgraph); |
| 3541 } else { | 3578 } else { |
| 3542 needs_generic = true; | 3579 needs_generic = true; |
| 3543 } | 3580 } |
| 3544 } | 3581 } |
| 3545 | 3582 |
| 3546 // If none of the properties were named fields we generate a | 3583 // If none of the properties were named fields we generate a |
| 3547 // generic load. | 3584 // generic load. |
| 3548 if (maps.length() == 0) { | 3585 if (maps.length() == 0) { |
| 3549 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3586 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3550 instr->set_position(expr->position()); | 3587 instr->set_position(expr->position()); |
| 3551 PushAndAdd(instr); | 3588 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3552 if (instr->HasSideEffects()) AddSimulate(expr->id()); | |
| 3553 } else { | 3589 } else { |
| 3554 // Build subgraph for generic load through IC. | 3590 // Build subgraph for generic load through IC. |
| 3555 { | 3591 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
| 3556 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3592 { SubgraphScope scope(this, default_graph); |
| 3557 SubgraphScope scope(this, subgraph); | |
| 3558 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3593 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3559 subgraph->FinishExit(new HDeoptimize()); | 3594 default_graph->FinishExit(new HDeoptimize()); |
| 3560 } else { | 3595 } else { |
| 3561 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3596 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3562 instr->set_position(expr->position()); | 3597 instr->set_position(expr->position()); |
| 3563 PushAndAdd(instr); | 3598 PushAndAdd(instr); |
| 3564 } | 3599 } |
| 3565 subgraphs.Add(subgraph); | |
| 3566 } | 3600 } |
| 3567 | 3601 |
| 3568 HBasicBlock* new_exit_block = | 3602 HBasicBlock* new_exit_block = |
| 3569 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | 3603 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
| 3570 subgraph()->set_exit_block(new_exit_block); | 3604 subgraph()->set_exit_block(new_exit_block); |
| 3605 // In an effect context, we did not materialized the value in the |
| 3606 // predecessor environments so there's no need to handle it here. |
| 3607 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { |
| 3608 ast_context()->ReturnValue(Pop()); |
| 3609 } |
| 3571 } | 3610 } |
| 3572 | |
| 3573 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | |
| 3574 } | 3611 } |
| 3575 | 3612 |
| 3576 | 3613 |
| 3577 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3614 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3578 Property* expr, | 3615 Property* expr, |
| 3579 Handle<Map> type, | 3616 Handle<Map> type, |
| 3580 LookupResult* lookup, | 3617 LookupResult* lookup, |
| 3581 bool smi_and_map_check) { | 3618 bool smi_and_map_check) { |
| 3582 if (smi_and_map_check) { | 3619 if (smi_and_map_check) { |
| 3583 AddInstruction(new HCheckNonSmi(object)); | 3620 AddInstruction(new HCheckNonSmi(object)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3595 int offset = (index * kPointerSize) + FixedArray::kHeaderSize; | 3632 int offset = (index * kPointerSize) + FixedArray::kHeaderSize; |
| 3596 return new HLoadNamedField(object, false, offset); | 3633 return new HLoadNamedField(object, false, offset); |
| 3597 } | 3634 } |
| 3598 } | 3635 } |
| 3599 | 3636 |
| 3600 | 3637 |
| 3601 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, | 3638 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, |
| 3602 Property* expr) { | 3639 Property* expr) { |
| 3603 ASSERT(expr->key()->IsPropertyName()); | 3640 ASSERT(expr->key()->IsPropertyName()); |
| 3604 Handle<Object> name = expr->key()->AsLiteral()->handle(); | 3641 Handle<Object> name = expr->key()->AsLiteral()->handle(); |
| 3605 return new HLoadNamedGeneric(obj, name); | 3642 HContext* context = new HContext; |
| 3643 AddInstruction(context); |
| 3644 return new HLoadNamedGeneric(context, obj, name); |
| 3606 } | 3645 } |
| 3607 | 3646 |
| 3608 | 3647 |
| 3609 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, | 3648 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, |
| 3610 Property* expr, | 3649 Property* expr, |
| 3611 Handle<Map> map, | 3650 Handle<Map> map, |
| 3612 Handle<String> name) { | 3651 Handle<String> name) { |
| 3613 LookupResult lookup; | 3652 LookupResult lookup; |
| 3614 map->LookupInDescriptors(NULL, *name, &lookup); | 3653 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3615 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3654 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3616 return BuildLoadNamedField(obj, | 3655 return BuildLoadNamedField(obj, |
| 3617 expr, | 3656 expr, |
| 3618 map, | 3657 map, |
| 3619 &lookup, | 3658 &lookup, |
| 3620 true); | 3659 true); |
| 3621 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { | 3660 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { |
| 3622 AddInstruction(new HCheckNonSmi(obj)); | 3661 AddInstruction(new HCheckNonSmi(obj)); |
| 3623 AddInstruction(new HCheckMap(obj, map)); | 3662 AddInstruction(new HCheckMap(obj, map)); |
| 3624 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); | 3663 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); |
| 3625 return new HConstant(function, Representation::Tagged()); | 3664 return new HConstant(function, Representation::Tagged()); |
| 3626 } else { | 3665 } else { |
| 3627 return BuildLoadNamedGeneric(obj, expr); | 3666 return BuildLoadNamedGeneric(obj, expr); |
| 3628 } | 3667 } |
| 3629 } | 3668 } |
| 3630 | 3669 |
| 3631 | 3670 |
| 3632 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 3671 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 3633 HValue* key) { | 3672 HValue* key) { |
| 3634 return new HLoadKeyedGeneric(object, key); | 3673 HContext* context = new HContext; |
| 3674 AddInstruction(context); |
| 3675 return new HLoadKeyedGeneric(context, object, key); |
| 3635 } | 3676 } |
| 3636 | 3677 |
| 3637 | 3678 |
| 3638 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, | 3679 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, |
| 3639 HValue* key, | 3680 HValue* key, |
| 3640 Property* expr) { | 3681 Property* expr) { |
| 3641 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3682 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); |
| 3642 AddInstruction(new HCheckNonSmi(object)); | 3683 AddInstruction(new HCheckNonSmi(object)); |
| 3643 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3684 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3644 ASSERT(map->has_fast_elements()); | 3685 ASSERT(map->has_fast_elements()); |
| 3645 AddInstruction(new HCheckMap(object, map)); | 3686 AddInstruction(new HCheckMap(object, map)); |
| 3646 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); | 3687 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); |
| 3647 HLoadElements* elements = new HLoadElements(object); | 3688 HLoadElements* elements = new HLoadElements(object); |
| 3648 HInstruction* length = NULL; | 3689 HInstruction* length = NULL; |
| 3649 if (is_array) { | 3690 if (is_array) { |
| 3650 length = AddInstruction(new HJSArrayLength(object)); | 3691 length = AddInstruction(new HJSArrayLength(object)); |
| 3651 AddInstruction(new HBoundsCheck(key, length)); | 3692 AddInstruction(new HBoundsCheck(key, length)); |
| 3652 AddInstruction(elements); | 3693 AddInstruction(elements); |
| 3653 } else { | 3694 } else { |
| 3654 AddInstruction(elements); | 3695 AddInstruction(elements); |
| 3655 length = AddInstruction(new HFixedArrayLength(elements)); | 3696 length = AddInstruction(new HFixedArrayLength(elements)); |
| 3656 AddInstruction(new HBoundsCheck(key, length)); | 3697 AddInstruction(new HBoundsCheck(key, length)); |
| 3657 } | 3698 } |
| 3658 return new HLoadKeyedFastElement(elements, key); | 3699 return new HLoadKeyedFastElement(elements, key); |
| 3659 } | 3700 } |
| 3660 | 3701 |
| 3661 | 3702 |
| 3703 HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object, |
| 3704 HValue* key, |
| 3705 Property* expr) { |
| 3706 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); |
| 3707 AddInstruction(new HCheckNonSmi(object)); |
| 3708 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3709 ASSERT(!map->has_fast_elements()); |
| 3710 ASSERT(map->has_pixel_array_elements()); |
| 3711 AddInstruction(new HCheckMap(object, map)); |
| 3712 HLoadElements* elements = new HLoadElements(object); |
| 3713 AddInstruction(elements); |
| 3714 HInstruction* length = AddInstruction(new HPixelArrayLength(elements)); |
| 3715 AddInstruction(new HBoundsCheck(key, length)); |
| 3716 HLoadPixelArrayExternalPointer* external_elements = |
| 3717 new HLoadPixelArrayExternalPointer(elements); |
| 3718 AddInstruction(external_elements); |
| 3719 HLoadPixelArrayElement* pixel_array_value = |
| 3720 new HLoadPixelArrayElement(external_elements, key); |
| 3721 return pixel_array_value; |
| 3722 } |
| 3723 |
| 3724 |
| 3662 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 3725 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
| 3663 HValue* key, | 3726 HValue* key, |
| 3664 HValue* value) { | 3727 HValue* value) { |
| 3665 return new HStoreKeyedGeneric(object, key, value); | 3728 HContext* context = new HContext; |
| 3729 AddInstruction(context); |
| 3730 return new HStoreKeyedGeneric(context, object, key, value); |
| 3666 } | 3731 } |
| 3667 | 3732 |
| 3668 | 3733 |
| 3669 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, | 3734 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, |
| 3670 HValue* key, | 3735 HValue* key, |
| 3671 HValue* val, | 3736 HValue* val, |
| 3672 Expression* expr) { | 3737 Expression* expr) { |
| 3673 ASSERT(expr->IsMonomorphic()); | 3738 ASSERT(expr->IsMonomorphic()); |
| 3674 AddInstruction(new HCheckNonSmi(object)); | 3739 AddInstruction(new HCheckNonSmi(object)); |
| 3675 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3740 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3725 | 3790 |
| 3726 VISIT_FOR_VALUE(expr->obj()); | 3791 VISIT_FOR_VALUE(expr->obj()); |
| 3727 | 3792 |
| 3728 HInstruction* instr = NULL; | 3793 HInstruction* instr = NULL; |
| 3729 if (expr->IsArrayLength()) { | 3794 if (expr->IsArrayLength()) { |
| 3730 HValue* array = Pop(); | 3795 HValue* array = Pop(); |
| 3731 AddInstruction(new HCheckNonSmi(array)); | 3796 AddInstruction(new HCheckNonSmi(array)); |
| 3732 AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); | 3797 AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE)); |
| 3733 instr = new HJSArrayLength(array); | 3798 instr = new HJSArrayLength(array); |
| 3734 | 3799 |
| 3800 } else if (expr->IsStringLength()) { |
| 3801 HValue* string = Pop(); |
| 3802 AddInstruction(new HCheckNonSmi(string)); |
| 3803 AddInstruction(new HCheckInstanceType(string, |
| 3804 FIRST_STRING_TYPE, |
| 3805 LAST_STRING_TYPE)); |
| 3806 instr = new HStringLength(string); |
| 3807 |
| 3735 } else if (expr->IsFunctionPrototype()) { | 3808 } else if (expr->IsFunctionPrototype()) { |
| 3736 HValue* function = Pop(); | 3809 HValue* function = Pop(); |
| 3737 AddInstruction(new HCheckNonSmi(function)); | 3810 AddInstruction(new HCheckNonSmi(function)); |
| 3738 instr = new HLoadFunctionPrototype(function); | 3811 instr = new HLoadFunctionPrototype(function); |
| 3739 | 3812 |
| 3740 } else if (expr->key()->IsPropertyName()) { | 3813 } else if (expr->key()->IsPropertyName()) { |
| 3741 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 3814 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3742 ZoneMapList* types = expr->GetReceiverTypes(); | 3815 ZoneMapList* types = expr->GetReceiverTypes(); |
| 3743 | 3816 |
| 3744 HValue* obj = Pop(); | 3817 HValue* obj = Pop(); |
| 3745 if (expr->IsMonomorphic()) { | 3818 if (expr->IsMonomorphic()) { |
| 3746 instr = BuildLoadNamed(obj, expr, types->first(), name); | 3819 instr = BuildLoadNamed(obj, expr, types->first(), name); |
| 3747 } else if (types != NULL && types->length() > 1) { | 3820 } else if (types != NULL && types->length() > 1) { |
| 3748 HandlePolymorphicLoadNamedField(expr, obj, types, name); | 3821 HandlePolymorphicLoadNamedField(expr, obj, types, name); |
| 3749 return; | 3822 return; |
| 3750 | 3823 |
| 3751 } else { | 3824 } else { |
| 3752 instr = BuildLoadNamedGeneric(obj, expr); | 3825 instr = BuildLoadNamedGeneric(obj, expr); |
| 3753 } | 3826 } |
| 3754 | 3827 |
| 3755 } else { | 3828 } else { |
| 3756 VISIT_FOR_VALUE(expr->key()); | 3829 VISIT_FOR_VALUE(expr->key()); |
| 3757 | 3830 |
| 3758 HValue* key = Pop(); | 3831 HValue* key = Pop(); |
| 3759 HValue* obj = Pop(); | 3832 HValue* obj = Pop(); |
| 3760 | 3833 |
| 3761 bool is_fast_elements = expr->IsMonomorphic() && | 3834 if (expr->IsMonomorphic()) { |
| 3762 expr->GetMonomorphicReceiverType()->has_fast_elements(); | 3835 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); |
| 3763 | 3836 // An object has either fast elements or pixel array elements, but never |
| 3764 instr = is_fast_elements | 3837 // both. Pixel array maps that are assigned to pixel array elements are |
| 3765 ? BuildLoadKeyedFastElement(obj, key, expr) | 3838 // always created with the fast elements flag cleared. |
| 3766 : BuildLoadKeyedGeneric(obj, key); | 3839 if (receiver_type->has_pixel_array_elements()) { |
| 3840 instr = BuildLoadKeyedPixelArrayElement(obj, key, expr); |
| 3841 } else if (receiver_type->has_fast_elements()) { |
| 3842 instr = BuildLoadKeyedFastElement(obj, key, expr); |
| 3843 } |
| 3844 } |
| 3845 if (instr == NULL) { |
| 3846 instr = BuildLoadKeyedGeneric(obj, key); |
| 3847 } |
| 3767 } | 3848 } |
| 3768 instr->set_position(expr->position()); | 3849 instr->set_position(expr->position()); |
| 3769 ast_context()->ReturnInstruction(instr, expr->id()); | 3850 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3770 } | 3851 } |
| 3771 | 3852 |
| 3772 | 3853 |
| 3773 void HGraphBuilder::AddCheckConstantFunction(Call* expr, | 3854 void HGraphBuilder::AddCheckConstantFunction(Call* expr, |
| 3774 HValue* receiver, | 3855 HValue* receiver, |
| 3775 Handle<Map> receiver_map, | 3856 Handle<Map> receiver_map, |
| 3776 bool smi_and_map_check) { | 3857 bool smi_and_map_check) { |
| 3777 // Constant functions have the nice property that the map will change if they | 3858 // Constant functions have the nice property that the map will change if they |
| 3778 // are overwritten. Therefore it is enough to check the map of the holder and | 3859 // are overwritten. Therefore it is enough to check the map of the holder and |
| 3779 // its prototypes. | 3860 // its prototypes. |
| 3780 if (smi_and_map_check) { | 3861 if (smi_and_map_check) { |
| 3781 AddInstruction(new HCheckNonSmi(receiver)); | 3862 AddInstruction(new HCheckNonSmi(receiver)); |
| 3782 AddInstruction(new HCheckMap(receiver, receiver_map)); | 3863 AddInstruction(new HCheckMap(receiver, receiver_map)); |
| 3783 } | 3864 } |
| 3784 if (!expr->holder().is_null()) { | 3865 if (!expr->holder().is_null()) { |
| 3785 AddInstruction(new HCheckPrototypeMaps(receiver, | 3866 AddInstruction(new HCheckPrototypeMaps( |
| 3786 expr->holder(), | 3867 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), |
| 3787 receiver_map)); | 3868 expr->holder())); |
| 3788 } | 3869 } |
| 3789 } | 3870 } |
| 3790 | 3871 |
| 3791 | 3872 |
| 3792 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 3873 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
| 3793 HValue* receiver, | 3874 HValue* receiver, |
| 3794 ZoneMapList* types, | 3875 ZoneMapList* types, |
| 3795 Handle<String> name) { | 3876 Handle<String> name) { |
| 3796 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 3877 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 3797 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | 3878 int number_of_types = Min(types->length(), kMaxCallPolymorphism); |
| 3798 ZoneMapList maps(number_of_types); | 3879 ZoneMapList maps(number_of_types); |
| 3799 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3880 ZoneList<HSubgraph*> subgraphs(number_of_types); |
| 3800 bool needs_generic = (types->length() > kMaxCallPolymorphism); | 3881 bool needs_generic = (types->length() > kMaxCallPolymorphism); |
| 3801 | 3882 |
| 3802 // Build subgraphs for each of the specific maps. | 3883 // Build subgraphs for each of the specific maps. |
| 3803 // | 3884 // |
| 3804 // TODO(ager): We should recognize when the prototype chains for different | 3885 // TODO(ager): We should recognize when the prototype chains for different |
| 3805 // maps are identical. In that case we can avoid repeatedly generating the | 3886 // maps are identical. In that case we can avoid repeatedly generating the |
| 3806 // same prototype map checks. | 3887 // same prototype map checks. |
| 3807 for (int i = 0; i < number_of_types; ++i) { | 3888 for (int i = 0; i < number_of_types; ++i) { |
| 3808 Handle<Map> map = types->at(i); | 3889 Handle<Map> map = types->at(i); |
| 3809 if (expr->ComputeTarget(map, name)) { | 3890 if (expr->ComputeTarget(map, name)) { |
| 3810 maps.Add(map); | |
| 3811 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3891 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3812 SubgraphScope scope(this, subgraph); | 3892 SubgraphScope scope(this, subgraph); |
| 3813 AddCheckConstantFunction(expr, receiver, map, false); | 3893 AddCheckConstantFunction(expr, receiver, map, false); |
| 3814 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 3894 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 3815 PrintF("Trying to inline the polymorphic call to %s\n", | 3895 PrintF("Trying to inline the polymorphic call to %s\n", |
| 3816 *name->ToCString()); | 3896 *name->ToCString()); |
| 3817 } | 3897 } |
| 3818 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { | 3898 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { |
| 3819 // Check for bailout, as trying to inline might fail due to bailout | 3899 // Check for bailout, as trying to inline might fail due to bailout |
| 3820 // during hydrogen processing. | 3900 // during hydrogen processing. |
| 3821 CHECK_BAILOUT; | 3901 CHECK_BAILOUT; |
| 3822 HCall* call = new HCallConstantFunction(expr->target(), argument_count); | 3902 HCall* call = new HCallConstantFunction(expr->target(), argument_count); |
| 3823 call->set_position(expr->position()); | 3903 call->set_position(expr->position()); |
| 3824 ProcessCall(call); | 3904 PreProcessCall(call); |
| 3825 PushAndAdd(call); | 3905 PushAndAdd(call); |
| 3826 } | 3906 } |
| 3907 maps.Add(map); |
| 3827 subgraphs.Add(subgraph); | 3908 subgraphs.Add(subgraph); |
| 3828 } else { | 3909 } else { |
| 3829 needs_generic = true; | 3910 needs_generic = true; |
| 3830 } | 3911 } |
| 3831 } | 3912 } |
| 3832 | 3913 |
| 3833 // If we couldn't compute the target for any of the maps just perform an | 3914 // If we couldn't compute the target for any of the maps just perform an |
| 3834 // IC call. | 3915 // IC call. |
| 3835 if (maps.length() == 0) { | 3916 if (maps.length() == 0) { |
| 3836 HCall* call = new HCallNamed(name, argument_count); | 3917 HContext* context = new HContext; |
| 3918 AddInstruction(context); |
| 3919 HCall* call = new HCallNamed(context, name, argument_count); |
| 3837 call->set_position(expr->position()); | 3920 call->set_position(expr->position()); |
| 3838 ProcessCall(call); | 3921 PreProcessCall(call); |
| 3839 ast_context()->ReturnInstruction(call, expr->id()); | 3922 ast_context()->ReturnInstruction(call, expr->id()); |
| 3840 } else { | 3923 } else { |
| 3841 // Build subgraph for generic call through IC. | 3924 // Build subgraph for generic call through IC. |
| 3842 { | 3925 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
| 3843 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3926 { SubgraphScope scope(this, default_graph); |
| 3844 SubgraphScope scope(this, subgraph); | |
| 3845 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3927 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3846 subgraph->FinishExit(new HDeoptimize()); | 3928 default_graph->FinishExit(new HDeoptimize()); |
| 3847 } else { | 3929 } else { |
| 3848 HCall* call = new HCallNamed(name, argument_count); | 3930 HContext* context = new HContext; |
| 3931 AddInstruction(context); |
| 3932 HCall* call = new HCallNamed(context, name, argument_count); |
| 3849 call->set_position(expr->position()); | 3933 call->set_position(expr->position()); |
| 3850 ProcessCall(call); | 3934 PreProcessCall(call); |
| 3851 PushAndAdd(call); | 3935 PushAndAdd(call); |
| 3852 } | 3936 } |
| 3853 subgraphs.Add(subgraph); | |
| 3854 } | 3937 } |
| 3855 | 3938 |
| 3856 HBasicBlock* new_exit_block = | 3939 HBasicBlock* new_exit_block = |
| 3857 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); | 3940 BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id()); |
| 3858 subgraph()->set_exit_block(new_exit_block); | 3941 subgraph()->set_exit_block(new_exit_block); |
| 3859 if (new_exit_block != NULL) ast_context()->ReturnValue(Pop()); | 3942 // In an effect context, we did not materialized the value in the |
| 3943 // predecessor environments so there's no need to handle it here. |
| 3944 if (new_exit_block != NULL && !ast_context()->IsEffect()) { |
| 3945 ast_context()->ReturnValue(Pop()); |
| 3946 } |
| 3860 } | 3947 } |
| 3861 } | 3948 } |
| 3862 | 3949 |
| 3863 | 3950 |
| 3864 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | 3951 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { |
| 3865 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); | 3952 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); |
| 3866 SmartPointer<char> caller = | 3953 SmartPointer<char> caller = |
| 3867 graph()->info()->function()->debug_name()->ToCString(); | 3954 graph()->info()->function()->debug_name()->ToCString(); |
| 3868 if (result) { | 3955 if (result) { |
| 3869 PrintF("Inlined %s called from %s.\n", *callee, *caller); | 3956 PrintF("Inlined %s called from %s.\n", *callee, *caller); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3907 | 3994 |
| 3908 // We don't want to add more than a certain number of nodes from inlining. | 3995 // We don't want to add more than a certain number of nodes from inlining. |
| 3909 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { | 3996 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { |
| 3910 if (FLAG_trace_inlining) TraceInline(target, false); | 3997 if (FLAG_trace_inlining) TraceInline(target, false); |
| 3911 return false; | 3998 return false; |
| 3912 } | 3999 } |
| 3913 | 4000 |
| 3914 int count_before = AstNode::Count(); | 4001 int count_before = AstNode::Count(); |
| 3915 | 4002 |
| 3916 // Parse and allocate variables. | 4003 // Parse and allocate variables. |
| 3917 Handle<SharedFunctionInfo> shared(target->shared()); | 4004 CompilationInfo inner_info(target); |
| 3918 CompilationInfo inner_info(shared); | |
| 3919 if (!ParserApi::Parse(&inner_info) || | 4005 if (!ParserApi::Parse(&inner_info) || |
| 3920 !Scope::Analyze(&inner_info)) { | 4006 !Scope::Analyze(&inner_info)) { |
| 4007 if (Top::has_pending_exception()) { |
| 4008 SetStackOverflow(); |
| 4009 } |
| 3921 return false; | 4010 return false; |
| 3922 } | 4011 } |
| 3923 FunctionLiteral* function = inner_info.function(); | 4012 FunctionLiteral* function = inner_info.function(); |
| 3924 | 4013 |
| 3925 // Count the number of AST nodes added by inlining this call. | 4014 // Count the number of AST nodes added by inlining this call. |
| 3926 int nodes_added = AstNode::Count() - count_before; | 4015 int nodes_added = AstNode::Count() - count_before; |
| 3927 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | 4016 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { |
| 3928 if (FLAG_trace_inlining) TraceInline(target, false); | 4017 if (FLAG_trace_inlining) TraceInline(target, false); |
| 3929 return false; | 4018 return false; |
| 3930 } | 4019 } |
| 3931 | 4020 |
| 3932 // Check if we can handle all declarations in the inlined functions. | 4021 // Check if we can handle all declarations in the inlined functions. |
| 3933 VisitDeclarations(inner_info.scope()->declarations()); | 4022 VisitDeclarations(inner_info.scope()->declarations()); |
| 3934 if (HasStackOverflow()) { | 4023 if (HasStackOverflow()) { |
| 3935 ClearStackOverflow(); | 4024 ClearStackOverflow(); |
| 3936 return false; | 4025 return false; |
| 3937 } | 4026 } |
| 3938 | 4027 |
| 3939 // Don't inline functions that uses the arguments object or that | 4028 // Don't inline functions that uses the arguments object or that |
| 3940 // have a mismatching number of parameters. | 4029 // have a mismatching number of parameters. |
| 4030 Handle<SharedFunctionInfo> shared(target->shared()); |
| 3941 int arity = expr->arguments()->length(); | 4031 int arity = expr->arguments()->length(); |
| 3942 if (function->scope()->arguments() != NULL || | 4032 if (function->scope()->arguments() != NULL || |
| 3943 arity != target->shared()->formal_parameter_count()) { | 4033 arity != shared->formal_parameter_count()) { |
| 3944 return false; | 4034 return false; |
| 3945 } | 4035 } |
| 3946 | 4036 |
| 3947 // All statements in the body must be inlineable. | 4037 // All statements in the body must be inlineable. |
| 3948 for (int i = 0, count = function->body()->length(); i < count; ++i) { | 4038 for (int i = 0, count = function->body()->length(); i < count; ++i) { |
| 3949 if (!function->body()->at(i)->IsInlineable()) return false; | 4039 if (!function->body()->at(i)->IsInlineable()) return false; |
| 3950 } | 4040 } |
| 3951 | 4041 |
| 3952 // Generate the deoptimization data for the unoptimized version of | 4042 // Generate the deoptimization data for the unoptimized version of |
| 3953 // the target function if we don't already have it. | 4043 // the target function if we don't already have it. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3985 if_false->MarkAsInlineReturnTarget(); | 4075 if_false->MarkAsInlineReturnTarget(); |
| 3986 // AstContext constructor pushes on the context stack. | 4076 // AstContext constructor pushes on the context stack. |
| 3987 test_context = new TestContext(this, if_true, if_false); | 4077 test_context = new TestContext(this, if_true, if_false); |
| 3988 function_return_ = NULL; | 4078 function_return_ = NULL; |
| 3989 } else { | 4079 } else { |
| 3990 // Inlined body is treated as if it occurs in the original call context. | 4080 // Inlined body is treated as if it occurs in the original call context. |
| 3991 function_return_ = graph()->CreateBasicBlock(); | 4081 function_return_ = graph()->CreateBasicBlock(); |
| 3992 function_return_->MarkAsInlineReturnTarget(); | 4082 function_return_->MarkAsInlineReturnTarget(); |
| 3993 } | 4083 } |
| 3994 call_context_ = ast_context(); | 4084 call_context_ = ast_context(); |
| 3995 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code())); | 4085 TypeFeedbackOracle new_oracle( |
| 4086 Handle<Code>(shared->code()), |
| 4087 Handle<Context>(target->context()->global_context())); |
| 3996 oracle_ = &new_oracle; | 4088 oracle_ = &new_oracle; |
| 3997 graph()->info()->SetOsrAstId(AstNode::kNoNumber); | 4089 graph()->info()->SetOsrAstId(AstNode::kNoNumber); |
| 3998 | 4090 |
| 3999 HSubgraph* body = CreateInlinedSubgraph(env, target, function); | 4091 HSubgraph* body = CreateInlinedSubgraph(env, target, function); |
| 4000 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); | 4092 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); |
| 4001 AddToSubgraph(body, function->body()); | 4093 AddToSubgraph(body, function->body()); |
| 4002 if (HasStackOverflow()) { | 4094 if (HasStackOverflow()) { |
| 4003 // Bail out if the inline function did, as we cannot residualize a call | 4095 // Bail out if the inline function did, as we cannot residualize a call |
| 4004 // instead. | 4096 // instead. |
| 4005 delete test_context; | 4097 delete test_context; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 4023 ASSERT(function_return_ != NULL); | 4115 ASSERT(function_return_ != NULL); |
| 4024 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4116 body->exit_block()->AddLeaveInlined(return_value, function_return_); |
| 4025 } else { | 4117 } else { |
| 4026 // The graph builder assumes control can reach both branches of a | 4118 // The graph builder assumes control can reach both branches of a |
| 4027 // test, so we materialize the undefined value and test it rather than | 4119 // test, so we materialize the undefined value and test it rather than |
| 4028 // simply jumping to the false target. | 4120 // simply jumping to the false target. |
| 4029 // | 4121 // |
| 4030 // TODO(3168478): refactor to avoid this. | 4122 // TODO(3168478): refactor to avoid this. |
| 4031 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4123 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 4032 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4124 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 4033 HBranch* branch = | 4125 HTest* test = new HTest(return_value, empty_true, empty_false); |
| 4034 new HBranch(empty_true, empty_false, return_value); | 4126 body->exit_block()->Finish(test); |
| 4035 body->exit_block()->Finish(branch); | |
| 4036 | 4127 |
| 4037 HValue* const no_return_value = NULL; | 4128 HValue* const no_return_value = NULL; |
| 4038 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); | 4129 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); |
| 4039 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); | 4130 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); |
| 4040 } | 4131 } |
| 4041 body->set_exit_block(NULL); | 4132 body->set_exit_block(NULL); |
| 4042 } | 4133 } |
| 4043 | 4134 |
| 4044 // Record the environment at the inlined function call. | 4135 // Record the environment at the inlined function call. |
| 4045 AddSimulate(expr->ReturnId()); | 4136 AddSimulate(expr->ReturnId()); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4094 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4185 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4095 ASSERT(target->IsInlineReturnTarget()); | 4186 ASSERT(target->IsInlineReturnTarget()); |
| 4096 AddInstruction(new HLeaveInlined); | 4187 AddInstruction(new HLeaveInlined); |
| 4097 HEnvironment* outer = last_environment()->outer(); | 4188 HEnvironment* outer = last_environment()->outer(); |
| 4098 if (return_value != NULL) outer->Push(return_value); | 4189 if (return_value != NULL) outer->Push(return_value); |
| 4099 UpdateEnvironment(outer); | 4190 UpdateEnvironment(outer); |
| 4100 Goto(target); | 4191 Goto(target); |
| 4101 } | 4192 } |
| 4102 | 4193 |
| 4103 | 4194 |
| 4104 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4195 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 4196 HValue* receiver, |
| 4197 Handle<Map> receiver_map, |
| 4198 CheckType check_type) { |
| 4199 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| 4105 // Try to inline calls like Math.* as operations in the calling function. | 4200 // Try to inline calls like Math.* as operations in the calling function. |
| 4106 if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; | 4201 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 4107 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4202 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4108 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4203 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4109 switch (id) { | 4204 switch (id) { |
| 4205 case kStringCharCodeAt: |
| 4206 if (argument_count == 2 && check_type == STRING_CHECK) { |
| 4207 HValue* index = Pop(); |
| 4208 HValue* string = Pop(); |
| 4209 ASSERT(!expr->holder().is_null()); |
| 4210 AddInstruction(new HCheckPrototypeMaps( |
| 4211 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), |
| 4212 expr->holder())); |
| 4213 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| 4214 ast_context()->ReturnInstruction(result, expr->id()); |
| 4215 return true; |
| 4216 } |
| 4217 break; |
| 4110 case kMathRound: | 4218 case kMathRound: |
| 4111 case kMathFloor: | 4219 case kMathFloor: |
| 4112 case kMathAbs: | 4220 case kMathAbs: |
| 4113 case kMathSqrt: | 4221 case kMathSqrt: |
| 4114 case kMathLog: | 4222 case kMathLog: |
| 4115 case kMathSin: | 4223 case kMathSin: |
| 4116 case kMathCos: | 4224 case kMathCos: |
| 4117 if (argument_count == 2) { | 4225 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| 4226 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4118 HValue* argument = Pop(); | 4227 HValue* argument = Pop(); |
| 4119 Drop(1); // Receiver. | 4228 Drop(1); // Receiver. |
| 4120 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4229 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4121 op->set_position(expr->position()); | 4230 op->set_position(expr->position()); |
| 4122 ast_context()->ReturnInstruction(op, expr->id()); | 4231 ast_context()->ReturnInstruction(op, expr->id()); |
| 4123 return true; | 4232 return true; |
| 4124 } | 4233 } |
| 4125 break; | 4234 break; |
| 4126 case kMathPow: | 4235 case kMathPow: |
| 4127 if (argument_count == 3) { | 4236 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
| 4237 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4128 HValue* right = Pop(); | 4238 HValue* right = Pop(); |
| 4129 HValue* left = Pop(); | 4239 HValue* left = Pop(); |
| 4130 Pop(); // Pop receiver. | 4240 Pop(); // Pop receiver. |
| 4131 HInstruction* result = NULL; | 4241 HInstruction* result = NULL; |
| 4132 // Use sqrt() if exponent is 0.5 or -0.5. | 4242 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4133 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 4243 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4134 double exponent = HConstant::cast(right)->DoubleValue(); | 4244 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4135 if (exponent == 0.5) { | 4245 if (exponent == 0.5) { |
| 4136 result = new HUnaryMathOperation(left, kMathPowHalf); | 4246 result = new HUnaryMathOperation(left, kMathPowHalf); |
| 4137 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4138 return true; | |
| 4139 } else if (exponent == -0.5) { | 4247 } else if (exponent == -0.5) { |
| 4140 HConstant* double_one = | 4248 HConstant* double_one = |
| 4141 new HConstant(Handle<Object>(Smi::FromInt(1)), | 4249 new HConstant(Handle<Object>(Smi::FromInt(1)), |
| 4142 Representation::Double()); | 4250 Representation::Double()); |
| 4143 AddInstruction(double_one); | 4251 AddInstruction(double_one); |
| 4144 HUnaryMathOperation* square_root = | 4252 HUnaryMathOperation* square_root = |
| 4145 new HUnaryMathOperation(left, kMathPowHalf); | 4253 new HUnaryMathOperation(left, kMathPowHalf); |
| 4146 AddInstruction(square_root); | 4254 AddInstruction(square_root); |
| 4147 // MathPowHalf doesn't have side effects so there's no need for | 4255 // MathPowHalf doesn't have side effects so there's no need for |
| 4148 // an environment simulation here. | 4256 // an environment simulation here. |
| 4149 ASSERT(!square_root->HasSideEffects()); | 4257 ASSERT(!square_root->HasSideEffects()); |
| 4150 result = new HDiv(double_one, square_root); | 4258 result = new HDiv(double_one, square_root); |
| 4151 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4152 return true; | |
| 4153 } else if (exponent == 2.0) { | 4259 } else if (exponent == 2.0) { |
| 4154 result = new HMul(left, left); | 4260 result = new HMul(left, left); |
| 4155 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4156 return true; | |
| 4157 } | 4261 } |
| 4158 } else if (right->IsConstant() && | 4262 } else if (right->IsConstant() && |
| 4159 HConstant::cast(right)->HasInteger32Value() && | 4263 HConstant::cast(right)->HasInteger32Value() && |
| 4160 HConstant::cast(right)->Integer32Value() == 2) { | 4264 HConstant::cast(right)->Integer32Value() == 2) { |
| 4161 result = new HMul(left, left); | 4265 result = new HMul(left, left); |
| 4162 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4163 return true; | |
| 4164 } | 4266 } |
| 4165 | 4267 |
| 4166 result = new HPower(left, right); | 4268 if (result == NULL) { |
| 4269 result = new HPower(left, right); |
| 4270 } |
| 4167 ast_context()->ReturnInstruction(result, expr->id()); | 4271 ast_context()->ReturnInstruction(result, expr->id()); |
| 4168 return true; | 4272 return true; |
| 4169 } | 4273 } |
| 4170 break; | 4274 break; |
| 4171 default: | 4275 default: |
| 4172 // Not yet supported for inlining. | 4276 // Not yet supported for inlining. |
| 4173 break; | 4277 break; |
| 4174 } | 4278 } |
| 4175 return false; | 4279 return false; |
| 4176 } | 4280 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4187 if (!name->IsEqualTo(CStrVector("apply"))) return false; | 4291 if (!name->IsEqualTo(CStrVector("apply"))) return false; |
| 4188 | 4292 |
| 4189 ZoneList<Expression*>* args = expr->arguments(); | 4293 ZoneList<Expression*>* args = expr->arguments(); |
| 4190 if (args->length() != 2) return false; | 4294 if (args->length() != 2) return false; |
| 4191 | 4295 |
| 4192 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 4296 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 4193 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 4297 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 4194 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 4298 HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
| 4195 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 4299 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 4196 | 4300 |
| 4197 if (!expr->IsMonomorphic()) return false; | 4301 if (!expr->IsMonomorphic() || |
| 4302 expr->check_type() != RECEIVER_MAP_CHECK) return false; |
| 4198 | 4303 |
| 4199 // Found pattern f.apply(receiver, arguments). | 4304 // Found pattern f.apply(receiver, arguments). |
| 4200 VisitForValue(prop->obj()); | 4305 VisitForValue(prop->obj()); |
| 4201 if (HasStackOverflow()) return false; | 4306 if (HasStackOverflow()) return false; |
| 4202 HValue* function = Pop(); | 4307 HValue* function = Pop(); |
| 4203 VisitForValue(args->at(0)); | 4308 VisitForValue(args->at(0)); |
| 4204 if (HasStackOverflow()) return false; | 4309 if (HasStackOverflow()) return false; |
| 4205 HValue* receiver = Pop(); | 4310 HValue* receiver = Pop(); |
| 4206 HInstruction* elements = AddInstruction(new HArgumentsElements); | 4311 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4207 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 4312 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 4208 AddCheckConstantFunction(expr, | 4313 AddCheckConstantFunction(expr, |
| 4209 function, | 4314 function, |
| 4210 expr->GetReceiverTypes()->first(), | 4315 expr->GetReceiverTypes()->first(), |
| 4211 true); | 4316 true); |
| 4212 HInstruction* result = | 4317 HInstruction* result = |
| 4213 new HApplyArguments(function, receiver, length, elements); | 4318 new HApplyArguments(function, receiver, length, elements); |
| 4214 result->set_position(expr->position()); | 4319 result->set_position(expr->position()); |
| 4215 ast_context()->ReturnInstruction(result, expr->id()); | 4320 ast_context()->ReturnInstruction(result, expr->id()); |
| 4216 return true; | 4321 return true; |
| 4217 } | 4322 } |
| 4218 | 4323 |
| 4219 | 4324 |
| 4325 static bool HasCustomCallGenerator(Handle<JSFunction> function) { |
| 4326 SharedFunctionInfo* info = function->shared(); |
| 4327 return info->HasBuiltinFunctionId() && |
| 4328 CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id()); |
| 4329 } |
| 4330 |
| 4331 |
| 4220 void HGraphBuilder::VisitCall(Call* expr) { | 4332 void HGraphBuilder::VisitCall(Call* expr) { |
| 4221 Expression* callee = expr->expression(); | 4333 Expression* callee = expr->expression(); |
| 4222 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4334 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4223 HCall* call = NULL; | 4335 HCall* call = NULL; |
| 4224 | 4336 |
| 4225 Property* prop = callee->AsProperty(); | 4337 Property* prop = callee->AsProperty(); |
| 4226 if (prop != NULL) { | 4338 if (prop != NULL) { |
| 4227 if (!prop->key()->IsPropertyName()) { | 4339 if (!prop->key()->IsPropertyName()) { |
| 4228 // Keyed function call. | 4340 // Keyed function call. |
| 4229 VisitArgument(prop->obj()); | 4341 VisitArgument(prop->obj()); |
| 4230 CHECK_BAILOUT; | 4342 CHECK_BAILOUT; |
| 4231 | 4343 |
| 4232 VISIT_FOR_VALUE(prop->key()); | 4344 VISIT_FOR_VALUE(prop->key()); |
| 4233 // Push receiver and key like the non-optimized code generator expects it. | 4345 // Push receiver and key like the non-optimized code generator expects it. |
| 4234 HValue* key = Pop(); | 4346 HValue* key = Pop(); |
| 4235 HValue* receiver = Pop(); | 4347 HValue* receiver = Pop(); |
| 4236 Push(key); | 4348 Push(key); |
| 4237 Push(receiver); | 4349 Push(receiver); |
| 4238 | 4350 |
| 4239 VisitArgumentList(expr->arguments()); | 4351 VisitArgumentList(expr->arguments()); |
| 4240 CHECK_BAILOUT; | 4352 CHECK_BAILOUT; |
| 4241 | 4353 |
| 4242 call = new HCallKeyed(key, argument_count); | 4354 HContext* context = new HContext; |
| 4355 AddInstruction(context); |
| 4356 call = new HCallKeyed(context, key, argument_count); |
| 4243 call->set_position(expr->position()); | 4357 call->set_position(expr->position()); |
| 4244 ProcessCall(call); | 4358 PreProcessCall(call); |
| 4245 Drop(1); // Key. | 4359 Drop(1); // Key. |
| 4246 ast_context()->ReturnInstruction(call, expr->id()); | 4360 ast_context()->ReturnInstruction(call, expr->id()); |
| 4247 return; | 4361 return; |
| 4248 } | 4362 } |
| 4249 | 4363 |
| 4250 // Named function call. | 4364 // Named function call. |
| 4251 expr->RecordTypeFeedback(oracle()); | 4365 expr->RecordTypeFeedback(oracle()); |
| 4252 | 4366 |
| 4253 if (TryCallApply(expr)) return; | 4367 if (TryCallApply(expr)) return; |
| 4254 CHECK_BAILOUT; | 4368 CHECK_BAILOUT; |
| 4255 | 4369 |
| 4256 HValue* receiver = VisitArgument(prop->obj()); | 4370 VisitArgument(prop->obj()); |
| 4257 CHECK_BAILOUT; | 4371 CHECK_BAILOUT; |
| 4258 VisitArgumentList(expr->arguments()); | 4372 VisitArgumentList(expr->arguments()); |
| 4259 CHECK_BAILOUT; | 4373 CHECK_BAILOUT; |
| 4260 | 4374 |
| 4261 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4375 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4262 | 4376 |
| 4263 expr->RecordTypeFeedback(oracle()); | 4377 expr->RecordTypeFeedback(oracle()); |
| 4264 ZoneMapList* types = expr->GetReceiverTypes(); | 4378 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4265 | 4379 |
| 4380 HValue* receiver = |
| 4381 environment()->ExpressionStackAt(expr->arguments()->length()); |
| 4266 if (expr->IsMonomorphic()) { | 4382 if (expr->IsMonomorphic()) { |
| 4267 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4383 Handle<Map> receiver_map = |
| 4268 | 4384 (types == NULL) ? Handle<Map>::null() : types->first(); |
| 4269 if (TryMathFunctionInline(expr)) { | 4385 if (TryInlineBuiltinFunction(expr, |
| 4386 receiver, |
| 4387 receiver_map, |
| 4388 expr->check_type())) { |
| 4270 return; | 4389 return; |
| 4271 } else if (TryInline(expr)) { | |
| 4272 if (subgraph()->HasExit()) { | |
| 4273 HValue* return_value = Pop(); | |
| 4274 // If we inlined a function in a test context then we need to emit | |
| 4275 // a simulate here to shadow the ones at the end of the | |
| 4276 // predecessor blocks. Those environments contain the return | |
| 4277 // value on top and do not correspond to any actual state of the | |
| 4278 // unoptimized code. | |
| 4279 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4280 ast_context()->ReturnValue(return_value); | |
| 4281 } | |
| 4282 return; | |
| 4283 } else { | |
| 4284 // Check for bailout, as the TryInline call in the if condition above | |
| 4285 // might return false due to bailout during hydrogen processing. | |
| 4286 CHECK_BAILOUT; | |
| 4287 call = new HCallConstantFunction(expr->target(), argument_count); | |
| 4288 } | 4390 } |
| 4289 | 4391 |
| 4392 if (HasCustomCallGenerator(expr->target()) || |
| 4393 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 4394 // When the target has a custom call IC generator, use the IC, |
| 4395 // because it is likely to generate better code. Also use the |
| 4396 // IC when a primitive receiver check is required. |
| 4397 HContext* context = new HContext; |
| 4398 AddInstruction(context); |
| 4399 call = new HCallNamed(context, name, argument_count); |
| 4400 } else { |
| 4401 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4402 |
| 4403 if (TryInline(expr)) { |
| 4404 if (subgraph()->HasExit()) { |
| 4405 HValue* return_value = Pop(); |
| 4406 // If we inlined a function in a test context then we need to emit |
| 4407 // a simulate here to shadow the ones at the end of the |
| 4408 // predecessor blocks. Those environments contain the return |
| 4409 // value on top and do not correspond to any actual state of the |
| 4410 // unoptimized code. |
| 4411 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4412 ast_context()->ReturnValue(return_value); |
| 4413 } |
| 4414 return; |
| 4415 } else { |
| 4416 // Check for bailout, as the TryInline call in the if condition above |
| 4417 // might return false due to bailout during hydrogen processing. |
| 4418 CHECK_BAILOUT; |
| 4419 call = new HCallConstantFunction(expr->target(), argument_count); |
| 4420 } |
| 4421 } |
| 4290 } else if (types != NULL && types->length() > 1) { | 4422 } else if (types != NULL && types->length() > 1) { |
| 4423 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4291 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4424 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4292 return; | 4425 return; |
| 4293 | 4426 |
| 4294 } else { | 4427 } else { |
| 4295 call = new HCallNamed(name, argument_count); | 4428 HContext* context = new HContext; |
| 4429 AddInstruction(context); |
| 4430 call = new HCallNamed(context, name, argument_count); |
| 4296 } | 4431 } |
| 4297 | 4432 |
| 4298 } else { | 4433 } else { |
| 4299 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4434 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4300 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4435 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); |
| 4301 | 4436 |
| 4302 if (!global_call) { | 4437 if (!global_call) { |
| 4303 ++argument_count; | 4438 ++argument_count; |
| 4304 VisitArgument(expr->expression()); | 4439 VisitArgument(expr->expression()); |
| 4305 CHECK_BAILOUT; | 4440 CHECK_BAILOUT; |
| 4306 } | 4441 } |
| 4307 | 4442 |
| 4308 if (global_call) { | 4443 if (global_call) { |
| 4309 // If there is a global property cell for the name at compile time and | 4444 // If there is a global property cell for the name at compile time and |
| 4310 // access check is not enabled we assume that the function will not change | 4445 // access check is not enabled we assume that the function will not change |
| 4311 // and generate optimized code for calling the function. | 4446 // and generate optimized code for calling the function. |
| 4312 CompilationInfo* info = graph()->info(); | 4447 CompilationInfo* info = graph()->info(); |
| 4313 bool known_global_function = info->has_global_object() && | 4448 bool known_global_function = info->has_global_object() && |
| 4314 !info->global_object()->IsAccessCheckNeeded() && | 4449 !info->global_object()->IsAccessCheckNeeded() && |
| 4315 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), | 4450 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), |
| 4316 var->name()); | 4451 var->name()); |
| 4317 if (known_global_function) { | 4452 if (known_global_function) { |
| 4318 // Push the global object instead of the global receiver because | 4453 // Push the global object instead of the global receiver because |
| 4319 // code generated by the full code generator expects it. | 4454 // code generated by the full code generator expects it. |
| 4320 PushAndAdd(new HGlobalObject); | 4455 HContext* context = new HContext; |
| 4456 HGlobalObject* global_object = new HGlobalObject(context); |
| 4457 AddInstruction(context); |
| 4458 PushAndAdd(global_object); |
| 4321 VisitArgumentList(expr->arguments()); | 4459 VisitArgumentList(expr->arguments()); |
| 4322 CHECK_BAILOUT; | 4460 CHECK_BAILOUT; |
| 4323 | 4461 |
| 4324 VISIT_FOR_VALUE(expr->expression()); | 4462 VISIT_FOR_VALUE(expr->expression()); |
| 4325 HValue* function = Pop(); | 4463 HValue* function = Pop(); |
| 4326 AddInstruction(new HCheckFunction(function, expr->target())); | 4464 AddInstruction(new HCheckFunction(function, expr->target())); |
| 4327 | 4465 |
| 4328 // Replace the global object with the global receiver. | 4466 // Replace the global object with the global receiver. |
| 4329 HGlobalReceiver* global_receiver = new HGlobalReceiver; | 4467 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); |
| 4330 // Index of the receiver from the top of the expression stack. | 4468 // Index of the receiver from the top of the expression stack. |
| 4331 const int receiver_index = argument_count - 1; | 4469 const int receiver_index = argument_count - 1; |
| 4332 AddInstruction(global_receiver); | 4470 AddInstruction(global_receiver); |
| 4333 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4471 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 4334 IsGlobalObject()); | 4472 IsGlobalObject()); |
| 4335 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4473 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 4336 | 4474 |
| 4337 if (TryInline(expr)) { | 4475 if (TryInline(expr)) { |
| 4338 if (subgraph()->HasExit()) { | 4476 if (subgraph()->HasExit()) { |
| 4339 HValue* return_value = Pop(); | 4477 HValue* return_value = Pop(); |
| 4340 // If we inlined a function in a test context then we need to | 4478 // If we inlined a function in a test context then we need to |
| 4341 // emit a simulate here to shadow the ones at the end of the | 4479 // emit a simulate here to shadow the ones at the end of the |
| 4342 // predecessor blocks. Those environments contain the return | 4480 // predecessor blocks. Those environments contain the return |
| 4343 // value on top and do not correspond to any actual state of the | 4481 // value on top and do not correspond to any actual state of the |
| 4344 // unoptimized code. | 4482 // unoptimized code. |
| 4345 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | 4483 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4346 ast_context()->ReturnValue(return_value); | 4484 ast_context()->ReturnValue(return_value); |
| 4347 } | 4485 } |
| 4348 return; | 4486 return; |
| 4349 } | 4487 } |
| 4350 // Check for bailout, as trying to inline might fail due to bailout | 4488 // Check for bailout, as trying to inline might fail due to bailout |
| 4351 // during hydrogen processing. | 4489 // during hydrogen processing. |
| 4352 CHECK_BAILOUT; | 4490 CHECK_BAILOUT; |
| 4353 | 4491 |
| 4354 call = new HCallKnownGlobal(expr->target(), argument_count); | 4492 call = new HCallKnownGlobal(expr->target(), argument_count); |
| 4355 } else { | 4493 } else { |
| 4356 PushAndAdd(new HGlobalObject); | 4494 HContext* context = new HContext; |
| 4495 AddInstruction(context); |
| 4496 PushAndAdd(new HGlobalObject(context)); |
| 4357 VisitArgumentList(expr->arguments()); | 4497 VisitArgumentList(expr->arguments()); |
| 4358 CHECK_BAILOUT; | 4498 CHECK_BAILOUT; |
| 4359 | 4499 |
| 4360 call = new HCallGlobal(var->name(), argument_count); | 4500 call = new HCallGlobal(context, var->name(), argument_count); |
| 4361 } | 4501 } |
| 4362 | 4502 |
| 4363 } else { | 4503 } else { |
| 4364 PushAndAdd(new HGlobalReceiver); | 4504 HContext* context = new HContext; |
| 4505 HGlobalObject* global_object = new HGlobalObject(context); |
| 4506 AddInstruction(context); |
| 4507 AddInstruction(global_object); |
| 4508 PushAndAdd(new HGlobalReceiver(global_object)); |
| 4365 VisitArgumentList(expr->arguments()); | 4509 VisitArgumentList(expr->arguments()); |
| 4366 CHECK_BAILOUT; | 4510 CHECK_BAILOUT; |
| 4367 | 4511 |
| 4368 call = new HCallFunction(argument_count); | 4512 call = new HCallFunction(context, argument_count); |
| 4369 } | 4513 } |
| 4370 } | 4514 } |
| 4371 | 4515 |
| 4372 call->set_position(expr->position()); | 4516 call->set_position(expr->position()); |
| 4373 ProcessCall(call); | 4517 PreProcessCall(call); |
| 4374 ast_context()->ReturnInstruction(call, expr->id()); | 4518 ast_context()->ReturnInstruction(call, expr->id()); |
| 4375 } | 4519 } |
| 4376 | 4520 |
| 4377 | 4521 |
| 4378 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 4522 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 4379 // The constructor function is also used as the receiver argument to the | 4523 // The constructor function is also used as the receiver argument to the |
| 4380 // JS construct call builtin. | 4524 // JS construct call builtin. |
| 4381 VisitArgument(expr->expression()); | 4525 VisitArgument(expr->expression()); |
| 4382 CHECK_BAILOUT; | 4526 CHECK_BAILOUT; |
| 4383 VisitArgumentList(expr->arguments()); | 4527 VisitArgumentList(expr->arguments()); |
| 4384 CHECK_BAILOUT; | 4528 CHECK_BAILOUT; |
| 4385 | 4529 |
| 4386 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 4530 HContext* context = new HContext; |
| 4387 HCall* call = new HCallNew(argument_count); | 4531 AddInstruction(context); |
| 4532 |
| 4533 // The constructor is both an operand to the instruction and an argument |
| 4534 // to the construct call. |
| 4535 int arg_count = expr->arguments()->length() + 1; // Plus constructor. |
| 4536 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1); |
| 4537 HCall* call = new HCallNew(context, constructor, arg_count); |
| 4388 call->set_position(expr->position()); | 4538 call->set_position(expr->position()); |
| 4389 ProcessCall(call); | 4539 PreProcessCall(call); |
| 4390 ast_context()->ReturnInstruction(call, expr->id()); | 4540 ast_context()->ReturnInstruction(call, expr->id()); |
| 4391 } | 4541 } |
| 4392 | 4542 |
| 4393 | 4543 |
| 4394 // Support for generating inlined runtime functions. | 4544 // Support for generating inlined runtime functions. |
| 4395 | 4545 |
| 4396 // Lookup table for generators for runtime calls that are generated inline. | 4546 // Lookup table for generators for runtime calls that are generated inline. |
| 4397 // Elements of the table are member pointers to functions of HGraphBuilder. | 4547 // Elements of the table are member pointers to functions of HGraphBuilder. |
| 4398 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 4548 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 4399 &HGraphBuilder::Generate##Name, | 4549 &HGraphBuilder::Generate##Name, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4433 ASSERT(static_cast<size_t>(lookup_index) < | 4583 ASSERT(static_cast<size_t>(lookup_index) < |
| 4434 ARRAY_SIZE(kInlineFunctionGenerators)); | 4584 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 4435 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 4585 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| 4436 | 4586 |
| 4437 // Call the inline code generator using the pointer-to-member. | 4587 // Call the inline code generator using the pointer-to-member. |
| 4438 (this->*generator)(argument_count, expr->id()); | 4588 (this->*generator)(argument_count, expr->id()); |
| 4439 } else { | 4589 } else { |
| 4440 ASSERT(function->intrinsic_type == Runtime::RUNTIME); | 4590 ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
| 4441 HCall* call = new HCallRuntime(name, expr->function(), argument_count); | 4591 HCall* call = new HCallRuntime(name, expr->function(), argument_count); |
| 4442 call->set_position(RelocInfo::kNoPosition); | 4592 call->set_position(RelocInfo::kNoPosition); |
| 4443 ProcessCall(call); | 4593 PreProcessCall(call); |
| 4444 ast_context()->ReturnInstruction(call, expr->id()); | 4594 ast_context()->ReturnInstruction(call, expr->id()); |
| 4445 } | 4595 } |
| 4446 } | 4596 } |
| 4447 | 4597 |
| 4448 | 4598 |
| 4449 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4599 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4450 Token::Value op = expr->op(); | 4600 Token::Value op = expr->op(); |
| 4451 if (op == Token::VOID) { | 4601 if (op == Token::VOID) { |
| 4452 VISIT_FOR_EFFECT(expr->expression()); | 4602 VISIT_FOR_EFFECT(expr->expression()); |
| 4453 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 4603 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4454 } else if (op == Token::DELETE) { | 4604 } else if (op == Token::DELETE) { |
| 4455 Property* prop = expr->expression()->AsProperty(); | 4605 Property* prop = expr->expression()->AsProperty(); |
| 4456 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4606 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4457 if (prop == NULL && var == NULL) { | 4607 if (prop == NULL && var == NULL) { |
| 4458 // Result of deleting non-property, non-variable reference is true. | 4608 // Result of deleting non-property, non-variable reference is true. |
| 4459 // Evaluate the subexpression for side effects. | 4609 // Evaluate the subexpression for side effects. |
| 4460 VISIT_FOR_EFFECT(expr->expression()); | 4610 VISIT_FOR_EFFECT(expr->expression()); |
| 4461 ast_context()->ReturnValue(graph()->GetConstantTrue()); | 4611 ast_context()->ReturnValue(graph()->GetConstantTrue()); |
| 4462 } else if (var != NULL && | 4612 } else if (var != NULL && |
| 4463 !var->is_global() && | 4613 !var->is_global() && |
| 4464 var->AsSlot() != NULL && | 4614 var->AsSlot() != NULL && |
| 4465 var->AsSlot()->type() != Slot::LOOKUP) { | 4615 var->AsSlot()->type() != Slot::LOOKUP) { |
| 4466 // Result of deleting non-global, non-dynamic variables is false. | 4616 // Result of deleting non-global, non-dynamic variables is false. |
| 4467 // The subexpression does not have side effects. | 4617 // The subexpression does not have side effects. |
| 4468 ast_context()->ReturnValue(graph()->GetConstantFalse()); | 4618 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4469 } else if (prop != NULL) { | 4619 } else if (prop != NULL) { |
| 4470 VISIT_FOR_VALUE(prop->obj()); | 4620 if (prop->is_synthetic()) { |
| 4471 VISIT_FOR_VALUE(prop->key()); | 4621 // Result of deleting parameters is false, even when they rewrite |
| 4472 HValue* key = Pop(); | 4622 // to accesses on the arguments object. |
| 4473 HValue* obj = Pop(); | 4623 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4474 ast_context()->ReturnInstruction(new HDeleteProperty(obj, key), | 4624 } else { |
| 4475 expr->id()); | 4625 VISIT_FOR_VALUE(prop->obj()); |
| 4626 VISIT_FOR_VALUE(prop->key()); |
| 4627 HValue* key = Pop(); |
| 4628 HValue* obj = Pop(); |
| 4629 HDeleteProperty* instr = new HDeleteProperty(obj, key); |
| 4630 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4631 } |
| 4476 } else if (var->is_global()) { | 4632 } else if (var->is_global()) { |
| 4477 BAILOUT("delete with global variable"); | 4633 BAILOUT("delete with global variable"); |
| 4478 } else { | 4634 } else { |
| 4479 BAILOUT("delete with non-global variable"); | 4635 BAILOUT("delete with non-global variable"); |
| 4480 } | 4636 } |
| 4481 } else if (op == Token::NOT) { | 4637 } else if (op == Token::NOT) { |
| 4482 if (ast_context()->IsTest()) { | 4638 if (ast_context()->IsTest()) { |
| 4483 TestContext* context = TestContext::cast(ast_context()); | 4639 TestContext* context = TestContext::cast(ast_context()); |
| 4484 VisitForControl(expr->expression(), | 4640 VisitForControl(expr->expression(), |
| 4485 context->if_false(), | 4641 context->if_false(), |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4545 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { | 4701 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 4546 IncrementOperation* increment = expr->increment(); | 4702 IncrementOperation* increment = expr->increment(); |
| 4547 Expression* target = increment->expression(); | 4703 Expression* target = increment->expression(); |
| 4548 VariableProxy* proxy = target->AsVariableProxy(); | 4704 VariableProxy* proxy = target->AsVariableProxy(); |
| 4549 Variable* var = proxy->AsVariable(); | 4705 Variable* var = proxy->AsVariable(); |
| 4550 Property* prop = target->AsProperty(); | 4706 Property* prop = target->AsProperty(); |
| 4551 ASSERT(var == NULL || prop == NULL); | 4707 ASSERT(var == NULL || prop == NULL); |
| 4552 bool inc = expr->op() == Token::INC; | 4708 bool inc = expr->op() == Token::INC; |
| 4553 | 4709 |
| 4554 if (var != NULL) { | 4710 if (var != NULL) { |
| 4555 if (!var->is_global() && !var->IsStackAllocated()) { | |
| 4556 BAILOUT("non-stack/non-global variable in count operation"); | |
| 4557 } | |
| 4558 | |
| 4559 VISIT_FOR_VALUE(target); | 4711 VISIT_FOR_VALUE(target); |
| 4560 | 4712 |
| 4561 // Match the full code generator stack by simulating an extra stack | 4713 // Match the full code generator stack by simulating an extra stack |
| 4562 // element for postfix operations in a non-effect context. | 4714 // element for postfix operations in a non-effect context. |
| 4563 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); | 4715 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
| 4564 HValue* before = has_extra ? Top() : Pop(); | 4716 HValue* before = has_extra ? Top() : Pop(); |
| 4565 HInstruction* after = BuildIncrement(before, inc); | 4717 HInstruction* after = BuildIncrement(before, inc); |
| 4566 AddInstruction(after); | 4718 AddInstruction(after); |
| 4567 Push(after); | 4719 Push(after); |
| 4568 | 4720 |
| 4569 if (var->is_global()) { | 4721 if (var->is_global()) { |
| 4570 HandleGlobalVariableAssignment(var, | 4722 HandleGlobalVariableAssignment(var, |
| 4571 after, | 4723 after, |
| 4572 expr->position(), | 4724 expr->position(), |
| 4573 expr->AssignmentId()); | 4725 expr->AssignmentId()); |
| 4726 } else if (var->IsStackAllocated()) { |
| 4727 Bind(var, after); |
| 4728 } else if (var->IsContextSlot()) { |
| 4729 HValue* context = BuildContextChainWalk(var); |
| 4730 int index = var->AsSlot()->index(); |
| 4731 HStoreContextSlot* instr = new HStoreContextSlot(context, index, after); |
| 4732 AddInstruction(instr); |
| 4733 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4574 } else { | 4734 } else { |
| 4575 ASSERT(var->IsStackAllocated()); | 4735 BAILOUT("lookup variable in count operation"); |
| 4576 Bind(var, after); | |
| 4577 } | 4736 } |
| 4578 Drop(has_extra ? 2 : 1); | 4737 Drop(has_extra ? 2 : 1); |
| 4579 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4738 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4580 | 4739 |
| 4581 } else if (prop != NULL) { | 4740 } else if (prop != NULL) { |
| 4582 prop->RecordTypeFeedback(oracle()); | 4741 prop->RecordTypeFeedback(oracle()); |
| 4583 | 4742 |
| 4584 if (prop->key()->IsPropertyName()) { | 4743 if (prop->key()->IsPropertyName()) { |
| 4585 // Named property. | 4744 // Named property. |
| 4586 | 4745 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4645 if (load->HasSideEffects()) AddSimulate(increment->id()); | 4804 if (load->HasSideEffects()) AddSimulate(increment->id()); |
| 4646 | 4805 |
| 4647 HValue* before = Pop(); | 4806 HValue* before = Pop(); |
| 4648 // There is no deoptimization to after the increment, so we don't need | 4807 // There is no deoptimization to after the increment, so we don't need |
| 4649 // to simulate the expression stack after this instruction. | 4808 // to simulate the expression stack after this instruction. |
| 4650 HInstruction* after = BuildIncrement(before, inc); | 4809 HInstruction* after = BuildIncrement(before, inc); |
| 4651 AddInstruction(after); | 4810 AddInstruction(after); |
| 4652 | 4811 |
| 4653 HInstruction* store = is_fast_elements | 4812 HInstruction* store = is_fast_elements |
| 4654 ? BuildStoreKeyedFastElement(obj, key, after, prop) | 4813 ? BuildStoreKeyedFastElement(obj, key, after, prop) |
| 4655 : new HStoreKeyedGeneric(obj, key, after); | 4814 : BuildStoreKeyedGeneric(obj, key, after); |
| 4656 AddInstruction(store); | 4815 AddInstruction(store); |
| 4657 | 4816 |
| 4658 // Drop the key from the bailout environment. Overwrite the receiver | 4817 // Drop the key from the bailout environment. Overwrite the receiver |
| 4659 // with the result of the operation, and the placeholder with the | 4818 // with the result of the operation, and the placeholder with the |
| 4660 // original value if necessary. | 4819 // original value if necessary. |
| 4661 Drop(1); | 4820 Drop(1); |
| 4662 environment()->SetExpressionStackAt(0, after); | 4821 environment()->SetExpressionStackAt(0, after); |
| 4663 if (has_extra) environment()->SetExpressionStackAt(1, before); | 4822 if (has_extra) environment()->SetExpressionStackAt(1, before); |
| 4664 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 4823 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4665 Drop(has_extra ? 2 : 1); | 4824 Drop(has_extra ? 2 : 1); |
| 4666 | 4825 |
| 4667 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4826 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4668 } | 4827 } |
| 4669 | 4828 |
| 4670 } else { | 4829 } else { |
| 4671 BAILOUT("invalid lhs in count operation"); | 4830 BAILOUT("invalid lhs in count operation"); |
| 4672 } | 4831 } |
| 4673 } | 4832 } |
| 4674 | 4833 |
| 4675 | 4834 |
| 4835 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, |
| 4836 HValue* index) { |
| 4837 AddInstruction(new HCheckNonSmi(string)); |
| 4838 AddInstruction(new HCheckInstanceType( |
| 4839 string, FIRST_STRING_TYPE, LAST_STRING_TYPE)); |
| 4840 HStringLength* length = new HStringLength(string); |
| 4841 AddInstruction(length); |
| 4842 AddInstruction(new HBoundsCheck(index, length)); |
| 4843 return new HStringCharCodeAt(string, index); |
| 4844 } |
| 4845 |
| 4846 |
| 4676 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 4847 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4677 HValue* left, | 4848 HValue* left, |
| 4678 HValue* right) { | 4849 HValue* right) { |
| 4679 HInstruction* instr = NULL; | 4850 HInstruction* instr = NULL; |
| 4680 switch (expr->op()) { | 4851 switch (expr->op()) { |
| 4681 case Token::ADD: | 4852 case Token::ADD: |
| 4682 instr = new HAdd(left, right); | 4853 instr = new HAdd(left, right); |
| 4683 break; | 4854 break; |
| 4684 case Token::SUB: | 4855 case Token::SUB: |
| 4685 instr = new HSub(left, right); | 4856 instr = new HSub(left, right); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 4707 break; | 4878 break; |
| 4708 case Token::SHR: | 4879 case Token::SHR: |
| 4709 instr = new HShr(left, right); | 4880 instr = new HShr(left, right); |
| 4710 break; | 4881 break; |
| 4711 case Token::SHL: | 4882 case Token::SHL: |
| 4712 instr = new HShl(left, right); | 4883 instr = new HShl(left, right); |
| 4713 break; | 4884 break; |
| 4714 default: | 4885 default: |
| 4715 UNREACHABLE(); | 4886 UNREACHABLE(); |
| 4716 } | 4887 } |
| 4717 TypeInfo info = oracle()->BinaryType(expr, TypeFeedbackOracle::RESULT); | 4888 TypeInfo info = oracle()->BinaryType(expr); |
| 4718 // If we hit an uninitialized binary op stub we will get type info | 4889 // If we hit an uninitialized binary op stub we will get type info |
| 4719 // for a smi operation. If one of the operands is a constant string | 4890 // for a smi operation. If one of the operands is a constant string |
| 4720 // do not generate code assuming it is a smi operation. | 4891 // do not generate code assuming it is a smi operation. |
| 4721 if (info.IsSmi() && | 4892 if (info.IsSmi() && |
| 4722 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || | 4893 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || |
| 4723 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { | 4894 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { |
| 4724 return instr; | 4895 return instr; |
| 4725 } | 4896 } |
| 4726 if (FLAG_trace_representation) { | 4897 if (FLAG_trace_representation) { |
| 4727 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); | 4898 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); |
| 4728 } | 4899 } |
| 4729 AssumeRepresentation(instr, ToRepresentation(info)); | 4900 Representation rep = ToRepresentation(info); |
| 4901 // We only generate either int32 or generic tagged bitwise operations. |
| 4902 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { |
| 4903 rep = Representation::Integer32(); |
| 4904 } |
| 4905 AssumeRepresentation(instr, rep); |
| 4730 return instr; | 4906 return instr; |
| 4731 } | 4907 } |
| 4732 | 4908 |
| 4733 | 4909 |
| 4734 // Check for the form (%_ClassOf(foo) === 'BarClass'). | 4910 // Check for the form (%_ClassOf(foo) === 'BarClass'). |
| 4735 static bool IsClassOfTest(CompareOperation* expr) { | 4911 static bool IsClassOfTest(CompareOperation* expr) { |
| 4736 if (expr->op() != Token::EQ_STRICT) return false; | 4912 if (expr->op() != Token::EQ_STRICT) return false; |
| 4737 CallRuntime* call = expr->left()->AsCallRuntime(); | 4913 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 4738 if (call == NULL) return false; | 4914 if (call == NULL) return false; |
| 4739 Literal* literal = expr->right()->AsLiteral(); | 4915 Literal* literal = expr->right()->AsLiteral(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4800 | 4976 |
| 4801 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { | 4977 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { |
| 4802 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { | 4978 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { |
| 4803 if (FLAG_trace_representation) { | 4979 if (FLAG_trace_representation) { |
| 4804 PrintF("Assume representation for %s to be %s (%d)\n", | 4980 PrintF("Assume representation for %s to be %s (%d)\n", |
| 4805 value->Mnemonic(), | 4981 value->Mnemonic(), |
| 4806 r.Mnemonic(), | 4982 r.Mnemonic(), |
| 4807 graph_->GetMaximumValueID()); | 4983 graph_->GetMaximumValueID()); |
| 4808 } | 4984 } |
| 4809 value->ChangeRepresentation(r); | 4985 value->ChangeRepresentation(r); |
| 4810 // The representation of the value is dictated by type feedback. | 4986 // The representation of the value is dictated by type feedback and |
| 4987 // will not be changed later. |
| 4811 value->ClearFlag(HValue::kFlexibleRepresentation); | 4988 value->ClearFlag(HValue::kFlexibleRepresentation); |
| 4812 } else if (FLAG_trace_representation) { | 4989 } else if (FLAG_trace_representation) { |
| 4813 PrintF("No representation assumed\n"); | 4990 PrintF("No representation assumed\n"); |
| 4814 } | 4991 } |
| 4815 } | 4992 } |
| 4816 | 4993 |
| 4817 | 4994 |
| 4818 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { | 4995 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { |
| 4819 if (info.IsSmi()) return Representation::Integer32(); | 4996 if (info.IsSmi()) return Representation::Integer32(); |
| 4820 if (info.IsInteger32()) return Representation::Integer32(); | 4997 if (info.IsInteger32()) return Representation::Integer32(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4852 return; | 5029 return; |
| 4853 } | 5030 } |
| 4854 | 5031 |
| 4855 VISIT_FOR_VALUE(expr->left()); | 5032 VISIT_FOR_VALUE(expr->left()); |
| 4856 VISIT_FOR_VALUE(expr->right()); | 5033 VISIT_FOR_VALUE(expr->right()); |
| 4857 | 5034 |
| 4858 HValue* right = Pop(); | 5035 HValue* right = Pop(); |
| 4859 HValue* left = Pop(); | 5036 HValue* left = Pop(); |
| 4860 Token::Value op = expr->op(); | 5037 Token::Value op = expr->op(); |
| 4861 | 5038 |
| 4862 TypeInfo info = oracle()->CompareType(expr, TypeFeedbackOracle::RESULT); | 5039 TypeInfo info = oracle()->CompareType(expr); |
| 4863 HInstruction* instr = NULL; | 5040 HInstruction* instr = NULL; |
| 4864 if (op == Token::INSTANCEOF) { | 5041 if (op == Token::INSTANCEOF) { |
| 4865 instr = new HInstanceOf(left, right); | 5042 // Check to see if the rhs of the instanceof is a global function not |
| 5043 // residing in new space. If it is we assume that the function will stay the |
| 5044 // same. |
| 5045 Handle<JSFunction> target = Handle<JSFunction>::null(); |
| 5046 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); |
| 5047 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); |
| 5048 CompilationInfo* info = graph()->info(); |
| 5049 if (global_function && |
| 5050 info->has_global_object() && |
| 5051 !info->global_object()->IsAccessCheckNeeded()) { |
| 5052 Handle<String> name = var->name(); |
| 5053 Handle<GlobalObject> global(info->global_object()); |
| 5054 LookupResult lookup; |
| 5055 global->Lookup(*name, &lookup); |
| 5056 if (lookup.IsProperty() && |
| 5057 lookup.type() == NORMAL && |
| 5058 lookup.GetValue()->IsJSFunction()) { |
| 5059 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
| 5060 // If the function is in new space we assume it's more likely to |
| 5061 // change and thus prefer the general IC code. |
| 5062 if (!Heap::InNewSpace(*candidate)) { |
| 5063 target = candidate; |
| 5064 } |
| 5065 } |
| 5066 } |
| 5067 |
| 5068 // If the target is not null we have found a known global function that is |
| 5069 // assumed to stay the same for this instanceof. |
| 5070 if (target.is_null()) { |
| 5071 HContext* context = new HContext; |
| 5072 AddInstruction(context); |
| 5073 instr = new HInstanceOf(context, left, right); |
| 5074 } else { |
| 5075 AddInstruction(new HCheckFunction(right, target)); |
| 5076 instr = new HInstanceOfKnownGlobal(left, target); |
| 5077 } |
| 4866 } else if (op == Token::IN) { | 5078 } else if (op == Token::IN) { |
| 4867 BAILOUT("Unsupported comparison: in"); | 5079 BAILOUT("Unsupported comparison: in"); |
| 4868 } else if (info.IsNonPrimitive()) { | 5080 } else if (info.IsNonPrimitive()) { |
| 4869 switch (op) { | 5081 switch (op) { |
| 4870 case Token::EQ: | 5082 case Token::EQ: |
| 4871 case Token::EQ_STRICT: { | 5083 case Token::EQ_STRICT: { |
| 4872 AddInstruction(new HCheckNonSmi(left)); | 5084 AddInstruction(new HCheckNonSmi(left)); |
| 4873 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); | 5085 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); |
| 4874 AddInstruction(new HCheckNonSmi(right)); | 5086 AddInstruction(new HCheckNonSmi(right)); |
| 4875 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); | 5087 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4994 } | 5206 } |
| 4995 | 5207 |
| 4996 | 5208 |
| 4997 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 5209 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 4998 int argument_count, | 5210 int argument_count, |
| 4999 int ast_id) { | 5211 int ast_id) { |
| 5000 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 5212 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 5001 } | 5213 } |
| 5002 | 5214 |
| 5003 | 5215 |
| 5004 // Support for construct call checks. | 5216 // Support for construct call checks. |
| 5005 void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { | 5217 void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { |
| 5006 BAILOUT("inlined runtime function: IsConstructCall"); | 5218 ASSERT(argument_count == 0); |
| 5219 ast_context()->ReturnInstruction(new HIsConstructCall, ast_id); |
| 5007 } | 5220 } |
| 5008 | 5221 |
| 5009 | 5222 |
| 5010 // Support for arguments.length and arguments[?]. | 5223 // Support for arguments.length and arguments[?]. |
| 5011 void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { | 5224 void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { |
| 5012 ASSERT(argument_count == 0); | 5225 ASSERT(argument_count == 0); |
| 5013 HInstruction* elements = AddInstruction(new HArgumentsElements); | 5226 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 5014 HArgumentsLength* result = new HArgumentsLength(elements); | 5227 HArgumentsLength* result = new HArgumentsLength(elements); |
| 5015 ast_context()->ReturnInstruction(result, ast_id); | 5228 ast_context()->ReturnInstruction(result, ast_id); |
| 5016 } | 5229 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 5042 } | 5255 } |
| 5043 | 5256 |
| 5044 | 5257 |
| 5045 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { | 5258 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { |
| 5046 BAILOUT("inlined runtime function: SetValueOf"); | 5259 BAILOUT("inlined runtime function: SetValueOf"); |
| 5047 } | 5260 } |
| 5048 | 5261 |
| 5049 | 5262 |
| 5050 // Fast support for charCodeAt(n). | 5263 // Fast support for charCodeAt(n). |
| 5051 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { | 5264 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { |
| 5052 BAILOUT("inlined runtime function: StringCharCodeAt"); | 5265 ASSERT(argument_count == 2); |
| 5266 HValue* index = Pop(); |
| 5267 HValue* string = Pop(); |
| 5268 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); |
| 5269 ast_context()->ReturnInstruction(result, ast_id); |
| 5053 } | 5270 } |
| 5054 | 5271 |
| 5055 | 5272 |
| 5056 // Fast support for string.charAt(n) and string[n]. | 5273 // Fast support for string.charAt(n) and string[n]. |
| 5057 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, | 5274 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, |
| 5058 int ast_id) { | 5275 int ast_id) { |
| 5059 BAILOUT("inlined runtime function: StringCharFromCode"); | 5276 BAILOUT("inlined runtime function: StringCharFromCode"); |
| 5060 } | 5277 } |
| 5061 | 5278 |
| 5062 | 5279 |
| 5063 // Fast support for string.charAt(n) and string[n]. | 5280 // Fast support for string.charAt(n) and string[n]. |
| 5064 void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { | 5281 void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { |
| 5065 ASSERT_EQ(2, argument_count); | 5282 ASSERT_EQ(2, argument_count); |
| 5066 PushArgumentsForStubCall(argument_count); | 5283 HContext* context = new HContext; |
| 5067 HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count); | 5284 AddInstruction(context); |
| 5285 HCallStub* result = |
| 5286 new HCallStub(context, CodeStub::StringCharAt, argument_count); |
| 5287 PreProcessCall(result); |
| 5068 ast_context()->ReturnInstruction(result, ast_id); | 5288 ast_context()->ReturnInstruction(result, ast_id); |
| 5069 } | 5289 } |
| 5070 | 5290 |
| 5071 | 5291 |
| 5072 // Fast support for object equality testing. | 5292 // Fast support for object equality testing. |
| 5073 void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { | 5293 void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { |
| 5074 ASSERT(argument_count == 2); | 5294 ASSERT(argument_count == 2); |
| 5075 HValue* right = Pop(); | 5295 HValue* right = Pop(); |
| 5076 HValue* left = Pop(); | 5296 HValue* left = Pop(); |
| 5077 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); | 5297 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); |
| 5078 ast_context()->ReturnInstruction(result, ast_id); | 5298 ast_context()->ReturnInstruction(result, ast_id); |
| 5079 } | 5299 } |
| 5080 | 5300 |
| 5081 | 5301 |
| 5082 void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { | 5302 void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { |
| 5083 UNREACHABLE(); // We caught this in VisitCallRuntime. | 5303 UNREACHABLE(); // We caught this in VisitCallRuntime. |
| 5084 } | 5304 } |
| 5085 | 5305 |
| 5086 | 5306 |
| 5087 // Fast support for Math.random(). | 5307 // Fast support for Math.random(). |
| 5088 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { | 5308 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { |
| 5089 BAILOUT("inlined runtime function: RandomHeapNumber"); | 5309 BAILOUT("inlined runtime function: RandomHeapNumber"); |
| 5090 } | 5310 } |
| 5091 | 5311 |
| 5092 | 5312 |
| 5093 // Fast support for StringAdd. | 5313 // Fast support for StringAdd. |
| 5094 void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { | 5314 void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { |
| 5095 ASSERT_EQ(2, argument_count); | 5315 ASSERT_EQ(2, argument_count); |
| 5096 PushArgumentsForStubCall(argument_count); | 5316 HContext* context = new HContext; |
| 5097 HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count); | 5317 AddInstruction(context); |
| 5318 HCallStub* result = |
| 5319 new HCallStub(context, CodeStub::StringAdd, argument_count); |
| 5320 PreProcessCall(result); |
| 5098 ast_context()->ReturnInstruction(result, ast_id); | 5321 ast_context()->ReturnInstruction(result, ast_id); |
| 5099 } | 5322 } |
| 5100 | 5323 |
| 5101 | 5324 |
| 5102 // Fast support for SubString. | 5325 // Fast support for SubString. |
| 5103 void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { | 5326 void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { |
| 5104 ASSERT_EQ(3, argument_count); | 5327 ASSERT_EQ(3, argument_count); |
| 5105 PushArgumentsForStubCall(argument_count); | 5328 HContext* context = new HContext; |
| 5106 HCallStub* result = new HCallStub(CodeStub::SubString, argument_count); | 5329 AddInstruction(context); |
| 5330 HCallStub* result = |
| 5331 new HCallStub(context, CodeStub::SubString, argument_count); |
| 5332 PreProcessCall(result); |
| 5107 ast_context()->ReturnInstruction(result, ast_id); | 5333 ast_context()->ReturnInstruction(result, ast_id); |
| 5108 } | 5334 } |
| 5109 | 5335 |
| 5110 | 5336 |
| 5111 // Fast support for StringCompare. | 5337 // Fast support for StringCompare. |
| 5112 void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { | 5338 void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { |
| 5113 ASSERT_EQ(2, argument_count); | 5339 ASSERT_EQ(2, argument_count); |
| 5114 PushArgumentsForStubCall(argument_count); | 5340 HContext* context = new HContext; |
| 5115 HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count); | 5341 AddInstruction(context); |
| 5342 HCallStub* result = |
| 5343 new HCallStub(context, CodeStub::StringCompare, argument_count); |
| 5344 PreProcessCall(result); |
| 5116 ast_context()->ReturnInstruction(result, ast_id); | 5345 ast_context()->ReturnInstruction(result, ast_id); |
| 5117 } | 5346 } |
| 5118 | 5347 |
| 5119 | 5348 |
| 5120 // Support for direct calls from JavaScript to native RegExp code. | 5349 // Support for direct calls from JavaScript to native RegExp code. |
| 5121 void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { | 5350 void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { |
| 5122 ASSERT_EQ(4, argument_count); | 5351 ASSERT_EQ(4, argument_count); |
| 5123 PushArgumentsForStubCall(argument_count); | 5352 HContext* context = new HContext; |
| 5124 HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count); | 5353 AddInstruction(context); |
| 5354 HCallStub* result = |
| 5355 new HCallStub(context, CodeStub::RegExpExec, argument_count); |
| 5356 PreProcessCall(result); |
| 5125 ast_context()->ReturnInstruction(result, ast_id); | 5357 ast_context()->ReturnInstruction(result, ast_id); |
| 5126 } | 5358 } |
| 5127 | 5359 |
| 5128 | 5360 |
| 5129 // Construct a RegExp exec result with two in-object properties. | 5361 // Construct a RegExp exec result with two in-object properties. |
| 5130 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, | 5362 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, |
| 5131 int ast_id) { | 5363 int ast_id) { |
| 5132 ASSERT_EQ(3, argument_count); | 5364 ASSERT_EQ(3, argument_count); |
| 5133 PushArgumentsForStubCall(argument_count); | 5365 HContext* context = new HContext; |
| 5366 AddInstruction(context); |
| 5134 HCallStub* result = | 5367 HCallStub* result = |
| 5135 new HCallStub(CodeStub::RegExpConstructResult, argument_count); | 5368 new HCallStub(context, CodeStub::RegExpConstructResult, argument_count); |
| 5369 PreProcessCall(result); |
| 5136 ast_context()->ReturnInstruction(result, ast_id); | 5370 ast_context()->ReturnInstruction(result, ast_id); |
| 5137 } | 5371 } |
| 5138 | 5372 |
| 5139 | 5373 |
| 5140 // Support for fast native caches. | 5374 // Support for fast native caches. |
| 5141 void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { | 5375 void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { |
| 5142 BAILOUT("inlined runtime function: GetFromCache"); | 5376 BAILOUT("inlined runtime function: GetFromCache"); |
| 5143 } | 5377 } |
| 5144 | 5378 |
| 5145 | 5379 |
| 5146 // Fast support for number to string. | 5380 // Fast support for number to string. |
| 5147 void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { | 5381 void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { |
| 5148 ASSERT_EQ(1, argument_count); | 5382 ASSERT_EQ(1, argument_count); |
| 5149 PushArgumentsForStubCall(argument_count); | 5383 HContext* context = new HContext; |
| 5150 HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count); | 5384 AddInstruction(context); |
| 5385 HCallStub* result = |
| 5386 new HCallStub(context, CodeStub::NumberToString, argument_count); |
| 5387 PreProcessCall(result); |
| 5151 ast_context()->ReturnInstruction(result, ast_id); | 5388 ast_context()->ReturnInstruction(result, ast_id); |
| 5152 } | 5389 } |
| 5153 | 5390 |
| 5154 | 5391 |
| 5155 // Fast swapping of elements. Takes three expressions, the object and two | 5392 // Fast swapping of elements. Takes three expressions, the object and two |
| 5156 // indices. This should only be used if the indices are known to be | 5393 // indices. This should only be used if the indices are known to be |
| 5157 // non-negative and within bounds of the elements array at the call site. | 5394 // non-negative and within bounds of the elements array at the call site. |
| 5158 void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { | 5395 void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { |
| 5159 BAILOUT("inlined runtime function: SwapElements"); | 5396 BAILOUT("inlined runtime function: SwapElements"); |
| 5160 } | 5397 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 5171 ASSERT_EQ(2, argument_count); | 5408 ASSERT_EQ(2, argument_count); |
| 5172 HValue* right = Pop(); | 5409 HValue* right = Pop(); |
| 5173 HValue* left = Pop(); | 5410 HValue* left = Pop(); |
| 5174 HPower* result = new HPower(left, right); | 5411 HPower* result = new HPower(left, right); |
| 5175 ast_context()->ReturnInstruction(result, ast_id); | 5412 ast_context()->ReturnInstruction(result, ast_id); |
| 5176 } | 5413 } |
| 5177 | 5414 |
| 5178 | 5415 |
| 5179 void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { | 5416 void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { |
| 5180 ASSERT_EQ(1, argument_count); | 5417 ASSERT_EQ(1, argument_count); |
| 5181 PushArgumentsForStubCall(argument_count); | 5418 HContext* context = new HContext; |
| 5419 AddInstruction(context); |
| 5182 HCallStub* result = | 5420 HCallStub* result = |
| 5183 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5421 new HCallStub(context, CodeStub::TranscendentalCache, argument_count); |
| 5184 result->set_transcendental_type(TranscendentalCache::SIN); | 5422 result->set_transcendental_type(TranscendentalCache::SIN); |
| 5423 PreProcessCall(result); |
| 5185 ast_context()->ReturnInstruction(result, ast_id); | 5424 ast_context()->ReturnInstruction(result, ast_id); |
| 5186 } | 5425 } |
| 5187 | 5426 |
| 5188 | 5427 |
| 5189 void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { | 5428 void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { |
| 5190 ASSERT_EQ(1, argument_count); | 5429 ASSERT_EQ(1, argument_count); |
| 5191 PushArgumentsForStubCall(argument_count); | 5430 HContext* context = new HContext; |
| 5431 AddInstruction(context); |
| 5192 HCallStub* result = | 5432 HCallStub* result = |
| 5193 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5433 new HCallStub(context, CodeStub::TranscendentalCache, argument_count); |
| 5194 result->set_transcendental_type(TranscendentalCache::COS); | 5434 result->set_transcendental_type(TranscendentalCache::COS); |
| 5435 PreProcessCall(result); |
| 5195 ast_context()->ReturnInstruction(result, ast_id); | 5436 ast_context()->ReturnInstruction(result, ast_id); |
| 5196 } | 5437 } |
| 5197 | 5438 |
| 5198 | 5439 |
| 5199 void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { | 5440 void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { |
| 5200 ASSERT_EQ(1, argument_count); | 5441 ASSERT_EQ(1, argument_count); |
| 5201 PushArgumentsForStubCall(argument_count); | 5442 HContext* context = new HContext; |
| 5443 AddInstruction(context); |
| 5202 HCallStub* result = | 5444 HCallStub* result = |
| 5203 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5445 new HCallStub(context, CodeStub::TranscendentalCache, argument_count); |
| 5204 result->set_transcendental_type(TranscendentalCache::LOG); | 5446 result->set_transcendental_type(TranscendentalCache::LOG); |
| 5447 PreProcessCall(result); |
| 5205 ast_context()->ReturnInstruction(result, ast_id); | 5448 ast_context()->ReturnInstruction(result, ast_id); |
| 5206 } | 5449 } |
| 5207 | 5450 |
| 5208 | 5451 |
| 5209 void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { | 5452 void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { |
| 5210 BAILOUT("inlined runtime function: MathSqrt"); | 5453 BAILOUT("inlined runtime function: MathSqrt"); |
| 5211 } | 5454 } |
| 5212 | 5455 |
| 5213 | 5456 |
| 5214 // Check whether two RegExps are equivalent | 5457 // Check whether two RegExps are equivalent |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5656 PrintF("Timing results:\n"); | 5899 PrintF("Timing results:\n"); |
| 5657 int64_t sum = 0; | 5900 int64_t sum = 0; |
| 5658 for (int i = 0; i < timing_.length(); ++i) { | 5901 for (int i = 0; i < timing_.length(); ++i) { |
| 5659 sum += timing_[i]; | 5902 sum += timing_[i]; |
| 5660 } | 5903 } |
| 5661 | 5904 |
| 5662 for (int i = 0; i < names_.length(); ++i) { | 5905 for (int i = 0; i < names_.length(); ++i) { |
| 5663 PrintF("%30s", names_[i]); | 5906 PrintF("%30s", names_[i]); |
| 5664 double ms = static_cast<double>(timing_[i]) / 1000; | 5907 double ms = static_cast<double>(timing_[i]) / 1000; |
| 5665 double percent = static_cast<double>(timing_[i]) * 100 / sum; | 5908 double percent = static_cast<double>(timing_[i]) * 100 / sum; |
| 5666 PrintF(" - %0.3f ms / %0.3f %% \n", ms, percent); | 5909 PrintF(" - %7.3f ms / %4.1f %% ", ms, percent); |
| 5910 |
| 5911 unsigned size = sizes_[i]; |
| 5912 double size_percent = static_cast<double>(size) * 100 / total_size_; |
| 5913 PrintF(" %8u bytes / %4.1f %%\n", size, size_percent); |
| 5667 } | 5914 } |
| 5668 PrintF("%30s - %0.3f ms \n", "Sum", static_cast<double>(sum) / 1000); | 5915 PrintF("%30s - %7.3f ms %8u bytes\n", "Sum", |
| 5916 static_cast<double>(sum) / 1000, |
| 5917 total_size_); |
| 5669 PrintF("---------------------------------------------------------------\n"); | 5918 PrintF("---------------------------------------------------------------\n"); |
| 5670 PrintF("%30s - %0.3f ms (%0.1f times slower than full code gen)\n", | 5919 PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", |
| 5671 "Total", | 5920 "Total", |
| 5672 static_cast<double>(total_) / 1000, | 5921 static_cast<double>(total_) / 1000, |
| 5673 static_cast<double>(total_) / full_code_gen_); | 5922 static_cast<double>(total_) / full_code_gen_); |
| 5674 } | 5923 } |
| 5675 | 5924 |
| 5676 | 5925 |
| 5677 void HStatistics::SaveTiming(const char* name, int64_t ticks) { | 5926 void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { |
| 5678 if (name == HPhase::kFullCodeGen) { | 5927 if (name == HPhase::kFullCodeGen) { |
| 5679 full_code_gen_ += ticks; | 5928 full_code_gen_ += ticks; |
| 5680 } else if (name == HPhase::kTotal) { | 5929 } else if (name == HPhase::kTotal) { |
| 5681 total_ += ticks; | 5930 total_ += ticks; |
| 5682 } else { | 5931 } else { |
| 5932 total_size_ += size; |
| 5683 for (int i = 0; i < names_.length(); ++i) { | 5933 for (int i = 0; i < names_.length(); ++i) { |
| 5684 if (names_[i] == name) { | 5934 if (names_[i] == name) { |
| 5685 timing_[i] += ticks; | 5935 timing_[i] += ticks; |
| 5936 sizes_[i] += size; |
| 5686 return; | 5937 return; |
| 5687 } | 5938 } |
| 5688 } | 5939 } |
| 5689 names_.Add(name); | 5940 names_.Add(name); |
| 5690 timing_.Add(ticks); | 5941 timing_.Add(ticks); |
| 5942 sizes_.Add(size); |
| 5691 } | 5943 } |
| 5692 } | 5944 } |
| 5693 | 5945 |
| 5694 | 5946 |
| 5695 const char* const HPhase::kFullCodeGen = "Full code generator"; | 5947 const char* const HPhase::kFullCodeGen = "Full code generator"; |
| 5696 const char* const HPhase::kTotal = "Total"; | 5948 const char* const HPhase::kTotal = "Total"; |
| 5697 | 5949 |
| 5698 | 5950 |
| 5699 void HPhase::Begin(const char* name, | 5951 void HPhase::Begin(const char* name, |
| 5700 HGraph* graph, | 5952 HGraph* graph, |
| 5701 LChunk* chunk, | 5953 LChunk* chunk, |
| 5702 LAllocator* allocator) { | 5954 LAllocator* allocator) { |
| 5703 name_ = name; | 5955 name_ = name; |
| 5704 graph_ = graph; | 5956 graph_ = graph; |
| 5705 chunk_ = chunk; | 5957 chunk_ = chunk; |
| 5706 allocator_ = allocator; | 5958 allocator_ = allocator; |
| 5707 if (allocator != NULL && chunk_ == NULL) { | 5959 if (allocator != NULL && chunk_ == NULL) { |
| 5708 chunk_ = allocator->chunk(); | 5960 chunk_ = allocator->chunk(); |
| 5709 } | 5961 } |
| 5710 if (FLAG_time_hydrogen) start_ = OS::Ticks(); | 5962 if (FLAG_time_hydrogen) start_ = OS::Ticks(); |
| 5963 start_allocation_size_ = Zone::allocation_size_; |
| 5711 } | 5964 } |
| 5712 | 5965 |
| 5713 | 5966 |
| 5714 void HPhase::End() const { | 5967 void HPhase::End() const { |
| 5715 if (FLAG_time_hydrogen) { | 5968 if (FLAG_time_hydrogen) { |
| 5716 int64_t end = OS::Ticks(); | 5969 int64_t end = OS::Ticks(); |
| 5717 HStatistics::Instance()->SaveTiming(name_, end - start_); | 5970 unsigned size = Zone::allocation_size_ - start_allocation_size_; |
| 5971 HStatistics::Instance()->SaveTiming(name_, end - start_, size); |
| 5718 } | 5972 } |
| 5719 | 5973 |
| 5720 if (FLAG_trace_hydrogen) { | 5974 if (FLAG_trace_hydrogen) { |
| 5721 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); | 5975 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); |
| 5722 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); | 5976 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); |
| 5723 if (allocator_ != NULL) { | 5977 if (allocator_ != NULL) { |
| 5724 HTracer::Instance()->TraceLiveRanges(name_, allocator_); | 5978 HTracer::Instance()->TraceLiveRanges(name_, allocator_); |
| 5725 } | 5979 } |
| 5726 } | 5980 } |
| 5727 | 5981 |
| 5728 #ifdef DEBUG | 5982 #ifdef DEBUG |
| 5729 if (graph_ != NULL) graph_->Verify(); | 5983 if (graph_ != NULL) graph_->Verify(); |
| 5730 if (chunk_ != NULL) chunk_->Verify(); | |
| 5731 if (allocator_ != NULL) allocator_->Verify(); | 5984 if (allocator_ != NULL) allocator_->Verify(); |
| 5732 #endif | 5985 #endif |
| 5733 } | 5986 } |
| 5734 | 5987 |
| 5735 } } // namespace v8::internal | 5988 } } // namespace v8::internal |
| OLD | NEW |