Mercurial > hg > graal-compiler
diff src/share/vm/interpreter/linkResolver.cpp @ 6266:1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
6984705: JSR 292 method handle creation should not go through JNI
Summary: remove assembly code for JDK 7 chained method handles
Reviewed-by: jrose, twisti, kvn, mhaupt
Contributed-by: John Rose <john.r.rose@oracle.com>, Christian Thalinger <christian.thalinger@oracle.com>, Michael Haupt <michael.haupt@oracle.com>
author | twisti |
---|---|
date | Tue, 24 Jul 2012 10:51:00 -0700 |
parents | f08d439fab8c |
children | 93c71eb28866 |
line wrap: on
line diff
--- a/src/share/vm/interpreter/linkResolver.cpp Mon Jul 23 13:04:59 2012 -0700 +++ b/src/share/vm/interpreter/linkResolver.cpp Tue Jul 24 10:51:00 2012 -0700 @@ -96,15 +96,21 @@ void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) { assert(vtable_index >= 0 || vtable_index == methodOopDesc::nonvirtual_vtable_index, "valid index"); set_common(resolved_klass, selected_klass, resolved_method, selected_method, vtable_index, CHECK); + assert(!resolved_method->is_compiled_lambda_form(), "these must be handled via an invokehandle call"); } -void CallInfo::set_dynamic(methodHandle resolved_method, TRAPS) { - assert(resolved_method->is_method_handle_invoke(), ""); +void CallInfo::set_handle(methodHandle resolved_method, Handle resolved_appendix, TRAPS) { + if (resolved_method.is_null()) { + THROW_MSG(vmSymbols::java_lang_InternalError(), "resolved method is null"); + } KlassHandle resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); - assert(resolved_klass == resolved_method->method_holder(), ""); + assert(resolved_method->intrinsic_id() == vmIntrinsics::_invokeBasic || + resolved_method->is_compiled_lambda_form(), + "linkMethod must return one of these"); int vtable_index = methodOopDesc::nonvirtual_vtable_index; assert(resolved_method->vtable_index() == vtable_index, ""); - set_common(resolved_klass, KlassHandle(), resolved_method, resolved_method, vtable_index, CHECK); + set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, vtable_index, CHECK); + _resolved_appendix = resolved_appendix; } void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) { @@ -114,6 +120,7 @@ _resolved_method = resolved_method; _selected_method = selected_method; _vtable_index = vtable_index; + _resolved_appendix = Handle(); if (CompilationPolicy::must_be_compiled(selected_method)) { // This path is unusual, mostly used by the '-Xcomp' stress test mode. @@ -180,11 +187,9 @@ void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { methodOop result_oop = klass->uncached_lookup_method(name, signature); if (EnableInvokeDynamic && result_oop != NULL) { - switch (result_oop->intrinsic_id()) { - case vmIntrinsics::_invokeExact: - case vmIntrinsics::_invokeGeneric: - case vmIntrinsics::_invokeDynamic: - // Do not link directly to these. The VM must produce a synthetic one using lookup_implicit_method. + vmIntrinsics::ID iid = result_oop->intrinsic_id(); + if (MethodHandles::is_signature_polymorphic(iid)) { + // Do not link directly to these. The VM must produce a synthetic one using lookup_polymorphic_method. return; } } @@ -213,31 +218,97 @@ result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name, signature)); } -void LinkResolver::lookup_implicit_method(methodHandle& result, - KlassHandle klass, Symbol* name, Symbol* signature, - KlassHandle current_klass, - TRAPS) { +void LinkResolver::lookup_polymorphic_method(methodHandle& result, + KlassHandle klass, Symbol* name, Symbol* full_signature, + KlassHandle current_klass, + Handle* appendix_result_or_null, + TRAPS) { + vmIntrinsics::ID iid = MethodHandles::signature_polymorphic_name_id(name); + if (TraceMethodHandles) { + tty->print_cr("lookup_polymorphic_method iid=%s %s.%s%s", + vmIntrinsics::name_at(iid), klass->external_name(), + name->as_C_string(), full_signature->as_C_string()); + } if (EnableInvokeDynamic && klass() == SystemDictionary::MethodHandle_klass() && - methodOopDesc::is_method_handle_invoke_name(name)) { - if (!THREAD->is_Compiler_thread() && !MethodHandles::enabled()) { - // Make sure the Java part of the runtime has been booted up. - klassOop natives = SystemDictionary::MethodHandleNatives_klass(); - if (natives == NULL || instanceKlass::cast(natives)->is_not_initialized()) { - SystemDictionary::resolve_or_fail(vmSymbols::java_lang_invoke_MethodHandleNatives(), - Handle(), - Handle(), - true, - CHECK); + iid != vmIntrinsics::_none) { + if (MethodHandles::is_signature_polymorphic_intrinsic(iid)) { + // Most of these do not need an up-call to Java to resolve, so can be done anywhere. + // Do not erase last argument type (MemberName) if it is a static linkTo method. + bool keep_last_arg = MethodHandles::is_signature_polymorphic_static(iid); + TempNewSymbol basic_signature = + MethodHandles::lookup_basic_type_signature(full_signature, keep_last_arg, CHECK); + if (TraceMethodHandles) { + tty->print_cr("lookup_polymorphic_method %s %s => basic %s", + name->as_C_string(), + full_signature->as_C_string(), + basic_signature->as_C_string()); + } + result = SystemDictionary::find_method_handle_intrinsic(iid, + basic_signature, + CHECK); + if (result.not_null()) { + assert(result->is_method_handle_intrinsic(), "MH.invokeBasic or MH.linkTo* intrinsic"); + assert(result->intrinsic_id() != vmIntrinsics::_invokeGeneric, "wrong place to find this"); + assert(basic_signature == result->signature(), "predict the result signature"); + if (TraceMethodHandles) { + tty->print("lookup_polymorphic_method => intrinsic "); + result->print_on(tty); + } + return; } - } - methodOop result_oop = SystemDictionary::find_method_handle_invoke(name, - signature, - current_klass, - CHECK); - if (result_oop != NULL) { - assert(result_oop->is_method_handle_invoke() && result_oop->signature() == signature, "consistent"); - result = methodHandle(THREAD, result_oop); + } else if (iid == vmIntrinsics::_invokeGeneric + && !THREAD->is_Compiler_thread() + && appendix_result_or_null != NULL) { + // This is a method with type-checking semantics. + // We will ask Java code to spin an adapter method for it. + if (!MethodHandles::enabled()) { + // Make sure the Java part of the runtime has been booted up. + klassOop natives = SystemDictionary::MethodHandleNatives_klass(); + if (natives == NULL || instanceKlass::cast(natives)->is_not_initialized()) { + SystemDictionary::resolve_or_fail(vmSymbols::java_lang_invoke_MethodHandleNatives(), + Handle(), + Handle(), + true, + CHECK); + } + } + + Handle appendix; + result = SystemDictionary::find_method_handle_invoker(name, + full_signature, + current_klass, + &appendix, + CHECK); + if (TraceMethodHandles) { + tty->print("lookup_polymorphic_method => (via Java) "); + result->print_on(tty); + tty->print(" lookup_polymorphic_method => appendix = "); + if (appendix.is_null()) tty->print_cr("(none)"); + else appendix->print_on(tty); + } + if (result.not_null()) { +#ifdef ASSERT + TempNewSymbol basic_signature = + MethodHandles::lookup_basic_type_signature(full_signature, CHECK); + int actual_size_of_params = result->size_of_parameters(); + int expected_size_of_params = ArgumentSizeComputer(basic_signature).size(); + // +1 for MethodHandle.this, +1 for trailing MethodType + if (!MethodHandles::is_signature_polymorphic_static(iid)) expected_size_of_params += 1; + if (appendix.not_null()) expected_size_of_params += 1; + if (actual_size_of_params != expected_size_of_params) { + tty->print_cr("*** basic_signature=%s", basic_signature->as_C_string()); + tty->print_cr("*** result for %s: ", vmIntrinsics::name_at(iid)); + result->print(); + } + assert(actual_size_of_params == expected_size_of_params, + err_msg("%d != %d", actual_size_of_params, expected_size_of_params)); +#endif //ASSERT + + assert(appendix_result_or_null != NULL, ""); + (*appendix_result_or_null) = appendix; + return; + } } } } @@ -267,6 +338,7 @@ new_flags = new_flags | JVM_ACC_PUBLIC; flags.set_flags(new_flags); } +// assert(extra_arg_result_or_null != NULL, "must be able to return extra argument"); if (!Reflection::verify_field_access(ref_klass->as_klassOop(), resolved_klass->as_klassOop(), @@ -287,10 +359,19 @@ } } -void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle& resolved_klass, - constantPoolHandle pool, int index, TRAPS) { +void LinkResolver::resolve_method_statically(methodHandle& resolved_method, KlassHandle& resolved_klass, + Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS) { // resolve klass + if (code == Bytecodes::_invokedynamic) { + resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); + Symbol* method_name = vmSymbols::invoke_name(); + Symbol* method_signature = pool->signature_ref_at(index); + KlassHandle current_klass(THREAD, pool->pool_holder()); + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + return; + } + resolve_klass(resolved_klass, pool, index, CHECK); Symbol* method_name = pool->name_ref_at(index); @@ -299,7 +380,7 @@ if (pool->has_preresolution() || (resolved_klass() == SystemDictionary::MethodHandle_klass() && - methodOopDesc::is_method_handle_invoke_name(method_name))) { + MethodHandles::is_signature_polymorphic_name(resolved_klass(), method_name))) { methodOop result_oop = constantPoolOopDesc::method_at_if_loaded(pool, index); if (result_oop != NULL) { resolved_method = methodHandle(THREAD, result_oop); @@ -307,33 +388,13 @@ } } - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + if (code == Bytecodes::_invokeinterface) { + resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + } else { + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); + } } -void LinkResolver::resolve_dynamic_method(methodHandle& resolved_method, KlassHandle& resolved_klass, constantPoolHandle pool, int index, TRAPS) { - // The class is java.lang.invoke.MethodHandle - resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); - - Symbol* method_name = vmSymbols::invokeExact_name(); - - Symbol* method_signature = pool->signature_ref_at(index); - KlassHandle current_klass (THREAD, pool->pool_holder()); - - resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); -} - -void LinkResolver::resolve_interface_method(methodHandle& resolved_method, KlassHandle& resolved_klass, constantPoolHandle pool, int index, TRAPS) { - - // resolve klass - resolve_klass(resolved_klass, pool, index, CHECK); - Symbol* method_name = pool->name_ref_at(index); - Symbol* method_signature = pool->signature_ref_at(index); - KlassHandle current_klass(THREAD, pool->pool_holder()); - - resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); -} - - void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) { @@ -346,6 +407,8 @@ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } + Handle nested_exception; + // 2. lookup method in resolved klass and its super klasses lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, CHECK); @@ -354,17 +417,23 @@ lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK); if (resolved_method.is_null()) { - // JSR 292: see if this is an implicitly generated method MethodHandle.invoke(*...) - lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, CHECK); + // JSR 292: see if this is an implicitly generated method MethodHandle.linkToVirtual(*...), etc + lookup_polymorphic_method(resolved_method, resolved_klass, method_name, method_signature, + current_klass, (Handle*)NULL, THREAD); + if (HAS_PENDING_EXCEPTION) { + nested_exception = Handle(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + } } if (resolved_method.is_null()) { // 4. method lookup failed ResourceMark rm(THREAD); - THROW_MSG(vmSymbols::java_lang_NoSuchMethodError(), - methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()), - method_name, - method_signature)); + THROW_MSG_CAUSE(vmSymbols::java_lang_NoSuchMethodError(), + methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()), + method_name, + method_signature), + nested_exception); } } @@ -1053,6 +1122,7 @@ case Bytecodes::_invokestatic : resolve_invokestatic (result, pool, index, CHECK); break; case Bytecodes::_invokespecial : resolve_invokespecial (result, pool, index, CHECK); break; case Bytecodes::_invokevirtual : resolve_invokevirtual (result, recv, pool, index, CHECK); break; + case Bytecodes::_invokehandle : resolve_invokehandle (result, pool, index, CHECK); break; case Bytecodes::_invokedynamic : resolve_invokedynamic (result, pool, index, CHECK); break; case Bytecodes::_invokeinterface: resolve_invokeinterface(result, recv, pool, index, CHECK); break; } @@ -1116,22 +1186,91 @@ } -void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int raw_index, TRAPS) { +void LinkResolver::resolve_invokehandle(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { assert(EnableInvokeDynamic, ""); + // This guy is reached from InterpreterRuntime::resolve_invokehandle. + KlassHandle resolved_klass; + Symbol* method_name = NULL; + Symbol* method_signature = NULL; + KlassHandle current_klass; + resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK); + if (TraceMethodHandles) + tty->print_cr("resolve_invokehandle %s %s", method_name->as_C_string(), method_signature->as_C_string()); + resolve_handle_call(result, resolved_klass, method_name, method_signature, current_klass, CHECK); +} - // This guy is reached from InterpreterRuntime::resolve_invokedynamic. +void LinkResolver::resolve_handle_call(CallInfo& result, KlassHandle resolved_klass, + Symbol* method_name, Symbol* method_signature, + KlassHandle current_klass, + TRAPS) { + // JSR 292: this must be an implicitly generated method MethodHandle.invokeExact(*...) or similar + assert(resolved_klass() == SystemDictionary::MethodHandle_klass(), ""); + assert(MethodHandles::is_signature_polymorphic_name(method_name), ""); + methodHandle resolved_method; + Handle resolved_appendix; + lookup_polymorphic_method(resolved_method, resolved_klass, + method_name, method_signature, + current_klass, &resolved_appendix, CHECK); + result.set_handle(resolved_method, resolved_appendix, CHECK); +} + + +void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { + assert(EnableInvokeDynamic, ""); + pool->set_invokedynamic(); // mark header to flag active call sites + + //resolve_pool(<resolved_klass>, method_name, method_signature, current_klass, pool, index, CHECK); + Symbol* method_name = pool->name_ref_at(index); + Symbol* method_signature = pool->signature_ref_at(index); + KlassHandle current_klass = KlassHandle(THREAD, pool->pool_holder()); - // At this point, we only need the signature, and can ignore the name. - Symbol* method_signature = pool->signature_ref_at(raw_index); // raw_index works directly - Symbol* method_name = vmSymbols::invokeExact_name(); - KlassHandle resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); + // Resolve the bootstrap specifier (BSM + optional arguments). + Handle bootstrap_specifier; + // Check if CallSite has been bound already: + ConstantPoolCacheEntry* cpce = pool->cache()->secondary_entry_at(index); + if (cpce->is_f1_null()) { + int pool_index = pool->cache()->main_entry_at(index)->constant_pool_index(); + oop bsm_info = pool->resolve_bootstrap_specifier_at(pool_index, CHECK); + assert(bsm_info != NULL, ""); + // FIXME: Cache this once per BootstrapMethods entry, not once per CONSTANT_InvokeDynamic. + bootstrap_specifier = Handle(THREAD, bsm_info); + } + if (!cpce->is_f1_null()) { + methodHandle method(THREAD, cpce->f2_as_vfinal_method()); + Handle appendix(THREAD, cpce->has_appendix() ? cpce->f1_appendix() : (oop)NULL); + result.set_handle(method, appendix, CHECK); + return; + } - // JSR 292: this must be an implicitly generated method MethodHandle.invokeExact(*...) - // The extra MH receiver will be inserted into the stack on every call. - methodHandle resolved_method; - KlassHandle current_klass(THREAD, pool->pool_holder()); - lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, THREAD); + if (TraceMethodHandles) { + tty->print_cr("resolve_invokedynamic #%d %s %s", + constantPoolCacheOopDesc::decode_secondary_index(index), + method_name->as_C_string(), method_signature->as_C_string()); + tty->print(" BSM info: "); bootstrap_specifier->print(); + } + + resolve_dynamic_call(result, bootstrap_specifier, method_name, method_signature, current_klass, CHECK); +} + +void LinkResolver::resolve_dynamic_call(CallInfo& result, + Handle bootstrap_specifier, + Symbol* method_name, Symbol* method_signature, + KlassHandle current_klass, + TRAPS) { + // JSR 292: this must resolve to an implicitly generated method MH.linkToCallSite(*...) + // The appendix argument is likely to be a freshly-created CallSite. + Handle resolved_appendix; + methodHandle resolved_method = + SystemDictionary::find_dynamic_call_site_invoker(current_klass, + bootstrap_specifier, + method_name, method_signature, + &resolved_appendix, + CHECK); if (HAS_PENDING_EXCEPTION) { + if (TraceMethodHandles) { + tty->print_cr("invokedynamic throws BSME for "INTPTR_FORMAT, PENDING_EXCEPTION); + PENDING_EXCEPTION->print(); + } if (PENDING_EXCEPTION->is_a(SystemDictionary::BootstrapMethodError_klass())) { // throw these guys, since they are already wrapped return; @@ -1141,17 +1280,12 @@ return; } // See the "Linking Exceptions" section for the invokedynamic instruction in the JVMS. - Handle ex(THREAD, PENDING_EXCEPTION); + Handle nested_exception(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; - oop bsme = Klass::cast(SystemDictionary::BootstrapMethodError_klass())->java_mirror(); - MethodHandles::raise_exception(Bytecodes::_athrow, ex(), bsme, CHECK); - // java code should not return, but if it does throw out anyway - THROW(vmSymbols::java_lang_InternalError()); + THROW_MSG_CAUSE(vmSymbols::java_lang_BootstrapMethodError(), + "BootstrapMethodError", nested_exception) } - if (resolved_method.is_null()) { - THROW(vmSymbols::java_lang_InternalError()); - } - result.set_dynamic(resolved_method, CHECK); + result.set_handle(resolved_method, resolved_appendix, CHECK); } //------------------------------------------------------------------------------------------------------------------------