diff -r b23970014931 src/share/vm/classfile/dictionary.cpp --- a/src/share/vm/classfile/dictionary.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/classfile/dictionary.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -368,6 +368,14 @@ int index = hash_to_index(hash); DictionaryEntry* entry = new_entry(hash, obj(), loader_data); add_entry(index, entry); + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + _debug_all_insertion_count++; + _debug_insertion_count++; + } +#endif } @@ -384,56 +392,114 @@ Symbol* class_name, ClassLoaderData* loader_data) { debug_only(_lookup_count++); + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + jlong time = os::javaTimeNanos(); + _debug_all_lookup_count++; + _debug_lookup_count++; +#endif + + unsigned int count = 0; for (DictionaryEntry* entry = bucket(index); entry != NULL; entry = entry->next()) { + count++; if (entry->hash() == hash && entry->equals(class_name, loader_data)) { + + entry->_debug_lookups++; +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + unsigned int duration = os::javaTimeNanos()-time; + _debug_lookup_found_count++; + _debug_lookup_found_max_duration = (_debug_lookup_found_max_duration > duration) ? _debug_lookup_found_max_duration : duration; + _debug_lookup_found_total_duration += duration; + _debug_chain_found_maximum_length = (_debug_chain_found_maximum_length > count) ? _debug_chain_found_maximum_length : count; + _debug_chain_found_total_length += count; + + long thread_id = os::current_thread_id(); + for (int i=0; i<1024; i++) { + if (_debug_table_threads[i] == thread_id) { + break; + } else if (_debug_table_threads[i] == 0) { + _debug_table_threads[i] = thread_id; + break; + } + } + } +#endif + return entry; } debug_only(_lookup_length++); } + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + unsigned int duration = os::javaTimeNanos()-time; + _debug_lookup_failed_count++; + _debug_lookup_failed_max_duration = (_debug_lookup_failed_max_duration > duration) ? _debug_lookup_failed_max_duration : duration; + _debug_lookup_failed_total_duration += duration; + _debug_chain_failed_maximum_length = (_debug_chain_failed_maximum_length > count) ? _debug_chain_failed_maximum_length : count; + _debug_chain_failed_total_length += count; + } +#endif + return NULL; } -Klass* Dictionary::find(int index, unsigned int hash, Symbol* name, +Klass* Dictionary::find(unsigned int hash, Symbol* name, ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { + + int index = this->hash_to_index(hash); DictionaryEntry* entry = get_entry(index, hash, name, loader_data); if (entry != NULL && entry->is_valid_protection_domain(protection_domain)) { return entry->klass(); } else { - return NULL; + return (Klass*)NULL; } } -Klass* Dictionary::find_class(int index, unsigned int hash, +Klass* Dictionary::find_class(unsigned int hash, Symbol* name, ClassLoaderData* loader_data) { assert_locked_or_safepoint(SystemDictionary_lock); - assert (index == index_for(name, loader_data), "incorrect index?"); + int index = this->hash_to_index(hash); DictionaryEntry* entry = get_entry(index, hash, name, loader_data); - return (entry != NULL) ? entry->klass() : (Klass*)NULL; + if (entry != NULL) { + return entry->klass(); + } else { + return (Klass*)NULL; + } } // Variant of find_class for shared classes. No locking required, as // that table is static. -Klass* Dictionary::find_shared_class(int index, unsigned int hash, +Klass* Dictionary::find_shared_class(unsigned int hash, Symbol* name) { - assert (index == index_for(name, NULL), "incorrect index?"); + int index = this->hash_to_index(hash); DictionaryEntry* entry = get_entry(index, hash, name, NULL); - return (entry != NULL) ? entry->klass() : (Klass*)NULL; + if (entry != NULL) { + return entry->klass(); + } else { + return (Klass*)NULL; + } } -void Dictionary::add_protection_domain(int index, unsigned int hash, +void Dictionary::add_protection_domain(unsigned int hash, instanceKlassHandle klass, ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { Symbol* klass_name = klass->name(); + int index = this->hash_to_index(hash); DictionaryEntry* entry = get_entry(index, hash, klass_name, loader_data); assert(entry != NULL,"entry must be present, we just created it"); @@ -447,11 +513,15 @@ } -bool Dictionary::is_valid_protection_domain(int index, unsigned int hash, +bool Dictionary::is_valid_protection_domain(unsigned int hash, Symbol* name, ClassLoaderData* loader_data, Handle protection_domain) { + int index = this->hash_to_index(hash); DictionaryEntry* entry = get_entry(index, hash, name, loader_data); + + assert(entry != NULL,"entry must be present"); + return entry->is_valid_protection_domain(protection_domain); } @@ -710,6 +780,9 @@ ResourceMark rm; HandleMark hm; + dump_table(tty, "SystemDictionary");//gznote: here + tty->cr(); + if (details) { tty->print_cr("Java system dictionary (table_size=%d, classes=%d)", table_size(), number_of_entries()); @@ -751,6 +824,9 @@ void Dictionary::verify() { guarantee(number_of_entries() >= 0, "Verify of system dictionary failed"); + MutexLocker mu(SystemDictionary_lock); + int actual_count = 0; + int element_count = 0; for (int index = 0; index < table_size(); index++) { for (DictionaryEntry* probe = bucket(index); @@ -768,11 +844,10 @@ "checking type of class_loader"); e->verify(); probe->verify_protection_domain_set(); - element_count++; + actual_count++; } } - guarantee(number_of_entries() == element_count, - "Verify of system dictionary failed"); + guarantee(number_of_entries() == actual_count, "should be equal"); debug_only(verify_lookup_length((double)number_of_entries() / table_size())); _pd_cache_table->verify(); diff -r b23970014931 src/share/vm/classfile/dictionary.hpp --- a/src/share/vm/classfile/dictionary.hpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/classfile/dictionary.hpp Wed Feb 18 10:22:07 2015 -0600 @@ -78,10 +78,10 @@ void add_klass(Symbol* class_name, ClassLoaderData* loader_data,KlassHandle obj); - Klass* find_class(int index, unsigned int hash, + Klass* find_class(unsigned int hash, Symbol* name, ClassLoaderData* loader_data); - Klass* find_shared_class(int index, unsigned int hash, Symbol* name); + Klass* find_shared_class(unsigned int hash, Symbol* name); // Compiler support Klass* try_get_next_class(); @@ -113,12 +113,12 @@ void do_unloading(); // Protection domains - Klass* find(int index, unsigned int hash, Symbol* name, + Klass* find(unsigned int hash, Symbol* name, ClassLoaderData* loader_data, Handle protection_domain, TRAPS); - bool is_valid_protection_domain(int index, unsigned int hash, + bool is_valid_protection_domain(unsigned int hash, Symbol* name, ClassLoaderData* loader_data, Handle protection_domain); - void add_protection_domain(int index, unsigned int hash, + void add_protection_domain(unsigned int hash, instanceKlassHandle klass, ClassLoaderData* loader_data, Handle protection_domain, TRAPS); diff -r b23970014931 src/share/vm/classfile/loaderConstraints.cpp --- a/src/share/vm/classfile/loaderConstraints.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/classfile/loaderConstraints.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -441,8 +441,7 @@ Symbol* name = ik->name(); ClassLoaderData* loader_data = ik->class_loader_data(); unsigned int d_hash = dictionary->compute_hash(name, loader_data); - int d_index = dictionary->hash_to_index(d_hash); - Klass* k = dictionary->find_class(d_index, d_hash, name, loader_data); + Klass* k = dictionary->find_class(d_hash, name, loader_data); if (k != NULL) { // We found the class in the system dictionary, so we should // make sure that the Klass* matches what we already have. diff -r b23970014931 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/classfile/symbolTable.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -97,6 +97,16 @@ volatile int SymbolTable::_parallel_claimed_idx = 0; void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total) { + const int limit = the_table()->table_size(); + + assert(0 <= start_idx && start_idx <= limit, + err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); + assert(0 <= end_idx && end_idx <= limit, + err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); + assert(start_idx <= end_idx, + err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, + start_idx, end_idx)); + for (int i = start_idx; i < end_idx; ++i) { HashtableEntry** p = the_table()->bucket_addr(i); HashtableEntry* entry = the_table()->bucket(i); @@ -192,7 +202,14 @@ Symbol* SymbolTable::lookup(int index, const char* name, int len, unsigned int hash) { - int count = 0; +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + jlong time = os::javaTimeNanos(); + _debug_all_lookup_count++; + _debug_lookup_count++; +#endif + + unsigned int count = 0; for (HashtableEntry* e = bucket(index); e != NULL; e = e->next()) { count++; // count all entries in this bucket, not just ones with same hash if (e->hash() == hash) { @@ -200,6 +217,31 @@ if (sym->equals(name, len)) { // something is referencing this symbol now. sym->increment_refcount(); + + e->_debug_lookups++; +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + unsigned int duration = os::javaTimeNanos()-time; + _debug_lookup_found_count++; + _debug_lookup_found_max_duration = (_debug_lookup_found_max_duration > duration) ? _debug_lookup_found_max_duration : duration; + _debug_lookup_found_total_duration += duration; + _debug_chain_found_maximum_length = (_debug_chain_found_maximum_length > count) ? _debug_chain_found_maximum_length : count; + _debug_chain_found_total_length += count; + //fprintf(stderr, "SymL %d:%d::%lu:\"%s\"\n", true, count, os::javaTimeNanos(), name); + + long thread_id = os::current_thread_id(); + for (int i=0; i<1024; i++) { + if (_debug_table_threads[i] == thread_id) { + break; + } else if (_debug_table_threads[i] == 0) { + _debug_table_threads[i] = thread_id; + break; + } + } + } +#endif + return sym; } } @@ -208,6 +250,20 @@ if (count >= rehash_count && !needs_rehashing()) { _needs_rehashing = check_rehash_table(count); } + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + unsigned int duration = os::javaTimeNanos()-time; + _debug_lookup_failed_count++; + _debug_lookup_failed_max_duration = (_debug_lookup_failed_max_duration > duration) ? _debug_lookup_failed_max_duration : duration; + _debug_lookup_failed_total_duration += duration; + _debug_chain_failed_maximum_length = (_debug_chain_failed_maximum_length > count) ? _debug_chain_failed_maximum_length : count; + _debug_chain_failed_total_length += count; + //fprintf(stderr, "SymL %d:%d::%lu:\"%s\"\n", false, count, os::javaTimeNanos(), name); + } +#endif + return NULL; } @@ -379,6 +435,7 @@ Symbol* SymbolTable::basic_add(int index_arg, u1 *name, int len, unsigned int hashValue_arg, bool c_heap, TRAPS) { + assert(SymbolTable_lock->is_locked(), "must hold SymbolTable_lock"); assert(!Universe::heap()->is_in_reserved(name), "proposed name of symbol must be stable"); @@ -418,6 +475,16 @@ HashtableEntry* entry = new_entry(hashValue, sym); add_entry(index, entry); + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + _debug_all_insertion_count++; + _debug_insertion_count++; + //fprintf(stderr, "SymA %lu:\"%s\"\n", os::javaTimeNanos(), name); + } +#endif + return sym; } @@ -428,6 +495,7 @@ const char** names, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS) { + assert(SymbolTable_lock->is_locked(), "must hold SymbolTable_lock"); // Check symbol names are not too long. If any are too long, don't add any. for (int i = 0; i< names_count; i++) { @@ -467,13 +535,24 @@ HashtableEntry* entry = new_entry(hashValue, sym); add_entry(index, entry); cp->symbol_at_put(cp_indices[i], sym); + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + _debug_all_insertion_count++; + _debug_insertion_count++; + //fprintf(stderr, "SymA %lu:\"%s\"\n", os::javaTimeNanos(), names[i]); + } +#endif + } } return true; } - void SymbolTable::verify() { + MutexLocker mu(SymbolTable_lock); + int actual_count = 0; for (int i = 0; i < the_table()->table_size(); ++i) { HashtableEntry* p = the_table()->bucket(i); for ( ; p != NULL; p = p->next()) { @@ -483,20 +562,19 @@ guarantee(p->hash() == h, "broken hash in symbol table entry"); guarantee(the_table()->hash_to_index(h) == i, "wrong index in symbol table"); + actual_count++; } } + if (the_table()->number_of_entries()!=actual_count) { + tty->print("StringTable assert failure: number_of_entries()!=actual_count [%d!=%d]\n", the_table()->number_of_entries(), actual_count); + } + guarantee(the_table()->number_of_entries() == actual_count, "should be equal"); } -void SymbolTable::dump(outputStream* st) { - the_table()->dump_table(st, "SymbolTable"); -} - - //--------------------------------------------------------------------------- // Non-product code #ifndef PRODUCT - void SymbolTable::print_histogram() { MutexLocker ml(SymbolTable_lock); const int results_length = 100; @@ -646,11 +724,42 @@ oop StringTable::lookup(int index, jchar* name, int len, unsigned int hash) { - int count = 0; +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + jlong time = os::javaTimeNanos(); + _debug_all_lookup_count++; + _debug_lookup_count++; +#endif + + unsigned 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)) { + + l->_debug_lookups++; +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + unsigned int duration = os::javaTimeNanos()-time; + _debug_lookup_found_count++; + _debug_lookup_found_max_duration = (_debug_lookup_found_max_duration > duration) ? _debug_lookup_found_max_duration : duration; + _debug_lookup_found_total_duration += duration; + _debug_chain_found_maximum_length = (_debug_chain_found_maximum_length > count) ? _debug_chain_found_maximum_length : count; + _debug_chain_found_total_length += count; + + long thread_id = os::current_thread_id(); + for (int i=0; i<1024; i++) { + if (_debug_table_threads[i] == thread_id) { + break; + } else if (_debug_table_threads[i] == 0) { + _debug_table_threads[i] = thread_id; + break; + } + } + } +#endif + return l->literal(); } } @@ -659,6 +768,19 @@ if (count >= rehash_count && !needs_rehashing()) { _needs_rehashing = check_rehash_table(count); } + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + unsigned int duration = os::javaTimeNanos()-time; + _debug_lookup_failed_count++; + _debug_lookup_failed_max_duration = (_debug_lookup_failed_max_duration > duration) ? _debug_lookup_failed_max_duration : duration; + _debug_lookup_failed_total_duration += duration; + _debug_chain_failed_maximum_length = (_debug_chain_failed_maximum_length > count) ? _debug_chain_failed_maximum_length : count; + _debug_chain_failed_total_length += count; + } +#endif + return NULL; } @@ -666,6 +788,7 @@ oop StringTable::basic_add(int index_arg, Handle string, jchar* name, int len, unsigned int hashValue_arg, TRAPS) { + assert(StringTable_lock->is_locked(), "must hold StringTable_lock"); assert(java_lang_String::equals(string(), name, len), "string must be properly initialized"); // Cannot hit a safepoint in this function because the "this" pointer can move. @@ -694,6 +817,15 @@ HashtableEntry* entry = new_entry(hashValue, string()); add_entry(index, entry); + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + { + _debug_all_insertion_count++; + _debug_insertion_count++; + } +#endif + return string(); } @@ -884,6 +1016,7 @@ (*removed)++; } (*processed)++; + entry = (HashtableEntry*)HashtableEntry::make_ptr(*p); entry = *p; } } @@ -912,6 +1045,8 @@ // This verification is part of Universe::verify() and needs to be quick. // See StringTable::verify_and_compare() below for exhaustive verification. void StringTable::verify() { + MutexLocker mu(StringTable_lock); + int actual_count = 0; for (int i = 0; i < the_table()->table_size(); ++i) { HashtableEntry* p = the_table()->bucket(i); for ( ; p != NULL; p = p->next()) { @@ -919,14 +1054,20 @@ guarantee(s != NULL, "interned string is NULL"); unsigned int h = java_lang_String::hash_string(s); guarantee(p->hash() == h, "broken hash in string table entry"); +// if (the_table()->hash_to_index(h) != i) { +// fprintf(stderr, "h: %d\n", h); +// fprintf(stderr, "the_table()->hash_to_index(h: %d\n", the_table()->hash_to_index(h)); +// fprintf(stderr, "i: %d\n", i); +// } guarantee(the_table()->hash_to_index(h) == i, "wrong index in string table"); + actual_count++; } } -} - -void StringTable::dump(outputStream* st) { - the_table()->dump_table(st, "StringTable"); + if (the_table()->number_of_entries()!=actual_count) { + tty->print("StringTable assert failure: number_of_entries()!=actual_count [%d!=%d]\n", the_table()->number_of_entries(), actual_count); + } + guarantee(the_table()->number_of_entries() == actual_count, "should be equal"); } StringTable::VerifyRetTypes StringTable::compare_entries( diff -r b23970014931 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/classfile/symbolTable.hpp Wed Feb 18 10:22:07 2015 -0600 @@ -110,11 +110,21 @@ Symbol* lookup(int index, const char* name, int len, unsigned int hash); SymbolTable() - : RehashableHashtable(SymbolTableSize, sizeof (HashtableEntry)) {} + : RehashableHashtable(SymbolTableSize, sizeof (HashtableEntry)) + { +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, "SymbolTable1 %p with size %d\n", this, (int)SymbolTableSize); +#endif + } SymbolTable(HashtableBucket* t, int number_of_entries) : RehashableHashtable(SymbolTableSize, sizeof (HashtableEntry), t, - number_of_entries) {} + number_of_entries) + { +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, "SymbolTable2 %p with size %d\n", this, (int)SymbolTableSize); +#endif + } // Arena for permanent symbols (null class loader) that are never unloaded static Arena* _arena; @@ -231,7 +241,6 @@ // Debugging static void verify(); - static void dump(outputStream* st); // Sharing static void copy_buckets(char** top, char*end) { @@ -279,11 +288,22 @@ static void buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed); StringTable() : RehashableHashtable((int)StringTableSize, - sizeof (HashtableEntry)) {} + sizeof (HashtableEntry)) + { +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, "StringTable1 %p with size %d\n", this, (int)StringTableSize); +#endif + } StringTable(HashtableBucket* t, int number_of_entries) : RehashableHashtable((int)StringTableSize, sizeof (HashtableEntry), t, - number_of_entries) {} + number_of_entries) + { +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, "StringTable2 %p with size %d\n", this, (int)StringTableSize); +#endif + } + public: // The string table static StringTable* the_table() { return _the_table; } @@ -341,7 +361,6 @@ // Debugging static void verify(); - static void dump(outputStream* st); enum VerifyMesgModes { _verify_quietly = 0, diff -r b23970014931 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -76,10 +76,10 @@ SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL; -int SystemDictionary::_number_of_modifications = 0; +int SystemDictionary::_number_of_modifications = 0; int SystemDictionary::_sdgeneration = 0; -const int SystemDictionary::_primelist[_prime_array_size] = {1009,2017,4049,5051,10103, - 20201,40423,99991}; +const int SystemDictionary::_primelist[_prime_array_size] = {defaultSystemDictionarySize,2017,4049,5051,10103, + 20201,40423,99991}; oop SystemDictionary::_system_loader_lock_obj = NULL; @@ -333,15 +333,14 @@ ClassLoaderData* loader_data = class_loader_data(class_loader); unsigned int d_hash = dictionary()->compute_hash(child_name, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); unsigned int p_hash = placeholders()->compute_hash(child_name, loader_data); - int p_index = placeholders()->hash_to_index(p_hash); // can't throw error holding a lock bool child_already_loaded = false; bool throw_circularity_error = false; { MutexLocker mu(SystemDictionary_lock, THREAD); - Klass* childk = find_class(d_index, d_hash, child_name, loader_data); + int p_index = placeholders()->hash_to_index(p_hash); + Klass* childk = find_class(d_hash, child_name, loader_data); Klass* quicksuperk; // to support // loading: if child done loading, just return superclass // if class_name, & class_loader don't match: @@ -388,6 +387,7 @@ // the loader_data. parseClassFile adds the instanceKlass to loader_data. { MutexLocker mu(SystemDictionary_lock, THREAD); + int p_index = placeholders()->hash_to_index(p_hash); placeholders()->find_and_remove(p_index, p_hash, child_name, loader_data, PlaceholderTable::LOAD_SUPER, THREAD); SystemDictionary_lock->notify_all(); } @@ -445,7 +445,6 @@ Symbol* kn = klass->name(); unsigned int d_hash = dictionary()->compute_hash(kn, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); MutexLocker mu(SystemDictionary_lock, THREAD); { @@ -457,7 +456,7 @@ // Dictionary::do_unloading() asserts that classes in SD are only // unloaded at a safepoint. Anonymous classes are not in SD. No_Safepoint_Verifier nosafepoint; - dictionary()->add_protection_domain(d_index, d_hash, klass, loader_data, + dictionary()->add_protection_domain(d_hash, klass, loader_data, protection_domain, THREAD); } } @@ -523,9 +522,7 @@ instanceKlassHandle nh = instanceKlassHandle(); // null Handle ClassLoaderData* loader_data = class_loader_data(class_loader); unsigned int d_hash = dictionary()->compute_hash(name, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); unsigned int p_hash = placeholders()->compute_hash(name, loader_data); - int p_index = placeholders()->hash_to_index(p_hash); // superk is not used, resolve_super called for circularity check only // This code is reached in two situations. One if this thread @@ -547,7 +544,7 @@ if (!class_loader.is_null() && is_parallelCapable(class_loader)) { MutexLocker mu(SystemDictionary_lock, THREAD); // Check if classloading completed while we were loading superclass or waiting - Klass* check = find_class(d_index, d_hash, name, loader_data); + Klass* check = find_class(d_hash, name, loader_data); if (check != NULL) { // Klass is already loaded, so just return it return(instanceKlassHandle(THREAD, check)); @@ -562,8 +559,9 @@ PlaceholderEntry* placeholder; while (super_load_in_progress) { MutexLocker mu(SystemDictionary_lock, THREAD); + int p_index = placeholders()->hash_to_index(p_hash); // Check if classloading completed while we were loading superclass or waiting - Klass* check = find_class(d_index, d_hash, name, loader_data); + Klass* check = find_class(d_hash, name, loader_data); if (check != NULL) { // Klass is already loaded, so just return it return(instanceKlassHandle(THREAD, check)); @@ -620,8 +618,7 @@ // before we return a result we call out to java to check for valid protection domain // to allow returning the Klass* and add it to the pd_set if it is valid unsigned int d_hash = dictionary()->compute_hash(name, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); - Klass* probe = dictionary()->find(d_index, d_hash, name, loader_data, + Klass* probe = dictionary()->find(d_hash, name, loader_data, protection_domain, THREAD); if (probe != NULL) return probe; @@ -641,7 +638,6 @@ } unsigned int p_hash = placeholders()->compute_hash(name, loader_data); - int p_index = placeholders()->hash_to_index(p_hash); // Class is not in SystemDictionary so we have to do loading. // Make sure we are synchronized on the class loader before we proceed @@ -659,7 +655,8 @@ { MutexLocker mu(SystemDictionary_lock, THREAD); - Klass* check = find_class(d_index, d_hash, name, loader_data); + int p_index = placeholders()->hash_to_index(p_hash); + Klass* check = find_class(d_hash, name, loader_data); if (check != NULL) { // Klass is already loaded, so just return it class_has_been_loaded = true; @@ -719,6 +716,7 @@ { MutexLocker mu(SystemDictionary_lock, THREAD); + int p_index = placeholders()->hash_to_index(p_hash); if (class_loader.is_null() || !is_parallelCapable(class_loader)) { PlaceholderEntry* oldprobe = placeholders()->get_entry(p_index, p_hash, name, loader_data); if (oldprobe) { @@ -740,7 +738,7 @@ double_lock_wait(lockObject, THREAD); } // Check if classloading completed while we were waiting - Klass* check = find_class(d_index, d_hash, name, loader_data); + Klass* check = find_class(d_hash, name, loader_data); if (check != NULL) { // Klass is already loaded, so just return it k = instanceKlassHandle(THREAD, check); @@ -765,7 +763,7 @@ // i.e. now that we hold the LOAD_INSTANCE token on loading this class/CL // one final check if the load has already completed // class loaders holding the ObjectLock shouldn't find the class here - Klass* check = find_class(d_index, d_hash, name, loader_data); + Klass* check = find_class(d_hash, name, loader_data); if (check != NULL) { // Klass is already loaded, so return it after checking/adding protection domain k = instanceKlassHandle(THREAD, check); @@ -798,7 +796,7 @@ if (k.is_null() && HAS_PENDING_EXCEPTION && PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) { MutexLocker mu(SystemDictionary_lock, THREAD); - Klass* check = find_class(d_index, d_hash, name, loader_data); + Klass* check = find_class(d_hash, name, loader_data); if (check != NULL) { // Klass is already loaded, so just use it k = instanceKlassHandle(THREAD, check); @@ -813,7 +811,7 @@ if (!HAS_PENDING_EXCEPTION && !k.is_null() && k->class_loader() != class_loader()) { - check_constraints(d_index, d_hash, k, class_loader, false, THREAD); + check_constraints(d_hash, k, class_loader, false, THREAD); // Need to check for a PENDING_EXCEPTION again; check_constraints // can throw and doesn't use the CHECK macro. @@ -821,7 +819,7 @@ { // Grabbing the Compile_lock prevents systemDictionary updates // during compilations. MutexLocker mu(Compile_lock, THREAD); - update_dictionary(d_index, d_hash, p_index, p_hash, + update_dictionary(d_hash, p_hash, k, class_loader, THREAD); } @@ -839,6 +837,7 @@ // This brackets the SystemDictionary updates for both defining // and initiating loaders MutexLocker mu(SystemDictionary_lock, THREAD); + int p_index = placeholders()->hash_to_index(p_hash); placeholders()->find_and_remove(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD); SystemDictionary_lock->notify_all(); } @@ -872,7 +871,7 @@ // Dictionary::do_unloading() asserts that classes in SD are only // unloaded at a safepoint. Anonymous classes are not in SD. No_Safepoint_Verifier nosafepoint; - if (dictionary()->is_valid_protection_domain(d_index, d_hash, name, + if (dictionary()->is_valid_protection_domain(d_hash, name, loader_data, protection_domain)) { return k(); @@ -916,7 +915,6 @@ } unsigned int d_hash = dictionary()->compute_hash(class_name, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); { // Note that we have an entry, and entries can be deleted only during GC, @@ -926,7 +924,7 @@ // Dictionary::do_unloading() asserts that classes in SD are only // unloaded at a safepoint. Anonymous classes are not in SD. No_Safepoint_Verifier nosafepoint; - return dictionary()->find(d_index, d_hash, class_name, loader_data, + return dictionary()->find(d_hash, class_name, loader_data, protection_domain, THREAD); } } @@ -1158,9 +1156,8 @@ Klass* SystemDictionary::find_shared_class(Symbol* class_name) { if (shared_dictionary() != NULL) { unsigned int d_hash = shared_dictionary()->compute_hash(class_name, NULL); - int d_index = shared_dictionary()->hash_to_index(d_hash); - return shared_dictionary()->find_shared_class(d_index, d_hash, class_name); + return shared_dictionary()->find_shared_class(d_hash, class_name); } else { return NULL; } @@ -1392,8 +1389,7 @@ // which will require a token to perform the define class Symbol* name_h = k->name(); unsigned int d_hash = dictionary()->compute_hash(name_h, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); - check_constraints(d_index, d_hash, k, class_loader_h, true, CHECK); + check_constraints(d_hash, k, class_loader_h, true, CHECK); // Register class just loaded with class loader (placed in Vector) // Note we do this before updating the dictionary, as this can @@ -1411,7 +1407,6 @@ // Add the new class. We need recompile lock during update of CHA. { unsigned int p_hash = placeholders()->compute_hash(name_h, loader_data); - int p_index = placeholders()->hash_to_index(p_hash); MutexLocker mu_r(Compile_lock, THREAD); @@ -1421,7 +1416,7 @@ // Add to systemDictionary - so other classes can see it. // Grabs and releases SystemDictionary_lock - update_dictionary(d_index, d_hash, p_index, p_hash, + update_dictionary(d_hash, p_hash, k, class_loader_h, THREAD); } k->eager_initialize(THREAD); @@ -1458,18 +1453,17 @@ ClassLoaderData* loader_data = class_loader_data(class_loader); unsigned int d_hash = dictionary()->compute_hash(name_h, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); // Hold SD lock around find_class and placeholder creation for DEFINE_CLASS unsigned int p_hash = placeholders()->compute_hash(name_h, loader_data); - int p_index = placeholders()->hash_to_index(p_hash); PlaceholderEntry* probe; { MutexLocker mu(SystemDictionary_lock, THREAD); + int p_index = placeholders()->hash_to_index(p_hash); // First check if class already defined if (UnsyncloadClass || (is_parallelDefine(class_loader))) { - Klass* check = find_class(d_index, d_hash, name_h, loader_data); + Klass* check = find_class(d_hash, name_h, loader_data); if (check != NULL) { return(instanceKlassHandle(THREAD, check)); } @@ -1481,7 +1475,7 @@ // All threads wait - even those that will throw duplicate class: otherwise // caller is surprised by LinkageError: duplicate, but findLoadedClass fails // if other thread has not finished updating dictionary - while (probe->definer() != NULL) { + while (probe->definer() != NULL) { // gznote: we're already holding SystemDictionary_lock, so why spin? SystemDictionary_lock->wait(); } // Only special cases allow parallel defines and can use other thread's results @@ -1491,7 +1485,7 @@ placeholders()->find_and_remove(p_index, p_hash, name_h, loader_data, PlaceholderTable::DEFINE_CLASS, THREAD); SystemDictionary_lock->notify_all(); #ifdef ASSERT - Klass* check = find_class(d_index, d_hash, name_h, loader_data); + Klass* check = find_class(d_hash, name_h, loader_data); assert(check != NULL, "definer missed recording success"); #endif return(instanceKlassHandle(THREAD, probe->instance_klass())); @@ -1508,6 +1502,7 @@ // definer must notify any waiting threads { MutexLocker mu(SystemDictionary_lock, THREAD); + int p_index = placeholders()->hash_to_index(p_hash); PlaceholderEntry* probe = placeholders()->get_entry(p_index, p_hash, name_h, loader_data); assert(probe != NULL, "DEFINE_CLASS placeholder lost?"); if (probe != NULL) { @@ -1565,14 +1560,11 @@ // ---------------------------------------------------------------------------- // Lookup -Klass* SystemDictionary::find_class(int index, unsigned int hash, +Klass* SystemDictionary::find_class(unsigned int hash, Symbol* class_name, ClassLoaderData* loader_data) { assert_locked_or_safepoint(SystemDictionary_lock); - assert (index == dictionary()->index_for(class_name, loader_data), - "incorrect index?"); - - Klass* k = dictionary()->find_class(index, hash, class_name, loader_data); + Klass* k = dictionary()->find_class(hash, class_name, loader_data); return k; } @@ -1600,8 +1592,7 @@ // First look in the loaded class array unsigned int d_hash = dictionary()->compute_hash(class_name, loader_data); - int d_index = dictionary()->hash_to_index(d_hash); - return find_class(d_index, d_hash, class_name, loader_data); + return find_class(d_hash, class_name, loader_data); } @@ -1815,12 +1806,27 @@ // Allocate arrays assert(dictionary() == NULL, "SystemDictionary should only be initialized once"); +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating SystemDictionary Dictionary\n"); +#endif _sdgeneration = 0; _dictionary = new Dictionary(calculate_systemdictionary_size(PredictedLoadedClassCount)); +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating SystemDictionary PlaceholderTable\n"); +#endif _placeholders = new PlaceholderTable(_nof_buckets); _number_of_modifications = 0; +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating SystemDictionary LoaderConstraintTable\n"); +#endif _loader_constraints = new LoaderConstraintTable(_loader_constraint_size); +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating SystemDictionary ResolutionErrorTable\n"); +#endif _resolution_errors = new ResolutionErrorTable(_resolution_error_size); +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating SystemDictionary SymbolPropertyTable\n"); +#endif _invoke_method_table = new SymbolPropertyTable(_invoke_method_size); // Allocate private object used as system class loader lock @@ -1966,7 +1972,7 @@ // if defining is true, then LinkageError if already in systemDictionary // if initiating loader, then ok if InstanceKlass matches existing entry -void SystemDictionary::check_constraints(int d_index, unsigned int d_hash, +void SystemDictionary::check_constraints(unsigned int d_hash, instanceKlassHandle k, Handle class_loader, bool defining, TRAPS) { @@ -1977,7 +1983,7 @@ MutexLocker mu(SystemDictionary_lock, THREAD); - Klass* check = find_class(d_index, d_hash, name, loader_data); + Klass* check = find_class(d_hash, name, loader_data); if (check != (Klass*)NULL) { // if different InstanceKlass - duplicate class definition, // else - ok, class loaded by a different thread in parallel, @@ -2025,8 +2031,8 @@ // Update system dictionary - done after check_constraint and add_to_hierachy // have been called. -void SystemDictionary::update_dictionary(int d_index, unsigned int d_hash, - int p_index, unsigned int p_hash, +void SystemDictionary::update_dictionary(unsigned int d_hash, + unsigned int p_hash, instanceKlassHandle k, Handle class_loader, TRAPS) { @@ -2059,13 +2065,13 @@ } // Make a new system dictionary entry. - Klass* sd_check = find_class(d_index, d_hash, name, loader_data); + Klass* sd_check = find_class(d_hash, name, loader_data); if (sd_check == NULL) { dictionary()->add_klass(name, loader_data, k); notice_modification(); } #ifdef ASSERT - sd_check = find_class(d_index, d_hash, name, loader_data); + sd_check = find_class(d_hash, name, loader_data); assert (sd_check != NULL, "should have entry in system dictionary"); // Note: there may be a placeholder entry: for circularity testing // or for parallel defines @@ -2140,20 +2146,17 @@ } } unsigned int d_hash1 = dictionary()->compute_hash(constraint_name, loader_data1); - int d_index1 = dictionary()->hash_to_index(d_hash1); + unsigned int d_hash2 = dictionary()->compute_hash(constraint_name, loader_data2); + { + MutexLocker mu_s(SystemDictionary_lock, THREAD); - unsigned int d_hash2 = dictionary()->compute_hash(constraint_name, loader_data2); - int d_index2 = dictionary()->hash_to_index(d_hash2); - { - MutexLocker mu_s(SystemDictionary_lock, THREAD); + // Better never do a GC while we're holding these oops + No_Safepoint_Verifier nosafepoint; - // Better never do a GC while we're holding these oops - No_Safepoint_Verifier nosafepoint; - - Klass* klass1 = find_class(d_index1, d_hash1, constraint_name, loader_data1); - Klass* klass2 = find_class(d_index2, d_hash2, constraint_name, loader_data2); - return constraints()->add_entry(constraint_name, klass1, class_loader1, - klass2, class_loader2); + Klass* klass1 = find_class(d_hash1, constraint_name, loader_data1); + Klass* klass2 = find_class(d_hash2, constraint_name, loader_data2); + return constraints()->add_entry(constraint_name, klass1, class_loader1, + klass2, class_loader2); } } @@ -2161,9 +2164,9 @@ // attempt to resolve a reference to a class has failed. void SystemDictionary::add_resolution_error(constantPoolHandle pool, int which, Symbol* error) { unsigned int hash = resolution_errors()->compute_hash(pool, which); - int index = resolution_errors()->hash_to_index(hash); { MutexLocker ml(SystemDictionary_lock, Thread::current()); + int index = resolution_errors()->hash_to_index(hash); resolution_errors()->add_entry(index, hash, pool, which, error); } } @@ -2176,9 +2179,9 @@ // Lookup resolution error table. Returns error if found, otherwise NULL. Symbol* SystemDictionary::find_resolution_error(constantPoolHandle pool, int which) { unsigned int hash = resolution_errors()->compute_hash(pool, which); - int index = resolution_errors()->hash_to_index(hash); { MutexLocker ml(SystemDictionary_lock, Thread::current()); + int index = resolution_errors()->hash_to_index(hash); ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which); return (entry != NULL) ? entry->error() : (Symbol*)NULL; } @@ -2288,6 +2291,7 @@ // if a racing thread has managed to install one at the same time. { MutexLocker ml(SystemDictionary_lock, THREAD); + index = invoke_method_table()->hash_to_index(hash); spe = invoke_method_table()->find_entry(index, hash, signature, iid); if (spe == NULL) spe = invoke_method_table()->add_entry(index, hash, signature, iid); @@ -2464,6 +2468,7 @@ if (is_on_bcp) { // We can cache this MethodType inside the JVM. MutexLocker ml(SystemDictionary_lock, THREAD); + index = invoke_method_table()->hash_to_index(hash); spe = invoke_method_table()->find_entry(index, hash, signature, null_iid); if (spe == NULL) spe = invoke_method_table()->add_entry(index, hash, signature, null_iid); @@ -2619,11 +2624,11 @@ dictionary()->print(details); // Placeholders - GCMutexLocker mu(SystemDictionary_lock); - placeholders()->print(); +// GCMutexLocker mu(SystemDictionary_lock); +// placeholders()->print(); // loader constraints - print under SD_lock - constraints()->print(); +// constraints()->print(); } diff -r b23970014931 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/classfile/systemDictionary.hpp Wed Feb 18 10:22:07 2015 -0600 @@ -228,6 +228,8 @@ CEIL_LG_OPTION_LIMIT = 4 // OPTION_LIMIT <= (1<* the_table() { return (TwoOopHashtable*)dictionary(); } // Returns a class with a given class name and class loader. Loads the // class if needed. If not found a NoClassDefFoundError or a @@ -555,13 +557,13 @@ protected: enum Constants { - _loader_constraint_size = 107, // number of entries in constraint table - _resolution_error_size = 107, // number of entries in resolution error table - _invoke_method_size = 139, // number of entries in invoke method table - _nof_buckets = 1009, // number of buckets in hash table for placeholders - _old_default_sdsize = 1009, // backward compat for system dictionary size - _prime_array_size = 8, // array of primes for system dictionary size - _average_depth_goal = 3 // goal for lookup length + _loader_constraint_size = 107, // number of entries in constraint table + _resolution_error_size = 107, // number of entries in resolution error table + _invoke_method_size = 139, // number of entries in invoke method table + _nof_buckets = defaultSystemDictionarySize,// number of buckets in hash table for placeholders + _old_default_sdsize = defaultSystemDictionarySize,// backward compat for system dictionary size + _prime_array_size = 8, // array of primes for system dictionary size + _average_depth_goal = 3 // goal for lookup length }; @@ -655,11 +657,9 @@ // event based tracing static void post_class_load_event(const Ticks& start_time, instanceKlassHandle k, Handle initiating_loader); - // We pass in the hashtable index so we can calculate it outside of - // the SystemDictionary_lock. // Basic find on loaded classes - static Klass* find_class(int index, unsigned int hash, + static Klass* find_class(unsigned int hash, Symbol* name, ClassLoaderData* loader_data); static Klass* find_class(Symbol* class_name, ClassLoaderData* loader_data); @@ -690,11 +690,11 @@ static void initialize_preloaded_classes(TRAPS); // Class loader constraints - static void check_constraints(int index, unsigned int hash, + static void check_constraints(unsigned int hash, instanceKlassHandle k, Handle loader, bool defining, TRAPS); - static void update_dictionary(int d_index, unsigned int d_hash, - int p_index, unsigned int p_hash, + static void update_dictionary(unsigned int d_hash, + unsigned int p_hash, instanceKlassHandle k, Handle loader, TRAPS); diff -r b23970014931 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/memory/universe.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -673,8 +673,17 @@ MetaspaceShared::initialize_shared_spaces(); StringTable::create_table(); } else { +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating SymbolTable\n"); +#endif SymbolTable::create_table(); +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating StringTable\n"); +#endif StringTable::create_table(); +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating ClassLoader PackageHashtable\n"); +#endif ClassLoader::create_package_info_table(); if (DumpSharedSpaces) { diff -r b23970014931 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/runtime/arguments.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -2175,10 +2175,10 @@ // Divide by bucket size to prevent a large size from causing rollover when // calculating amount of memory needed to be allocated for the String table. status = status && verify_interval(StringTableSize, minimumStringTableSize, - (max_uintx / StringTable::bucket_size()), "StringTable size"); + (max_uintx / StringTable::bucket_size()), "StringTable size"); status = status && verify_interval(SymbolTableSize, minimumSymbolTableSize, - (max_uintx / SymbolTable::bucket_size()), "SymbolTable size"); + (max_uintx / SymbolTable::bucket_size()), "SymbolTable size"); { // Using "else if" below to avoid printing two error messages if min > max. diff -r b23970014931 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/runtime/globals.hpp Wed Feb 18 10:22:07 2015 -0600 @@ -1083,12 +1083,6 @@ develop(bool, MemProfiling, false, \ "Write memory usage profiling to log file") \ \ - notproduct(bool, PrintSystemDictionaryAtExit, false, \ - "Print the system dictionary at exit") \ - \ - experimental(intx, PredictedLoadedClassCount, 0, \ - "Experimental: Tune loaded class cache starting size") \ - \ diagnostic(bool, UnsyncloadClass, false, \ "Unstable: VM calls loadClass unsynchronized. Custom " \ "class loader must call VM synchronized for findClass " \ @@ -2640,8 +2634,18 @@ product(bool, UseHeavyMonitors, false, \ "use heavyweight instead of lightweight Java monitors") \ \ + notproduct(bool, PrintSystemDictionaryAtExit, false, \ + "Print statistics about the system dictionary at exit. " \ + "Deprecated: Please use PrintSystemDictionaryStatisticsAtExit" \ + "instead") \ + \ + experimental(intx, PredictedLoadedClassCount, 0, \ + "Experimental: Tune loaded class cache starting size.") \ + \ product(bool, PrintStringTableStatistics, false, \ - "print statistics about the StringTable and SymbolTable") \ + "Print statistics about the StringTable and SymbolTable. " \ + "Deprecated: Please use PrintStringTableStatisticsAtExit " \ + "and PrintStringTableStatisticsAtExit instead") \ \ diagnostic(bool, VerifyStringTableAtExit, false, \ "verify StringTable contents at exit") \ @@ -2649,6 +2653,70 @@ notproduct(bool, PrintSymbolTableSizeHistogram, false, \ "print histogram of the symbol table") \ \ + experimental(bool, PrintStringTableStatisticsAtExit, false, \ + "Print statistics about the string table at exit") \ + \ + experimental(bool, PrintSymbolTableStatisticsAtExit, false, \ + "Print statistics about the symbol table at exit") \ + \ + experimental(bool, PrintSystemDictionaryStatisticsAtExit, false, \ + "Print statistics about the system dictionary at exit") \ + \ + experimental(bool, PrintStringTableStatisticsTimeline, false, \ + "Print timeline statistics about the string table") \ + \ + experimental(bool, PrintSymbolTableStatisticsTimeline, false, \ + "Print timeline statistics about the symbol table") \ + \ + experimental(bool, PrintSystemDictionaryStatisticsTimeline, false, \ + "Print timeline statistics about the system dictionary") \ + \ + experimental(bool, HashtablesResizeSymbolTable, true, \ + "Experimental: Turns on/off SymbolTable resizing") \ + \ + experimental(bool, HashtablesResizeStringTable, true, \ + "Experimental: Turns on/off StringTable resizing") \ + \ + experimental(bool, HashtablesResizeSystemDictionary, true, \ + "Experimental: Turns on/off SystemDictionary resizing") \ + \ + experimental(bool, HashtablesVerifyBeforeResize, false, \ + "Experimental: Verify hashtable before resizing") \ + \ + experimental(bool, HashtablesVerifyAfterResize, false, \ + "Experimental: Verify hashtable after resizing") \ + \ + experimental(double, HashtablesResizeSymbolTableTriggerLoadFactor, 12.0, \ + "Experimental: Heurstic for calculating when to resize " \ + "SymbolTable") \ + \ + experimental(double, HashtablesResizeStringTableTriggerLoadFactor, 12.0, \ + "Experimental: Heurstic for calculating when to resize " \ + "StringTable") \ + \ + experimental(double, HashtablesResizeSystemDictionaryTriggerLoadFactor, 12.0,\ + "Experimental: Heurstic for calculating when to resize " \ + "SystemDictionary") \ + \ + experimental(double, HashtablesResizeSymbolTableDesiredLoadFactor, 4.0, \ + "Experimental: Heurstic for calculating by how much to resize " \ + "SymbolTable") \ + \ + experimental(double, HashtablesResizeStringTableDesiredLoadFactor, 4.0, \ + "Experimental: Heurstic for calculating by how much to resize " \ + "StringTable") \ + \ + experimental(double, HashtablesResizeSystemDictionaryDesiredLoadFactor, 4.0,\ + "Experimental: Heurstic for calculating by how much to resize " \ + "SystemDictionary") \ + \ + experimental(bool, HashtablesResizeSort, false, \ + "Experimental: Heurstic for sorting entries according to their " \ + "lookup counters, when resizing hash tables") \ + \ + experimental(bool, HashtablesUseEvenSize, false, \ + "Experimental: Use even sizes for hashtables") \ + \ notproduct(bool, ExitVMOnVerifyError, false, \ "standard exit from VM if bytecode verify error " \ "(only in debug mode)") \ diff -r b23970014931 src/share/vm/runtime/init.cpp --- a/src/share/vm/runtime/init.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/runtime/init.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -158,9 +158,18 @@ // Print the collected safepoint statistics. SafepointSynchronize::print_stat_on_exit(); } - if (PrintStringTableStatistics) { - SymbolTable::dump(tty); - StringTable::dump(tty); + if (PrintStringTableStatistics) { // deprecated + SymbolTable::the_table()->dump_table(tty, "SymbolTable"); + StringTable::the_table()->dump_table(tty, "StringTable"); + } + if (PrintStringTableStatisticsAtExit) { + StringTable::the_table()->dump(tty, "StringTable"); + } + if (PrintSymbolTableStatisticsAtExit) { + SymbolTable::the_table()->dump(tty, "SymbolTable"); + } + if (PrintSystemDictionaryStatisticsAtExit) { + SystemDictionary::the_table()->dump(tty, "SystemDictionary"); } ostream_exit(); } diff -r b23970014931 src/share/vm/runtime/java.cpp --- a/src/share/vm/runtime/java.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/runtime/java.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -345,7 +345,7 @@ tty->cr(); } - if (PrintSystemDictionaryAtExit) { + if (PrintSystemDictionaryAtExit) { // deprecated SystemDictionary::print(); } diff -r b23970014931 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/runtime/safepoint.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -51,6 +51,7 @@ #include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" #include "services/runtimeService.hpp" +#include "trace/tracing.hpp" #include "utilities/events.hpp" #include "utilities/macros.hpp" #ifdef TARGET_ARCH_x86 @@ -502,8 +503,6 @@ return false; } - - // Various cleaning tasks that should be done periodically at safepoints void SafepointSynchronize::do_cleanup_tasks() { { @@ -515,6 +514,7 @@ TraceTime t2("updating inline caches", TraceSafepointCleanupTime); InlineCacheBuffer::update_inline_caches(); } + { TraceTime t3("compilation policy safepoint handler", TraceSafepointCleanupTime); CompilationPolicy::policy()->do_safepoint_work(); @@ -525,13 +525,123 @@ NMethodSweeper::mark_active_nmethods(); } +//#define PRINT_RESIZE + + if (HashtablesResizeSymbolTable == true) { + ResizeHashtableStats stats; + { + //tty->print("SymbolTable "); + TraceTime t5("resize_table for SymbolTable", TraceSafepointCleanupTime); + EventSymbolTableResize event; + stats = SymbolTable::the_table()->resize_table(SymbolTable_lock, + HashtablesResizeSymbolTableTriggerLoadFactor, + HashtablesResizeSymbolTableDesiredLoadFactor); + if (stats.resized == true) { + if (PrintSymbolTableStatisticsTimeline == true) { + tty->print("-------------------------------------------------------------------------------\n"); + tty->print("SymbolTable resized from %d to %d\n", stats.old_size, stats.new_size); + tty->print("-------------------------------------------------------------------------------\n"); + } + if (event.should_commit() == true) { + event.set_oldSize(stats.old_size); + event.set_newSize(stats.new_size); + event.commit(); + } + } + } + } + + if (HashtablesResizeStringTable == true) { + ResizeHashtableStats stats; + { + //tty->print("StringTable "); + TraceTime t6("resize_table for StringTable", TraceSafepointCleanupTime); + EventStringTableResize event; + stats = StringTable::the_table()->resize_table(StringTable_lock, + HashtablesResizeStringTableTriggerLoadFactor, + HashtablesResizeStringTableDesiredLoadFactor); + if (stats.resized == true) { + if (PrintStringTableStatisticsTimeline == true) { + tty->print("-------------------------------------------------------------------------------\n"); + tty->print("StringTable resized from %d to %d\n", stats.old_size, stats.new_size); + tty->print("-------------------------------------------------------------------------------\n"); + } + if (event.should_commit() == true) { + event.set_oldSize(stats.old_size); + event.set_newSize(stats.new_size); + event.commit(); + } + } + } + } + + if (HashtablesResizeSystemDictionary == true) { + ResizeHashtableStats stats; + { + //tty->print("SystemDictionary "); + TraceTime t6("resize_table for SystemDictionary", TraceSafepointCleanupTime); + EventSystemDictionaryResize event; + stats = SystemDictionary::the_table()->resize_table(SystemDictionary_lock, + HashtablesResizeSystemDictionaryTriggerLoadFactor, + HashtablesResizeSystemDictionaryDesiredLoadFactor); + if (stats.resized == true) { + if (PrintStringTableStatisticsTimeline == true) { + tty->print("-------------------------------------------------------------------------------\n"); + tty->print("SystemDictionary resized from %d to %d\n", stats.old_size, stats.new_size); + tty->print("-------------------------------------------------------------------------------\n"); + } + if (event.should_commit() == true) { + event.set_oldSize(stats.old_size); + event.set_newSize(stats.new_size); + event.commit(); + } + } + } + } + + { + bool wants = false; + bool reported = false; + static int skip = 1000; + if (PrintSymbolTableStatisticsTimeline == true) { + wants = true; + static int number_of_entries = 0; + if (SymbolTable::the_table()->number_of_entries() > (skip+number_of_entries)) { + number_of_entries = SymbolTable::the_table()->number_of_entries(); + tty->print("SymbolTable %9d:%6.3f:%lld\n", number_of_entries, (float)number_of_entries/(float)SymbolTable::the_table()->table_size(), os::javaTimeNanos()); + reported = true; + } + } + if (PrintStringTableStatisticsTimeline == true) { + wants = true; + static int number_of_entries = 0; + if (StringTable::the_table()->number_of_entries() > (skip+number_of_entries)) { + number_of_entries = StringTable::the_table()->number_of_entries(); + tty->print("StringTable %9d:%6.3f:%lld\n", number_of_entries, (float)number_of_entries/(float)SymbolTable::the_table()->table_size(), os::javaTimeNanos()); + reported = true; + } + } + if (PrintSystemDictionaryStatisticsTimeline == true) { + wants = true; + static int number_of_entries = 0; + if (SystemDictionary::the_table()->number_of_entries() > (skip+number_of_entries)) { + number_of_entries = SystemDictionary::the_table()->number_of_entries(); + tty->print("SystemDictionary %9d:%6.3f:%lld\n", number_of_entries, (float)number_of_entries/(float)SymbolTable::the_table()->table_size(), os::javaTimeNanos()); + reported = true; + } + } + if ((wants == true) && (reported == false)) { + tty->print(".\n"); + } + } + if (SymbolTable::needs_rehashing()) { - TraceTime t5("rehashing symbol table", TraceSafepointCleanupTime); + TraceTime t8("rehashing symbol table", TraceSafepointCleanupTime); SymbolTable::rehash_table(); } if (StringTable::needs_rehashing()) { - TraceTime t6("rehashing string table", TraceSafepointCleanupTime); + TraceTime t9("rehashing string table", TraceSafepointCleanupTime); StringTable::rehash_table(); } diff -r b23970014931 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/runtime/sharedRuntime.cpp Wed Feb 18 10:22:07 2015 -0600 @@ -2361,6 +2361,9 @@ void AdapterHandlerLibrary::initialize() { if (_adapters != NULL) return; +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, ">>>>> Creating AdapterHandlerTable\n"); +#endif _adapters = new AdapterHandlerTable(); // Create a special handler for abstract methods. Abstract methods diff -r b23970014931 src/share/vm/trace/trace.xml --- a/src/share/vm/trace/trace.xml Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/trace/trace.xml Wed Feb 18 10:22:07 2015 -0600 @@ -352,6 +352,23 @@ + + + + + + + + + + + + + + + + + *)BasicHashtable::new_entry(hashValue); entry->set_literal(obj); + entry->_debug_lookups = 0; return entry; } @@ -154,6 +199,163 @@ } } +// Resize the internal bucket table if the current one reaches its maximum allowed chain length (LoadFactor) +template ResizeHashtableStats BasicHashtable::resize_table(Monitor* lock, float trigger, float desired) { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + assert(lock->is_locked()==false, "table lock must not be held"); + + //tty->print(" %9d, %9llu\n", _number_of_entries, _debug_all_lookup_count); + + ResizeHashtableStats stats = {false, 0, 0}; + + static bool _resize_failed = false; + if (_resize_failed == true) { + return stats; + } + + //#define FORCE_RESIZE +#ifdef FORCE_RESIZE + int force_mod = 3; + if (((_debug_resize_fire++) % force_mod) != 0) { + return stats; + } +#else // FORCE_RESIZE + // Check if there is anything to be done here + float load_factor = (float)_number_of_entries/(float)_table_size; + if (load_factor < trigger) { + return stats; + } +#endif // FORCE_RESIZE + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + julong time = (julong)os::javaTimeNanos(); +#endif // PRODUCT + + MutexLocker mu(lock); + + if (HashtablesVerifyBeforeResize == true) { + verify(); + } + + // Find the next best size for the hashtable. + int table_size_old = _table_size; +#ifdef FORCE_RESIZE + int table_size_new = next_prime(table_size_old+1); +#else + int table_size_new = next_prime((int)(((float)_number_of_entries/(float)desired)+0.5f)); +#endif // FORCE_RESIZE + + // Allocate new buckets + HashtableBucket* buckets_new = NEW_C_HEAP_ARRAY2(HashtableBucket, table_size_new, F, CURRENT_PC); + if (buckets_new == NULL) { + _resize_failed = true; + return stats; + } + + // Clear the new buckets + for (int i = 0; i < table_size_new; i++) { + buckets_new[i].clear(); + } + + // hash_to_index() uses _table_size, so switch the sizes now + _table_size = table_size_new; + + // Do not bother sorting if new size is bigger than the number of entries + bool sort = HashtablesResizeSort && (table_size_new > _number_of_entries); + + // Move entries from the old table to a new table + for (int index_old = 0; index_old < table_size_old; index_old++) { + for (BasicHashtableEntry* p = _buckets[index_old].get_entry(); p != NULL; ) { + BasicHashtableEntry* next = p->next(); + bool keep_shared = p->is_shared(); + + int index_new = hash_to_index(p->hash()); + + if (sort == true) { + // Insert according to the lookup counter value, higher scored entries go to the front + BasicHashtableEntry* p_new_bigger = NULL; + for (BasicHashtableEntry* p_new = buckets_new[index_new].get_entry(); p_new != NULL; p_new = p_new->next()) { + if (p_new != NULL) { + if (p_new->_debug_lookups > p->_debug_lookups) { + p_new_bigger = p_new; + } else { + break; + } + } + } + BasicHashtableEntry* p_new_bigger_next = NULL; + if (p_new_bigger == NULL) { + p_new_bigger_next = buckets_new[index_new].get_entry(); + buckets_new[index_new].set_entry(p); + } else { + p_new_bigger_next = p_new_bigger->next(); + p_new_bigger->set_next(p); + } + p->set_next(p_new_bigger_next); + } else { +//#define ADD_TO_END +#ifdef ADD_TO_END + BasicHashtableEntry* p_new_last = NULL; + for (BasicHashtableEntry* p_new = buckets_new[index_new].get_entry(); p_new != NULL; p_new = p_new->next()) { + p_new_last = p_new; + } + if (p_new_last == NULL) { + buckets_new[index_new].set_entry(p); + } else { + p_new_last->set_next(p); + } + p->set_next(NULL); +#else // ADD_TO_END + p->set_next(buckets_new[index_new].get_entry()); + buckets_new[index_new].set_entry(p); +#endif // ADD_TO_END + } + + if (keep_shared) { + p->set_shared(); + } + p = next; + } + } + + // The old backets now can be released + BasicHashtable::free_buckets(); + + // Switch to the new storage + _buckets = buckets_new; + + if (HashtablesVerifyAfterResize == true) { + verify(); + } + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + julong duration = (julong)os::javaTimeNanos() - time; + + // Reset new table's statistics + _debug_lookup_count = 0; + _debug_insertion_count = 0; + _debug_lookup_found_count = 0; + _debug_lookup_found_max_duration = 0; + _debug_lookup_found_total_duration = 0; + _debug_chain_found_maximum_length = 0; + _debug_chain_found_total_length = 0; + _debug_lookup_failed_count = 0; + _debug_lookup_failed_max_duration = 0; + _debug_lookup_failed_total_duration = 0; + _debug_chain_failed_maximum_length = 0; + _debug_chain_failed_total_length = 0; + _debug_resize_max_duration = (duration > _debug_resize_max_duration) ? duration : _debug_resize_max_duration; + _debug_resize_total_duration += duration; + _debug_resize_total_count++; +#endif // PRODUCT + + stats.resized = true; + stats.old_size = table_size_old; + stats.new_size = table_size_new; + return stats; +} // Reverse the order of elements in the hash buckets. @@ -205,8 +407,6 @@ } } - - // Reverse the order of elements in the hash buckets. template void Hashtable::reverse(void* boundary) { @@ -239,11 +439,28 @@ } } -template int RehashableHashtable::literal_size(Symbol *symbol) { +// Dump the hash table buckets. + +template void BasicHashtable::copy_buckets(char** top, char* end) { + intptr_t len = _table_size * sizeof(HashtableBucket); + *(intptr_t*)(*top) = len; + *top += sizeof(intptr_t); + + *(intptr_t*)(*top) = _number_of_entries; + *top += sizeof(intptr_t); + + if (*top + len > end) { + report_out_of_shared_space(SharedMiscData); + } + _buckets = (HashtableBucket*)memcpy(*top, _buckets, len); + *top += len; +} + +template int Hashtable::literal_size(Symbol *symbol) { return symbol->size() * HeapWordSize; } -template int RehashableHashtable::literal_size(oop oop) { +template int Hashtable::literal_size(oop oop) { // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, // and the String.value array is shared by several Strings. However, starting from JDK8, // the String.value array is not shared anymore. @@ -251,12 +468,16 @@ return (oop->size() + java_lang_String::value(oop)->size()) * HeapWordSize; } +template int Hashtable::literal_size(Klass *klass) { + return klass->size() * HeapWordSize; +} + // Dump footprint and bucket length statistics // // Note: if you create a new subclass of Hashtable, you will need to // add a new function Hashtable::literal_size(MyNewType lit) -template void RehashableHashtable::dump_table(outputStream* st, const char *table_name) { +template void Hashtable::dump_table(outputStream* st, const char *table_name) { NumberSeq summary; int literal_bytes = 0; for (int i = 0; i < this->table_size(); ++i) { @@ -284,31 +505,108 @@ st->print_cr("Number of entries : %9d = %9d bytes, avg %7.3f", (int)num_entries, entry_bytes, entry_avg); st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg); st->print_cr("Total footprint : %9s = %9d bytes", "", total_bytes); - st->print_cr("Average bucket size : %9.3f", summary.avg()); + st->print_cr("Average bucket size : %9.3f (load factor)", summary.avg()); st->print_cr("Variance of bucket size : %9.3f", summary.variance()); st->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); st->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); } - -// Dump the hash table buckets. - -template void BasicHashtable::copy_buckets(char** top, char* end) { - intptr_t len = _table_size * sizeof(HashtableBucket); - *(intptr_t*)(*top) = len; - *top += sizeof(intptr_t); - - *(intptr_t*)(*top) = _number_of_entries; - *top += sizeof(intptr_t); - - if (*top + len > end) { - report_out_of_shared_space(SharedMiscData); +template void Hashtable::dump(outputStream* st, const char* table_name) { +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + st->print("\n-------------------------------------------------------------------------------\n"); + dump_table(st, table_name); + st->print("-------------------------\n"); + { + int count = 0; + for (int i=0; i<1024; i++) { + if (this->_debug_table_threads[i] != 0) { + count++; + } else { + break; + } + } + st->print_cr("Number of threads : %9d", count); } - _buckets = (HashtableBucket*)memcpy(*top, _buckets, len); - *top += len; + st->print("-------------------------\n"); + { + st->print_cr("All Lookups : %9llu", this->_debug_all_lookup_count); + st->print_cr("All Insertions : %9llu", this->_debug_all_insertion_count); + double ratio = 0.0; + if (this->_debug_all_lookup_count > 0.0) { + ratio = (double)(this->_debug_all_lookup_count-this->_debug_all_insertion_count) / (double)this->_debug_all_lookup_count; + } + st->print_cr("All Lookups ratio : %9.3f", 100.0*ratio); + } + st->print("-------------------------\n"); + { + st->print_cr("Lookups : %9llu", this->_debug_lookup_count); + st->print_cr("Insertions : %9llu", this->_debug_insertion_count); + double ratio = 0.0; + if (this->_debug_lookup_count > 0.0) { + ratio = (double)(this->_debug_lookup_count-this->_debug_insertion_count) / (double)this->_debug_lookup_count; + } + st->print_cr("Lookups ratio : %9.3f", 100.0*ratio); + } + { + st->print_cr("Found Lookups : %9llu", this->_debug_lookup_found_count); + st->print_cr("Failed Lookups : %9llu", this->_debug_lookup_failed_count); + double ratio = 0.0; + if (this->_debug_lookup_found_count > 0) { + ratio = (double)this->_debug_lookup_found_count / (double)(this->_debug_lookup_found_count+this->_debug_lookup_failed_count); + } + st->print_cr("Found ratio : %9.3f", 100.0*ratio); + } + st->print("-------------------------\n"); + { + double average = 0.0; + if (this->_debug_lookup_found_count > 0) { + average = (((double)this->_debug_lookup_found_total_duration / (double)this->_debug_lookup_found_count) + 0.5); + } + st->print_cr("Total found lookup time : %9llu ns", this->_debug_lookup_found_total_duration); + st->print_cr("Max found lookup time : %9llu ns", this->_debug_lookup_found_max_duration); + st->print_cr("Avg found lookup time : %9d ns", (int)average); + } + { + double average = 0.0; + if (this->_debug_lookup_failed_count > 0) { + average = (((double)this->_debug_lookup_failed_total_duration / (double)this->_debug_lookup_failed_count) + 0.5); + } + st->print_cr("Total failed lookup time: %9llu ns", this->_debug_lookup_failed_total_duration); + st->print_cr("Max failed lookup time : %9llu ns", this->_debug_lookup_failed_max_duration); + st->print_cr("Avg failed lookup time : %9d ns", (int)average); + } + st->print("-------------------------\n"); + { + double average = 0.0; + if (this->_debug_lookup_found_count > 0) { + average = (double)this->_debug_chain_found_total_length / (double)this->_debug_lookup_found_count; + } + st->print_cr("Max found chain length : %9llu", this->_debug_chain_found_maximum_length); + st->print_cr("Avg found chain length : %9.3f", average); + } + { + double average = 0.0; + if (this->_debug_lookup_failed_count > 0) { + average = (double)this->_debug_chain_failed_total_length / (double)this->_debug_lookup_failed_count; + } + st->print_cr("Max failed chain length : %9llu", this->_debug_chain_failed_maximum_length); + st->print_cr("Avg failed chain length : %9.3f", average); + } + st->print("-------------------------\n"); + { + st->print_cr("Times table was resized : %9llu", this->_debug_resize_total_count); + double average = 0.0; + if (this->_debug_resize_total_count > 0) { + average = (((double)this->_debug_resize_total_duration / (double)this->_debug_resize_total_count) + 0.5); + } + st->print_cr("Maximum resize time : %9d ns (%.5f s)", (int)this->_debug_resize_max_duration, (double)this->_debug_resize_max_duration/1000000000.0); + st->print_cr("Average resize time : %9d ns (%.5f s)", (int)average, (double)average/1000000000.0); + st->print_cr("Total resize time : %9.5f s", (double)this->_debug_resize_total_duration/1000000000.0); + } +#endif } - #ifndef PRODUCT template void Hashtable::print() { @@ -325,7 +623,6 @@ } } - template void BasicHashtable::verify() { int count = 0; for (int i = 0; i < table_size(); i++) { @@ -336,10 +633,8 @@ assert(count == number_of_entries(), "number of hashtable entries incorrect"); } - #endif // PRODUCT - #ifdef ASSERT template void BasicHashtable::verify_lookup_length(double load) { @@ -351,7 +646,8 @@ } } -#endif +#endif // ASSERT + // Explicitly instantiate these types #if INCLUDE_ALL_GCS template class Hashtable; diff -r b23970014931 src/share/vm/utilities/hashtable.hpp --- a/src/share/vm/utilities/hashtable.hpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/utilities/hashtable.hpp Wed Feb 18 10:22:07 2015 -0600 @@ -40,11 +40,12 @@ // - TableEntrys are allocated in blocks to reduce the space overhead. - template class BasicHashtableEntry : public CHeapObj { friend class VMStructs; private: - unsigned int _hash; // 32-bit hash for item + unsigned int _hash; // 32-bit hash for item + public: + int _debug_lookups; // Link to next element in the linked list for this bucket. EXCEPT // bit 0 set indicates that this entry is shared and must not be @@ -116,8 +117,6 @@ } }; - - template class HashtableBucket : public CHeapObj { friend class VMStructs; private: @@ -137,6 +136,12 @@ BasicHashtableEntry** entry_addr() { return &_entry; } }; +typedef struct +{ + bool resized; + unsigned int old_size; + unsigned int new_size; +} ResizeHashtableStats; template class BasicHashtable : public CHeapObj { friend class VMStructs; @@ -150,6 +155,9 @@ void copy_buckets(char** top, char* end); void copy_table(char** top, char* end); + // Resizing support. + ResizeHashtableStats resize_table(Monitor* lock, float trigger, float desired); + // Bucket handling int hash_to_index(unsigned int full_hash) { int h = full_hash % _table_size; @@ -172,6 +180,35 @@ protected: + julong _debug_resize_fire; // FORCE_RESIZE + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + + long _debug_table_threads[1024]; + + // statistics kept through life of VM per table type + julong _debug_all_lookup_count; + julong _debug_all_insertion_count; + + // statistics per table's duration of life + julong _debug_lookup_count; + julong _debug_insertion_count; + julong _debug_lookup_found_count; + julong _debug_lookup_found_max_duration; + julong _debug_lookup_found_total_duration; + julong _debug_chain_found_maximum_length; + julong _debug_chain_found_total_length; + julong _debug_lookup_failed_count; + julong _debug_lookup_failed_max_duration; + julong _debug_lookup_failed_total_duration; + julong _debug_chain_failed_maximum_length; + julong _debug_chain_failed_total_length; + julong _debug_resize_max_duration; + julong _debug_resize_total_duration; + julong _debug_resize_total_count; +#endif + #ifdef ASSERT int _lookup_count; int _lookup_length; @@ -226,6 +263,8 @@ int number_of_entries() { return _number_of_entries; } void verify() PRODUCT_RETURN; + + void dump(outputStream* st, const char* table_name) { tty->print("BasicHashtable\n"); }; }; @@ -272,6 +311,20 @@ return (HashtableEntry**)BasicHashtable::bucket_addr(i); } + static int literal_size(Symbol *symbol); + static int literal_size(oop oop); + static int literal_size(Klass *k); + + // The following ones are currently not used, but are needed anyway because some + // C++ compilers (MacOS and Solaris) force the instantiation of + // Hashtable::dump_table() even though we never call this function + // in the VM code. + static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} + static int literal_size(nmethod *nm) {Unimplemented(); return 0;} + +public: + void dump_table(outputStream* st, const char *table_name); + void dump(outputStream* st, const char* table_name); }; template class RehashableHashtable : public Hashtable { @@ -299,18 +352,6 @@ static bool use_alternate_hashcode() { return _seed != 0; } static juint seed() { return _seed; } - static int literal_size(Symbol *symbol); - static int literal_size(oop oop); - - // The following two are currently not used, but are needed anyway because some - // C++ compilers (MacOS and Solaris) force the instantiation of - // Hashtable::dump_table() even though we never call this function - // in the VM code. - static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} - static int literal_size(Klass *k) {Unimplemented(); return 0;} - - void dump_table(outputStream* st, const char *table_name); - private: static juint _seed; }; diff -r b23970014931 src/share/vm/utilities/hashtable.inline.hpp --- a/src/share/vm/utilities/hashtable.inline.hpp Wed Dec 17 14:38:47 2014 -0800 +++ b/src/share/vm/utilities/hashtable.inline.hpp Wed Feb 18 10:22:07 2015 -0600 @@ -37,6 +37,9 @@ // Initialize a table. template inline BasicHashtable::BasicHashtable(int table_size, int entry_size) { + if (HashtablesUseEvenSize == true) { + table_size += (table_size%2); + } // Called on startup, no locking needed initialize(table_size, entry_size, 0); _buckets = NEW_C_HEAP_ARRAY2(HashtableBucket, table_size, F, CURRENT_PC); @@ -57,6 +60,9 @@ template inline void BasicHashtable::initialize(int table_size, int entry_size, int number_of_entries) { +#ifdef PRINT_HASHTABLES_CREATION + fprintf(stderr, "BasicHashtable %p with size %d\n", this, (int)table_size); +#endif // Called on startup, no locking needed _table_size = table_size; _entry_size = entry_size; @@ -64,6 +70,32 @@ _first_free_entry = NULL; _end_block = NULL; _number_of_entries = number_of_entries; + +#ifndef PRODUCT +//#ifdef PRODUCT_TEST + for (int i=0; i<1024; i++) { + _debug_table_threads[i] = 0; + } + _debug_resize_fire = 0; + _debug_all_lookup_count = 0; + _debug_all_insertion_count = 0; + _debug_lookup_count = 0; + _debug_insertion_count = 0; + _debug_lookup_found_count = 0; + _debug_lookup_found_max_duration = 0; + _debug_lookup_found_total_duration = 0; + _debug_chain_found_maximum_length = 0; + _debug_chain_found_total_length = 0; + _debug_lookup_failed_count = 0; + _debug_lookup_failed_max_duration = 0; + _debug_lookup_failed_total_duration = 0; + _debug_chain_failed_maximum_length = 0; + _debug_chain_failed_total_length = 0; + _debug_resize_max_duration = 0; + _debug_resize_total_duration = 0; + _debug_resize_total_count = 0; +#endif + #ifdef ASSERT _lookup_count = 0; _lookup_length = 0;