Java调试接口,Lambda和行号

dav*_*agp 11 java lambda jdi java-8

我在更新调试器以使用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));
    }
}
Run Code Online (Sandbox Code Playgroud)

正如所料,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
Run Code Online (Sandbox Code Playgroud)

这看起来非常像普通代码.但是,我试图使用Java调试器接口(JDI)来拦截程序的每一步.出现问题的第一件事是当我处理ClassPrepareEvent event对应的lambda类时.问event.referenceType()我给了我一些Lam$$Lambda$1.1464642111很酷的东西.但随后调用.allLineLocations().referenceType()给出了一个AbsentInformationException,这在同赔率似乎LineNumberTable在编译的文件.

看起来像是在Java 8中单步执行lambda主体是可能的.但有谁知道如何在JDI中完成它?

更新:

  • .allLineLocationsLam类上调用时,它确实反映了所有这些行号.
  • 当JDI Event在lambda类中发生时(例如从步进中),.sourceName()该位置抛出一个AbsentInformationException
  • 它似乎jdk.internal.org.objectweb.asm.*正在做一堆与复制lambda相关的东西
  • 我不确定从源代码行到字节代码的映射是保存在Java中还是保存在JDI中

所以我的工作假设是,当lambda的类在运行时创建时,JDI需要做一些事情来识别新类的字节码来自旧类的字节码(后来又来自Lam.java).我不了解内部表示java.lang.Classcom.sun.jdi.ClassType知道从哪里开始.

为什么我要这样做:

小智 7

您似乎将编译的类与运行时生成的lambda类混淆.后者只包含连接功能接口和编译器类lambda方法中的实现的粘合剂 - 这里没有任何你想要介入的东西,可能的例外是没有源的方法名称.lambda类没有sourceName,因为没有源.ASM代码正在构建生成的lambda类.从字节码位置到源代码行的映射在类文件中.