131 } |
131 } |
132 CallJavaNode* generate_method_call_virtual(vmIntrinsics::ID method_id) { |
132 CallJavaNode* generate_method_call_virtual(vmIntrinsics::ID method_id) { |
133 return generate_method_call(method_id, true, false); |
133 return generate_method_call(method_id, true, false); |
134 } |
134 } |
135 |
135 |
|
136 Node* make_string_method_node(int opcode, Node* str1, Node* cnt1, Node* str2, Node* cnt2); |
136 bool inline_string_compareTo(); |
137 bool inline_string_compareTo(); |
137 bool inline_string_indexOf(); |
138 bool inline_string_indexOf(); |
138 Node* string_indexOf(Node* string_object, ciTypeArray* target_array, jint offset, jint cache_i, jint md2_i); |
139 Node* string_indexOf(Node* string_object, ciTypeArray* target_array, jint offset, jint cache_i, jint md2_i); |
139 bool inline_string_equals(); |
140 bool inline_string_equals(); |
140 Node* pop_math_arg(); |
141 Node* pop_math_arg(); |
794 tls_output = thread; |
795 tls_output = thread; |
795 return threadObj; |
796 return threadObj; |
796 } |
797 } |
797 |
798 |
798 |
799 |
|
800 //------------------------------make_string_method_node------------------------ |
|
801 // Helper method for String intrinsic finctions. |
|
802 Node* LibraryCallKit::make_string_method_node(int opcode, Node* str1, Node* cnt1, Node* str2, Node* cnt2) { |
|
803 const int value_offset = java_lang_String::value_offset_in_bytes(); |
|
804 const int count_offset = java_lang_String::count_offset_in_bytes(); |
|
805 const int offset_offset = java_lang_String::offset_offset_in_bytes(); |
|
806 |
|
807 Node* no_ctrl = NULL; |
|
808 |
|
809 ciInstanceKlass* klass = env()->String_klass(); |
|
810 const TypeInstPtr* string_type = |
|
811 TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); |
|
812 |
|
813 const TypeAryPtr* value_type = |
|
814 TypeAryPtr::make(TypePtr::NotNull, |
|
815 TypeAry::make(TypeInt::CHAR,TypeInt::POS), |
|
816 ciTypeArrayKlass::make(T_CHAR), true, 0); |
|
817 |
|
818 // Get start addr of string and substring |
|
819 Node* str1_valuea = basic_plus_adr(str1, str1, value_offset); |
|
820 Node* str1_value = make_load(no_ctrl, str1_valuea, value_type, T_OBJECT, string_type->add_offset(value_offset)); |
|
821 Node* str1_offseta = basic_plus_adr(str1, str1, offset_offset); |
|
822 Node* str1_offset = make_load(no_ctrl, str1_offseta, TypeInt::INT, T_INT, string_type->add_offset(offset_offset)); |
|
823 Node* str1_start = array_element_address(str1_value, str1_offset, T_CHAR); |
|
824 |
|
825 // Pin loads from String::equals() argument since it could be NULL. |
|
826 Node* str2_ctrl = (opcode == Op_StrEquals) ? control() : no_ctrl; |
|
827 Node* str2_valuea = basic_plus_adr(str2, str2, value_offset); |
|
828 Node* str2_value = make_load(str2_ctrl, str2_valuea, value_type, T_OBJECT, string_type->add_offset(value_offset)); |
|
829 Node* str2_offseta = basic_plus_adr(str2, str2, offset_offset); |
|
830 Node* str2_offset = make_load(str2_ctrl, str2_offseta, TypeInt::INT, T_INT, string_type->add_offset(offset_offset)); |
|
831 Node* str2_start = array_element_address(str2_value, str2_offset, T_CHAR); |
|
832 |
|
833 Node* result = NULL; |
|
834 switch (opcode) { |
|
835 case Op_StrIndexOf: |
|
836 result = new (C, 6) StrIndexOfNode(control(), memory(TypeAryPtr::CHARS), |
|
837 str1_start, cnt1, str2_start, cnt2); |
|
838 break; |
|
839 case Op_StrComp: |
|
840 result = new (C, 6) StrCompNode(control(), memory(TypeAryPtr::CHARS), |
|
841 str1_start, cnt1, str2_start, cnt2); |
|
842 break; |
|
843 case Op_StrEquals: |
|
844 result = new (C, 5) StrEqualsNode(control(), memory(TypeAryPtr::CHARS), |
|
845 str1_start, str2_start, cnt1); |
|
846 break; |
|
847 default: |
|
848 ShouldNotReachHere(); |
|
849 return NULL; |
|
850 } |
|
851 |
|
852 // All these intrinsics have checks. |
|
853 C->set_has_split_ifs(true); // Has chance for split-if optimization |
|
854 |
|
855 return _gvn.transform(result); |
|
856 } |
|
857 |
799 //------------------------------inline_string_compareTo------------------------ |
858 //------------------------------inline_string_compareTo------------------------ |
800 bool LibraryCallKit::inline_string_compareTo() { |
859 bool LibraryCallKit::inline_string_compareTo() { |
801 |
860 |
802 if (!Matcher::has_match_rule(Op_StrComp)) return false; |
861 if (!Matcher::has_match_rule(Op_StrComp)) return false; |
803 |
862 |
822 } |
881 } |
823 |
882 |
824 ciInstanceKlass* klass = env()->String_klass(); |
883 ciInstanceKlass* klass = env()->String_klass(); |
825 const TypeInstPtr* string_type = |
884 const TypeInstPtr* string_type = |
826 TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); |
885 TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); |
827 |
886 Node* no_ctrl = NULL; |
828 Node* compare = |
887 |
829 _gvn.transform(new (C, 7) StrCompNode( |
888 // Get counts for string and argument |
830 control(), |
889 Node* receiver_cnta = basic_plus_adr(receiver, receiver, count_offset); |
831 memory(TypeAryPtr::CHARS), |
890 Node* receiver_cnt = make_load(no_ctrl, receiver_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); |
832 memory(string_type->add_offset(value_offset)), |
891 |
833 memory(string_type->add_offset(count_offset)), |
892 Node* argument_cnta = basic_plus_adr(argument, argument, count_offset); |
834 memory(string_type->add_offset(offset_offset)), |
893 Node* argument_cnt = make_load(no_ctrl, argument_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); |
835 receiver, |
894 |
836 argument)); |
895 Node* compare = make_string_method_node(Op_StrComp, receiver, receiver_cnt, argument, argument_cnt); |
837 push(compare); |
896 push(compare); |
838 return true; |
897 return true; |
839 } |
898 } |
840 |
899 |
841 //------------------------------inline_string_equals------------------------ |
900 //------------------------------inline_string_equals------------------------ |
863 |
922 |
864 if (stopped()) { |
923 if (stopped()) { |
865 return true; |
924 return true; |
866 } |
925 } |
867 |
926 |
|
927 // paths (plus control) merge |
|
928 RegionNode* region = new (C, 5) RegionNode(5); |
|
929 Node* phi = new (C, 5) PhiNode(region, TypeInt::BOOL); |
|
930 |
|
931 // does source == target string? |
|
932 Node* cmp = _gvn.transform(new (C, 3) CmpPNode(receiver, argument)); |
|
933 Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq)); |
|
934 |
|
935 Node* if_eq = generate_slow_guard(bol, NULL); |
|
936 if (if_eq != NULL) { |
|
937 // receiver == argument |
|
938 phi->init_req(2, intcon(1)); |
|
939 region->init_req(2, if_eq); |
|
940 } |
|
941 |
868 // get String klass for instanceOf |
942 // get String klass for instanceOf |
869 ciInstanceKlass* klass = env()->String_klass(); |
943 ciInstanceKlass* klass = env()->String_klass(); |
870 |
944 |
871 // two paths (plus control) merge |
945 if (!stopped()) { |
872 RegionNode* region = new (C, 3) RegionNode(3); |
946 Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass))); |
873 Node* phi = new (C, 3) PhiNode(region, TypeInt::BOOL); |
947 Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1))); |
874 |
948 Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::ne)); |
875 Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass))); |
949 |
876 Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1))); |
950 Node* inst_false = generate_guard(bol, NULL, PROB_MIN); |
877 Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq)); |
951 //instanceOf == true, fallthrough |
878 |
952 |
879 IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); |
953 if (inst_false != NULL) { |
880 |
954 phi->init_req(3, intcon(0)); |
881 Node* if_true = _gvn.transform(new (C, 1) IfTrueNode(iff)); |
955 region->init_req(3, inst_false); |
882 set_control(if_true); |
956 } |
|
957 } |
883 |
958 |
884 const TypeInstPtr* string_type = |
959 const TypeInstPtr* string_type = |
885 TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); |
960 TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); |
886 |
961 |
887 // instanceOf == true |
962 Node* no_ctrl = NULL; |
888 Node* equals = |
963 Node* receiver_cnt; |
889 _gvn.transform(new (C, 7) StrEqualsNode( |
964 Node* argument_cnt; |
890 control(), |
965 |
891 memory(TypeAryPtr::CHARS), |
966 if (!stopped()) { |
892 memory(string_type->add_offset(value_offset)), |
967 // Get counts for string and argument |
893 memory(string_type->add_offset(count_offset)), |
968 Node* receiver_cnta = basic_plus_adr(receiver, receiver, count_offset); |
894 memory(string_type->add_offset(offset_offset)), |
969 receiver_cnt = make_load(no_ctrl, receiver_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); |
895 receiver, |
970 |
896 argument)); |
971 // Pin load from argument string since it could be NULL. |
897 |
972 Node* argument_cnta = basic_plus_adr(argument, argument, count_offset); |
898 phi->init_req(1, _gvn.transform(equals)); |
973 argument_cnt = make_load(control(), argument_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); |
899 region->init_req(1, if_true); |
974 |
900 |
975 // Check for receiver count != argument count |
901 //instanceOf == false, fallthrough |
976 Node* cmp = _gvn.transform( new(C, 3) CmpINode(receiver_cnt, argument_cnt) ); |
902 Node* if_false = _gvn.transform(new (C, 1) IfFalseNode(iff)); |
977 Node* bol = _gvn.transform( new(C, 2) BoolNode(cmp, BoolTest::ne) ); |
903 set_control(if_false); |
978 Node* if_ne = generate_slow_guard(bol, NULL); |
904 |
979 if (if_ne != NULL) { |
905 phi->init_req(2, _gvn.transform(intcon(0))); |
980 phi->init_req(4, intcon(0)); |
906 region->init_req(2, if_false); |
981 region->init_req(4, if_ne); |
|
982 } |
|
983 } |
|
984 |
|
985 // Check for count == 0 is done by mach node StrEquals. |
|
986 |
|
987 if (!stopped()) { |
|
988 Node* equals = make_string_method_node(Op_StrEquals, receiver, receiver_cnt, argument, argument_cnt); |
|
989 phi->init_req(1, equals); |
|
990 region->init_req(1, control()); |
|
991 } |
907 |
992 |
908 // post merge |
993 // post merge |
909 set_control(_gvn.transform(region)); |
994 set_control(_gvn.transform(region)); |
910 record_for_igvn(region); |
995 record_for_igvn(region); |
911 |
996 |
1106 |
1189 |
1107 if (stopped()) { |
1190 if (stopped()) { |
1108 return true; |
1191 return true; |
1109 } |
1192 } |
1110 |
1193 |
|
1194 // Make the merge point |
|
1195 RegionNode* result_rgn = new (C, 3) RegionNode(3); |
|
1196 Node* result_phi = new (C, 3) PhiNode(result_rgn, TypeInt::INT); |
|
1197 Node* no_ctrl = NULL; |
|
1198 |
1111 ciInstanceKlass* klass = env()->String_klass(); |
1199 ciInstanceKlass* klass = env()->String_klass(); |
1112 const TypeInstPtr* string_type = |
1200 const TypeInstPtr* string_type = |
1113 TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); |
1201 TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); |
1114 |
1202 |
1115 result = |
1203 // Get counts for string and substr |
1116 _gvn.transform(new (C, 7) |
1204 Node* source_cnta = basic_plus_adr(receiver, receiver, count_offset); |
1117 StrIndexOfNode(control(), |
1205 Node* source_cnt = make_load(no_ctrl, source_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); |
1118 memory(TypeAryPtr::CHARS), |
1206 |
1119 memory(string_type->add_offset(value_offset)), |
1207 Node* substr_cnta = basic_plus_adr(argument, argument, count_offset); |
1120 memory(string_type->add_offset(count_offset)), |
1208 Node* substr_cnt = make_load(no_ctrl, substr_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); |
1121 memory(string_type->add_offset(offset_offset)), |
1209 |
1122 receiver, |
1210 // Check for substr count > string count |
1123 argument)); |
1211 Node* cmp = _gvn.transform( new(C, 3) CmpINode(substr_cnt, source_cnt) ); |
|
1212 Node* bol = _gvn.transform( new(C, 2) BoolNode(cmp, BoolTest::gt) ); |
|
1213 Node* if_gt = generate_slow_guard(bol, NULL); |
|
1214 if (if_gt != NULL) { |
|
1215 result_phi->init_req(2, intcon(-1)); |
|
1216 result_rgn->init_req(2, if_gt); |
|
1217 } |
|
1218 |
|
1219 if (!stopped()) { |
|
1220 result = make_string_method_node(Op_StrIndexOf, receiver, source_cnt, argument, substr_cnt); |
|
1221 result_phi->init_req(1, result); |
|
1222 result_rgn->init_req(1, control()); |
|
1223 } |
|
1224 set_control(_gvn.transform(result_rgn)); |
|
1225 record_for_igvn(result_rgn); |
|
1226 result = _gvn.transform(result_phi); |
|
1227 |
1124 } else { //Use LibraryCallKit::string_indexOf |
1228 } else { //Use LibraryCallKit::string_indexOf |
1125 // don't intrinsify is argument isn't a constant string. |
1229 // don't intrinsify is argument isn't a constant string. |
1126 if (!argument->is_Con()) { |
1230 if (!argument->is_Con()) { |
1127 return false; |
1231 return false; |
1128 } |
1232 } |