I am having some problems updating a debugger to work with Java 8. Consider the following program for example:
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));
}
}
As expected, Java 8 compiles the lambda to something like this:
> 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
This looks pretty much like normal code. However, I am trying to use the Java Debugger Interface (JDI) to intercept every step of the program. The fist thing that goes wrong is when I handle the ClassPrepareEvent event
corresponding to the lambda class. Asking the event.referenceType()
gives me something like Lam$$Lambda$1.1464642111
which is cool. But then calling .allLineLocations()
on the .referenceType()
gives a AbsentInformationException
, which seems at odds with the LineNumberTable
in the compiled file.
It looks like stepping through lambda bodies in Java 8 is possible. But does anyone know how it can be done in JDI?
Updates:
- when
.allLineLocations
is called on theLam
class, it does reflect all of these line numbers. - when a JDI
Event
happens within the lambda class (e.g. from stepping), the.sourceName()
of the location throws anAbsentInformationException
- it looks like
jdk.internal.org.objectweb.asm.*
is doing a bunch of stuff related to copying the lambda - I'm not sure if the map from source lines to bytecodes is kept in Java, or in the JDI
So my working hypothesis is that when the lambda's class is created at runtime, the JDI needs to do something to recognize that the new class's bytecode is coming from the old class's bytecode (which is in turn coming from from Lam.java
). I don't know enough about the internal representation of java.lang.Class
or com.sun.jdi.ClassType
to know where to begin.
Why am I trying to do this:
- to update the Java Visualizer to work with lambdas