summaryrefslogtreecommitdiff
path: root/java/openjdk6/files/icedtea/security/7158800.patch
diff options
context:
space:
mode:
Diffstat (limited to 'java/openjdk6/files/icedtea/security/7158800.patch')
-rw-r--r--java/openjdk6/files/icedtea/security/7158800.patch1413
1 files changed, 0 insertions, 1413 deletions
diff --git a/java/openjdk6/files/icedtea/security/7158800.patch b/java/openjdk6/files/icedtea/security/7158800.patch
deleted file mode 100644
index cf16db2f05b0..000000000000
--- a/java/openjdk6/files/icedtea/security/7158800.patch
+++ /dev/null
@@ -1,1413 +0,0 @@
-# HG changeset patch
-# User kevinw
-# Date 1345802362 -3600
-# Node ID 2faa3f7bad65189e69ab2f9a491743786bb8f07f
-# Parent a080633e3a056dae9e94077c9ac4cf966137ade9
-7158800: Improve storage of symbol tables
-7178670: runtime/7158800/BadUtf8.java fails in SymbolTable::rehash_table
-7181200: JVM new hashing code breaks SA in product mode
-7190262: Debug builds fail to verify String table with +UseCompressedStrings after 7158800
-Reviewed-by: coleenp
-
-diff --git a/src/share/vm/classfile/altHashing.cpp b/src/share/vm/classfile/altHashing.cpp
-new file mode 100644
---- /dev/null
-+++ hotspot/src/share/vm/classfile/altHashing.cpp
-@@ -0,0 +1,304 @@
-+/*
-+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-+ * or visit www.oracle.com if you need additional information or have any
-+ * questions.
-+ *
-+ */
-+
-+#include "precompiled.hpp"
-+#include "classfile/altHashing.hpp"
-+#include "classfile/symbolTable.hpp"
-+#include "classfile/systemDictionary.hpp"
-+#include "oops/markOop.hpp"
-+#include "runtime/thread.hpp"
-+
-+// Get the hash code of the classes mirror if it exists, otherwise just
-+// return a random number, which is one of the possible hash code used for
-+// objects. We don't want to call the synchronizer hash code to install
-+// this value because it may safepoint.
-+intptr_t object_hash(klassOop k) {
-+ intptr_t hc = Klass::cast(k)->java_mirror()->mark()->hash();
-+ return hc != markOopDesc::no_hash ? hc : os::random();
-+}
-+
-+// Seed value used for each alternative hash calculated.
-+jint AltHashing::compute_seed() {
-+ jlong nanos = os::javaTimeNanos();
-+ jlong now = os::javaTimeMillis();
-+ jint SEED_MATERIAL[8] = {
-+ (jint) object_hash(SystemDictionary::String_klass()),
-+ (jint) object_hash(SystemDictionary::System_klass()),
-+ (jint) os::random(), // current thread isn't a java thread
-+ (jint) (((julong)nanos) >> 32),
-+ (jint) nanos,
-+ (jint) (((julong)now) >> 32),
-+ (jint) now,
-+ (jint) (os::javaTimeNanos() >> 2)
-+ };
-+
-+ return murmur3_32(SEED_MATERIAL, 8);
-+}
-+
-+
-+// Murmur3 hashing for Symbol
-+jint AltHashing::murmur3_32(jint seed, const jbyte* data, int len) {
-+ jint h1 = seed;
-+ int count = len;
-+ int offset = 0;
-+
-+ // body
-+ while (count >= 4) {
-+ jint k1 = (data[offset] & 0x0FF)
-+ | (data[offset + 1] & 0x0FF) << 8
-+ | (data[offset + 2] & 0x0FF) << 16
-+ | data[offset + 3] << 24;
-+
-+ count -= 4;
-+ offset += 4;
-+
-+ k1 *= 0xcc9e2d51;
-+ k1 = Integer_rotateLeft(k1, 15);
-+ k1 *= 0x1b873593;
-+
-+ h1 ^= k1;
-+ h1 = Integer_rotateLeft(h1, 13);
-+ h1 = h1 * 5 + 0xe6546b64;
-+ }
-+
-+ // tail
-+
-+ if (count > 0) {
-+ jint k1 = 0;
-+
-+ switch (count) {
-+ case 3:
-+ k1 ^= (data[offset + 2] & 0xff) << 16;
-+ // fall through
-+ case 2:
-+ k1 ^= (data[offset + 1] & 0xff) << 8;
-+ // fall through
-+ case 1:
-+ k1 ^= (data[offset] & 0xff);
-+ // fall through
-+ default:
-+ k1 *= 0xcc9e2d51;
-+ k1 = Integer_rotateLeft(k1, 15);
-+ k1 *= 0x1b873593;
-+ h1 ^= k1;
-+ }
-+ }
-+
-+ // finalization
-+ h1 ^= len;
-+
-+ // finalization mix force all bits of a hash block to avalanche
-+ h1 ^= ((unsigned int)h1) >> 16;
-+ h1 *= 0x85ebca6b;
-+ h1 ^= ((unsigned int)h1) >> 13;
-+ h1 *= 0xc2b2ae35;
-+ h1 ^= ((unsigned int)h1) >> 16;
-+
-+ return h1;
-+}
-+
-+// Murmur3 hashing for Strings
-+jint AltHashing::murmur3_32(jint seed, const jchar* data, int len) {
-+ jint h1 = seed;
-+
-+ int off = 0;
-+ int count = len;
-+
-+ // body
-+ while (count >= 2) {
-+ jchar d1 = data[off++] & 0xFFFF;
-+ jchar d2 = data[off++];
-+ jint k1 = (d1 | d2 << 16);
-+
-+ count -= 2;
-+
-+ k1 *= 0xcc9e2d51;
-+ k1 = Integer_rotateLeft(k1, 15);
-+ k1 *= 0x1b873593;
-+
-+ h1 ^= k1;
-+ h1 = Integer_rotateLeft(h1, 13);
-+ h1 = h1 * 5 + 0xe6546b64;
-+ }
-+
-+ // tail
-+
-+ if (count > 0) {
-+ int k1 = data[off];
-+
-+ k1 *= 0xcc9e2d51;
-+ k1 = Integer_rotateLeft(k1, 15);
-+ k1 *= 0x1b873593;
-+ h1 ^= k1;
-+ }
-+
-+ // finalization
-+ h1 ^= len * 2; // (Character.SIZE / Byte.SIZE);
-+
-+ // finalization mix force all bits of a hash block to avalanche
-+ h1 ^= ((unsigned int)h1) >> 16;
-+ h1 *= 0x85ebca6b;
-+ h1 ^= ((unsigned int)h1) >> 13;
-+ h1 *= 0xc2b2ae35;
-+ h1 ^= ((unsigned int)h1) >> 16;
-+
-+ return h1;
-+}
-+
-+// Hash used for the seed.
-+jint AltHashing::murmur3_32(jint seed, const int* data, int len) {
-+ jint h1 = seed;
-+
-+ int off = 0;
-+ int end = len;
-+
-+ // body
-+ while (off < end) {
-+ jint k1 = data[off++];
-+
-+ k1 *= 0xcc9e2d51;
-+ k1 = Integer_rotateLeft(k1, 15);
-+ k1 *= 0x1b873593;
-+
-+ h1 ^= k1;
-+ h1 = Integer_rotateLeft(h1, 13);
-+ h1 = h1 * 5 + 0xe6546b64;
-+ }
-+
-+ // tail (always empty, as body is always 32-bit chunks)
-+
-+ // finalization
-+
-+ h1 ^= len * 4; // (Integer.SIZE / Byte.SIZE);
-+
-+ // finalization mix force all bits of a hash block to avalanche
-+ h1 ^= ((juint)h1) >> 16;
-+ h1 *= 0x85ebca6b;
-+ h1 ^= ((juint)h1) >> 13;
-+ h1 *= 0xc2b2ae35;
-+ h1 ^= ((juint)h1) >> 16;
-+
-+ return h1;
-+}
-+
-+jint AltHashing::murmur3_32(const int* data, int len) {
-+ return murmur3_32(0, data, len);
-+}
-+
-+#ifndef PRODUCT
-+// Overloaded versions for internal test.
-+jint AltHashing::murmur3_32(const jbyte* data, int len) {
-+ return murmur3_32(0, data, len);
-+}
-+
-+jint AltHashing::murmur3_32(const jchar* data, int len) {
-+ return murmur3_32(0, data, len);
-+}
-+
-+// Internal test for alternate hashing. Translated from JDK version
-+// test/sun/misc/Hashing.java
-+static const jbyte ONE_BYTE[] = { (jbyte) 0x80};
-+static const jbyte TWO_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81};
-+static const jchar ONE_CHAR[] = { (jchar) 0x8180};
-+static const jbyte THREE_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82};
-+static const jbyte FOUR_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83};
-+static const jchar TWO_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382};
-+static const jint ONE_INT[] = { 0x83828180};
-+static const jbyte SIX_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85};
-+static const jchar THREE_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8584};
-+static const jbyte EIGHT_BYTE[] = {
-+ (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82,
-+ (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85,
-+ (jbyte) 0x86, (jbyte) 0x87};
-+static const jchar FOUR_CHAR[] = {
-+ (jchar) 0x8180, (jchar) 0x8382,
-+ (jchar) 0x8584, (jchar) 0x8786};
-+
-+static const jint TWO_INT[] = { 0x83828180, 0x87868584};
-+
-+static const juint MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3;
-+
-+void AltHashing::testMurmur3_32_ByteArray() {
-+ // printf("testMurmur3_32_ByteArray\n");
-+
-+ jbyte* vector = new jbyte[256];
-+ jbyte* hashes = new jbyte[4 * 256];
-+
-+ for (int i = 0; i < 256; i++) {
-+ vector[i] = (jbyte) i;
-+ }
-+
-+ // Hash subranges {}, {0}, {0,1}, {0,1,2}, ..., {0,...,255}
-+ for (int i = 0; i < 256; i++) {
-+ jint hash = murmur3_32(256 - i, vector, i);
-+ hashes[i * 4] = (jbyte) hash;
-+ hashes[i * 4 + 1] = (jbyte) (((juint)hash) >> 8);
-+ hashes[i * 4 + 2] = (jbyte) (((juint)hash) >> 16);
-+ hashes[i * 4 + 3] = (jbyte) (((juint)hash) >> 24);
-+ }
-+
-+ // hash to get const result.
-+ juint final_hash = murmur3_32(hashes, 4*256);
-+
-+ assert (MURMUR3_32_X86_CHECK_VALUE == final_hash,
-+ err_msg(
-+ "Calculated hash result not as expected. Expected %08X got %08X\n",
-+ MURMUR3_32_X86_CHECK_VALUE,
-+ final_hash));
-+}
-+
-+void AltHashing::testEquivalentHashes() {
-+ jint jbytes, jchars, ints;
-+
-+ // printf("testEquivalentHashes\n");
-+
-+ jbytes = murmur3_32(TWO_BYTE, 2);
-+ jchars = murmur3_32(ONE_CHAR, 1);
-+ assert (jbytes == jchars,
-+ err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars));
-+
-+ jbytes = murmur3_32(FOUR_BYTE, 4);
-+ jchars = murmur3_32(TWO_CHAR, 2);
-+ ints = murmur3_32(ONE_INT, 1);
-+ assert ((jbytes == jchars) && (jbytes == ints),
-+ err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints));
-+
-+ jbytes = murmur3_32(SIX_BYTE, 6);
-+ jchars = murmur3_32(THREE_CHAR, 3);
-+ assert (jbytes == jchars,
-+ err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars));
-+
-+ jbytes = murmur3_32(EIGHT_BYTE, 8);
-+ jchars = murmur3_32(FOUR_CHAR, 4);
-+ ints = murmur3_32(TWO_INT, 2);
-+ assert ((jbytes == jchars) && (jbytes == ints),
-+ err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints));
-+}
-+
-+// Returns true if the alternate hashcode is correct
-+void AltHashing::test_alt_hash() {
-+ testMurmur3_32_ByteArray();
-+ testEquivalentHashes();
-+}
-+#endif // PRODUCT
-diff --git a/src/share/vm/classfile/altHashing.hpp b/src/share/vm/classfile/altHashing.hpp
-new file mode 100644
---- /dev/null
-+++ hotspot/src/share/vm/classfile/altHashing.hpp
-@@ -0,0 +1,62 @@
-+/*
-+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-+ * or visit www.oracle.com if you need additional information or have any
-+ * questions.
-+ *
-+ */
-+
-+#ifndef SHARE_VM_CLASSFILE_ALTHASHING_HPP
-+#define SHARE_VM_CLASSFILE_ALTHASHING_HPP
-+
-+#include "prims/jni.h"
-+#include "classfile/symbolTable.hpp"
-+
-+/**
-+ * Hashing utilities.
-+ *
-+ * Implementation of Murmur3 hashing.
-+ * This code was translated from src/share/classes/sun/misc/Hashing.java
-+ * code in the JDK.
-+ */
-+
-+class AltHashing : AllStatic {
-+
-+ // utility function copied from java/lang/Integer
-+ static jint Integer_rotateLeft(jint i, int distance) {
-+ return (i << distance) | (((juint)i) >> (32-distance));
-+ }
-+ static jint murmur3_32(const int* data, int len);
-+ static jint murmur3_32(jint seed, const int* data, int len);
-+
-+#ifndef PRODUCT
-+ // Hashing functions used for internal testing
-+ static jint murmur3_32(const jbyte* data, int len);
-+ static jint murmur3_32(const jchar* data, int len);
-+ static void testMurmur3_32_ByteArray();
-+ static void testEquivalentHashes();
-+#endif // PRODUCT
-+
-+ public:
-+ static jint compute_seed();
-+ static jint murmur3_32(jint seed, const jbyte* data, int len);
-+ static jint murmur3_32(jint seed, const jchar* data, int len);
-+ NOT_PRODUCT(static void test_alt_hash();)
-+};
-+#endif // SHARE_VM_CLASSFILE_ALTHASHING_HPP
-diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp
---- hotspot/src/share/vm/classfile/javaClasses.cpp
-+++ hotspot/src/share/vm/classfile/javaClasses.cpp
-@@ -278,6 +278,28 @@
- return result;
- }
-
-+unsigned int java_lang_String::to_hash(oop java_string) {
-+ int length = java_lang_String::length(java_string);
-+ // Zero length string will hash to zero with String.toHash() function.
-+ if (length == 0) return 0;
-+
-+ typeArrayOop value = java_lang_String::value(java_string);
-+ int offset = java_lang_String::offset(java_string);
-+ return java_lang_String::to_hash(value->char_at_addr(offset), length);
-+}
-+
-+unsigned int java_lang_String::hash_string(oop java_string) {
-+ int length = java_lang_String::length(java_string);
-+ // Zero length string doesn't hash necessarily hash to zero.
-+ if (length == 0) {
-+ return StringTable::hash_string(NULL, 0);
-+ }
-+
-+ typeArrayOop value = java_lang_String::value(java_string);
-+ int offset = java_lang_String::offset(java_string);
-+ return StringTable::hash_string(value->char_at_addr(offset), length);
-+}
-+
- symbolHandle java_lang_String::as_symbol(Handle java_string, TRAPS) {
- oop obj = java_string();
- typeArrayOop value = java_lang_String::value(obj);
-diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
---- hotspot/src/share/vm/classfile/javaClasses.hpp
-+++ hotspot/src/share/vm/classfile/javaClasses.hpp
-@@ -109,6 +109,30 @@
- static char* as_platform_dependent_str(Handle java_string, TRAPS);
- static jchar* as_unicode_string(oop java_string, int& length);
-
-+ // Compute the hash value for a java.lang.String object which would
-+ // contain the characters passed in.
-+ //
-+ // As the hash value used by the String object itself, in
-+ // String.hashCode(). This value is normally calculated in Java code
-+ // in the String.hashCode method(), but is precomputed for String
-+ // objects in the shared archive file.
-+ // hash P(31) from Kernighan & Ritchie
-+ //
-+ // For this reason, THIS ALGORITHM MUST MATCH String.toHash().
-+ template <typename T> static unsigned int to_hash(T* s, int len) {
-+ unsigned int h = 0;
-+ while (len-- > 0) {
-+ h = 31*h + (unsigned int) *s;
-+ s++;
-+ }
-+ return h;
-+ }
-+ static unsigned int to_hash(oop java_string);
-+
-+ // This is the string hash code used by the StringTable, which may be
-+ // the same as String.toHash or an alternate hash code.
-+ static unsigned int hash_string(oop java_string);
-+
- static bool equals(oop java_string, jchar* chars, int len);
-
- // Conversion between '.' and '/' formats
-diff --git a/src/share/vm/classfile/symbolTable.cpp b/src/share/vm/classfile/symbolTable.cpp
---- hotspot/src/share/vm/classfile/symbolTable.cpp
-+++ hotspot/src/share/vm/classfile/symbolTable.cpp
-@@ -23,6 +23,7 @@
- */
-
- #include "precompiled.hpp"
-+#include "classfile/altHashing.hpp"
- #include "classfile/javaClasses.hpp"
- #include "classfile/symbolTable.hpp"
- #include "classfile/systemDictionary.hpp"
-@@ -34,16 +35,40 @@
- #include "oops/symbolKlass.hpp"
- #include "runtime/mutexLocker.hpp"
- #include "utilities/hashtable.inline.hpp"
-+#include "utilities/numberSeq.hpp"
-
- // --------------------------------------------------------------------------
-
- SymbolTable* SymbolTable::_the_table = NULL;
-+bool SymbolTable::_needs_rehashing = false;
-+
-+// Create a new table and using alternate hash code, populate the new table
-+// with the existing strings. Set flag to use the alternate hash code afterwards.
-+void SymbolTable::rehash_table() {
-+
-+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
-+ // This should never happen with -Xshare:dump but it might in testing mode.
-+ if (DumpSharedSpaces) return;
-+ // Create a new symbol table
-+ SymbolTable* new_table = new SymbolTable();
-+
-+ the_table()->move_to(new_table);
-+
-+ // Delete the table and buckets (entries are reused in new table).
-+ delete _the_table;
-+ // Don't check if we need rehashing until the table gets unbalanced again.
-+ // Then rehash with a new global seed.
-+ _needs_rehashing = false;
-+ _the_table = new_table;
-+}
-
- // Lookup a symbol in a bucket.
-
- symbolOop SymbolTable::lookup(int index, const char* name,
- int len, unsigned int hash) {
-+ int count = 0;
- for (HashtableEntry* e = bucket(index); e != NULL; e = e->next()) {
-+ count++;
- if (e->hash() == hash) {
- symbolOop sym = symbolOop(e->literal());
- if (sym->equals(name, len)) {
-@@ -51,9 +76,20 @@
- }
- }
- }
-+ // If the bucket size is too deep check if this hash code is insufficient.
-+ if (count >= BasicHashtable::rehash_count && !needs_rehashing()) {
-+ _needs_rehashing = check_rehash_table(count);
-+ }
- return NULL;
- }
-
-+// Pick hashing algorithm.
-+unsigned int SymbolTable::hash_symbol(const char* s, int len) {
-+ return the_table()->use_alternate_hashcode() ?
-+ AltHashing::murmur3_32(the_table()->seed(), (const jbyte*)s, len) :
-+ java_lang_String::to_hash(s, len);
-+}
-+
-
- // We take care not to be blocking while holding the
- // SymbolTable_lock. Otherwise, the system might deadlock, since the
-@@ -71,8 +107,17 @@
- // Found
- if (s != NULL) return s;
-
-+ // We assume that lookup() has been called already, that it failed,
-+ // and symbol was not found. We create the symbol here.
-+ symbolKlass* sk = (symbolKlass*) Universe::symbolKlassObj()->klass_part();
-+ symbolOop s_oop = sk->allocate_symbol((u1*)name, len, CHECK_NULL);
-+ symbolHandle sym (THREAD, s_oop);
-+
-+ // Allocation must be done before grabbing the SymbolTable_lock lock
-+ MutexLocker ml(SymbolTable_lock, THREAD);
-+
- // Otherwise, add to symbol to table
-- return the_table()->basic_add(index, (u1*)name, len, hashValue, CHECK_NULL);
-+ return the_table()->basic_add(sym, index, (u1*)name, len, hashValue, CHECK_NULL);
- }
-
- symbolOop SymbolTable::lookup(symbolHandle sym, int begin, int end, TRAPS) {
-@@ -108,7 +153,16 @@
- // We can't include the code in No_Safepoint_Verifier because of the
- // ResourceMark.
-
-- return the_table()->basic_add(index, (u1*)buffer, len, hashValue, CHECK_NULL);
-+ // We assume that lookup() has been called already, that it failed,
-+ // and symbol was not found. We create the symbol here.
-+ symbolKlass* sk = (symbolKlass*) Universe::symbolKlassObj()->klass_part();
-+ symbolOop s_oop = sk->allocate_symbol((u1*)buffer, len, CHECK_NULL);
-+ symbolHandle newsym (THREAD, s_oop);
-+
-+ // Allocation must be done before grabbing the SymbolTable_lock lock
-+ MutexLocker ml(SymbolTable_lock, THREAD);
-+
-+ return the_table()->basic_add(newsym, index, (u1*)buffer, len, hashValue, CHECK_NULL);
- }
-
- symbolOop SymbolTable::lookup_only(const char* name, int len,
-@@ -156,36 +210,68 @@
- void SymbolTable::add(constantPoolHandle cp, int names_count,
- const char** names, int* lengths, int* cp_indices,
- unsigned int* hashValues, TRAPS) {
-- SymbolTable* table = the_table();
-- bool added = table->basic_add(cp, names_count, names, lengths,
-- cp_indices, hashValues, CHECK);
-- if (!added) {
-+
-+ symbolKlass* sk = (symbolKlass*) Universe::symbolKlassObj()->klass_part();
-+ symbolOop sym_oops[symbol_alloc_batch_size];
-+ bool allocated = sk->allocate_symbols(names_count, names, lengths,
-+ sym_oops, CHECK);
-+ if (!allocated) {
- // do it the hard way
- for (int i=0; i<names_count; i++) {
-+ assert(!Universe::heap()->is_in_reserved(names[i]) || GC_locker::is_active(),
-+ "proposed name of symbol must be stable");
-+
-+ // We assume that lookup() has been called already, that it failed,
-+ // and symbol was not found. We create the symbol here.
-+ symbolKlass* sk = (symbolKlass*) Universe::symbolKlassObj()->klass_part();
-+ symbolOop s_oop = sk->allocate_symbol((u1*)names[i], lengths[i], CHECK);
-+ symbolHandle sym (THREAD, s_oop);
-+
-+ // Allocation must be done before grabbing the SymbolTable_lock lock
-+ MutexLocker ml(SymbolTable_lock, THREAD);
-+
-+ SymbolTable* table = the_table();
- int index = table->hash_to_index(hashValues[i]);
-- symbolOop sym = table->basic_add(index, (u1*)names[i], lengths[i],
-+ symbolOop s = table->basic_add(sym, index, (u1*)names[i], lengths[i],
- hashValues[i], CHECK);
-- cp->symbol_at_put(cp_indices[i], sym);
-+ cp->symbol_at_put(cp_indices[i], s);
- }
-+ return;
- }
-+
-+ symbolHandle syms[symbol_alloc_batch_size];
-+ for (int i=0; i<names_count; i++) {
-+ syms[i] = symbolHandle(THREAD, sym_oops[i]);
-+ }
-+
-+ // Allocation must be done before grabbing the SymbolTable_lock lock
-+ MutexLocker ml(SymbolTable_lock, THREAD);
-+
-+ SymbolTable* table = the_table();
-+ bool added = table->basic_add(syms, cp, names_count, names, lengths,
-+ cp_indices, hashValues, CHECK);
-+ assert(added, "should always return true");
- }
-
--symbolOop SymbolTable::basic_add(int index, u1 *name, int len,
-- unsigned int hashValue, TRAPS) {
-- assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
-- "proposed name of symbol must be stable");
--
-- // We assume that lookup() has been called already, that it failed,
-- // and symbol was not found. We create the symbol here.
-- symbolKlass* sk = (symbolKlass*) Universe::symbolKlassObj()->klass_part();
-- symbolOop s_oop = sk->allocate_symbol(name, len, CHECK_NULL);
-- symbolHandle sym (THREAD, s_oop);
--
-- // Allocation must be done before grapping the SymbolTable_lock lock
-- MutexLocker ml(SymbolTable_lock, THREAD);
-+symbolOop SymbolTable::basic_add(symbolHandle sym, int index_arg, u1 *name, int len,
-+ unsigned int hashValue_arg, TRAPS) {
-+ // Cannot hit a safepoint in this function because the "this" pointer can move.
-+ No_Safepoint_Verifier nsv;
-
- assert(sym->equals((char*)name, len), "symbol must be properly initialized");
-
-+ // Check if the symbol table has been rehashed, if so, need to recalculate
-+ // the hash value and index.
-+ unsigned int hashValue;
-+ int index;
-+ if (use_alternate_hashcode()) {
-+ hashValue = hash_symbol((const char*)name, len);
-+ index = hash_to_index(hashValue);
-+ } else {
-+ hashValue = hashValue_arg;
-+ index = index_arg;
-+ }
-+
- // Since look-up was done lock-free, we need to check if another
- // thread beat us in the race to insert the symbol.
-
-@@ -201,48 +287,42 @@
- return sym();
- }
-
--bool SymbolTable::basic_add(constantPoolHandle cp, int names_count,
-+bool SymbolTable::basic_add(symbolHandle* syms,
-+ constantPoolHandle cp, int names_count,
- const char** names, int* lengths,
- int* cp_indices, unsigned int* hashValues,
- TRAPS) {
-- symbolKlass* sk = (symbolKlass*) Universe::symbolKlassObj()->klass_part();
-- symbolOop sym_oops[symbol_alloc_batch_size];
-- bool allocated = sk->allocate_symbols(names_count, names, lengths,
-- sym_oops, CHECK_false);
-- if (!allocated) {
-- return false;
-- }
-- symbolHandle syms[symbol_alloc_batch_size];
-- int i;
-- for (i=0; i<names_count; i++) {
-- syms[i] = symbolHandle(THREAD, sym_oops[i]);
-- }
-+ // Cannot hit a safepoint in this function because the "this" pointer can move.
-+ No_Safepoint_Verifier nsv;
-
-- // Allocation must be done before grabbing the SymbolTable_lock lock
-- MutexLocker ml(SymbolTable_lock, THREAD);
--
-- for (i=0; i<names_count; i++) {
-+ for (int i=0; i<names_count; i++) {
- assert(syms[i]->equals(names[i], lengths[i]), "symbol must be properly initialized");
-+ // Check if the symbol table has been rehashed, if so, need to recalculate
-+ // the hash value.
-+ unsigned int hashValue;
-+ if (use_alternate_hashcode()) {
-+ hashValue = hash_symbol(names[i], lengths[i]);
-+ } else {
-+ hashValue = hashValues[i];
-+ }
- // Since look-up was done lock-free, we need to check if another
- // thread beat us in the race to insert the symbol.
-- int index = hash_to_index(hashValues[i]);
-- symbolOop test = lookup(index, names[i], lengths[i], hashValues[i]);
-+ int index = hash_to_index(hashValue);
-+ symbolOop test = lookup(index, names[i], lengths[i], hashValue);
- if (test != NULL) {
- // A race occurred and another thread introduced the symbol, this one
- // will be dropped and collected. Use test instead.
- cp->symbol_at_put(cp_indices[i], test);
- } else {
- symbolOop sym = syms[i]();
-- HashtableEntry* entry = new_entry(hashValues[i], sym);
-+ HashtableEntry* entry = new_entry(hashValue, sym);
- add_entry(index, entry);
- cp->symbol_at_put(cp_indices[i], sym);
- }
- }
--
-- return true;
-+ return true; // always returns true
- }
-
--
- void SymbolTable::verify() {
- for (int i = 0; i < the_table()->table_size(); ++i) {
- HashtableEntry* p = the_table()->bucket(i);
-@@ -251,7 +331,7 @@
- guarantee(s != NULL, "symbol is NULL");
- s->verify();
- guarantee(s->is_perm(), "symbol not in permspace");
-- unsigned int h = hash_symbol((char*)s->bytes(), s->utf8_length());
-+ unsigned int h = hash_symbol((const char*)s->bytes(), s->utf8_length());
- guarantee(p->hash() == h, "broken hash in symbol table entry");
- guarantee(the_table()->hash_to_index(h) == i,
- "wrong index in symbol table");
-@@ -259,6 +339,23 @@
- }
- }
-
-+void SymbolTable::dump(outputStream* st) {
-+ NumberSeq summary;
-+ for (int i = 0; i < the_table()->table_size(); ++i) {
-+ int count = 0;
-+ for (HashtableEntry* e = the_table()->bucket(i);
-+ e != NULL; e = e->next()) {
-+ count++;
-+ }
-+ summary.add((double)count);
-+ }
-+ st->print_cr("SymbolTable statistics:");
-+ st->print_cr("Number of buckets : %7d", summary.num());
-+ st->print_cr("Average bucket size : %7.0f", summary.avg());
-+ st->print_cr("Variance of bucket size : %7.0f", summary.variance());
-+ st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd());
-+ st->print_cr("Maximum bucket size : %7.0f", summary.maximum());
-+}
-
- //---------------------------------------------------------------------------
- // Non-product code
-@@ -321,7 +418,6 @@
- tty->print_cr(" %s %d: %d\n", "Number chains longer than",
- results_length, out_of_range);
- }
--
- #endif // PRODUCT
-
- // --------------------------------------------------------------------------
-@@ -367,66 +463,56 @@
- // --------------------------------------------------------------------------
-
-
--// Compute the hash value for a java.lang.String object which would
--// contain the characters passed in. This hash value is used for at
--// least two purposes.
--//
--// (a) As the hash value used by the StringTable for bucket selection
--// and comparison (stored in the HashtableEntry structures). This
--// is used in the String.intern() method.
--//
--// (b) As the hash value used by the String object itself, in
--// String.hashCode(). This value is normally calculate in Java code
--// in the String.hashCode method(), but is precomputed for String
--// objects in the shared archive file.
--//
--// For this reason, THIS ALGORITHM MUST MATCH String.hashCode().
-+StringTable* StringTable::_the_table = NULL;
-
--int StringTable::hash_string(jchar* s, int len) {
-- unsigned h = 0;
-- while (len-- > 0) {
-- h = 31*h + (unsigned) *s;
-- s++;
-- }
-- return h;
-+bool StringTable::_needs_rehashing = false;
-+
-+// Pick hashing algorithm
-+unsigned int StringTable::hash_string(const jchar* s, int len) {
-+ return the_table()->use_alternate_hashcode() ? AltHashing::murmur3_32(the_table()->seed(), s, len) :
-+ java_lang_String::to_hash(s, len);
- }
-
--
--StringTable* StringTable::_the_table = NULL;
--
- oop StringTable::lookup(int index, jchar* name,
- int len, unsigned int hash) {
-+ int count = 0;
- for (HashtableEntry* l = bucket(index); l != NULL; l = l->next()) {
-+ count++;
- if (l->hash() == hash) {
- if (java_lang_String::equals(l->literal(), name, len)) {
- return l->literal();
- }
- }
- }
-+ // If the bucket size is too deep check if this hash code is insufficient.
-+ if (count >= BasicHashtable::rehash_count && !needs_rehashing()) {
-+ _needs_rehashing = check_rehash_table(count);
-+ }
- return NULL;
- }
-
-
--oop StringTable::basic_add(int index, Handle string_or_null, jchar* name,
-- int len, unsigned int hashValue, TRAPS) {
-- debug_only(StableMemoryChecker smc(name, len * sizeof(name[0])));
-- assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
-- "proposed name of symbol must be stable");
-+oop StringTable::basic_add(int index_arg, Handle string, jchar* name,
-+ int len, unsigned int hashValue_arg, TRAPS) {
-
-- Handle string;
-- // try to reuse the string if possible
-- if (!string_or_null.is_null() && string_or_null()->is_perm()) {
-- string = string_or_null;
-- } else {
-- string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL);
-- }
--
-- // Allocation must be done before grapping the SymbolTable_lock lock
-- MutexLocker ml(StringTable_lock, THREAD);
-+ // Cannot hit a safepoint in this function because the "this" pointer can move.
-+ No_Safepoint_Verifier nsv;
-
- assert(java_lang_String::equals(string(), name, len),
- "string must be properly initialized");
-
-+ // Check if the symbol table has been rehashed, if so, need to recalculate
-+ // the hash value and index before second lookup.
-+ unsigned int hashValue;
-+ int index;
-+ if (use_alternate_hashcode()) {
-+ hashValue = hash_string(name, len);
-+ index = hash_to_index(hashValue);
-+ } else {
-+ hashValue = hashValue_arg;
-+ index = index_arg;
-+ }
-+
- // Since look-up was done lock-free, we need to check if another
- // thread beat us in the race to insert the symbol.
-
-@@ -456,13 +542,28 @@
- int len, TRAPS) {
- unsigned int hashValue = hash_string(name, len);
- int index = the_table()->hash_to_index(hashValue);
-- oop string = the_table()->lookup(index, name, len, hashValue);
-+ oop found_string = the_table()->lookup(index, name, len, hashValue);
-
- // Found
-- if (string != NULL) return string;
-+ if (found_string != NULL) return found_string;
-+
-+ debug_only(StableMemoryChecker smc(name, len * sizeof(name[0])));
-+ assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
-+ "proposed name of symbol must be stable");
-+
-+ Handle string;
-+ // try to reuse the string if possible
-+ if (!string_or_null.is_null() && string_or_null()->is_perm()) {
-+ string = string_or_null;
-+ } else {
-+ string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL);
-+ }
-+
-+ // Allocation must be done before grabbing the StringTable_lock lock
-+ MutexLocker ml(StringTable_lock, THREAD);
-
- // Otherwise, add to symbol to table
-- return the_table()->basic_add(index, string_or_null, name, len,
-+ return the_table()->basic_add(index, string, name, len,
- hashValue, CHECK_NULL);
- }
-
-@@ -517,3 +618,41 @@
- }
- }
- }
-+
-+void StringTable::dump(outputStream* st) {
-+ NumberSeq summary;
-+ for (int i = 0; i < the_table()->table_size(); ++i) {
-+ HashtableEntry* p = the_table()->bucket(i);
-+ int count = 0;
-+ for ( ; p != NULL; p = p->next()) {
-+ count++;
-+ }
-+ summary.add((double)count);
-+ }
-+ st->print_cr("StringTable statistics:");
-+ st->print_cr("Number of buckets : %7d", summary.num());
-+ st->print_cr("Average bucket size : %7.0f", summary.avg());
-+ st->print_cr("Variance of bucket size : %7.0f", summary.variance());
-+ st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd());
-+ st->print_cr("Maximum bucket size : %7.0f", summary.maximum());
-+}
-+
-+
-+// Create a new table and using alternate hash code, populate the new table
-+// with the existing strings. Set flag to use the alternate hash code afterwards.
-+void StringTable::rehash_table() {
-+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
-+ // This should never happen with -Xshare:dump but it might in testing mode.
-+ if (DumpSharedSpaces) return;
-+ StringTable* new_table = new StringTable();
-+
-+ // Rehash the table
-+ the_table()->move_to(new_table);
-+
-+ // Delete the table and buckets (entries are reused in new table).
-+ delete _the_table;
-+ // Don't check if we need rehashing until the table gets unbalanced again.
-+ // Then rehash with a new global seed.
-+ _needs_rehashing = false;
-+ _the_table = new_table;
-+}
-diff --git a/src/share/vm/classfile/symbolTable.hpp b/src/share/vm/classfile/symbolTable.hpp
---- hotspot/src/share/vm/classfile/symbolTable.hpp
-+++ hotspot/src/share/vm/classfile/symbolTable.hpp
-@@ -40,6 +40,7 @@
- // - symbolTableEntrys are allocated in blocks to reduce the space overhead.
-
- class BoolObjectClosure;
-+class outputStream;
-
-
- class SymbolTable : public Hashtable {
-@@ -49,10 +50,13 @@
- // The symbol table
- static SymbolTable* _the_table;
-
-+ // Set if one bucket is out of balance due to hash algorithm deficiency
-+ static bool _needs_rehashing;
-+
- // Adding elements
-- symbolOop basic_add(int index, u1* name, int len,
-+ symbolOop basic_add(symbolHandle sym, int index, u1* name, int len,
- unsigned int hashValue, TRAPS);
-- bool basic_add(constantPoolHandle cp, int names_count,
-+ bool basic_add(symbolHandle* syms, constantPoolHandle cp, int names_count,
- const char** names, int* lengths, int* cp_indices,
- unsigned int* hashValues, TRAPS);
-
-@@ -61,6 +65,8 @@
- symbol_table_size = 20011
- };
-
-+ static unsigned int hash_symbol(const char* s, int len);
-+
- symbolOop lookup(int index, const char* name, int len, unsigned int hash);
-
- SymbolTable()
-@@ -70,7 +76,6 @@
- : Hashtable(symbol_table_size, sizeof (HashtableEntry), t,
- number_of_entries) {}
-
--
- public:
- enum {
- symbol_alloc_batch_size = 8
-@@ -137,6 +142,7 @@
-
- // Debugging
- static void verify();
-+ static void dump(outputStream* st);
-
- // Sharing
- static void copy_buckets(char** top, char*end) {
-@@ -148,6 +154,10 @@
- static void reverse(void* boundary = NULL) {
- ((Hashtable*)the_table())->reverse(boundary);
- }
-+
-+ // Rehash the symbol table if it gets out of balance
-+ static void rehash_table();
-+ static bool needs_rehashing() { return _needs_rehashing; }
- };
-
-
-@@ -158,8 +168,11 @@
- // The string table
- static StringTable* _the_table;
-
-+ // Set if one bucket is out of balance due to hash algorithm deficiency
-+ static bool _needs_rehashing;
-+
- static oop intern(Handle string_or_null, jchar* chars, int length, TRAPS);
-- oop basic_add(int index, Handle string_or_null, jchar* name, int len,
-+ oop basic_add(int index, Handle string, jchar* name, int len,
- unsigned int hashValue, TRAPS);
-
- // Table size
-@@ -192,10 +205,6 @@
- _the_table = new StringTable(t, number_of_entries);
- }
-
--
-- static int hash_string(jchar* s, int len);
--
--
- // GC support
- // Delete pointers to otherwise-unreachable objects.
- static void unlink(BoolObjectClosure* cl) {
-@@ -207,6 +216,14 @@
- the_table()->Hashtable::oops_do(f);
- }
-
-+ // Hashing algorithm, used as the hash value used by the
-+ // StringTable for bucket selection and comparison (stored in the
-+ // HashtableEntry structures). This is used in the String.intern() method.
-+ static unsigned int hash_string(const jchar* s, int len);
-+
-+ // Internal test.
-+ static void test_alt_hash() PRODUCT_RETURN;
-+
- // Probing
- static oop lookup(symbolOop symbol);
-
-@@ -217,6 +234,7 @@
-
- // Debugging
- static void verify();
-+ static void dump(outputStream* st);
-
- // Sharing
- static void copy_buckets(char** top, char*end) {
-@@ -228,6 +246,9 @@
- static void reverse() {
- ((BasicHashtable*)the_table())->reverse();
- }
-+
-+ // Rehash the symbol table if it gets out of balance
-+ static void rehash_table();
-+ static bool needs_rehashing() { return _needs_rehashing; }
- };
--
- #endif // SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP
-diff --git a/src/share/vm/memory/dump.cpp b/src/share/vm/memory/dump.cpp
---- hotspot/src/share/vm/memory/dump.cpp
-+++ hotspot/src/share/vm/memory/dump.cpp
-@@ -62,8 +62,8 @@
- // written later, increasing the likelihood that the shared page contain
- // the hash can be shared.
- //
--// NOTE THAT the algorithm in StringTable::hash_string() MUST MATCH the
--// algorithm in java.lang.String.hashCode().
-+// NOTE THAT we have to call java_lang_String::to_hash() to match the
-+// algorithm in java.lang.String.toHash().
-
- class StringHashCodeClosure: public OopClosure {
- private:
-@@ -88,7 +88,7 @@
- } else {
- int offset = java_lang_String::offset(obj);
- jchar* s = value->char_at_addr(offset);
-- hash = StringTable::hash_string(s, length);
-+ hash = java_lang_String::to_hash(s, length);
- }
- obj->int_field_put(hash_offset, hash);
- }
-diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
---- hotspot/src/share/vm/runtime/globals.hpp
-+++ hotspot/src/share/vm/runtime/globals.hpp
-@@ -2511,6 +2511,9 @@
- product(bool, UseHeavyMonitors, false, \
- "use heavyweight instead of lightweight Java monitors") \
- \
-+ product(bool, PrintStringTableStatistics, false, \
-+ "print statistics about the StringTable and SymbolTable") \
-+ \
- notproduct(bool, PrintSymbolTableSizeHistogram, false, \
- "print histogram of the symbol table") \
- \
-diff --git a/src/share/vm/runtime/init.cpp b/src/share/vm/runtime/init.cpp
---- hotspot/src/share/vm/runtime/init.cpp
-+++ hotspot/src/share/vm/runtime/init.cpp
-@@ -23,6 +23,7 @@
- */
-
- #include "precompiled.hpp"
-+#include "classfile/symbolTable.hpp"
- #include "code/icBuffer.hpp"
- #include "gc_interface/collectedHeap.hpp"
- #include "interpreter/bytecodes.hpp"
-@@ -153,6 +154,10 @@
- // Print the collected safepoint statistics.
- SafepointSynchronize::print_stat_on_exit();
- }
-+ if (PrintStringTableStatistics) {
-+ SymbolTable::dump(tty);
-+ StringTable::dump(tty);
-+ }
- ostream_exit();
- }
- }
-diff --git a/src/share/vm/runtime/safepoint.cpp b/src/share/vm/runtime/safepoint.cpp
---- hotspot/src/share/vm/runtime/safepoint.cpp
-+++ hotspot/src/share/vm/runtime/safepoint.cpp
-@@ -23,6 +23,7 @@
- */
-
- #include "precompiled.hpp"
-+#include "classfile/symbolTable.hpp"
- #include "classfile/systemDictionary.hpp"
- #include "code/codeCache.hpp"
- #include "code/icBuffer.hpp"
-@@ -501,8 +502,20 @@
- CompilationPolicy::policy()->do_safepoint_work();
- }
-
-- TraceTime t4("sweeping nmethods", TraceSafepointCleanupTime);
-- NMethodSweeper::scan_stacks();
-+ {
-+ TraceTime t4("sweeping nmethods", TraceSafepointCleanupTime);
-+ NMethodSweeper::scan_stacks();
-+ }
-+
-+ if (SymbolTable::needs_rehashing()) {
-+ TraceTime t5("rehashing symbol table", TraceSafepointCleanupTime);
-+ SymbolTable::rehash_table();
-+ }
-+
-+ if (StringTable::needs_rehashing()) {
-+ TraceTime t6("rehashing string table", TraceSafepointCleanupTime);
-+ StringTable::rehash_table();
-+ }
- }
-
-
-diff --git a/src/share/vm/utilities/hashtable.cpp b/src/share/vm/utilities/hashtable.cpp
---- hotspot/src/share/vm/utilities/hashtable.cpp
-+++ hotspot/src/share/vm/utilities/hashtable.cpp
-@@ -1,5 +1,4 @@
--/*
-- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
-+/* * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
-@@ -23,7 +22,10 @@
- */
-
- #include "precompiled.hpp"
-+#include "classfile/altHashing.hpp"
-+#include "classfile/javaClasses.hpp"
- #include "memory/allocation.inline.hpp"
-+#include "memory/filemap.hpp"
- #include "memory/resourceArea.hpp"
- #include "oops/oop.inline.hpp"
- #include "runtime/safepoint.hpp"
-@@ -69,7 +71,6 @@
-
- HashtableEntry* Hashtable::new_entry(unsigned int hashValue, oop obj) {
- HashtableEntry* entry;
--
- entry = (HashtableEntry*)BasicHashtable::new_entry(hashValue);
- entry->set_literal(obj); // clears literal string field
- HS_DTRACE_PROBE4(hs_private, hashtable__new_entry,
-@@ -85,18 +86,24 @@
- // entries at a safepoint.
- assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
- for (int i = 0; i < table_size(); ++i) {
-- for (HashtableEntry** p = bucket_addr(i); *p != NULL; ) {
-- HashtableEntry* entry = *p;
-- if (entry->is_shared()) {
-+ HashtableEntry** p = bucket_addr(i);
-+ HashtableEntry* entry = bucket(i);
-+ while (entry != NULL) {
-+ // Shared entries are normally at the end of the bucket and if we run into
-+ // a shared entry, then there is nothing more to remove. However, if we
-+ // have rehashed the table, then the shared entries are no longer at the
-+ // end of the bucket.
-+ if (entry->is_shared() && !use_alternate_hashcode()) {
- break;
- }
- assert(entry->literal() != NULL, "just checking");
-- if (is_alive->do_object_b(entry->literal())) {
-+ if (entry->is_shared() || is_alive->do_object_b(entry->literal())) {
- p = entry->next_addr();
- } else {
- *p = entry->next();
- free_entry(entry);
- }
-+ entry = (HashtableEntry*)HashtableEntry::make_ptr(*p);
- }
- }
- }
-@@ -123,6 +130,96 @@
- }
-
-
-+// Check to see if the hashtable is unbalanced. The caller set a flag to
-+// rehash at the next safepoint. If this bucket is 60 times greater than the
-+// expected average bucket length, it's an unbalanced hashtable.
-+// This is somewhat an arbitrary heuristic but if one bucket gets to
-+// rehash_count which is currently 100, there's probably something wrong.
-+
-+bool BasicHashtable::check_rehash_table(int count) {
-+ assert(table_size() != 0, "underflow");
-+ if (count > (((double)number_of_entries()/(double)table_size())*rehash_multiple)) {
-+ // Set a flag for the next safepoint, which should be at some guaranteed
-+ // safepoint interval.
-+ return true;
-+ }
-+ return false;
-+}
-+
-+unsigned int Hashtable::new_hash(oop string) {
-+ ResourceMark rm;
-+ int length;
-+ if (java_lang_String::is_instance(string)) {
-+ jchar* chars = java_lang_String::as_unicode_string(string, length);
-+ // Use alternate hashing algorithm on the string
-+ return AltHashing::murmur3_32(seed(), chars, length);
-+ } else {
-+ // Use alternate hashing algorithm on this symbol.
-+ symbolOop symOop = (symbolOop) string;
-+ return AltHashing::murmur3_32(seed(), (const jbyte*)symOop->bytes(), symOop->utf8_length());
-+ }
-+}
-+
-+// Create a new table and using alternate hash code, populate the new table
-+// with the existing elements. This can be used to change the hash code
-+// and could in the future change the size of the table.
-+
-+void Hashtable::move_to(Hashtable* new_table) {
-+ // Initialize the global seed for hashing.
-+ assert(new_table->seed() == 0, "should be zero");
-+ _seed = AltHashing::compute_seed();
-+ assert(seed() != 0, "shouldn't be zero");
-+ new_table->set_seed(_seed);
-+
-+ int saved_entry_count = this->number_of_entries();
-+
-+ // Iterate through the table and create a new entry for the new table
-+ for (int i = 0; i < new_table->table_size(); ++i) {
-+ for (HashtableEntry* p = bucket(i); p != NULL; ) {
-+ HashtableEntry* next = p->next();
-+ oop string = p->literal();
-+ // Use alternate hashing algorithm on the symbol in the first table
-+ unsigned int hashValue = new_hash(string);
-+ // Get a new index relative to the new table (can also change size)
-+ int index = new_table->hash_to_index(hashValue);
-+ p->set_hash(hashValue);
-+ // Keep the shared bit in the Hashtable entry to indicate that this entry
-+ // can't be deleted. The shared bit is the LSB in the _next field so
-+ // walking the hashtable past these entries requires
-+ // BasicHashtableEntry::make_ptr() call.
-+ bool keep_shared = p->is_shared();
-+ unlink_entry(p);
-+ new_table->add_entry(index, p);
-+ if (keep_shared) {
-+ p->set_shared();
-+ }
-+ p = next;
-+ }
-+ }
-+ // give the new table the free list as well
-+ new_table->copy_freelist(this);
-+ assert(new_table->number_of_entries() == saved_entry_count, "lost entry on dictionary copy?");
-+
-+ // Destroy memory used by the buckets in the hashtable. The memory
-+ // for the elements has been used in a new table and is not
-+ // destroyed. The memory reuse will benefit resizing the SystemDictionary
-+ // to avoid a memory allocation spike at safepoint.
-+ free_buckets();
-+}
-+
-+void BasicHashtable::free_buckets() {
-+ if (NULL != _buckets) {
-+ // Don't delete the buckets in the shared space. They aren't
-+ // allocated by os::malloc
-+ if (!UseSharedSpaces ||
-+ !FileMapInfo::current_info()->is_in_shared_space(_buckets)) {
-+ FREE_C_HEAP_ARRAY(HashtableBucket, _buckets);
-+ }
-+ _buckets = NULL;
-+ }
-+}
-+
-+
- // Reverse the order of elements in the hash buckets.
-
- void BasicHashtable::reverse() {
-diff --git a/src/share/vm/utilities/hashtable.hpp b/src/share/vm/utilities/hashtable.hpp
---- hotspot/src/share/vm/utilities/hashtable.hpp
-+++ hotspot/src/share/vm/utilities/hashtable.hpp
-@@ -177,6 +177,11 @@
- void verify_lookup_length(double load);
- #endif
-
-+ enum {
-+ rehash_count = 100,
-+ rehash_multiple = 60
-+ };
-+
- void initialize(int table_size, int entry_size, int number_of_entries);
-
- // Accessor
-@@ -192,6 +197,29 @@
- // Table entry management
- BasicHashtableEntry* new_entry(unsigned int hashValue);
-
-+ // Check that the table is unbalanced
-+ bool check_rehash_table(int count);
-+
-+ // Used when moving the entry to another table
-+ // Clean up links, but do not add to free_list
-+ void unlink_entry(BasicHashtableEntry* entry) {
-+ entry->set_next(NULL);
-+ --_number_of_entries;
-+ }
-+
-+ // Move over freelist and free block for allocation
-+ void copy_freelist(BasicHashtable* src) {
-+ _free_list = src->_free_list;
-+ src->_free_list = NULL;
-+ _first_free_entry = src->_first_free_entry;
-+ src->_first_free_entry = NULL;
-+ _end_block = src->_end_block;
-+ src->_end_block = NULL;
-+ }
-+
-+ // Free the buckets in this hashtable
-+ void free_buckets();
-+
- public:
- void set_entry(int index, BasicHashtableEntry* entry);
-
-@@ -210,11 +238,11 @@
-
- public:
- Hashtable(int table_size, int entry_size)
-- : BasicHashtable(table_size, entry_size) { }
-+ : BasicHashtable(table_size, entry_size), _seed(0) { }
-
- Hashtable(int table_size, int entry_size,
- HashtableBucket* buckets, int number_of_entries)
-- : BasicHashtable(table_size, entry_size, buckets, number_of_entries) { }
-+ : BasicHashtable(table_size, entry_size, buckets, number_of_entries), _seed(0) { }
-
- // Invoke "f->do_oop" on the locations of all oops in the table.
- void oops_do(OopClosure* f);
-@@ -234,8 +262,6 @@
-
- protected:
-
-- static unsigned int hash_symbol(const char* s, int len);
--
- unsigned int compute_hash(symbolHandle name) {
- return (unsigned int) name->identity_hash();
- }
-@@ -256,6 +282,17 @@
- HashtableEntry** bucket_addr(int i) {
- return (HashtableEntry**)BasicHashtable::bucket_addr(i);
- }
-+
-+ // Function to move these elements into the new table.
-+ void move_to(Hashtable* new_table);
-+ bool use_alternate_hashcode() { return _seed != 0; }
-+ jint seed() { return _seed; }
-+ void set_seed(jint seed) { _seed = seed; }
-+
-+ private:
-+ jint _seed;
-+
-+ unsigned int new_hash(oop string);
- };
-
-
-diff --git a/src/share/vm/utilities/hashtable.inline.hpp b/src/share/vm/utilities/hashtable.inline.hpp
---- hotspot/src/share/vm/utilities/hashtable.inline.hpp
-+++ hotspot/src/share/vm/utilities/hashtable.inline.hpp
-@@ -30,27 +30,6 @@
-
- // Inline function definitions for hashtable.hpp.
-
--
--// --------------------------------------------------------------------------
--// Hash function
--
--// We originally used hashpjw, but hash P(31) gives just as good results
--// and is slighly faster. We would like a hash function that looks at every
--// character, since package names have large common prefixes, and also because
--// hash_or_fail does error checking while iterating.
--
--// hash P(31) from Kernighan & Ritchie
--
--inline unsigned int Hashtable::hash_symbol(const char* s, int len) {
-- unsigned int h = 0;
-- while (len-- > 0) {
-- h = 31*h + (unsigned) *s;
-- s++;
-- }
-- return h;
--}
--
--
- // --------------------------------------------------------------------------
-
- // Initialize a table.