jvm.go是一个完全用Go语言实现的JVM,关于这个项目的发起原因和简单介绍可以看这篇文章。
jvm.go的开发已经进行了一个半月了,除了HelloWorld和一些简单的Java代码以外,JUnit也可以正常运行了。下一步的计划是在jvm.go上把Jetty跑起来。下面介绍一下jvm.go的一些关键部分的设计和实现。
实现核心JVM其实是相对比较简单的,对照着JVM规范,把Thread、Frame、Operand Stack、Local Vars、Class、Object、Array、指令集等一一实现就可以了。下面以FrameStack和OperandStack为例,简单介绍一下:
type Stack struct { maxSize uint size uint _top *Frame // stack is implemented as linked list }
type OperandStack struct { size uint slots []Any }FrameStack是用链表(LinkedList)实现的,OperandStack内部其实用了Slice。
为了更好的代码可读性,每一个指令都实现成一了个struct,下面是iinc指令的完整代码:
package instructions import "jvmgo/jvm/rtda" // Increment local variable by constant type iinc struct { index uint _const int32 } func (self *iinc) fetchOperands(decoder *InstructionDecoder) { self.index = uint(decoder.readUint8()) self._const = int32(decoder.readInt8()) } func (self *iinc) Execute(frame *rtda.Frame) { localVars := frame.LocalVars() val := localVars.GetInt(self.index) val += self._const localVars.SetInt(self.index, val) }因为大部分指令都是需要操作OperandStack和/或LocalVars的,所以指令的Execute方法参数设计接收为*Frame类型的参数:
type Instruction interface { fetchOperands(decoder *InstructionDecoder) Execute(frame *rtda.Frame) }
最初开始写jvm.go的时候,用的是OpenJDK的rt.jar。但是因为要经常查看rt.jar的Java代码,用IDE可以直接跳进Oracle JDK的rt.jar代码里。所以为了方便,后来就改为针对Oracle的rt.jar进行开发。rt.jar里有几千个本地方法,目前为止,只实现了不到100个。下面是本地方法的类型定义:
type NativeMethod func(frame *rtda.Frame)
Go本身就是垃圾回收语言,所以jvm.go没有单独实现垃圾回收机制。
jvm.go把每个Java线程都映射为一个goroutine,下面是Thread.start0()本地方法的实现代码:
// private native void start0(); // ()V func start0(frame *rtda.Frame) { vars := frame.LocalVars() this := vars.GetThis() newThread := rtda.NewThread(this) runMethod := this.Class().GetInstanceMethod("run", "()V") newFrame := newThread.NewFrame(runMethod) newFrame.LocalVars().SetRef(0, this) newThread.PushFrame(newFrame) this.LockState() this.SetExtra(newThread) this.UnlockState() go interpreter.Loop(newThread) }
jvm.go已经有了很大的进展,但是离完整的JVM实现还差的很远。希望对Java和JVM,或者Go语言感兴趣的朋友可以review代码,甚至贡献代码。希望jvm.go有朝一日能够成为一个正真的jvm,一个有用的jvm
原文地址:http://blog.csdn.net/zxhoo/article/details/44104553