8019835: Strings interned in different threads equal but does not ==

Wed, 18 Sep 2013 07:02:10 -0700

author
dcubed
date
Wed, 18 Sep 2013 07:02:10 -0700
changeset 5743
63147986a428
parent 5686
6f45933aef35
child 5744
dfae98867ee8
child 5746
8c84f04ff977

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

src/share/vm/classfile/javaClasses.cpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/javaClasses.hpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/symbolTable.cpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/symbolTable.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/globals.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/java.cpp file | annotate | diff | comparison | revisions
     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

mercurial