在我当前的项目中,我希望能够“重新实现”一个lambda方法(不知道“重新实现”是否是正确的词)
考虑以下示例
public static void main(String[] args) throws Throwable {
TestUser tu = new TestUser();
ITest1 lam = t->{
System.out.println("whoops" + tu.toString());
return 1;
};
tu.doExec(lam);
calls++;
if( calls == 1) main(args);
}
这里我试图通过JVM调试进行调试,我注意到JVM为metafactory方法(创建构建MethodType
)和我的lambda创建了MethodHandle
和CallSite
个对象方法。现在一旦完成,就会调用linkCallSite
。此方法构建CallSite并将lambda方法仅链接到它一次。在这一点上,我的问题是,我可以以某种方式从jvm中删除lambda CallSite和LambdaForm并以某种方式再次触发整个过程吗?
另一个问题,当通过JVM调用进行调试时,我注意到每次JVM执行lambda方法时,都会调用方法Ljava/lang/invoke/LambdaForm$MH/818403870;.linkToTargetMethod(Object)
,我无法在JVM cpp源代码中找到源代码,也无法在java的。这个方法究竟是如何调用的,或者它在何处被调用?
我知道问题有点复杂,所以我对你的问题持开放态度。 提前谢谢。
答案 0 :(得分:1)
在字节码解析时,我可以以某种方式从jvm中删除lambda CallSite和LambdaForm 并以某种方式再次触发整个过程?
invokedynamic
仅与CallSite(或有时直接与目标方法)链接一次。解析结果保存在常量池缓存中,之后不会修改。
重置常量池缓存的一种可能方法是重新定义类。我不计算在不同的ClassLoader中重新加载类,因为这在技术上与加载与旧的类无关的新类相同。
因此,为了再次触发linkCallSite
内容,您可以调用Instrumentation.redefineClasses或等效的JVM TI RedefineClasses函数。
这个方法到底是怎么调用的,或者它在哪里被调用?
linkToTargetMethod
是在运行时动态创建的适配器,用于调用链接到特定invokedynamic
字节码的MethodHandle。它基本上是调用此适配器的invokedynamic
的实现。
Here is生成此适配器的源。