--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Mon Jul 23 13:04:59 2012 -0700
+++ b/hotspot/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);
}
//------------------------------------------------------------------------------------------------------------------------