changeset 2342:8ce625481709

7032407: Crash in LinkResolver::runtime_resolve_virtual_method() Summary: Make CDS reorder vtables so that dump time vtables match run time order, so when redefine classes reinitializes them, they aren't in the wrong order. Reviewed-by: dcubed, acorn
author coleenp
date Fri, 15 Apr 2011 09:36:28 -0400
parents a534c140904e
children fcc932c8238c
files src/share/vm/classfile/classFileParser.cpp src/share/vm/classfile/systemDictionary.cpp src/share/vm/memory/dump.cpp src/share/vm/oops/instanceKlassKlass.cpp src/share/vm/oops/klass.cpp src/share/vm/oops/klassVtable.cpp src/share/vm/oops/klassVtable.hpp
diffstat 7 files changed, 75 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/classfile/classFileParser.cpp	Thu Apr 14 23:06:33 2011 -0400
+++ b/src/share/vm/classfile/classFileParser.cpp	Fri Apr 15 09:36:28 2011 -0400
@@ -2196,11 +2196,12 @@
                                               TRAPS) {
   typeArrayHandle nullHandle;
   int length = methods()->length();
-  // If JVMTI original method ordering is enabled we have to
+  // If JVMTI original method ordering or sharing is enabled we have to
   // remember the original class file ordering.
   // We temporarily use the vtable_index field in the methodOop to store the
   // class file index, so we can read in after calling qsort.
-  if (JvmtiExport::can_maintain_original_method_order()) {
+  // Put the method ordering in the shared archive.
+  if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
     for (int index = 0; index < length; index++) {
       methodOop m = methodOop(methods->obj_at(index));
       assert(!m->valid_vtable_index(), "vtable index should not be set");
@@ -2214,8 +2215,9 @@
                               methods_parameter_annotations(),
                               methods_default_annotations());
 
-  // If JVMTI original method ordering is enabled construct int array remembering the original ordering
-  if (JvmtiExport::can_maintain_original_method_order()) {
+  // If JVMTI original method ordering or sharing is enabled construct int
+  // array remembering the original ordering
+  if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
     typeArrayOop new_ordering = oopFactory::new_permanent_intArray(length, CHECK_(nullHandle));
     typeArrayHandle method_ordering(THREAD, new_ordering);
     for (int index = 0; index < length; index++) {
--- a/src/share/vm/classfile/systemDictionary.cpp	Thu Apr 14 23:06:33 2011 -0400
+++ b/src/share/vm/classfile/systemDictionary.cpp	Fri Apr 15 09:36:28 2011 -0400
@@ -1255,6 +1255,16 @@
         methodHandle m(THREAD, methodOop(methods->obj_at(index2)));
         m()->link_method(m, CHECK_(nh));
       }
+      if (JvmtiExport::has_redefined_a_class()) {
+        // Reinitialize vtable because RedefineClasses may have changed some
+        // entries in this vtable for super classes so the CDS vtable might
+        // point to old or obsolete entries.  RedefineClasses doesn't fix up
+        // vtables in the shared system dictionary, only the main one.
+        // It also redefines the itable too so fix that too.
+        ResourceMark rm(THREAD);
+        ik->vtable()->initialize_vtable(false, CHECK_(nh));
+        ik->itable()->initialize_itable(false, CHECK_(nh));
+      }
     }
 
     if (TraceClassLoading) {
--- a/src/share/vm/memory/dump.cpp	Thu Apr 14 23:06:33 2011 -0400
+++ b/src/share/vm/memory/dump.cpp	Fri Apr 15 09:36:28 2011 -0400
@@ -623,24 +623,48 @@
   }
 };
 
-// Itable indices are calculated based on methods array order
-// (see klassItable::compute_itable_index()).  Must reinitialize
+// Vtable and Itable indices are calculated based on methods array
+// order (see klassItable::compute_itable_index()).  Must reinitialize
 // after ALL methods of ALL classes have been reordered.
 // We assume that since checkconstraints is false, this method
 // cannot throw an exception.  An exception here would be
 // problematic since this is the VMThread, not a JavaThread.
 
-class ReinitializeItables: public ObjectClosure {
+class ReinitializeTables: public ObjectClosure {
 private:
   Thread* _thread;
 
 public:
-  ReinitializeItables(Thread* thread) : _thread(thread) {}
+  ReinitializeTables(Thread* thread) : _thread(thread) {}
+
+  // Initialize super vtable first, check if already initialized to avoid
+  // quadradic behavior.  The vtable is cleared in remove_unshareable_info.
+  void reinitialize_vtables(klassOop k) {
+    if (k->blueprint()->oop_is_instanceKlass()) {
+      instanceKlass* ik = instanceKlass::cast(k);
+      if (ik->vtable()->is_initialized()) return;
+      if (ik->super() != NULL) {
+        reinitialize_vtables(ik->super());
+      }
+      ik->vtable()->initialize_vtable(false, _thread);
+    }
+  }
 
   void do_object(oop obj) {
     if (obj->blueprint()->oop_is_instanceKlass()) {
       instanceKlass* ik = instanceKlass::cast((klassOop)obj);
+      ResourceMark rm(_thread);
       ik->itable()->initialize_itable(false, _thread);
+      reinitialize_vtables((klassOop)obj);
+#ifdef ASSERT
+      ik->vtable()->verify(tty, true);
+#endif // ASSERT
+    } else if (obj->blueprint()->oop_is_arrayKlass()) {
+      // The vtable for array klasses are that of its super class,
+      // ie. java.lang.Object.
+      arrayKlass* ak = arrayKlass::cast((klassOop)obj);
+      if (ak->vtable()->is_initialized()) return;
+      ak->vtable()->initialize_vtable(false, _thread);
     }
   }
 };
@@ -1205,9 +1229,9 @@
     gen->ro_space()->object_iterate(&sort);
     gen->rw_space()->object_iterate(&sort);
 
-    ReinitializeItables reinit_itables(THREAD);
-    gen->ro_space()->object_iterate(&reinit_itables);
-    gen->rw_space()->object_iterate(&reinit_itables);
+    ReinitializeTables reinit_tables(THREAD);
+    gen->ro_space()->object_iterate(&reinit_tables);
+    gen->rw_space()->object_iterate(&reinit_tables);
     tty->print_cr("done. ");
     tty->cr();
 
--- a/src/share/vm/oops/instanceKlassKlass.cpp	Thu Apr 14 23:06:33 2011 -0400
+++ b/src/share/vm/oops/instanceKlassKlass.cpp	Fri Apr 15 09:36:28 2011 -0400
@@ -690,7 +690,8 @@
     guarantee(method_ordering->is_perm(),              "should be in permspace");
     guarantee(method_ordering->is_typeArray(),         "should be type array");
     int length = method_ordering->length();
-    if (JvmtiExport::can_maintain_original_method_order()) {
+    if (JvmtiExport::can_maintain_original_method_order() ||
+        (UseSharedSpaces && length != 0)) {
       guarantee(length == methods->length(),           "invalid method ordering length");
       jlong sum = 0;
       for (j = 0; j < length; j++) {
--- a/src/share/vm/oops/klass.cpp	Thu Apr 14 23:06:33 2011 -0400
+++ b/src/share/vm/oops/klass.cpp	Fri Apr 15 09:36:28 2011 -0400
@@ -453,6 +453,14 @@
       ik->unlink_class();
     }
   }
+  // Clear the Java vtable if the oop has one.
+  // The vtable isn't shareable because it's in the wrong order wrt the methods
+  // once the method names get moved and resorted.
+  klassVtable* vt = vtable();
+  if (vt != NULL) {
+    assert(oop_is_instance() || oop_is_array(), "nothing else has vtable");
+    vt->clear_vtable();
+  }
   set_subklass(NULL);
   set_next_sibling(NULL);
 }
--- a/src/share/vm/oops/klassVtable.cpp	Thu Apr 14 23:06:33 2011 -0400
+++ b/src/share/vm/oops/klassVtable.cpp	Fri Apr 15 09:36:28 2011 -0400
@@ -645,6 +645,15 @@
   }
 }
 
