打印Java热点JIT汇编代码

5

我在Java中编写了一个非常愚蠢的测试类:

public class Vector3 {
   public double x,y,z ;

   public Vector3(double x, double y, double z) {
       this.x=x ; this.y=y ; this.z=z ;
   }

   public Vector3 subst(Vector3 v) {
      return new Vector3(x-v.x,y-v.y,z-v.z) ;
   }
}

然后我想要查看由Java Hotspot JIT(Client VM build 23.7-b01)生成的代码。我使用了"-XX:+PrintAssembly"选项和来自http://classparser.blogspot.dk/2010/03/hsdis-i386dll.html的hsdis-i386.dll。
这里是生成代码的有趣部分(我省略了新对象的初始化。编辑:subst方法的代码)。显然,ebx是“this”指针,edx是参数指针。
lds    edi,(bad)
sti    
adc    BYTE PTR [ebx+8],al  ;*getfield x
mov    edx,DWORD PTR [esp+56]
lds    edi,(bad)          ; implicit exception: dispatches to 0x02611f2d
sti    
adc    BYTE PTR [edx+8],cl  ;*getfield x
lds    edi,(bad)
sti    
adc    BYTE PTR [ebx+16],dl  ;*getfield y
lds    edi,(bad)
sti    
adc    BYTE PTR [edx+16],bl  ;*getfield y
lds    edi,(bad)
sti    
adc    BYTE PTR [ebx+24],ah  ;*getfield z
lds    edi,(bad)
sti    
adc    BYTE PTR [edx+24],ch  ;*getfield z
lds    edi,(bad)
sti    
pop    esp
rol    ebp,0xfb
adc    DWORD PTR [eax+8],eax  ;*putfield x
lds    ebp,(bad)
jmp    0x02611f66
rol    ebp,cl
sti    
adc    DWORD PTR [eax+16],edx  ;*putfield y
lds    ebx,(bad)
fistp  DWORD PTR [ebp-59]
sti    
adc    DWORD PTR [eax+24],esp  ;*putfield z

说实话,我对x86汇编不是很熟悉,但是这段代码对你来说有意义吗?像"adc BYTE PTR [edx+8],cl"这样的奇怪指令是做什么的?我本来期望看到一些FPU指令。

如果您将问题标记为 assembly,可能会获得更好的答案。 - assylias
对我来说,这个汇编代码毫无意义。我怀疑这不是HotSpot生成的实际可执行代码。 - NPE
3
我怀疑你的反汇编器无法正确解释机器码。 LDS 操作码是 0xc5,但在较新的 x86 CPU 上,它也可能是一个 2字节的 VEX 前缀 - Michael
感谢您的回答。结论似乎是dll中使用的反汇编器未能正确解码生成的代码。我将尝试按照http://dropzone.nfshost.com/hsdis.htm上的说明自己构建dll。 - trunklop
请编写您自己找到的解决方案并接受它,这样人们就可以立即看到此问题已解决。这将有助于可能遇到类似问题的其他人。 - nrz
1个回答

6
我又来了。我已经使用最新的binutils 2.23构建了hsdis-i386.dll。由于http://dropzone.nfshost.com/hsdis.htm上的说明,这比我预期的要容易得多(至少对于x86版本是如此)。64位版本编译完成后立即停止JVM而没有任何错误消息。

现在的输出看起来好多了:

vmovsd xmm0,QWORD PTR [ebx+0x8]  ;*getfield x
mov    edx,DWORD PTR [esp+0x40]
vmovsd xmm1,QWORD PTR [edx+0x8]  ;*getfield x
vmovsd xmm2,QWORD PTR [ebx+0x10] ;*getfield y
vmovsd xmm3,QWORD PTR [edx+0x10] ;*getfield y
vmovsd xmm4,QWORD PTR [ebx+0x18] ;*getfield z
vmovsd xmm5,QWORD PTR [edx+0x18] ;*getfield z
vsubsd xmm0,xmm0,xmm1
vmovsd QWORD PTR [eax+0x8],xmm0  ;*putfield x
vsubsd xmm2,xmm2,xmm3
vmovsd QWORD PTR [eax+0x10],xmm2 ;*putfield y
vsubsd xmm4,xmm4,xmm5
vmovsd QWORD PTR [eax+0x18],xmm4 ;*putfield z

看起来非常可信 (+1) - NPE
确实 :) 我编写了一个简单的光线追踪程序,通过这个功能,看到JIT如何工作真是太好了。像Vector3这样的类完全内联,因为它们没有子类。 SSE2扩展被用作一种“超级FPU”。有点令人失望的是:在Vector3的构造函数中,JIT代码总是首先将this.x,this.y,this.z设置为0.0,即使在“new Vector3(x-v.x,y-v.y,z-v.z)”中也是如此。三个不必要的每个8字节的内存访问。 - trunklop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接