# HG changeset patch # User jrose # Date 1302221541 25200 # Node ID 758ba0bf7bcca5dc82da483f224ed30c41ae568b # Parent ed69575596acb3c70987a8607c01ba6f0ebce8c3 7012087: JSR 292 Misleading exception message for a non-bound MH for a virtual method Summary: Improve error message formatting to give more information to user. Also, catch a corner case related to 6930553 and 6844449. Reviewed-by: kvn diff -r ed69575596ac -r 758ba0bf7bcc src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Thu Apr 07 17:02:30 2011 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Thu Apr 07 17:12:21 2011 -0700 @@ -560,6 +560,7 @@ } break; } + case JVM_CONSTANT_InvokeDynamic: case JVM_CONSTANT_Fieldref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: { diff -r ed69575596ac -r 758ba0bf7bcc src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Thu Apr 07 17:02:30 2011 -0700 +++ b/src/share/vm/runtime/sharedRuntime.cpp Thu Apr 07 17:12:21 2011 -0700 @@ -1700,9 +1700,11 @@ message = generate_class_cast_message(objName, targetKlass->external_name()); } else { // %%% need to get the MethodType string, without messing around too much + const char* desc = NULL; // Get a signature from the invoke instruction const char* mhName = "method handle"; const char* targetType = "the required signature"; + int targetArity = -1, mhArity = -1; vframeStream vfst(thread, true); if (!vfst.at_end()) { Bytecode_invoke call(vfst.method(), vfst.bci()); @@ -1716,20 +1718,35 @@ && target->is_method_handle_invoke() && required == target->method_handle_type()) { targetType = target->signature()->as_C_string(); + targetArity = ArgumentCount(target->signature()).size(); } } - klassOop kignore; int fignore; - methodOop actual_method = MethodHandles::decode_method(actual, - kignore, fignore); + klassOop kignore; int dmf_flags = 0; + methodOop actual_method = MethodHandles::decode_method(actual, kignore, dmf_flags); + if ((dmf_flags & ~(MethodHandles::_dmf_has_receiver | + MethodHandles::_dmf_does_dispatch | + MethodHandles::_dmf_from_interface)) != 0) + actual_method = NULL; // MH does extra binds, drops, etc. + bool has_receiver = ((dmf_flags & MethodHandles::_dmf_has_receiver) != 0); if (actual_method != NULL) { - if (methodOopDesc::is_method_handle_invoke_name(actual_method->name())) - mhName = "$"; + mhName = actual_method->signature()->as_C_string(); + mhArity = ArgumentCount(actual_method->signature()).size(); + if (!actual_method->is_static()) mhArity += 1; + } else if (java_lang_invoke_MethodHandle::is_instance(actual)) { + oopDesc* mhType = java_lang_invoke_MethodHandle::type(actual); + mhArity = java_lang_invoke_MethodType::ptype_count(mhType); + stringStream st; + java_lang_invoke_MethodType::print_signature(mhType, &st); + mhName = st.as_string(); + } + if (targetArity != -1 && targetArity != mhArity) { + if (has_receiver && targetArity == mhArity-1) + desc = " cannot be called without a receiver argument as "; else - mhName = actual_method->signature()->as_C_string(); - if (mhName[0] == '$') - mhName = actual_method->signature()->as_C_string(); + desc = " cannot be called with a different arity as "; } message = generate_class_cast_message(mhName, targetType, + desc != NULL ? desc : " cannot be called as "); } if (TraceMethodHandles) {