| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 phi->Verify(); | 600 phi->Verify(); |
| 601 } | 601 } |
| 602 | 602 |
| 603 // Check that all join blocks have predecessors that end with an | 603 // Check that all join blocks have predecessors that end with an |
| 604 // unconditional goto and agree on their environment node id. | 604 // unconditional goto and agree on their environment node id. |
| 605 if (block->predecessors()->length() >= 2) { | 605 if (block->predecessors()->length() >= 2) { |
| 606 BailoutId id = | 606 BailoutId id = |
| 607 block->predecessors()->first()->last_environment()->ast_id(); | 607 block->predecessors()->first()->last_environment()->ast_id(); |
| 608 for (int k = 0; k < block->predecessors()->length(); k++) { | 608 for (int k = 0; k < block->predecessors()->length(); k++) { |
| 609 HBasicBlock* predecessor = block->predecessors()->at(k); | 609 HBasicBlock* predecessor = block->predecessors()->at(k); |
| 610 ASSERT(predecessor->end()->IsGoto()); | 610 ASSERT(predecessor->end()->IsGoto() || |
| 611 predecessor->end()->IsDeoptimize()); |
| 611 ASSERT(predecessor->last_environment()->ast_id() == id); | 612 ASSERT(predecessor->last_environment()->ast_id() == id); |
| 612 } | 613 } |
| 613 } | 614 } |
| 614 } | 615 } |
| 615 | 616 |
| 616 // Check special property of first block to have no predecessors. | 617 // Check special property of first block to have no predecessors. |
| 617 ASSERT(blocks_.at(0)->predecessors()->is_empty()); | 618 ASSERT(blocks_.at(0)->predecessors()->is_empty()); |
| 618 | 619 |
| 619 if (do_full_verify) { | 620 if (do_full_verify) { |
| 620 // Check that the graph is fully connected. | 621 // Check that the graph is fully connected. |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 if (IsConstantFalse(constant)) return true; | 741 if (IsConstantFalse(constant)) return true; |
| 741 if (IsConstantHole(constant)) return true; | 742 if (IsConstantHole(constant)) return true; |
| 742 if (IsConstantNull(constant)) return true; | 743 if (IsConstantNull(constant)) return true; |
| 743 return false; | 744 return false; |
| 744 } | 745 } |
| 745 | 746 |
| 746 | 747 |
| 747 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) | 748 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) |
| 748 : builder_(builder), | 749 : builder_(builder), |
| 749 finished_(false), | 750 finished_(false), |
| 750 deopt_then_(false), | |
| 751 deopt_else_(false), | |
| 752 did_then_(false), | 751 did_then_(false), |
| 753 did_else_(false), | 752 did_else_(false), |
| 753 did_else_if_(false), |
| 754 did_and_(false), | 754 did_and_(false), |
| 755 did_or_(false), | 755 did_or_(false), |
| 756 captured_(false), | 756 captured_(false), |
| 757 needs_compare_(true), | 757 needs_compare_(true), |
| 758 pending_merge_block_(false), |
| 758 split_edge_merge_block_(NULL), | 759 split_edge_merge_block_(NULL), |
| 759 merge_block_(NULL) { | 760 merge_at_join_blocks_(NULL), |
| 761 normal_merge_at_join_block_count_(0), |
| 762 deopt_merge_at_join_block_count_(0) { |
| 760 HEnvironment* env = builder->environment(); | 763 HEnvironment* env = builder->environment(); |
| 761 first_true_block_ = builder->CreateBasicBlock(env->Copy()); | 764 first_true_block_ = builder->CreateBasicBlock(env->Copy()); |
| 762 last_true_block_ = NULL; | |
| 763 first_false_block_ = builder->CreateBasicBlock(env->Copy()); | 765 first_false_block_ = builder->CreateBasicBlock(env->Copy()); |
| 764 } | 766 } |
| 765 | 767 |
| 766 | 768 |
| 767 HGraphBuilder::IfBuilder::IfBuilder( | 769 HGraphBuilder::IfBuilder::IfBuilder( |
| 768 HGraphBuilder* builder, | 770 HGraphBuilder* builder, |
| 769 HIfContinuation* continuation) | 771 HIfContinuation* continuation) |
| 770 : builder_(builder), | 772 : builder_(builder), |
| 771 finished_(false), | 773 finished_(false), |
| 772 deopt_then_(false), | |
| 773 deopt_else_(false), | |
| 774 did_then_(false), | 774 did_then_(false), |
| 775 did_else_(false), | 775 did_else_(false), |
| 776 did_else_if_(false), |
| 776 did_and_(false), | 777 did_and_(false), |
| 777 did_or_(false), | 778 did_or_(false), |
| 778 captured_(false), | 779 captured_(false), |
| 779 needs_compare_(false), | 780 needs_compare_(false), |
| 781 pending_merge_block_(false), |
| 780 first_true_block_(NULL), | 782 first_true_block_(NULL), |
| 781 last_true_block_(NULL), | |
| 782 first_false_block_(NULL), | 783 first_false_block_(NULL), |
| 783 split_edge_merge_block_(NULL), | 784 split_edge_merge_block_(NULL), |
| 784 merge_block_(NULL) { | 785 merge_at_join_blocks_(NULL), |
| 786 normal_merge_at_join_block_count_(0), |
| 787 deopt_merge_at_join_block_count_(0) { |
| 785 continuation->Continue(&first_true_block_, | 788 continuation->Continue(&first_true_block_, |
| 786 &first_false_block_); | 789 &first_false_block_); |
| 787 } | 790 } |
| 788 | 791 |
| 789 | 792 |
| 790 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( | 793 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( |
| 791 HControlInstruction* compare) { | 794 HControlInstruction* compare) { |
| 795 ASSERT(did_then_ == did_else_); |
| 796 if (did_else_) { |
| 797 // Handle if-then-elseif |
| 798 did_else_if_ = true; |
| 799 did_else_ = false; |
| 800 did_then_ = false; |
| 801 did_and_ = false; |
| 802 did_or_ = false; |
| 803 pending_merge_block_ = false; |
| 804 split_edge_merge_block_ = NULL; |
| 805 HEnvironment* env = builder_->environment(); |
| 806 first_true_block_ = builder_->CreateBasicBlock(env->Copy()); |
| 807 first_false_block_ = builder_->CreateBasicBlock(env->Copy()); |
| 808 } |
| 792 if (split_edge_merge_block_ != NULL) { | 809 if (split_edge_merge_block_ != NULL) { |
| 793 HEnvironment* env = first_false_block_->last_environment(); | 810 HEnvironment* env = first_false_block_->last_environment(); |
| 794 HBasicBlock* split_edge = | 811 HBasicBlock* split_edge = |
| 795 builder_->CreateBasicBlock(env->Copy()); | 812 builder_->CreateBasicBlock(env->Copy()); |
| 796 if (did_or_) { | 813 if (did_or_) { |
| 797 compare->SetSuccessorAt(0, split_edge); | 814 compare->SetSuccessorAt(0, split_edge); |
| 798 compare->SetSuccessorAt(1, first_false_block_); | 815 compare->SetSuccessorAt(1, first_false_block_); |
| 799 } else { | 816 } else { |
| 800 compare->SetSuccessorAt(0, first_true_block_); | 817 compare->SetSuccessorAt(0, first_true_block_); |
| 801 compare->SetSuccessorAt(1, split_edge); | 818 compare->SetSuccessorAt(1, split_edge); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 builder_->GotoNoSimulate(first_false_block_, split_edge_merge_block_); | 854 builder_->GotoNoSimulate(first_false_block_, split_edge_merge_block_); |
| 838 first_false_block_ = split_edge_merge_block_; | 855 first_false_block_ = split_edge_merge_block_; |
| 839 } | 856 } |
| 840 builder_->set_current_block(first_true_block_); | 857 builder_->set_current_block(first_true_block_); |
| 841 first_true_block_ = builder_->CreateBasicBlock(env->Copy()); | 858 first_true_block_ = builder_->CreateBasicBlock(env->Copy()); |
| 842 } | 859 } |
| 843 | 860 |
| 844 | 861 |
| 845 void HGraphBuilder::IfBuilder::CaptureContinuation( | 862 void HGraphBuilder::IfBuilder::CaptureContinuation( |
| 846 HIfContinuation* continuation) { | 863 HIfContinuation* continuation) { |
| 864 ASSERT(!did_else_if_); |
| 847 ASSERT(!finished_); | 865 ASSERT(!finished_); |
| 848 ASSERT(!captured_); | 866 ASSERT(!captured_); |
| 849 HBasicBlock* true_block = last_true_block_ == NULL | 867 |
| 850 ? first_true_block_ | 868 HBasicBlock* true_block = NULL; |
| 851 : last_true_block_; | 869 HBasicBlock* false_block = NULL; |
| 852 HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) | 870 Finish(&true_block, &false_block); |
| 853 ? builder_->current_block() | 871 ASSERT(true_block != NULL); |
| 854 : first_false_block_; | 872 ASSERT(false_block != NULL); |
| 855 continuation->Capture(true_block, false_block); | 873 continuation->Capture(true_block, false_block); |
| 856 captured_ = true; | 874 captured_ = true; |
| 875 builder_->set_current_block(NULL); |
| 857 End(); | 876 End(); |
| 858 } | 877 } |
| 859 | 878 |
| 860 | 879 |
| 861 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { | 880 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { |
| 881 ASSERT(!did_else_if_); |
| 862 ASSERT(!finished_); | 882 ASSERT(!finished_); |
| 863 ASSERT(!captured_); | 883 ASSERT(!captured_); |
| 864 ASSERT(did_then_); | 884 HBasicBlock* true_block = NULL; |
| 865 if (!did_else_) Else(); | 885 HBasicBlock* false_block = NULL; |
| 866 HBasicBlock* true_block = last_true_block_ == NULL | 886 Finish(&true_block, &false_block); |
| 867 ? first_true_block_ | 887 merge_at_join_blocks_ = NULL; |
| 868 : last_true_block_; | |
| 869 HBasicBlock* false_block = builder_->current_block(); | |
| 870 if (true_block != NULL && !true_block->IsFinished()) { | 888 if (true_block != NULL && !true_block->IsFinished()) { |
| 871 ASSERT(continuation->IsTrueReachable()); | 889 ASSERT(continuation->IsTrueReachable()); |
| 872 builder_->GotoNoSimulate(true_block, continuation->true_branch()); | 890 builder_->GotoNoSimulate(true_block, continuation->true_branch()); |
| 873 } | 891 } |
| 874 if (false_block != NULL && !false_block->IsFinished()) { | 892 if (false_block != NULL && !false_block->IsFinished()) { |
| 875 ASSERT(continuation->IsFalseReachable()); | 893 ASSERT(continuation->IsFalseReachable()); |
| 876 builder_->GotoNoSimulate(false_block, continuation->false_branch()); | 894 builder_->GotoNoSimulate(false_block, continuation->false_branch()); |
| 877 } | 895 } |
| 878 captured_ = true; | 896 captured_ = true; |
| 879 End(); | 897 End(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 890 // so that the graph builder visits it and sees any live range extending | 908 // so that the graph builder visits it and sees any live range extending |
| 891 // constructs within it. | 909 // constructs within it. |
| 892 HConstant* constant_false = builder_->graph()->GetConstantFalse(); | 910 HConstant* constant_false = builder_->graph()->GetConstantFalse(); |
| 893 ToBooleanStub::Types boolean_type = ToBooleanStub::Types(); | 911 ToBooleanStub::Types boolean_type = ToBooleanStub::Types(); |
| 894 boolean_type.Add(ToBooleanStub::BOOLEAN); | 912 boolean_type.Add(ToBooleanStub::BOOLEAN); |
| 895 HBranch* branch = builder()->New<HBranch>( | 913 HBranch* branch = builder()->New<HBranch>( |
| 896 constant_false, boolean_type, first_true_block_, first_false_block_); | 914 constant_false, boolean_type, first_true_block_, first_false_block_); |
| 897 builder_->FinishCurrentBlock(branch); | 915 builder_->FinishCurrentBlock(branch); |
| 898 } | 916 } |
| 899 builder_->set_current_block(first_true_block_); | 917 builder_->set_current_block(first_true_block_); |
| 918 pending_merge_block_ = true; |
| 900 } | 919 } |
| 901 | 920 |
| 902 | 921 |
| 903 void HGraphBuilder::IfBuilder::Else() { | 922 void HGraphBuilder::IfBuilder::Else() { |
| 904 ASSERT(did_then_); | 923 ASSERT(did_then_); |
| 905 ASSERT(!captured_); | 924 ASSERT(!captured_); |
| 906 ASSERT(!finished_); | 925 ASSERT(!finished_); |
| 907 last_true_block_ = builder_->current_block(); | 926 AddMergeAtJoinBlock(false); |
| 908 builder_->set_current_block(first_false_block_); | 927 builder_->set_current_block(first_false_block_); |
| 928 pending_merge_block_ = true; |
| 909 did_else_ = true; | 929 did_else_ = true; |
| 910 } | 930 } |
| 911 | 931 |
| 912 | 932 |
| 913 void HGraphBuilder::IfBuilder::Deopt(const char* reason) { | 933 void HGraphBuilder::IfBuilder::Deopt(const char* reason) { |
| 914 ASSERT(did_then_); | 934 ASSERT(did_then_); |
| 915 if (did_else_) { | |
| 916 deopt_else_ = true; | |
| 917 } else { | |
| 918 deopt_then_ = true; | |
| 919 } | |
| 920 builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER); | 935 builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER); |
| 936 AddMergeAtJoinBlock(true); |
| 921 } | 937 } |
| 922 | 938 |
| 923 | 939 |
| 924 void HGraphBuilder::IfBuilder::Return(HValue* value) { | 940 void HGraphBuilder::IfBuilder::Return(HValue* value) { |
| 925 HValue* parameter_count = builder_->graph()->GetConstantMinus1(); | 941 HValue* parameter_count = builder_->graph()->GetConstantMinus1(); |
| 926 builder_->FinishExitCurrentBlock( | 942 builder_->FinishExitCurrentBlock( |
| 927 builder_->New<HReturn>(value, parameter_count)); | 943 builder_->New<HReturn>(value, parameter_count)); |
| 928 if (did_else_) { | 944 AddMergeAtJoinBlock(false); |
| 929 first_false_block_ = NULL; | |
| 930 } else { | |
| 931 first_true_block_ = NULL; | |
| 932 } | |
| 933 } | 945 } |
| 934 | 946 |
| 935 | 947 |
| 936 void HGraphBuilder::IfBuilder::End() { | 948 void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) { |
| 937 if (!captured_) { | 949 if (!pending_merge_block_) return; |
| 938 ASSERT(did_then_); | 950 HBasicBlock* block = builder_->current_block(); |
| 939 if (!did_else_) { | 951 ASSERT(block == NULL || !block->IsFinished()); |
| 940 last_true_block_ = builder_->current_block(); | 952 MergeAtJoinBlock* record = |
| 953 new(builder_->zone()) MergeAtJoinBlock(block, deopt, |
| 954 merge_at_join_blocks_); |
| 955 merge_at_join_blocks_ = record; |
| 956 if (block != NULL) { |
| 957 ASSERT(block->end() == NULL); |
| 958 if (deopt) { |
| 959 normal_merge_at_join_block_count_++; |
| 960 } else { |
| 961 deopt_merge_at_join_block_count_++; |
| 941 } | 962 } |
| 942 if (last_true_block_ == NULL || last_true_block_->IsFinished()) { | 963 } |
| 943 ASSERT(did_else_); | 964 builder_->set_current_block(NULL); |
| 944 // Return on true. Nothing to do, just continue the false block. | 965 pending_merge_block_ = false; |
| 945 } else if (first_false_block_ == NULL || | 966 } |
| 946 (did_else_ && builder_->current_block()->IsFinished())) { | 967 |
| 947 // Deopt on false. Nothing to do except switching to the true block. | 968 |
| 948 builder_->set_current_block(last_true_block_); | 969 void HGraphBuilder::IfBuilder::Finish() { |
| 949 } else { | 970 ASSERT(!finished_); |
| 950 merge_block_ = builder_->graph()->CreateBasicBlock(); | 971 if (!did_then_) { |
| 951 ASSERT(!finished_); | 972 Then(); |
| 952 if (!did_else_) Else(); | 973 } |
| 953 ASSERT(!last_true_block_->IsFinished()); | 974 AddMergeAtJoinBlock(false); |
| 954 HBasicBlock* last_false_block = builder_->current_block(); | 975 if (!did_else_) { |
| 955 ASSERT(!last_false_block->IsFinished()); | 976 Else(); |
| 956 if (deopt_then_) { | 977 AddMergeAtJoinBlock(false); |
| 957 builder_->GotoNoSimulate(last_false_block, merge_block_); | |
| 958 builder_->PadEnvironmentForContinuation(last_true_block_, | |
| 959 merge_block_); | |
| 960 builder_->GotoNoSimulate(last_true_block_, merge_block_); | |
| 961 } else { | |
| 962 builder_->GotoNoSimulate(last_true_block_, merge_block_); | |
| 963 if (deopt_else_) { | |
| 964 builder_->PadEnvironmentForContinuation(last_false_block, | |
| 965 merge_block_); | |
| 966 } | |
| 967 builder_->GotoNoSimulate(last_false_block, merge_block_); | |
| 968 } | |
| 969 builder_->set_current_block(merge_block_); | |
| 970 } | |
| 971 } | 978 } |
| 972 finished_ = true; | 979 finished_ = true; |
| 973 } | 980 } |
| 974 | 981 |
| 975 | 982 |
| 983 void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation, |
| 984 HBasicBlock** else_continuation) { |
| 985 Finish(); |
| 986 |
| 987 MergeAtJoinBlock* else_record = merge_at_join_blocks_; |
| 988 if (else_continuation != NULL) { |
| 989 *else_continuation = else_record->block_; |
| 990 } |
| 991 MergeAtJoinBlock* then_record = else_record->next_; |
| 992 if (then_continuation != NULL) { |
| 993 *then_continuation = then_record->block_; |
| 994 } |
| 995 ASSERT(then_record->next_ == NULL); |
| 996 } |
| 997 |
| 998 |
| 999 void HGraphBuilder::IfBuilder::End() { |
| 1000 if (captured_) return; |
| 1001 Finish(); |
| 1002 |
| 1003 int total_merged_blocks = normal_merge_at_join_block_count_ + |
| 1004 deopt_merge_at_join_block_count_; |
| 1005 ASSERT(total_merged_blocks >= 1); |
| 1006 HBasicBlock* merge_block = total_merged_blocks == 1 |
| 1007 ? NULL : builder_->graph()->CreateBasicBlock(); |
| 1008 |
| 1009 // Merge non-deopt blocks first to ensure environment has right size for |
| 1010 // padding. |
| 1011 MergeAtJoinBlock* current = merge_at_join_blocks_; |
| 1012 while (current != NULL) { |
| 1013 if (!current->deopt_ && current->block_ != NULL) { |
| 1014 // If there is only one block that makes it through to the end of the |
| 1015 // if, then just set it as the current block and continue rather then |
| 1016 // creating an unnecessary merge block. |
| 1017 if (total_merged_blocks == 1) { |
| 1018 builder_->set_current_block(current->block_); |
| 1019 return; |
| 1020 } |
| 1021 builder_->GotoNoSimulate(current->block_, merge_block); |
| 1022 } |
| 1023 current = current->next_; |
| 1024 } |
| 1025 |
| 1026 // Merge deopt blocks, padding when necessary. |
| 1027 current = merge_at_join_blocks_; |
| 1028 while (current != NULL) { |
| 1029 if (current->deopt_ && current->block_ != NULL) { |
| 1030 builder_->PadEnvironmentForContinuation(current->block_, |
| 1031 merge_block); |
| 1032 builder_->GotoNoSimulate(current->block_, merge_block); |
| 1033 } |
| 1034 current = current->next_; |
| 1035 } |
| 1036 builder_->set_current_block(merge_block); |
| 1037 } |
| 1038 |
| 1039 |
| 976 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, | 1040 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, |
| 977 HValue* context, | 1041 HValue* context, |
| 978 LoopBuilder::Direction direction) | 1042 LoopBuilder::Direction direction) |
| 979 : builder_(builder), | 1043 : builder_(builder), |
| 980 context_(context), | 1044 context_(context), |
| 981 direction_(direction), | 1045 direction_(direction), |
| 982 finished_(false) { | 1046 finished_(false) { |
| 983 header_block_ = builder->CreateLoopHeaderBlock(); | 1047 header_block_ = builder->CreateLoopHeaderBlock(); |
| 984 body_block_ = NULL; | 1048 body_block_ = NULL; |
| 985 exit_block_ = NULL; | 1049 exit_block_ = NULL; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1046 | 1110 |
| 1047 void HGraphBuilder::LoopBuilder::Break() { | 1111 void HGraphBuilder::LoopBuilder::Break() { |
| 1048 if (exit_trampoline_block_ == NULL) { | 1112 if (exit_trampoline_block_ == NULL) { |
| 1049 // Its the first time we saw a break. | 1113 // Its the first time we saw a break. |
| 1050 HEnvironment* env = exit_block_->last_environment()->Copy(); | 1114 HEnvironment* env = exit_block_->last_environment()->Copy(); |
| 1051 exit_trampoline_block_ = builder_->CreateBasicBlock(env); | 1115 exit_trampoline_block_ = builder_->CreateBasicBlock(env); |
| 1052 builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_); | 1116 builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_); |
| 1053 } | 1117 } |
| 1054 | 1118 |
| 1055 builder_->GotoNoSimulate(exit_trampoline_block_); | 1119 builder_->GotoNoSimulate(exit_trampoline_block_); |
| 1120 builder_->set_current_block(NULL); |
| 1056 } | 1121 } |
| 1057 | 1122 |
| 1058 | 1123 |
| 1059 void HGraphBuilder::LoopBuilder::EndBody() { | 1124 void HGraphBuilder::LoopBuilder::EndBody() { |
| 1060 ASSERT(!finished_); | 1125 ASSERT(!finished_); |
| 1061 | 1126 |
| 1062 if (direction_ == kPostIncrement || direction_ == kPostDecrement) { | 1127 if (direction_ == kPostIncrement || direction_ == kPostDecrement) { |
| 1063 if (direction_ == kPostIncrement) { | 1128 if (direction_ == kPostIncrement) { |
| 1064 increment_ = HAdd::New(zone(), context_, phi_, increment_amount_); | 1129 increment_ = HAdd::New(zone(), context_, phi_, increment_amount_); |
| 1065 } else { | 1130 } else { |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1335 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, | 1400 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, |
| 1336 array_length, elements_length); | 1401 array_length, elements_length); |
| 1337 | 1402 |
| 1338 if_builder.End(); | 1403 if_builder.End(); |
| 1339 } | 1404 } |
| 1340 | 1405 |
| 1341 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); | 1406 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); |
| 1342 } | 1407 } |
| 1343 | 1408 |
| 1344 | 1409 |
| 1410 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper( |
| 1411 HValue* elements, |
| 1412 HValue* key, |
| 1413 HValue* hash, |
| 1414 HValue* mask, |
| 1415 int current_probe) { |
| 1416 if (current_probe == kNumberDictionaryProbes) { |
| 1417 return NULL; |
| 1418 } |
| 1419 |
| 1420 int32_t offset = SeededNumberDictionary::GetProbeOffset(current_probe); |
| 1421 HValue* raw_index = (current_probe == 0) |
| 1422 ? hash |
| 1423 : Add<HAdd>(hash, Add<HConstant>(offset)); |
| 1424 raw_index = Add<HBitwise>(Token::BIT_AND, raw_index, mask); |
| 1425 int32_t entry_size = SeededNumberDictionary::kEntrySize; |
| 1426 raw_index = Add<HMul>(raw_index, Add<HConstant>(entry_size)); |
| 1427 raw_index->ClearFlag(HValue::kCanOverflow); |
| 1428 |
| 1429 int32_t base_offset = SeededNumberDictionary::kElementsStartIndex; |
| 1430 HValue* key_index = Add<HAdd>(raw_index, Add<HConstant>(base_offset)); |
| 1431 key_index->ClearFlag(HValue::kCanOverflow); |
| 1432 |
| 1433 HValue* candidate_key = Add<HLoadKeyed>(elements, key_index, |
| 1434 static_cast<HValue*>(NULL), |
| 1435 FAST_SMI_ELEMENTS); |
| 1436 |
| 1437 IfBuilder key_compare(this); |
| 1438 key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key); |
| 1439 key_compare.Then(); |
| 1440 { |
| 1441 // Key at the current probe doesn't match, try at the next probe. |
| 1442 HValue* result = BuildUncheckedDictionaryElementLoadHelper( |
| 1443 elements, key, hash, mask, current_probe + 1); |
| 1444 if (result == NULL) { |
| 1445 key_compare.Deopt("probes exhausted in keyed load dictionary lookup"); |
| 1446 result = graph()->GetConstantUndefined(); |
| 1447 } else { |
| 1448 Push(result); |
| 1449 } |
| 1450 } |
| 1451 key_compare.Else(); |
| 1452 { |
| 1453 // Key at current probe matches. Details must be zero, otherwise the |
| 1454 // dictionary element requires special handling. |
| 1455 HValue* details_index = Add<HAdd>(raw_index, |
| 1456 Add<HConstant>(base_offset + 2)); |
| 1457 details_index->ClearFlag(HValue::kCanOverflow); |
| 1458 |
| 1459 HValue* details = Add<HLoadKeyed>(elements, details_index, |
| 1460 static_cast<HValue*>(NULL), |
| 1461 FAST_SMI_ELEMENTS); |
| 1462 IfBuilder details_compare(this); |
| 1463 details_compare.If<HCompareNumericAndBranch>(details, |
| 1464 graph()->GetConstant0(), |
| 1465 Token::NE); |
| 1466 details_compare.ThenDeopt("keyed load dictionary element not fast case"); |
| 1467 |
| 1468 details_compare.Else(); |
| 1469 { |
| 1470 // Key matches and details are zero --> fast case. Load and return the |
| 1471 // value. |
| 1472 HValue* result_index = Add<HAdd>(raw_index, |
| 1473 Add<HConstant>(base_offset + 1)); |
| 1474 result_index->ClearFlag(HValue::kCanOverflow); |
| 1475 |
| 1476 Push(Add<HLoadKeyed>(elements, result_index, |
| 1477 static_cast<HValue*>(NULL), |
| 1478 FAST_ELEMENTS)); |
| 1479 } |
| 1480 details_compare.End(); |
| 1481 } |
| 1482 key_compare.End(); |
| 1483 |
| 1484 return Pop(); |
| 1485 } |
| 1486 |
| 1487 |
| 1488 HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) { |
| 1489 int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed()); |
| 1490 HValue* seed = Add<HConstant>(seed_value); |
| 1491 HValue* hash = Add<HBitwise>(Token::BIT_XOR, index, seed); |
| 1492 |
| 1493 // hash = ~hash + (hash << 15); |
| 1494 HValue* shifted_hash = Add<HShl>(hash, Add<HConstant>(15)); |
| 1495 HValue* not_hash = Add<HBitwise>(Token::BIT_XOR, hash, |
| 1496 graph()->GetConstantMinus1()); |
| 1497 hash = Add<HAdd>(shifted_hash, not_hash); |
| 1498 |
| 1499 // hash = hash ^ (hash >> 12); |
| 1500 shifted_hash = Add<HShr>(hash, Add<HConstant>(12)); |
| 1501 hash = Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
| 1502 |
| 1503 // hash = hash + (hash << 2); |
| 1504 shifted_hash = Add<HShl>(hash, Add<HConstant>(2)); |
| 1505 hash = Add<HAdd>(hash, shifted_hash); |
| 1506 |
| 1507 // hash = hash ^ (hash >> 4); |
| 1508 shifted_hash = Add<HShr>(hash, Add<HConstant>(4)); |
| 1509 hash = Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
| 1510 |
| 1511 // hash = hash * 2057; |
| 1512 hash = Add<HMul>(hash, Add<HConstant>(2057)); |
| 1513 hash->ClearFlag(HValue::kCanOverflow); |
| 1514 |
| 1515 // hash = hash ^ (hash >> 16); |
| 1516 shifted_hash = Add<HShr>(hash, Add<HConstant>(16)); |
| 1517 return Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
| 1518 } |
| 1519 |
| 1520 |
| 1521 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, |
| 1522 HValue* key) { |
| 1523 HValue* elements = AddLoadElements(receiver); |
| 1524 |
| 1525 HValue* hash = BuildElementIndexHash(key); |
| 1526 |
| 1527 HValue* capacity = Add<HLoadKeyed>( |
| 1528 elements, |
| 1529 Add<HConstant>(NameDictionary::kCapacityIndex), |
| 1530 static_cast<HValue*>(NULL), |
| 1531 FAST_SMI_ELEMENTS); |
| 1532 |
| 1533 HValue* mask = Add<HSub>(capacity, graph()->GetConstant1()); |
| 1534 mask->ChangeRepresentation(Representation::Integer32()); |
| 1535 mask->ClearFlag(HValue::kCanOverflow); |
| 1536 |
| 1537 return BuildUncheckedDictionaryElementLoadHelper(elements, key, |
| 1538 hash, mask, 0); |
| 1539 } |
| 1540 |
| 1541 |
| 1345 HValue* HGraphBuilder::BuildNumberToString(HValue* object, | 1542 HValue* HGraphBuilder::BuildNumberToString(HValue* object, |
| 1346 Handle<Type> type) { | 1543 Handle<Type> type) { |
| 1347 NoObservableSideEffectsScope scope(this); | 1544 NoObservableSideEffectsScope scope(this); |
| 1348 | 1545 |
| 1349 // Create a joinable continuation. | 1546 // Create a joinable continuation. |
| 1350 HIfContinuation found(graph()->CreateBasicBlock(), | 1547 HIfContinuation found(graph()->CreateBasicBlock(), |
| 1351 graph()->CreateBasicBlock()); | 1548 graph()->CreateBasicBlock()); |
| 1352 | 1549 |
| 1353 // Load the number string cache. | 1550 // Load the number string cache. |
| 1354 HValue* number_string_cache = | 1551 HValue* number_string_cache = |
| (...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1854 IfBuilder length_checker(this); | 2051 IfBuilder length_checker(this); |
| 1855 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); | 2052 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); |
| 1856 length_checker.Then(); | 2053 length_checker.Then(); |
| 1857 IfBuilder negative_checker(this); | 2054 IfBuilder negative_checker(this); |
| 1858 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( | 2055 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( |
| 1859 key, graph()->GetConstant0(), Token::GTE); | 2056 key, graph()->GetConstant0(), Token::GTE); |
| 1860 negative_checker.Then(); | 2057 negative_checker.Then(); |
| 1861 HInstruction* result = AddElementAccess( | 2058 HInstruction* result = AddElementAccess( |
| 1862 external_elements, key, val, bounds_check, elements_kind, is_store); | 2059 external_elements, key, val, bounds_check, elements_kind, is_store); |
| 1863 negative_checker.ElseDeopt("Negative key encountered"); | 2060 negative_checker.ElseDeopt("Negative key encountered"); |
| 2061 negative_checker.End(); |
| 1864 length_checker.End(); | 2062 length_checker.End(); |
| 1865 return result; | 2063 return result; |
| 1866 } else { | 2064 } else { |
| 1867 ASSERT(store_mode == STANDARD_STORE); | 2065 ASSERT(store_mode == STANDARD_STORE); |
| 1868 checked_key = Add<HBoundsCheck>(key, length); | 2066 checked_key = Add<HBoundsCheck>(key, length); |
| 1869 HLoadExternalArrayPointer* external_elements = | 2067 HLoadExternalArrayPointer* external_elements = |
| 1870 Add<HLoadExternalArrayPointer>(elements); | 2068 Add<HLoadExternalArrayPointer>(elements); |
| 1871 return AddElementAccess( | 2069 return AddElementAccess( |
| 1872 external_elements, checked_key, val, | 2070 external_elements, checked_key, val, |
| 1873 checked_object, elements_kind, is_store); | 2071 checked_object, elements_kind, is_store); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1904 elements, isolate()->factory()->fixed_array_map(), top_info()); | 2102 elements, isolate()->factory()->fixed_array_map(), top_info()); |
| 1905 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 2103 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 1906 } | 2104 } |
| 1907 } | 2105 } |
| 1908 } | 2106 } |
| 1909 return AddElementAccess(elements, checked_key, val, checked_object, | 2107 return AddElementAccess(elements, checked_key, val, checked_object, |
| 1910 elements_kind, is_store, load_mode); | 2108 elements_kind, is_store, load_mode); |
| 1911 } | 2109 } |
| 1912 | 2110 |
| 1913 | 2111 |
| 2112 |
| 2113 HValue* HGraphBuilder::BuildAllocateArrayFromLength( |
| 2114 JSArrayBuilder* array_builder, |
| 2115 HValue* length_argument) { |
| 2116 if (length_argument->IsConstant() && |
| 2117 HConstant::cast(length_argument)->HasSmiValue()) { |
| 2118 int array_length = HConstant::cast(length_argument)->Integer32Value(); |
| 2119 HValue* new_object = array_length == 0 |
| 2120 ? array_builder->AllocateEmptyArray() |
| 2121 : array_builder->AllocateArray(length_argument, length_argument); |
| 2122 return new_object; |
| 2123 } |
| 2124 |
| 2125 HValue* constant_zero = graph()->GetConstant0(); |
| 2126 HConstant* max_alloc_length = |
| 2127 Add<HConstant>(JSObject::kInitialMaxFastElementArray); |
| 2128 HInstruction* checked_length = Add<HBoundsCheck>(length_argument, |
| 2129 max_alloc_length); |
| 2130 IfBuilder if_builder(this); |
| 2131 if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero, |
| 2132 Token::EQ); |
| 2133 if_builder.Then(); |
| 2134 const int initial_capacity = JSArray::kPreallocatedArrayElements; |
| 2135 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); |
| 2136 Push(initial_capacity_node); // capacity |
| 2137 Push(constant_zero); // length |
| 2138 if_builder.Else(); |
| 2139 if (!(top_info()->IsStub()) && |
| 2140 IsFastPackedElementsKind(array_builder->kind())) { |
| 2141 // We'll come back later with better (holey) feedback. |
| 2142 if_builder.Deopt("Holey array despite packed elements_kind feedback"); |
| 2143 } else { |
| 2144 Push(checked_length); // capacity |
| 2145 Push(checked_length); // length |
| 2146 } |
| 2147 if_builder.End(); |
| 2148 |
| 2149 // Figure out total size |
| 2150 HValue* length = Pop(); |
| 2151 HValue* capacity = Pop(); |
| 2152 return array_builder->AllocateArray(capacity, length); |
| 2153 } |
| 2154 |
| 1914 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, | 2155 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, |
| 1915 HValue* capacity) { | 2156 HValue* capacity) { |
| 1916 int elements_size; | 2157 int elements_size; |
| 1917 InstanceType instance_type; | 2158 InstanceType instance_type; |
| 1918 | 2159 |
| 1919 if (IsFastDoubleElementsKind(kind)) { | 2160 if (IsFastDoubleElementsKind(kind)) { |
| 1920 elements_size = kDoubleSize; | 2161 elements_size = kDoubleSize; |
| 1921 instance_type = FIXED_DOUBLE_ARRAY_TYPE; | 2162 instance_type = FIXED_DOUBLE_ARRAY_TYPE; |
| 1922 } else { | 2163 } else { |
| 1923 elements_size = kPointerSize; | 2164 elements_size = kPointerSize; |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2092 // Fast elements kinds need to be initialized in case statements below cause | 2333 // Fast elements kinds need to be initialized in case statements below cause |
| 2093 // a garbage collection. | 2334 // a garbage collection. |
| 2094 Factory* factory = isolate()->factory(); | 2335 Factory* factory = isolate()->factory(); |
| 2095 | 2336 |
| 2096 double nan_double = FixedDoubleArray::hole_nan_as_double(); | 2337 double nan_double = FixedDoubleArray::hole_nan_as_double(); |
| 2097 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) | 2338 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) |
| 2098 ? Add<HConstant>(factory->the_hole_value()) | 2339 ? Add<HConstant>(factory->the_hole_value()) |
| 2099 : Add<HConstant>(nan_double); | 2340 : Add<HConstant>(nan_double); |
| 2100 | 2341 |
| 2101 // Special loop unfolding case | 2342 // Special loop unfolding case |
| 2102 static const int kLoopUnfoldLimit = 4; | 2343 static const int kLoopUnfoldLimit = 8; |
| 2103 bool unfold_loop = false; | 2344 STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit); |
| 2104 int initial_capacity = JSArray::kPreallocatedArrayElements; | 2345 int initial_capacity = -1; |
| 2105 if (from->IsConstant() && to->IsConstant() && | 2346 if (from->IsInteger32Constant() && to->IsInteger32Constant()) { |
| 2106 initial_capacity <= kLoopUnfoldLimit) { | 2347 int constant_from = from->GetInteger32Constant(); |
| 2107 HConstant* constant_from = HConstant::cast(from); | 2348 int constant_to = to->GetInteger32Constant(); |
| 2108 HConstant* constant_to = HConstant::cast(to); | |
| 2109 | 2349 |
| 2110 if (constant_from->HasInteger32Value() && | 2350 if (constant_from == 0 && constant_to <= kLoopUnfoldLimit) { |
| 2111 constant_from->Integer32Value() == 0 && | 2351 initial_capacity = constant_to; |
| 2112 constant_to->HasInteger32Value() && | |
| 2113 constant_to->Integer32Value() == initial_capacity) { | |
| 2114 unfold_loop = true; | |
| 2115 } | 2352 } |
| 2116 } | 2353 } |
| 2117 | 2354 |
| 2118 // Since we're about to store a hole value, the store instruction below must | 2355 // Since we're about to store a hole value, the store instruction below must |
| 2119 // assume an elements kind that supports heap object values. | 2356 // assume an elements kind that supports heap object values. |
| 2120 if (IsFastSmiOrObjectElementsKind(elements_kind)) { | 2357 if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 2121 elements_kind = FAST_HOLEY_ELEMENTS; | 2358 elements_kind = FAST_HOLEY_ELEMENTS; |
| 2122 } | 2359 } |
| 2123 | 2360 |
| 2124 if (unfold_loop) { | 2361 if (initial_capacity >= 0) { |
| 2125 for (int i = 0; i < initial_capacity; i++) { | 2362 for (int i = 0; i < initial_capacity; i++) { |
| 2126 HInstruction* key = Add<HConstant>(i); | 2363 HInstruction* key = Add<HConstant>(i); |
| 2127 Add<HStoreKeyed>(elements, key, hole, elements_kind); | 2364 Add<HStoreKeyed>(elements, key, hole, elements_kind); |
| 2128 } | 2365 } |
| 2129 } else { | 2366 } else { |
| 2130 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); | 2367 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); |
| 2131 | 2368 |
| 2132 HValue* key = builder.BeginBody(from, to, Token::LT); | 2369 HValue* key = builder.BeginBody(from, to, Token::LT); |
| 2133 | 2370 |
| 2134 Add<HStoreKeyed>(elements, key, hole, elements_kind); | 2371 Add<HStoreKeyed>(elements, key, hole, elements_kind); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2373 HValue* constructor_function) : | 2610 HValue* constructor_function) : |
| 2374 builder_(builder), | 2611 builder_(builder), |
| 2375 kind_(kind), | 2612 kind_(kind), |
| 2376 mode_(DONT_TRACK_ALLOCATION_SITE), | 2613 mode_(DONT_TRACK_ALLOCATION_SITE), |
| 2377 allocation_site_payload_(NULL), | 2614 allocation_site_payload_(NULL), |
| 2378 constructor_function_(constructor_function) { | 2615 constructor_function_(constructor_function) { |
| 2379 } | 2616 } |
| 2380 | 2617 |
| 2381 | 2618 |
| 2382 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { | 2619 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { |
| 2383 if (kind_ == GetInitialFastElementsKind()) { | 2620 if (!builder()->top_info()->IsStub()) { |
| 2621 // A constant map is fine. |
| 2622 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), |
| 2623 builder()->isolate()); |
| 2624 return builder()->Add<HConstant>(map); |
| 2625 } |
| 2626 |
| 2627 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) { |
| 2384 // No need for a context lookup if the kind_ matches the initial | 2628 // No need for a context lookup if the kind_ matches the initial |
| 2385 // map, because we can just load the map in that case. | 2629 // map, because we can just load the map in that case. |
| 2386 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | 2630 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
| 2387 return builder()->AddLoadNamedField(constructor_function_, access); | 2631 return builder()->AddLoadNamedField(constructor_function_, access); |
| 2388 } | 2632 } |
| 2389 | 2633 |
| 2390 HInstruction* native_context = builder()->BuildGetNativeContext(); | 2634 HInstruction* native_context = builder()->BuildGetNativeContext(); |
| 2391 HInstruction* index = builder()->Add<HConstant>( | 2635 HInstruction* index = builder()->Add<HConstant>( |
| 2392 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); | 2636 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); |
| 2393 | 2637 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2415 int base_size = JSArray::kSize; | 2659 int base_size = JSArray::kSize; |
| 2416 if (mode_ == TRACK_ALLOCATION_SITE) { | 2660 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2417 base_size += AllocationMemento::kSize; | 2661 base_size += AllocationMemento::kSize; |
| 2418 } | 2662 } |
| 2419 | 2663 |
| 2420 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); | 2664 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); |
| 2421 base_size += FixedArray::kHeaderSize; | 2665 base_size += FixedArray::kHeaderSize; |
| 2422 | 2666 |
| 2423 HInstruction* elements_size_value = | 2667 HInstruction* elements_size_value = |
| 2424 builder()->Add<HConstant>(elements_size()); | 2668 builder()->Add<HConstant>(elements_size()); |
| 2425 HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value); | 2669 HInstruction* mul = HMul::NewImul(builder()->zone(), builder()->context(), |
| 2426 mul->ClearFlag(HValue::kCanOverflow); | 2670 length_node, elements_size_value); |
| 2427 | 2671 builder()->AddInstruction(mul); |
| 2428 HInstruction* base = builder()->Add<HConstant>(base_size); | 2672 HInstruction* base = builder()->Add<HConstant>(base_size); |
| 2429 HInstruction* total_size = builder()->Add<HAdd>(base, mul); | 2673 HInstruction* total_size = HAdd::New(builder()->zone(), builder()->context(), |
| 2674 base, mul); |
| 2430 total_size->ClearFlag(HValue::kCanOverflow); | 2675 total_size->ClearFlag(HValue::kCanOverflow); |
| 2676 builder()->AddInstruction(total_size); |
| 2431 return total_size; | 2677 return total_size; |
| 2432 } | 2678 } |
| 2433 | 2679 |
| 2434 | 2680 |
| 2435 HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() { | 2681 HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() { |
| 2436 int base_size = JSArray::kSize; | 2682 int base_size = JSArray::kSize; |
| 2437 if (mode_ == TRACK_ALLOCATION_SITE) { | 2683 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2438 base_size += AllocationMemento::kSize; | 2684 base_size += AllocationMemento::kSize; |
| 2439 } | 2685 } |
| 2440 | 2686 |
| 2441 base_size += IsFastDoubleElementsKind(kind_) | 2687 base_size += IsFastDoubleElementsKind(kind_) |
| 2442 ? FixedDoubleArray::SizeFor(initial_capacity()) | 2688 ? FixedDoubleArray::SizeFor(initial_capacity()) |
| 2443 : FixedArray::SizeFor(initial_capacity()); | 2689 : FixedArray::SizeFor(initial_capacity()); |
| 2444 | 2690 |
| 2445 return builder()->Add<HConstant>(base_size); | 2691 return builder()->Add<HConstant>(base_size); |
| 2446 } | 2692 } |
| 2447 | 2693 |
| 2448 | 2694 |
| 2449 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { | 2695 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { |
| 2450 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); | 2696 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); |
| 2451 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); | 2697 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); |
| 2452 return AllocateArray(size_in_bytes, | 2698 return AllocateArray(size_in_bytes, |
| 2453 capacity, | 2699 capacity, |
| 2454 builder()->graph()->GetConstant0(), | 2700 builder()->graph()->GetConstant0()); |
| 2455 true); | |
| 2456 } | 2701 } |
| 2457 | 2702 |
| 2458 | 2703 |
| 2459 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, | 2704 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, |
| 2460 HValue* length_field, | 2705 HValue* length_field, |
| 2461 bool fill_with_hole) { | 2706 FillMode fill_mode) { |
| 2462 HValue* size_in_bytes = EstablishAllocationSize(capacity); | 2707 HValue* size_in_bytes = EstablishAllocationSize(capacity); |
| 2463 return AllocateArray(size_in_bytes, capacity, length_field, fill_with_hole); | 2708 return AllocateArray(size_in_bytes, capacity, length_field, fill_mode); |
| 2464 } | 2709 } |
| 2465 | 2710 |
| 2466 | 2711 |
| 2467 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, | 2712 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, |
| 2468 HValue* capacity, | 2713 HValue* capacity, |
| 2469 HValue* length_field, | 2714 HValue* length_field, |
| 2470 bool fill_with_hole) { | 2715 FillMode fill_mode) { |
| 2471 // These HForceRepresentations are because we store these as fields in the | 2716 // These HForceRepresentations are because we store these as fields in the |
| 2472 // objects we construct, and an int32-to-smi HChange could deopt. Accept | 2717 // objects we construct, and an int32-to-smi HChange could deopt. Accept |
| 2473 // the deopt possibility now, before allocation occurs. | 2718 // the deopt possibility now, before allocation occurs. |
| 2474 capacity = builder()->Add<HForceRepresentation>(capacity, | 2719 capacity = builder()->Add<HForceRepresentation>(capacity, |
| 2475 Representation::Smi()); | 2720 Representation::Smi()); |
| 2476 length_field = builder()->Add<HForceRepresentation>(length_field, | 2721 length_field = builder()->Add<HForceRepresentation>(length_field, |
| 2477 Representation::Smi()); | 2722 Representation::Smi()); |
| 2478 // Allocate (dealing with failure appropriately) | 2723 // Allocate (dealing with failure appropriately) |
| 2479 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, | 2724 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, |
| 2480 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); | 2725 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2494 elements_location_ = builder()->BuildJSArrayHeader(new_object, | 2739 elements_location_ = builder()->BuildJSArrayHeader(new_object, |
| 2495 map, | 2740 map, |
| 2496 mode_, | 2741 mode_, |
| 2497 kind_, | 2742 kind_, |
| 2498 allocation_site_payload_, | 2743 allocation_site_payload_, |
| 2499 length_field); | 2744 length_field); |
| 2500 | 2745 |
| 2501 // Initialize the elements | 2746 // Initialize the elements |
| 2502 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); | 2747 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); |
| 2503 | 2748 |
| 2504 if (fill_with_hole) { | 2749 if (fill_mode == FILL_WITH_HOLE) { |
| 2505 builder()->BuildFillElementsWithHole(elements_location_, kind_, | 2750 builder()->BuildFillElementsWithHole(elements_location_, kind_, |
| 2506 graph()->GetConstant0(), capacity); | 2751 graph()->GetConstant0(), capacity); |
| 2507 } | 2752 } |
| 2508 | 2753 |
| 2509 return new_object; | 2754 return new_object; |
| 2510 } | 2755 } |
| 2511 | 2756 |
| 2512 | 2757 |
| 2513 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, | 2758 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, |
| 2514 Handle<Map> map) { | 2759 Handle<Map> map) { |
| (...skipping 4185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6700 | 6945 |
| 6701 | 6946 |
| 6702 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { | 6947 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { |
| 6703 if (!FLAG_use_inlining) return kNotInlinable; | 6948 if (!FLAG_use_inlining) return kNotInlinable; |
| 6704 | 6949 |
| 6705 // Precondition: call is monomorphic and we have found a target with the | 6950 // Precondition: call is monomorphic and we have found a target with the |
| 6706 // appropriate arity. | 6951 // appropriate arity. |
| 6707 Handle<JSFunction> caller = current_info()->closure(); | 6952 Handle<JSFunction> caller = current_info()->closure(); |
| 6708 Handle<SharedFunctionInfo> target_shared(target->shared()); | 6953 Handle<SharedFunctionInfo> target_shared(target->shared()); |
| 6709 | 6954 |
| 6955 // Always inline builtins marked for inlining. |
| 6956 if (target->IsBuiltin()) { |
| 6957 return target_shared->inline_builtin() ? 0 : kNotInlinable; |
| 6958 } |
| 6959 |
| 6710 // Do a quick check on source code length to avoid parsing large | 6960 // Do a quick check on source code length to avoid parsing large |
| 6711 // inlining candidates. | 6961 // inlining candidates. |
| 6712 if (target_shared->SourceSize() > | 6962 if (target_shared->SourceSize() > |
| 6713 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { | 6963 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { |
| 6714 TraceInline(target, caller, "target text too big"); | 6964 TraceInline(target, caller, "target text too big"); |
| 6715 return kNotInlinable; | 6965 return kNotInlinable; |
| 6716 } | 6966 } |
| 6717 | 6967 |
| 6718 // Target must be inlineable. | 6968 // Target must be inlineable. |
| 6719 if (!target->IsInlineable()) { | 6969 if (!target_shared->IsInlineable()) { |
| 6720 TraceInline(target, caller, "target not inlineable"); | 6970 TraceInline(target, caller, "target not inlineable"); |
| 6721 return kNotInlinable; | 6971 return kNotInlinable; |
| 6722 } | 6972 } |
| 6723 if (target_shared->dont_inline() || target_shared->dont_optimize()) { | 6973 if (target_shared->dont_inline() || target_shared->dont_optimize()) { |
| 6724 TraceInline(target, caller, "target contains unsupported syntax [early]"); | 6974 TraceInline(target, caller, "target contains unsupported syntax [early]"); |
| 6725 return kNotInlinable; | 6975 return kNotInlinable; |
| 6726 } | 6976 } |
| 6727 | 6977 |
| 6728 int nodes_added = target_shared->ast_node_count(); | 6978 int nodes_added = target_shared->ast_node_count(); |
| 6729 return nodes_added; | 6979 return nodes_added; |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7089 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7339 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 7090 switch (id) { | 7340 switch (id) { |
| 7091 case kMathExp: | 7341 case kMathExp: |
| 7092 if (!FLAG_fast_math) break; | 7342 if (!FLAG_fast_math) break; |
| 7093 // Fall through if FLAG_fast_math. | 7343 // Fall through if FLAG_fast_math. |
| 7094 case kMathRound: | 7344 case kMathRound: |
| 7095 case kMathFloor: | 7345 case kMathFloor: |
| 7096 case kMathAbs: | 7346 case kMathAbs: |
| 7097 case kMathSqrt: | 7347 case kMathSqrt: |
| 7098 case kMathLog: | 7348 case kMathLog: |
| 7099 case kMathSin: | |
| 7100 case kMathCos: | |
| 7101 case kMathTan: | |
| 7102 if (expr->arguments()->length() == 1) { | 7349 if (expr->arguments()->length() == 1) { |
| 7103 HValue* argument = Pop(); | 7350 HValue* argument = Pop(); |
| 7104 Drop(1); // Receiver. | 7351 Drop(1); // Receiver. |
| 7105 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7352 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 7106 if (drop_extra) Drop(1); // Optionally drop the function. | 7353 if (drop_extra) Drop(1); // Optionally drop the function. |
| 7107 ast_context()->ReturnInstruction(op, expr->id()); | 7354 ast_context()->ReturnInstruction(op, expr->id()); |
| 7108 return true; | 7355 return true; |
| 7109 } | 7356 } |
| 7110 break; | 7357 break; |
| 7111 case kMathImul: | 7358 case kMathImul: |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7170 } | 7417 } |
| 7171 break; | 7418 break; |
| 7172 case kMathExp: | 7419 case kMathExp: |
| 7173 if (!FLAG_fast_math) break; | 7420 if (!FLAG_fast_math) break; |
| 7174 // Fall through if FLAG_fast_math. | 7421 // Fall through if FLAG_fast_math. |
| 7175 case kMathRound: | 7422 case kMathRound: |
| 7176 case kMathFloor: | 7423 case kMathFloor: |
| 7177 case kMathAbs: | 7424 case kMathAbs: |
| 7178 case kMathSqrt: | 7425 case kMathSqrt: |
| 7179 case kMathLog: | 7426 case kMathLog: |
| 7180 case kMathSin: | |
| 7181 case kMathCos: | |
| 7182 case kMathTan: | |
| 7183 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 7427 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| 7184 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | 7428 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
| 7185 HValue* argument = Pop(); | 7429 HValue* argument = Pop(); |
| 7186 Drop(1); // Receiver. | 7430 Drop(1); // Receiver. |
| 7187 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7431 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 7188 ast_context()->ReturnInstruction(op, expr->id()); | 7432 ast_context()->ReturnInstruction(op, expr->id()); |
| 7189 return true; | 7433 return true; |
| 7190 } | 7434 } |
| 7191 break; | 7435 break; |
| 7192 case kMathPow: | 7436 case kMathPow: |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7351 ASSERT(current_block() != NULL); | 7595 ASSERT(current_block() != NULL); |
| 7352 ASSERT(current_block()->HasPredecessor()); | 7596 ASSERT(current_block()->HasPredecessor()); |
| 7353 Expression* callee = expr->expression(); | 7597 Expression* callee = expr->expression(); |
| 7354 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 7598 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 7355 HInstruction* call = NULL; | 7599 HInstruction* call = NULL; |
| 7356 | 7600 |
| 7357 Property* prop = callee->AsProperty(); | 7601 Property* prop = callee->AsProperty(); |
| 7358 if (prop != NULL) { | 7602 if (prop != NULL) { |
| 7359 if (!prop->key()->IsPropertyName()) { | 7603 if (!prop->key()->IsPropertyName()) { |
| 7360 // Keyed function call. | 7604 // Keyed function call. |
| 7361 CHECK_ALIVE(VisitArgument(prop->obj())); | 7605 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 7606 CHECK_ALIVE(VisitForValue(prop->key())); |
| 7362 | 7607 |
| 7363 CHECK_ALIVE(VisitForValue(prop->key())); | |
| 7364 // Push receiver and key like the non-optimized code generator expects it. | 7608 // Push receiver and key like the non-optimized code generator expects it. |
| 7365 HValue* key = Pop(); | 7609 HValue* key = Pop(); |
| 7366 HValue* receiver = Pop(); | 7610 HValue* receiver = Pop(); |
| 7367 Push(key); | 7611 Push(key); |
| 7368 Push(receiver); | 7612 Push(Add<HPushArgument>(receiver)); |
| 7369 | |
| 7370 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 7613 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 7371 | 7614 |
| 7372 call = New<HCallKeyed>(key, argument_count); | 7615 if (expr->IsMonomorphic()) { |
| 7616 BuildCheckHeapObject(receiver); |
| 7617 ElementsKind kind = expr->KeyedArrayCallIsHoley() |
| 7618 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; |
| 7619 |
| 7620 Handle<Map> map(isolate()->get_initial_js_array_map(kind)); |
| 7621 |
| 7622 HValue* function = BuildMonomorphicElementAccess( |
| 7623 receiver, key, NULL, NULL, map, false, STANDARD_STORE); |
| 7624 |
| 7625 call = New<HCallFunction>(function, argument_count); |
| 7626 } else { |
| 7627 call = New<HCallKeyed>(key, argument_count); |
| 7628 } |
| 7373 Drop(argument_count + 1); // 1 is the key. | 7629 Drop(argument_count + 1); // 1 is the key. |
| 7374 return ast_context()->ReturnInstruction(call, expr->id()); | 7630 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7375 } | 7631 } |
| 7376 | 7632 |
| 7377 // Named function call. | 7633 // Named function call. |
| 7378 if (TryCallApply(expr)) return; | 7634 if (TryCallApply(expr)) return; |
| 7379 | 7635 |
| 7380 CHECK_ALIVE(VisitForValue(prop->obj())); | 7636 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 7381 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 7637 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7382 | 7638 |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7531 | 7787 |
| 7532 call = New<HCallFunction>(function, argument_count); | 7788 call = New<HCallFunction>(function, argument_count); |
| 7533 Drop(argument_count + 1); | 7789 Drop(argument_count + 1); |
| 7534 } | 7790 } |
| 7535 } | 7791 } |
| 7536 | 7792 |
| 7537 return ast_context()->ReturnInstruction(call, expr->id()); | 7793 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7538 } | 7794 } |
| 7539 | 7795 |
| 7540 | 7796 |
| 7797 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
| 7798 NoObservableSideEffectsScope no_effects(this); |
| 7799 |
| 7800 int argument_count = expr->arguments()->length(); |
| 7801 // We should at least have the constructor on the expression stack. |
| 7802 HValue* constructor = environment()->ExpressionStackAt(argument_count); |
| 7803 |
| 7804 ElementsKind kind = expr->elements_kind(); |
| 7805 Handle<Cell> cell = expr->allocation_info_cell(); |
| 7806 AllocationSite* site = AllocationSite::cast(cell->value()); |
| 7807 |
| 7808 // Register on the site for deoptimization if the cell value changes. |
| 7809 site->AddDependentCompilationInfo(AllocationSite::TRANSITIONS, top_info()); |
| 7810 HInstruction* cell_instruction = Add<HConstant>(cell); |
| 7811 |
| 7812 // In the single constant argument case, we may have to adjust elements kind |
| 7813 // to avoid creating a packed non-empty array. |
| 7814 if (argument_count == 1 && !IsHoleyElementsKind(kind)) { |
| 7815 HValue* argument = environment()->Top(); |
| 7816 if (argument->IsConstant()) { |
| 7817 HConstant* constant_argument = HConstant::cast(argument); |
| 7818 ASSERT(constant_argument->HasSmiValue()); |
| 7819 int constant_array_size = constant_argument->Integer32Value(); |
| 7820 if (constant_array_size != 0) { |
| 7821 kind = GetHoleyElementsKind(kind); |
| 7822 } |
| 7823 } |
| 7824 } |
| 7825 |
| 7826 // Build the array. |
| 7827 JSArrayBuilder array_builder(this, |
| 7828 kind, |
| 7829 cell_instruction, |
| 7830 constructor, |
| 7831 DISABLE_ALLOCATION_SITES); |
| 7832 HValue* new_object; |
| 7833 if (argument_count == 0) { |
| 7834 new_object = array_builder.AllocateEmptyArray(); |
| 7835 } else if (argument_count == 1) { |
| 7836 HValue* argument = environment()->Top(); |
| 7837 new_object = BuildAllocateArrayFromLength(&array_builder, argument); |
| 7838 } else { |
| 7839 HValue* length = Add<HConstant>(argument_count); |
| 7840 // Smi arrays need to initialize array elements with the hole because |
| 7841 // bailout could occur if the arguments don't fit in a smi. |
| 7842 // |
| 7843 // TODO(mvstanton): If all the arguments are constants in smi range, then |
| 7844 // we could set fill_with_hole to false and save a few instructions. |
| 7845 JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind) |
| 7846 ? JSArrayBuilder::FILL_WITH_HOLE |
| 7847 : JSArrayBuilder::DONT_FILL_WITH_HOLE; |
| 7848 new_object = array_builder.AllocateArray(length, length, fill_mode); |
| 7849 HValue* elements = array_builder.GetElementsLocation(); |
| 7850 for (int i = 0; i < argument_count; i++) { |
| 7851 HValue* value = environment()->ExpressionStackAt(argument_count - i - 1); |
| 7852 HValue* constant_i = Add<HConstant>(i); |
| 7853 Add<HStoreKeyed>(elements, constant_i, value, kind); |
| 7854 } |
| 7855 } |
| 7856 |
| 7857 Drop(argument_count + 1); // drop constructor and args. |
| 7858 ast_context()->ReturnValue(new_object); |
| 7859 } |
| 7860 |
| 7861 |
| 7541 // Checks whether allocation using the given constructor can be inlined. | 7862 // Checks whether allocation using the given constructor can be inlined. |
| 7542 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 7863 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
| 7543 return constructor->has_initial_map() && | 7864 return constructor->has_initial_map() && |
| 7544 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 7865 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
| 7545 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && | 7866 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
| 7546 constructor->initial_map()->InitialPropertiesLength() == 0; | 7867 constructor->initial_map()->InitialPropertiesLength() == 0; |
| 7547 } | 7868 } |
| 7548 | 7869 |
| 7549 | 7870 |
| 7871 bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { |
| 7872 bool inline_ok = false; |
| 7873 Handle<JSFunction> caller = current_info()->closure(); |
| 7874 Handle<JSFunction> target(isolate()->global_context()->array_function(), |
| 7875 isolate()); |
| 7876 int argument_count = expr->arguments()->length(); |
| 7877 // We should have the function plus array arguments on the environment stack. |
| 7878 ASSERT(environment()->length() >= (argument_count + 1)); |
| 7879 Handle<Cell> cell = expr->allocation_info_cell(); |
| 7880 AllocationSite* site = AllocationSite::cast(cell->value()); |
| 7881 if (site->CanInlineCall()) { |
| 7882 // We also want to avoid inlining in certain 1 argument scenarios. |
| 7883 if (argument_count == 1) { |
| 7884 HValue* argument = Top(); |
| 7885 if (argument->IsConstant()) { |
| 7886 // Do not inline if the constant length argument is not a smi or |
| 7887 // outside the valid range for a fast array. |
| 7888 HConstant* constant_argument = HConstant::cast(argument); |
| 7889 if (constant_argument->HasSmiValue()) { |
| 7890 int value = constant_argument->Integer32Value(); |
| 7891 inline_ok = value >= 0 && |
| 7892 value < JSObject::kInitialMaxFastElementArray; |
| 7893 if (!inline_ok) { |
| 7894 TraceInline(target, caller, |
| 7895 "Length outside of valid array range"); |
| 7896 } |
| 7897 } |
| 7898 } else { |
| 7899 inline_ok = true; |
| 7900 } |
| 7901 } else { |
| 7902 inline_ok = true; |
| 7903 } |
| 7904 } else { |
| 7905 TraceInline(target, caller, "AllocationSite requested no inlining."); |
| 7906 } |
| 7907 |
| 7908 if (inline_ok) { |
| 7909 TraceInline(target, caller, NULL); |
| 7910 } |
| 7911 return inline_ok; |
| 7912 } |
| 7913 |
| 7914 |
| 7550 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 7915 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| 7551 ASSERT(!HasStackOverflow()); | 7916 ASSERT(!HasStackOverflow()); |
| 7552 ASSERT(current_block() != NULL); | 7917 ASSERT(current_block() != NULL); |
| 7553 ASSERT(current_block()->HasPredecessor()); | 7918 ASSERT(current_block()->HasPredecessor()); |
| 7554 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 7919 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 7555 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 7920 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 7556 Factory* factory = isolate()->factory(); | 7921 Factory* factory = isolate()->factory(); |
| 7557 | 7922 |
| 7923 // The constructor function is on the stack in the unoptimized code |
| 7924 // during evaluation of the arguments. |
| 7925 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 7926 HValue* function = Top(); |
| 7927 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7928 |
| 7558 if (FLAG_inline_construct && | 7929 if (FLAG_inline_construct && |
| 7559 expr->IsMonomorphic() && | 7930 expr->IsMonomorphic() && |
| 7560 IsAllocationInlineable(expr->target())) { | 7931 IsAllocationInlineable(expr->target())) { |
| 7561 // The constructor function is on the stack in the unoptimized code | |
| 7562 // during evaluation of the arguments. | |
| 7563 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 7564 HValue* function = Top(); | |
| 7565 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
| 7566 Handle<JSFunction> constructor = expr->target(); | 7932 Handle<JSFunction> constructor = expr->target(); |
| 7567 HValue* check = Add<HCheckValue>(function, constructor); | 7933 HValue* check = Add<HCheckValue>(function, constructor); |
| 7568 | 7934 |
| 7569 // Force completion of inobject slack tracking before generating | 7935 // Force completion of inobject slack tracking before generating |
| 7570 // allocation code to finalize instance size. | 7936 // allocation code to finalize instance size. |
| 7571 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { | 7937 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { |
| 7572 constructor->shared()->CompleteInobjectSlackTracking(); | 7938 constructor->shared()->CompleteInobjectSlackTracking(); |
| 7573 } | 7939 } |
| 7574 | 7940 |
| 7575 // Calculate instance size from initial map of constructor. | 7941 // Calculate instance size from initial map of constructor. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7642 check->DeleteAndReplaceWith(NULL); | 8008 check->DeleteAndReplaceWith(NULL); |
| 7643 environment()->SetExpressionStackAt(receiver_index, function); | 8009 environment()->SetExpressionStackAt(receiver_index, function); |
| 7644 HInstruction* call = | 8010 HInstruction* call = |
| 7645 PreProcessCall(New<HCallNew>(function, argument_count)); | 8011 PreProcessCall(New<HCallNew>(function, argument_count)); |
| 7646 return ast_context()->ReturnInstruction(call, expr->id()); | 8012 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7647 } else { | 8013 } else { |
| 7648 // The constructor function is both an operand to the instruction and an | 8014 // The constructor function is both an operand to the instruction and an |
| 7649 // argument to the construct call. | 8015 // argument to the construct call. |
| 7650 Handle<JSFunction> array_function( | 8016 Handle<JSFunction> array_function( |
| 7651 isolate()->global_context()->array_function(), isolate()); | 8017 isolate()->global_context()->array_function(), isolate()); |
| 7652 CHECK_ALIVE(VisitArgument(expr->expression())); | 8018 bool use_call_new_array = expr->target().is_identical_to(array_function); |
| 7653 HValue* constructor = HPushArgument::cast(Top())->argument(); | 8019 Handle<Cell> cell = expr->allocation_info_cell(); |
| 7654 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8020 if (use_call_new_array && IsCallNewArrayInlineable(expr)) { |
| 8021 // Verify we are still calling the array function for our native context. |
| 8022 Add<HCheckValue>(function, array_function); |
| 8023 BuildInlinedCallNewArray(expr); |
| 8024 return; |
| 8025 } |
| 8026 |
| 7655 HBinaryCall* call; | 8027 HBinaryCall* call; |
| 7656 if (expr->target().is_identical_to(array_function)) { | 8028 if (use_call_new_array) { |
| 7657 Handle<Cell> cell = expr->allocation_info_cell(); | 8029 Add<HCheckValue>(function, array_function); |
| 7658 Add<HCheckValue>(constructor, array_function); | 8030 call = New<HCallNewArray>(function, argument_count, cell, |
| 7659 call = New<HCallNewArray>(constructor, argument_count, | 8031 expr->elements_kind()); |
| 7660 cell, expr->elements_kind()); | |
| 7661 } else { | 8032 } else { |
| 7662 call = New<HCallNew>(constructor, argument_count); | 8033 call = New<HCallNew>(function, argument_count); |
| 7663 } | 8034 } |
| 7664 Drop(argument_count); | 8035 PreProcessCall(call); |
| 7665 return ast_context()->ReturnInstruction(call, expr->id()); | 8036 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7666 } | 8037 } |
| 7667 } | 8038 } |
| 7668 | 8039 |
| 7669 | 8040 |
| 7670 // Support for generating inlined runtime functions. | 8041 // Support for generating inlined runtime functions. |
| 7671 | 8042 |
| 7672 // Lookup table for generators for runtime calls that are generated inline. | 8043 // Lookup table for generators for runtime calls that are generated inline. |
| 7673 // Elements of the table are member pointers to functions of | 8044 // Elements of the table are member pointers to functions of |
| 7674 // HOptimizedGraphBuilder. | 8045 // HOptimizedGraphBuilder. |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8191 Deoptimizer::SOFT); | 8562 Deoptimizer::SOFT); |
| 8192 right_type = handle(Type::Any(), isolate()); | 8563 right_type = handle(Type::Any(), isolate()); |
| 8193 } else { | 8564 } else { |
| 8194 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); | 8565 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); |
| 8195 right_rep = Representation::FromType(right_type); | 8566 right_rep = Representation::FromType(right_type); |
| 8196 } | 8567 } |
| 8197 | 8568 |
| 8198 // Special case for string addition here. | 8569 // Special case for string addition here. |
| 8199 if (op == Token::ADD && | 8570 if (op == Token::ADD && |
| 8200 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { | 8571 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { |
| 8572 // Validate type feedback for left argument. |
| 8201 if (left_type->Is(Type::String())) { | 8573 if (left_type->Is(Type::String())) { |
| 8202 IfBuilder if_isstring(this); | 8574 IfBuilder if_isstring(this); |
| 8203 if_isstring.If<HIsStringAndBranch>(left); | 8575 if_isstring.If<HIsStringAndBranch>(left); |
| 8204 if_isstring.Then(); | 8576 if_isstring.Then(); |
| 8205 if_isstring.ElseDeopt("Expected string for LHS of binary operation"); | 8577 if_isstring.ElseDeopt("Expected string for LHS of binary operation"); |
| 8206 } else if (left_type->Is(Type::Number())) { | 8578 } |
| 8579 |
| 8580 // Validate type feedback for right argument. |
| 8581 if (right_type->Is(Type::String())) { |
| 8582 IfBuilder if_isstring(this); |
| 8583 if_isstring.If<HIsStringAndBranch>(right); |
| 8584 if_isstring.Then(); |
| 8585 if_isstring.ElseDeopt("Expected string for RHS of binary operation"); |
| 8586 } |
| 8587 |
| 8588 // Convert left argument as necessary. |
| 8589 if (left_type->Is(Type::Number())) { |
| 8590 ASSERT(right_type->Is(Type::String())); |
| 8207 left = BuildNumberToString(left, left_type); | 8591 left = BuildNumberToString(left, left_type); |
| 8208 } else { | 8592 } else if (!left_type->Is(Type::String())) { |
| 8209 ASSERT(right_type->Is(Type::String())); | 8593 ASSERT(right_type->Is(Type::String())); |
| 8210 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT); | 8594 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT); |
| 8211 Add<HPushArgument>(left); | 8595 Add<HPushArgument>(left); |
| 8212 Add<HPushArgument>(right); | 8596 Add<HPushArgument>(right); |
| 8213 return NewUncasted<HInvokeFunction>(function, 2); | 8597 return NewUncasted<HInvokeFunction>(function, 2); |
| 8214 } | 8598 } |
| 8215 | 8599 |
| 8216 if (right_type->Is(Type::String())) { | 8600 // Convert right argument as necessary. |
| 8217 IfBuilder if_isstring(this); | 8601 if (right_type->Is(Type::Number())) { |
| 8218 if_isstring.If<HIsStringAndBranch>(right); | 8602 ASSERT(left_type->Is(Type::String())); |
| 8219 if_isstring.Then(); | |
| 8220 if_isstring.ElseDeopt("Expected string for RHS of binary operation"); | |
| 8221 } else if (right_type->Is(Type::Number())) { | |
| 8222 right = BuildNumberToString(right, right_type); | 8603 right = BuildNumberToString(right, right_type); |
| 8223 } else { | 8604 } else if (!right_type->Is(Type::String())) { |
| 8224 ASSERT(left_type->Is(Type::String())); | 8605 ASSERT(left_type->Is(Type::String())); |
| 8225 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); | 8606 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); |
| 8226 Add<HPushArgument>(left); | 8607 Add<HPushArgument>(left); |
| 8227 Add<HPushArgument>(right); | 8608 Add<HPushArgument>(right); |
| 8228 return NewUncasted<HInvokeFunction>(function, 2); | 8609 return NewUncasted<HInvokeFunction>(function, 2); |
| 8229 } | 8610 } |
| 8230 | 8611 |
| 8231 return NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE); | 8612 return NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE); |
| 8232 } | 8613 } |
| 8233 | 8614 |
| (...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9109 void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) { | 9490 void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) { |
| 9110 ASSERT(call->arguments()->length() == 1); | 9491 ASSERT(call->arguments()->length() == 1); |
| 9111 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9492 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9112 HValue* value = Pop(); | 9493 HValue* value = Pop(); |
| 9113 HHasInstanceTypeAndBranch* result = | 9494 HHasInstanceTypeAndBranch* result = |
| 9114 New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE); | 9495 New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE); |
| 9115 return ast_context()->ReturnControl(result, call->id()); | 9496 return ast_context()->ReturnControl(result, call->id()); |
| 9116 } | 9497 } |
| 9117 | 9498 |
| 9118 | 9499 |
| 9500 void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) { |
| 9501 ASSERT(call->arguments()->length() == 1); |
| 9502 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9503 HValue* value = Pop(); |
| 9504 HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value); |
| 9505 return ast_context()->ReturnControl(result, call->id()); |
| 9506 } |
| 9507 |
| 9508 |
| 9119 void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { | 9509 void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { |
| 9120 ASSERT(call->arguments()->length() == 1); | 9510 ASSERT(call->arguments()->length() == 1); |
| 9121 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9511 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9122 HValue* value = Pop(); | 9512 HValue* value = Pop(); |
| 9123 HHasCachedArrayIndexAndBranch* result = | 9513 HHasCachedArrayIndexAndBranch* result = |
| 9124 New<HHasCachedArrayIndexAndBranch>(value); | 9514 New<HHasCachedArrayIndexAndBranch>(value); |
| 9125 return ast_context()->ReturnControl(result, call->id()); | 9515 return ast_context()->ReturnControl(result, call->id()); |
| 9126 } | 9516 } |
| 9127 | 9517 |
| 9128 | 9518 |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9492 ASSERT_EQ(2, call->arguments()->length()); | 9882 ASSERT_EQ(2, call->arguments()->length()); |
| 9493 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9883 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9494 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 9884 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 9495 HValue* right = Pop(); | 9885 HValue* right = Pop(); |
| 9496 HValue* left = Pop(); | 9886 HValue* left = Pop(); |
| 9497 HInstruction* result = NewUncasted<HPower>(left, right); | 9887 HInstruction* result = NewUncasted<HPower>(left, right); |
| 9498 return ast_context()->ReturnInstruction(result, call->id()); | 9888 return ast_context()->ReturnInstruction(result, call->id()); |
| 9499 } | 9889 } |
| 9500 | 9890 |
| 9501 | 9891 |
| 9502 void HOptimizedGraphBuilder::GenerateMathSin(CallRuntime* call) { | |
| 9503 ASSERT_EQ(1, call->arguments()->length()); | |
| 9504 CHECK_ALIVE(VisitArgumentList(call->arguments())); | |
| 9505 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | |
| 9506 result->set_transcendental_type(TranscendentalCache::SIN); | |
| 9507 Drop(1); | |
| 9508 return ast_context()->ReturnInstruction(result, call->id()); | |
| 9509 } | |
| 9510 | |
| 9511 | |
| 9512 void HOptimizedGraphBuilder::GenerateMathCos(CallRuntime* call) { | |
| 9513 ASSERT_EQ(1, call->arguments()->length()); | |
| 9514 CHECK_ALIVE(VisitArgumentList(call->arguments())); | |
| 9515 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | |
| 9516 result->set_transcendental_type(TranscendentalCache::COS); | |
| 9517 Drop(1); | |
| 9518 return ast_context()->ReturnInstruction(result, call->id()); | |
| 9519 } | |
| 9520 | |
| 9521 | |
| 9522 void HOptimizedGraphBuilder::GenerateMathTan(CallRuntime* call) { | |
| 9523 ASSERT_EQ(1, call->arguments()->length()); | |
| 9524 CHECK_ALIVE(VisitArgumentList(call->arguments())); | |
| 9525 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | |
| 9526 result->set_transcendental_type(TranscendentalCache::TAN); | |
| 9527 Drop(1); | |
| 9528 return ast_context()->ReturnInstruction(result, call->id()); | |
| 9529 } | |
| 9530 | |
| 9531 | |
| 9532 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) { | 9892 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) { |
| 9533 ASSERT_EQ(1, call->arguments()->length()); | 9893 ASSERT_EQ(1, call->arguments()->length()); |
| 9534 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 9894 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 9535 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | 9895 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); |
| 9536 result->set_transcendental_type(TranscendentalCache::LOG); | 9896 result->set_transcendental_type(TranscendentalCache::LOG); |
| 9537 Drop(1); | 9897 Drop(1); |
| 9538 return ast_context()->ReturnInstruction(result, call->id()); | 9898 return ast_context()->ReturnInstruction(result, call->id()); |
| 9539 } | 9899 } |
| 9540 | 9900 |
| 9541 | 9901 |
| (...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10192 if (ShouldProduceTraceOutput()) { | 10552 if (ShouldProduceTraceOutput()) { |
| 10193 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10553 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10194 } | 10554 } |
| 10195 | 10555 |
| 10196 #ifdef DEBUG | 10556 #ifdef DEBUG |
| 10197 graph_->Verify(false); // No full verify. | 10557 graph_->Verify(false); // No full verify. |
| 10198 #endif | 10558 #endif |
| 10199 } | 10559 } |
| 10200 | 10560 |
| 10201 } } // namespace v8::internal | 10561 } } // namespace v8::internal |
| OLD | NEW |