我在更新调试器以使用 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) 来拦截程序的每一步。出错的第一件事是当我处理ClassPrepareEvent event
对应于 lambda 类的时候。问这个event.referenceType()
给了我一些Lam$$Lambda$1.1464642111
很酷的东西。但是随后调用a .allLineLocations()
,这似乎与编译文件中的 the不一致。.referenceType()
AbsentInformationException
LineNumberTable
看起来在 Java 8 中单步执行 lambda 体是可能的。但是有谁知道如何在 JDI 中完成它?
更新:
- 当
.allLineLocations
在类上调用时Lam
,它确实反映了所有这些行号。 - 当 JDI
Event
在 lambda 类中发生时(例如,从步进),.sourceName()
该位置的AbsentInformationException
- 看起来
jdk.internal.org.objectweb.asm.*
正在做一堆与复制 lambda 相关的事情 - 我不确定从源代码行到字节码的映射是否保存在 Java 或 JDI 中
所以我的工作假设是,当 lambda 的类在运行时创建时,JDI 需要做一些事情来识别新类的字节码来自旧类的字节码(而旧类的字节码又来自Lam.java
)。我对内部表示的了解不够多,也不知道java.lang.Class
从com.sun.jdi.ClassType
哪里开始。
我为什么要这样做:
- 更新Java Visualizer以使用 lambda