提交 2e25de79 编写于 作者: L lfoltan

8033150: invokestatic: IncompatibleClassChangeError trying to invoke static...

8033150: invokestatic: IncompatibleClassChangeError trying to invoke static method from a parent in presence of conflicting defaults.
Summary: A static method should be preferred during method resolution over an overpass, search the current class as well as its superclasses.
Reviewed-by: acorn, coleenp, kamg
上级 a75981b2
......@@ -390,20 +390,6 @@ class MethodFamily : public ResourceObj {
Symbol* get_exception_message() { return _exception_message; }
Symbol* get_exception_name() { return _exception_name; }
// Return true if the specified klass has a static method that matches
// the name and signature of the target method.
bool has_matching_static(InstanceKlass* root) {
if (_members.length() > 0) {
Pair<Method*,QualifiedState> entry = _members.at(0);
Method* impl = root->find_method(entry.first->name(),
entry.first->signature());
if ((impl != NULL) && impl->is_static()) {
return true;
}
}
return false;
}
// Either sets the target or the exception error message
void determine_target(InstanceKlass* root, TRAPS) {
if (has_target() || throws_exception()) {
......@@ -433,21 +419,19 @@ class MethodFamily : public ResourceObj {
// If the root klass has a static method with matching name and signature
// then do not generate an overpass method because it will hide the
// static method during resolution.
if (!has_matching_static(root)) {
if (qualified_methods.length() == 0) {
_exception_message = generate_no_defaults_message(CHECK);
} else {
assert(root != NULL, "Null root class");
_exception_message = generate_method_message(root->name(), qualified_methods.at(0), CHECK);
}
_exception_name = vmSymbols::java_lang_AbstractMethodError();
if (qualified_methods.length() == 0) {
_exception_message = generate_no_defaults_message(CHECK);
} else {
assert(root != NULL, "Null root class");
_exception_message = generate_method_message(root->name(), qualified_methods.at(0), CHECK);
}
_exception_name = vmSymbols::java_lang_AbstractMethodError();
// If only one qualified method is default, select that
} else if (num_defaults == 1) {
_selected_target = qualified_methods.at(default_index);
} else if (num_defaults > 1 && !has_matching_static(root)) {
} else if (num_defaults > 1) {
_exception_message = generate_conflicts_message(&qualified_methods,CHECK);
_exception_name = vmSymbols::java_lang_IncompatibleClassChangeError();
if (TraceDefaultMethods) {
......
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -1943,7 +1943,7 @@ bool ClassVerifier::is_protected_access(instanceKlassHandle this_class,
InstanceKlass* target_instance = InstanceKlass::cast(target_class);
fieldDescriptor fd;
if (is_method) {
Method* m = target_instance->uncached_lookup_method(field_name, field_sig);
Method* m = target_instance->uncached_lookup_method(field_name, field_sig, Klass::normal);
if (m != NULL && m->is_protected()) {
if (!this_class->is_same_class_package(m->method_holder())) {
return true;
......@@ -2280,7 +2280,8 @@ void ClassVerifier::verify_invoke_init(
ref_class_type.name(), CHECK_VERIFY(this));
Method* m = InstanceKlass::cast(ref_klass)->uncached_lookup_method(
vmSymbols::object_initializer_name(),
cp->signature_ref_at(bcs->get_index_u2()));
cp->signature_ref_at(bcs->get_index_u2()),
Klass::normal);
instanceKlassHandle mh(THREAD, m->method_holder());
if (m->is_protected() && !mh->is_same_class_package(_klass())) {
bool assignable = current_type().is_assignable_from(
......
......@@ -243,7 +243,8 @@ void LinkResolver::resolve_klass(KlassHandle& result, constantPoolHandle pool, i
// Look up method in klasses, including static methods
// Then look up local default methods
void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, bool checkpolymorphism, bool in_imethod_resolve, TRAPS) {
Method* result_oop = klass->uncached_lookup_method(name, signature);
// Ignore overpasses so statics can be found during resolution
Method* result_oop = klass->uncached_lookup_method(name, signature, Klass::skip_overpass);
// JDK 8, JVMS 5.4.3.4: Interface method resolution should
// ignore static and non-public methods of java.lang.Object,
......@@ -256,6 +257,12 @@ void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle kl
result_oop = NULL;
}
// Before considering default methods, check for an overpass in the
// current class if a method has not been found.
if (result_oop == NULL) {
result_oop = InstanceKlass::cast(klass())->find_method(name, signature);
}
if (result_oop == NULL) {
Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
if (default_methods != NULL) {
......@@ -276,11 +283,11 @@ void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle kl
// returns first instance method
// Looks up method in classes, then looks up local default methods
void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
Method* result_oop = klass->uncached_lookup_method(name, signature);
Method* result_oop = klass->uncached_lookup_method(name, signature, Klass::normal);
result = methodHandle(THREAD, result_oop);
while (!result.is_null() && result->is_static() && result->method_holder()->super() != NULL) {
KlassHandle super_klass = KlassHandle(THREAD, result->method_holder()->super());
result = methodHandle(THREAD, super_klass->uncached_lookup_method(name, signature));
result = methodHandle(THREAD, super_klass->uncached_lookup_method(name, signature, Klass::normal));
}
if (result.is_null()) {
......@@ -302,7 +309,7 @@ int LinkResolver::vtable_index_of_interface_method(KlassHandle klass,
// First check in default method array
if (!resolved_method->is_abstract() &&
(InstanceKlass::cast(klass())->default_methods() != NULL)) {
int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature);
int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false);
if (index >= 0 ) {
vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index);
}
......@@ -322,7 +329,7 @@ void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle
// Specify 'true' in order to skip default methods when searching the
// interfaces. Function lookup_method_in_klasses() already looked for
// the method in the default methods table.
result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name, signature, true));
result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name, signature, Klass::skip_defaults));
}
void LinkResolver::lookup_polymorphic_method(methodHandle& result,
......
......@@ -64,10 +64,10 @@ oop ArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) {
return NULL;
}
Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature) const {
Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const {
// There are no methods in an array klass but the super class (Object) has some
assert(super(), "super klass must be present");
return super()->uncached_lookup_method(name, signature);
return super()->uncached_lookup_method(name, signature, mode);
}
ArrayKlass::ArrayKlass(Symbol* name) {
......
......@@ -86,7 +86,7 @@ class ArrayKlass: public Klass {
objArrayOop allocate_arrayArray(int n, int length, TRAPS);
// Lookup operations
Method* uncached_lookup_method(Symbol* name, Symbol* signature) const;
Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
// Casting from Klass*
static ArrayKlass* cast(Klass* k) {
......
......@@ -1389,7 +1389,11 @@ static int binary_search(Array<Method*>* methods, Symbol* name) {
// find_method looks up the name/signature in the local methods array
Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const {
return InstanceKlass::find_method(methods(), name, signature);
return find_method_impl(name, signature, false);
}
Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const {
return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass);
}
// find_instance_method looks up the name/signature in the local methods array
......@@ -1406,40 +1410,49 @@ Method* InstanceKlass::find_instance_method(
// find_method looks up the name/signature in the local methods array
Method* InstanceKlass::find_method(
Array<Method*>* methods, Symbol* name, Symbol* signature) {
int hit = find_method_index(methods, name, signature);
return InstanceKlass::find_method_impl(methods, name, signature, false);
}
Method* InstanceKlass::find_method_impl(
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) {
int hit = find_method_index(methods, name, signature, skipping_overpass);
return hit >= 0 ? methods->at(hit): NULL;
}
// Used directly for default_methods to find the index into the
// default_vtable_indices, and indirectly by find_method
// find_method_index looks in the local methods array to return the index
// of the matching name/signature
// of the matching name/signature. If, overpass methods are being ignored,
// the search continues to find a potential non-overpass match. This capability
// is important during method resolution to prefer a static method, for example,
// over an overpass method.
int InstanceKlass::find_method_index(
Array<Method*>* methods, Symbol* name, Symbol* signature) {
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) {
int hit = binary_search(methods, name);
if (hit != -1) {
Method* m = methods->at(hit);
// Do linear search to find matching signature. First, quick check
// for common case
if (m->signature() == signature) return hit;
// for common case, ignoring overpasses if requested.
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return hit;
// search downwards through overloaded methods
int i;
for (i = hit - 1; i >= 0; --i) {
Method* m = methods->at(i);
assert(m->is_method(), "must be method");
if (m->name() != name) break;
if (m->signature() == signature) return i;
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i;
}
// search upwards
for (i = hit + 1; i < methods->length(); ++i) {
Method* m = methods->at(i);
assert(m->is_method(), "must be method");
if (m->name() != name) break;
if (m->signature() == signature) return i;
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i;
}
// not found
#ifdef ASSERT
int index = linear_search(methods, name, signature);
int index = skipping_overpass ? -1 : linear_search(methods, name, signature);
assert(index == -1, err_msg("binary search should have found entry %d", index));
#endif
}
......@@ -1465,16 +1478,16 @@ int InstanceKlass::find_method_by_name(
// uncached_lookup_method searches both the local class methods array and all
// superclasses methods arrays, skipping any overpass methods in superclasses.
Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature) const {
Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const {
MethodLookupMode lookup_mode = mode;
Klass* klass = const_cast<InstanceKlass*>(this);
bool dont_ignore_overpasses = true; // For the class being searched, find its overpasses.
while (klass != NULL) {
Method* method = InstanceKlass::cast(klass)->find_method(name, signature);
if ((method != NULL) && (dont_ignore_overpasses || !method->is_overpass())) {
Method* method = InstanceKlass::cast(klass)->find_method_impl(name, signature, (lookup_mode == skip_overpass));
if (method != NULL) {
return method;
}
klass = InstanceKlass::cast(klass)->super();
dont_ignore_overpasses = false; // Ignore overpass methods in all superclasses.
lookup_mode = skip_overpass; // Always ignore overpass methods in superclasses
}
return NULL;
}
......@@ -1489,7 +1502,7 @@ Method* InstanceKlass::lookup_method_in_ordered_interfaces(Symbol* name,
}
// Look up interfaces
if (m == NULL) {
m = lookup_method_in_all_interfaces(name, signature, false);
m = lookup_method_in_all_interfaces(name, signature, normal);
}
return m;
}
......@@ -1499,7 +1512,7 @@ Method* InstanceKlass::lookup_method_in_ordered_interfaces(Symbol* name,
// They should only be found in the initial InterfaceMethodRef
Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name,
Symbol* signature,
bool skip_default_methods) const {
MethodLookupMode mode) const {
Array<Klass*>* all_ifs = transitive_interfaces();
int num_ifs = all_ifs->length();
InstanceKlass *ik = NULL;
......@@ -1507,7 +1520,7 @@ Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name,
ik = InstanceKlass::cast(all_ifs->at(i));
Method* m = ik->lookup_method(name, signature);
if (m != NULL && m->is_public() && !m->is_static() &&
(!skip_default_methods || !m->is_default_method())) {
((mode != skip_defaults) || !m->is_default_method())) {
return m;
}
}
......
......@@ -490,14 +490,14 @@ class InstanceKlass: public Klass {
static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
// find a local method index in default_methods (returns -1 if not found)
static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature);
static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass);
// lookup operation (returns NULL if not found)
Method* uncached_lookup_method(Symbol* name, Symbol* signature) const;
Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
// lookup a method in all the interfaces that this class implements
// (returns NULL if not found)
Method* lookup_method_in_all_interfaces(Symbol* name, Symbol* signature, bool skip_default_methods) const;
Method* lookup_method_in_all_interfaces(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
// lookup a method in local defaults then in all interfaces
// (returns NULL if not found)
......@@ -1020,6 +1020,10 @@ private:
// Returns the array class with this class as element type
Klass* array_klass_impl(bool or_null, TRAPS);
// find a local method (returns NULL if not found)
Method* find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const;
static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass);
// Free CHeap allocated fields.
void release_C_heap_structures();
public:
......
......@@ -129,7 +129,7 @@ bool Klass::compute_is_subtype_of(Klass* k) {
}
Method* Klass::uncached_lookup_method(Symbol* name, Symbol* signature) const {
Method* Klass::uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const {
#ifdef ASSERT
tty->print_cr("Error: uncached_lookup_method called on a klass oop."
" Likely error: reflection method does not correctly"
......
......@@ -154,6 +154,8 @@ class Klass : public Metadata {
void* operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw();
public:
enum MethodLookupMode { normal, skip_overpass, skip_defaults };
bool is_klass() const volatile { return true; }
// super
......@@ -391,10 +393,10 @@ class Klass : public Metadata {
virtual void initialize(TRAPS);
// lookup operation for MethodLookupCache
friend class MethodLookupCache;
virtual Method* uncached_lookup_method(Symbol* name, Symbol* signature) const;
virtual Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
public:
Method* lookup_method(Symbol* name, Symbol* signature) const {
return uncached_lookup_method(name, signature);
return uncached_lookup_method(name, signature, normal);
}
// array class with specific rank
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -622,7 +622,7 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
// 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, false) != NULL) {
if (sk->lookup_method_in_all_interfaces(name, signature, Klass::normal) != NULL) {
return false; // found a matching miranda; we do not need a new entry
}
}
......@@ -698,7 +698,7 @@ bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods,
&& mo->method_holder() != NULL
&& mo->method_holder()->super() != NULL)
{
mo = mo->method_holder()->super()->uncached_lookup_method(name, signature);
mo = mo->method_holder()->super()->uncached_lookup_method(name, signature, Klass::normal);
}
if (mo == NULL || mo->access_flags().is_private() ) {
// super class hierarchy does not implement it or protection is different
......@@ -743,7 +743,7 @@ void klassVtable::add_new_mirandas_to_lists(
if (is_miranda(im, class_methods, default_methods, super)) { // is it a miranda at all?
InstanceKlass *sk = InstanceKlass::cast(super);
// check if it is a duplicate of a super's miranda
if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), false) == NULL) {
if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::normal) == NULL) {
new_mirandas->append(im);
}
if (all_mirandas != NULL) {
......
......@@ -1215,7 +1215,8 @@ JVM_ENTRY(jobject, JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject action, job
// get run() method
Method* m_oop = object->klass()->uncached_lookup_method(
vmSymbols::run_method_name(),
vmSymbols::void_object_signature());
vmSymbols::void_object_signature(),
Klass::normal);
methodHandle m (THREAD, m_oop);
if (m.is_null() || !m->is_method() || !m()->is_public() || m()->is_static()) {
THROW_MSG_0(vmSymbols::java_lang_InternalError(), "No run method");
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -408,7 +408,7 @@ address NativeLookup::base_library_lookup(const char* class_name, const char* me
// Find method and invoke standard lookup
methodHandle method (THREAD,
klass->uncached_lookup_method(m_name, s_name));
klass->uncached_lookup_method(m_name, s_name, Klass::normal));
address result = lookup(method, in_base_library, CATCH);
assert(in_base_library, "must be in basic library");
guarantee(result != NULL, "must be non NULL");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册