OpenJDK 8 Lambdas处理

时间:2017-08-18 15:49:44

标签: java lambda jvm

在我当前的项目中,我希望能够“重新实现”一个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创建了MethodHandleCallSite个对象方法。现在一旦完成,就会调用linkCallSite。此方法构建CallSite并将lambda方法仅链接到它一次。在这一点上,我的问题是,我可以以某种方式从jvm中删除lambda CallSite和LambdaForm并以某种方式再次触发整个过程吗?

另一个问题,当通过JVM调用进行调试时,我注意到每次JVM执行lambda方法时,都会调用方法Ljava/lang/invoke/LambdaForm$MH/818403870;.linkToTargetMethod(Object),我无法在JVM cpp源代码中找到源代码,也无法在java的。这个方法究竟是如何调用的,或者它在何处被调用?

我知道问题有点复杂,所以我对你的问题持开放态度。 提前谢谢。

1 个答案:

答案 0 :(得分:1)

  

我可以以某种方式从jvm中删除lambda CallSite和LambdaForm   并以某种方式再次触发整个过程?

在字节码解析时,

invokedynamic仅与CallSite(或有时直接与目标方法)链接一次。解析结果保存在常量池缓存中,之后不会修改。

重置常量池缓存的一种可能方法是重新定义类。我不计算在不同的ClassLoader中重新加载类,因为这在技术上与加载与旧的类无关的新类相同。

因此,为了再次触发linkCallSite内容,您可以调用Instrumentation.redefineClasses或等效的JVM TI RedefineClasses函数。

  

这个方法到底是怎么调用的,或者它在哪里被调用?

linkToTargetMethod是在运行时动态创建的适配器,用于调用链接到特定invokedynamic字节码的MethodHandle。它基本上是调用此适配器的invokedynamic的实现。

Here is生成此适配器的源。