hotspot/src/share/vm/classfile/symbolTable.cpp
changeset 12263 d20640f4f8fe
parent 11480 1bf714e8adb4
child 13087 673ea6efaf18
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp	Thu Mar 15 13:37:13 2012 +0100
+++ b/hotspot/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; i<names_count; i++) {
       int index = table->hash_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<Symbol*>* 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; i<names_count; i++) {
-    assert(syms[i]->equals(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<Symbol*>* 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);