< prev index next >

src/hotspot/share/interpreter/linkResolver.cpp

Print this page
rev 49011 : 8197405: Improve messages of AbstractMethodErrors and IncompatibleClassChangeErrors.
Reviewed-by: coleenp, dholmes

@@ -1341,22 +1341,21 @@
   // a missing receiver might result in a bogus lookup.
   assert(resolved_method->method_holder()->is_linked(), "must be linked");
 
   // do lookup based on receiver klass using the vtable index
   if (resolved_method->method_holder()->is_interface()) { // default or miranda method
-    vtable_index = vtable_index_of_interface_method(resolved_klass,
-                           resolved_method);
+    vtable_index = vtable_index_of_interface_method(resolved_klass, resolved_method);
     assert(vtable_index >= 0 , "we should have valid vtable index at this point");
 
     selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
   } else {
     // at this point we are sure that resolved_method is virtual and not
     // a default or miranda method; therefore, it must have a valid vtable index.
     assert(!resolved_method->has_itable_index(), "");
     vtable_index = resolved_method->vtable_index();
     // We could get a negative vtable_index for final methods,
-    // because as an optimization they are they are never put in the vtable,
+    // because as an optimization they are never put in the vtable,
     // unless they override an existing method.
     // If we do get a negative, it means the resolved method is the the selected
     // method, and it can never be changed by an override.
     if (vtable_index == Method::nonvirtual_vtable_index) {
       assert(resolved_method->can_be_statically_bound(), "cannot override this method");

@@ -1366,24 +1365,17 @@
     }
   }
 
   // check if method exists
   if (selected_method.is_null()) {
-    ResourceMark rm(THREAD);
-    THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
-              Method::name_and_sig_as_C_string(resolved_klass,
-                                               resolved_method->name(),
-                                               resolved_method->signature()));
+    throw_abstract_method_error(resolved_method, recv_klass, CHECK);
   }
 
   // check if abstract
   if (check_null_and_abstract && selected_method->is_abstract()) {
-    ResourceMark rm(THREAD);
-    THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
-              Method::name_and_sig_as_C_string(resolved_klass,
-                                               selected_method->name(),
-                                               selected_method->signature()));
+    // Pass arguments for generating a verbose error message.
+    throw_abstract_method_error_abstract(resolved_method, selected_method, recv_klass, CHECK);
   }
 
   if (log_develop_is_enabled(Trace, vtables)) {
     trace_method_resolution("invokevirtual selected method: receiver-class:",
                             recv_klass, resolved_klass, selected_method,

@@ -1435,57 +1427,50 @@
   }
 
   // do lookup based on receiver klass
   // This search must match the linktime preparation search for itable initialization
   // to correctly enforce loader constraints for interface method inheritance
-  methodHandle sel_method = lookup_instance_method_in_klasses(recv_klass,
+  methodHandle selected_method = lookup_instance_method_in_klasses(recv_klass,
                                                   resolved_method->name(),
                                                   resolved_method->signature(), CHECK);
-  if (sel_method.is_null() && !check_null_and_abstract) {
+  if (selected_method.is_null() && !check_null_and_abstract) {
     // In theory this is a harmless placeholder value, but
     // in practice leaving in null affects the nsk default method tests.
     // This needs further study.
-    sel_method = resolved_method;
+    selected_method = resolved_method;
   }
   // check if method exists
-  if (sel_method.is_null()) {
-    ResourceMark rm(THREAD);
-    THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
-                   Method::name_and_sig_as_C_string(recv_klass,
-                                                    resolved_method->name(),
-                                                    resolved_method->signature()));
+  if (selected_method.is_null()) {
+    // Pass arguments for generating a verbose error message.
+    throw_abstract_method_error(resolved_method, recv_klass, CHECK);
   }
   // check access
-  // Throw Illegal Access Error if sel_method is not public.
-  if (!sel_method->is_public()) {
+  // Throw Illegal Access Error if selected_method is not public.
+  if (!selected_method->is_public()) {
     ResourceMark rm(THREAD);
     THROW_MSG(vmSymbols::java_lang_IllegalAccessError(),
               Method::name_and_sig_as_C_string(recv_klass,
-                                               sel_method->name(),
-                                               sel_method->signature()));
+                                               selected_method->name(),
+                                               selected_method->signature()));
   }
   // check if abstract
-  if (check_null_and_abstract && sel_method->is_abstract()) {
-    ResourceMark rm(THREAD);
-    THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
-              Method::name_and_sig_as_C_string(recv_klass,
-                                               sel_method->name(),
-                                               sel_method->signature()));
+  if (check_null_and_abstract && selected_method->is_abstract()) {
+    throw_abstract_method_error_abstract(resolved_method, selected_method, recv_klass, CHECK);
   }
 
   if (log_develop_is_enabled(Trace, itables)) {
     trace_method_resolution("invokeinterface selected method: receiver-class:",
-                            recv_klass, resolved_klass, sel_method, true);
+                            recv_klass, resolved_klass, selected_method, true);
   }
   // setup result
   if (!resolved_method->has_itable_index()) {
     int vtable_index = resolved_method->vtable_index();
-    assert(vtable_index == sel_method->vtable_index(), "sanity check");
-    result.set_virtual(resolved_klass, recv_klass, resolved_method, sel_method, vtable_index, CHECK);
+    assert(vtable_index == selected_method->vtable_index(), "sanity check");
+    result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK);
   } else {
     int itable_index = resolved_method()->itable_index();
-    result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK);
+    result.set_interface(resolved_klass, recv_klass, resolved_method, selected_method, itable_index, CHECK);
   }
 }
 
 
 methodHandle LinkResolver::linktime_resolve_interface_method_or_null(

@@ -1771,5 +1756,56 @@
                                                      THREAD);
   Exceptions::wrap_dynamic_exception(CHECK);
   result.set_handle(resolved_method, resolved_appendix, resolved_method_type, THREAD);
   Exceptions::wrap_dynamic_exception(CHECK);
 }
