`
chenjingbo
  • 浏览: 456149 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

使用-XX:+PrintAssembly打印asm代码遇到的问题

 
阅读更多

       要用PrintAssembly的目的 应该会另开帖子说明,本帖只是为了记录为了简单的记录使用这个命令遇到的问题.

 

      1 ,直接使用,用的是

写道
C:\Users\zhenghui>java -version
java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)

 该版本,当然,必须用不了咯..继续google.发现,需要用fastjson版本的jdk.然后,继续找.

       2,找到对应的下载地址. http://download.java.net/jdk6/6u25/promoted/b03/index.html

 注意,需要下载debug版本的.下载下来是一个jar,双击运行.然后就可以安装.

这里下载的b03版本,有可能在window下跑不通,每次运行都会造成jvm crash.可以换一下b01的试试

http://download.java.net/jdk6/6u25/promoted/b01/index.html  

 

     3  然后,就运行试试.继续遇到问题

写道
D:\software\jdk6_fastdebug\jdk1.6.0_25\fastdebug\bin>java -XX:+UnlockDiagnosticV
MOptions -XX:+PrintAssembly Test
VM option '+UnlockDiagnosticVMOptions'
VM option '+PrintAssembly'
Java HotSpot(TM) Client VM warning: PrintAssembly is enabled; turning on DebugNo
nSafepoints to gain additional output
Could not load hsdis-i386.dll; library not loadable; PrintAssembly is disabled

  4 后续就是找hsdis-i386.dll 的问题了.这也是我用时间最久的地方.我按照stackoverflow的说明,自己build这货,但是死的很惨,一直没成功.具体就不多说了,最后还是万能的撒迦告诉了我答案. 

RednaxelaFX 写道
是撒迦…  

这个疑问在之前某帖的回复里有提到:HotSpot的JIT编译器遇到简单无限循环时
RednaxelaFX 写道
lvgang 写道
好文,很有深度,就是看不太懂,呵呵。有个问题向博主请教,从上面打印出来的汇编代码来看,貌似是 gnu as,windows 上也能用 gnu as?

是的,这个是由GNU binutils里的as提供反汇编功能。
Sun HotSpot需要一个反汇编插件才可以使用-XX:+PrintAssembly参数来打印JIT编译生成的代码。该插件有一组通用接口,本来是可以用任意反汇编器套个适配器就行。官方提供了一个现成的版本(hsdis)是基于gas的,我懒于是就直接用它了。在Windows上直接build我还没成功过,用MinGW和Cygwin都试过不行。我用的版本是在Ubuntu上cross-compile出来的,根据插件作者提供的cross-compile指引来做没有遇到问题。
编译出来的hsdis-i386.dll放到JDK安装目录中jre/bin/server和jre/bin/client中即可。


不太记得是不是从Sun JDK 6 update 20开始,在product build的HotSpot里要用-XX:+PrintAssembly参数必须同时带上-XX:+UnlockDiagnosticVMOptions参数才可以。
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly YourMainClass

debug与fastdebug build就不用带。

而在比较老的Sun JDK 6里这个插件的名字要改为hdis-i486.dll才行。具体是从哪个版本开始变的我可以回头查查看。

如果有人需要我编译好的这个插件的话,待会儿可以上传一个到圈子共享里。
已经上传到圈子的共享里了

OpenJDK 7里可以看到还有另外一个附加的选项,-XX:PrintAssemblyOptions,可以用来向反编译插件传递参数。

借助HotSpot SA来反汇编
这帖提到的也是其中一个办法。看图:


=======================================

上面是针对Sun JDK的HotSpot而言。
JRockit的话要用别的办法,不过由于Oracle在输出的日志里说那信息是confidential的,所以抱歉我不能在这里说。
IBM J9的话我还没找到简单的办法。
Harmony、Jikes RVM、Maxine这些都有提供命令行参数可以让JVM把动态编译的汇编吐出来。

    然后 在JE的虚拟机圈子里找到了下载链接.

http://hllvm.group.iteye.com/group/share

 

     最后就是下载对应的 hsdis-i386.dll ,在DK目录下jre/bin/client和jre/bin/server中各放一份 .这个问题终于搞定..

 

在实际的使用中,我们通过直接加-XX:+PrintAssembly 打印ASM码会有两个问题

1 ASM码非常多.因为系统会打印出类似loadclass toString对应这些方法的ASM码.但是我们可能只关心对应的某一个方法而已.系统会打印8W行+的输出,但是我们可能只关心里面的100行

2 经常会帮我们内联.这个其实很纠结.之前为了这个内联,每次都想方设法如何让方法不被内联.当然,对应的解决方法也很简单.

 

对应的代码(我懒得自己写,就直接copy网上的了)

public class Test{
	int a = 1;
	static int b = 2;

	public int sum(int c){
		return a + b + c;
	}
	
	public static void main(String[] args){
		new Test().sum(3);
	}
}

 运行的代码如下

写道
D:\software\jdk6_fastdebug\jdk1.6.0_25\fastdebug\bin>java -Xcomp -XX:+PrintAssembly -XX:CompileCommand=dontinline,*Test.sum -XX:CompileCommand=compileonly,*Test.sum Test > log.txt

 其中,

  -XX:CompileCommand=dontinline,*Test.sum 这个表示不要把sum方法给内联了.这是解决内联问题

-XX:CompileCommand=compileonly,*Test.sum 这个表示只编译sum方法,这样的话,只会输出sum方法的ASM码.

对应的输出如下

写道
Java HotSpot(TM) Client VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output
VM option '+PrintAssembly'
VM option 'CompileCommand=dontinline,*Test.sum'
VM option 'CompileCommand=compileonly,*Test.sum'
CompilerOracle: dontinline *Test.sum
CompilerOracle: compileonly *Test.sum
Loaded disassembler from D:\software\jdk6_fastdebug\jdk1.6.0_25\fastdebug\jre\bin\client\hsdis-i386.dll
Decoding compiled method 0x026ab608:
Code:
[Disassembling for mach='i386']
[Entry Point]
[Constants]
# {method} 'sum' '(I)I' in 'Test'  //这个好理解,记录一下这个方法名对应的描述符
# this: ecx = 'Test'  //表示this指针在ecx寄存器中
# parm0: edx = int  //sum 方法对应的参数在edx寄存器中.
# [sp+0x20] (sp of caller)
;; block B1 [0, 0]

0x026ab700: nop
0x026ab701: nop
0x026ab702: nop
0x026ab703: nop
0x026ab704: nop
0x026ab705: nop
0x026ab706: nop
0x026ab707: cmp 0x4(%ecx),%eax
0x026ab70a: jne 0x0266ad90 ; {runtime_call}
[Verified Entry Point]
0x026ab710: mov %eax,-0x8000(%esp) //检查栈溢出
0x026ab717: push %ebp //保存上一栈帧基址
0x026ab718: sub $0x18,%esp ;*aload_0 //给新栈帧分配空间.这个18很奇怪,我试了好多,无聊方法写成什么样,都是$0x18.
; - Test::sum@0 (line 13)
;; block B0 [0, 10]

0x026ab71b: mov 0x8(%ecx),%eax ;*getfield a //获取实例变量a,放入eax寄存器中, %ecx在上面已经说了,是存放this指针的寄存器. 0x8(%ecx)表示越过test对象头(对象头占8个字节,后面就是跟着实例变量a的内存位置)
; - Test::sum@1 (line 13)
0x026ab71e: mov $0x2024d7d8,%esi ; {oop('Test')}//获取Test在方法区的指针, 可以看标记oop(methodName),$0x2024d7d8就是对应的Test方法区位置
0x026ab723: mov 0x150(%esi),%esi ;*getstatic b //获取对应的类变量b,放到esi寄存器中,0x150(%esi)表示在Test方法区指针开始的150偏移量的位置存放类变量b
; - Test::sum@4 (line 13)
0x026ab729: add %esi,%eax// esi存放的是b,eax存放的是a.两者相加,放到eax寄存器中
0x026ab72b: add %edx,%eax //edx 存放的是sum方法对应的参数c,eax存放着a+b的和.两者相加放到eax寄存器中
0x026ab72d: add $0x18,%esp //esp为对应的栈帧指针,之前sub 0x18 ,现在加回去.也就是撤销栈帧
0x026ab730: pop %ebp //恢复上一个栈帧
0x026ab731: test %eax,0x230100 ; {poll_return} //轮询方法返回处的SafePoint
0x026ab737: ret  //返回.
0x026ab738: nop
0x026ab739: nop
;; Unwind handler
0x026ab73a: mov %fs:0x0(,%eiz,1),%esi
0x026ab742: mov -0xc(%esi),%esi
0x026ab745: mov 0x198(%esi),%eax
0x026ab74b: movl $0x0,0x198(%esi)
0x026ab755: movl $0x0,0x19c(%esi)
0x026ab75f: add $0x18,%esp
0x026ab762: pop %ebp
0x026ab763: jmp 0x026a7be0 ; {runtime_call}
0x026ab768: hlt
0x026ab769: hlt
0x026ab76a: hlt
0x026ab76b: hlt
0x026ab76c: hlt
0x026ab76d: hlt
0x026ab76e: hlt
0x026ab76f: hlt
[Exception Handler]
[Stub Code]
0x026ab770: mov $0xdead,%ebx ; {no_reloc}
0x026ab775: mov $0xdead,%ecx
0x026ab77a: mov $0xdead,%esi
0x026ab77f: mov $0xdead,%edi
0x026ab784: call 0x026a9c40 ; {runtime_call}
0x026ab789: push $0x83c8bc0 ; {external_word}
0x026ab78e: call 0x026ab793
0x026ab793: pusha
0x026ab794: call 0x0822c2e0 ; {runtime_call}
0x026ab799: hlt
[Deopt Handler Code]
0x026ab79a: push $0x26ab79a ; {section_word}
0x026ab79f: jmp 0x0266bac0 ; {runtime_call}

 指令码的解析,上面基本都写了.

 

 

参照链接

http://stackoverflow.com/questions/1503479/how-to-see-jit-compiled-code-in-jvm/4149878#4149878

http://hllvm.group.iteye.com/group/topic/21769

https://blogs.oracle.com/kto/entry/mustang_jdk_6_0_fastdebug

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics