寒假看《自己动手写JVM》和《java虚拟机精讲》写了一个半成品JVM,C++实现,项目地址:JVM。
首先是字节码解析,主要是常量池,字段的解析,除了几个涉及到Annotation属性外,基本都实现了解析,Attribute_Annotation_xxx涉及到的一些结构体嵌套太复杂了,暂时先没做(不影响运行)
然后是运行时数据区(RDTA),主要涉及到线程,java虚拟机栈(Stack),方法帧(Frame),本地变量(Local Variables),操作数栈(Operand Stack)。都是简单的数据结构。
之后实现100多条基本字节码指令,const,load,store,math之类的。自此已经可以通过hack运行一些简单的单函数class文件。
直后开始写heap,存放class静态字段和方法的地方,把class文件的constantpool转化为堆区的constantpool,然后实现堆区的方法和字段信息,以及方法字段的符号引用。然后就可以开始写classloader了,注意数组和非数组类要分开实现,加载有几个阶段:先read,用composite模式实现zip,目录,同配符的entry,实现一个classpath读取器,根据classname获取对应path中类文件的字节数组;然后define,解析类文件,然后link,verify,prepare,迭代解析类的接口,超类,级联加载到heap。
然后开始写方法的调用和参数传递返回,完善指令解释器,实现return系列的指令。此时可以初始化类了(调用<clinit>
)方法,并可运行一些带有递归和调用的例子,如fibonacci,可以在repo的demo里面找到测试用例。
最后时注册本地方法实现native method。例如System.out.println()
。然而我的java.lang.System
一直没法正常初始化。解析到native method就死循环,还没发现bug在哪。所以这里的println
是hack出来的。以后有空补上GC,多线程和异常处理。项目本身只能运行不多的class文件,io网络GUI什么的统统没有,经典的成功的case都在demo里面给出了。
大概1.5w行的样子,估计bug很多,内存泄露的问题很严重,(还是敲出来学习为主)。编译的class文件使用jdk11,repo中附带的rt.jar
是8的,测试通过。