+
+// No need to report selected method differing from resolved method.
+void LinkResolver::throw_abstract_method_error(const methodHandle& resolved_method, Klass *recv_klass, TRAPS) {
+  Klass *resolved_klass = resolved_method->method_holder();
+  ResourceMark rm;
+
+  char buf[1000];
+  jio_snprintf(buf, sizeof(buf),
+               "Receiver class %s does not define or inherit an implementation of the resolved method %s%s%s of %s %s.",
+               recv_klass->external_name(),
+               resolved_method->modifiers_as_C_string(),
+               resolved_method->name()->as_C_string(),
+               resolved_method->signature()->as_C_string(),
+               resolved_klass->external_kind(),
+               resolved_klass->external_name());
+
+  THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), buf);
+}
+
+// Selected method is abstract.
+void LinkResolver::throw_abstract_method_error_abstract(const methodHandle& resolved_method,
+                                                        const methodHandle& selected_method,
+                                                        Klass *recv_klass, TRAPS) {
+  if (resolved_method == selected_method) {
+    throw_abstract_method_error(resolved_method, recv_klass, CHECK);
+  }
+  Klass *resolved_klass = resolved_method->method_holder();
+  ResourceMark rm;
+
+  const char *resolvedKind = "class";
+  if (resolved_klass->is_interface()) {
+    resolvedKind = "interface";
+  } else if (resolved_klass->is_abstract()) {
+    resolvedKind = "abstract class";
+  }
+
+  char buf[1000];
+  jio_snprintf(buf, sizeof(buf),
+               "Receiver class %s does not define or inherit an implementation of the resolved method %s%s%s of %s %s."
+               " Selected method is %s%s.",
+               recv_klass->external_name(),
+               resolved_method->modifiers_as_C_string(),
+               resolved_method->name()->as_C_string(),
+               resolved_method->signature()->as_C_string(),
+               resolved_klass->external_kind(),
+               resolved_klass->external_name(),
+               selected_method->modifiers_as_C_string(),  // This should print 'abstract'.
+               selected_method->name_and_sig_as_C_string());
+
+  THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), buf);
+}
< prev index next >