< 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 >