我对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吗?
最佳答案
Java程序集没有标准化的格式,因此,可能会有所不同,具体取决于您用来获取文本形式的工具。
显然,您使用的工具不会打印LDC
指令使用的常量池索引(实际上必须为正数),而是打印池中的实际常量值。最强的指示符是显示实际String
值而不是常量池索引的后续指令。
这适合于getProbes(JLjava/lang/String;I)
的后续调用,该调用在堆栈上需要long
,String
和int
。
LDC -1475355800743669619
将文字long
值-1475355800743669619
压入堆栈,当-1475355800743669619
符合long
值范围(带符号)时有效LDC "ClassUnderTest"
将对表示String
的"ClassUnderTest"
的引用推入堆栈BIPUSH 64
将文字int
值64
推入堆栈因此,您在堆栈上有一个
long
,String
和int
,用于调用getProbes
。由于
long
值是getProbes
的第一个参数的参数,因此getProbes
方法确定其含义以及负值或正值是合理的参数,以及JDK 8或JDK 11的值必须相同。https://www.jacoco.org/jacoco/trunk/doc/implementation.html说:
在运行时加载的每个类都需要一个唯一的标识才能将coverage数据与之关联。 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
确实在行尾以注释形式显示了正常数池索引和实际值。当然,由于我没有原始 class 文件,所以我只是补上了数字。这只是为了说明答案开头所述的事实,没有Java程序集输出的标准化形式。您可以在实际字节码上运行
javap
。