Mercurial > hg > graal-compiler
comparison src/share/vm/opto/library_call.cpp @ 986:62001a362ce9
6827605: new String intrinsics may prevent EA scalar replacement
6875866: Intrinsic for String.indexOf() is broken on x86 with SSE4.2
Summary: Modify String intrinsic methods to pass char[] pointers instead of string oops.
Reviewed-by: never
author | kvn |
---|---|
date | Mon, 14 Sep 2009 12:14:20 -0700 |
parents | c7e94e8fff43 |
children | 39b01ab7035a |
comparison
equal
deleted
inserted
replaced
985:685e959d09ea | 986:62001a362ce9 |
---|---|
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 |
922 _sp += 2; | 1007 _sp += 2; |
923 Node *argument2 = pop(); | 1008 Node *argument2 = pop(); |
924 Node *argument1 = pop(); | 1009 Node *argument1 = pop(); |
925 | 1010 |
926 Node* equals = | 1011 Node* equals = |
927 _gvn.transform(new (C, 3) AryEqNode(control(), | 1012 _gvn.transform(new (C, 4) AryEqNode(control(), memory(TypeAryPtr::CHARS), |
928 argument1, | 1013 argument1, argument2) ); |
929 argument2) | |
930 ); | |
931 push(equals); | 1014 push(equals); |
932 return true; | 1015 return true; |
933 } | 1016 } |
934 | 1017 |
935 // Java version of String.indexOf(constant string) | 1018 // Java version of String.indexOf(constant string) |
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 } |