hotspot/src/share/vm/classfile/classLoaderData.cpp
changeset 14588 8ec26d2d9339
parent 13728 882756847a04
child 14824 42c57756cf23
child 14816 f2935b95cb54
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp	Tue Nov 27 14:11:37 2012 -0800
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp	Thu Nov 29 16:50:29 2012 -0500
@@ -65,13 +65,19 @@
 ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
 
 ClassLoaderData::ClassLoaderData(Handle h_class_loader) : _class_loader(h_class_loader()),
-  _metaspace(NULL), _unloading(false), _klasses(NULL),
-  _claimed(0), _jmethod_ids(NULL), _handles(NULL),
-  _deallocate_list(NULL), _next(NULL),
+  _metaspace(NULL), _unloading(false), _keep_alive(false), _klasses(NULL),
+  _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
+  _next(NULL), _dependencies(NULL),
   _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
     // empty
 }
 
+void ClassLoaderData::init_dependencies(TRAPS) {
+  // Create empty dependencies array to add to. CMS requires this to be
+  // an oop so that it can track additions via card marks.  We think.
+  _dependencies = (oop)oopFactory::new_objectArray(2, CHECK);
+}
+
 bool ClassLoaderData::claim() {
   if (_claimed == 1) {
     return false;
@@ -86,6 +92,7 @@
   }
 
   f->do_oop(&_class_loader);
+  f->do_oop(&_dependencies);
   _handles->oops_do(f);
   if (klass_closure != NULL) {
     classes_do(klass_closure);
@@ -110,70 +117,100 @@
   ClassLoaderData * const from_cld = this;
   ClassLoaderData * const to_cld = k->class_loader_data();
 
-  // Records dependency between non-null class loaders only.
-  if (to_cld->is_the_null_class_loader_data() || from_cld->is_the_null_class_loader_data()) {
+  // Dependency to the null class loader data doesn't need to be recorded
+  // because the null class loader data never goes away.
+  if (to_cld->is_the_null_class_loader_data()) {
     return;
   }
 
-  // Check that this dependency isn't from the same or parent class_loader
-  oop to = to_cld->class_loader();
-  oop from = from_cld->class_loader();
+  oop to;
+  if (to_cld->is_anonymous()) {
+    // Anonymous class dependencies are through the mirror.
+    to = k->java_mirror();
+  } else {
+    to = to_cld->class_loader();
 
-  oop curr = from;
-  while (curr != NULL) {
-    if (curr == to) {
-      return; // this class loader is in the parent list, no need to add it.
+    // If from_cld is anonymous, even if it's class_loader is a parent of 'to'
+    // we still have to add it.  The class_loader won't keep from_cld alive.
+    if (!from_cld->is_anonymous()) {
+      // Check that this dependency isn't from the same or parent class_loader
+      oop from = from_cld->class_loader();
+
+      oop curr = from;
+      while (curr != NULL) {
+        if (curr == to) {
+          return; // this class loader is in the parent list, no need to add it.
+        }
+        curr = java_lang_ClassLoader::parent(curr);
+      }
     }
-    curr = java_lang_ClassLoader::parent(curr);
   }
 
   // It's a dependency we won't find through GC, add it. This is relatively rare
-  from_cld->add_dependency(to_cld, CHECK);
+  // Must handle over GC point.
+  Handle dependency(THREAD, to);
+  from_cld->add_dependency(dependency, CHECK);
 }
 
-bool ClassLoaderData::has_dependency(ClassLoaderData* dependency) {
-  oop loader = dependency->class_loader();
 
-  // Get objArrayOop out of the class_loader oop and see if this dependency
-  // is there.  Don't safepoint!  These are all oops.
-  // Dependency list is (oop class_loader, objArrayOop next)
-  objArrayOop ok = (objArrayOop)java_lang_ClassLoader::dependencies(class_loader());
+void ClassLoaderData::add_dependency(Handle dependency, TRAPS) {
+  // Check first if this dependency is already in the list.
+  // Save a pointer to the last to add to under the lock.
+  objArrayOop ok = (objArrayOop)_dependencies;
+  objArrayOop last = NULL;
   while (ok != NULL) {
-    if (ok->obj_at(0) == loader) {
-      return true;
+    last = ok;
+    if (ok->obj_at(0) == dependency()) {
+      // Don't need to add it
+      return;
     }
     ok = (objArrayOop)ok->obj_at(1);
   }
-  return false;
+
+  // Create a new dependency node with fields for (class_loader or mirror, next)
+  objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
+  deps->obj_at_put(0, dependency());
+
+  // Must handle over more GC points
+  objArrayHandle new_dependency(THREAD, deps);
+
+  // Add the dependency under lock
+  assert (last != NULL, "dependencies should be initialized");
+  objArrayHandle last_handle(THREAD, last);
+  locked_add_dependency(last_handle, new_dependency);
 }
 
-void ClassLoaderData::add_dependency(ClassLoaderData* dependency, TRAPS) {
-  // Minimize the number of duplicates in the list.
-  if (has_dependency(dependency)) {
-    return;
-  }
+void ClassLoaderData::locked_add_dependency(objArrayHandle last_handle,
+                                            objArrayHandle new_dependency) {
 
-  // Create a new dependency node with fields for (class_loader, next)
-  objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
-  deps->obj_at_put(0, dependency->class_loader());
+  // Have to lock and put the new dependency on the end of the dependency
+  // array so the card mark for CMS sees that this dependency is new.
+  // Can probably do this lock free with some effort.
+  MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
+
+  oop loader_or_mirror = new_dependency->obj_at(0);
 
-  // Add this lock free, using compare and exchange, need barriers for GC
-  // Do the barrier first.
-  HeapWord* addr = java_lang_ClassLoader::dependencies_addr(class_loader());
-  while (true) {
-    oop old_dependency = java_lang_ClassLoader::dependencies(class_loader());
-    deps->obj_at_put(1, old_dependency);
-
-    oop newold = oopDesc::atomic_compare_exchange_oop((oop)deps, addr, old_dependency, true);
-    if (newold == old_dependency) {
-      update_barrier_set((void*)addr, (oop)deps);
-      // we won the race to add this dependency
-      break;
+  // Since the dependencies are only added, add to the end.
+  objArrayOop end = last_handle();
+  objArrayOop last = NULL;
+  while (end != NULL) {
+    last = end;
+    // check again if another thread added it to the end.
+    if (end->obj_at(0) == loader_or_mirror) {
+      // Don't need to add it
+      return;
     }
+    end = (objArrayOop)end->obj_at(1);
+  }
+  assert (last != NULL, "dependencies should be initialized");
+  // fill in the first element with the oop in new_dependency.
+  if (last->obj_at(0) == NULL) {
+    last->obj_at_put(0, new_dependency->obj_at(0));
+  } else {
+    last->obj_at_put(1, new_dependency());
   }
 }
 
-
 void ClassLoaderDataGraph::clear_claimed_marks() {
   for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
     cld->clear_claimed();
@@ -187,7 +224,7 @@
   // link the new item into the list
   _klasses = k;
 
-  if (TraceClassLoaderData && k->class_loader_data() != NULL) {
+  if (TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
     ResourceMark rm;
     tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
                   PTR_FORMAT " loader: " PTR_FORMAT " %s",
@@ -195,8 +232,7 @@
                   k->external_name(),
                   k->class_loader_data(),
                   k->class_loader(),
-                  k->class_loader() != NULL ? k->class_loader()->klass()->external_name() : "NULL"
-      );
+                  loader_name());
   }
 }
 
@@ -221,6 +257,38 @@
   ShouldNotReachHere();   // should have found this class!!
 }
 
+
+bool ClassLoaderData::is_anonymous() const {
+  Klass* k = _klasses;
+  return (_keep_alive || (k != NULL && k->oop_is_instance() &&
+          InstanceKlass::cast(k)->is_anonymous()));
+}
+
+void ClassLoaderData::unload() {
+  _unloading = true;
+
+  if (TraceClassLoaderData) {
+    ResourceMark rm;
+    tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, this);
+    tty->print(" for instance "PTR_FORMAT" of %s", class_loader(),
+               loader_name());
+    if (is_anonymous()) {
+      tty->print(" for anonymous class  "PTR_FORMAT " ", _klasses);
+    }
+    tty->print_cr("]");
+  }
+}
+
+bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
+  bool alive =
+    is_anonymous() ?
+       is_alive_closure->do_object_b(_klasses->java_mirror()) :
+       class_loader() == NULL || is_alive_closure->do_object_b(class_loader());
+  assert(!alive || claimed(), "must be claimed");
+  return alive;
+}
+
+
 ClassLoaderData::~ClassLoaderData() {
   Metaspace *m = _metaspace;
   if (m != NULL) {
@@ -263,8 +331,8 @@
     if (_metaspace != NULL) {
       return _metaspace;
     }
-    if (class_loader() == NULL) {
-      assert(this == the_null_class_loader_data(), "Must be");
+    if (this == the_null_class_loader_data()) {
+      assert (class_loader() == NULL, "Must be");
       size_t word_size = Metaspace::first_chunk_word_size();
       set_metaspace(new Metaspace(_metaspace_lock, word_size));
     } else {
@@ -325,12 +393,19 @@
   }
 }
 
-#ifndef PRODUCT
-void ClassLoaderData::print_loader(ClassLoaderData *loader_data, outputStream* out) {
-  oop class_loader = loader_data->class_loader();
-  out->print("%s", SystemDictionary::loader_name(class_loader));
+// These anonymous class loaders are to contain classes used for JSR292
+ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) {
+  // Add a new class loader data to the graph.
+  ClassLoaderData* cld = ClassLoaderDataGraph::add(NULL, loader, CHECK_NULL);
+  return cld;
 }
 
+const char* ClassLoaderData::loader_name() {
+  // Handles null class loader
+  return SystemDictionary::loader_name(class_loader());
+}
+
+#ifndef PRODUCT
 // Define to dump klasses
 #undef CLD_DUMP_KLASSES
 
@@ -338,8 +413,7 @@
   ResourceMark rm;
   out->print("ClassLoaderData CLD: "PTR_FORMAT", loader: "PTR_FORMAT", loader_klass: "PTR_FORMAT" %s {",
       this, class_loader(),
-      class_loader() != NULL ? class_loader()->klass() : NULL,
-      class_loader() != NULL ? class_loader()->klass()->external_name() : "NULL");
+      class_loader() != NULL ? class_loader()->klass() : NULL, loader_name());
   if (claimed()) out->print(" claimed ");
   if (is_unloading()) out->print(" unloading ");
   out->print(" handles " INTPTR_FORMAT, handles());
@@ -373,8 +447,8 @@
 void ClassLoaderData::verify() {
   oop cl = class_loader();
 
-  guarantee(this == class_loader_data(cl), "Must be the same");
-  guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data(), "must be");
+  guarantee(this == class_loader_data(cl) || is_anonymous(), "Must be the same");
+  guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || is_anonymous(), "must be");
 
   // Verify the integrity of the allocated space.
   if (metaspace_or_null() != NULL) {
@@ -387,6 +461,7 @@
   }
 }
 
+
 // GC root of class loader data created.
 ClassLoaderData* ClassLoaderDataGraph::_head = NULL;
 ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL;
@@ -395,19 +470,25 @@
 
 // Add a new class loader data node to the list.  Assign the newly created
 // ClassLoaderData into the java/lang/ClassLoader object as a hidden field
-ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader_data) {
+ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader, TRAPS) {
   // Not assigned a class loader data yet.
   // Create one.
   ClassLoaderData* *list_head = &_head;
   ClassLoaderData* next = _head;
-  ClassLoaderData* cld = new ClassLoaderData(loader_data);
+  ClassLoaderData* cld = new ClassLoaderData(loader);
 
-  // First, Atomically set it.
-  ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
-  if (old != NULL) {
-    delete cld;
-    // Returns the data.
-    return old;
+  if (cld_addr != NULL) {
+    // First, Atomically set it
+    ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
+    if (old != NULL) {
+      delete cld;
+      // Returns the data.
+      return old;
+    }
+  } else {
+    // Disallow unloading for this CLD during initialization if there is no
+    // class_loader oop to link this to.
+    cld->set_keep_alive(true);
   }
 
   // We won the race, and therefore the task of adding the data to the list of
@@ -417,16 +498,22 @@
     ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
     if (exchanged == next) {
       if (TraceClassLoaderData) {
+        ResourceMark rm;
         tty->print("[ClassLoaderData: ");
         tty->print("create class loader data "PTR_FORMAT, cld);
-        tty->print(" for instance "PTR_FORMAT" of ", cld->class_loader());
-        loader_data->klass()->name()->print_symbol_on(tty);
+        tty->print(" for instance "PTR_FORMAT" of %s", cld->class_loader(),
+                   cld->loader_name());
         tty->print_cr("]");
       }
+      // Create dependencies after the CLD is added to the list.  Otherwise,
+      // the GC GC will not find the CLD and the _class_loader field will
+      // not be updated.
+      cld->init_dependencies(CHECK_NULL);
       return cld;
     }
     next = exchanged;
   } while (true);
+
 }
 
 void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
@@ -435,9 +522,19 @@
   }
 }
 
+void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+  for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
+    if (cld->keep_alive()) {
+      cld->oops_do(f, klass_closure, must_claim);
+    }
+  }
+}
+
 void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
   if (ClassUnloading) {
     ClassLoaderData::the_null_class_loader_data()->oops_do(f, klass_closure, must_claim);
+    // keep any special CLDs alive.
+    ClassLoaderDataGraph::keep_alive_oops_do(f, klass_closure, must_claim);
   } else {
     ClassLoaderDataGraph::oops_do(f, klass_closure, must_claim);
   }
