Wed, 18 Sep 2013 07:02:10 -0700
8019835: Strings interned in different threads equal but does not ==
Summary: Add -XX:+VerifyStringTableAtExit option and code to verify StringTable invariants.
Reviewed-by: rdurbin, sspitsyn, coleenp
1.1 --- a/src/share/vm/classfile/javaClasses.cpp Tue Sep 17 20:20:03 2013 +0200 1.2 +++ b/src/share/vm/classfile/javaClasses.cpp Wed Sep 18 07:02:10 2013 -0700 1.3 @@ -438,6 +438,29 @@ 1.4 return true; 1.5 } 1.6 1.7 +bool java_lang_String::equals(oop str1, oop str2) { 1.8 + assert(str1->klass() == SystemDictionary::String_klass(), 1.9 + "must be java String"); 1.10 + assert(str2->klass() == SystemDictionary::String_klass(), 1.11 + "must be java String"); 1.12 + typeArrayOop value1 = java_lang_String::value(str1); 1.13 + int offset1 = java_lang_String::offset(str1); 1.14 + int length1 = java_lang_String::length(str1); 1.15 + typeArrayOop value2 = java_lang_String::value(str2); 1.16 + int offset2 = java_lang_String::offset(str2); 1.17 + int length2 = java_lang_String::length(str2); 1.18 + 1.19 + if (length1 != length2) { 1.20 + return false; 1.21 + } 1.22 + for (int i = 0; i < length1; i++) { 1.23 + if (value1->char_at(i + offset1) != value2->char_at(i + offset2)) { 1.24 + return false; 1.25 + } 1.26 + } 1.27 + return true; 1.28 +} 1.29 + 1.30 void java_lang_String::print(Handle java_string, outputStream* st) { 1.31 oop obj = java_string(); 1.32 assert(obj->klass() == SystemDictionary::String_klass(), "must be java_string");
2.1 --- a/src/share/vm/classfile/javaClasses.hpp Tue Sep 17 20:20:03 2013 +0200 2.2 +++ b/src/share/vm/classfile/javaClasses.hpp Wed Sep 18 07:02:10 2013 -0700 2.3 @@ -182,6 +182,7 @@ 2.4 static unsigned int hash_string(oop java_string); 2.5 2.6 static bool equals(oop java_string, jchar* chars, int len); 2.7 + static bool equals(oop str1, oop str2); 2.8 2.9 // Conversion between '.' and '/' formats 2.10 static Handle externalize_classname(Handle java_string, TRAPS) { return char_converter(java_string, '/', '.', THREAD); }
3.1 --- a/src/share/vm/classfile/symbolTable.cpp Tue Sep 17 20:20:03 2013 +0200 3.2 +++ b/src/share/vm/classfile/symbolTable.cpp Wed Sep 18 07:02:10 2013 -0700 3.3 @@ -807,6 +807,8 @@ 3.4 } 3.5 } 3.6 3.7 +// This verification is part of Universe::verify() and needs to be quick. 3.8 +// See StringTable::verify_and_compare() below for exhaustive verification. 3.9 void StringTable::verify() { 3.10 for (int i = 0; i < the_table()->table_size(); ++i) { 3.11 HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i); 3.12 @@ -825,6 +827,162 @@ 3.13 the_table()->dump_table(st, "StringTable"); 3.14 } 3.15 3.16 +StringTable::VerifyRetTypes StringTable::compare_entries( 3.17 + int bkt1, int e_cnt1, 3.18 + HashtableEntry<oop, mtSymbol>* e_ptr1, 3.19 + int bkt2, int e_cnt2, 3.20 + HashtableEntry<oop, mtSymbol>* e_ptr2) { 3.21 + // These entries are sanity checked by verify_and_compare_entries() 3.22 + // before this function is called. 3.23 + oop str1 = e_ptr1->literal(); 3.24 + oop str2 = e_ptr2->literal(); 3.25 + 3.26 + if (str1 == str2) { 3.27 + tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") " 3.28 + "in entry @ bucket[%d][%d] and entry @ bucket[%d][%d]", 3.29 + str1, bkt1, e_cnt1, bkt2, e_cnt2); 3.30 + return _verify_fail_continue; 3.31 + } 3.32 + 3.33 + if (java_lang_String::equals(str1, str2)) { 3.34 + tty->print_cr("ERROR: identical String values in entry @ " 3.35 + "bucket[%d][%d] and entry @ bucket[%d][%d]", 3.36 + bkt1, e_cnt1, bkt2, e_cnt2); 3.37 + return _verify_fail_continue; 3.38 + } 3.39 + 3.40 + return _verify_pass; 3.41 +} 3.42 + 3.43 +StringTable::VerifyRetTypes StringTable::verify_entry(int bkt, int e_cnt, 3.44 + HashtableEntry<oop, mtSymbol>* e_ptr, 3.45 + StringTable::VerifyMesgModes mesg_mode) { 3.46 + 3.47 + VerifyRetTypes ret = _verify_pass; // be optimistic 3.48 + 3.49 + oop str = e_ptr->literal(); 3.50 + if (str == NULL) { 3.51 + if (mesg_mode == _verify_with_mesgs) { 3.52 + tty->print_cr("ERROR: NULL oop value in entry @ bucket[%d][%d]", bkt, 3.53 + e_cnt); 3.54 + } 3.55 + // NULL oop means no more verifications are possible 3.56 + return _verify_fail_done; 3.57 + } 3.58 + 3.59 + if (str->klass() != SystemDictionary::String_klass()) { 3.60 + if (mesg_mode == _verify_with_mesgs) { 3.61 + tty->print_cr("ERROR: oop is not a String in entry @ bucket[%d][%d]", 3.62 + bkt, e_cnt); 3.63 + } 3.64 + // not a String means no more verifications are possible 3.65 + return _verify_fail_done; 3.66 + } 3.67 + 3.68 + unsigned int h = java_lang_String::hash_string(str); 3.69 + if (e_ptr->hash() != h) { 3.70 + if (mesg_mode == _verify_with_mesgs) { 3.71 + tty->print_cr("ERROR: broken hash value in entry @ bucket[%d][%d], " 3.72 + "bkt_hash=%d, str_hash=%d", bkt, e_cnt, e_ptr->hash(), h); 3.73 + } 3.74 + ret = _verify_fail_continue; 3.75 + } 3.76 + 3.77 + if (the_table()->hash_to_index(h) != bkt) { 3.78 + if (mesg_mode == _verify_with_mesgs) { 3.79 + tty->print_cr("ERROR: wrong index value for entry @ bucket[%d][%d], " 3.80 + "str_hash=%d, hash_to_index=%d", bkt, e_cnt, h, 3.81 + the_table()->hash_to_index(h)); 3.82 + } 3.83 + ret = _verify_fail_continue; 3.84 + } 3.85 + 3.86 + return ret; 3.87 +} 3.88 + 3.89 +// See StringTable::verify() above for the quick verification that is 3.90 +// part of Universe::verify(). This verification is exhaustive and 3.91 +// reports on every issue that is found. StringTable::verify() only 3.92 +// reports on the first issue that is found. 3.93 +// 3.94 +// StringTable::verify_entry() checks: 3.95 +// - oop value != NULL (same as verify()) 3.96 +// - oop value is a String 3.97 +// - hash(String) == hash in entry (same as verify()) 3.98 +// - index for hash == index of entry (same as verify()) 3.99 +// 3.100 +// StringTable::compare_entries() checks: 3.101 +// - oops are unique across all entries 3.102 +// - String values are unique across all entries 3.103 +// 3.104 +int StringTable::verify_and_compare_entries() { 3.105 + assert(StringTable_lock->is_locked(), "sanity check"); 3.106 + 3.107 + int fail_cnt = 0; 3.108 + 3.109 + // first, verify all the entries individually: 3.110 + for (int bkt = 0; bkt < the_table()->table_size(); bkt++) { 3.111 + HashtableEntry<oop, mtSymbol>* e_ptr = the_table()->bucket(bkt); 3.112 + for (int e_cnt = 0; e_ptr != NULL; e_ptr = e_ptr->next(), e_cnt++) { 3.113 + VerifyRetTypes ret = verify_entry(bkt, e_cnt, e_ptr, _verify_with_mesgs); 3.114 + if (ret != _verify_pass) { 3.115 + fail_cnt++; 3.116 + } 3.117 + } 3.118 + } 3.119 + 3.120 + // Optimization: if the above check did not find any failures, then 3.121 + // the comparison loop below does not need to call verify_entry() 3.122 + // before calling compare_entries(). If there were failures, then we 3.123 + // have to call verify_entry() to see if the entry can be passed to 3.124 + // compare_entries() safely. When we call verify_entry() in the loop 3.125 + // below, we do so quietly to void duplicate messages and we don't 3.126 + // increment fail_cnt because the failures have already been counted. 3.127 + bool need_entry_verify = (fail_cnt != 0); 3.128 + 3.129 + // second, verify all entries relative to each other: 3.130 + for (int bkt1 = 0; bkt1 < the_table()->table_size(); bkt1++) { 3.131 + HashtableEntry<oop, mtSymbol>* e_ptr1 = the_table()->bucket(bkt1); 3.132 + for (int e_cnt1 = 0; e_ptr1 != NULL; e_ptr1 = e_ptr1->next(), e_cnt1++) { 3.133 + if (need_entry_verify) { 3.134 + VerifyRetTypes ret = verify_entry(bkt1, e_cnt1, e_ptr1, 3.135 + _verify_quietly); 3.136 + if (ret == _verify_fail_done) { 3.137 + // cannot use the current entry to compare against other entries 3.138 + continue; 3.139 + } 3.140 + } 3.141 + 3.142 + for (int bkt2 = bkt1; bkt2 < the_table()->table_size(); bkt2++) { 3.143 + HashtableEntry<oop, mtSymbol>* e_ptr2 = the_table()->bucket(bkt2); 3.144 + int e_cnt2; 3.145 + for (e_cnt2 = 0; e_ptr2 != NULL; e_ptr2 = e_ptr2->next(), e_cnt2++) { 3.146 + if (bkt1 == bkt2 && e_cnt2 <= e_cnt1) { 3.147 + // skip the entries up to and including the one that 3.148 + // we're comparing against 3.149 + continue; 3.150 + } 3.151 + 3.152 + if (need_entry_verify) { 3.153 + VerifyRetTypes ret = verify_entry(bkt2, e_cnt2, e_ptr2, 3.154 + _verify_quietly); 3.155 + if (ret == _verify_fail_done) { 3.156 + // cannot compare against this entry 3.157 + continue; 3.158 + } 3.159 + } 3.160 + 3.161 + // compare two entries, report and count any failures: 3.162 + if (compare_entries(bkt1, e_cnt1, e_ptr1, bkt2, e_cnt2, e_ptr2) 3.163 + != _verify_pass) { 3.164 + fail_cnt++; 3.165 + } 3.166 + } 3.167 + } 3.168 + } 3.169 + } 3.170 + return fail_cnt; 3.171 +} 3.172 3.173 // Create a new table and using alternate hash code, populate the new table 3.174 // with the existing strings. Set flag to use the alternate hash code afterwards.
4.1 --- a/src/share/vm/classfile/symbolTable.hpp Tue Sep 17 20:20:03 2013 +0200 4.2 +++ b/src/share/vm/classfile/symbolTable.hpp Wed Sep 18 07:02:10 2013 -0700 4.3 @@ -311,6 +311,26 @@ 4.4 static void verify(); 4.5 static void dump(outputStream* st); 4.6 4.7 + enum VerifyMesgModes { 4.8 + _verify_quietly = 0, 4.9 + _verify_with_mesgs = 1 4.10 + }; 4.11 + 4.12 + enum VerifyRetTypes { 4.13 + _verify_pass = 0, 4.14 + _verify_fail_continue = 1, 4.15 + _verify_fail_done = 2 4.16 + }; 4.17 + 4.18 + static VerifyRetTypes compare_entries(int bkt1, int e_cnt1, 4.19 + HashtableEntry<oop, mtSymbol>* e_ptr1, 4.20 + int bkt2, int e_cnt2, 4.21 + HashtableEntry<oop, mtSymbol>* e_ptr2); 4.22 + static VerifyRetTypes verify_entry(int bkt, int e_cnt, 4.23 + HashtableEntry<oop, mtSymbol>* e_ptr, 4.24 + VerifyMesgModes mesg_mode); 4.25 + static int verify_and_compare_entries(); 4.26 + 4.27 // Sharing 4.28 static void copy_buckets(char** top, char*end) { 4.29 the_table()->Hashtable<oop, mtSymbol>::copy_buckets(top, end);
5.1 --- a/src/share/vm/runtime/globals.hpp Tue Sep 17 20:20:03 2013 +0200 5.2 +++ b/src/share/vm/runtime/globals.hpp Wed Sep 18 07:02:10 2013 -0700 5.3 @@ -2525,6 +2525,9 @@ 5.4 product(bool, PrintStringTableStatistics, false, \ 5.5 "print statistics about the StringTable and SymbolTable") \ 5.6 \ 5.7 + diagnostic(bool, VerifyStringTableAtExit, false, \ 5.8 + "verify StringTable contents at exit") \ 5.9 + \ 5.10 notproduct(bool, PrintSymbolTableSizeHistogram, false, \ 5.11 "print histogram of the symbol table") \ 5.12 \
6.1 --- a/src/share/vm/runtime/java.cpp Tue Sep 17 20:20:03 2013 +0200 6.2 +++ b/src/share/vm/runtime/java.cpp Wed Sep 18 07:02:10 2013 -0700 6.3 @@ -544,6 +544,19 @@ 6.4 // it will run into trouble when system destroys static variables. 6.5 MemTracker::shutdown(MemTracker::NMT_normal); 6.6 6.7 + if (VerifyStringTableAtExit) { 6.8 + int fail_cnt = 0; 6.9 + { 6.10 + MutexLocker ml(StringTable_lock); 6.11 + fail_cnt = StringTable::verify_and_compare_entries(); 6.12 + } 6.13 + 6.14 + if (fail_cnt != 0) { 6.15 + tty->print_cr("ERROR: fail_cnt=%d", fail_cnt); 6.16 + guarantee(fail_cnt == 0, "unexpected StringTable verification failures"); 6.17 + } 6.18 + } 6.19 + 6.20 #undef BEFORE_EXIT_NOT_RUN 6.21 #undef BEFORE_EXIT_RUNNING 6.22 #undef BEFORE_EXIT_DONE