duke@435: /* xdono@905: * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: # include "incls/_precompiled.incl" duke@435: # include "incls/_hashtable.cpp.incl" duke@435: duke@435: HS_DTRACE_PROBE_DECL4(hs_private, hashtable__new_entry, duke@435: void*, unsigned int, oop, void*); duke@435: duke@435: // This is a generic hashtable, designed to be used for the symbol duke@435: // and string tables. duke@435: // duke@435: // It is implemented as an open hash table with a fixed number of buckets. duke@435: // duke@435: // %note: duke@435: // - HashtableEntrys are allocated in blocks to reduce the space overhead. duke@435: duke@435: BasicHashtableEntry* BasicHashtable::new_entry(unsigned int hashValue) { duke@435: BasicHashtableEntry* entry; duke@435: duke@435: if (_free_list) { duke@435: entry = _free_list; duke@435: _free_list = _free_list->next(); duke@435: } else { jrose@867: if (_first_free_entry + _entry_size >= _end_block) { jrose@867: int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries)); duke@435: int len = _entry_size * block_size; jrose@867: len = 1 << log2_intptr(len); // round down to power of 2 jrose@867: assert(len >= _entry_size, ""); duke@435: _first_free_entry = NEW_C_HEAP_ARRAY(char, len); duke@435: _end_block = _first_free_entry + len; duke@435: } duke@435: entry = (BasicHashtableEntry*)_first_free_entry; duke@435: _first_free_entry += _entry_size; duke@435: } duke@435: jrose@867: assert(_entry_size % HeapWordSize == 0, ""); duke@435: entry->set_hash(hashValue); duke@435: return entry; duke@435: } duke@435: duke@435: duke@435: HashtableEntry* Hashtable::new_entry(unsigned int hashValue, oop obj) { duke@435: HashtableEntry* entry; duke@435: duke@435: entry = (HashtableEntry*)BasicHashtable::new_entry(hashValue); duke@435: entry->set_literal(obj); // clears literal string field duke@435: HS_DTRACE_PROBE4(hs_private, hashtable__new_entry, duke@435: this, hashValue, obj, entry); duke@435: return entry; duke@435: } duke@435: duke@435: duke@435: // GC support duke@435: duke@435: void Hashtable::unlink(BoolObjectClosure* is_alive) { duke@435: // Readers of the table are unlocked, so we should only be removing duke@435: // entries at a safepoint. duke@435: assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); duke@435: for (int i = 0; i < table_size(); ++i) { duke@435: for (HashtableEntry** p = bucket_addr(i); *p != NULL; ) { duke@435: HashtableEntry* entry = *p; duke@435: if (entry->is_shared()) { duke@435: break; duke@435: } duke@435: assert(entry->literal() != NULL, "just checking"); duke@435: if (is_alive->do_object_b(entry->literal())) { duke@435: p = entry->next_addr(); duke@435: } else { duke@435: *p = entry->next(); duke@435: free_entry(entry); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: void Hashtable::oops_do(OopClosure* f) { duke@435: for (int i = 0; i < table_size(); ++i) { duke@435: HashtableEntry** p = bucket_addr(i); duke@435: HashtableEntry* entry = bucket(i); duke@435: while (entry != NULL) { duke@435: f->do_oop(entry->literal_addr()); duke@435: duke@435: // Did the closure remove the literal from the table? duke@435: if (entry->literal() == NULL) { duke@435: assert(!entry->is_shared(), "immutable hashtable entry?"); duke@435: *p = entry->next(); duke@435: free_entry(entry); duke@435: } else { duke@435: p = entry->next_addr(); duke@435: } duke@435: entry = (HashtableEntry*)HashtableEntry::make_ptr(*p); duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: // Reverse the order of elements in the hash buckets. duke@435: duke@435: void BasicHashtable::reverse() { duke@435: duke@435: for (int i = 0; i < _table_size; ++i) { duke@435: BasicHashtableEntry* new_list = NULL; duke@435: BasicHashtableEntry* p = bucket(i); duke@435: while (p != NULL) { duke@435: BasicHashtableEntry* next = p->next(); duke@435: p->set_next(new_list); duke@435: new_list = p; duke@435: p = next; duke@435: } duke@435: *bucket_addr(i) = new_list; duke@435: } duke@435: } duke@435: duke@435: duke@435: // Copy the table to the shared space. duke@435: duke@435: void BasicHashtable::copy_table(char** top, char* end) { duke@435: duke@435: // Dump the hash table entries. duke@435: duke@435: intptr_t *plen = (intptr_t*)(*top); duke@435: *top += sizeof(*plen); duke@435: duke@435: int i; duke@435: for (i = 0; i < _table_size; ++i) { duke@435: for (BasicHashtableEntry** p = _buckets[i].entry_addr(); duke@435: *p != NULL; duke@435: p = (*p)->next_addr()) { duke@435: if (*top + entry_size() > end) { duke@435: warning("\nThe shared miscellaneous data space is not large " duke@435: "enough to \npreload requested classes. Use " duke@435: "-XX:SharedMiscDataSize= to increase \nthe initial " duke@435: "size of the miscellaneous data space.\n"); duke@435: exit(2); duke@435: } duke@435: *p = (BasicHashtableEntry*)memcpy(*top, *p, entry_size()); duke@435: *top += entry_size(); duke@435: } duke@435: } duke@435: *plen = (char*)(*top) - (char*)plen - sizeof(*plen); duke@435: duke@435: // Set the shared bit. duke@435: duke@435: for (i = 0; i < _table_size; ++i) { duke@435: for (BasicHashtableEntry* p = bucket(i); p != NULL; p = p->next()) { duke@435: p->set_shared(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: duke@435: // Reverse the order of elements in the hash buckets. duke@435: duke@435: void Hashtable::reverse(void* boundary) { duke@435: duke@435: for (int i = 0; i < table_size(); ++i) { duke@435: HashtableEntry* high_list = NULL; duke@435: HashtableEntry* low_list = NULL; duke@435: HashtableEntry* last_low_entry = NULL; duke@435: HashtableEntry* p = bucket(i); duke@435: while (p != NULL) { duke@435: HashtableEntry* next = p->next(); duke@435: if ((void*)p->literal() >= boundary) { duke@435: p->set_next(high_list); duke@435: high_list = p; duke@435: } else { duke@435: p->set_next(low_list); duke@435: low_list = p; duke@435: if (last_low_entry == NULL) { duke@435: last_low_entry = p; duke@435: } duke@435: } duke@435: p = next; duke@435: } duke@435: if (low_list != NULL) { duke@435: *bucket_addr(i) = low_list; duke@435: last_low_entry->set_next(high_list); duke@435: } else { duke@435: *bucket_addr(i) = high_list; duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: // Dump the hash table buckets. duke@435: duke@435: void BasicHashtable::copy_buckets(char** top, char* end) { duke@435: intptr_t len = _table_size * sizeof(HashtableBucket); duke@435: *(intptr_t*)(*top) = len; duke@435: *top += sizeof(intptr_t); duke@435: duke@435: *(intptr_t*)(*top) = _number_of_entries; duke@435: *top += sizeof(intptr_t); duke@435: duke@435: if (*top + len > end) { duke@435: warning("\nThe shared miscellaneous data space is not large " duke@435: "enough to \npreload requested classes. Use " duke@435: "-XX:SharedMiscDataSize= to increase \nthe initial " duke@435: "size of the miscellaneous data space.\n"); duke@435: exit(2); duke@435: } duke@435: _buckets = (HashtableBucket*)memcpy(*top, _buckets, len); duke@435: *top += len; duke@435: } duke@435: duke@435: duke@435: #ifndef PRODUCT duke@435: duke@435: void Hashtable::print() { duke@435: ResourceMark rm; duke@435: duke@435: for (int i = 0; i < table_size(); i++) { duke@435: HashtableEntry* entry = bucket(i); duke@435: while(entry != NULL) { duke@435: tty->print("%d : ", i); duke@435: entry->literal()->print(); duke@435: tty->cr(); duke@435: entry = entry->next(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: void BasicHashtable::verify() { duke@435: int count = 0; duke@435: for (int i = 0; i < table_size(); i++) { duke@435: for (BasicHashtableEntry* p = bucket(i); p != NULL; p = p->next()) { duke@435: ++count; duke@435: } duke@435: } duke@435: assert(count == number_of_entries(), "number of hashtable entries incorrect"); duke@435: } duke@435: duke@435: duke@435: #endif // PRODUCT duke@435: duke@435: duke@435: #ifdef ASSERT duke@435: duke@435: void BasicHashtable::verify_lookup_length(double load) { duke@435: if ((double)_lookup_length / (double)_lookup_count > load * 2.0) { duke@435: warning("Performance bug: SystemDictionary lookup_count=%d " duke@435: "lookup_length=%d average=%lf load=%f", duke@435: _lookup_count, _lookup_length, duke@435: (double) _lookup_length / _lookup_count, load); duke@435: } duke@435: } duke@435: duke@435: #endif