changeset 5908:1f1bbeff94d1

8264079: Improve abstractions Summary: includes prerequisites from JDK-8010319 and JDK-8087342 Reviewed-by: bae
author akozlov
date Thu, 08 Jul 2021 11:58:38 +0300
parents 7909af5d627a
children 6a969eca033a
files src/share/vm/code/dependencies.cpp src/share/vm/code/dependencies.hpp src/share/vm/oops/instanceKlass.cpp src/share/vm/oops/instanceKlass.hpp src/share/vm/oops/klass.hpp
diffstat 5 files changed, 116 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/code/dependencies.cpp	Thu Apr 15 20:51:26 2021 +0300
+++ b/src/share/vm/code/dependencies.cpp	Thu Jul 08 11:58:38 2021 +0300
@@ -884,8 +884,8 @@
   klassOop find_witness_in(KlassDepChange& changes,
                            klassOop context_type,
                            bool participants_hide_witnesses);
+ public:
   bool witnessed_reabstraction_in_supers(klassOop k);
- public:
   klassOop find_witness_subtype(klassOop context_type, KlassDepChange* changes = NULL) {
     assert(doing_subtype_search(), "must set up a subtype search");
     // When looking for unexpected concrete types,
@@ -997,15 +997,8 @@
     }
   }
 
-  if (is_witness(new_type)) {
-    if (!ignore_witness(new_type)) {
-      return new_type;
-    }
-  } else if (!doing_subtype_search()) {
-    // No witness found, but is_witness() doesn't detect method re-abstraction in case of spot-checking.
-    if (witnessed_reabstraction_in_supers(new_type)) {
-      return new_type;
-    }
+  if (is_witness(new_type) && !ignore_witness(new_type)) {
+    return new_type;
   }
 
   return NULL;
@@ -1384,16 +1377,87 @@
   return num;
 }
 
+
+// Try to determine whether root method in some context is concrete or not based on the information about the unique method
+// in that context. It exploits the fact that concrete root method is always inherited into the context when there's a unique method.
+// Hence, unique method holder is always a supertype of the context class when root method is concrete.
+// Examples for concrete_root_method
+//      C (C.m uniqm)
+//      |
+//      CX (ctxk) uniqm is inherited into context.
+//
+//      CX (ctxk) (CX.m uniqm) here uniqm is defined in ctxk.
+// Examples for !concrete_root_method
+//      CX (ctxk)
+//      |
+//      C (C.m uniqm) uniqm is in subtype of ctxk.
+bool Dependencies::is_concrete_root_method(methodOop uniqm, klassOop ctxk) {
+  if (uniqm == NULL) {
+    return false; // match Dependencies::is_concrete_method() behavior
+  }
+  // Theoretically, the "direction" of subtype check matters here.
+  // On one hand, in case of interface context with a single implementor, uniqm can be in a superclass of the implementor which
+  // is not related to context class.
+  // On another hand, uniqm could come from an interface unrelated to the context class, but right now it is not possible:
+  // it is required that uniqm->method_holder() is the participant (uniqm->method_holder() <: ctxk), hence a default method
+  // can't be used as unique.
+  if (ctxk->klass_part()->is_interface()) {
+    klassOop implementor = instanceKlass::cast(ctxk)->implementor();
+    assert(implementor != ctxk, "single implementor only"); // should have been invalidated earlier
+    ctxk = implementor;
+  }
+  klassOop holder = uniqm->method_holder();
+  assert(!holder->is_interface(), "no default methods allowed");
+  assert(ctxk->klass_part()->is_subclass_of(holder) || holder->klass_part()->is_subclass_of(ctxk), "not related");
+  return ctxk->klass_part()->is_subclass_of(holder);
+}
+
 // If a class (or interface) has a unique concrete method uniqm, return NULL.
 // Otherwise, return a class that contains an interfering method.
 klassOop Dependencies::check_unique_concrete_method(klassOop ctxk, methodOop uniqm,
                                                     KlassDepChange* changes) {
-  // Here is a missing optimization:  If uniqm->is_final(),
-  // we don't really need to search beneath it for overrides.
-  // This is probably not important, since we don't use dependencies
-  // to track final methods.  (They can't be "definalized".)
   ClassHierarchyWalker wf(uniqm->method_holder(), uniqm);
-  return wf.find_witness_definer(ctxk, changes);
+  klassOop witness = wf.find_witness_definer(ctxk, changes);
+  if (witness != NULL) {
+    return witness;
+  }
+  if (!Dependencies::is_concrete_root_method(uniqm, ctxk) || changes != NULL) {
+    klassOop conck = find_witness_AME(ctxk, uniqm, changes);
+    if (conck != NULL) {
+      // Found a concrete subtype 'conck' which does not override abstract root method.
+      return conck;
+    }
+  }
+  return NULL;
+}
+
+// Search for AME.
+// There are two version of checks.
+//   1) Spot checking version(Classload time). Newly added class is checked for AME.
+//      Checks whether abstract/overpass method is inherited into/declared in newly added concrete class.
+//   2) Compile time analysis for abstract/overpass(abstract klass) root_m. The non uniqm subtrees are checked for concrete classes.
+klassOop Dependencies::find_witness_AME(klassOop ctxk, methodOop m, KlassDepChange* changes) {
+  if (m != NULL) {
+    if (changes != NULL) {
+      // Spot checking version.
+      ClassHierarchyWalker wf(m);
+      klassOop new_type = changes->new_type();
+      if (wf.witnessed_reabstraction_in_supers(new_type)) {
+        return new_type;
+      }
+    } else {
+      // Note: It is required that uniqm->method_holder() is the participant (see ClassHierarchyWalker::found_method()).
+      ClassHierarchyWalker wf(m->method_holder());
+      klassOop conck = wf.find_witness_subtype(ctxk);
+      if (conck != NULL) {
+        methodOop cm = instanceKlass::cast(conck)->find_instance_method(m->name(), m->signature(), Klass::skip_private);
+        if (!Dependencies::is_concrete_method(cm)) {
+          return conck;
+        }
+      }
+    }
+  }
+  return NULL;
 }
 
 // Find the set of all non-abstract methods under ctxk that match m.
