首页 > 解决方案 > LDC指令代码的负值是什么意思?

问题描述

我对 java 字节码世界很陌生。我有一些涉及字节码的调试任务。在经历这些时,我注意到一些看起来可疑的值,但我不确定。这是完整字节码的一部分

// access flags 0x100A
  private static synthetic $jacocoInit()[Z
    GETSTATIC ClassUnderTest.$jacocoData : [Z
    DUP
    IFNONNULL L0
    POP
    LDC -1475355800743669619
    LDC "ClassUnderTest"
    BIPUSH 64
    INVOKESTATIC org/jacoco/agent/rt/internal_1f1cc91/Offline.getProbes (JLjava/lang/String;I)[Z
    DUP
    PUTSTATIC ClassUnderTest.$jacocoData : [Z
   L0

这里LDC -1475355800743669619是我关心的。到目前为止我学到的是,这是一个类中常量值的字段。

我很困惑LDC值是否可以为负?

我遇到的另一个问题是,对于 JDK-8,同一类的 LDC 值是正的,但对于 JDK-11,它是负的。所以我的问题是,它是否也依赖于 JDK?

标签: javajvmbytecodejacocojava-11

解决方案


Java 汇编没有标准化格式,因此,可能存在差异,具体取决于您用于获取文本形式的工具。

显然,您使用的工具不会打印LDC指令使用的常量池索引(确实必须是正数),而是打印池中的实际常量值。最强的指标是显示实际String值而不是常量池索引的后续指令。

这与随后的 调用相吻合getProbes(JLjava/lang/String;I),它需要堆栈上的a long、 aString和 an 。int

  • LDC -1475355800743669619将文字long值推送到-1475355800743669619堆栈上,该值在-1475355800743669619适合long值范围(有符号)时是有效的
  • LDC "ClassUnderTest"String将对表示的引用推"ClassUnderTest"送到堆栈
  • BIPUSH 64将文字int值推64入堆栈

那么,您在堆栈上有 a long、 aString和 anint用于调用getProbes.

由于该long值是 的getProbes第一个参数的参数,因此该方法getProbes确定其含义以及负值还是正值是合理的参数,以及对于 JDK 8 或 JDK 11,该值是否必须相同。

https://www.jacoco.org/jacoco/trunk/doc/implementation.html说:

在运行时加载的每个类都需要一个唯一的标识来关联覆盖数据。JaCoCo 通过原始类定义的 CRC64 哈希码创建此类身份。

如果这是long我们在这里看到的值,那么仅使用不同的 JDK 版本重新编译一个类可能会改变实际值,而负值是完全合理的。

请注意,如果您javap改用它来获取文本输出,它看起来更像

 0: getstatic       #42             // ClassUnderTest.$jacocoData : [Z
 3: dup
 4: ifnonnull       22
 7: pop
 9: ldc2_w          #43             // long -1475355800743669619l
11: ldc             #44             // String ClassUnderTest
13: bipush          64
15: invokestatic    #45             // org/jacoco/agent/rt/internal_1f1cc91/Offline."getProbes":(JLjava/lang/String;I)[Z
18: dup
19: putstatic       #42             // ClassUnderTest.$jacocoData : [Z

确实在行尾以注释形式显示了正常量池索引和实际值。当然,我只是编造了数字,因为我没有原始的类文件。这只是为了说明答案开头所述的事实,Java汇编输出没有标准化的形式。您可以javap在实际的字节码上运行。


推荐阅读