changeset 49772:10041d61f50c

8190877: Better handling of abstract classes Reviewed-by: kvn, vlivanov, rhalade, ahgross, jwilhelm Contributed-by: tobias.hartmann@oracle.com
author thartmann
date Thu, 16 Nov 2017 12:03:42 -0500
parents 07556bea9c5c
children 3b0d5f4e1e30
files src/hotspot/share/code/dependencies.cpp
diffstat 1 files changed, 26 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/code/dependencies.cpp	Wed Nov 15 07:07:16 2017 -0800
+++ b/src/hotspot/share/code/dependencies.cpp	Thu Nov 16 12:03:42 2017 -0500
@@ -1117,6 +1117,14 @@
     _signature = NULL;
     initialize(participant);
   }
+  ClassHierarchyWalker(Klass* participants[], int num_participants) {
+    _name      = NULL;
+    _signature = NULL;
+    initialize(NULL);
+    for (int i = 0; i < num_participants; ++i) {
+      add_participant(participants[i]);
+    }
+  }
 
   // This is common code for two searches:  One for concrete subtypes,
   // the other for concrete method implementations and overrides.
@@ -1222,6 +1230,24 @@
       // Search class hierarchy first.
       Method* m = InstanceKlass::cast(k)->find_instance_method(_name, _signature);
       if (!Dependencies::is_concrete_method(m, k)) {
+        // Check for re-abstraction of method
+        if (!k->is_interface() && m != NULL && m->is_abstract()) {
+          // Found a matching abstract method 'm' in the class hierarchy.
+          // This is fine iff 'k' is an abstract class and all concrete subtypes
+          // of 'k' override 'm' and are participates of the current search.
+          ClassHierarchyWalker wf(_participants, _num_participants);
+          Klass* w = wf.find_witness_subtype(k);
+          if (w != NULL) {
+            Method* wm = InstanceKlass::cast(w)->find_instance_method(_name, _signature);
+            if (!Dependencies::is_concrete_method(wm, w)) {
+              // Found a concrete subtype 'w' which does not override abstract method 'm'.
+              // Bail out because 'm' could be called with 'w' as receiver (leading to an
+              // AbstractMethodError) and thus the method we are looking for is not unique.
+              _found_methods[_num_participants] = m;
+              return true;
+            }
+          }
+        }
         // Check interface defaults also, if any exist.
         Array<Method*>* default_methods = InstanceKlass::cast(k)->default_methods();
         if (default_methods == NULL)