之前在C 语言陷阱最后提到了 JamVm,它是一个十分短小的 java 虚拟机,对于研究 java 虚拟机的实现是一个很好的起点。
JamVm 很早以前就已经不在维护了,具体可以看它的官网介绍。源码下载地址在sourceforge上。我个人感觉研究 jam 从它最老的的版本 1.0.0 下手是个比较好的选择。虽然 1.0.0 对 native 的支持不全,而且只支持 java4,但是毕竟代码量小( 6000+ C ),而 1.5.4 就已经近 2W 的 C 了。
2w 的 C 代码其实并没什么,只是对于研究 java 虚拟机实现来说,没必要。无非是多支持了几条新的虚拟机指令,多支持了一些 native,有些模块甚至为了效率牺牲了可读性等等。很多时候代码的复杂度和代码量往往不是线性关系的,而是指数关系不是么?
这个过程中会遇到一些问题,各种问题会导致探索体验变差,其中的几个问题我在之前的文章中提到过,现在系统的总结一下,想要自己折腾的可以忽略后面的全部内容。
下载的源码中包括 jam 的源码,以及它所需要的 classpath0.0.4 的源码。这个 classpath 就是 jre,当然现在也已经停止开发了,详情可以参考GNU Classpath。
推荐直接在 32bit 的系统上 build,我用的是 ubuntu12.04-32bit。
classpath 用的还是 GNU 编译 3 步走,configure,make,make install。不过 configure 的时候很可能会出错,说找不到 javac。根本原因是 configure 文件需要 gcj 或者 jikes,但是这两个项目现在都 die 了。一种解决方案是,ubuntu 源里面有 gcj4.8,先装一个 gcj4.8,configure 没有问题,但是编译肯定还是一堆的错误。原因是 gcj4.8 默认是 java5,而 classpath 的源码是 java4,所以手动改一下生成的 lib/Makefile,用 gcj 的-fsource 和-ftarget 参数将版本指定为 java1.4 就行了。
不想装 gcj 的可以装 openjdk,然后做个软连接,用 openjdk 的 javac 冒充 gcj。也需要再修改 Makefile,原理相同。
当然编译中可能还会有其他问题。
如果编译器支持 cast-as-lvalue 扩展,那么编译 jam 还是很容易的。不过很遗憾,gcc4.X 这个扩展已经没有了。由于 JamVM1.0.0 是 2003 年开发的,所以代码里面充斥着将 cast-as-lvalue。另外代码里面还存在 undefined behavior,这个在C 语言陷阱里面提到过,所以这个 JamVM 我直接修改了一个neojam,不存在 cast-as-lvalue 和其他的一些 gcc4.X 的编译错误,以及我已经发现的 undefined behavior。
如果还有问题请提 issue。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.