changeset 23999:22eb7be3d99d

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
author lfoltan
date Mon, 14 Apr 2014 14:27:45 -0400
parents 418ac4fe9834
children 4ed166e87a9d
files hotspot/src/share/vm/classfile/defaultMethods.cpp hotspot/src/share/vm/classfile/verifier.cpp hotspot/src/share/vm/interpreter/linkResolver.cpp hotspot/src/share/vm/oops/arrayKlass.cpp hotspot/src/share/vm/oops/arrayKlass.hpp hotspot/src/share/vm/oops/instanceKlass.cpp hotspot/src/share/vm/oops/instanceKlass.hpp hotspot/src/share/vm/oops/klass.cpp hotspot/src/share/vm/oops/klass.hpp hotspot/src/share/vm/oops/klassVtable.cpp hotspot/src/share/vm/prims/jvm.cpp hotspot/src/share/vm/prims/nativeLookup.cpp
diffstat 12 files changed, 76 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/hotspot/src/share/vm/classfile/defaultMethods.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -390,20 +390,6 @@
   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 @@
       // 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) {
--- a/hotspot/src/share/vm/classfile/verifier.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/classfile/verifier.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * 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 @@
   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 @@
         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(
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -243,7 +243,8 @@
 // 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 @@
     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 @@
 // 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 @@
   // 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 @@
   // 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,
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -64,10 +64,10 @@
   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) {
--- a/hotspot/src/share/vm/oops/arrayKlass.hpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp	Mon Apr 14 14:27:45 2014 -0400
@@ -86,7 +86,7 @@
   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) {
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -1389,7 +1389,11 @@
 
 // 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 @@
 // 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 @@
 
 // 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 @@
   }
   // 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 @@
 // 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 @@
     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;
     }
   }
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp	Mon Apr 14 14:27:45 2014 -0400
@@ -490,14 +490,14 @@
   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 @@
   // 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:
--- a/hotspot/src/share/vm/oops/klass.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/oops/klass.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -129,7 +129,7 @@
 }
 
 
-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"
--- a/hotspot/src/share/vm/oops/klass.hpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/oops/klass.hpp	Mon Apr 14 14:27:45 2014 -0400
@@ -154,6 +154,8 @@
   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 @@
   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
--- a/hotspot/src/share/vm/oops/klassVtable.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * 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 @@
   // 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 @@
              && 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 @@
       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) {
--- a/hotspot/src/share/vm/prims/jvm.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/prims/jvm.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -1215,7 +1215,8 @@
   // 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");
--- a/hotspot/src/share/vm/prims/nativeLookup.cpp	Mon Apr 14 10:13:03 2014 -0400
+++ b/hotspot/src/share/vm/prims/nativeLookup.cpp	Mon Apr 14 14:27:45 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * 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 @@
 
   // 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");