1.6.5 在IDE工具中进行源码调试

在阅读OpenJDK源码的过程中,经常需要运行、调试程序来帮助理解。我们现在已经可以编译出一个调试版本HotSpot虚拟机,禁用优化,并带有符号信息,这样就可以使用GDB来进行调试了。据笔者了解,许多对虚拟机了解比较深的开发人员确实就是直接使用GDB加VIM编辑器来开发、修改HotSpot的,不过相信大部分读者更倾向于在IDE环境而不是纯文本的GDB下阅读、跟踪HotSpot源码,因此这节就简单介绍一下“如何在IDE中进行HotSpot源码调试”。

首先,到NetBeans网站(http://netbeans.org/)上下载最新版的NetBeans,下载时选择支持C/C++开发的那个版本。安装后,新建一个项目,选择“基于现有源代码的C/C++项目”,在源码文件夹中填入OpenJDK目录下hotspot目录的路径,在下面的单选按钮中选择“定制”,如图1-8所示,然后单击“下一步”按钮。

figure_0050_0010

图 1-8 在NetBeans中创建HotSpot项目(1)

接着,在“指定构建代码的方法”中选择“使用现有的makefile”,并填入Makefile文件的路径(在hotspot/make目录下),如图1-9所示。单击“下一步”按钮,将“构建命令”修改为以下内容:


${MAKE}-f Makefile clean jvmg

ALT_BOOTDIR=/Library/Java/JavaVirtualMachines/jdk1.7.0_04.jdk/Contents/Home ARCH_DATA_MODEL=64 LANG=C


figure_0051_0011

图 1-9 在NetBeans中创建HotSpot项目(2)

OpenJDK 7u4源码Makefile在终端运行时能正确获取到系统指令集架构为64位,但在NetBeans中却没有取得正确的值,误认为是32位,因此这里必须使用ARCH_DATA_MODEL参数明确指定为64位。另外两个参数ALT_BOOTDIR和LANG的作用前面已经介绍过。单击“完成”按钮,HotSpot项目就这样导入到NetBeans中了。

不过,这时候HotSpot还运行不起来,因为NetBeans根本不知道编译出来的结果放在哪里、哪个程序是虚拟机的入口等,这些内容都需要明确告知NetBeans。在HotSpot工程上单击右键,在弹出的快捷菜单中选择“属性”,在弹出的对话框中找到“运行”选项,设置运行命令为:


/Users/IcyFenix/Develop/JVM/jdkBuild/openjdk_7u4/hotspot/build/bsd/bsd_amd64_compiler2/jvmg/gamma Queens


上面的Queens是Makefile脚本自动产生的一段解八皇后问题的Java程序,用于测试虚拟机,这里笔者直接拿来用了,读者完全可以将它替换为自己的Java程序。

读者在调试Java代码执行时,如果要跟踪具体Java代码在虚拟机中是如何执行的,也许会觉得无从下手,因为目前在HotSpot主流的操作系统上,都采用模板解释器来执行字节码,它与JIT编译器一样,最终执行的汇编代码都是运行期间产生的,无法直接设置断点,所以HotSpot增加了以下参数来方便开发人员调试解释器。


-XX:+TraceBytecodes-XX:StopInterpreterAt=<n>


这组参数的作用是当遇到序号为<n>的字节码指令时,便会中断程序执行,进入断点调试。在调试解释器部分代码时,把这两个参数加到gamma后面即可。

最后,还需要在“环境”窗口中设置环境变量,也就是前面env.sh脚本所设置的那几个环境变量,如图1-10所示。

figure_0052_0012

图 1-10 在NetBeans中创建HotSpot项目(3)

完成以上配置之后,一个可修改、编译、调试的HotSpot工程就完全建立起来了,启动器的执行入口是java.c的main()方法,读者可以设置断点单步跟踪,如图1-11所示。

figure_0053_0013

图 1-11 在NetBeans中创建HotSpot项目(4)

由于HotSpot的源码比较长,C/C++文件数量也很多,为了便于读者阅读,所以代码清单1-3给出了各个目录中代码的主要用途,供读者参考。

代码清单1-3 HotSpot源码结构[1]

figure_0053_0014

figure_0054_0015

[1]该目录结构由RednaxelaFX整理:http://hllvm.group.iteye.com/group/topic/26998。