提交 6c43f36a 编写于 作者: C coleenp

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
上级 692b44d5
...@@ -2196,11 +2196,12 @@ typeArrayHandle ClassFileParser::sort_methods(objArrayHandle methods, ...@@ -2196,11 +2196,12 @@ typeArrayHandle ClassFileParser::sort_methods(objArrayHandle methods,
TRAPS) { TRAPS) {
typeArrayHandle nullHandle; typeArrayHandle nullHandle;
int length = methods()->length(); 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. // remember the original class file ordering.
// We temporarily use the vtable_index field in the methodOop to store the // We temporarily use the vtable_index field in the methodOop to store the
// class file index, so we can read in after calling qsort. // 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++) { for (int index = 0; index < length; index++) {
methodOop m = methodOop(methods->obj_at(index)); methodOop m = methodOop(methods->obj_at(index));
assert(!m->valid_vtable_index(), "vtable index should not be set"); assert(!m->valid_vtable_index(), "vtable index should not be set");
...@@ -2214,8 +2215,9 @@ typeArrayHandle ClassFileParser::sort_methods(objArrayHandle methods, ...@@ -2214,8 +2215,9 @@ typeArrayHandle ClassFileParser::sort_methods(objArrayHandle methods,
methods_parameter_annotations(), methods_parameter_annotations(),
methods_default_annotations()); methods_default_annotations());
// If JVMTI original method ordering is enabled construct int array remembering the original ordering // If JVMTI original method ordering or sharing is enabled construct int
if (JvmtiExport::can_maintain_original_method_order()) { // array remembering the original ordering
if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
typeArrayOop new_ordering = oopFactory::new_permanent_intArray(length, CHECK_(nullHandle)); typeArrayOop new_ordering = oopFactory::new_permanent_intArray(length, CHECK_(nullHandle));
typeArrayHandle method_ordering(THREAD, new_ordering); typeArrayHandle method_ordering(THREAD, new_ordering);
for (int index = 0; index < length; index++) { for (int index = 0; index < length; index++) {
......
...@@ -1255,6 +1255,16 @@ instanceKlassHandle SystemDictionary::load_shared_class( ...@@ -1255,6 +1255,16 @@ instanceKlassHandle SystemDictionary::load_shared_class(
methodHandle m(THREAD, methodOop(methods->obj_at(index2))); methodHandle m(THREAD, methodOop(methods->obj_at(index2)));
m()->link_method(m, CHECK_(nh)); 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) { if (TraceClassLoading) {
......
...@@ -623,24 +623,48 @@ public: ...@@ -623,24 +623,48 @@ public:
} }
}; };
// Itable indices are calculated based on methods array order // Vtable and Itable indices are calculated based on methods array
// (see klassItable::compute_itable_index()). Must reinitialize // order (see klassItable::compute_itable_index()). Must reinitialize
// after ALL methods of ALL classes have been reordered. // after ALL methods of ALL classes have been reordered.
// We assume that since checkconstraints is false, this method // We assume that since checkconstraints is false, this method
// cannot throw an exception. An exception here would be // cannot throw an exception. An exception here would be
// problematic since this is the VMThread, not a JavaThread. // problematic since this is the VMThread, not a JavaThread.
class ReinitializeItables: public ObjectClosure { class ReinitializeTables: public ObjectClosure {
private: private:
Thread* _thread; Thread* _thread;
public: 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) { void do_object(oop obj) {
if (obj->blueprint()->oop_is_instanceKlass()) { if (obj->blueprint()->oop_is_instanceKlass()) {
instanceKlass* ik = instanceKlass::cast((klassOop)obj); instanceKlass* ik = instanceKlass::cast((klassOop)obj);
ResourceMark rm(_thread);
ik->itable()->initialize_itable(false, _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 @@ public: ...@@ -1205,9 +1229,9 @@ public:
gen->ro_space()->object_iterate(&sort); gen->ro_space()->object_iterate(&sort);
gen->rw_space()->object_iterate(&sort); gen->rw_space()->object_iterate(&sort);
ReinitializeItables reinit_itables(THREAD); ReinitializeTables reinit_tables(THREAD);
gen->ro_space()->object_iterate(&reinit_itables); gen->ro_space()->object_iterate(&reinit_tables);
gen->rw_space()->object_iterate(&reinit_itables); gen->rw_space()->object_iterate(&reinit_tables);
tty->print_cr("done. "); tty->print_cr("done. ");
tty->cr(); tty->cr();
......
...@@ -690,7 +690,8 @@ void instanceKlassKlass::oop_verify_on(oop obj, outputStream* st) { ...@@ -690,7 +690,8 @@ void instanceKlassKlass::oop_verify_on(oop obj, outputStream* st) {
guarantee(method_ordering->is_perm(), "should be in permspace"); guarantee(method_ordering->is_perm(), "should be in permspace");
guarantee(method_ordering->is_typeArray(), "should be type array"); guarantee(method_ordering->is_typeArray(), "should be type array");
int length = method_ordering->length(); 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"); guarantee(length == methods->length(), "invalid method ordering length");
jlong sum = 0; jlong sum = 0;
for (j = 0; j < length; j++) { for (j = 0; j < length; j++) {
......
...@@ -453,6 +453,14 @@ void Klass::remove_unshareable_info() { ...@@ -453,6 +453,14 @@ void Klass::remove_unshareable_info() {
ik->unlink_class(); 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_subklass(NULL);
set_next_sibling(NULL); set_next_sibling(NULL);
} }
......
...@@ -645,6 +645,15 @@ void klassVtable::adjust_method_entries(methodOop* old_methods, methodOop* new_m ...@@ -645,6 +645,15 @@ void klassVtable::adjust_method_entries(methodOop* old_methods, methodOop* new_m
} }
} }
// 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 // Garbage collection
void klassVtable::oop_follow_contents() { void klassVtable::oop_follow_contents() {
......
...@@ -75,7 +75,15 @@ class klassVtable : public ResourceObj { ...@@ -75,7 +75,15 @@ class klassVtable : public ResourceObj {
void initialize_vtable(bool checkconstraints, TRAPS); // initialize vtable of a new klass 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, static void compute_vtable_size_and_num_mirandas(int &vtable_length, int &num_miranda_methods,
klassOop super, objArrayOop methods, klassOop super, objArrayOop methods,
AccessFlags class_flags, Handle classloader, AccessFlags class_flags, Handle classloader,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册