我在更新调试器以使用Java 8时遇到一些问题。例如,请考虑以下程序:
public class Lam {
public static void main(String[] args) {
java.util.function.Function<Integer, Integer> square =
x -> {
int result = 0;
for (int i=0;
i<x;
i++)
result++;
return result;
};
System.out.println(square.apply(5));
}
}
正如所料,Java 8将lambda编译成如下:
> javap -c -p -v -s -constants Lam
Classfile Lam.class
...
private static java.lang.Integer lambda$main$0(java.lang.Integer);
...
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
...
LineNumberTable:
line 5: 0
line 6: 2
line 7: 4
line 9: 12
line 8: 15
line 10: 21
这看起来非常像普通代码。但是,我试图使用Java调试器接口(JDI)来拦截程序的每一步。出错的第一件事是当我处理对应于lambda类的ClassPrepareEvent event
时。问event.referenceType()
给我一些像Lam$$Lambda$1.1464642111
这样很酷的东西。但是,在.allLineLocations()
上调用.referenceType()
会产生AbsentInformationException
,这似乎与编译文件中的LineNumberTable
不一致。
它看起来像是在Java 8 is possible中逐步执行lambda主体。但有人知道如何在JDI中完成它吗?
更新:
.allLineLocations
类上调用Lam
时, 会反映所有这些行号。 Event
发生在lambda类中时(例如来自步进),该位置的.sourceName()
会抛出AbsentInformationException
jdk.internal.org.objectweb.asm.*
正在做一堆与复制lambda相关的东西所以我的工作假设是,当lambda的类在运行时创建时,JDI需要做一些事情来识别新类的字节码来自旧类的字节码(而后者来自{{1} })。我对Lam.java
或java.lang.Class
的内部表示知之甚少,不知道从哪里开始。
为什么我要尝试这样做:
答案 0 :(得分:7)
您似乎将编译的类与运行时生成的lambda类混淆。后者只包含连接功能接口和编译器类lambda方法中的实现的粘合剂 - 这里没有任何你想要介入的东西,可能的例外是没有源的方法名称。 lambda类没有sourceName,因为没有源。 ASM代码正在构建生成的lambda类。从字节码位置到源代码行的映射在类文件中。