提交 8fdb95ad 编写于 作者: A acorn

4766230: Hotspot vtable inconsistencies cause core dumps. 6579515. 6582242.

Reviewed-by: kamg, coleenp
上级 579d807c
......@@ -2747,9 +2747,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
super_klass(),
methods(),
access_flags,
class_loader(),
class_name(),
local_interfaces());
class_loader,
class_name,
local_interfaces(),
CHECK_(nullHandle));
// Size of Java itable (in words)
itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces);
......
......@@ -1859,6 +1859,25 @@ bool instanceKlass::is_same_class_package(oop class_loader1, symbolOop class_nam
}
}
// Returns true iff super_method can be overridden by a method in targetclassname
// See JSL 3rd edition 8.4.6.1
// Assumes name-signature match
// "this" is instanceKlass of super_method which must exist
// note that the instanceKlass of the method in the targetclassname has not always been created yet
bool instanceKlass::is_override(methodHandle super_method, Handle targetclassloader, symbolHandle targetclassname, TRAPS) {
// Private methods can not be overridden
if (super_method->is_private()) {
return false;
}
// If super method is accessible, then override
if ((super_method->is_protected()) ||
(super_method->is_public())) {
return true;
}
// Package-private methods are not inherited outside of package
assert(super_method->is_package_private(), "must be package private");
return(is_same_class_package(targetclassloader(), targetclassname()));
}
jint instanceKlass::compute_modifier_flags(TRAPS) const {
klassOop k = as_klassOop();
......
......@@ -303,6 +303,9 @@ class instanceKlass: public Klass {
inner_class_next_offset = 4
};
// method override check
bool is_override(methodHandle super_method, Handle targetclassloader, symbolHandle targetclassname, TRAPS);
// package
bool is_same_class_package(klassOop class2);
bool is_same_class_package(oop classloader2, symbolOop classname2);
......
......@@ -45,9 +45,10 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length,
klassOop super,
objArrayOop methods,
AccessFlags class_flags,
oop classloader,
symbolOop classname,
objArrayOop local_interfaces
Handle classloader,
symbolHandle classname,
objArrayOop local_interfaces,
TRAPS
) {
No_Safepoint_Verifier nsv;
......@@ -64,9 +65,9 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length,
int len = methods->length();
for (int i = 0; i < len; i++) {
assert(methods->obj_at(i)->is_method(), "must be a methodOop");
methodOop m = methodOop(methods->obj_at(i));
methodHandle mh(THREAD, methodOop(methods->obj_at(i)));
if (needs_new_vtable_entry(m, super, classloader, classname, class_flags)) {
if (needs_new_vtable_entry(mh, super, classloader, classname, class_flags, THREAD)) {
vtable_length += vtableEntry::size(); // we need a new entry
}
}
......@@ -117,6 +118,7 @@ int klassVtable::initialize_from_super(KlassHandle super) {
superVtable->copy_vtable_to(table());
#ifndef PRODUCT
if (PrintVtables && Verbose) {
ResourceMark rm;
tty->print_cr("copy vtable from %s to %s size %d", sk->internal_name(), klass()->internal_name(), _length);
}
#endif
......@@ -159,13 +161,13 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
int len = methods()->length();
int initialized = super_vtable_len;
// update_super_vtable can stop for gc - ensure using handles
// update_inherited_vtable can stop for gc - ensure using handles
for (int i = 0; i < len; i++) {
HandleMark hm(THREAD);
assert(methods()->obj_at(i)->is_method(), "must be a methodOop");
methodHandle mh(THREAD, (methodOop)methods()->obj_at(i));
bool needs_new_entry = update_super_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK);
bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK);
if (needs_new_entry) {
put_method_at(mh(), initialized);
......@@ -177,7 +179,7 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
// add miranda methods; it will also update the value of initialized
fill_in_mirandas(initialized);
// In class hierachieswhere the accesibility is not increasing (i.e., going from private ->
// In class hierarchies where the accessibility is not increasing (i.e., going from private ->
// package_private -> publicprotected), the vtable might actually be smaller than our initial
// calculation.
assert(initialized <= _length, "vtable initialization failed");
......@@ -188,26 +190,49 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
}
}
// Interates through the vtables to find the broadest access level. This
// will always be monotomic for valid Java programs - but not neccesarily
// for incompatible class files.
klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) {
// This vtable is not implementing the specific method
if (i >= length()) return acc_private;
// Compute AccessType for current method. public or protected we are done.
methodOop m = method_at(i);
if (m->is_protected() || m->is_public()) return acc_publicprotected;
AccessType acc = m->is_package_private() ? acc_package_private : acc_private;
// Compute AccessType for method in super classes
klassOop super = klass()->super();
AccessType super_acc = (super != NULL) ? instanceKlass::cast(klass()->super())->vtable()->vtable_accessibility_at(i)
: acc_private;
// Called for cases where a method does not override its superclass' vtable entry
// For bytecodes not produced by javac together it is possible that a method does not override
// the superclass's method, but might indirectly override a super-super class's vtable entry
// If none found, return a null superk, else return the superk of the method this does override
instanceKlass* klassVtable::find_transitive_override(instanceKlass* initialsuper, methodHandle target_method,
int vtable_index, Handle target_loader, symbolHandle target_classname, Thread * THREAD) {
instanceKlass* superk = initialsuper;
while (superk != NULL && superk->super() != NULL) {
instanceKlass* supersuperklass = instanceKlass::cast(superk->super());
klassVtable* ssVtable = supersuperklass->vtable();
if (vtable_index < ssVtable->length()) {
methodOop super_method = ssVtable->method_at(vtable_index);
#ifndef PRODUCT
symbolHandle name(THREAD,target_method()->name());
symbolHandle signature(THREAD,target_method()->signature());
assert(super_method->name() == name() && super_method->signature() == signature(), "vtable entry name/sig mismatch");
#endif
if (supersuperklass->is_override(super_method, target_loader, target_classname, THREAD)) {
#ifndef PRODUCT
if (PrintVtables && Verbose) {
ResourceMark rm(THREAD);
tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ",
supersuperklass->internal_name(),
_klass->internal_name(), (target_method() != NULL) ?
target_method()->name()->as_C_string() : "<NULL>", vtable_index);
super_method->access_flags().print_on(tty);
tty->print("overriders flags: ");
target_method->access_flags().print_on(tty);
tty->cr();
}
#endif /*PRODUCT*/
break; // return found superk
}
} else {
// super class has no vtable entry here, stop transitive search
superk = (instanceKlass*)NULL;
break;
}
// if no override found yet, continue to search up
superk = instanceKlass::cast(superk->super());
}
// Merge
return (AccessType)MAX2((int)acc, (int)super_acc);
return superk;
}
......@@ -215,7 +240,8 @@ klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) {
// OR return true if a new vtable entry is required
// Only called for instanceKlass's, i.e. not for arrays
// If that changed, could not use _klass as handle for klass
bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS) {
bool klassVtable::update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len,
bool checkconstraints, TRAPS) {
ResourceMark rm;
bool allocate_new = true;
assert(klass->oop_is_instance(), "must be instanceKlass");
......@@ -242,58 +268,35 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_
}
// private methods always have a new entry in the vtable
// specification interpretation since classic has
// private methods not overriding
if (target_method()->is_private()) {
return allocate_new;
}
// search through the vtable and update overridden entries
// Since check_signature_loaders acquires SystemDictionary_lock
// which can block for gc, once we are in this loop, use handles, not
// unhandled oops unless they are reinitialized for each loop
// handles for name, signature, klass, target_method
// not for match_method, holder
// which can block for gc, once we are in this loop, use handles
// For classfiles built with >= jdk7, we now look for transitive overrides
symbolHandle name(THREAD,target_method()->name());
symbolHandle signature(THREAD,target_method()->signature());
Handle target_loader(THREAD, _klass->class_loader());
symbolHandle target_classname(THREAD, _klass->name());
for(int i = 0; i < super_vtable_len; i++) {
methodOop match_method = method_at(i);
methodOop super_method = method_at(i);
// Check if method name matches
if (match_method->name() == name() && match_method->signature() == signature()) {
if (super_method->name() == name() && super_method->signature() == signature()) {
instanceKlass* holder = (THREAD, instanceKlass::cast(match_method->method_holder()));
// get super_klass for method_holder for the found method
instanceKlass* super_klass = instanceKlass::cast(super_method->method_holder());
// Check if the match_method is accessable from current class
bool same_package_init = false;
bool same_package_flag = false;
bool simple_match = match_method->is_public() || match_method->is_protected();
if (!simple_match) {
same_package_init = true;
same_package_flag = holder->is_same_class_package(_klass->class_loader(), _klass->name());
simple_match = match_method->is_package_private() && same_package_flag;
}
// match_method is the superclass' method. Note we can't override
// and shouldn't access superclass' ACC_PRIVATE methods
// (although they have been copied into our vtable)
// A simple form of this statement is:
// if ( (match_method->is_public() || match_method->is_protected()) ||
// (match_method->is_package_private() && holder->is_same_class_package(klass->class_loader(), klass->name()))) {
//
// The complexity is introduced it avoid recomputing 'is_same_class_package' which is expensive.
if (simple_match) {
// Check if target_method and match_method has same level of accessibility. The accesibility of the
// match method is the "most-general" visibility of all entries at it's particular vtable index for
// all superclasses. This check must be done before we override the current entry in the vtable.
AccessType at = vtable_accessibility_at(i);
bool same_access = false;
if ( (at == acc_publicprotected && (target_method()->is_public() || target_method()->is_protected())
|| (at == acc_package_private && (target_method()->is_package_private() &&
(( same_package_init && same_package_flag) ||
(!same_package_init && holder->is_same_class_package(_klass->class_loader(), _klass->name()))))))) {
same_access = true;
}
if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) ||
((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION)
&& ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader,
target_classname, THREAD)) != (instanceKlass*)NULL))) {
// overriding, so no new entry
allocate_new = false;
if (checkconstraints) {
// Override vtable entry if passes loader constraint check
......@@ -302,15 +305,12 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_
// have already made any needed loader constraints.
// Since loader constraints are transitive, it is enough
// to link to the first super, and we get all the others.
symbolHandle signature(THREAD, target_method()->signature());
Handle this_loader(THREAD, _klass->class_loader());
instanceKlassHandle super_klass(THREAD, _klass->super());
Handle super_loader(THREAD, super_klass->class_loader());
if (this_loader() != super_loader()) {
if (target_loader() != super_loader()) {
ResourceMark rm(THREAD);
char* failed_type_name =
SystemDictionary::check_signature_loaders(signature, this_loader,
SystemDictionary::check_signature_loaders(signature, target_loader,
super_loader, true,
CHECK_(false));
if (failed_type_name != NULL) {
......@@ -320,7 +320,7 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_
"(instance of %s), have different Class objects for the type "
"%s used in the signature";
char* sig = target_method()->name_and_sig_as_C_string();
const char* loader1 = SystemDictionary::loader_name(this_loader());
const char* loader1 = SystemDictionary::loader_name(target_loader());
char* current = _klass->name()->as_C_string();
const char* loader2 = SystemDictionary::loader_name(super_loader());
size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) +
......@@ -331,59 +331,46 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_
THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false);
}
}
}
put_method_at(target_method(), i);
}
if (same_access) {
// target and match has same accessiblity - share entry
allocate_new = false;
target_method()->set_vtable_index(i);
put_method_at(target_method(), i);
target_method()->set_vtable_index(i);
#ifndef PRODUCT
if (PrintVtables && Verbose) {
AccessType targetacc;
if (target_method()->is_protected() ||
target_method()->is_public()) {
targetacc = acc_publicprotected;
} else {
targetacc = target_method()->is_package_private() ? acc_package_private : acc_private;
}
tty->print_cr("overriding with %s::%s index %d, original flags: %x overriders flags: %x",
_klass->internal_name(), (target_method() != NULL) ?
target_method()->name()->as_C_string() : "<NULL>", i,
at, targetacc);
}
if (PrintVtables && Verbose) {
tty->print("overriding with %s::%s index %d, original flags: ",
_klass->internal_name(), (target_method() != NULL) ?
target_method()->name()->as_C_string() : "<NULL>", i);
super_method->access_flags().print_on(tty);
tty->print("overriders flags: ");
target_method->access_flags().print_on(tty);
tty->cr();
}
#endif /*PRODUCT*/
} else {
} else {
// allocate_new = true; default. We might override one entry,
// but not override another. Once we override one, not need new
#ifndef PRODUCT
if (PrintVtables && Verbose) {
AccessType targetacc;
if (target_method()->is_protected() ||
target_method()->is_public()) {
targetacc = acc_publicprotected;
} else {
targetacc = target_method()->is_package_private() ? acc_package_private : acc_private;
}
tty->print_cr("override %s %s::%s at index %d, original flags: %x overriders flags: %x",
allocate_new ? "+ new" : "only",
_klass->internal_name(), (target_method() != NULL) ?
target_method()->name()->as_C_string() : "<NULL>", i,
at, targetacc);
}
#endif /*PRODUCT*/
if (PrintVtables && Verbose) {
tty->print("NOT overriding with %s::%s index %d, original flags: ",
_klass->internal_name(), (target_method() != NULL) ?
target_method()->name()->as_C_string() : "<NULL>", i);
super_method->access_flags().print_on(tty);
tty->print("overriders flags: ");
target_method->access_flags().print_on(tty);
tty->cr();
}
#endif /*PRODUCT*/
}
}
}
return allocate_new;
}
void klassVtable::put_method_at(methodOop m, int index) {
assert(m->is_oop_or_null(), "Not an oop or null");
#ifndef PRODUCT
if (PrintVtables && Verbose) {
ResourceMark rm;
tty->print_cr("adding %s::%s at index %d", _klass->internal_name(),
(m != NULL) ? m->name()->as_C_string() : "<NULL>", index);
}
......@@ -397,19 +384,23 @@ void klassVtable::put_method_at(methodOop m, int index) {
// by "classloader" and "classname".
// NOTE: The logic used here is very similar to the one used for computing
// the vtables indices for a method. We cannot directly use that function because,
// when the Universe is boostrapping, a super's vtable might not be initialized.
bool klassVtable::needs_new_vtable_entry(methodOop target_method,
// we allocate the instanceKlass at load time, and that requires that the
// superclass has been loaded.
// However, the vtable entries are filled in at link time, and therefore
// the superclass' vtable may not yet have been filled in.
bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
klassOop super,
oop classloader,
symbolOop classname,
AccessFlags class_flags) {
if ((class_flags.is_final() || target_method->is_final()) ||
Handle classloader,
symbolHandle classname,
AccessFlags class_flags,
TRAPS) {
if ((class_flags.is_final() || target_method()->is_final()) ||
// a final method never needs a new entry; final methods can be statically
// resolved and they have to be present in the vtable only if they override
// a super's method, in which case they re-use its entry
(target_method->is_static()) ||
(target_method()->is_static()) ||
// static methods don't need to be in vtable
(target_method->name() == vmSymbols::object_initializer_name())
(target_method()->name() == vmSymbols::object_initializer_name())
// <init> is never called dynamically-bound
) {
return false;
......@@ -421,55 +412,58 @@ bool klassVtable::needs_new_vtable_entry(methodOop target_method,
}
// private methods always have a new entry in the vtable
if (target_method->is_private()) {
// specification interpretation since classic has
// private methods not overriding
if (target_method()->is_private()) {
return true;
}
// search through the super class hierarchy to see if we need
// a new entry
symbolOop name = target_method->name();
symbolOop signature = target_method->signature();
ResourceMark rm;
symbolOop name = target_method()->name();
symbolOop signature = target_method()->signature();
klassOop k = super;
methodOop match_method = NULL;
methodOop super_method = NULL;
instanceKlass *holder = NULL;
methodOop recheck_method = NULL;
while (k != NULL) {
// lookup through the hierarchy for a method with matching name and sign.
match_method = instanceKlass::cast(k)->lookup_method(name, signature);
if (match_method == NULL) {
super_method = instanceKlass::cast(k)->lookup_method(name, signature);
if (super_method == NULL) {
break; // we still have to search for a matching miranda method
}
// get the class holding the matching method
holder = instanceKlass::cast(match_method->method_holder());
if (!match_method->is_static()) { // we want only instance method matches
if ((target_method->is_public() || target_method->is_protected()) &&
(match_method->is_public() || match_method->is_protected())) {
// target and match are public/protected; we do not need a new entry
return false;
}
if (target_method->is_package_private() &&
match_method->is_package_private() &&
holder->is_same_class_package(classloader, classname)) {
// target and match are P private; we do not need a new entry
// make sure you use that class for is_override
instanceKlass* superk = instanceKlass::cast(super_method->method_holder());
// we want only instance method matches
// pretend private methods are not in the super vtable
// since we do override around them: e.g. a.m pub/b.m private/c.m pub,
// ignore private, c.m pub does override a.m pub
// For classes that were not javac'd together, we also do transitive overriding around
// methods that have less accessibility
if ((!super_method->is_static()) &&
(!super_method->is_private())) {
if (superk->is_override(super_method, classloader, classname, THREAD)) {
return false;
// else keep looking for transitive overrides
}
}
k = holder->super(); // haven't found a match yet; continue to look
// Start with lookup result and continue to search up
k = superk->super(); // haven't found an override match yet; continue to look
}
// if the target method is public or protected it may have a matching
// miranda method in the super, whose entry it should re-use.
if (target_method->is_public() || target_method->is_protected()) {
instanceKlass *sk = instanceKlass::cast(super);
if (sk->has_miranda_methods()) {
if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) {
return false; // found a matching miranda; we do not need a new entry
}
// Actually, to handle cases that javac would not generate, we need
// this check for all access permissions.
instanceKlass *sk = instanceKlass::cast(super);
if (sk->has_miranda_methods()) {
if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) {
return false; // found a matching miranda; we do not need a new entry
}
}
return true; // found no match; we need a new entry
}
......@@ -884,7 +878,7 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
_klass->name()->as_C_string());
// Interate through all interfaces
// Iterate through all interfaces
int i;
for(i = 0; i < num_interfaces; i++) {
itableOffsetEntry* ioe = offset_entry(i);
......@@ -1012,6 +1006,7 @@ void klassItable::adjust_method_entries(methodOop* old_methods, methodOop* new_m
new_method->name()->as_C_string(),
new_method->signature()->as_C_string()));
}
break;
}
ime++;
}
......
......@@ -70,8 +70,9 @@ class klassVtable : public ResourceObj {
// conputes 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, oop classloader,
symbolOop classname, objArrayOop local_interfaces);
AccessFlags class_flags, Handle classloader,
symbolHandle classname, objArrayOop local_interfaces,
TRAPS);
// RedefineClasses() API support:
// If any entry of this vtable points to any of old_methods,
......@@ -111,14 +112,16 @@ class klassVtable : public ResourceObj {
protected:
friend class vtableEntry;
private:
enum { VTABLE_TRANSITIVE_OVERRIDE_VERSION = 51 } ;
void copy_vtable_to(vtableEntry* start);
int initialize_from_super(KlassHandle super);
int index_of(methodOop m, int len) const; // same as index_of, but search only up to len
void put_method_at(methodOop m, int index);
static bool needs_new_vtable_entry(methodOop m, klassOop super, oop classloader, symbolOop classname, AccessFlags access_flags);
AccessType vtable_accessibility_at(int i);
static bool needs_new_vtable_entry(methodHandle m, klassOop super, Handle classloader, symbolHandle classname, AccessFlags access_flags, TRAPS);
bool update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS);
bool update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS);
instanceKlass* find_transitive_override(instanceKlass* initialsuper, methodHandle target_method, int vtable_index,
Handle target_loader, symbolHandle target_classname, Thread* THREAD);
// support for miranda methods
bool is_miranda_entry_at(int i);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册