@@ -516,9 +613,10 @@
 }
 #endif // PRODUCT
 
+
 // Move class loader data from main list to the unloaded list for unloading
 // and deallocation later.
-bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive) {
+bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
   ClassLoaderData* data = _head;
   ClassLoaderData* prev = NULL;
   bool seen_dead_loader = false;
@@ -527,8 +625,7 @@
   bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
   MetadataOnStackMark md_on_stack;
   while (data != NULL) {
-    if (data->class_loader() == NULL || is_alive->do_object_b(data->class_loader())) {
-      assert(data->claimed(), "class loader data must have been claimed");
+    if (data->keep_alive() || data->is_alive(is_alive_closure)) {
       if (has_redefined_a_class) {
         data->classes_do(InstanceKlass::purge_previous_versions);
       }
@@ -539,13 +636,7 @@
     }
     seen_dead_loader = true;
     ClassLoaderData* dead = data;
-    dead->mark_for_unload();
-    if (TraceClassLoaderData) {
-      tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, dead);
-      tty->print(" for instance "PTR_FORMAT" of ", dead->class_loader());
-      dead->class_loader()->klass()->name()->print_symbol_on(tty);
-      tty->print_cr("]");
-    }
+    dead->unload();
     data = data->next();
     // Remove from loader list.
     if (prev != NULL) {