| 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 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 phi->Verify(); | 598 phi->Verify(); |
| 599 } | 599 } |
| 600 | 600 |
| 601 // Check that all join blocks have predecessors that end with an | 601 // Check that all join blocks have predecessors that end with an |
| 602 // unconditional goto and agree on their environment node id. | 602 // unconditional goto and agree on their environment node id. |
| 603 if (block->predecessors()->length() >= 2) { | 603 if (block->predecessors()->length() >= 2) { |
| 604 BailoutId id = | 604 BailoutId id = |
| 605 block->predecessors()->first()->last_environment()->ast_id(); | 605 block->predecessors()->first()->last_environment()->ast_id(); |
| 606 for (int k = 0; k < block->predecessors()->length(); k++) { | 606 for (int k = 0; k < block->predecessors()->length(); k++) { |
| 607 HBasicBlock* predecessor = block->predecessors()->at(k); | 607 HBasicBlock* predecessor = block->predecessors()->at(k); |
| 608 ASSERT(predecessor->end()->IsGoto()); | 608 ASSERT(predecessor->end()->IsGoto() || |
| 609 predecessor->end()->IsDeoptimize()); |
| 609 ASSERT(predecessor->last_environment()->ast_id() == id); | 610 ASSERT(predecessor->last_environment()->ast_id() == id); |
| 610 } | 611 } |
| 611 } | 612 } |
| 612 } | 613 } |
| 613 | 614 |
| 614 // Check special property of first block to have no predecessors. | 615 // Check special property of first block to have no predecessors. |
| 615 ASSERT(blocks_.at(0)->predecessors()->is_empty()); | 616 ASSERT(blocks_.at(0)->predecessors()->is_empty()); |
| 616 | 617 |
| 617 if (do_full_verify) { | 618 if (do_full_verify) { |
| 618 // Check that the graph is fully connected. | 619 // Check that the graph is fully connected. |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 if (IsConstantFalse(constant)) return true; | 739 if (IsConstantFalse(constant)) return true; |
| 739 if (IsConstantHole(constant)) return true; | 740 if (IsConstantHole(constant)) return true; |
| 740 if (IsConstantNull(constant)) return true; | 741 if (IsConstantNull(constant)) return true; |
| 741 return false; | 742 return false; |
| 742 } | 743 } |
| 743 | 744 |
| 744 | 745 |
| 745 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) | 746 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) |
| 746 : builder_(builder), | 747 : builder_(builder), |
| 747 finished_(false), | 748 finished_(false), |
| 748 deopt_then_(false), | |
| 749 deopt_else_(false), | |
| 750 did_then_(false), | 749 did_then_(false), |
| 751 did_else_(false), | 750 did_else_(false), |
| 751 did_else_if_(false), |
| 752 did_and_(false), | 752 did_and_(false), |
| 753 did_or_(false), | 753 did_or_(false), |
| 754 captured_(false), | 754 captured_(false), |
| 755 needs_compare_(true), | 755 needs_compare_(true), |
| 756 pending_merge_block_(false), |
| 756 split_edge_merge_block_(NULL), | 757 split_edge_merge_block_(NULL), |
| 757 merge_block_(NULL) { | 758 merge_at_join_blocks_(NULL), |
| 759 normal_merge_at_join_block_count_(0), |
| 760 deopt_merge_at_join_block_count_(0) { |
| 758 HEnvironment* env = builder->environment(); | 761 HEnvironment* env = builder->environment(); |
| 759 first_true_block_ = builder->CreateBasicBlock(env->Copy()); | 762 first_true_block_ = builder->CreateBasicBlock(env->Copy()); |
| 760 last_true_block_ = NULL; | |
| 761 first_false_block_ = builder->CreateBasicBlock(env->Copy()); | 763 first_false_block_ = builder->CreateBasicBlock(env->Copy()); |
| 762 } | 764 } |
| 763 | 765 |
| 764 | 766 |
| 765 HGraphBuilder::IfBuilder::IfBuilder( | 767 HGraphBuilder::IfBuilder::IfBuilder( |
| 766 HGraphBuilder* builder, | 768 HGraphBuilder* builder, |
| 767 HIfContinuation* continuation) | 769 HIfContinuation* continuation) |
| 768 : builder_(builder), | 770 : builder_(builder), |
| 769 finished_(false), | 771 finished_(false), |
| 770 deopt_then_(false), | |
| 771 deopt_else_(false), | |
| 772 did_then_(false), | 772 did_then_(false), |
| 773 did_else_(false), | 773 did_else_(false), |
| 774 did_else_if_(false), |
| 774 did_and_(false), | 775 did_and_(false), |
| 775 did_or_(false), | 776 did_or_(false), |
| 776 captured_(false), | 777 captured_(false), |
| 777 needs_compare_(false), | 778 needs_compare_(false), |
| 779 pending_merge_block_(false), |
| 778 first_true_block_(NULL), | 780 first_true_block_(NULL), |
| 779 last_true_block_(NULL), | |
| 780 first_false_block_(NULL), | 781 first_false_block_(NULL), |
| 781 split_edge_merge_block_(NULL), | 782 split_edge_merge_block_(NULL), |
| 782 merge_block_(NULL) { | 783 merge_at_join_blocks_(NULL), |
| 784 normal_merge_at_join_block_count_(0), |
| 785 deopt_merge_at_join_block_count_(0) { |
| 783 continuation->Continue(&first_true_block_, | 786 continuation->Continue(&first_true_block_, |
| 784 &first_false_block_); | 787 &first_false_block_); |
| 785 } | 788 } |
| 786 | 789 |
| 787 | 790 |
| 788 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( | 791 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( |
| 789 HControlInstruction* compare) { | 792 HControlInstruction* compare) { |
| 793 ASSERT(did_then_ == did_else_); |
| 794 if (did_else_) { |
| 795 // Handle if-then-elseif |
| 796 did_else_if_ = true; |
| 797 did_else_ = false; |
| 798 did_then_ = false; |
| 799 did_and_ = false; |
| 800 did_or_ = false; |
| 801 pending_merge_block_ = false; |
| 802 split_edge_merge_block_ = NULL; |
| 803 HEnvironment* env = builder_->environment(); |
| 804 first_true_block_ = builder_->CreateBasicBlock(env->Copy()); |
| 805 first_false_block_ = builder_->CreateBasicBlock(env->Copy()); |
| 806 } |
| 790 if (split_edge_merge_block_ != NULL) { | 807 if (split_edge_merge_block_ != NULL) { |
| 791 HEnvironment* env = first_false_block_->last_environment(); | 808 HEnvironment* env = first_false_block_->last_environment(); |
| 792 HBasicBlock* split_edge = | 809 HBasicBlock* split_edge = |
| 793 builder_->CreateBasicBlock(env->Copy()); | 810 builder_->CreateBasicBlock(env->Copy()); |
| 794 if (did_or_) { | 811 if (did_or_) { |
| 795 compare->SetSuccessorAt(0, split_edge); | 812 compare->SetSuccessorAt(0, split_edge); |
| 796 compare->SetSuccessorAt(1, first_false_block_); | 813 compare->SetSuccessorAt(1, first_false_block_); |
| 797 } else { | 814 } else { |
| 798 compare->SetSuccessorAt(0, first_true_block_); | 815 compare->SetSuccessorAt(0, first_true_block_); |
| 799 compare->SetSuccessorAt(1, split_edge); | 816 compare->SetSuccessorAt(1, split_edge); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 835 builder_->GotoNoSimulate(first_false_block_, split_edge_merge_block_); | 852 builder_->GotoNoSimulate(first_false_block_, split_edge_merge_block_); |
| 836 first_false_block_ = split_edge_merge_block_; | 853 first_false_block_ = split_edge_merge_block_; |
| 837 } | 854 } |
| 838 builder_->set_current_block(first_true_block_); | 855 builder_->set_current_block(first_true_block_); |
| 839 first_true_block_ = builder_->CreateBasicBlock(env->Copy()); | 856 first_true_block_ = builder_->CreateBasicBlock(env->Copy()); |
| 840 } | 857 } |
| 841 | 858 |
| 842 | 859 |
| 843 void HGraphBuilder::IfBuilder::CaptureContinuation( | 860 void HGraphBuilder::IfBuilder::CaptureContinuation( |
| 844 HIfContinuation* continuation) { | 861 HIfContinuation* continuation) { |
| 862 ASSERT(!did_else_if_); |
| 845 ASSERT(!finished_); | 863 ASSERT(!finished_); |
| 846 ASSERT(!captured_); | 864 ASSERT(!captured_); |
| 847 HBasicBlock* true_block = last_true_block_ == NULL | 865 |
| 848 ? first_true_block_ | 866 HBasicBlock* true_block = NULL; |
| 849 : last_true_block_; | 867 HBasicBlock* false_block = NULL; |
| 850 HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) | 868 Finish(&true_block, &false_block); |
| 851 ? builder_->current_block() | 869 ASSERT(true_block != NULL); |
| 852 : first_false_block_; | 870 ASSERT(false_block != NULL); |
| 853 continuation->Capture(true_block, false_block); | 871 continuation->Capture(true_block, false_block); |
| 854 captured_ = true; | 872 captured_ = true; |
| 873 builder_->set_current_block(NULL); |
| 855 End(); | 874 End(); |
| 856 } | 875 } |
| 857 | 876 |
| 858 | 877 |
| 859 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { | 878 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { |
| 879 ASSERT(!did_else_if_); |
| 860 ASSERT(!finished_); | 880 ASSERT(!finished_); |
| 861 ASSERT(!captured_); | 881 ASSERT(!captured_); |
| 862 ASSERT(did_then_); | 882 HBasicBlock* true_block = NULL; |
| 863 if (!did_else_) Else(); | 883 HBasicBlock* false_block = NULL; |
| 864 HBasicBlock* true_block = last_true_block_ == NULL | 884 Finish(&true_block, &false_block); |
| 865 ? first_true_block_ | 885 merge_at_join_blocks_ = NULL; |
| 866 : last_true_block_; | |
| 867 HBasicBlock* false_block = builder_->current_block(); | |
| 868 if (true_block != NULL && !true_block->IsFinished()) { | 886 if (true_block != NULL && !true_block->IsFinished()) { |
| 869 ASSERT(continuation->IsTrueReachable()); | 887 ASSERT(continuation->IsTrueReachable()); |
| 870 builder_->GotoNoSimulate(true_block, continuation->true_branch()); | 888 builder_->GotoNoSimulate(true_block, continuation->true_branch()); |
| 871 } | 889 } |
| 872 if (false_block != NULL && !false_block->IsFinished()) { | 890 if (false_block != NULL && !false_block->IsFinished()) { |
| 873 ASSERT(continuation->IsFalseReachable()); | 891 ASSERT(continuation->IsFalseReachable()); |
| 874 builder_->GotoNoSimulate(false_block, continuation->false_branch()); | 892 builder_->GotoNoSimulate(false_block, continuation->false_branch()); |
| 875 } | 893 } |
| 876 captured_ = true; | 894 captured_ = true; |
| 877 End(); | 895 End(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 888 // so that the graph builder visits it and sees any live range extending | 906 // so that the graph builder visits it and sees any live range extending |
| 889 // constructs within it. | 907 // constructs within it. |
| 890 HConstant* constant_false = builder_->graph()->GetConstantFalse(); | 908 HConstant* constant_false = builder_->graph()->GetConstantFalse(); |
| 891 ToBooleanStub::Types boolean_type = ToBooleanStub::Types(); | 909 ToBooleanStub::Types boolean_type = ToBooleanStub::Types(); |
| 892 boolean_type.Add(ToBooleanStub::BOOLEAN); | 910 boolean_type.Add(ToBooleanStub::BOOLEAN); |
| 893 HBranch* branch = builder()->New<HBranch>( | 911 HBranch* branch = builder()->New<HBranch>( |
| 894 constant_false, boolean_type, first_true_block_, first_false_block_); | 912 constant_false, boolean_type, first_true_block_, first_false_block_); |
| 895 builder_->FinishCurrentBlock(branch); | 913 builder_->FinishCurrentBlock(branch); |
| 896 } | 914 } |
| 897 builder_->set_current_block(first_true_block_); | 915 builder_->set_current_block(first_true_block_); |
| 916 pending_merge_block_ = true; |
| 898 } | 917 } |
| 899 | 918 |
| 900 | 919 |
| 901 void HGraphBuilder::IfBuilder::Else() { | 920 void HGraphBuilder::IfBuilder::Else() { |
| 902 ASSERT(did_then_); | 921 ASSERT(did_then_); |
| 903 ASSERT(!captured_); | 922 ASSERT(!captured_); |
| 904 ASSERT(!finished_); | 923 ASSERT(!finished_); |
| 905 last_true_block_ = builder_->current_block(); | 924 AddMergeAtJoinBlock(false); |
| 906 builder_->set_current_block(first_false_block_); | 925 builder_->set_current_block(first_false_block_); |
| 926 pending_merge_block_ = true; |
| 907 did_else_ = true; | 927 did_else_ = true; |
| 908 } | 928 } |
| 909 | 929 |
| 910 | 930 |
| 911 void HGraphBuilder::IfBuilder::Deopt(const char* reason) { | 931 void HGraphBuilder::IfBuilder::Deopt(const char* reason) { |
| 912 ASSERT(did_then_); | 932 ASSERT(did_then_); |
| 913 if (did_else_) { | |
| 914 deopt_else_ = true; | |
| 915 } else { | |
| 916 deopt_then_ = true; | |
| 917 } | |
| 918 builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER); | 933 builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER); |
| 934 AddMergeAtJoinBlock(true); |
| 919 } | 935 } |
| 920 | 936 |
| 921 | 937 |
| 922 void HGraphBuilder::IfBuilder::Return(HValue* value) { | 938 void HGraphBuilder::IfBuilder::Return(HValue* value) { |
| 923 HValue* parameter_count = builder_->graph()->GetConstantMinus1(); | 939 HValue* parameter_count = builder_->graph()->GetConstantMinus1(); |
| 924 builder_->FinishExitCurrentBlock( | 940 builder_->FinishExitCurrentBlock( |
| 925 builder_->New<HReturn>(value, parameter_count)); | 941 builder_->New<HReturn>(value, parameter_count)); |
| 926 if (did_else_) { | 942 AddMergeAtJoinBlock(false); |
| 927 first_false_block_ = NULL; | |
| 928 } else { | |
| 929 first_true_block_ = NULL; | |
| 930 } | |
| 931 } | 943 } |
| 932 | 944 |
| 933 | 945 |
| 934 void HGraphBuilder::IfBuilder::End() { | 946 void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) { |
| 935 if (!captured_) { | 947 if (!pending_merge_block_) return; |
| 936 ASSERT(did_then_); | 948 HBasicBlock* block = builder_->current_block(); |
| 937 if (!did_else_) { | 949 ASSERT(block == NULL || !block->IsFinished()); |
| 938 last_true_block_ = builder_->current_block(); | 950 MergeAtJoinBlock* record = |
| 951 new(builder_->zone()) MergeAtJoinBlock(block, deopt, |
| 952 merge_at_join_blocks_); |
| 953 merge_at_join_blocks_ = record; |
| 954 if (block != NULL) { |
| 955 ASSERT(block->end() == NULL); |
| 956 if (deopt) { |
| 957 normal_merge_at_join_block_count_++; |
| 958 } else { |
| 959 deopt_merge_at_join_block_count_++; |
| 939 } | 960 } |
| 940 if (last_true_block_ == NULL || last_true_block_->IsFinished()) { | 961 } |
| 941 ASSERT(did_else_); | 962 builder_->set_current_block(NULL); |
| 942 // Return on true. Nothing to do, just continue the false block. | 963 pending_merge_block_ = false; |
| 943 } else if (first_false_block_ == NULL || | 964 } |
| 944 (did_else_ && builder_->current_block()->IsFinished())) { | 965 |
| 945 // Deopt on false. Nothing to do except switching to the true block. | 966 |
| 946 builder_->set_current_block(last_true_block_); | 967 void HGraphBuilder::IfBuilder::Finish() { |
| 947 } else { | 968 ASSERT(!finished_); |
| 948 merge_block_ = builder_->graph()->CreateBasicBlock(); | 969 if (!did_then_) { |
| 949 ASSERT(!finished_); | 970 Then(); |
| 950 if (!did_else_) Else(); | 971 } |
| 951 ASSERT(!last_true_block_->IsFinished()); | 972 AddMergeAtJoinBlock(false); |
| 952 HBasicBlock* last_false_block = builder_->current_block(); | 973 if (!did_else_) { |
| 953 ASSERT(!last_false_block->IsFinished()); | 974 Else(); |
| 954 if (deopt_then_) { | 975 AddMergeAtJoinBlock(false); |
| 955 builder_->GotoNoSimulate(last_false_block, merge_block_); | |
| 956 builder_->PadEnvironmentForContinuation(last_true_block_, | |
| 957 merge_block_); | |
| 958 builder_->GotoNoSimulate(last_true_block_, merge_block_); | |
| 959 } else { | |
| 960 builder_->GotoNoSimulate(last_true_block_, merge_block_); | |
| 961 if (deopt_else_) { | |
| 962 builder_->PadEnvironmentForContinuation(last_false_block, | |
| 963 merge_block_); | |
| 964 } | |
| 965 builder_->GotoNoSimulate(last_false_block, merge_block_); | |
| 966 } | |
| 967 builder_->set_current_block(merge_block_); | |
| 968 } | |
| 969 } | 976 } |
| 970 finished_ = true; | 977 finished_ = true; |
| 971 } | 978 } |
| 972 | 979 |
| 973 | 980 |
| 981 void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation, |
| 982 HBasicBlock** else_continuation) { |
| 983 Finish(); |
| 984 |
| 985 MergeAtJoinBlock* else_record = merge_at_join_blocks_; |
| 986 if (else_continuation != NULL) { |
| 987 *else_continuation = else_record->block_; |
| 988 } |
| 989 MergeAtJoinBlock* then_record = else_record->next_; |
| 990 if (then_continuation != NULL) { |
| 991 *then_continuation = then_record->block_; |
| 992 } |
| 993 ASSERT(then_record->next_ == NULL); |
| 994 } |
| 995 |
| 996 |
| 997 void HGraphBuilder::IfBuilder::End() { |
| 998 if (captured_) return; |
| 999 Finish(); |
| 1000 |
| 1001 int total_merged_blocks = normal_merge_at_join_block_count_ + |
| 1002 deopt_merge_at_join_block_count_; |
| 1003 ASSERT(total_merged_blocks >= 1); |
| 1004 HBasicBlock* merge_block = total_merged_blocks == 1 |
| 1005 ? NULL : builder_->graph()->CreateBasicBlock(); |
| 1006 |
| 1007 // Merge non-deopt blocks first to ensure environment has right size for |
| 1008 // padding. |
| 1009 MergeAtJoinBlock* current = merge_at_join_blocks_; |
| 1010 while (current != NULL) { |
| 1011 if (!current->deopt_ && current->block_ != NULL) { |
| 1012 // If there is only one block that makes it through to the end of the |
| 1013 // if, then just set it as the current block and continue rather then |
| 1014 // creating an unnecessary merge block. |
| 1015 if (total_merged_blocks == 1) { |
| 1016 builder_->set_current_block(current->block_); |
| 1017 return; |
| 1018 } |
| 1019 builder_->GotoNoSimulate(current->block_, merge_block); |
| 1020 } |
| 1021 current = current->next_; |
| 1022 } |
| 1023 |
| 1024 // Merge deopt blocks, padding when necessary. |
| 1025 current = merge_at_join_blocks_; |
| 1026 while (current != NULL) { |
| 1027 if (current->deopt_ && current->block_ != NULL) { |
| 1028 builder_->PadEnvironmentForContinuation(current->block_, |
| 1029 merge_block); |
| 1030 builder_->GotoNoSimulate(current->block_, merge_block); |
| 1031 } |
| 1032 current = current->next_; |
| 1033 } |
| 1034 builder_->set_current_block(merge_block); |
| 1035 } |
| 1036 |
| 1037 |
| 974 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, | 1038 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, |
| 975 HValue* context, | 1039 HValue* context, |
| 976 LoopBuilder::Direction direction) | 1040 LoopBuilder::Direction direction) |
| 977 : builder_(builder), | 1041 : builder_(builder), |
| 978 context_(context), | 1042 context_(context), |
| 979 direction_(direction), | 1043 direction_(direction), |
| 980 finished_(false) { | 1044 finished_(false) { |
| 981 header_block_ = builder->CreateLoopHeaderBlock(); | 1045 header_block_ = builder->CreateLoopHeaderBlock(); |
| 982 body_block_ = NULL; | 1046 body_block_ = NULL; |
| 983 exit_block_ = NULL; | 1047 exit_block_ = NULL; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1044 | 1108 |
| 1045 void HGraphBuilder::LoopBuilder::Break() { | 1109 void HGraphBuilder::LoopBuilder::Break() { |
| 1046 if (exit_trampoline_block_ == NULL) { | 1110 if (exit_trampoline_block_ == NULL) { |
| 1047 // Its the first time we saw a break. | 1111 // Its the first time we saw a break. |
| 1048 HEnvironment* env = exit_block_->last_environment()->Copy(); | 1112 HEnvironment* env = exit_block_->last_environment()->Copy(); |
| 1049 exit_trampoline_block_ = builder_->CreateBasicBlock(env); | 1113 exit_trampoline_block_ = builder_->CreateBasicBlock(env); |
| 1050 builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_); | 1114 builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_); |
| 1051 } | 1115 } |
| 1052 | 1116 |
| 1053 builder_->GotoNoSimulate(exit_trampoline_block_); | 1117 builder_->GotoNoSimulate(exit_trampoline_block_); |
| 1118 builder_->set_current_block(NULL); |
| 1054 } | 1119 } |
| 1055 | 1120 |
| 1056 | 1121 |
| 1057 void HGraphBuilder::LoopBuilder::EndBody() { | 1122 void HGraphBuilder::LoopBuilder::EndBody() { |
| 1058 ASSERT(!finished_); | 1123 ASSERT(!finished_); |
| 1059 | 1124 |
| 1060 if (direction_ == kPostIncrement || direction_ == kPostDecrement) { | 1125 if (direction_ == kPostIncrement || direction_ == kPostDecrement) { |
| 1061 if (direction_ == kPostIncrement) { | 1126 if (direction_ == kPostIncrement) { |
| 1062 increment_ = HAdd::New(zone(), context_, phi_, increment_amount_); | 1127 increment_ = HAdd::New(zone(), context_, phi_, increment_amount_); |
| 1063 } else { | 1128 } else { |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1201 ASSERT(continuation->predecessors()->length() == 0); | 1266 ASSERT(continuation->predecessors()->length() == 0); |
| 1202 } | 1267 } |
| 1203 } | 1268 } |
| 1204 | 1269 |
| 1205 | 1270 |
| 1206 HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) { | 1271 HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) { |
| 1207 return Add<HCheckMaps>(obj, map, top_info()); | 1272 return Add<HCheckMaps>(obj, map, top_info()); |
| 1208 } | 1273 } |
| 1209 | 1274 |
| 1210 | 1275 |
| 1276 HValue* HGraphBuilder::BuildCheckString(HValue* string) { |
| 1277 if (!string->type().IsString()) { |
| 1278 ASSERT(!string->IsConstant() || |
| 1279 !HConstant::cast(string)->HasStringValue()); |
| 1280 BuildCheckHeapObject(string); |
| 1281 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); |
| 1282 } |
| 1283 return string; |
| 1284 } |
| 1285 |
| 1286 |
| 1211 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { | 1287 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { |
| 1212 if (object->type().IsJSObject()) return object; | 1288 if (object->type().IsJSObject()) return object; |
| 1213 return Add<HWrapReceiver>(object, function); | 1289 return Add<HWrapReceiver>(object, function); |
| 1214 } | 1290 } |
| 1215 | 1291 |
| 1216 | 1292 |
| 1217 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, | 1293 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, |
| 1218 HValue* elements, | 1294 HValue* elements, |
| 1219 ElementsKind kind, | 1295 ElementsKind kind, |
| 1220 HValue* length, | 1296 HValue* length, |
| 1221 HValue* key, | 1297 HValue* key, |
| 1222 bool is_js_array) { | 1298 bool is_js_array) { |
| 1223 IfBuilder length_checker(this); | 1299 IfBuilder length_checker(this); |
| 1224 | 1300 |
| 1225 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; | 1301 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; |
| 1226 length_checker.If<HCompareNumericAndBranch>(key, length, token); | 1302 length_checker.If<HCompareNumericAndBranch>(key, length, token); |
| 1227 | 1303 |
| 1228 length_checker.Then(); | 1304 length_checker.Then(); |
| 1229 | 1305 |
| 1230 HValue* current_capacity = AddLoadFixedArrayLength(elements); | 1306 HValue* current_capacity = AddLoadFixedArrayLength(elements); |
| 1231 | 1307 |
| 1232 IfBuilder capacity_checker(this); | 1308 IfBuilder capacity_checker(this); |
| 1233 | 1309 |
| 1234 capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity, | 1310 capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity, |
| 1235 Token::GTE); | 1311 Token::GTE); |
| 1236 capacity_checker.Then(); | 1312 capacity_checker.Then(); |
| 1237 | 1313 |
| 1238 HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap)); | 1314 HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap)); |
| 1239 HValue* max_capacity = Add<HAdd>(current_capacity, max_gap); | 1315 HValue* max_capacity = AddUncasted<HAdd>(current_capacity, max_gap); |
| 1240 IfBuilder key_checker(this); | 1316 IfBuilder key_checker(this); |
| 1241 key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT); | 1317 key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT); |
| 1242 key_checker.Then(); | 1318 key_checker.Then(); |
| 1243 key_checker.ElseDeopt("Key out of capacity range"); | 1319 key_checker.ElseDeopt("Key out of capacity range"); |
| 1244 key_checker.End(); | 1320 key_checker.End(); |
| 1245 | 1321 |
| 1246 HValue* new_capacity = BuildNewElementsCapacity(key); | 1322 HValue* new_capacity = BuildNewElementsCapacity(key); |
| 1247 HValue* new_elements = BuildGrowElementsCapacity(object, elements, | 1323 HValue* new_elements = BuildGrowElementsCapacity(object, elements, |
| 1248 kind, kind, length, | 1324 kind, kind, length, |
| 1249 new_capacity); | 1325 new_capacity); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1333 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, | 1409 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, |
| 1334 array_length, elements_length); | 1410 array_length, elements_length); |
| 1335 | 1411 |
| 1336 if_builder.End(); | 1412 if_builder.End(); |
| 1337 } | 1413 } |
| 1338 | 1414 |
| 1339 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); | 1415 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); |
| 1340 } | 1416 } |
| 1341 | 1417 |
| 1342 | 1418 |
| 1419 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper( |
| 1420 HValue* elements, |
| 1421 HValue* key, |
| 1422 HValue* hash, |
| 1423 HValue* mask, |
| 1424 int current_probe) { |
| 1425 if (current_probe == kNumberDictionaryProbes) { |
| 1426 return NULL; |
| 1427 } |
| 1428 |
| 1429 int32_t offset = SeededNumberDictionary::GetProbeOffset(current_probe); |
| 1430 HValue* raw_index = (current_probe == 0) |
| 1431 ? hash |
| 1432 : AddUncasted<HAdd>(hash, Add<HConstant>(offset)); |
| 1433 raw_index = AddUncasted<HBitwise>(Token::BIT_AND, raw_index, mask); |
| 1434 int32_t entry_size = SeededNumberDictionary::kEntrySize; |
| 1435 raw_index = AddUncasted<HMul>(raw_index, Add<HConstant>(entry_size)); |
| 1436 raw_index->ClearFlag(HValue::kCanOverflow); |
| 1437 |
| 1438 int32_t base_offset = SeededNumberDictionary::kElementsStartIndex; |
| 1439 HValue* key_index = AddUncasted<HAdd>(raw_index, Add<HConstant>(base_offset)); |
| 1440 key_index->ClearFlag(HValue::kCanOverflow); |
| 1441 |
| 1442 HValue* candidate_key = Add<HLoadKeyed>(elements, key_index, |
| 1443 static_cast<HValue*>(NULL), |
| 1444 FAST_SMI_ELEMENTS); |
| 1445 |
| 1446 IfBuilder key_compare(this); |
| 1447 key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key); |
| 1448 key_compare.Then(); |
| 1449 { |
| 1450 // Key at the current probe doesn't match, try at the next probe. |
| 1451 HValue* result = BuildUncheckedDictionaryElementLoadHelper( |
| 1452 elements, key, hash, mask, current_probe + 1); |
| 1453 if (result == NULL) { |
| 1454 key_compare.Deopt("probes exhausted in keyed load dictionary lookup"); |
| 1455 result = graph()->GetConstantUndefined(); |
| 1456 } else { |
| 1457 Push(result); |
| 1458 } |
| 1459 } |
| 1460 key_compare.Else(); |
| 1461 { |
| 1462 // Key at current probe matches. Details must be zero, otherwise the |
| 1463 // dictionary element requires special handling. |
| 1464 HValue* details_index = AddUncasted<HAdd>( |
| 1465 raw_index, Add<HConstant>(base_offset + 2)); |
| 1466 details_index->ClearFlag(HValue::kCanOverflow); |
| 1467 |
| 1468 HValue* details = Add<HLoadKeyed>(elements, details_index, |
| 1469 static_cast<HValue*>(NULL), |
| 1470 FAST_SMI_ELEMENTS); |
| 1471 IfBuilder details_compare(this); |
| 1472 details_compare.If<HCompareNumericAndBranch>(details, |
| 1473 graph()->GetConstant0(), |
| 1474 Token::NE); |
| 1475 details_compare.ThenDeopt("keyed load dictionary element not fast case"); |
| 1476 |
| 1477 details_compare.Else(); |
| 1478 { |
| 1479 // Key matches and details are zero --> fast case. Load and return the |
| 1480 // value. |
| 1481 HValue* result_index = AddUncasted<HAdd>( |
| 1482 raw_index, Add<HConstant>(base_offset + 1)); |
| 1483 result_index->ClearFlag(HValue::kCanOverflow); |
| 1484 |
| 1485 Push(Add<HLoadKeyed>(elements, result_index, |
| 1486 static_cast<HValue*>(NULL), |
| 1487 FAST_ELEMENTS)); |
| 1488 } |
| 1489 details_compare.End(); |
| 1490 } |
| 1491 key_compare.End(); |
| 1492 |
| 1493 return Pop(); |
| 1494 } |
| 1495 |
| 1496 |
| 1497 HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) { |
| 1498 int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed()); |
| 1499 HValue* seed = Add<HConstant>(seed_value); |
| 1500 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed); |
| 1501 |
| 1502 // hash = ~hash + (hash << 15); |
| 1503 HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15)); |
| 1504 HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, |
| 1505 graph()->GetConstantMinus1()); |
| 1506 hash = AddUncasted<HAdd>(shifted_hash, not_hash); |
| 1507 |
| 1508 // hash = hash ^ (hash >> 12); |
| 1509 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12)); |
| 1510 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
| 1511 |
| 1512 // hash = hash + (hash << 2); |
| 1513 shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(2)); |
| 1514 hash = AddUncasted<HAdd>(hash, shifted_hash); |
| 1515 |
| 1516 // hash = hash ^ (hash >> 4); |
| 1517 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(4)); |
| 1518 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
| 1519 |
| 1520 // hash = hash * 2057; |
| 1521 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057)); |
| 1522 hash->ClearFlag(HValue::kCanOverflow); |
| 1523 |
| 1524 // hash = hash ^ (hash >> 16); |
| 1525 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16)); |
| 1526 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
| 1527 } |
| 1528 |
| 1529 |
| 1530 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, |
| 1531 HValue* key) { |
| 1532 HValue* elements = AddLoadElements(receiver); |
| 1533 |
| 1534 HValue* hash = BuildElementIndexHash(key); |
| 1535 |
| 1536 HValue* capacity = Add<HLoadKeyed>( |
| 1537 elements, |
| 1538 Add<HConstant>(NameDictionary::kCapacityIndex), |
| 1539 static_cast<HValue*>(NULL), |
| 1540 FAST_SMI_ELEMENTS); |
| 1541 |
| 1542 HValue* mask = Add<HSub>(capacity, graph()->GetConstant1()); |
| 1543 mask->ChangeRepresentation(Representation::Integer32()); |
| 1544 mask->ClearFlag(HValue::kCanOverflow); |
| 1545 |
| 1546 return BuildUncheckedDictionaryElementLoadHelper(elements, key, |
| 1547 hash, mask, 0); |
| 1548 } |
| 1549 |
| 1550 |
| 1343 HValue* HGraphBuilder::BuildNumberToString(HValue* object, | 1551 HValue* HGraphBuilder::BuildNumberToString(HValue* object, |
| 1344 Handle<Type> type) { | 1552 Handle<Type> type) { |
| 1345 NoObservableSideEffectsScope scope(this); | 1553 NoObservableSideEffectsScope scope(this); |
| 1346 | 1554 |
| 1555 // Convert constant numbers at compile time. |
| 1556 if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) { |
| 1557 Handle<Object> number = HConstant::cast(object)->handle(isolate()); |
| 1558 Handle<String> result = isolate()->factory()->NumberToString(number); |
| 1559 return Add<HConstant>(result); |
| 1560 } |
| 1561 |
| 1347 // Create a joinable continuation. | 1562 // Create a joinable continuation. |
| 1348 HIfContinuation found(graph()->CreateBasicBlock(), | 1563 HIfContinuation found(graph()->CreateBasicBlock(), |
| 1349 graph()->CreateBasicBlock()); | 1564 graph()->CreateBasicBlock()); |
| 1350 | 1565 |
| 1351 // Load the number string cache. | 1566 // Load the number string cache. |
| 1352 HValue* number_string_cache = | 1567 HValue* number_string_cache = |
| 1353 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex); | 1568 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex); |
| 1354 | 1569 |
| 1355 // Make the hash mask from the length of the number string cache. It | 1570 // Make the hash mask from the length of the number string cache. It |
| 1356 // contains two elements (number and string) for each cache entry. | 1571 // contains two elements (number and string) for each cache entry. |
| 1357 HValue* mask = AddLoadFixedArrayLength(number_string_cache); | 1572 HValue* mask = AddLoadFixedArrayLength(number_string_cache); |
| 1358 mask->set_type(HType::Smi()); | 1573 mask->set_type(HType::Smi()); |
| 1359 mask = Add<HSar>(mask, graph()->GetConstant1()); | 1574 mask = Add<HSar>(mask, graph()->GetConstant1()); |
| 1360 mask = Add<HSub>(mask, graph()->GetConstant1()); | 1575 mask = Add<HSub>(mask, graph()->GetConstant1()); |
| 1361 | 1576 |
| 1362 // Check whether object is a smi. | 1577 // Check whether object is a smi. |
| 1363 IfBuilder if_objectissmi(this); | 1578 IfBuilder if_objectissmi(this); |
| 1364 if_objectissmi.If<HIsSmiAndBranch>(object); | 1579 if_objectissmi.If<HIsSmiAndBranch>(object); |
| 1365 if_objectissmi.Then(); | 1580 if_objectissmi.Then(); |
| 1366 { | 1581 { |
| 1367 // Compute hash for smi similar to smi_get_hash(). | 1582 // Compute hash for smi similar to smi_get_hash(). |
| 1368 HValue* hash = Add<HBitwise>(Token::BIT_AND, object, mask); | 1583 HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask); |
| 1369 | 1584 |
| 1370 // Load the key. | 1585 // Load the key. |
| 1371 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); | 1586 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1()); |
| 1372 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, | 1587 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, |
| 1373 static_cast<HValue*>(NULL), | 1588 static_cast<HValue*>(NULL), |
| 1374 FAST_ELEMENTS, ALLOW_RETURN_HOLE); | 1589 FAST_ELEMENTS, ALLOW_RETURN_HOLE); |
| 1375 | 1590 |
| 1376 // Check if object == key. | 1591 // Check if object == key. |
| 1377 IfBuilder if_objectiskey(this); | 1592 IfBuilder if_objectiskey(this); |
| 1378 if_objectiskey.If<HCompareObjectEqAndBranch>(object, key); | 1593 if_objectiskey.If<HCompareObjectEqAndBranch>(object, key); |
| 1379 if_objectiskey.Then(); | 1594 if_objectiskey.Then(); |
| 1380 { | 1595 { |
| 1381 // Make the key_index available. | 1596 // Make the key_index available. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1392 IfBuilder if_objectisnumber(this); | 1607 IfBuilder if_objectisnumber(this); |
| 1393 if_objectisnumber.If<HCompareMap>( | 1608 if_objectisnumber.If<HCompareMap>( |
| 1394 object, isolate()->factory()->heap_number_map()); | 1609 object, isolate()->factory()->heap_number_map()); |
| 1395 if_objectisnumber.Then(); | 1610 if_objectisnumber.Then(); |
| 1396 { | 1611 { |
| 1397 // Compute hash for heap number similar to double_get_hash(). | 1612 // Compute hash for heap number similar to double_get_hash(). |
| 1398 HValue* low = Add<HLoadNamedField>( | 1613 HValue* low = Add<HLoadNamedField>( |
| 1399 object, HObjectAccess::ForHeapNumberValueLowestBits()); | 1614 object, HObjectAccess::ForHeapNumberValueLowestBits()); |
| 1400 HValue* high = Add<HLoadNamedField>( | 1615 HValue* high = Add<HLoadNamedField>( |
| 1401 object, HObjectAccess::ForHeapNumberValueHighestBits()); | 1616 object, HObjectAccess::ForHeapNumberValueHighestBits()); |
| 1402 HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high); | 1617 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high); |
| 1403 hash = Add<HBitwise>(Token::BIT_AND, hash, mask); | 1618 hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask); |
| 1404 | 1619 |
| 1405 // Load the key. | 1620 // Load the key. |
| 1406 HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); | 1621 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1()); |
| 1407 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, | 1622 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, |
| 1408 static_cast<HValue*>(NULL), | 1623 static_cast<HValue*>(NULL), |
| 1409 FAST_ELEMENTS, ALLOW_RETURN_HOLE); | 1624 FAST_ELEMENTS, ALLOW_RETURN_HOLE); |
| 1410 | 1625 |
| 1411 // Check if key is a heap number (the number string cache contains only | 1626 // Check if key is a heap number (the number string cache contains only |
| 1412 // SMIs and heap number, so it is sufficient to do a SMI check here). | 1627 // SMIs and heap number, so it is sufficient to do a SMI check here). |
| 1413 IfBuilder if_keyisnotsmi(this); | 1628 IfBuilder if_keyisnotsmi(this); |
| 1414 if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key); | 1629 if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key); |
| 1415 if_keyisnotsmi.Then(); | 1630 if_keyisnotsmi.Then(); |
| 1416 { | 1631 { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1442 | 1657 |
| 1443 // Check for cache hit. | 1658 // Check for cache hit. |
| 1444 IfBuilder if_found(this, &found); | 1659 IfBuilder if_found(this, &found); |
| 1445 if_found.Then(); | 1660 if_found.Then(); |
| 1446 { | 1661 { |
| 1447 // Count number to string operation in native code. | 1662 // Count number to string operation in native code. |
| 1448 AddIncrementCounter(isolate()->counters()->number_to_string_native()); | 1663 AddIncrementCounter(isolate()->counters()->number_to_string_native()); |
| 1449 | 1664 |
| 1450 // Load the value in case of cache hit. | 1665 // Load the value in case of cache hit. |
| 1451 HValue* key_index = Pop(); | 1666 HValue* key_index = Pop(); |
| 1452 HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1()); | 1667 HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1()); |
| 1453 Push(Add<HLoadKeyed>(number_string_cache, value_index, | 1668 Push(Add<HLoadKeyed>(number_string_cache, value_index, |
| 1454 static_cast<HValue*>(NULL), | 1669 static_cast<HValue*>(NULL), |
| 1455 FAST_ELEMENTS, ALLOW_RETURN_HOLE)); | 1670 FAST_ELEMENTS, ALLOW_RETURN_HOLE)); |
| 1456 } | 1671 } |
| 1457 if_found.Else(); | 1672 if_found.Else(); |
| 1458 { | 1673 { |
| 1459 // Cache miss, fallback to runtime. | 1674 // Cache miss, fallback to runtime. |
| 1460 Add<HPushArgument>(object); | 1675 Add<HPushArgument>(object); |
| 1461 Push(Add<HCallRuntime>( | 1676 Push(Add<HCallRuntime>( |
| 1462 isolate()->factory()->empty_string(), | 1677 isolate()->factory()->empty_string(), |
| 1463 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), | 1678 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), |
| 1464 1)); | 1679 1)); |
| 1465 } | 1680 } |
| 1466 if_found.End(); | 1681 if_found.End(); |
| 1467 | 1682 |
| 1468 return Pop(); | 1683 return Pop(); |
| 1469 } | 1684 } |
| 1470 | 1685 |
| 1471 | 1686 |
| 1472 HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length, | 1687 HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length, |
| 1473 String::Encoding encoding) { | 1688 String::Encoding encoding) { |
| 1474 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); | 1689 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 1475 HValue* size = length; | 1690 HValue* size = length; |
| 1476 if (encoding == String::TWO_BYTE_ENCODING) { | 1691 if (encoding == String::TWO_BYTE_ENCODING) { |
| 1477 size = Add<HShl>(length, graph()->GetConstant1()); | 1692 size = AddUncasted<HShl>(length, graph()->GetConstant1()); |
| 1478 size->ClearFlag(HValue::kCanOverflow); | 1693 size->ClearFlag(HValue::kCanOverflow); |
| 1479 size->SetFlag(HValue::kUint32); | 1694 size->SetFlag(HValue::kUint32); |
| 1480 } | 1695 } |
| 1481 size = Add<HAdd>(size, Add<HConstant>(static_cast<int32_t>( | 1696 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>( |
| 1482 SeqString::kHeaderSize + kObjectAlignmentMask))); | 1697 SeqString::kHeaderSize + kObjectAlignmentMask))); |
| 1483 size->ClearFlag(HValue::kCanOverflow); | 1698 size->ClearFlag(HValue::kCanOverflow); |
| 1484 size = Add<HBitwise>( | 1699 size = AddUncasted<HBitwise>( |
| 1485 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( | 1700 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( |
| 1486 ~kObjectAlignmentMask))); | 1701 ~kObjectAlignmentMask))); |
| 1487 return size; | 1702 return size; |
| 1488 } | 1703 } |
| 1489 | 1704 |
| 1490 | 1705 |
| 1491 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, | 1706 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, |
| 1492 HValue* src_offset, | 1707 HValue* src_offset, |
| 1493 String::Encoding src_encoding, | 1708 String::Encoding src_encoding, |
| 1494 HValue* dst, | 1709 HValue* dst, |
| 1495 HValue* dst_offset, | 1710 HValue* dst_offset, |
| 1496 String::Encoding dst_encoding, | 1711 String::Encoding dst_encoding, |
| 1497 HValue* length) { | 1712 HValue* length) { |
| 1498 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || | 1713 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || |
| 1499 src_encoding == String::ONE_BYTE_ENCODING); | 1714 src_encoding == String::ONE_BYTE_ENCODING); |
| 1500 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); | 1715 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); |
| 1501 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); | 1716 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); |
| 1502 { | 1717 { |
| 1503 HValue* src_index = Add<HAdd>(src_offset, index); | 1718 HValue* src_index = AddUncasted<HAdd>(src_offset, index); |
| 1504 HValue* value = Add<HSeqStringGetChar>(src_encoding, src, src_index); | 1719 HValue* value = Add<HSeqStringGetChar>(src_encoding, src, src_index); |
| 1505 HValue* dst_index = Add<HAdd>(dst_offset, index); | 1720 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); |
| 1506 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); | 1721 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); |
| 1507 } | 1722 } |
| 1508 loop.EndBody(); | 1723 loop.EndBody(); |
| 1509 } | 1724 } |
| 1510 | 1725 |
| 1511 | 1726 |
| 1512 HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left, | 1727 HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left, |
| 1513 HValue* right, | 1728 HValue* right, |
| 1514 PretenureFlag pretenure_flag) { | 1729 PretenureFlag pretenure_flag) { |
| 1515 // Determine the string lengths. | 1730 // Determine the string lengths. |
| 1516 HValue* left_length = Add<HLoadNamedField>( | 1731 HValue* left_length = Add<HLoadNamedField>( |
| 1517 left, HObjectAccess::ForStringLength()); | 1732 left, HObjectAccess::ForStringLength()); |
| 1518 HValue* right_length = Add<HLoadNamedField>( | 1733 HValue* right_length = Add<HLoadNamedField>( |
| 1519 right, HObjectAccess::ForStringLength()); | 1734 right, HObjectAccess::ForStringLength()); |
| 1520 | 1735 |
| 1521 // Check if we concatenated the strings here, or if we have to resort to the | 1736 // Compute the combined string length. If the result is larger than the max |
| 1522 // runtime function. | 1737 // supported string length, we bailout to the runtime. This is done implicitly |
| 1523 HIfContinuation handled(graph()->CreateBasicBlock(), | 1738 // when converting the result back to a smi in case the max string length |
| 1524 graph()->CreateBasicBlock()); | 1739 // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do |
| 1525 | 1740 HValue* length = AddUncasted<HAdd>(left_length, right_length); |
| 1526 // Check if both parameters do not exceed half the max string length, because | 1741 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| 1527 // exceptionally long strings should be handled in the runtime. Unfortunately | 1742 if (String::kMaxLength != Smi::kMaxValue) { |
| 1528 // we cannot actually check whether the combined length of both strings | 1743 IfBuilder if_nooverflow(this); |
| 1529 // exceeds String::kMaxLength (because of unclear results from the | 1744 if_nooverflow.If<HCompareNumericAndBranch>( |
| 1530 // representation inference phase), so we use a pessimistic approach here | 1745 length, Add<HConstant>(String::kMaxLength), Token::LTE); |
| 1531 // instead, checking that the length of either substring does not exceed half | 1746 if_nooverflow.Then(); |
| 1532 // of String::kMaxLength. | 1747 if_nooverflow.ElseDeopt("String length exceeds limit"); |
| 1533 HConstant* max_length = Add<HConstant>(String::kMaxLength / 2); | 1748 } |
| 1534 IfBuilder if_nooverflow(this); | 1749 |
| 1535 if_nooverflow.If<HCompareNumericAndBranch>( | 1750 // Determine the string instance types. |
| 1536 left_length, max_length, Token::LTE); | 1751 HLoadNamedField* left_instance_type = Add<HLoadNamedField>( |
| 1537 if_nooverflow.AndIf<HCompareNumericAndBranch>( | 1752 Add<HLoadNamedField>(left, HObjectAccess::ForMap()), |
| 1538 right_length, max_length, Token::LTE); | 1753 HObjectAccess::ForMapInstanceType()); |
| 1539 if_nooverflow.Then(); | 1754 HLoadNamedField* right_instance_type = Add<HLoadNamedField>( |
| 1755 Add<HLoadNamedField>(right, HObjectAccess::ForMap()), |
| 1756 HObjectAccess::ForMapInstanceType()); |
| 1757 |
| 1758 // Compute difference of instance types. |
| 1759 HValue* xored_instance_types = AddUncasted<HBitwise>( |
| 1760 Token::BIT_XOR, left_instance_type, right_instance_type); |
| 1761 |
| 1762 // Check if we should create a cons string. |
| 1763 IfBuilder if_createcons(this); |
| 1764 if_createcons.If<HCompareNumericAndBranch>( |
| 1765 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); |
| 1766 if_createcons.Then(); |
| 1540 { | 1767 { |
| 1541 // Determine the string instance types. | 1768 // Allocate the cons string object. HAllocate does not care whether we |
| 1542 HLoadNamedField* left_instance_type = Add<HLoadNamedField>( | 1769 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use |
| 1543 Add<HLoadNamedField>(left, HObjectAccess::ForMap()), | 1770 // CONS_STRING_TYPE here. Below we decide whether the cons string is |
| 1544 HObjectAccess::ForMapInstanceType()); | 1771 // one-byte or two-byte and set the appropriate map. |
| 1545 HLoadNamedField* right_instance_type = Add<HLoadNamedField>( | 1772 HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize), |
| 1546 Add<HLoadNamedField>(right, HObjectAccess::ForMap()), | 1773 HType::String(), pretenure_flag, |
| 1547 HObjectAccess::ForMapInstanceType()); | 1774 CONS_STRING_TYPE); |
| 1548 | 1775 |
| 1549 // Compute difference of instance types. | 1776 // Compute the intersection of instance types. |
| 1550 HValue* xored_instance_types = Add<HBitwise>( | 1777 HValue* anded_instance_types = AddUncasted<HBitwise>( |
| 1551 Token::BIT_XOR, left_instance_type, right_instance_type); | 1778 Token::BIT_AND, left_instance_type, right_instance_type); |
| 1552 | 1779 |
| 1553 // Compute the length of the resulting string. | 1780 // We create a one-byte cons string if |
| 1554 HValue* length = Add<HAdd>(left_length, right_length); | 1781 // 1. both strings are one-byte, or |
| 1555 | 1782 // 2. at least one of the strings is two-byte, but happens to contain only |
| 1556 // Check if we should create a cons string. | 1783 // one-byte characters. |
| 1557 IfBuilder if_createcons(this); | 1784 // To do this, we check |
| 1558 if_createcons.If<HCompareNumericAndBranch>( | 1785 // 1. if both strings are one-byte, or if the one-byte data hint is set in |
| 1559 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); | 1786 // both strings, or |
| 1560 if_createcons.Then(); | 1787 // 2. if one of the strings has the one-byte data hint set and the other |
| 1561 { | 1788 // string is one-byte. |
| 1562 // Allocate the cons string object. HAllocate does not care whether we | 1789 IfBuilder if_onebyte(this); |
| 1563 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use | 1790 STATIC_ASSERT(kOneByteStringTag != 0); |
| 1564 // CONS_STRING_TYPE here. Below we decide whether the cons string is | 1791 STATIC_ASSERT(kOneByteDataHintMask != 0); |
| 1565 // one-byte or two-byte and set the appropriate map. | 1792 if_onebyte.If<HCompareNumericAndBranch>( |
| 1566 HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize), | 1793 AddUncasted<HBitwise>( |
| 1567 HType::String(), pretenure_flag, | 1794 Token::BIT_AND, anded_instance_types, |
| 1568 CONS_STRING_TYPE); | 1795 Add<HConstant>(static_cast<int32_t>( |
| 1569 | 1796 kStringEncodingMask | kOneByteDataHintMask))), |
| 1570 // Compute the intersection of instance types. | 1797 graph()->GetConstant0(), Token::NE); |
| 1571 HValue* anded_instance_types = Add<HBitwise>( | 1798 if_onebyte.Or(); |
| 1572 Token::BIT_AND, left_instance_type, right_instance_type); | 1799 STATIC_ASSERT(kOneByteStringTag != 0 && |
| 1573 | 1800 kOneByteDataHintTag != 0 && |
| 1574 // We create a one-byte cons string if | 1801 kOneByteDataHintTag != kOneByteStringTag); |
| 1575 // 1. both strings are one-byte, or | 1802 if_onebyte.If<HCompareNumericAndBranch>( |
| 1576 // 2. at least one of the strings is two-byte, but happens to contain only | 1803 AddUncasted<HBitwise>( |
| 1577 // one-byte characters. | 1804 Token::BIT_AND, xored_instance_types, |
| 1578 // To do this, we check | 1805 Add<HConstant>(static_cast<int32_t>( |
| 1579 // 1. if both strings are one-byte, or if the one-byte data hint is set in | 1806 kOneByteStringTag | kOneByteDataHintTag))), |
| 1580 // both strings, or | 1807 Add<HConstant>(static_cast<int32_t>( |
| 1581 // 2. if one of the strings has the one-byte data hint set and the other | 1808 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); |
| 1582 // string is one-byte. | 1809 if_onebyte.Then(); |
| 1810 { |
| 1811 // We can safely skip the write barrier for storing the map here. |
| 1812 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); |
| 1813 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1814 } |
| 1815 if_onebyte.Else(); |
| 1816 { |
| 1817 // We can safely skip the write barrier for storing the map here. |
| 1818 Handle<Map> map = isolate()->factory()->cons_string_map(); |
| 1819 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1820 } |
| 1821 if_onebyte.End(); |
| 1822 |
| 1823 // Initialize the cons string fields. |
| 1824 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), |
| 1825 Add<HConstant>(String::kEmptyHashField)); |
| 1826 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); |
| 1827 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left); |
| 1828 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(), |
| 1829 right); |
| 1830 |
| 1831 // Count the native string addition. |
| 1832 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1833 |
| 1834 // Cons string is result. |
| 1835 Push(string); |
| 1836 } |
| 1837 if_createcons.Else(); |
| 1838 { |
| 1839 // Compute union of instance types. |
| 1840 HValue* ored_instance_types = AddUncasted<HBitwise>( |
| 1841 Token::BIT_OR, left_instance_type, right_instance_type); |
| 1842 |
| 1843 // Check if both strings have the same encoding and both are |
| 1844 // sequential. |
| 1845 IfBuilder if_sameencodingandsequential(this); |
| 1846 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
| 1847 AddUncasted<HBitwise>( |
| 1848 Token::BIT_AND, xored_instance_types, |
| 1849 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
| 1850 graph()->GetConstant0(), Token::EQ); |
| 1851 if_sameencodingandsequential.And(); |
| 1852 STATIC_ASSERT(kSeqStringTag == 0); |
| 1853 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
| 1854 AddUncasted<HBitwise>( |
| 1855 Token::BIT_AND, ored_instance_types, |
| 1856 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), |
| 1857 graph()->GetConstant0(), Token::EQ); |
| 1858 if_sameencodingandsequential.Then(); |
| 1859 { |
| 1860 // Check if the result is a one-byte string. |
| 1583 IfBuilder if_onebyte(this); | 1861 IfBuilder if_onebyte(this); |
| 1584 STATIC_ASSERT(kOneByteStringTag != 0); | 1862 STATIC_ASSERT(kOneByteStringTag != 0); |
| 1585 STATIC_ASSERT(kOneByteDataHintMask != 0); | |
| 1586 if_onebyte.If<HCompareNumericAndBranch>( | 1863 if_onebyte.If<HCompareNumericAndBranch>( |
| 1587 Add<HBitwise>( | 1864 AddUncasted<HBitwise>( |
| 1588 Token::BIT_AND, anded_instance_types, | 1865 Token::BIT_AND, ored_instance_types, |
| 1589 Add<HConstant>(static_cast<int32_t>( | 1866 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
| 1590 kStringEncodingMask | kOneByteDataHintMask))), | |
| 1591 graph()->GetConstant0(), Token::NE); | 1867 graph()->GetConstant0(), Token::NE); |
| 1592 if_onebyte.Or(); | |
| 1593 STATIC_ASSERT(kOneByteStringTag != 0 && | |
| 1594 kOneByteDataHintTag != 0 && | |
| 1595 kOneByteDataHintTag != kOneByteStringTag); | |
| 1596 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1597 Add<HBitwise>( | |
| 1598 Token::BIT_AND, xored_instance_types, | |
| 1599 Add<HConstant>(static_cast<int32_t>( | |
| 1600 kOneByteStringTag | kOneByteDataHintTag))), | |
| 1601 Add<HConstant>(static_cast<int32_t>( | |
| 1602 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); | |
| 1603 if_onebyte.Then(); | 1868 if_onebyte.Then(); |
| 1604 { | 1869 { |
| 1605 // We can safely skip the write barrier for storing the map here. | 1870 // Calculate the number of bytes needed for the characters in the |
| 1606 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); | 1871 // string while observing object alignment. |
| 1872 HValue* size = BuildSeqStringSizeFor( |
| 1873 length, String::ONE_BYTE_ENCODING); |
| 1874 |
| 1875 // Allocate the ASCII string object. |
| 1876 Handle<Map> map = isolate()->factory()->ascii_string_map(); |
| 1877 HAllocate* string = Add<HAllocate>(size, HType::String(), |
| 1878 pretenure_flag, ASCII_STRING_TYPE); |
| 1879 string->set_known_initial_map(map); |
| 1880 |
| 1881 // We can safely skip the write barrier for storing map here. |
| 1607 AddStoreMapConstantNoWriteBarrier(string, map); | 1882 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1883 |
| 1884 // Length must be stored into the string before we copy characters to |
| 1885 // make debug verification code happy. |
| 1886 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), |
| 1887 length); |
| 1888 |
| 1889 // Copy bytes from the left string. |
| 1890 BuildCopySeqStringChars( |
| 1891 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1892 string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1893 left_length); |
| 1894 |
| 1895 // Copy bytes from the right string. |
| 1896 BuildCopySeqStringChars( |
| 1897 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1898 string, left_length, String::ONE_BYTE_ENCODING, |
| 1899 right_length); |
| 1900 |
| 1901 // Count the native string addition. |
| 1902 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1903 |
| 1904 // Return the string. |
| 1905 Push(string); |
| 1608 } | 1906 } |
| 1609 if_onebyte.Else(); | 1907 if_onebyte.Else(); |
| 1610 { | 1908 { |
| 1611 // We can safely skip the write barrier for storing the map here. | 1909 // Calculate the number of bytes needed for the characters in the |
| 1612 Handle<Map> map = isolate()->factory()->cons_string_map(); | 1910 // string while observing object alignment. |
| 1911 HValue* size = BuildSeqStringSizeFor( |
| 1912 length, String::TWO_BYTE_ENCODING); |
| 1913 |
| 1914 // Allocate the two-byte string object. |
| 1915 Handle<Map> map = isolate()->factory()->string_map(); |
| 1916 HAllocate* string = Add<HAllocate>(size, HType::String(), |
| 1917 pretenure_flag, STRING_TYPE); |
| 1918 string->set_known_initial_map(map); |
| 1919 |
| 1920 // We can safely skip the write barrier for storing map here. |
| 1613 AddStoreMapConstantNoWriteBarrier(string, map); | 1921 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1922 |
| 1923 // Length must be stored into the string before we copy characters to |
| 1924 // make debug verification code happy. |
| 1925 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), |
| 1926 length); |
| 1927 |
| 1928 // Copy bytes from the left string. |
| 1929 BuildCopySeqStringChars( |
| 1930 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1931 string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1932 left_length); |
| 1933 |
| 1934 // Copy bytes from the right string. |
| 1935 BuildCopySeqStringChars( |
| 1936 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1937 string, left_length, String::TWO_BYTE_ENCODING, |
| 1938 right_length); |
| 1939 |
| 1940 // Return the string. |
| 1941 Push(string); |
| 1614 } | 1942 } |
| 1615 if_onebyte.End(); | 1943 if_onebyte.End(); |
| 1616 | 1944 |
| 1617 // Initialize the cons string fields. | 1945 // Initialize the (common) string fields. |
| 1946 HValue* string = Pop(); |
| 1618 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | 1947 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), |
| 1619 Add<HConstant>(String::kEmptyHashField)); | 1948 Add<HConstant>(String::kEmptyHashField)); |
| 1620 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); | 1949 |
| 1621 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left); | 1950 // Count the native string addition. |
| 1622 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(), | 1951 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1623 right); | 1952 |
| 1624 | |
| 1625 // Cons string is result. | |
| 1626 Push(string); | 1953 Push(string); |
| 1627 } | 1954 } |
| 1628 if_createcons.Else(); | 1955 if_sameencodingandsequential.Else(); |
| 1629 { | 1956 { |
| 1630 // Compute union of instance types. | 1957 // Fallback to the runtime to add the two strings. |
| 1631 HValue* ored_instance_types = Add<HBitwise>( | 1958 Add<HPushArgument>(left); |
| 1632 Token::BIT_OR, left_instance_type, right_instance_type); | 1959 Add<HPushArgument>(right); |
| 1633 | 1960 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 1634 // Check if both strings have the same encoding and both are | 1961 Runtime::FunctionForId(Runtime::kStringAdd), |
| 1635 // sequential. | 1962 2)); |
| 1636 IfBuilder if_sameencodingandsequential(this); | 1963 } |
| 1637 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | 1964 if_sameencodingandsequential.End(); |
| 1638 Add<HBitwise>( | |
| 1639 Token::BIT_AND, xored_instance_types, | |
| 1640 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | |
| 1641 graph()->GetConstant0(), Token::EQ); | |
| 1642 if_sameencodingandsequential.And(); | |
| 1643 STATIC_ASSERT(kSeqStringTag == 0); | |
| 1644 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | |
| 1645 Add<HBitwise>( | |
| 1646 Token::BIT_AND, ored_instance_types, | |
| 1647 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), | |
| 1648 graph()->GetConstant0(), Token::EQ); | |
| 1649 if_sameencodingandsequential.Then(); | |
| 1650 { | |
| 1651 // Check if the result is a one-byte string. | |
| 1652 IfBuilder if_onebyte(this); | |
| 1653 STATIC_ASSERT(kOneByteStringTag != 0); | |
| 1654 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1655 Add<HBitwise>( | |
| 1656 Token::BIT_AND, ored_instance_types, | |
| 1657 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | |
| 1658 graph()->GetConstant0(), Token::NE); | |
| 1659 if_onebyte.Then(); | |
| 1660 { | |
| 1661 // Calculate the number of bytes needed for the characters in the | |
| 1662 // string while observing object alignment. | |
| 1663 HValue* size = BuildSeqStringSizeFor( | |
| 1664 length, String::ONE_BYTE_ENCODING); | |
| 1665 | |
| 1666 // Allocate the ASCII string object. | |
| 1667 Handle<Map> map = isolate()->factory()->ascii_string_map(); | |
| 1668 HAllocate* string = Add<HAllocate>(size, HType::String(), | |
| 1669 pretenure_flag, ASCII_STRING_TYPE); | |
| 1670 string->set_known_initial_map(map); | |
| 1671 | |
| 1672 // We can safely skip the write barrier for storing map here. | |
| 1673 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1674 | |
| 1675 // Copy bytes from the left string. | |
| 1676 BuildCopySeqStringChars( | |
| 1677 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1678 string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1679 left_length); | |
| 1680 | |
| 1681 // Copy bytes from the right string. | |
| 1682 BuildCopySeqStringChars( | |
| 1683 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1684 string, left_length, String::ONE_BYTE_ENCODING, | |
| 1685 right_length); | |
| 1686 | |
| 1687 // Return the string. | |
| 1688 Push(string); | |
| 1689 } | |
| 1690 if_onebyte.Else(); | |
| 1691 { | |
| 1692 // Calculate the number of bytes needed for the characters in the | |
| 1693 // string while observing object alignment. | |
| 1694 HValue* size = BuildSeqStringSizeFor( | |
| 1695 length, String::TWO_BYTE_ENCODING); | |
| 1696 | |
| 1697 // Allocate the two-byte string object. | |
| 1698 Handle<Map> map = isolate()->factory()->string_map(); | |
| 1699 HAllocate* string = Add<HAllocate>(size, HType::String(), | |
| 1700 pretenure_flag, STRING_TYPE); | |
| 1701 string->set_known_initial_map(map); | |
| 1702 | |
| 1703 // We can safely skip the write barrier for storing map here. | |
| 1704 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1705 | |
| 1706 // Copy bytes from the left string. | |
| 1707 BuildCopySeqStringChars( | |
| 1708 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1709 string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1710 left_length); | |
| 1711 | |
| 1712 // Copy bytes from the right string. | |
| 1713 BuildCopySeqStringChars( | |
| 1714 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1715 string, left_length, String::TWO_BYTE_ENCODING, | |
| 1716 right_length); | |
| 1717 | |
| 1718 // Return the string. | |
| 1719 Push(string); | |
| 1720 } | |
| 1721 if_onebyte.End(); | |
| 1722 | |
| 1723 // Initialize the (common) string fields. | |
| 1724 HValue* string = Pop(); | |
| 1725 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | |
| 1726 Add<HConstant>(String::kEmptyHashField)); | |
| 1727 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), | |
| 1728 length); | |
| 1729 Push(string); | |
| 1730 } | |
| 1731 if_sameencodingandsequential.JoinContinuation(&handled); | |
| 1732 } | |
| 1733 if_createcons.JoinContinuation(&handled); | |
| 1734 } | 1965 } |
| 1735 if_nooverflow.JoinContinuation(&handled); | 1966 if_createcons.End(); |
| 1736 | |
| 1737 // Check if the strings were concatenated successfully, otherwise fallback to | |
| 1738 // add the strings in the runtime. | |
| 1739 IfBuilder if_handled(this, &handled); | |
| 1740 if_handled.Then(); | |
| 1741 { | |
| 1742 // Count the native string addition. | |
| 1743 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
| 1744 } | |
| 1745 if_handled.Else(); | |
| 1746 { | |
| 1747 // Fallback to the runtime to add the two strings. | |
| 1748 Add<HPushArgument>(left); | |
| 1749 Add<HPushArgument>(right); | |
| 1750 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), | |
| 1751 Runtime::FunctionForId(Runtime::kStringAdd), | |
| 1752 2)); | |
| 1753 } | |
| 1754 if_handled.End(); | |
| 1755 | 1967 |
| 1756 return Pop(); | 1968 return Pop(); |
| 1757 } | 1969 } |
| 1758 | 1970 |
| 1759 | 1971 |
| 1760 HValue* HGraphBuilder::BuildStringAdd(HValue* left, | 1972 HValue* HGraphBuilder::BuildStringAdd(HValue* left, |
| 1761 HValue* right, | 1973 HValue* right, |
| 1762 PretenureFlag pretenure_flag) { | 1974 PretenureFlag pretenure_flag) { |
| 1763 // Determine the string lengths. | 1975 // Determine the string lengths. |
| 1764 HValue* left_length = Add<HLoadNamedField>( | 1976 HValue* left_length = Add<HLoadNamedField>( |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1852 IfBuilder length_checker(this); | 2064 IfBuilder length_checker(this); |
| 1853 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); | 2065 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); |
| 1854 length_checker.Then(); | 2066 length_checker.Then(); |
| 1855 IfBuilder negative_checker(this); | 2067 IfBuilder negative_checker(this); |
| 1856 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( | 2068 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( |
| 1857 key, graph()->GetConstant0(), Token::GTE); | 2069 key, graph()->GetConstant0(), Token::GTE); |
| 1858 negative_checker.Then(); | 2070 negative_checker.Then(); |
| 1859 HInstruction* result = AddElementAccess( | 2071 HInstruction* result = AddElementAccess( |
| 1860 external_elements, key, val, bounds_check, elements_kind, is_store); | 2072 external_elements, key, val, bounds_check, elements_kind, is_store); |
| 1861 negative_checker.ElseDeopt("Negative key encountered"); | 2073 negative_checker.ElseDeopt("Negative key encountered"); |
| 2074 negative_checker.End(); |
| 1862 length_checker.End(); | 2075 length_checker.End(); |
| 1863 return result; | 2076 return result; |
| 1864 } else { | 2077 } else { |
| 1865 ASSERT(store_mode == STANDARD_STORE); | 2078 ASSERT(store_mode == STANDARD_STORE); |
| 1866 checked_key = Add<HBoundsCheck>(key, length); | 2079 checked_key = Add<HBoundsCheck>(key, length); |
| 1867 HLoadExternalArrayPointer* external_elements = | 2080 HLoadExternalArrayPointer* external_elements = |
| 1868 Add<HLoadExternalArrayPointer>(elements); | 2081 Add<HLoadExternalArrayPointer>(elements); |
| 1869 return AddElementAccess( | 2082 return AddElementAccess( |
| 1870 external_elements, checked_key, val, | 2083 external_elements, checked_key, val, |
| 1871 checked_object, elements_kind, is_store); | 2084 checked_object, elements_kind, is_store); |
| 1872 } | 2085 } |
| 1873 } | 2086 } |
| 1874 ASSERT(fast_smi_only_elements || | 2087 ASSERT(fast_smi_only_elements || |
| 1875 fast_elements || | 2088 fast_elements || |
| 1876 IsFastDoubleElementsKind(elements_kind)); | 2089 IsFastDoubleElementsKind(elements_kind)); |
| 1877 | 2090 |
| 1878 // In case val is stored into a fast smi array, assure that the value is a smi | 2091 // In case val is stored into a fast smi array, assure that the value is a smi |
| 1879 // before manipulating the backing store. Otherwise the actual store may | 2092 // before manipulating the backing store. Otherwise the actual store may |
| 1880 // deopt, leaving the backing store in an invalid state. | 2093 // deopt, leaving the backing store in an invalid state. |
| 1881 if (is_store && IsFastSmiElementsKind(elements_kind) && | 2094 if (is_store && IsFastSmiElementsKind(elements_kind) && |
| 1882 !val->type().IsSmi()) { | 2095 !val->type().IsSmi()) { |
| 1883 val = Add<HForceRepresentation>(val, Representation::Smi()); | 2096 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); |
| 1884 } | 2097 } |
| 1885 | 2098 |
| 1886 if (IsGrowStoreMode(store_mode)) { | 2099 if (IsGrowStoreMode(store_mode)) { |
| 1887 NoObservableSideEffectsScope no_effects(this); | 2100 NoObservableSideEffectsScope no_effects(this); |
| 1888 elements = BuildCheckForCapacityGrow(checked_object, elements, | 2101 elements = BuildCheckForCapacityGrow(checked_object, elements, |
| 1889 elements_kind, length, key, | 2102 elements_kind, length, key, |
| 1890 is_js_array); | 2103 is_js_array); |
| 1891 checked_key = key; | 2104 checked_key = key; |
| 1892 } else { | 2105 } else { |
| 1893 checked_key = Add<HBoundsCheck>(key, length); | 2106 checked_key = Add<HBoundsCheck>(key, length); |
| 1894 | 2107 |
| 1895 if (is_store && (fast_elements || fast_smi_only_elements)) { | 2108 if (is_store && (fast_elements || fast_smi_only_elements)) { |
| 1896 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { | 2109 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { |
| 1897 NoObservableSideEffectsScope no_effects(this); | 2110 NoObservableSideEffectsScope no_effects(this); |
| 1898 elements = BuildCopyElementsOnWrite(checked_object, elements, | 2111 elements = BuildCopyElementsOnWrite(checked_object, elements, |
| 1899 elements_kind, length); | 2112 elements_kind, length); |
| 1900 } else { | 2113 } else { |
| 1901 HCheckMaps* check_cow_map = Add<HCheckMaps>( | 2114 HCheckMaps* check_cow_map = Add<HCheckMaps>( |
| 1902 elements, isolate()->factory()->fixed_array_map(), top_info()); | 2115 elements, isolate()->factory()->fixed_array_map(), top_info()); |
| 1903 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 2116 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 1904 } | 2117 } |
| 1905 } | 2118 } |
| 1906 } | 2119 } |
| 1907 return AddElementAccess(elements, checked_key, val, checked_object, | 2120 return AddElementAccess(elements, checked_key, val, checked_object, |
| 1908 elements_kind, is_store, load_mode); | 2121 elements_kind, is_store, load_mode); |
| 1909 } | 2122 } |
| 1910 | 2123 |
| 1911 | 2124 |
| 2125 |
| 2126 HValue* HGraphBuilder::BuildAllocateArrayFromLength( |
| 2127 JSArrayBuilder* array_builder, |
| 2128 HValue* length_argument) { |
| 2129 if (length_argument->IsConstant() && |
| 2130 HConstant::cast(length_argument)->HasSmiValue()) { |
| 2131 int array_length = HConstant::cast(length_argument)->Integer32Value(); |
| 2132 HValue* new_object = array_length == 0 |
| 2133 ? array_builder->AllocateEmptyArray() |
| 2134 : array_builder->AllocateArray(length_argument, length_argument); |
| 2135 return new_object; |
| 2136 } |
| 2137 |
| 2138 HValue* constant_zero = graph()->GetConstant0(); |
| 2139 HConstant* max_alloc_length = |
| 2140 Add<HConstant>(JSObject::kInitialMaxFastElementArray); |
| 2141 HInstruction* checked_length = Add<HBoundsCheck>(length_argument, |
| 2142 max_alloc_length); |
| 2143 IfBuilder if_builder(this); |
| 2144 if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero, |
| 2145 Token::EQ); |
| 2146 if_builder.Then(); |
| 2147 const int initial_capacity = JSArray::kPreallocatedArrayElements; |
| 2148 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); |
| 2149 Push(initial_capacity_node); // capacity |
| 2150 Push(constant_zero); // length |
| 2151 if_builder.Else(); |
| 2152 if (!(top_info()->IsStub()) && |
| 2153 IsFastPackedElementsKind(array_builder->kind())) { |
| 2154 // We'll come back later with better (holey) feedback. |
| 2155 if_builder.Deopt("Holey array despite packed elements_kind feedback"); |
| 2156 } else { |
| 2157 Push(checked_length); // capacity |
| 2158 Push(checked_length); // length |
| 2159 } |
| 2160 if_builder.End(); |
| 2161 |
| 2162 // Figure out total size |
| 2163 HValue* length = Pop(); |
| 2164 HValue* capacity = Pop(); |
| 2165 return array_builder->AllocateArray(capacity, length); |
| 2166 } |
| 2167 |
| 1912 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, | 2168 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, |
| 1913 HValue* capacity) { | 2169 HValue* capacity) { |
| 1914 int elements_size; | 2170 int elements_size; |
| 1915 InstanceType instance_type; | 2171 InstanceType instance_type; |
| 1916 | 2172 |
| 1917 if (IsFastDoubleElementsKind(kind)) { | 2173 if (IsFastDoubleElementsKind(kind)) { |
| 1918 elements_size = kDoubleSize; | 2174 elements_size = kDoubleSize; |
| 1919 instance_type = FIXED_DOUBLE_ARRAY_TYPE; | 2175 instance_type = FIXED_DOUBLE_ARRAY_TYPE; |
| 1920 } else { | 2176 } else { |
| 1921 elements_size = kPointerSize; | 2177 elements_size = kPointerSize; |
| 1922 instance_type = FIXED_ARRAY_TYPE; | 2178 instance_type = FIXED_ARRAY_TYPE; |
| 1923 } | 2179 } |
| 1924 | 2180 |
| 1925 HConstant* elements_size_value = Add<HConstant>(elements_size); | 2181 HConstant* elements_size_value = Add<HConstant>(elements_size); |
| 1926 HValue* mul = Add<HMul>(capacity, elements_size_value); | 2182 HValue* mul = AddUncasted<HMul>(capacity, elements_size_value); |
| 1927 mul->ClearFlag(HValue::kCanOverflow); | 2183 mul->ClearFlag(HValue::kCanOverflow); |
| 1928 | 2184 |
| 1929 HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize); | 2185 HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize); |
| 1930 HValue* total_size = Add<HAdd>(mul, header_size); | 2186 HValue* total_size = AddUncasted<HAdd>(mul, header_size); |
| 1931 total_size->ClearFlag(HValue::kCanOverflow); | 2187 total_size->ClearFlag(HValue::kCanOverflow); |
| 1932 | 2188 |
| 1933 return Add<HAllocate>(total_size, HType::JSArray(), | 2189 return Add<HAllocate>(total_size, HType::JSArray(), |
| 1934 isolate()->heap()->GetPretenureMode(), instance_type); | 2190 isolate()->heap()->GetPretenureMode(), instance_type); |
| 1935 } | 2191 } |
| 1936 | 2192 |
| 1937 | 2193 |
| 1938 void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements, | 2194 void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements, |
| 1939 ElementsKind kind, | 2195 ElementsKind kind, |
| 1940 HValue* capacity) { | 2196 HValue* capacity) { |
| 1941 Factory* factory = isolate()->factory(); | 2197 Factory* factory = isolate()->factory(); |
| 1942 Handle<Map> map = IsFastDoubleElementsKind(kind) | 2198 Handle<Map> map = IsFastDoubleElementsKind(kind) |
| 1943 ? factory->fixed_double_array_map() | 2199 ? factory->fixed_double_array_map() |
| 1944 : factory->fixed_array_map(); | 2200 : factory->fixed_array_map(); |
| 1945 | 2201 |
| 1946 AddStoreMapConstant(elements, map); | 2202 AddStoreMapConstant(elements, map); |
| 1947 Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(), | 2203 Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(), |
| 1948 capacity); | 2204 capacity); |
| 1949 } | 2205 } |
| 1950 | 2206 |
| 1951 | 2207 |
| 1952 HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader( | 2208 HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader( |
| 1953 ElementsKind kind, | 2209 ElementsKind kind, |
| 1954 HValue* capacity) { | 2210 HValue* capacity) { |
| 1955 // The HForceRepresentation is to prevent possible deopt on int-smi | 2211 // The HForceRepresentation is to prevent possible deopt on int-smi |
| 1956 // conversion after allocation but before the new object fields are set. | 2212 // conversion after allocation but before the new object fields are set. |
| 1957 capacity = Add<HForceRepresentation>(capacity, Representation::Smi()); | 2213 capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi()); |
| 1958 HValue* new_elements = BuildAllocateElements(kind, capacity); | 2214 HValue* new_elements = BuildAllocateElements(kind, capacity); |
| 1959 BuildInitializeElementsHeader(new_elements, kind, capacity); | 2215 BuildInitializeElementsHeader(new_elements, kind, capacity); |
| 1960 return new_elements; | 2216 return new_elements; |
| 1961 } | 2217 } |
| 1962 | 2218 |
| 1963 | 2219 |
| 1964 HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array, | 2220 HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array, |
| 1965 HValue* array_map, | 2221 HValue* array_map, |
| 1966 AllocationSiteMode mode, | 2222 AllocationSiteMode mode, |
| 1967 ElementsKind elements_kind, | 2223 ElementsKind elements_kind, |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2090 // Fast elements kinds need to be initialized in case statements below cause | 2346 // Fast elements kinds need to be initialized in case statements below cause |
| 2091 // a garbage collection. | 2347 // a garbage collection. |
| 2092 Factory* factory = isolate()->factory(); | 2348 Factory* factory = isolate()->factory(); |
| 2093 | 2349 |
| 2094 double nan_double = FixedDoubleArray::hole_nan_as_double(); | 2350 double nan_double = FixedDoubleArray::hole_nan_as_double(); |
| 2095 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) | 2351 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) |
| 2096 ? Add<HConstant>(factory->the_hole_value()) | 2352 ? Add<HConstant>(factory->the_hole_value()) |
| 2097 : Add<HConstant>(nan_double); | 2353 : Add<HConstant>(nan_double); |
| 2098 | 2354 |
| 2099 // Special loop unfolding case | 2355 // Special loop unfolding case |
| 2100 static const int kLoopUnfoldLimit = 4; | 2356 static const int kLoopUnfoldLimit = 8; |
| 2101 bool unfold_loop = false; | 2357 STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit); |
| 2102 int initial_capacity = JSArray::kPreallocatedArrayElements; | 2358 int initial_capacity = -1; |
| 2103 if (from->IsConstant() && to->IsConstant() && | 2359 if (from->IsInteger32Constant() && to->IsInteger32Constant()) { |
| 2104 initial_capacity <= kLoopUnfoldLimit) { | 2360 int constant_from = from->GetInteger32Constant(); |
| 2105 HConstant* constant_from = HConstant::cast(from); | 2361 int constant_to = to->GetInteger32Constant(); |
| 2106 HConstant* constant_to = HConstant::cast(to); | |
| 2107 | 2362 |
| 2108 if (constant_from->HasInteger32Value() && | 2363 if (constant_from == 0 && constant_to <= kLoopUnfoldLimit) { |
| 2109 constant_from->Integer32Value() == 0 && | 2364 initial_capacity = constant_to; |
| 2110 constant_to->HasInteger32Value() && | |
| 2111 constant_to->Integer32Value() == initial_capacity) { | |
| 2112 unfold_loop = true; | |
| 2113 } | 2365 } |
| 2114 } | 2366 } |
| 2115 | 2367 |
| 2116 // Since we're about to store a hole value, the store instruction below must | 2368 // Since we're about to store a hole value, the store instruction below must |
| 2117 // assume an elements kind that supports heap object values. | 2369 // assume an elements kind that supports heap object values. |
| 2118 if (IsFastSmiOrObjectElementsKind(elements_kind)) { | 2370 if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 2119 elements_kind = FAST_HOLEY_ELEMENTS; | 2371 elements_kind = FAST_HOLEY_ELEMENTS; |
| 2120 } | 2372 } |
| 2121 | 2373 |
| 2122 if (unfold_loop) { | 2374 if (initial_capacity >= 0) { |
| 2123 for (int i = 0; i < initial_capacity; i++) { | 2375 for (int i = 0; i < initial_capacity; i++) { |
| 2124 HInstruction* key = Add<HConstant>(i); | 2376 HInstruction* key = Add<HConstant>(i); |
| 2125 Add<HStoreKeyed>(elements, key, hole, elements_kind); | 2377 Add<HStoreKeyed>(elements, key, hole, elements_kind); |
| 2126 } | 2378 } |
| 2127 } else { | 2379 } else { |
| 2128 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); | 2380 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); |
| 2129 | 2381 |
| 2130 HValue* key = builder.BeginBody(from, to, Token::LT); | 2382 HValue* key = builder.BeginBody(from, to, Token::LT); |
| 2131 | 2383 |
| 2132 Add<HStoreKeyed>(elements, key, hole, elements_kind); | 2384 Add<HStoreKeyed>(elements, key, hole, elements_kind); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2371 HValue* constructor_function) : | 2623 HValue* constructor_function) : |
| 2372 builder_(builder), | 2624 builder_(builder), |
| 2373 kind_(kind), | 2625 kind_(kind), |
| 2374 mode_(DONT_TRACK_ALLOCATION_SITE), | 2626 mode_(DONT_TRACK_ALLOCATION_SITE), |
| 2375 allocation_site_payload_(NULL), | 2627 allocation_site_payload_(NULL), |
| 2376 constructor_function_(constructor_function) { | 2628 constructor_function_(constructor_function) { |
| 2377 } | 2629 } |
| 2378 | 2630 |
| 2379 | 2631 |
| 2380 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { | 2632 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { |
| 2381 if (kind_ == GetInitialFastElementsKind()) { | 2633 if (!builder()->top_info()->IsStub()) { |
| 2634 // A constant map is fine. |
| 2635 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), |
| 2636 builder()->isolate()); |
| 2637 return builder()->Add<HConstant>(map); |
| 2638 } |
| 2639 |
| 2640 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) { |
| 2382 // No need for a context lookup if the kind_ matches the initial | 2641 // No need for a context lookup if the kind_ matches the initial |
| 2383 // map, because we can just load the map in that case. | 2642 // map, because we can just load the map in that case. |
| 2384 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | 2643 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
| 2385 return builder()->AddLoadNamedField(constructor_function_, access); | 2644 return builder()->AddLoadNamedField(constructor_function_, access); |
| 2386 } | 2645 } |
| 2387 | 2646 |
| 2388 HInstruction* native_context = builder()->BuildGetNativeContext(); | 2647 HInstruction* native_context = builder()->BuildGetNativeContext(); |
| 2389 HInstruction* index = builder()->Add<HConstant>( | 2648 HInstruction* index = builder()->Add<HConstant>( |
| 2390 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); | 2649 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); |
| 2391 | 2650 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2413 int base_size = JSArray::kSize; | 2672 int base_size = JSArray::kSize; |
| 2414 if (mode_ == TRACK_ALLOCATION_SITE) { | 2673 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2415 base_size += AllocationMemento::kSize; | 2674 base_size += AllocationMemento::kSize; |
| 2416 } | 2675 } |
| 2417 | 2676 |
| 2418 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); | 2677 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); |
| 2419 base_size += FixedArray::kHeaderSize; | 2678 base_size += FixedArray::kHeaderSize; |
| 2420 | 2679 |
| 2421 HInstruction* elements_size_value = | 2680 HInstruction* elements_size_value = |
| 2422 builder()->Add<HConstant>(elements_size()); | 2681 builder()->Add<HConstant>(elements_size()); |
| 2423 HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value); | 2682 HInstruction* mul = HMul::NewImul(builder()->zone(), builder()->context(), |
| 2424 mul->ClearFlag(HValue::kCanOverflow); | 2683 length_node, elements_size_value); |
| 2425 | 2684 builder()->AddInstruction(mul); |
| 2426 HInstruction* base = builder()->Add<HConstant>(base_size); | 2685 HInstruction* base = builder()->Add<HConstant>(base_size); |
| 2427 HInstruction* total_size = builder()->Add<HAdd>(base, mul); | 2686 HInstruction* total_size = HAdd::New(builder()->zone(), builder()->context(), |
| 2687 base, mul); |
| 2428 total_size->ClearFlag(HValue::kCanOverflow); | 2688 total_size->ClearFlag(HValue::kCanOverflow); |
| 2689 builder()->AddInstruction(total_size); |
| 2429 return total_size; | 2690 return total_size; |
| 2430 } | 2691 } |
| 2431 | 2692 |
| 2432 | 2693 |
| 2433 HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() { | 2694 HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() { |
| 2434 int base_size = JSArray::kSize; | 2695 int base_size = JSArray::kSize; |
| 2435 if (mode_ == TRACK_ALLOCATION_SITE) { | 2696 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2436 base_size += AllocationMemento::kSize; | 2697 base_size += AllocationMemento::kSize; |
| 2437 } | 2698 } |
| 2438 | 2699 |
| 2439 base_size += IsFastDoubleElementsKind(kind_) | 2700 base_size += IsFastDoubleElementsKind(kind_) |
| 2440 ? FixedDoubleArray::SizeFor(initial_capacity()) | 2701 ? FixedDoubleArray::SizeFor(initial_capacity()) |
| 2441 : FixedArray::SizeFor(initial_capacity()); | 2702 : FixedArray::SizeFor(initial_capacity()); |
| 2442 | 2703 |
| 2443 return builder()->Add<HConstant>(base_size); | 2704 return builder()->Add<HConstant>(base_size); |
| 2444 } | 2705 } |
| 2445 | 2706 |
| 2446 | 2707 |
| 2447 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { | 2708 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { |
| 2448 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); | 2709 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); |
| 2449 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); | 2710 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); |
| 2450 return AllocateArray(size_in_bytes, | 2711 return AllocateArray(size_in_bytes, |
| 2451 capacity, | 2712 capacity, |
| 2452 builder()->graph()->GetConstant0(), | 2713 builder()->graph()->GetConstant0()); |
| 2453 true); | |
| 2454 } | 2714 } |
| 2455 | 2715 |
| 2456 | 2716 |
| 2457 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, | 2717 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, |
| 2458 HValue* length_field, | 2718 HValue* length_field, |
| 2459 bool fill_with_hole) { | 2719 FillMode fill_mode) { |
| 2460 HValue* size_in_bytes = EstablishAllocationSize(capacity); | 2720 HValue* size_in_bytes = EstablishAllocationSize(capacity); |
| 2461 return AllocateArray(size_in_bytes, capacity, length_field, fill_with_hole); | 2721 return AllocateArray(size_in_bytes, capacity, length_field, fill_mode); |
| 2462 } | 2722 } |
| 2463 | 2723 |
| 2464 | 2724 |
| 2465 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, | 2725 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, |
| 2466 HValue* capacity, | 2726 HValue* capacity, |
| 2467 HValue* length_field, | 2727 HValue* length_field, |
| 2468 bool fill_with_hole) { | 2728 FillMode fill_mode) { |
| 2469 // These HForceRepresentations are because we store these as fields in the | 2729 // These HForceRepresentations are because we store these as fields in the |
| 2470 // objects we construct, and an int32-to-smi HChange could deopt. Accept | 2730 // objects we construct, and an int32-to-smi HChange could deopt. Accept |
| 2471 // the deopt possibility now, before allocation occurs. | 2731 // the deopt possibility now, before allocation occurs. |
| 2472 capacity = builder()->Add<HForceRepresentation>(capacity, | 2732 capacity = |
| 2473 Representation::Smi()); | 2733 builder()->AddUncasted<HForceRepresentation>(capacity, |
| 2474 length_field = builder()->Add<HForceRepresentation>(length_field, | 2734 Representation::Smi()); |
| 2475 Representation::Smi()); | 2735 length_field = |
| 2736 builder()->AddUncasted<HForceRepresentation>(length_field, |
| 2737 Representation::Smi()); |
| 2476 // Allocate (dealing with failure appropriately) | 2738 // Allocate (dealing with failure appropriately) |
| 2477 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, | 2739 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, |
| 2478 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); | 2740 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); |
| 2479 | 2741 |
| 2480 // Folded array allocation should be aligned if it has fast double elements. | 2742 // Folded array allocation should be aligned if it has fast double elements. |
| 2481 if (IsFastDoubleElementsKind(kind_)) { | 2743 if (IsFastDoubleElementsKind(kind_)) { |
| 2482 new_object->MakeDoubleAligned(); | 2744 new_object->MakeDoubleAligned(); |
| 2483 } | 2745 } |
| 2484 | 2746 |
| 2485 // Fill in the fields: map, properties, length | 2747 // Fill in the fields: map, properties, length |
| 2486 HValue* map; | 2748 HValue* map; |
| 2487 if (allocation_site_payload_ == NULL) { | 2749 if (allocation_site_payload_ == NULL) { |
| 2488 map = EmitInternalMapCode(); | 2750 map = EmitInternalMapCode(); |
| 2489 } else { | 2751 } else { |
| 2490 map = EmitMapCode(); | 2752 map = EmitMapCode(); |
| 2491 } | 2753 } |
| 2492 elements_location_ = builder()->BuildJSArrayHeader(new_object, | 2754 elements_location_ = builder()->BuildJSArrayHeader(new_object, |
| 2493 map, | 2755 map, |
| 2494 mode_, | 2756 mode_, |
| 2495 kind_, | 2757 kind_, |
| 2496 allocation_site_payload_, | 2758 allocation_site_payload_, |
| 2497 length_field); | 2759 length_field); |
| 2498 | 2760 |
| 2499 // Initialize the elements | 2761 // Initialize the elements |
| 2500 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); | 2762 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); |
| 2501 | 2763 |
| 2502 if (fill_with_hole) { | 2764 if (fill_mode == FILL_WITH_HOLE) { |
| 2503 builder()->BuildFillElementsWithHole(elements_location_, kind_, | 2765 builder()->BuildFillElementsWithHole(elements_location_, kind_, |
| 2504 graph()->GetConstant0(), capacity); | 2766 graph()->GetConstant0(), capacity); |
| 2505 } | 2767 } |
| 2506 | 2768 |
| 2507 return new_object; | 2769 return new_object; |
| 2508 } | 2770 } |
| 2509 | 2771 |
| 2510 | 2772 |
| 2511 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, | 2773 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, |
| 2512 Handle<Map> map) { | 2774 Handle<Map> map) { |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2652 | 2914 |
| 2653 HBasicBlock* HGraph::CreateBasicBlock() { | 2915 HBasicBlock* HGraph::CreateBasicBlock() { |
| 2654 HBasicBlock* result = new(zone()) HBasicBlock(this); | 2916 HBasicBlock* result = new(zone()) HBasicBlock(this); |
| 2655 blocks_.Add(result, zone()); | 2917 blocks_.Add(result, zone()); |
| 2656 return result; | 2918 return result; |
| 2657 } | 2919 } |
| 2658 | 2920 |
| 2659 | 2921 |
| 2660 void HGraph::FinalizeUniqueness() { | 2922 void HGraph::FinalizeUniqueness() { |
| 2661 DisallowHeapAllocation no_gc; | 2923 DisallowHeapAllocation no_gc; |
| 2662 ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread()); | 2924 ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate())); |
| 2663 for (int i = 0; i < blocks()->length(); ++i) { | 2925 for (int i = 0; i < blocks()->length(); ++i) { |
| 2664 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { | 2926 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { |
| 2665 it.Current()->FinalizeUniqueness(); | 2927 it.Current()->FinalizeUniqueness(); |
| 2666 } | 2928 } |
| 2667 } | 2929 } |
| 2668 } | 2930 } |
| 2669 | 2931 |
| 2670 | 2932 |
| 2671 // Block ordering was implemented with two mutually recursive methods, | 2933 // Block ordering was implemented with two mutually recursive methods, |
| 2672 // HGraph::Postorder and HGraph::PostorderLoopBlocks. | 2934 // HGraph::Postorder and HGraph::PostorderLoopBlocks. |
| (...skipping 1569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4242 BreakAndContinueInfo break_info(stmt, 5); | 4504 BreakAndContinueInfo break_info(stmt, 5); |
| 4243 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info)); | 4505 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info)); |
| 4244 | 4506 |
| 4245 HBasicBlock* body_exit = | 4507 HBasicBlock* body_exit = |
| 4246 JoinContinue(stmt, current_block(), break_info.continue_block()); | 4508 JoinContinue(stmt, current_block(), break_info.continue_block()); |
| 4247 | 4509 |
| 4248 if (body_exit != NULL) { | 4510 if (body_exit != NULL) { |
| 4249 set_current_block(body_exit); | 4511 set_current_block(body_exit); |
| 4250 | 4512 |
| 4251 HValue* current_index = Pop(); | 4513 HValue* current_index = Pop(); |
| 4252 Push(Add<HAdd>(current_index, graph()->GetConstant1())); | 4514 Push(AddUncasted<HAdd>(current_index, graph()->GetConstant1())); |
| 4253 body_exit = current_block(); | 4515 body_exit = current_block(); |
| 4254 } | 4516 } |
| 4255 | 4517 |
| 4256 HBasicBlock* loop_exit = CreateLoop(stmt, | 4518 HBasicBlock* loop_exit = CreateLoop(stmt, |
| 4257 loop_entry, | 4519 loop_entry, |
| 4258 body_exit, | 4520 body_exit, |
| 4259 loop_successor, | 4521 loop_successor, |
| 4260 break_info.break_block()); | 4522 break_info.break_block()); |
| 4261 | 4523 |
| 4262 set_current_block(loop_exit); | 4524 set_current_block(loop_exit); |
| (...skipping 1409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5672 CHECK_ALIVE(VisitForValue(prop->key())); | 5934 CHECK_ALIVE(VisitForValue(prop->key())); |
| 5673 key = Top(); | 5935 key = Top(); |
| 5674 } | 5936 } |
| 5675 | 5937 |
| 5676 CHECK_ALIVE(PushLoad(prop, object, key)); | 5938 CHECK_ALIVE(PushLoad(prop, object, key)); |
| 5677 | 5939 |
| 5678 CHECK_ALIVE(VisitForValue(expr->value())); | 5940 CHECK_ALIVE(VisitForValue(expr->value())); |
| 5679 HValue* right = Pop(); | 5941 HValue* right = Pop(); |
| 5680 HValue* left = Pop(); | 5942 HValue* left = Pop(); |
| 5681 | 5943 |
| 5682 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 5944 Push(BuildBinaryOperation(operation, left, right)); |
| 5683 AddInstruction(instr); | |
| 5684 Push(instr); | |
| 5685 if (instr->HasObservableSideEffects()) { | |
| 5686 Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); | |
| 5687 } | |
| 5688 BuildStore(expr, prop, expr->id(), | 5945 BuildStore(expr, prop, expr->id(), |
| 5689 expr->AssignmentId(), expr->IsUninitialized()); | 5946 expr->AssignmentId(), expr->IsUninitialized()); |
| 5690 } else { | 5947 } else { |
| 5691 return Bailout(kInvalidLhsInCompoundAssignment); | 5948 return Bailout(kInvalidLhsInCompoundAssignment); |
| 5692 } | 5949 } |
| 5693 } | 5950 } |
| 5694 | 5951 |
| 5695 | 5952 |
| 5696 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { | 5953 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { |
| 5697 ASSERT(!HasStackOverflow()); | 5954 ASSERT(!HasStackOverflow()); |
| (...skipping 1513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7211 } | 7468 } |
| 7212 } | 7469 } |
| 7213 | 7470 |
| 7214 if (result == NULL) { | 7471 if (result == NULL) { |
| 7215 result = NewUncasted<HPower>(left, right); | 7472 result = NewUncasted<HPower>(left, right); |
| 7216 } | 7473 } |
| 7217 ast_context()->ReturnInstruction(result, expr->id()); | 7474 ast_context()->ReturnInstruction(result, expr->id()); |
| 7218 return true; | 7475 return true; |
| 7219 } | 7476 } |
| 7220 break; | 7477 break; |
| 7221 case kMathRandom: | |
| 7222 if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) { | |
| 7223 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
| 7224 Drop(1); // Receiver. | |
| 7225 HGlobalObject* global_object = Add<HGlobalObject>(); | |
| 7226 HRandom* result = New<HRandom>(global_object); | |
| 7227 ast_context()->ReturnInstruction(result, expr->id()); | |
| 7228 return true; | |
| 7229 } | |
| 7230 break; | |
| 7231 case kMathMax: | 7478 case kMathMax: |
| 7232 case kMathMin: | 7479 case kMathMin: |
| 7233 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7480 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
| 7234 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | 7481 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
| 7235 HValue* right = Pop(); | 7482 HValue* right = Pop(); |
| 7236 HValue* left = Pop(); | 7483 HValue* left = Pop(); |
| 7237 Drop(1); // Receiver. | 7484 Drop(1); // Receiver. |
| 7238 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin | 7485 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin |
| 7239 : HMathMinMax::kMathMax; | 7486 : HMathMinMax::kMathMax; |
| 7240 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); | 7487 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7348 ASSERT(current_block() != NULL); | 7595 ASSERT(current_block() != NULL); |
| 7349 ASSERT(current_block()->HasPredecessor()); | 7596 ASSERT(current_block()->HasPredecessor()); |
| 7350 Expression* callee = expr->expression(); | 7597 Expression* callee = expr->expression(); |
| 7351 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 7598 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 7352 HInstruction* call = NULL; | 7599 HInstruction* call = NULL; |
| 7353 | 7600 |
| 7354 Property* prop = callee->AsProperty(); | 7601 Property* prop = callee->AsProperty(); |
| 7355 if (prop != NULL) { | 7602 if (prop != NULL) { |
| 7356 if (!prop->key()->IsPropertyName()) { | 7603 if (!prop->key()->IsPropertyName()) { |
| 7357 // Keyed function call. | 7604 // Keyed function call. |
| 7358 CHECK_ALIVE(VisitArgument(prop->obj())); | 7605 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 7606 CHECK_ALIVE(VisitForValue(prop->key())); |
| 7359 | 7607 |
| 7360 CHECK_ALIVE(VisitForValue(prop->key())); | |
| 7361 // 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. |
| 7362 HValue* key = Pop(); | 7609 HValue* key = Pop(); |
| 7363 HValue* receiver = Pop(); | 7610 HValue* receiver = Pop(); |
| 7364 Push(key); | 7611 Push(key); |
| 7365 Push(receiver); | 7612 Push(Add<HPushArgument>(receiver)); |
| 7366 | |
| 7367 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 7613 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 7368 | 7614 |
| 7369 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 } |
| 7370 Drop(argument_count + 1); // 1 is the key. | 7629 Drop(argument_count + 1); // 1 is the key. |
| 7371 return ast_context()->ReturnInstruction(call, expr->id()); | 7630 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7372 } | 7631 } |
| 7373 | 7632 |
| 7374 // Named function call. | 7633 // Named function call. |
| 7375 if (TryCallApply(expr)) return; | 7634 if (TryCallApply(expr)) return; |
| 7376 | 7635 |
| 7377 CHECK_ALIVE(VisitForValue(prop->obj())); | 7636 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 7378 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 7637 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7379 | 7638 |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7528 | 7787 |
| 7529 call = New<HCallFunction>(function, argument_count); | 7788 call = New<HCallFunction>(function, argument_count); |
| 7530 Drop(argument_count + 1); | 7789 Drop(argument_count + 1); |
| 7531 } | 7790 } |
| 7532 } | 7791 } |
| 7533 | 7792 |
| 7534 return ast_context()->ReturnInstruction(call, expr->id()); | 7793 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7535 } | 7794 } |
| 7536 | 7795 |
| 7537 | 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 |
| 7538 // Checks whether allocation using the given constructor can be inlined. | 7862 // Checks whether allocation using the given constructor can be inlined. |
| 7539 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 7863 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
| 7540 return constructor->has_initial_map() && | 7864 return constructor->has_initial_map() && |
| 7541 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 7865 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
| 7542 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && | 7866 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
| 7543 constructor->initial_map()->InitialPropertiesLength() == 0; | 7867 constructor->initial_map()->InitialPropertiesLength() == 0; |
| 7544 } | 7868 } |
| 7545 | 7869 |
| 7546 | 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 |
| 7547 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 7915 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| 7548 ASSERT(!HasStackOverflow()); | 7916 ASSERT(!HasStackOverflow()); |
| 7549 ASSERT(current_block() != NULL); | 7917 ASSERT(current_block() != NULL); |
| 7550 ASSERT(current_block()->HasPredecessor()); | 7918 ASSERT(current_block()->HasPredecessor()); |
| 7551 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 7919 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 7552 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 7920 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 7553 Factory* factory = isolate()->factory(); | 7921 Factory* factory = isolate()->factory(); |
| 7554 | 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 |
| 7555 if (FLAG_inline_construct && | 7929 if (FLAG_inline_construct && |
| 7556 expr->IsMonomorphic() && | 7930 expr->IsMonomorphic() && |
| 7557 IsAllocationInlineable(expr->target())) { | 7931 IsAllocationInlineable(expr->target())) { |
| 7558 // The constructor function is on the stack in the unoptimized code | |
| 7559 // during evaluation of the arguments. | |
| 7560 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 7561 HValue* function = Top(); | |
| 7562 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
| 7563 Handle<JSFunction> constructor = expr->target(); | 7932 Handle<JSFunction> constructor = expr->target(); |
| 7564 HValue* check = Add<HCheckValue>(function, constructor); | 7933 HValue* check = Add<HCheckValue>(function, constructor); |
| 7565 | 7934 |
| 7566 // Force completion of inobject slack tracking before generating | 7935 // Force completion of inobject slack tracking before generating |
| 7567 // allocation code to finalize instance size. | 7936 // allocation code to finalize instance size. |
| 7568 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { | 7937 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { |
| 7569 constructor->shared()->CompleteInobjectSlackTracking(); | 7938 constructor->shared()->CompleteInobjectSlackTracking(); |
| 7570 } | 7939 } |
| 7571 | 7940 |
| 7572 // 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... |
| 7639 check->DeleteAndReplaceWith(NULL); | 8008 check->DeleteAndReplaceWith(NULL); |
| 7640 environment()->SetExpressionStackAt(receiver_index, function); | 8009 environment()->SetExpressionStackAt(receiver_index, function); |
| 7641 HInstruction* call = | 8010 HInstruction* call = |
| 7642 PreProcessCall(New<HCallNew>(function, argument_count)); | 8011 PreProcessCall(New<HCallNew>(function, argument_count)); |
| 7643 return ast_context()->ReturnInstruction(call, expr->id()); | 8012 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7644 } else { | 8013 } else { |
| 7645 // 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 |
| 7646 // argument to the construct call. | 8015 // argument to the construct call. |
| 7647 Handle<JSFunction> array_function( | 8016 Handle<JSFunction> array_function( |
| 7648 isolate()->global_context()->array_function(), isolate()); | 8017 isolate()->global_context()->array_function(), isolate()); |
| 7649 CHECK_ALIVE(VisitArgument(expr->expression())); | 8018 bool use_call_new_array = expr->target().is_identical_to(array_function); |
| 7650 HValue* constructor = HPushArgument::cast(Top())->argument(); | 8019 Handle<Cell> cell = expr->allocation_info_cell(); |
| 7651 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 |
| 7652 HBinaryCall* call; | 8027 HBinaryCall* call; |
| 7653 if (expr->target().is_identical_to(array_function)) { | 8028 if (use_call_new_array) { |
| 7654 Handle<Cell> cell = expr->allocation_info_cell(); | 8029 Add<HCheckValue>(function, array_function); |
| 7655 Add<HCheckValue>(constructor, array_function); | 8030 call = New<HCallNewArray>(function, argument_count, cell, |
| 7656 call = New<HCallNewArray>(constructor, argument_count, | 8031 expr->elements_kind()); |
| 7657 cell, expr->elements_kind()); | |
| 7658 } else { | 8032 } else { |
| 7659 call = New<HCallNew>(constructor, argument_count); | 8033 call = New<HCallNew>(function, argument_count); |
| 7660 } | 8034 } |
| 7661 Drop(argument_count); | 8035 PreProcessCall(call); |
| 7662 return ast_context()->ReturnInstruction(call, expr->id()); | 8036 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7663 } | 8037 } |
| 7664 } | 8038 } |
| 7665 | 8039 |
| 7666 | 8040 |
| 7667 // Support for generating inlined runtime functions. | 8041 // Support for generating inlined runtime functions. |
| 7668 | 8042 |
| 7669 // Lookup table for generators for runtime calls that are generated inline. | 8043 // Lookup table for generators for runtime calls that are generated inline. |
| 7670 // Elements of the table are member pointers to functions of | 8044 // Elements of the table are member pointers to functions of |
| 7671 // HOptimizedGraphBuilder. | 8045 // HOptimizedGraphBuilder. |
| 7672 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 8046 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 7673 &HOptimizedGraphBuilder::Generate##Name, | 8047 &HOptimizedGraphBuilder::Generate##Name, |
| 7674 | 8048 |
| 7675 const HOptimizedGraphBuilder::InlineFunctionGenerator | 8049 const HOptimizedGraphBuilder::InlineFunctionGenerator |
| 7676 HOptimizedGraphBuilder::kInlineFunctionGenerators[] = { | 8050 HOptimizedGraphBuilder::kInlineFunctionGenerators[] = { |
| 7677 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 8051 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 7678 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 8052 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 7679 }; | 8053 }; |
| 7680 #undef INLINE_FUNCTION_GENERATOR_ADDRESS | 8054 #undef INLINE_FUNCTION_GENERATOR_ADDRESS |
| 7681 | 8055 |
| 7682 | 8056 |
| 8057 void HOptimizedGraphBuilder::VisitDataViewInitialize( |
| 8058 CallRuntime* expr) { |
| 8059 ZoneList<Expression*>* arguments = expr->arguments(); |
| 8060 |
| 8061 NoObservableSideEffectsScope scope(this); |
| 8062 ASSERT(arguments->length()== 4); |
| 8063 CHECK_ALIVE(VisitForValue(arguments->at(0))); |
| 8064 HValue* obj = Pop(); |
| 8065 |
| 8066 CHECK_ALIVE(VisitForValue(arguments->at(1))); |
| 8067 HValue* buffer = Pop(); |
| 8068 |
| 8069 CHECK_ALIVE(VisitForValue(arguments->at(2))); |
| 8070 HValue* byte_offset = Pop(); |
| 8071 |
| 8072 CHECK_ALIVE(VisitForValue(arguments->at(3))); |
| 8073 HValue* byte_length = Pop(); |
| 8074 |
| 8075 for (int offset = JSDataView::kSize; |
| 8076 offset < JSDataView::kSizeWithInternalFields; |
| 8077 offset += kPointerSize) { |
| 8078 Add<HStoreNamedField>(obj, |
| 8079 HObjectAccess::ForJSObjectOffset(offset), |
| 8080 Add<HConstant>(static_cast<int32_t>(0))); |
| 8081 } |
| 8082 |
| 8083 Add<HStoreNamedField>(obj, |
| 8084 HObjectAccess::ForJSObjectOffset(JSDataView::kBufferOffset), buffer); |
| 8085 Add<HStoreNamedField>(obj, |
| 8086 HObjectAccess::ForJSObjectOffset(JSDataView::kByteOffsetOffset), |
| 8087 byte_offset); |
| 8088 Add<HStoreNamedField>(obj, |
| 8089 HObjectAccess::ForJSObjectOffset(JSDataView::kByteLengthOffset), |
| 8090 byte_length); |
| 8091 |
| 8092 Add<HStoreNamedField>(obj, |
| 8093 HObjectAccess::ForJSObjectOffset(JSDataView::kWeakNextOffset), |
| 8094 Add<HLoadNamedField>(buffer, |
| 8095 HObjectAccess::ForJSObjectOffset( |
| 8096 JSArrayBuffer::kWeakFirstViewOffset))); |
| 8097 Add<HStoreNamedField>(buffer, |
| 8098 HObjectAccess::ForJSObjectOffset(JSArrayBuffer::kWeakFirstViewOffset), |
| 8099 obj); |
| 8100 } |
| 8101 |
| 8102 |
| 7683 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) { | 8103 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 7684 ASSERT(!HasStackOverflow()); | 8104 ASSERT(!HasStackOverflow()); |
| 7685 ASSERT(current_block() != NULL); | 8105 ASSERT(current_block() != NULL); |
| 7686 ASSERT(current_block()->HasPredecessor()); | 8106 ASSERT(current_block()->HasPredecessor()); |
| 7687 if (expr->is_jsruntime()) { | 8107 if (expr->is_jsruntime()) { |
| 7688 return Bailout(kCallToAJavaScriptRuntimeFunction); | 8108 return Bailout(kCallToAJavaScriptRuntimeFunction); |
| 7689 } | 8109 } |
| 7690 | 8110 |
| 7691 const Runtime::Function* function = expr->function(); | 8111 const Runtime::Function* function = expr->function(); |
| 7692 ASSERT(function != NULL); | 8112 ASSERT(function != NULL); |
| 8113 |
| 8114 if (function->function_id == Runtime::kDataViewInitialize) { |
| 8115 return VisitDataViewInitialize(expr); |
| 8116 } |
| 8117 |
| 7693 if (function->intrinsic_type == Runtime::INLINE) { | 8118 if (function->intrinsic_type == Runtime::INLINE) { |
| 7694 ASSERT(expr->name()->length() > 0); | 8119 ASSERT(expr->name()->length() > 0); |
| 7695 ASSERT(expr->name()->Get(0) == '_'); | 8120 ASSERT(expr->name()->Get(0) == '_'); |
| 7696 // Call to an inline function. | 8121 // Call to an inline function. |
| 7697 int lookup_index = static_cast<int>(function->function_id) - | 8122 int lookup_index = static_cast<int>(function->function_id) - |
| 7698 static_cast<int>(Runtime::kFirstInlineFunction); | 8123 static_cast<int>(Runtime::kFirstInlineFunction); |
| 7699 ASSERT(lookup_index >= 0); | 8124 ASSERT(lookup_index >= 0); |
| 7700 ASSERT(static_cast<size_t>(lookup_index) < | 8125 ASSERT(static_cast<size_t>(lookup_index) < |
| 7701 ARRAY_SIZE(kInlineFunctionGenerators)); | 8126 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 7702 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 8127 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7837 Representation rep = Representation::FromType(info); | 8262 Representation rep = Representation::FromType(info); |
| 7838 if (rep.IsNone() || rep.IsTagged()) { | 8263 if (rep.IsNone() || rep.IsTagged()) { |
| 7839 rep = Representation::Smi(); | 8264 rep = Representation::Smi(); |
| 7840 } | 8265 } |
| 7841 | 8266 |
| 7842 if (returns_original_input) { | 8267 if (returns_original_input) { |
| 7843 // We need an explicit HValue representing ToNumber(input). The | 8268 // We need an explicit HValue representing ToNumber(input). The |
| 7844 // actual HChange instruction we need is (sometimes) added in a later | 8269 // actual HChange instruction we need is (sometimes) added in a later |
| 7845 // phase, so it is not available now to be used as an input to HAdd and | 8270 // phase, so it is not available now to be used as an input to HAdd and |
| 7846 // as the return value. | 8271 // as the return value. |
| 7847 HInstruction* number_input = Add<HForceRepresentation>(Pop(), rep); | 8272 HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep); |
| 7848 if (!rep.IsDouble()) { | 8273 if (!rep.IsDouble()) { |
| 7849 number_input->SetFlag(HInstruction::kFlexibleRepresentation); | 8274 number_input->SetFlag(HInstruction::kFlexibleRepresentation); |
| 7850 number_input->SetFlag(HInstruction::kCannotBeTagged); | 8275 number_input->SetFlag(HInstruction::kCannotBeTagged); |
| 7851 } | 8276 } |
| 7852 Push(number_input); | 8277 Push(number_input); |
| 7853 } | 8278 } |
| 7854 | 8279 |
| 7855 // The addition has no side effects, so we do not need | 8280 // The addition has no side effects, so we do not need |
| 7856 // to simulate the expression stack after this instruction. | 8281 // to simulate the expression stack after this instruction. |
| 7857 // Any later failures deopt to the load of the input or earlier. | 8282 // Any later failures deopt to the load of the input or earlier. |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8084 return false; | 8509 return false; |
| 8085 } | 8510 } |
| 8086 } | 8511 } |
| 8087 return true; | 8512 return true; |
| 8088 } | 8513 } |
| 8089 | 8514 |
| 8090 | 8515 |
| 8091 HValue* HGraphBuilder::EnforceNumberType(HValue* number, | 8516 HValue* HGraphBuilder::EnforceNumberType(HValue* number, |
| 8092 Handle<Type> expected) { | 8517 Handle<Type> expected) { |
| 8093 if (expected->Is(Type::Smi())) { | 8518 if (expected->Is(Type::Smi())) { |
| 8094 return Add<HForceRepresentation>(number, Representation::Smi()); | 8519 return AddUncasted<HForceRepresentation>(number, Representation::Smi()); |
| 8095 } | 8520 } |
| 8096 if (expected->Is(Type::Signed32())) { | 8521 if (expected->Is(Type::Signed32())) { |
| 8097 return Add<HForceRepresentation>(number, Representation::Integer32()); | 8522 return AddUncasted<HForceRepresentation>(number, |
| 8523 Representation::Integer32()); |
| 8098 } | 8524 } |
| 8099 return number; | 8525 return number; |
| 8100 } | 8526 } |
| 8101 | 8527 |
| 8102 | 8528 |
| 8103 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { | 8529 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { |
| 8104 if (value->IsConstant()) { | 8530 if (value->IsConstant()) { |
| 8105 HConstant* constant = HConstant::cast(value); | 8531 HConstant* constant = HConstant::cast(value); |
| 8106 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); | 8532 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); |
| 8107 if (number.has_value) { | 8533 if (number.has_value) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 8134 // This is already done by HChange. | 8560 // This is already done by HChange. |
| 8135 *expected = handle(Type::Union( | 8561 *expected = handle(Type::Union( |
| 8136 expected_number, handle(Type::Double(), isolate())), isolate()); | 8562 expected_number, handle(Type::Double(), isolate())), isolate()); |
| 8137 return value; | 8563 return value; |
| 8138 } | 8564 } |
| 8139 | 8565 |
| 8140 return value; | 8566 return value; |
| 8141 } | 8567 } |
| 8142 | 8568 |
| 8143 | 8569 |
| 8144 HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( | 8570 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( |
| 8145 BinaryOperation* expr, | 8571 BinaryOperation* expr, |
| 8146 HValue* left, | 8572 HValue* left, |
| 8147 HValue* right) { | 8573 HValue* right) { |
| 8148 Handle<Type> left_type = expr->left()->bounds().lower; | 8574 Handle<Type> left_type = expr->left()->bounds().lower; |
| 8149 Handle<Type> right_type = expr->right()->bounds().lower; | 8575 Handle<Type> right_type = expr->right()->bounds().lower; |
| 8150 Handle<Type> result_type = expr->bounds().lower; | 8576 Handle<Type> result_type = expr->bounds().lower; |
| 8151 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); | 8577 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
| 8152 | 8578 |
| 8153 return HGraphBuilder::BuildBinaryOperation(expr->op(), left, right, | 8579 HValue* result = HGraphBuilder::BuildBinaryOperation( |
| 8154 left_type, right_type, result_type, fixed_right_arg); | 8580 expr->op(), left, right, left_type, right_type, |
| 8581 result_type, fixed_right_arg); |
| 8582 // Add a simulate after instructions with observable side effects, and |
| 8583 // after phis, which are the result of BuildBinaryOperation when we |
| 8584 // inlined some complex subgraph. |
| 8585 if (result->HasObservableSideEffects() || result->IsPhi()) { |
| 8586 Push(result); |
| 8587 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 8588 Drop(1); |
| 8589 } |
| 8590 return result; |
| 8155 } | 8591 } |
| 8156 | 8592 |
| 8157 | 8593 |
| 8158 HInstruction* HGraphBuilder::BuildBinaryOperation( | 8594 HValue* HGraphBuilder::BuildBinaryOperation( |
| 8159 Token::Value op, | 8595 Token::Value op, |
| 8160 HValue* left, | 8596 HValue* left, |
| 8161 HValue* right, | 8597 HValue* right, |
| 8162 Handle<Type> left_type, | 8598 Handle<Type> left_type, |
| 8163 Handle<Type> right_type, | 8599 Handle<Type> right_type, |
| 8164 Handle<Type> result_type, | 8600 Handle<Type> result_type, |
| 8165 Maybe<int> fixed_right_arg, | 8601 Maybe<int> fixed_right_arg) { |
| 8166 bool binop_stub) { | |
| 8167 | 8602 |
| 8168 Representation left_rep = Representation::FromType(left_type); | 8603 Representation left_rep = Representation::FromType(left_type); |
| 8169 Representation right_rep = Representation::FromType(right_type); | 8604 Representation right_rep = Representation::FromType(right_type); |
| 8170 | 8605 |
| 8171 bool maybe_string_add = op == Token::ADD && | 8606 bool maybe_string_add = op == Token::ADD && |
| 8172 (left_type->Maybe(Type::String()) || | 8607 (left_type->Maybe(Type::String()) || |
| 8173 right_type->Maybe(Type::String())); | 8608 right_type->Maybe(Type::String())); |
| 8174 | 8609 |
| 8175 if (left_type->Is(Type::None())) { | 8610 if (left_type->Is(Type::None())) { |
| 8176 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", | 8611 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
| (...skipping 11 matching lines...) Expand all Loading... |
| 8188 Deoptimizer::SOFT); | 8623 Deoptimizer::SOFT); |
| 8189 right_type = handle(Type::Any(), isolate()); | 8624 right_type = handle(Type::Any(), isolate()); |
| 8190 } else { | 8625 } else { |
| 8191 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); | 8626 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); |
| 8192 right_rep = Representation::FromType(right_type); | 8627 right_rep = Representation::FromType(right_type); |
| 8193 } | 8628 } |
| 8194 | 8629 |
| 8195 // Special case for string addition here. | 8630 // Special case for string addition here. |
| 8196 if (op == Token::ADD && | 8631 if (op == Token::ADD && |
| 8197 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { | 8632 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { |
| 8633 // Validate type feedback for left argument. |
| 8198 if (left_type->Is(Type::String())) { | 8634 if (left_type->Is(Type::String())) { |
| 8199 IfBuilder if_isstring(this); | 8635 left = BuildCheckString(left); |
| 8200 if_isstring.If<HIsStringAndBranch>(left); | 8636 } |
| 8201 if_isstring.Then(); | 8637 |
| 8202 if_isstring.ElseDeopt("Expected string for LHS of binary operation"); | 8638 // Validate type feedback for right argument. |
| 8203 } else if (left_type->Is(Type::Number())) { | 8639 if (right_type->Is(Type::String())) { |
| 8640 right = BuildCheckString(right); |
| 8641 } |
| 8642 |
| 8643 // Convert left argument as necessary. |
| 8644 if (left_type->Is(Type::Number())) { |
| 8645 ASSERT(right_type->Is(Type::String())); |
| 8204 left = BuildNumberToString(left, left_type); | 8646 left = BuildNumberToString(left, left_type); |
| 8205 } else { | 8647 } else if (!left_type->Is(Type::String())) { |
| 8206 ASSERT(right_type->Is(Type::String())); | 8648 ASSERT(right_type->Is(Type::String())); |
| 8207 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT); | 8649 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT); |
| 8208 Add<HPushArgument>(left); | 8650 Add<HPushArgument>(left); |
| 8209 Add<HPushArgument>(right); | 8651 Add<HPushArgument>(right); |
| 8210 return NewUncasted<HInvokeFunction>(function, 2); | 8652 return AddUncasted<HInvokeFunction>(function, 2); |
| 8211 } | 8653 } |
| 8212 | 8654 |
| 8213 if (right_type->Is(Type::String())) { | 8655 // Convert right argument as necessary. |
| 8214 IfBuilder if_isstring(this); | 8656 if (right_type->Is(Type::Number())) { |
| 8215 if_isstring.If<HIsStringAndBranch>(right); | 8657 ASSERT(left_type->Is(Type::String())); |
| 8216 if_isstring.Then(); | |
| 8217 if_isstring.ElseDeopt("Expected string for RHS of binary operation"); | |
| 8218 } else if (right_type->Is(Type::Number())) { | |
| 8219 right = BuildNumberToString(right, right_type); | 8658 right = BuildNumberToString(right, right_type); |
| 8220 } else { | 8659 } else if (!right_type->Is(Type::String())) { |
| 8221 ASSERT(left_type->Is(Type::String())); | 8660 ASSERT(left_type->Is(Type::String())); |
| 8222 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); | 8661 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); |
| 8223 Add<HPushArgument>(left); | 8662 Add<HPushArgument>(left); |
| 8224 Add<HPushArgument>(right); | 8663 Add<HPushArgument>(right); |
| 8225 return NewUncasted<HInvokeFunction>(function, 2); | 8664 return AddUncasted<HInvokeFunction>(function, 2); |
| 8226 } | 8665 } |
| 8227 | 8666 |
| 8228 return NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE); | 8667 return AddUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE); |
| 8229 } | 8668 } |
| 8230 | 8669 |
| 8231 if (binop_stub) { | 8670 if (graph()->info()->IsStub()) { |
| 8232 left = EnforceNumberType(left, left_type); | 8671 left = EnforceNumberType(left, left_type); |
| 8233 right = EnforceNumberType(right, right_type); | 8672 right = EnforceNumberType(right, right_type); |
| 8234 } | 8673 } |
| 8235 | 8674 |
| 8236 Representation result_rep = Representation::FromType(result_type); | 8675 Representation result_rep = Representation::FromType(result_type); |
| 8237 | 8676 |
| 8238 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || | 8677 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || |
| 8239 (right_rep.IsTagged() && !right_rep.IsSmi()); | 8678 (right_rep.IsTagged() && !right_rep.IsSmi()); |
| 8240 | 8679 |
| 8241 HInstruction* instr = NULL; | 8680 HInstruction* instr = NULL; |
| 8242 // Only the stub is allowed to call into the runtime, since otherwise we would | 8681 // Only the stub is allowed to call into the runtime, since otherwise we would |
| 8243 // inline several instructions (including the two pushes) for every tagged | 8682 // inline several instructions (including the two pushes) for every tagged |
| 8244 // operation in optimized code, which is more expensive, than a stub call. | 8683 // operation in optimized code, which is more expensive, than a stub call. |
| 8245 if (binop_stub && is_non_primitive) { | 8684 if (graph()->info()->IsStub() && is_non_primitive) { |
| 8246 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op)); | 8685 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op)); |
| 8247 Add<HPushArgument>(left); | 8686 Add<HPushArgument>(left); |
| 8248 Add<HPushArgument>(right); | 8687 Add<HPushArgument>(right); |
| 8249 instr = NewUncasted<HInvokeFunction>(function, 2); | 8688 instr = AddUncasted<HInvokeFunction>(function, 2); |
| 8250 } else { | 8689 } else { |
| 8251 switch (op) { | 8690 switch (op) { |
| 8252 case Token::ADD: | 8691 case Token::ADD: |
| 8253 instr = NewUncasted<HAdd>(left, right); | 8692 instr = AddUncasted<HAdd>(left, right); |
| 8254 break; | 8693 break; |
| 8255 case Token::SUB: | 8694 case Token::SUB: |
| 8256 instr = NewUncasted<HSub>(left, right); | 8695 instr = AddUncasted<HSub>(left, right); |
| 8257 break; | 8696 break; |
| 8258 case Token::MUL: | 8697 case Token::MUL: |
| 8259 instr = NewUncasted<HMul>(left, right); | 8698 instr = AddUncasted<HMul>(left, right); |
| 8260 break; | 8699 break; |
| 8261 case Token::MOD: | 8700 case Token::MOD: { |
| 8262 instr = NewUncasted<HMod>(left, right, fixed_right_arg); | 8701 if (fixed_right_arg.has_value) { |
| 8702 if (right->IsConstant()) { |
| 8703 ASSERT_EQ(fixed_right_arg.value, |
| 8704 HConstant::cast(right)->Integer32Value()); |
| 8705 } else { |
| 8706 HConstant* fixed_right = Add<HConstant>( |
| 8707 static_cast<int>(fixed_right_arg.value)); |
| 8708 IfBuilder if_same(this); |
| 8709 if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ); |
| 8710 if_same.Then(); |
| 8711 if_same.ElseDeopt("Unexpected RHS of binary operation"); |
| 8712 right = fixed_right; |
| 8713 } |
| 8714 } |
| 8715 instr = AddUncasted<HMod>(left, right); |
| 8263 break; | 8716 break; |
| 8717 } |
| 8264 case Token::DIV: | 8718 case Token::DIV: |
| 8265 instr = NewUncasted<HDiv>(left, right); | 8719 instr = AddUncasted<HDiv>(left, right); |
| 8266 break; | 8720 break; |
| 8267 case Token::BIT_XOR: | 8721 case Token::BIT_XOR: |
| 8268 case Token::BIT_AND: | 8722 case Token::BIT_AND: |
| 8269 instr = NewUncasted<HBitwise>(op, left, right); | 8723 instr = AddUncasted<HBitwise>(op, left, right); |
| 8270 break; | 8724 break; |
| 8271 case Token::BIT_OR: { | 8725 case Token::BIT_OR: { |
| 8272 HValue* operand, *shift_amount; | 8726 HValue* operand, *shift_amount; |
| 8273 if (left_type->Is(Type::Signed32()) && | 8727 if (left_type->Is(Type::Signed32()) && |
| 8274 right_type->Is(Type::Signed32()) && | 8728 right_type->Is(Type::Signed32()) && |
| 8275 MatchRotateRight(left, right, &operand, &shift_amount)) { | 8729 MatchRotateRight(left, right, &operand, &shift_amount)) { |
| 8276 instr = NewUncasted<HRor>(operand, shift_amount); | 8730 instr = AddUncasted<HRor>(operand, shift_amount); |
| 8277 } else { | 8731 } else { |
| 8278 instr = NewUncasted<HBitwise>(op, left, right); | 8732 instr = AddUncasted<HBitwise>(op, left, right); |
| 8279 } | 8733 } |
| 8280 break; | 8734 break; |
| 8281 } | 8735 } |
| 8282 case Token::SAR: | 8736 case Token::SAR: |
| 8283 instr = NewUncasted<HSar>(left, right); | 8737 instr = AddUncasted<HSar>(left, right); |
| 8284 break; | 8738 break; |
| 8285 case Token::SHR: | 8739 case Token::SHR: |
| 8286 instr = NewUncasted<HShr>(left, right); | 8740 instr = AddUncasted<HShr>(left, right); |
| 8287 if (FLAG_opt_safe_uint32_operations && instr->IsShr() && | 8741 if (FLAG_opt_safe_uint32_operations && instr->IsShr() && |
| 8288 CanBeZero(right)) { | 8742 CanBeZero(right)) { |
| 8289 graph()->RecordUint32Instruction(instr); | 8743 graph()->RecordUint32Instruction(instr); |
| 8290 } | 8744 } |
| 8291 break; | 8745 break; |
| 8292 case Token::SHL: | 8746 case Token::SHL: |
| 8293 instr = NewUncasted<HShl>(left, right); | 8747 instr = AddUncasted<HShl>(left, right); |
| 8294 break; | 8748 break; |
| 8295 default: | 8749 default: |
| 8296 UNREACHABLE(); | 8750 UNREACHABLE(); |
| 8297 } | 8751 } |
| 8298 } | 8752 } |
| 8299 | 8753 |
| 8300 if (instr->IsBinaryOperation()) { | 8754 if (instr->IsBinaryOperation()) { |
| 8301 HBinaryOperation* binop = HBinaryOperation::cast(instr); | 8755 HBinaryOperation* binop = HBinaryOperation::cast(instr); |
| 8302 binop->set_observed_input_representation(1, left_rep); | 8756 binop->set_observed_input_representation(1, left_rep); |
| 8303 binop->set_observed_input_representation(2, right_rep); | 8757 binop->set_observed_input_representation(2, right_rep); |
| 8304 binop->initialize_output_representation(result_rep); | 8758 binop->initialize_output_representation(result_rep); |
| 8305 if (binop_stub) { | 8759 if (graph()->info()->IsStub()) { |
| 8306 // Stub should not call into stub. | 8760 // Stub should not call into stub. |
| 8307 instr->SetFlag(HValue::kCannotBeTagged); | 8761 instr->SetFlag(HValue::kCannotBeTagged); |
| 8308 // And should truncate on HForceRepresentation already. | 8762 // And should truncate on HForceRepresentation already. |
| 8309 if (left->IsForceRepresentation()) { | 8763 if (left->IsForceRepresentation()) { |
| 8310 left->CopyFlag(HValue::kTruncatingToSmi, instr); | 8764 left->CopyFlag(HValue::kTruncatingToSmi, instr); |
| 8311 left->CopyFlag(HValue::kTruncatingToInt32, instr); | 8765 left->CopyFlag(HValue::kTruncatingToInt32, instr); |
| 8312 } | 8766 } |
| 8313 if (right->IsForceRepresentation()) { | 8767 if (right->IsForceRepresentation()) { |
| 8314 right->CopyFlag(HValue::kTruncatingToSmi, instr); | 8768 right->CopyFlag(HValue::kTruncatingToSmi, instr); |
| 8315 right->CopyFlag(HValue::kTruncatingToInt32, instr); | 8769 right->CopyFlag(HValue::kTruncatingToInt32, instr); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8456 set_current_block(join_block); | 8910 set_current_block(join_block); |
| 8457 // We did not materialize any value in the predecessor environments, | 8911 // We did not materialize any value in the predecessor environments, |
| 8458 // so there is no need to handle it here. | 8912 // so there is no need to handle it here. |
| 8459 } | 8913 } |
| 8460 } | 8914 } |
| 8461 | 8915 |
| 8462 | 8916 |
| 8463 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { | 8917 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { |
| 8464 CHECK_ALIVE(VisitForValue(expr->left())); | 8918 CHECK_ALIVE(VisitForValue(expr->left())); |
| 8465 CHECK_ALIVE(VisitForValue(expr->right())); | 8919 CHECK_ALIVE(VisitForValue(expr->right())); |
| 8466 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 8920 SetSourcePosition(expr->position()); |
| 8467 HValue* right = Pop(); | 8921 HValue* right = Pop(); |
| 8468 HValue* left = Pop(); | 8922 HValue* left = Pop(); |
| 8469 HInstruction* instr = BuildBinaryOperation(expr, left, right); | 8923 HValue* result = BuildBinaryOperation(expr, left, right); |
| 8470 return ast_context()->ReturnInstruction(instr, expr->id()); | 8924 if (FLAG_emit_opt_code_positions && result->IsBinaryOperation()) { |
| 8925 HBinaryOperation::cast(result)->SetOperandPositions( |
| 8926 zone(), expr->left()->position(), expr->right()->position()); |
| 8927 } |
| 8928 return ast_context()->ReturnValue(result); |
| 8471 } | 8929 } |
| 8472 | 8930 |
| 8473 | 8931 |
| 8474 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, | 8932 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, |
| 8475 Expression* sub_expr, | 8933 Expression* sub_expr, |
| 8476 Handle<String> check) { | 8934 Handle<String> check) { |
| 8477 CHECK_ALIVE(VisitForTypeOf(sub_expr)); | 8935 CHECK_ALIVE(VisitForTypeOf(sub_expr)); |
| 8478 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 8936 SetSourcePosition(expr->position()); |
| 8479 HValue* value = Pop(); | 8937 HValue* value = Pop(); |
| 8480 HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check); | 8938 HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check); |
| 8481 return ast_context()->ReturnControl(instr, expr->id()); | 8939 return ast_context()->ReturnControl(instr, expr->id()); |
| 8482 } | 8940 } |
| 8483 | 8941 |
| 8484 | 8942 |
| 8485 static bool IsLiteralCompareBool(Isolate* isolate, | 8943 static bool IsLiteralCompareBool(Isolate* isolate, |
| 8486 HValue* left, | 8944 HValue* left, |
| 8487 Token::Value op, | 8945 Token::Value op, |
| 8488 HValue* right) { | 8946 HValue* right) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8530 Handle<Type> left_type = expr->left()->bounds().lower; | 8988 Handle<Type> left_type = expr->left()->bounds().lower; |
| 8531 Handle<Type> right_type = expr->right()->bounds().lower; | 8989 Handle<Type> right_type = expr->right()->bounds().lower; |
| 8532 Handle<Type> combined_type = expr->combined_type(); | 8990 Handle<Type> combined_type = expr->combined_type(); |
| 8533 Representation combined_rep = Representation::FromType(combined_type); | 8991 Representation combined_rep = Representation::FromType(combined_type); |
| 8534 Representation left_rep = Representation::FromType(left_type); | 8992 Representation left_rep = Representation::FromType(left_type); |
| 8535 Representation right_rep = Representation::FromType(right_type); | 8993 Representation right_rep = Representation::FromType(right_type); |
| 8536 | 8994 |
| 8537 CHECK_ALIVE(VisitForValue(expr->left())); | 8995 CHECK_ALIVE(VisitForValue(expr->left())); |
| 8538 CHECK_ALIVE(VisitForValue(expr->right())); | 8996 CHECK_ALIVE(VisitForValue(expr->right())); |
| 8539 | 8997 |
| 8998 if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 8999 |
| 8540 HValue* right = Pop(); | 9000 HValue* right = Pop(); |
| 8541 HValue* left = Pop(); | 9001 HValue* left = Pop(); |
| 8542 Token::Value op = expr->op(); | 9002 Token::Value op = expr->op(); |
| 8543 | 9003 |
| 8544 if (IsLiteralCompareBool(isolate(), left, op, right)) { | 9004 if (IsLiteralCompareBool(isolate(), left, op, right)) { |
| 8545 HCompareObjectEqAndBranch* result = | 9005 HCompareObjectEqAndBranch* result = |
| 8546 New<HCompareObjectEqAndBranch>(left, right); | 9006 New<HCompareObjectEqAndBranch>(left, right); |
| 8547 return ast_context()->ReturnControl(result, expr->id()); | 9007 return ast_context()->ReturnControl(result, expr->id()); |
| 8548 } | 9008 } |
| 8549 | 9009 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8608 switch (op) { | 9068 switch (op) { |
| 8609 case Token::EQ: | 9069 case Token::EQ: |
| 8610 case Token::EQ_STRICT: { | 9070 case Token::EQ_STRICT: { |
| 8611 // Can we get away with map check and not instance type check? | 9071 // Can we get away with map check and not instance type check? |
| 8612 if (combined_type->IsClass()) { | 9072 if (combined_type->IsClass()) { |
| 8613 Handle<Map> map = combined_type->AsClass(); | 9073 Handle<Map> map = combined_type->AsClass(); |
| 8614 AddCheckMap(left, map); | 9074 AddCheckMap(left, map); |
| 8615 AddCheckMap(right, map); | 9075 AddCheckMap(right, map); |
| 8616 HCompareObjectEqAndBranch* result = | 9076 HCompareObjectEqAndBranch* result = |
| 8617 New<HCompareObjectEqAndBranch>(left, right); | 9077 New<HCompareObjectEqAndBranch>(left, right); |
| 9078 if (FLAG_emit_opt_code_positions) { |
| 9079 result->set_operand_position(zone(), 0, expr->left()->position()); |
| 9080 result->set_operand_position(zone(), 1, expr->right()->position()); |
| 9081 } |
| 8618 return ast_context()->ReturnControl(result, expr->id()); | 9082 return ast_context()->ReturnControl(result, expr->id()); |
| 8619 } else { | 9083 } else { |
| 8620 BuildCheckHeapObject(left); | 9084 BuildCheckHeapObject(left); |
| 8621 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT); | 9085 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT); |
| 8622 BuildCheckHeapObject(right); | 9086 BuildCheckHeapObject(right); |
| 8623 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT); | 9087 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT); |
| 8624 HCompareObjectEqAndBranch* result = | 9088 HCompareObjectEqAndBranch* result = |
| 8625 New<HCompareObjectEqAndBranch>(left, right); | 9089 New<HCompareObjectEqAndBranch>(left, right); |
| 8626 return ast_context()->ReturnControl(result, expr->id()); | 9090 return ast_context()->ReturnControl(result, expr->id()); |
| 8627 } | 9091 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 8649 } else { | 9113 } else { |
| 8650 if (combined_rep.IsTagged() || combined_rep.IsNone()) { | 9114 if (combined_rep.IsTagged() || combined_rep.IsNone()) { |
| 8651 HCompareGeneric* result = New<HCompareGeneric>(left, right, op); | 9115 HCompareGeneric* result = New<HCompareGeneric>(left, right, op); |
| 8652 result->set_observed_input_representation(1, left_rep); | 9116 result->set_observed_input_representation(1, left_rep); |
| 8653 result->set_observed_input_representation(2, right_rep); | 9117 result->set_observed_input_representation(2, right_rep); |
| 8654 return ast_context()->ReturnInstruction(result, expr->id()); | 9118 return ast_context()->ReturnInstruction(result, expr->id()); |
| 8655 } else { | 9119 } else { |
| 8656 HCompareNumericAndBranch* result = | 9120 HCompareNumericAndBranch* result = |
| 8657 New<HCompareNumericAndBranch>(left, right, op); | 9121 New<HCompareNumericAndBranch>(left, right, op); |
| 8658 result->set_observed_input_representation(left_rep, right_rep); | 9122 result->set_observed_input_representation(left_rep, right_rep); |
| 9123 if (FLAG_emit_opt_code_positions) { |
| 9124 result->SetOperandPositions(zone(), |
| 9125 expr->left()->position(), |
| 9126 expr->right()->position()); |
| 9127 } |
| 8659 return ast_context()->ReturnControl(result, expr->id()); | 9128 return ast_context()->ReturnControl(result, expr->id()); |
| 8660 } | 9129 } |
| 8661 } | 9130 } |
| 8662 } | 9131 } |
| 8663 | 9132 |
| 8664 | 9133 |
| 8665 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, | 9134 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
| 8666 Expression* sub_expr, | 9135 Expression* sub_expr, |
| 8667 NilValue nil) { | 9136 NilValue nil) { |
| 8668 ASSERT(!HasStackOverflow()); | 9137 ASSERT(!HasStackOverflow()); |
| (...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9257 | 9726 |
| 9258 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( | 9727 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( |
| 9259 CallRuntime* call) { | 9728 CallRuntime* call) { |
| 9260 ASSERT(call->arguments()->length() == 3); | 9729 ASSERT(call->arguments()->length() == 3); |
| 9261 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9730 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9262 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 9731 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 9263 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); | 9732 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 9264 HValue* value = Pop(); | 9733 HValue* value = Pop(); |
| 9265 HValue* index = Pop(); | 9734 HValue* index = Pop(); |
| 9266 HValue* string = Pop(); | 9735 HValue* string = Pop(); |
| 9267 HSeqStringSetChar* result = New<HSeqStringSetChar>( | 9736 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string, |
| 9268 String::ONE_BYTE_ENCODING, string, index, value); | 9737 index, value); |
| 9269 return ast_context()->ReturnInstruction(result, call->id()); | 9738 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 9739 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 9270 } | 9740 } |
| 9271 | 9741 |
| 9272 | 9742 |
| 9273 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( | 9743 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( |
| 9274 CallRuntime* call) { | 9744 CallRuntime* call) { |
| 9275 ASSERT(call->arguments()->length() == 3); | 9745 ASSERT(call->arguments()->length() == 3); |
| 9276 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9746 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9277 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 9747 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 9278 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); | 9748 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 9279 HValue* value = Pop(); | 9749 HValue* value = Pop(); |
| 9280 HValue* index = Pop(); | 9750 HValue* index = Pop(); |
| 9281 HValue* string = Pop(); | 9751 HValue* string = Pop(); |
| 9282 HSeqStringSetChar* result = New<HSeqStringSetChar>( | 9752 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string, |
| 9283 String::TWO_BYTE_ENCODING, string, index, value); | 9753 index, value); |
| 9284 return ast_context()->ReturnInstruction(result, call->id()); | 9754 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 9755 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 9285 } | 9756 } |
| 9286 | 9757 |
| 9287 | 9758 |
| 9288 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { | 9759 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { |
| 9289 ASSERT(call->arguments()->length() == 2); | 9760 ASSERT(call->arguments()->length() == 2); |
| 9290 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9761 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9291 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 9762 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 9292 HValue* value = Pop(); | 9763 HValue* value = Pop(); |
| 9293 HValue* object = Pop(); | 9764 HValue* object = Pop(); |
| 9294 // Check if object is a not a smi. | 9765 // Check if object is a not a smi. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9368 return ast_context()->ReturnControl(result, call->id()); | 9839 return ast_context()->ReturnControl(result, call->id()); |
| 9369 } | 9840 } |
| 9370 | 9841 |
| 9371 | 9842 |
| 9372 void HOptimizedGraphBuilder::GenerateLog(CallRuntime* call) { | 9843 void HOptimizedGraphBuilder::GenerateLog(CallRuntime* call) { |
| 9373 // %_Log is ignored in optimized code. | 9844 // %_Log is ignored in optimized code. |
| 9374 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 9845 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 9375 } | 9846 } |
| 9376 | 9847 |
| 9377 | 9848 |
| 9378 // Fast support for Math.random(). | |
| 9379 void HOptimizedGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { | |
| 9380 HGlobalObject* global_object = Add<HGlobalObject>(); | |
| 9381 HRandom* result = New<HRandom>(global_object); | |
| 9382 return ast_context()->ReturnInstruction(result, call->id()); | |
| 9383 } | |
| 9384 | |
| 9385 | |
| 9386 // Fast support for StringAdd. | 9849 // Fast support for StringAdd. |
| 9387 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { | 9850 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
| 9388 ASSERT_EQ(2, call->arguments()->length()); | 9851 ASSERT_EQ(2, call->arguments()->length()); |
| 9389 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9852 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9390 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 9853 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 9391 HValue* right = Pop(); | 9854 HValue* right = Pop(); |
| 9392 HValue* left = Pop(); | 9855 HValue* left = Pop(); |
| 9393 HInstruction* result = New<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH); | 9856 HInstruction* result = New<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH); |
| 9394 return ast_context()->ReturnInstruction(result, call->id()); | 9857 return ast_context()->ReturnInstruction(result, call->id()); |
| 9395 } | 9858 } |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9873 } else { | 10336 } else { |
| 9874 CodeStub::Major major_key = info->code_stub()->MajorKey(); | 10337 CodeStub::Major major_key = info->code_stub()->MajorKey(); |
| 9875 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); | 10338 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); |
| 9876 PrintStringProperty("method", "stub"); | 10339 PrintStringProperty("method", "stub"); |
| 9877 } | 10340 } |
| 9878 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); | 10341 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); |
| 9879 } | 10342 } |
| 9880 | 10343 |
| 9881 | 10344 |
| 9882 void HTracer::TraceLithium(const char* name, LChunk* chunk) { | 10345 void HTracer::TraceLithium(const char* name, LChunk* chunk) { |
| 9883 ASSERT(!FLAG_concurrent_recompilation); | 10346 ASSERT(!chunk->isolate()->concurrent_recompilation_enabled()); |
| 9884 AllowHandleDereference allow_deref; | 10347 AllowHandleDereference allow_deref; |
| 9885 AllowDeferredHandleDereference allow_deferred_deref; | 10348 AllowDeferredHandleDereference allow_deferred_deref; |
| 9886 Trace(name, chunk->graph(), chunk); | 10349 Trace(name, chunk->graph(), chunk); |
| 9887 } | 10350 } |
| 9888 | 10351 |
| 9889 | 10352 |
| 9890 void HTracer::TraceHydrogen(const char* name, HGraph* graph) { | 10353 void HTracer::TraceHydrogen(const char* name, HGraph* graph) { |
| 9891 ASSERT(!FLAG_concurrent_recompilation); | 10354 ASSERT(!graph->isolate()->concurrent_recompilation_enabled()); |
| 9892 AllowHandleDereference allow_deref; | 10355 AllowHandleDereference allow_deref; |
| 9893 AllowDeferredHandleDereference allow_deferred_deref; | 10356 AllowDeferredHandleDereference allow_deferred_deref; |
| 9894 Trace(name, graph, NULL); | 10357 Trace(name, graph, NULL); |
| 9895 } | 10358 } |
| 9896 | 10359 |
| 9897 | 10360 |
| 9898 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { | 10361 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { |
| 9899 Tag tag(this, "cfg"); | 10362 Tag tag(this, "cfg"); |
| 9900 PrintStringProperty("name", name); | 10363 PrintStringProperty("name", name); |
| 9901 const ZoneList<HBasicBlock*>* blocks = graph->blocks(); | 10364 const ZoneList<HBasicBlock*>* blocks = graph->blocks(); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9965 trace_.Add(" "); | 10428 trace_.Add(" "); |
| 9966 phi->PrintTo(&trace_); | 10429 phi->PrintTo(&trace_); |
| 9967 trace_.Add("\n"); | 10430 trace_.Add("\n"); |
| 9968 } | 10431 } |
| 9969 } | 10432 } |
| 9970 | 10433 |
| 9971 { | 10434 { |
| 9972 Tag HIR_tag(this, "HIR"); | 10435 Tag HIR_tag(this, "HIR"); |
| 9973 for (HInstructionIterator it(current); !it.Done(); it.Advance()) { | 10436 for (HInstructionIterator it(current); !it.Done(); it.Advance()) { |
| 9974 HInstruction* instruction = it.Current(); | 10437 HInstruction* instruction = it.Current(); |
| 9975 int bci = 0; | 10438 int bci = FLAG_emit_opt_code_positions && instruction->has_position() ? |
| 10439 instruction->position() : 0; |
| 9976 int uses = instruction->UseCount(); | 10440 int uses = instruction->UseCount(); |
| 9977 PrintIndent(); | 10441 PrintIndent(); |
| 9978 trace_.Add("%d %d ", bci, uses); | 10442 trace_.Add("%d %d ", bci, uses); |
| 9979 instruction->PrintNameTo(&trace_); | 10443 instruction->PrintNameTo(&trace_); |
| 9980 trace_.Add(" "); | 10444 trace_.Add(" "); |
| 9981 instruction->PrintTo(&trace_); | 10445 instruction->PrintTo(&trace_); |
| 9982 trace_.Add(" <|@\n"); | 10446 trace_.Add(" <|@\n"); |
| 9983 } | 10447 } |
| 9984 } | 10448 } |
| 9985 | 10449 |
| 9986 | 10450 |
| 9987 if (chunk != NULL) { | 10451 if (chunk != NULL) { |
| 9988 Tag LIR_tag(this, "LIR"); | 10452 Tag LIR_tag(this, "LIR"); |
| 9989 int first_index = current->first_instruction_index(); | 10453 int first_index = current->first_instruction_index(); |
| 9990 int last_index = current->last_instruction_index(); | 10454 int last_index = current->last_instruction_index(); |
| 9991 if (first_index != -1 && last_index != -1) { | 10455 if (first_index != -1 && last_index != -1) { |
| 9992 const ZoneList<LInstruction*>* instructions = chunk->instructions(); | 10456 const ZoneList<LInstruction*>* instructions = chunk->instructions(); |
| 9993 for (int i = first_index; i <= last_index; ++i) { | 10457 for (int i = first_index; i <= last_index; ++i) { |
| 9994 LInstruction* linstr = instructions->at(i); | 10458 LInstruction* linstr = instructions->at(i); |
| 9995 if (linstr != NULL) { | 10459 if (linstr != NULL) { |
| 9996 PrintIndent(); | 10460 PrintIndent(); |
| 9997 trace_.Add("%d ", | 10461 trace_.Add("%d ", |
| 9998 LifetimePosition::FromInstructionIndex(i).Value()); | 10462 LifetimePosition::FromInstructionIndex(i).Value()); |
| 9999 linstr->PrintTo(&trace_); | 10463 linstr->PrintTo(&trace_); |
| 10464 trace_.Add(" [hir:"); |
| 10465 linstr->hydrogen_value()->PrintNameTo(&trace_); |
| 10466 trace_.Add("]"); |
| 10000 trace_.Add(" <|@\n"); | 10467 trace_.Add(" <|@\n"); |
| 10001 } | 10468 } |
| 10002 } | 10469 } |
| 10003 } | 10470 } |
| 10004 } | 10471 } |
| 10005 } | 10472 } |
| 10006 } | 10473 } |
| 10007 | 10474 |
| 10008 | 10475 |
| 10009 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) { | 10476 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10168 if (ShouldProduceTraceOutput()) { | 10635 if (ShouldProduceTraceOutput()) { |
| 10169 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10636 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10170 } | 10637 } |
| 10171 | 10638 |
| 10172 #ifdef DEBUG | 10639 #ifdef DEBUG |
| 10173 graph_->Verify(false); // No full verify. | 10640 graph_->Verify(false); // No full verify. |
| 10174 #endif | 10641 #endif |
| 10175 } | 10642 } |
| 10176 | 10643 |
| 10177 } } // namespace v8::internal | 10644 } } // namespace v8::internal |
| OLD | NEW |