+// CDS/RedefineClasses support - clear vtables so they can be reinitialized
+void klassVtable::clear_vtable() {
+  for (int i = 0; i < _length; i++) table()[i].clear();
+}
+
+bool klassVtable::is_initialized() {
+  return _length == 0 || table()[0].method() != NULL;
+}
+
 
 // Garbage collection
 void klassVtable::oop_follow_contents() {
--- a/src/share/vm/oops/klassVtable.hpp	Thu Apr 14 23:06:33 2011 -0400
+++ b/src/share/vm/oops/klassVtable.hpp	Fri Apr 15 09:36:28 2011 -0400
@@ -75,7 +75,15 @@
 
   void initialize_vtable(bool checkconstraints, TRAPS);   // initialize vtable of a new klass
 
-  // conputes vtable length (in words) and the number of miranda methods
+  // CDS/RedefineClasses support - clear vtables so they can be reinitialized
+  // at dump time.  Clearing gives us an easy way to tell if the vtable has
+  // already been reinitialized at dump time (see dump.cpp).  Vtables can
+  // be initialized at run time by RedefineClasses so dumping the right order
+  // is necessary.
+  void clear_vtable();
+  bool is_initialized();
+
+  // computes vtable length (in words) and the number of miranda methods
   static void compute_vtable_size_and_num_mirandas(int &vtable_length, int &num_miranda_methods,
                                                    klassOop super, objArrayOop methods,
                                                    AccessFlags class_flags, Handle classloader,