8067713: Move clean_weak_method_links for redefinition out of class unloading
authorcoleenp
Thu, 18 Dec 2014 16:15:21 -0500
changeset 28365 ccf31849c7a4
parent 28364 aa22c7773cc4
child 28366 de66d915b262
8067713: Move clean_weak_method_links for redefinition out of class unloading Summary: Do this work during class redefinition, only verify clean during class unloading in debug mode. Reviewed-by: sspitsyn, roland, kbarrett
hotspot/src/share/vm/classfile/classLoaderData.cpp
hotspot/src/share/vm/oops/instanceKlass.cpp
hotspot/src/share/vm/oops/methodData.cpp
hotspot/src/share/vm/oops/methodData.hpp
hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp	Thu Dec 18 04:56:27 2014 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp	Thu Dec 18 16:15:21 2014 -0500
@@ -786,17 +786,12 @@
   MetadataOnStackMark md_on_stack(has_redefined_a_class);
 
   if (has_redefined_a_class) {
-    // purge_previous_versions also cleans weak method links. Because
-    // one method's MDO can reference another method from another
-    // class loader, we need to first clean weak method links for all
-    // class loaders here. Below, we can then free redefined methods
-    // for all class loaders.
     for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
       data->classes_do(InstanceKlass::purge_previous_versions);
     }
   }
 
-  // Need to purge the previous version before deallocating.
+  // Should purge the previous version before deallocating.
   free_deallocate_lists();
 }
 
@@ -834,8 +829,6 @@
 
 void ClassLoaderDataGraph::free_deallocate_lists() {
   for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
-    // We need to keep this data until InstanceKlass::purge_previous_version has been
-    // called on all alive classes. See the comment in ClassLoaderDataGraph::clean_metaspaces.
     cld->free_deallocate_list();
   }
 }
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Thu Dec 18 04:56:27 2014 +0000
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Thu Dec 18 16:15:21 2014 -0500
@@ -3543,11 +3543,12 @@
               ("purge: %s(%s): prev method @%d in version @%d is alive",
               method->name()->as_C_string(),
               method->signature()->as_C_string(), j, version));
+#ifdef ASSERT
             if (method->method_data() != NULL) {
-              // Clean out any weak method links for running methods
-              // (also should include not EMCP methods)
-              method->method_data()->clean_weak_method_links();
+              // Verify MethodData for running methods don't refer to old methods.
+              method->method_data()->verify_clean_weak_method_links();
             }
+#endif // ASSERT
           }
         }
       }
@@ -3561,15 +3562,17 @@
       deleted_count));
   }
 
-  // Clean MethodData of this class's methods so they don't refer to
+#ifdef ASSERT
+  // Verify clean MethodData for this class's methods, e.g. they don't refer to
   // old methods that are no longer running.
   Array<Method*>* methods = ik->methods();
   int num_methods = methods->length();
-  for (int index2 = 0; index2 < num_methods; ++index2) {
-    if (methods->at(index2)->method_data() != NULL) {
-      methods->at(index2)->method_data()->clean_weak_method_links();
+  for (int index = 0; index < num_methods; ++index) {
+    if (methods->at(index)->method_data() != NULL) {
+      methods->at(index)->method_data()->verify_clean_weak_method_links();
     }
   }
+#endif // ASSERT
 }
 
 void InstanceKlass::mark_newly_obsolete_methods(Array<Method*>* old_methods,
--- a/hotspot/src/share/vm/oops/methodData.cpp	Thu Dec 18 04:56:27 2014 +0000
+++ b/hotspot/src/share/vm/oops/methodData.cpp	Thu Dec 18 16:15:21 2014 -0500
@@ -1283,6 +1283,11 @@
          DataLayout::compute_size_in_bytes(SpeculativeTrapData::static_cell_count()),
          "code needs to be adjusted");
 
+  // Do not create one of these if method has been redefined.
+  if (m != NULL && m->is_old()) {
+    return NULL;
+  }
+
   DataLayout* dp  = extra_data_base();
   DataLayout* end = args_data_limit();
 
@@ -1554,9 +1559,7 @@
 class CleanExtraDataMethodClosure : public CleanExtraDataClosure {
 public:
   CleanExtraDataMethodClosure() {}
-  bool is_live(Method* m) {
-    return !m->is_old() || m->on_stack();
-  }
+  bool is_live(Method* m) { return !m->is_old(); }
 };
 
 
@@ -1658,3 +1661,16 @@
   clean_extra_data(&cl);
   verify_extra_data_clean(&cl);
 }
