1.起源
既然JVM在执行到invokedynamic指令时最终会调用到java.lang.invoke.LambdaMetafactory.metafactory()方法, 那么断点看看堆栈.
可以看到, 调用是从java.lang.invoke.MethodHandleNatives.linkCallSite()方法开始的, 来看看这个方法的代码.
/**
* The JVM is linking an invokedynamic instruction. Create a reified call site for it.
*/
static MemberName linkCallSite(Object callerObj, Object bootstrapMethodObj, Object nameObj, Object typeObj,
Object staticArguments, Object[] appendixResult) {
MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
Class<?> caller = (Class<?>)callerObj;
String name = nameObj.toString().intern();
MethodType type = (MethodType)typeObj;
CallSite callSite = CallSite.makeSite(bootstrapMethod, name, type, staticArguments, caller);
if (callSite instanceof ConstantCallSite) {
appendixResult[0] = callSite.dynamicInvoker();
return Invokers.linkToTargetMethod(type);
} else {
appendixResult[0] = callSite;
return Invokers.linkToCallSiteMethod(type);
}
}
代码逻辑先不管, 比较疑惑的是, 这个调用是怎么来的呢? 肯定是JVM调用的(废话-.-!!)~~~
尝试翻了下对应版本的hotspot代码, C++不会, 所以下面的说法不一定正确, 如有不对, 请务必指正!
先找到JVM执行invokedynamic指令的地方, 全局搜索了下invokedynamic 找到这个文件bytecodeInterpreter.cpp
HotSpot的源码里, 平台中立的部分, 有两套解释器实现: 一个叫模板解释器( template interpreter ), 平时用的就是这个;
另一个叫"C++解释器", 也就是bytecodeInterpreter.cpp. 平时用的是前者而不是后者主要是历史原因。 --- RednaxelaFX
我们只是看运作过程, 所以看这个文件应该没问题~~~~
//hotspot-d3d5604ea0de\src\share\vm\interpreter\bytecodeInterpreter.cpp文件
CASE(_invokedynamic): {
//是否支持InvokeDynamic
if (!EnableInvokeDynamic) {
// We should not encounter this bytecode if !EnableInvokeDynamic.
// The verifier will stop it. However, if we get past the verifier,
// this will stop the thread in a reasonable way, without crashing the JVM.
CALL_VM(InterpreterRuntime::throw_IncompatibleClassChangeError(THREAD), handle_exception);
ShouldNotReachHere();
}
//第一篇中有说 BA 00 18 00 00 BA表示invokedynamic 后面四个字节表示参数, 这里应该是把后面四个字节作为常量池缓存的索引来用
u4 index = Bytes::get_native_u4(pc+1);
ConstantPoolCacheEntry* cache = cp->constant_pool()->invokedynamic_cp_cache_entry_at(index);
// We are resolved if the resolved_references field contains a non-null object (CallSite, etc.)
// This kind of CP cache entry does not need to match the flags byte, because
// there is a 1-1 relation between bytecode type and CP entry type.
if (! cache->is_resolved((Bytecodes::Code) opcode)) {
CALL_VM(InterpreterRuntime::resolve_invokedynamic(THREAD), handle_exception);
cache = cp->constant_pool()->invokedynamic_cp_cache_entry_at(index);
}
//这时获取到的方法为
Method* method = cache->f1_as_method();
if (VerifyOops) method->verify();
if (cache->has_appendix()) {
ConstantPool* constants = METHOD->constants();
SET_STACK_OBJECT(cache->appendix_if_resolved(constants), 0);
MORE_STACK(1);
}
istate->set_msg(call_method);
istate->set_callee(method);
istate->set_callee_entry_point(method->from_interpreted_entry());
istate->set_bcp_advance(5);
// Invokedynamic has got a call counter, just like an invokestatic -> increment!
BI_PROFILE_UPDATE_CALL();
UPDATE_PC_AND_RETURN(0); // I'll be back...
}
这里是上面代码里用到的 InterpreterRuntime::resolve_invokedynamic 方法, 这个方法进行符合解析, 创建固定的CallSite对象
//src\share\vm\interpreter\interpreterRuntime.cpp
// First time execution: Resolve symbols, create a permanent CallSite object.
IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
assert(EnableInvokeDynamic, "");
const Bytecodes::Code bytecode = Bytecodes::_invokedynamic;
//TO DO: consider passing BCI to Java.
// int caller_bci = method(thread)->bci_from(bcp(thread));
// resolve method
CallInfo info;
constantPoolHandle pool(thread, method(thread)->constants());
int index = get_index_u4(thread, bytecode);
{
JvmtiHideSingleStepping jhss(thread);//JvmtiHideSingleStepping is a helper class for hiding internal single step events.
LinkResolver::resolve_invoke(info, Handle(), pool, index, bytecode, CHECK);
} // end JvmtiHideSingleStepping
ConstantPoolCacheEntry* cp_cache_entry = pool->invokedynamic_cp_cache_entry_at(index);
cp_cache_entry->set_dynamic_call(pool, info);
}
IRT_END
这里是上面代码主要逻辑是调用LinkResolver::resolve_invoke 方法, 该方法具体代码如下.
//src\share\vm\interpreter\linkResolver.cpp
void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS) {
switch (byte) {
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;
}
return;
}
继续, 找到 resolve_dynamic_call 方法代码如下.
//src\share\vm\interpreter\linkResolver.cpp
void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) {
assert(EnableInvokeDynamic, "");
//符号解析 也就是获取CONSTANT_InvokeDynamic_info.CONSTANT_NameAndType_info
//在这里的method_name应该是apply, method_signature应该是(Ljava/lang/String;)Ljava/util/function/Function;
//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());
//这里是找到Bootstrap Method, 在这里也就是java/lang/invoke/LambdaMetafactory.metafactory
// Resolve the bootstrap specifier (BSM + optional arguments).
Handle bootstrap_specifier;
// Check if CallSite has been bound already:
ConstantPoolCacheEntry* cpce = pool->invokedynamic_cp_cache_entry_at(index);
if (cpce->is_f1_null()) {
int pool_index = cpce->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->f1_as_method());
Handle appendix( THREAD, cpce->appendix_if_resolved(pool));
Handle method_type(THREAD, cpce->method_type_if_resolved(pool));
result.set_handle(method, appendix, method_type, CHECK);
return;
}
if (TraceMethodHandles) {
ResourceMark rm(THREAD);
tty->print_cr("resolve_invokedynamic #%d %s %s",
ConstantPool::decode_invokedynamic_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);
}
这里是上面调用的 resolve_dynamic_call 方法
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;
Handle resolved_method_type;
methodHandle resolved_method =
SystemDictionary::find_dynamic_call_site_invoker(current_klass,
bootstrap_specifier,
method_name, method_signature,
&resolved_appendix,
&resolved_method_type,
THREAD);
if (HAS_PENDING_EXCEPTION) {
if (TraceMethodHandles) {
tty->print_cr("invokedynamic throws BSME for " INTPTR_FORMAT, p2i((void *)PENDING_EXCEPTION));
PENDING_EXCEPTION->print();
}
if (PENDING_EXCEPTION->is_a(SystemDictionary::BootstrapMethodError_klass())) {
// throw these guys, since they are already wrapped
return;
}
if (!PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
// intercept only LinkageErrors which might have failed to wrap
return;
}
// See the "Linking Exceptions" section for the invokedynamic instruction in the JVMS.
Handle nested_exception(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
THROW_CAUSE(vmSymbols::java_lang_BootstrapMethodError(), nested_exception)
}
result.set_handle(resolved_method, resolved_appendix, resolved_method_type, CHECK);
}
大概过程是这样的.
static java.lang.Object linkToTargetMethod(java.lang.Object arg0, java.lang.Object arg1);
0 aload_1 [arg1]
1 checkcast java.lang.invoke.MethodHandle [12]
4 aload_0 [arg0]
5 invokevirtual java.lang.invoke.MethodHandle.invokeBasic(java.lang.Object) : java.lang.Object [16]
8 areturn
#翻译过来是这样的
#对应这里的例子, arg0就是 "hello lambda", arg1就是 DirectMethodHandle(代表Main$$Lambda$1.get$Lambda(String)Function/invokeStatic)
#所以这里的返回值就是Function实例, 也就是我们main方法中的func所引用的对象
static Object linkToTargetMethod(Object arg0, Object arg1){
return ((MethodHandle)arg1).invokeBasic(arg0);
}
有图有真相