< prev index next >

src/share/vm/classfile/classLoaderData.cpp

Print this page

        

@@ -47,10 +47,11 @@
 // the singleton class the_null_class_loader_data().
 
 #include "precompiled.hpp"
 #include "classfile/classLoaderData.hpp"
 #include "classfile/classLoaderData.inline.hpp"
+#include "classfile/dictionary.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/metadataOnStackMark.hpp"
 #include "classfile/moduleEntry.hpp"
 #include "classfile/packageEntry.hpp"
 #include "classfile/systemDictionary.hpp"

@@ -90,11 +91,11 @@
   // An anonymous class loader data doesn't have anything to keep
   // it from being unloaded during parsing of the anonymous class.
   // The null-class-loader should always be kept alive.
   _keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
   _metaspace(NULL), _unloading(false), _klasses(NULL),
-  _modules(NULL), _packages(NULL),
+  _modules(NULL), _packages(NULL), _dictionary(NULL),
   _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
   _next(NULL), _dependencies(dependencies),
   _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
                             Monitor::_safepoint_check_never)) {
 

@@ -447,14 +448,81 @@
                   p2i((void *)k->class_loader()),
                   loader_name());
   }
 }
 
+// Class iterator used by the compiler.  It gets some number of classes at
+// a safepoint to decay invocation counters on the methods.
+class ClassLoaderDataGraphKlassIteratorStatic {
+  ClassLoaderData* _current_loader_data = NULL;
+  Klass*           _current_class_entry = NULL;
+ public:
+
+  InstanceKlass* try_get_next_class() {
+    assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
+    while (true) {
+  
+      if (_current_class_entry != NULL) {
+        Klass* k = _current_class_entry;
+        _current_class_entry = _current_class_entry->next_link();
+  
+        if (k->is_instance_klass()) {
+          InstanceKlass* ik = InstanceKlass::cast(k);
+          // Only return loaded classes
+          if (ik->is_loaded()) {
+            return ik;
+          }
+        }
+      } else {
+        // Go to next CLD
+        if (_current_loader_data != NULL) {
+          _current_loader_data = _current_loader_data->next();
+        }
+        // Start at the beginning
+        if (_current_loader_data == NULL) {
+          _current_loader_data = ClassLoaderDataGraph::_head;
+        }
+  
+        _current_class_entry = _current_loader_data->klasses();
+      }
+    }
+    // never reached: an InstanceKlass should be returned above
+  }
+
+  // If the current class for the static iterator is a class being unloaded or
+  // deallocated, adjust the current class.
+  void adjust_saved_class(ClassLoaderData* cld) {
+    if (_current_loader_data == cld) {
+      _current_loader_data = cld->next();
+      if (_current_loader_data != NULL) {
+        _current_class_entry = _current_loader_data->klasses();
+      }  // else try_get_next_class will start at the head
+    }
+  }
+
+  void adjust_saved_class(Klass* klass) {
+    if (_current_class_entry == klass) {
+      _current_class_entry = klass->next_link();
+    }
+  }
+};
+
+static ClassLoaderDataGraphKlassIteratorStatic static_klass_iterator;
+
+InstanceKlass* ClassLoaderDataGraph::try_get_next_class() {
+  return static_klass_iterator.try_get_next_class();
+}
+
+
 // Remove a klass from the _klasses list for scratch_class during redefinition
 // or parsed class in the case of an error.
 void ClassLoaderData::remove_class(Klass* scratch_class) {
   assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
+
+  // Adjust global class iterator.
+  static_klass_iterator.adjust_saved_class(scratch_class);
+
   Klass* prev = NULL;
   for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
     if (k == scratch_class) {
       if (prev == NULL) {
         _klasses = k->next_link();

@@ -489,10 +557,13 @@
   }
 
   // In some rare cases items added to this list will not be freed elsewhere.
   // To keep it simple, just free everything in it here.
   free_deallocate_list();
+
+  // Clean up global class iterator for compiler
+  static_klass_iterator.adjust_saved_class(this);
 }
 
 ModuleEntryTable* ClassLoaderData::modules() {
   // Lazily create the module entry table at first request.
   // Lock-free access requires load_ptr_acquire.

@@ -511,10 +582,69 @@
     }
   }
   return modules;
 }
 