+
+#ifdef ASSERT
+void MethodData::verify_clean_weak_method_links() {
+  for (ProfileData* data = first_data();
+       is_valid(data);
+       data = next_data(data)) {
+    data->verify_clean_weak_method_links();
+  }
+
+  CleanExtraDataMethodClosure cl;
+  verify_extra_data_clean(&cl);
+}
+#endif // ASSERT
--- a/hotspot/src/share/vm/oops/methodData.hpp	Thu Dec 18 04:56:27 2014 +0000
+++ b/hotspot/src/share/vm/oops/methodData.hpp	Thu Dec 18 16:15:21 2014 -0500
@@ -254,6 +254,7 @@
 
   // Redefinition support
   void clean_weak_method_links();
+  DEBUG_ONLY(void verify_clean_weak_method_links();)
 };
 
 
@@ -511,6 +512,7 @@
 
   // Redefinition support
   virtual void clean_weak_method_links() {}
+  DEBUG_ONLY(virtual void verify_clean_weak_method_links() {})
 
   // CI translation: ProfileData can represent both MethodDataOop data
   // as well as CIMethodData data. This function is provided for translating
@@ -1971,6 +1973,7 @@
   }
 
   void set_method(Method* m) {
+    assert(!m->is_old(), "cannot add old methods");
     set_intptr_at(speculative_trap_method, (intptr_t)m);
   }
 
@@ -2480,6 +2483,7 @@
 
   void clean_method_data(BoolObjectClosure* is_alive);
   void clean_weak_method_links();
+  DEBUG_ONLY(void verify_clean_weak_method_links();)
   Mutex* extra_data_lock() { return &_extra_data_lock; }
 };
 
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp	Thu Dec 18 04:56:27 2014 +0000
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp	Thu Dec 18 16:15:21 2014 -0500
@@ -148,6 +148,10 @@
     _scratch_classes[i] = NULL;
   }
 
+  // Clean out MethodData pointing to old Method*
+  MethodDataCleaner clean_weak_method_links;
+  ClassLoaderDataGraph::classes_do(&clean_weak_method_links);
+
   // Disable any dependent concurrent compilations
   SystemDictionary::notice_modification();
 
@@ -155,8 +159,8 @@
   // See jvmtiExport.hpp for detailed explanation.
   JvmtiExport::set_has_redefined_a_class();
 
-// check_class() is optionally called for product bits, but is
-// always called for non-product bits.
+  // check_class() is optionally called for product bits, but is
+  // always called for non-product bits.
 #ifdef PRODUCT
   if (RC_TRACE_ENABLED(0x00004000)) {
 #endif
@@ -3445,6 +3449,22 @@
   }
 }
 
+// Clean method data for this class
+void VM_RedefineClasses::MethodDataCleaner::do_klass(Klass* k) {
+  if (k->oop_is_instance()) {
+    InstanceKlass *ik = InstanceKlass::cast(k);
+    // Clean MethodData of this class's methods so they don't refer to
+    // old methods that are no longer running.
+    Array<Method*>* methods = ik->methods();
+    int num_methods = methods->length();
+    for (int index = 0; index < num_methods; ++index) {
+      if (methods->at(index)->method_data() != NULL) {
+        methods->at(index)->method_data()->clean_weak_method_links();
+      }
+    }
+  }
+}
+
 void VM_RedefineClasses::update_jmethod_ids() {
   for (int j = 0; j < _matching_methods_length; ++j) {
     Method* old_method = _matching_old_methods[j];
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp	Thu Dec 18 04:56:27 2014 +0000
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp	Thu Dec 18 16:15:21 2014 -0500
@@ -511,6 +511,12 @@
     void do_klass(Klass* k);
   };
 
+  // Clean MethodData out
+  class MethodDataCleaner : public KlassClosure {
+   public:
+    MethodDataCleaner() {}
+    void do_klass(Klass* k);
+  };
  public:
   VM_RedefineClasses(jint class_count,
                      const jvmtiClassDefinition *class_defs,