# HG changeset patch # User coleenp # Date 1302874588 14400 # Node ID 8ce62548170911511d900ab7a2f79b33ed34d013 # Parent a534c140904e3e003199509e7626eddb621d417d 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 diff -r a534c140904e -r 8ce625481709 src/share/vm/classfile/classFileParser.cpp --- 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++) { diff -r a534c140904e -r 8ce625481709 src/share/vm/classfile/systemDictionary.cpp --- 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) { diff -r a534c140904e -r 8ce625481709 src/share/vm/memory/dump.cpp --- 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(); diff -r a534c140904e -r 8ce625481709 src/share/vm/oops/instanceKlassKlass.cpp --- 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++) { diff -r a534c140904e -r 8ce625481709 src/share/vm/oops/klass.cpp --- 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); } diff -r a534c140904e -r 8ce625481709 src/share/vm/oops/klassVtable.cpp --- 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() { diff -r a534c140904e -r 8ce625481709 src/share/vm/oops/klassVtable.hpp --- 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,