diff -r 51612f0c0a79 -r fc9d8850ab8b src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Thu Mar 15 13:37:13 2012 +0100 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Mar 23 11:16:05 2012 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -27,6 +27,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "memory/gcLocker.inline.hpp" #include "oops/oop.inline.hpp" @@ -37,34 +38,35 @@ // -------------------------------------------------------------------------- SymbolTable* SymbolTable::_the_table = NULL; +// Static arena for symbols that are not deallocated +Arena* SymbolTable::_arena = NULL; -Symbol* SymbolTable::allocate_symbol(const u1* name, int len, TRAPS) { +Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) { // Don't allow symbols to be created which cannot fit in a Symbol*. if (len > Symbol::max_length()) { THROW_MSG_0(vmSymbols::java_lang_InternalError(), "name is too long to represent"); } - Symbol* sym = new (len) Symbol(name, len); + Symbol* sym; + // Allocate symbols in the C heap when dumping shared spaces in case there + // are temporary symbols we can remove. + if (c_heap || DumpSharedSpaces) { + // refcount starts as 1 + sym = new (len, THREAD) Symbol(name, len, 1); + } else { + sym = new (len, arena(), THREAD) Symbol(name, len, -1); + } assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted"); return sym; } -bool SymbolTable::allocate_symbols(int names_count, const u1** names, - int* lengths, Symbol** syms, TRAPS) { - for (int i = 0; i< names_count; i++) { - if (lengths[i] > Symbol::max_length()) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), - "name is too long to represent"); - } +void SymbolTable::initialize_symbols(int arena_alloc_size) { + // Initialize the arena for global symbols, size passed in depends on CDS. + if (arena_alloc_size == 0) { + _arena = new Arena(); + } else { + _arena = new Arena(arena_alloc_size); } - - for (int i = 0; i< names_count; i++) { - int len = lengths[i]; - syms[i] = new (len) Symbol(names[i], len); - assert(syms[i] != NULL, "new should call vm_exit_out_of_memory if " - "C_HEAP is exhausted"); - } - return true; } // Call function for all symbols in the symbol table. @@ -83,8 +85,7 @@ int SymbolTable::symbols_counted = 0; // Remove unreferenced symbols from the symbol table -// This is done late during GC. This doesn't use the hash table unlink because -// it assumes that the literals are oops. +// This is done late during GC. void SymbolTable::unlink() { int removed = 0; int total = 0; @@ -156,7 +157,7 @@ if (s != NULL) return s; // Otherwise, add to symbol to table - return the_table()->basic_add(index, (u1*)name, len, hashValue, CHECK_NULL); + return the_table()->basic_add(index, (u1*)name, len, hashValue, true, CHECK_NULL); } Symbol* SymbolTable::lookup(const Symbol* sym, int begin, int end, TRAPS) { @@ -192,7 +193,7 @@ // 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); + return the_table()->basic_add(index, (u1*)buffer, len, hashValue, true, CHECK_NULL); } Symbol* SymbolTable::lookup_only(const char* name, int len, @@ -256,71 +257,81 @@ } } -void SymbolTable::add(constantPoolHandle cp, int names_count, +void SymbolTable::add(Handle class_loader, 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, + bool added = table->basic_add(class_loader, cp, names_count, names, lengths, cp_indices, hashValues, CHECK); if (!added) { // do it the hard way for (int i=0; ihash_to_index(hashValues[i]); - Symbol* sym = table->basic_add(index, (u1*)names[i], lengths[i], - hashValues[i], CHECK); + bool c_heap = class_loader() != NULL; + Symbol* sym = table->basic_add(index, (u1*)names[i], lengths[i], hashValues[i], c_heap, CHECK); cp->symbol_at_put(cp_indices[i], sym); } } } +Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) { + unsigned int hash; + Symbol* result = SymbolTable::lookup_only((char*)name, (int)strlen(name), hash); + if (result != NULL) { + return result; + } + SymbolTable* table = the_table(); + int index = table->hash_to_index(hash); + return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD); +} + Symbol* SymbolTable::basic_add(int index, u1 *name, int len, - unsigned int hashValue, TRAPS) { + unsigned int hashValue, bool c_heap, 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. - Symbol* sym = allocate_symbol(name, len, CHECK_NULL); - - // Allocation must be done before grabbing the SymbolTable_lock lock + // Grab SymbolTable_lock first. MutexLocker ml(SymbolTable_lock, THREAD); - assert(sym->equals((char*)name, len), "symbol must be properly initialized"); - // Since look-up was done lock-free, we need to check if another // thread beat us in the race to insert the symbol. - Symbol* test = lookup(index, (char*)name, len, hashValue); if (test != NULL) { - // A race occurred and another thread introduced the symbol, this one - // will be dropped and collected. - delete sym; + // A race occurred and another thread introduced the symbol. assert(test->refcount() != 0, "lookup should have incremented the count"); return test; } + // Create a new symbol. + Symbol* sym = allocate_symbol(name, len, c_heap, CHECK_NULL); + assert(sym->equals((char*)name, len), "symbol must be properly initialized"); + HashtableEntry* entry = new_entry(hashValue, sym); - sym->increment_refcount(); add_entry(index, entry); return sym; } -bool SymbolTable::basic_add(constantPoolHandle cp, int names_count, +// This version of basic_add adds symbols in batch from the constant pool +// parsing. +bool SymbolTable::basic_add(Handle class_loader, constantPoolHandle cp, + int names_count, const char** names, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS) { - Symbol* syms[symbol_alloc_batch_size]; - bool allocated = allocate_symbols(names_count, (const u1**)names, lengths, - syms, CHECK_false); - if (!allocated) { - return false; + + // Check symbol names are not too long. If any are too long, don't add any. + for (int i = 0; i< names_count; i++) { + if (lengths[i] > Symbol::max_length()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), + "name is too long to represent"); + } } - // Allocation must be done before grabbing the SymbolTable_lock lock + // Hold SymbolTable_lock through the symbol creation MutexLocker ml(SymbolTable_lock, THREAD); for (int i=0; iequals(names[i], lengths[i]), "symbol must be properly initialized"); // 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]); @@ -330,16 +341,17 @@ // will be dropped and collected. Use test instead. cp->symbol_at_put(cp_indices[i], test); assert(test->refcount() != 0, "lookup should have incremented the count"); - delete syms[i]; } else { - Symbol* sym = syms[i]; + // Create a new symbol. The null class loader is never unloaded so these + // are allocated specially in a permanent arena. + bool c_heap = class_loader() != NULL; + Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false)); + assert(sym->equals(names[i], lengths[i]), "symbol must be properly initialized"); // why wouldn't it be??? HashtableEntry* entry = new_entry(hashValues[i], sym); - sym->increment_refcount(); // increment refcount in external hashtable add_entry(index, entry); cp->symbol_at_put(cp_indices[i], sym); } } - return true; } @@ -406,6 +418,8 @@ ((float)symbols_removed/(float)symbols_counted)* 100); } tty->print_cr("Reference counts %5d", Symbol::_total_count); + tty->print_cr("Symbol arena size %5d used %5d", + arena()->size_in_bytes(), arena()->used()); tty->print_cr("Histogram of symbol length:"); tty->print_cr("%8s %5d", "Total ", total); tty->print_cr("%8s %5d", "Maximum", max_symbols);