+const int _boot_loader_dictionary_size = 1009;
+const int _prime_array_size         = 8;                       // array of primes for system dictionary size
+const int _average_depth_goal       = 3;                       // goal for lookup length
+const int _primelist[_prime_array_size] = {107, 1009, 2017, 4049, 5051, 10103, 20201, 40423};
+
+// Calculate a "good" dictionary size based
+// on predicted or current loaded classes count *per class loader*
+// This size will be used for all class loaders if specified,
+// except boot loader and reflection class loaders
+static int calculate_dictionary_size(int classcount) {
+  static int newsize = 0;  // only calculate once
+  if (newsize != 0) {
+    return newsize;
+  }
+  newsize = _primelist[0];
+  if (classcount > 0 && !DumpSharedSpaces) {
+    int index = 0;
+    int desiredsize = classcount/_average_depth_goal;
+    for (newsize = _primelist[index]; index < _prime_array_size -1;
+         newsize = _primelist[++index]) {
+      if (desiredsize <=  newsize) {
+        break;
+      }
+    }
+  }
+  return newsize;
+}
+
+Dictionary* ClassLoaderData::dictionary_or_null() {
+  return load_ptr_acquire(&_dictionary);
+}
+
+Dictionary* ClassLoaderData::dictionary() {
+  assert(!is_anonymous(), "anonymous class loader data do not have a dictionary");
+  // Lazily create the dictionary, in the same way of lazily creating modules.
+  // Lock-free access requires load_ptr_acquire.
+  Dictionary* dictionary = load_ptr_acquire(&_dictionary);
+  if (dictionary == NULL) {
+    MutexLocker m1(SystemDictionary_lock);
+    // Check if _dictionary got allocated while we were waiting for this lock.
+    if ((dictionary = _dictionary) == NULL) {
+      int size;
+      if (this == the_null_class_loader_data()) {
+        size = _boot_loader_dictionary_size;
+      } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
+        size = 1;  // there's only one class in relection class loader and no initiated classes
+      } else {
+        size = calculate_dictionary_size(PredictedLoadedClassCount);
+      }
+      dictionary = new Dictionary(this, size);
+      // Ensure _dictionary is stable, since it is examined without a lock.
+      // Don't need metaspace_lock since SystemDictionary_lock is held.
+      OrderAccess::release_store_ptr(&_dictionary, dictionary);
+    }
+  }
+  return dictionary;
+}
+
+// Unloading support
 oop ClassLoaderData::keep_alive_object() const {
   assert_locked_or_safepoint(_metaspace_lock);
   assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
   return is_anonymous() ? _klasses->java_mirror() : class_loader();
 }

@@ -542,10 +672,17 @@
     // Destroy the table itself
     delete _modules;
     _modules = NULL;
   }
 
+  // Release C heap allocated hashtable for the dictionary
+  if (_dictionary != NULL) {
+    // Destroy the table itself
+    delete _dictionary;
+    _dictionary = NULL;
+  }
+
   if (_unnamed_module != NULL) {
     _unnamed_module->delete_unnamed_module();
     _unnamed_module = NULL;
   }
 

@@ -969,10 +1106,47 @@
     assert(cld->is_unloading(), "invariant");
     cld->classes_do(f);
   }
 }
 
+#define FOR_ALL_DICTIONARY(X) for (ClassLoaderData* X = _head; X != NULL; X = X->next()) \
+                                  if (X->dictionary_or_null() != NULL)
+
+// Walk classes in the loaded class dictionaries in various forms.
+void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) {
+  FOR_ALL_DICTIONARY(cld) {
+    cld->dictionary()->classes_do(f);
+  }
+}
+
+void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
+  FOR_ALL_DICTIONARY(cld) {
+    cld->dictionary()->classes_do(f, CHECK);
+  }
+}
+
+void ClassLoaderDataGraph::dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*)) {
+  FOR_ALL_DICTIONARY(cld) {
+    cld->dictionary()->all_entries_do(f);
+  }
+}
+
+void ClassLoaderDataGraph::verify_dictionary() {
+  FOR_ALL_DICTIONARY(cld) {
+    cld->dictionary()->verify();
+  }
+}
+
+void ClassLoaderDataGraph::print_dictionary(bool details) {
+  FOR_ALL_DICTIONARY(cld) {
+    tty->print("Dictionary for class loader ");
+    cld->print_value();
+    tty->cr();
+    cld->dictionary()->print(details);
+  }
+}
+
 GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
   assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
 
   GrowableArray<ClassLoaderData*>* array = new GrowableArray<ClassLoaderData*>();
 

@@ -1069,18 +1243,21 @@
     dead->set_next(_unloading);
     _unloading = dead;
   }
 
   if (seen_dead_loader) {
-    // Walk a ModuleEntry's reads and a PackageEntry's exports lists
-    // to determine if there are modules on those lists that are now
+    // Walk a Dictionary, ModuleEntry's reads, and a PackageEntry's exports
+    // lists to determine if there are modules on those lists that are now
     // dead and should be removed.  A module's life cycle is equivalent
     // to its defining class loader's life cycle.  Since a module is
     // considered dead if its class loader is dead, these walks must
     // occur after each class loader's aliveness is determined.
     data = _head;
     while (data != NULL) {
+      if (data->dictionary_or_null() != NULL) {
+        data->dictionary()->do_unloading();
+      }
       if (data->packages() != NULL) {
         data->packages()->purge_all_package_exports();
       }
       if (data->modules_defined()) {
         data->modules()->purge_all_module_reads();

@@ -1248,10 +1425,19 @@
     out->print("class loader " INTPTR_FORMAT " ", p2i(this));
     class_loader()->print_value_on(out);
   }
 }
 
+void ClassLoaderData::print_on(outputStream* out) const {
+  if (class_loader() == NULL) {
+    out->print("NULL class_loader");
+  } else {
+    out->print("class loader " INTPTR_FORMAT " ", p2i(this));
+    class_loader()->print_on(out);
+  }
+}
+
 #if INCLUDE_TRACE
 
 Ticks ClassLoaderDataGraph::_class_unload_time;
 
 void ClassLoaderDataGraph::class_unload_event(Klass* const k) {
< prev index next >