@@ -1416,7 +1480,11 @@
       // (This can happen if m is inherited into ctxk and fm overrides it.)
       return NULL;
     }
+  } else if (Dependencies::find_witness_AME(ctxk, fm) != NULL) {
+    // Found a concrete subtype which does not override abstract root method.
+    return NULL;
   }
+  assert(Dependencies::is_concrete_root_method(fm, ctxk) == Dependencies::is_concrete_method(m, ctxk), "mismatch");
 #ifndef PRODUCT
   // Make sure the dependency mechanism will pass this discovery:
   if (VerifyDependencies && fm != NULL) {
--- a/src/share/vm/code/dependencies.hpp	Thu Apr 15 20:51:26 2021 +0300
+++ b/src/share/vm/code/dependencies.hpp	Thu Jul 08 11:58:38 2021 +0300
@@ -290,6 +290,9 @@
   static bool is_concrete_method(methodOop m);  // m is invocable
   static Klass* find_finalizable_subclass(Klass* k);
 
+  static bool is_concrete_root_method(methodOop uniqm, klassOop ctxk);
+  static klassOop find_witness_AME(klassOop ctxk, methodOop m, KlassDepChange* changes = NULL);
+
   // These versions of the concreteness queries work through the CI.
   // The CI versions are allowed to skew sometimes from the VM
   // (oop-based) versions.  The cost of such a difference is a
--- a/src/share/vm/oops/instanceKlass.cpp	Thu Apr 15 20:51:26 2021 +0300
+++ b/src/share/vm/oops/instanceKlass.cpp	Thu Jul 08 11:58:38 2021 +0300
@@ -1074,60 +1074,66 @@
 
 // find_instance_method looks up the name/signature in the local methods array
 // and skips over static methods
-methodOop instanceKlass::find_instance_method(Symbol* name, Symbol* signature) {
-  return instanceKlass::find_instance_method(methods(), name, signature);
+methodOop instanceKlass::find_instance_method(Symbol* name, Symbol* signature,
+                                              PrivateLookupMode private_mode)
+{
+  return instanceKlass::find_instance_method(methods(), name, signature, private_mode);
 }
 
 // find_instance_method looks up the name/signature in the local methods array
 // and skips over static methods
-methodOop instanceKlass::find_instance_method(objArrayOop methods, Symbol* name, Symbol* signature) {
-  methodOop meth = instanceKlass::find_method_impl(methods, name, signature, true);
+methodOop instanceKlass::find_instance_method(objArrayOop methods, Symbol* name, Symbol* signature,
+                                              PrivateLookupMode private_mode)
+{
+  methodOop meth = instanceKlass::find_method_impl(methods, name, signature, true, private_mode == skip_private);
   return meth;
 }
 
 // find_method looks up the name/signature in the local methods array
 methodOop instanceKlass::find_method(objArrayOop methods, Symbol* name, Symbol* signature) {
-  return instanceKlass::find_method_impl(methods, name, signature, false);
+  return instanceKlass::find_method_impl(methods, name, signature, false, false);
 }
 
-methodOop instanceKlass::find_method_impl(objArrayOop methods, Symbol* name, Symbol* signature, bool skipping_static) {
-  int hit = find_method_index(methods, name, signature, skipping_static);
+methodOop instanceKlass::find_method_impl(objArrayOop methods, Symbol* name, Symbol* signature, bool skipping_static, bool skipping_private) {
+  int hit = find_method_index(methods, name, signature, skipping_static, skipping_private);
   return hit >= 0 ? (methodOop) methods->obj_at(hit): NULL;
 }
 
-bool instanceKlass::method_matches(methodOop m, Symbol* signature, bool skipping_static) {
-    return (m->signature() == signature) && (!skipping_static || !m->is_static());
+bool instanceKlass::method_matches(methodOop m, Symbol* signature, bool skipping_static, bool skipping_private) {
+    return  ((m->signature() == signature) &&
+            (!skipping_static || !m->is_static()) &&
+            (!skipping_private || !m->is_private()));
 }
 
 // Used indirectly by find_method
 // find_method_index looks in the local methods array to return the index
 // of the matching name/signature
-int instanceKlass::find_method_index(objArrayOop methods, Symbol* name, Symbol* signature, bool skipping_static) {
+int instanceKlass::find_method_index(objArrayOop methods, Symbol* name, Symbol* signature, bool skipping_static, bool skipping_private) {
   int hit = binary_search(methods, name);
   if (hit != -1) {
     methodOop m = (methodOop) methods->obj_at(hit);
 
     // Do linear search to find matching signature.  First, quick check
     // for common case
-    if (method_matches(m, signature, skipping_static)) return hit;
+    if (method_matches(m, signature, skipping_static, skipping_private)) return hit;
     // search downwards through overloaded methods
     int i;
     for (i = hit - 1; i >= 0; --i) {
         methodOop m = (methodOop) methods->obj_at(i);
         assert(m->is_method(), "must be method");
         if (m->name() != name) break;
-        if (method_matches(m, signature, skipping_static)) return i;
+        if (method_matches(m, signature, skipping_static, skipping_private)) return i;
     }
     // search upwards
     for (i = hit + 1; i < methods->length(); ++i) {
         methodOop m = (methodOop) methods->obj_at(i);
         assert(m->is_method(), "must be method");
         if (m->name() != name) break;
-        if (method_matches(m, signature, skipping_static)) return i;
+        if (method_matches(m, signature, skipping_static, skipping_private)) return i;
     }
     // not found
 #ifdef ASSERT
-    int index = skipping_static ? -1 : linear_search(methods, name, signature);
+    int index = (skipping_static || skipping_private) ? -1 : linear_search(methods, name, signature);
     assert(index == -1, err_msg("binary search should have found entry %d", index));
 #endif
   }
--- a/src/share/vm/oops/instanceKlass.hpp	Thu Apr 15 20:51:26 2021 +0300
+++ b/src/share/vm/oops/instanceKlass.hpp	Thu Jul 08 11:58:38 2021 +0300
@@ -495,14 +495,17 @@
   static methodOop find_method(objArrayOop methods, Symbol* name, Symbol* signature);
 
   // find a local method, but skip static methods
-  methodOop find_instance_method(Symbol* name, Symbol* signature);
-  static methodOop find_instance_method(objArrayOop methods, Symbol* name, Symbol* signature);
+  methodOop find_instance_method(Symbol* name, Symbol* signature,
+                                 PrivateLookupMode private_mode = Klass::find_private);
+  static methodOop find_instance_method(objArrayOop methods, Symbol* name, Symbol* signature,
+                                        PrivateLookupMode private_mode = Klass::find_private);
 
   // true if method matches signature and conforms to skipping_X conditions.
-  static bool method_matches(methodOop m, Symbol* signature, bool skipping_static);
+  static bool method_matches(methodOop m, Symbol* signature, bool skipping_static, bool skipping_private);
 
   // find a local method index in default_methods (returns -1 if not found)
-  static int find_method_index(objArrayOop methods, Symbol* name, Symbol* signature, bool skipping_static);
+
+  static int find_method_index(objArrayOop methods, Symbol* name, Symbol* signature, bool skipping_static, bool skipping_private);
 
   // lookup operation (returns NULL if not found)
   methodOop uncached_lookup_method(Symbol* name, Symbol* signature) const;
@@ -986,7 +989,7 @@
   klassOop array_klass_impl(bool or_null, TRAPS);
 
   // find a local method (returns NULL if not found)
-  static methodOop find_method_impl(objArrayOop methods, Symbol* name, Symbol* signature, bool skipping_static);
+  static methodOop find_method_impl(objArrayOop methods, Symbol* name, Symbol* signature, bool skipping_static, bool skipping_private);
 
 public:
   // sharing support
--- a/src/share/vm/oops/klass.hpp	Thu Apr 15 20:51:26 2021 +0300
+++ b/src/share/vm/oops/klass.hpp	Thu Jul 08 11:58:38 2021 +0300
@@ -276,6 +276,8 @@
   }
 
  public:
+  enum PrivateLookupMode  { find_private,  skip_private };
+
   // Allocation
   const Klass_vtbl& vtbl_value() const { return *this; }  // used only on "example instances"
   static KlassHandle base_create_klass(KlassHandle& klass, int size, const Klass_vtbl& vtbl, TRAPS);