< prev index next >
src/hotspot/share/interpreter/linkResolver.cpp
Print this page
rev 49028 : 8197405: Improve messages of AbstractMethodErrors and IncompatibleClassChangeErrors.
Reviewed-by: coleenp, dholmes, mdoerr
*** 1341,1362 ****
// 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);
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,
// 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");
--- 1341,1361 ----
// 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);
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 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,1389 ****
}
}
// 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()));
}
// 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()));
}
if (log_develop_is_enabled(Trace, vtables)) {
trace_method_resolution("invokevirtual selected method: receiver-class:",
recv_klass, resolved_klass, selected_method,
--- 1365,1381 ----
}
}
// check if method exists
if (selected_method.is_null()) {
! throw_abstract_method_error(resolved_method, recv_klass, CHECK);
}
// check if abstract
if (check_null_and_abstract && selected_method->is_abstract()) {
! // Pass arguments for generating a verbose error message.
! throw_abstract_method_error(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,1491 ****
}
// 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,
resolved_method->name(),
resolved_method->signature(), CHECK);
! if (sel_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;
}
// 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()));
}
// check access
! // Throw Illegal Access Error if sel_method is not public.
! if (!sel_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()));
}
// 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 (log_develop_is_enabled(Trace, itables)) {
trace_method_resolution("invokeinterface selected method: receiver-class:",
! recv_klass, resolved_klass, sel_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);
} else {
int itable_index = resolved_method()->itable_index();
! result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK);
}
}
methodHandle LinkResolver::linktime_resolve_interface_method_or_null(
--- 1427,1476 ----
}
// 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 selected_method = lookup_instance_method_in_klasses(recv_klass,
resolved_method->name(),
resolved_method->signature(), CHECK);
! 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.
! selected_method = resolved_method;
}
// check if method exists
! 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 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,
! selected_method->name(),
! selected_method->signature()));
}
// check if abstract
! if (check_null_and_abstract && selected_method->is_abstract()) {
! throw_abstract_method_error(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, selected_method, true);
}
// setup result
if (!resolved_method->has_itable_index()) {
int vtable_index = resolved_method->vtable_index();
! 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, selected_method, itable_index, CHECK);
}
}
methodHandle LinkResolver::linktime_resolve_interface_method_or_null(
*** 1771,1775 ****
--- 1756,1795 ----
THREAD);
Exceptions::wrap_dynamic_exception(CHECK);
result.set_handle(resolved_method, resolved_appendix, resolved_method_type, THREAD);
Exceptions::wrap_dynamic_exception(CHECK);
}
+
+ // Selected method is abstract.
+ void LinkResolver::throw_abstract_method_error(const methodHandle& resolved_method,
+ const methodHandle& selected_method,
+ Klass *recv_klass, TRAPS) {
+ Klass *resolved_klass = resolved_method->method_holder();
+ ResourceMark rm;
+ stringStream ss;
+
+ if (recv_klass != NULL) {
+ ss.print("Receiver class %s does not define or inherit an "
+ "implementation of the",
+ recv_klass->external_name());
+ } else {
+ ss.print("Missing implementation of");
+ }
+
+ assert(resolved_method.not_null(), "Sanity");
+ ss.print(" resolved method %s%s%s%s of %s %s.",
+ resolved_method->is_abstract() ? "abstract " : "",
+ resolved_method->is_private() ? "private " : "",
+ resolved_method->name()->as_C_string(),
+ resolved_method->signature()->as_C_string(),
+ resolved_klass->external_kind(),
+ resolved_klass->external_name());
+
+ if (selected_method.not_null() && !(resolved_method == selected_method)) {
+ ss.print(" Selected method is %s%s%s.",
+ selected_method->is_abstract() ? "abstract " : "",
+ selected_method->is_private() ? "private " : "",
+ selected_method->name_and_sig_as_C_string());
+ }
+
+ THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string());
+ }
< prev index next >