4.从0开始的手写java虚拟机 - 指令集和解释器
上一节我们描述了jvm是通过一个死循环不断执行指令直至循环结束;
接下来我们将描述每一条指令
4.1.通用指令接口
package base
import "HandWritingJVM/rtda"
//指令通用接口
type Instruction interface {
FetchOperands(reader *BytecodeReader)
Execute(frame *rtda.Frame)
}
//对应无操作数指令,如return, add, mul...
type NoOperandsInstruction struct {
}
func (self *NoOperandsInstruction) FetchOperands(reader *BytecodeReader) {
//...
}
//分支跳转指令
type BranchInstruction struct {
Offset int
}
func (self *BranchInstruction) FetchOperands(reader *BytecodeReader) {
self.Offset = int(reader.ReadInt16())
}
//操作数长度为8的相关指令
type Index8Instruction struct {
Index uint
}
func (self *Index8Instruction) FetchOperands(reader *BytecodeReader) {
self.Index = uint(reader.ReadUint8())
}
//操作数长度为16的相关指令
type Index16Instruction struct {
Index uint
}
func (self *Index16Instruction) FetchOperands(reader *BytecodeReader) {
self.Index = uint(reader.ReadUint16())
}
4.2.读取字节码相关操作
package base
type BytecodeReader struct {
code []byte
pc int
}
//重置当前栈帧的pc以及将要执行的方法
func (self *BytecodeReader) Reset(code []byte, pc int) {
self.code = code
self.pc = pc
}
func (self *BytecodeReader) PC() int {
return self.pc
}
//获取当前代码块中pc所指向的字节码指令
func (self *BytecodeReader) ReadUint8() uint8 {
i := self.code[self.pc]
self.pc++
return i
}
func (self *BytecodeReader) ReadInt8() int8 {
return int8(self.ReadUint8())
}
func (self *BytecodeReader) ReadUint16() uint16 {
byte1 := uint16(self.ReadUint8())
byte2 := uint16(self.ReadUint8())
return (byte1 << 8) | byte2
}
func (self *BytecodeReader) ReadInt16() int16 {
return int16(self.ReadUint16())
}
func (self *BytecodeReader) ReadInt32() int32 {
byte1 := int32(self.ReadUint8())
byte2 := int32(self.ReadUint8())
byte3 := int32(self.ReadUint8())
byte4 := int32(self.ReadUint8())
return (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4
}
func (self *BytecodeReader) ReadInt32s(count int32) []int32 {
ret := make([]int32, count)
for i := 0; i < int(count); i++ {
ret[i] = self.ReadInt32()
}
return ret
}
func (self *BytecodeReader) SkipPadding() {
for self.pc%4 != 0 {
self.ReadUint8()
}
}
4.3.常量指令
4.3.1.nop
解释:
package constants
import (
"HandWritingJVM/instructions/base"
"HandWritingJVM/rtda"
)
type NOP struct {
base.NoOperandsInstruction
}
func (self *NOP) Execute(frame *rtda.Frame) {
//...
}
4.3.2.const
解释:将一个值推入操作数栈中
package constants
import (
"HandWritingJVM/instructions/base"
"HandWritingJVM/rtda"
)
//将null推入操作数栈顶
type ACONST_NULL struct {
base.NoOperandsInstruction
}
/**
An aconst_null instruction is type safe if one can validly push the type
null onto the incoming operand stack yielding the outgoing type state.
*/
func (self *ACONST_NULL) Execute(frame *rtda.Frame) {
frame.OperandStack().PushRef(nil)
}
type DCONST_0 struct {
base.NoOperandsInstruction
}
//将double 0推入操作数栈顶,其他以此类推
func (self *DCONST_0) Execute(frame *rtda.Frame) {
frame.OperandStack().PushDouble(0.0)
}
//将double 1推入操作数栈顶
type DCONST_1 struct {
base.NoOperandsInstruction
}
func (self *DCONST_1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushDouble(1.0)
}
//将float 0推入栈顶,其他以此类推
type FCONST_0 struct {
base.NoOperandsInstruction
}
func (self *FCONST_0) Execute(frame *rtda.Frame) {
frame.OperandStack().PushFloat(0.0)
}
type FCONST_1 struct {
base.NoOperandsInstruction
}
func (self *FCONST_1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushFloat(1.0)
}
type FCONST_2 struct {
base.NoOperandsInstruction
}
func (self *FCONST_2) Execute(frame *rtda.Frame) {
frame.OperandStack().PushFloat(2)
}
//将int -1 推入栈顶,其他以此类推
type ICONST_M1 struct {
base.NoOperandsInstruction
}
func (self *ICONST_M1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(-1)
}
//将int 0推入栈顶,其他以此类推
type ICONST_0 struct {
base.NoOperandsInstruction
}
func (self *ICONST_0) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(0)
}
type ICONST_1 struct {
base.NoOperandsInstruction
}
func (self *ICONST_1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(1)
}
type ICONST_2 struct {
base.NoOperandsInstruction
}
func (self *ICONST_2) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(2)
}
type ICONST_3 struct {
base.NoOperandsInstruction
}
func (self *ICONST_3) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(3)
}
type ICONST_4 struct {
base.NoOperandsInstruction
}
func (self *ICONST_4) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(4)
}
type ICONST_5 struct {
base.NoOperandsInstruction
}
func (self *ICONST_5) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(5)
}
//将long 0推入栈顶,其他以此类推
type LCONST_0 struct {
base.NoOperandsInstruction
}
func (self *LCONST_0) Execute(frame *rtda.Frame) {
frame.OperandStack().PushLong(0)
}
type LCONST_1 struct {
base.NoOperandsInstruction
}
func (self *LCONST_1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushLong(1)
}
4.3.3.ipush
解释:读取一个值并推入操作数栈中
package constants
import (
"HandWritingJVM/instructions/base"
"HandWritingJVM/rtda"
)
type BIPUSH struct {
val int8
}
//从操作数中获取一个byte类型数据,扩展成int,然后推入栈顶
func (self *BIPUSH) FetchOperands(reader *base.BytecodeReader) {
self.val = reader.ReadInt8()
}
func (self *BIPUSH) Execute(frame *rtda.Frame) {
i := int32(self.val)
frame.OperandStack().PushInt(i)
}
type SIPUSH struct {
val int16
}
//从操作数中获取一个short类型数据,扩展成int,然后推入栈顶
func (self *SIPUSH) FetchOperands(reader *base.BytecodeReader) {
self.val = reader.ReadInt16()
}
func (self *SIPUSH) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(int32(self.val))
}
4.3.4.ldc
解释:从运行时常量池中取出元素并推入操作数栈顶
package constants
import (
"HandWritingJVM/instructions/base"
"HandWritingJVM/rtda"
"HandWritingJVM/rtda/heap"
)
//从常量池中取出元素然后推入操作数栈中,下标长度为8
//且推入的元素类型为int, float, string, classRef
type LDC struct {
base.Index8Instruction
}
//从常量池中取出元素然后推入操作数栈中,下标长度为16
//且推入的元素类型为int, float, string, classRef
type LDC_W struct {
base.Index16Instruction
}
//从常量池中取出元素然后推入操作数栈中,下标长度为16
//且推入的元素类型为long,double
type LDC2_W struct {
base.Index16Instruction
}
func (self *LDC) Execute(frame *rtda.Frame) {
_ldc(frame, self.Index)
}
func (self *LDC_W) Execute(frame *rtda.Frame) {
_ldc(frame, self.Index)
}
func _ldc(frame *rtda.Frame, index uint) {
stack := frame.OperandStack()
clazz := frame.Method().Class()
cp := clazz.ConstantPool()
c := cp.GetConstant(index)
switch c.(type) {
case int32:
stack.PushInt(c.(int32))
case float32:
stack.PushFloat(c.(float32))
case string:
internedStr := heap.JString(clazz.Loader(), c.(string))
stack.PushRef(internedStr)
case *heap.ClassRef:
classRef := c.(*heap.ClassRef)
classObj := classRef.ResolvedClass().JClass()
stack.PushRef(classObj)
default:
panic("todo: ldc!")
}
}
func (self *LDC2_W) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
cp := frame.Method().Class().ConstantPool()
c := cp.GetConstant(self.Index)
switch c.(type) {
case int64:
stack.PushLong(c.(int64))
case