第五章讲的是指令集和解释器,这张主要讲解了JVM的指令集相关内容并实现了一些指令,最终实现了加载类并运行main函数实现一个1+2+...100的程序
虚拟机就是一台虚拟的机器一样,模拟我们真实的硬件环境,虚拟机的指令集就像是我们电脑上运行的汇编指令集一样,JVM就是通过定义自己的字节码指令集,在不同的平台上实现能够执行这些指令集的Java虚拟机才能够实现跨平台,Java编译器会把Java代码编译成对应的字节码指令,让JVM执行。不仅Java有字节码,其他基于虚拟机平台的语言也有类似的指令集,CLR的IL指令集,Lua也有对应的指令集。
接下来让我们来了解一下JVM的指令集,前面我们知道,每个class文件都有一个method_info存储了方法,每个方法都有自己的属性表,其中code属性就存储了我们的字节码指令,执行方法的时候就会拿到对应的字节码序列创建一个栈帧,压栈到虚拟机栈
为什么叫字节码?因为Java的每一个操作指令有对应的一个操作码(opcode)来对应,这个opcode只有一字节来存储,所以最多只能有256个指令(理论上),截至JDK8已经有205个指令
method_info的code属性里面的code字段存储了字节码序列,一条字节码由两部分组成
opcode operands
也就是操作码和操作数,操作数也可以看作参数,操作数可有可无,看具体指令,JVM的指令集分为以下几类
有一个注意的点是操作数栈只存储数据的值而不存储对应的类型,比如我存储一个1,他可能是int,long,char,但是指令操作数据的时候必须要知道自己操作的是什么类型,JVM用助记符来做到这一点,每个操作码都对应一个助记符,比如add类指令,有
iadd,ladd,fadd,dadd
这四个指令开头一个字母就代表操作类型,所以一类指令有很多重复版本。
书中把指令集分为11类
网上也有分为以下的
我们按书上得来,建立以下结构
了解了上面指令集相关内容,来了解一下解释器,虚拟机无非是一个不断解释执行命令的机器,按对应的指令实现不同的操作,我们可以用一下伪代码来了解一下常见的解释器的逻辑
c// 初始化JVM状态
initializeJVMState()
// 主循环,解释并执行字节码指令
while (true) {
// 获取当前指令的地址
pc = getProgramCounter()
// 从代码区读取当前指令
opcode = fetchInstruction(pc)
// 根据操作码执行相应的操作
switch (opcode) {
case ILOAD:
// 加载int类型局部变量
index = fetchOperand(pc + 1)
value = getLocalVariable(index)
pushOperandStack(value)
pc += 2
break
case ISTORE:
// 存储int类型局部变量
index = fetchOperand(pc + 1)
value = popOperandStack()
setLocalVariable(index, value)
pc += 2
break
case IADD:
// 执行int类型加法
value2 = popOperandStack()
value1 = popOperandStack()
result = value1 + value2
pushOperandStack(result)
pc += 1
break
case IF_ICMPEQ:
// 如果两个int值相等则跳转
offset = fetchOperand(pc + 1)
value2 = popOperandStack()
value1 = popOperandStack()
if (value1 == value2) {
pc += offset
} else {
pc += 2
}
break
case GOTO:
// 无条件跳转
offset = fetchOperand(pc + 1)
pc += offset
break
case RETURN:
// 方法返回
return
// 其他指令...
default:
throwException("Unsupported opcode: " + opcode)
}
// 更新程序计数器
setProgramCounter(pc)
}
就是不断取命令执行的死循环,但是两百多个指令,都写在一个switch case里面很难看,所以我们用接口来实现对应的指令,每个指令都是接口的实现,这样就变成了以下的样子
gofunc Run() {
for {
pc := calculatPc()
opcode := byteCode[pc]
inst := createIs(opcode)
inst.Execute()
}
}
是不是很简洁!接下来实现对应接口
go// Instruction 接口定义了所有指令的通用行为
type Instruction interface {
FetchOperands(reader *BytecodeReader) // 从字节码读取操作数
Execute(frame *rtda.Frame) // 执行指令
}
因为我们观察到有很多同一类型指令他的操作数的个数是相同的,所以取操作数过程也相同,我们用一个结构体来代表这类指令,这样FetchOperands一类指令只需要实现一次,减少重复代码
go// NoOperandsInstruction 结构体表示没有操作数的指令
type NoOperandsInstruction struct {
}
// FetchOperands 方法实现,对于没有操作数的指令,什么也不做
func (self *NoOperandsInstruction) FetchOperands(reader *BytecodeReader) {
}
// BranchInstruction 结构体表示分支指令
type BranchInstruction struct {
Offset int // 分支偏移量
}
// FetchOperands 方法实现,从字节码读取分支偏移量
func (self *BranchInstruction) FetchOperands(reader *BytecodeReader) {
self.Offset = int(reader.ReadInt16()) // 读取一个16位的有符号整数作为偏移量
}
// Index8Instruction 结构体表示需要8位索引的指令 存储,加载类
type Index8Instruction struct {
Index uint // 8位索引
}
// FetchOperands 方法实现,从字节码读取8位索引
func (self *Index8Instruction) FetchOperands(reader *BytecodeReader) {
self.Index = uint(reader.ReadUint8()) // 读取一个8位的无符号整数作为索引
}
// Index16Instruction 结构体表示需要16位索引的指令 运行时常量池
type Index16Instruction struct {
Index uint // 16位索引
}
// FetchOperands 方法实现,从字节码读取16位索引
func (self *Index16Instruction) FetchOperands(reader *BytecodeReader) {
self.Index = uint(reader.ReadUint16()) // 读取一个16位的无符号整数作为索引
}
以上对应无操作数指令,分支跳转类,存储加载类指令,还有常量池类指令
接下来定义ByteCodeReader对象,管理字节码
gopackage base
// BytecodeReader 结构体用于读取字节码
type BytecodeReader struct {
code []byte // 字节码数组
pc int // 程序计数器
}
// Reset 方法重置 BytecodeReader 的状态
func (self *BytecodeReader) Reset(code []byte, pc int) {
self.code = code // 设置字节码数组
self.pc = pc // 设置程序计数器
}
// PC 方法返回当前的程序计数器值
func (self *BytecodeReader) PC() int {
return self.pc
}
// ReadInt8 方法读取一个有符号的8位整数
func (self *BytecodeReader) ReadInt8() int8 {
return int8(self.ReadUint8()) // 调用 ReadUint8 并转换为 int8
}
// ReadUint8 方法读取一个无符号的8位整数
func (self *BytecodeReader) ReadUint8() uint8 {
i := self.code[self.pc] // 读取当前字节
self.pc++ // 增加程序计数器
return i
}
// ReadInt16 方法读取一个有符号的16位整数
func (self *BytecodeReader) ReadInt16() int16 {
return int16(self.ReadUint16()) // 调用 ReadUint16 并转换为 int16
}
// ReadUint16 方法读取一个无符号的16位整数
func (self *BytecodeReader) ReadUint16() uint16 {
byte1 := uint16(self.ReadUint8()) // 读取第一个字节
byte2 := uint16(self.ReadUint8()) // 读取第二个字节
return (byte1 << 8) | byte2 // 组合成16位整数
}
// ReadInt32 方法读取一个有符号的32位整数
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 // 组合成32位整数
}
// ReadInt32s 方法读取多个32位整数,用于 lookupswitch 和 tableswitch 指令
func (self *BytecodeReader) ReadInt32s(n int32) []int32 {
ints := make([]int32, n) // 创建一个长度为 n 的 int32 数组
for i := range ints {
ints[i] = self.ReadInt32() // 读取每个32位整数
}
return ints
}
// SkipPadding 方法跳过填充字节,确保字节码对齐
func (self *BytecodeReader) SkipPadding() {
for self.pc%4 != 0 { // 循环直到程序计数器对齐到4字节边界
self.ReadUint8() // 读取并丢弃一个字节
}
}
接下来将实现150多个指令,大部分是重复指令,第一个是nop
,他什么也不做
go// NOP 结构体表示无操作指令
type NOP struct{ base.NoOperandsInstruction }
// Execute 方法实现,对于 NOP 指令,什么也不做
func (self *NOP) Execute(frame *rtda.Frame) {
// really do nothing
}
作用是把操作码中隐藏的的常量压入操作数栈的栈顶
go
// Push null
type ACONST_NULL struct{ base.NoOperandsInstruction }
func (self *ACONST_NULL) Execute(frame *rtda.Frame) {
frame.OperandStack().PushRef(nil) // 将 nil 推入操作数栈
}
// Push double
type DCONST_0 struct{ base.NoOperandsInstruction }
func (self *DCONST_0) Execute(frame *rtda.Frame) {
frame.OperandStack().PushDouble(0.0) // 将 0.0 推入操作数栈
}
type DCONST_1 struct{ base.NoOperandsInstruction }
func (self *DCONST_1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushDouble(1.0) // 将 1.0 推入操作数栈
}
// Push float
type FCONST_0 struct{ base.NoOperandsInstruction }
func (self *FCONST_0) Execute(frame *rtda.Frame) {
frame.OperandStack().PushFloat(0.0) // 将 0.0 推入操作数栈
}
type FCONST_1 struct{ base.NoOperandsInstruction }
func (self *FCONST_1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushFloat(1.0) // 将 1.0 推入操作数栈
}
type FCONST_2 struct{ base.NoOperandsInstruction }
func (self *FCONST_2) Execute(frame *rtda.Frame) {
frame.OperandStack().PushFloat(2.0) // 将 2.0 推入操作数栈
}
// Push int constant
type ICONST_M1 struct{ base.NoOperandsInstruction }
func (self *ICONST_M1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(-1) // 将 -1 推入操作数栈
}
type ICONST_0 struct{ base.NoOperandsInstruction }
func (self *ICONST_0) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(0) // 将 0 推入操作数栈
}
type ICONST_1 struct{ base.NoOperandsInstruction }
func (self *ICONST_1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(1) // 将 1 推入操作数栈
}
type ICONST_2 struct{ base.NoOperandsInstruction }
func (self *ICONST_2) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(2) // 将 2 推入操作数栈
}
type ICONST_3 struct{ base.NoOperandsInstruction }
func (self *ICONST_3) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(3) // 将 3 推入操作数栈
}
type ICONST_4 struct{ base.NoOperandsInstruction }
func (self *ICONST_4) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(4) // 将 4 推入操作数栈
}
type ICONST_5 struct{ base.NoOperandsInstruction }
func (self *ICONST_5) Execute(frame *rtda.Frame) {
frame.OperandStack().PushInt(5) // 将 5 推入操作数栈
}
// Push long constant
type LCONST_0 struct{ base.NoOperandsInstruction }
func (self *LCONST_0) Execute(frame *rtda.Frame) {
frame.OperandStack().PushLong(0) // 将 0 推入操作数栈
}
type LCONST_1 struct{ base.NoOperandsInstruction }
func (self *LCONST_1) Execute(frame *rtda.Frame) {
frame.OperandStack().PushLong(1) // 将 1 推入操作数栈
}
接下来是bipush和sipush分别是从操作数取得一个byte类型转成Int在压到操作数栈,从操作数取出一个short转成int在压到操作数栈
go
type BIPUSH struct {
val int8
}
func (self *BIPUSH) FetchOperands(reader *base.BytecodeReader) {
self.val = reader.ReadInt8() // 从字节码读取一个有符号的8位整数
}
func (self *BIPUSH) Execute(frame *rtda.Frame) {
i := int32(self.val) // 将8位整数转换为32位整数
frame.OperandStack().PushInt(i) // 将整数推入操作数栈
}
type SIPUSH struct {
val int16
}
func (self *SIPUSH) FetchOperands(reader *base.BytecodeReader) {
self.val = reader.ReadInt16() // 从字节码读取一个有符号的16位整数
}
func (self *SIPUSH) Execute(frame *rtda.Frame) {
i := int32(self.val) // 将16位整数转换为32位整数
frame.OperandStack().PushInt(i) // 将整数推入操作数栈
}
加载类指令从局部变量表取出变量并压到操作数栈,因为都是重复代码,所以只给出引用加载和Double加载的代码
gotype ALOAD struct{ base.Index8Instruction }
func (self *ALOAD) Execute(frame *rtda.Frame) {
_aload(frame, self.Index) // 调用 _aload 函数,传入当前帧和索引
}
type ALOAD_0 struct{ base.NoOperandsInstruction }
func (self *ALOAD_0) Execute(frame *rtda.Frame) {
_aload(frame, 0) // 调用 _aload 函数,传入当前帧和索引0
}
type ALOAD_1 struct{ base.NoOperandsInstruction }
func (self *ALOAD_1) Execute(frame *rtda.Frame) {
_aload(frame, 1) // 调用 _aload 函数,传入当前帧和索引1
}
type ALOAD_2 struct{ base.NoOperandsInstruction }
func (self *ALOAD_2) Execute(frame *rtda.Frame) {
_aload(frame, 2) // 调用 _aload 函数,传入当前帧和索引2
}
type ALOAD_3 struct{ base.NoOperandsInstruction }
func (self *ALOAD_3) Execute(frame *rtda.Frame) {
_aload(frame, 3) // 调用 _aload 函数,传入当前帧和索引3
}
func _aload(frame *rtda.Frame, index uint) {
ref := frame.LocalVars().GetRef(index) // 从局部变量表获取引用
frame.OperandStack().PushRef(ref) // 将引用推入操作数栈
}
// double load
type DLOAD struct{ base.Index8Instruction } // DLOAD 指令结构体,继承自 base.Index8Instruction
func (self *DLOAD) Execute(frame *rtda.Frame) {
_dload(frame, self.Index) // 执行 DLOAD 指令,调用 _dload 函数
}
type DLOAD_0 struct{ base.NoOperandsInstruction } // DLOAD_0 指令结构体,继承自 base.NoOperandsInstruction
func (self *DLOAD_0) Execute(frame *rtda.Frame) {
_dload(frame, 0) // 执行 DLOAD_0 指令,调用 _dload 函数
}
type DLOAD_1 struct{ base.NoOperandsInstruction } // DLOAD_1 指令结构体,继承自 base.NoOperandsInstruction
func (self *DLOAD_1) Execute(frame *rtda.Frame) {
_dload(frame, 1) // 执行 DLOAD_1 指令,调用 _dload 函数
}
type DLOAD_2 struct{ base.NoOperandsInstruction } // DLOAD_2 指令结构体,继承自 base.NoOperandsInstruction
func (self *DLOAD_2) Execute(frame *rtda.Frame) {
_dload(frame, 2) // 执行 DLOAD_2 指令,调用 _dload 函数
}
type DLOAD_3 struct{ base.NoOperandsInstruction } // DLOAD_3 指令结构体,继承自 base.NoOperandsInstruction
func (self *DLOAD_3) Execute(frame *rtda.Frame) {
_dload(frame, 3) // 执行 DLOAD_3 指令,调用 _dload 函数
}
func _dload(frame *rtda.Frame, index uint) {
val := frame.LocalVars().GetDouble(index) // 从局部变量表中获取 double 值
frame.OperandStack().PushDouble(val) // 将 double 值推入操作数栈
}
其他的都差不多
存储指令从操作数栈弹出变量存到局部变量表
go
type ASTORE struct{ base.Index8Instruction } // ASTORE 指令结构体,继承自 base.Index8Instruction
func (self *ASTORE) Execute(frame *rtda.Frame) {
_astore(frame, uint(self.Index)) // 执行 ASTORE 指令,调用 _astore 函数
}
type ASTORE_0 struct{ base.NoOperandsInstruction } // ASTORE_0 指令结构体,继承自 base.NoOperandsInstruction
func (self *ASTORE_0) Execute(frame *rtda.Frame) {
_astore(frame, 0) // 执行 ASTORE_0 指令,调用 _astore 函数
}
type ASTORE_1 struct{ base.NoOperandsInstruction } // ASTORE_1 指令结构体,继承自 base.NoOperandsInstruction
func (self *ASTORE_1) Execute(frame *rtda.Frame) {
_astore(frame, 1) // 执行 ASTORE_1 指令,调用 _astore 函数
}
type ASTORE_2 struct{ base.NoOperandsInstruction } // ASTORE_2 指令结构体,继承自 base.NoOperandsInstruction
func (self *ASTORE_2) Execute(frame *rtda.Frame) {
_astore(frame, 2) // 执行 ASTORE_2 指令,调用 _astore 函数
}
type ASTORE_3 struct{ base.NoOperandsInstruction } // ASTORE_3 指令结构体,继承自 base.NoOperandsInstruction
func (self *ASTORE_3) Execute(frame *rtda.Frame) {
_astore(frame, 3) // 执行 ASTORE_3 指令,调用 _astore 函数
}
func _astore(frame *rtda.Frame, index uint) {
ref := frame.OperandStack().PopRef() // 从操作数栈中弹出引用
frame.LocalVars().SetRef(index, ref) // 将引用存储到局部变量表中
}
// double store
type DSTORE struct{ base.Index8Instruction } // DSTORE 指令结构体,继承自 base.Index8Instruction
func (self *DSTORE) Execute(frame *rtda.Frame) {
_dstore(frame, uint(self.Index)) // 执行 DSTORE 指令,调用 _dstore 函数
}
type DSTORE_0 struct{ base.NoOperandsInstruction } // DSTORE_0 指令结构体,继承自 base.NoOperandsInstruction
func (self *DSTORE_0) Execute(frame *rtda.Frame) {
_dstore(frame, 0) // 执行 DSTORE_0 指令,调用 _dstore 函数
}
type DSTORE_1 struct{ base.NoOperandsInstruction } // DSTORE_1 指令结构体,继承自 base.NoOperandsInstruction
func (self *DSTORE_1) Execute(frame *rtda.Frame) {
_dstore(frame, 1) // 执行 DSTORE_1 指令,调用 _dstore 函数
}
type DSTORE_2 struct{ base.NoOperandsInstruction } // DSTORE_2 指令结构体,继承自 base.NoOperandsInstruction
func (self *DSTORE_2) Execute(frame *rtda.Frame) {
_dstore(frame, 2) // 执行 DSTORE_2 指令,调用 _dstore 函数
}
type DSTORE_3 struct{ base.NoOperandsInstruction } // DSTORE_3 指令结构体,继承自 base.NoOperandsInstruction
func (self *DSTORE_3) Execute(frame *rtda.Frame) {
_dstore(frame, 3) // 执行 DSTORE_3 指令,调用 _dstore 函数
}
func _dstore(frame *rtda.Frame, index uint) {
val := frame.OperandStack().PopDouble() // 从操作数栈中弹出 double 值
frame.LocalVars().SetDouble(index, val) // 将 double 值存储到局部变量表中
}
栈指令是直接对操作数栈进行操作
go// 从操作数弹出
type POP struct{ base.NoOperandsInstruction } // 定义 POP 指令结构体,继承自 base.NoOperandsInstruction
func (self *POP) Execute(frame *rtda.Frame) { // 实现 POP 指令的 Execute 方法
stack := frame.OperandStack() // 获取当前帧的操作数栈
stack.PopSlot() // 弹出操作数栈的栈顶值
}
type POP2 struct{ base.NoOperandsInstruction } // 定义 POP2 指令结构体,继承自 base.NoOperandsInstruction
func (self *POP2) Execute(frame *rtda.Frame) { // 实现 POP2 指令的 Execute 方法
stack := frame.OperandStack() // 获取当前帧的操作数栈
stack.PopSlot() // 弹出操作数栈的栈顶值
stack.PopSlot() // 再次弹出操作数栈的栈顶值
}
// 复制 dup
type DUP struct{ base.NoOperandsInstruction } // 定义 DUP 指令结构体,继承自 base.NoOperandsInstruction
func (self *DUP) Execute(frame *rtda.Frame) { // 实现 DUP 指令的 Execute 方法
stack := frame.OperandStack() // 获取当前帧的操作数栈
slot := stack.PopSlot() // 弹出操作数栈的栈顶值
stack.PushSlot(slot) // 将弹出的值再次压入操作数栈
stack.PushSlot(slot) // 再次将弹出的值压入操作数栈
}
type DUP_X1 struct{ base.NoOperandsInstruction } // 定义 DUP_X1 指令结构体,继承自 base.NoOperandsInstruction
func (self *DUP_X1) Execute(frame *rtda.Frame) { // 实现 DUP_X1 指令的 Execute 方法
stack := frame.OperandStack() // 获取当前帧的操作数栈
slot1 := stack.PopSlot() // 弹出操作数栈的栈顶值
slot2 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
stack.PushSlot(slot1) // 将第一次弹出的值压入操作数栈
stack.PushSlot(slot2) // 将第二次弹出的值压入操作数栈
stack.PushSlot(slot1) // 再次将第一次弹出的值压入操作数栈
}
type DUP_X2 struct{ base.NoOperandsInstruction } // 定义 DUP_X2 指令结构体,继承自 base.NoOperandsInstruction
func (self *DUP_X2) Execute(frame *rtda.Frame) { // 实现 DUP_X2 指令的 Execute 方法
stack := frame.OperandStack() // 获取当前帧的操作数栈
slot1 := stack.PopSlot() // 弹出操作数栈的栈顶值
slot2 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
slot3 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
stack.PushSlot(slot1) // 将第一次弹出的值压入操作数栈
stack.PushSlot(slot3) // 将第三次弹出的值压入操作数栈
stack.PushSlot(slot2) // 将第二次弹出的值压入操作数栈
stack.PushSlot(slot1) // 再次将第一次弹出的值压入操作数栈
}
type DUP2 struct{ base.NoOperandsInstruction } // 定义 DUP2 指令结构体,继承自 base.NoOperandsInstruction
func (self *DUP2) Execute(frame *rtda.Frame) { // 实现 DUP2 指令的 Execute 方法
stack := frame.OperandStack() // 获取当前帧的操作数栈
slot1 := stack.PopSlot() // 弹出操作数栈的栈顶值
slot2 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
stack.PushSlot(slot2) // 将第二次弹出的值压入操作数栈
stack.PushSlot(slot1) // 将第一次弹出的值压入操作数栈
stack.PushSlot(slot2) // 再次将第二次弹出的值压入操作数栈
stack.PushSlot(slot1) // 再次将第一次弹出的值压入操作数栈
}
type DUP2_X1 struct{ base.NoOperandsInstruction } // 定义 DUP2_X1 指令结构体,继承自 base.NoOperandsInstruction
func (self *DUP2_X1) Execute(frame *rtda.Frame) { // 实现 DUP2_X1 指令的 Execute 方法
stack := frame.OperandStack() // 获取当前帧的操作数栈
slot1 := stack.PopSlot() // 弹出操作数栈的栈顶值
slot2 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
slot3 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
stack.PushSlot(slot2) // 将第二次弹出的值压入操作数栈
stack.PushSlot(slot1) // 将第一次弹出的值压入操作数栈
stack.PushSlot(slot3) // 将第三次弹出的值压入操作数栈
stack.PushSlot(slot2) // 再次将第二次弹出的值压入操作数栈
stack.PushSlot(slot1) // 再次将第一次弹出的值压入操作数栈
}
type DUP2_X2 struct{ base.NoOperandsInstruction } // 定义 DUP2_X2 指令结构体,继承自 base.NoOperandsInstruction
func (self *DUP2_X2) Execute(frame *rtda.Frame) { // 实现 DUP2_X2 指令的 Execute 方法
stack := frame.OperandStack() // 获取当前帧的操作数栈
slot1 := stack.PopSlot() // 弹出操作数栈的栈顶值
slot2 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
slot3 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
slot4 := stack.PopSlot() // 再次弹出操作数栈的栈顶值
stack.PushSlot(slot2) // 将第二次弹出的值压入操作数栈
stack.PushSlot(slot1) // 将第一次弹出的值压入操作数栈
stack.PushSlot(slot4) // 将第四次弹出的值压入操作数栈
stack.PushSlot(slot3) // 将第三次弹出的值压入操作数栈
stack.PushSlot(slot2) // 再次将第二次弹出的值压入操作数栈
stack.PushSlot(slot1) // 再次将第一次弹出的值压入操作数栈
}
// swap
type SWAP struct{ base.NoOperandsInstruction }
func (self *SWAP) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
slot1 := stack.PopSlot()
slot2 := stack.PopSlot()
stack.PushSlot(slot1)
stack.PushSlot(slot2)
}
加减乘除指令
go
type DADD struct{ base.NoOperandsInstruction }
func (self *DADD) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
v1 := stack.PopDouble()
v2 := stack.PopDouble()
result := v1 + v2
stack.PushDouble(result)
}
...
// 增加局部变量表某个值
type IINC struct {
Index uint
Const int32
}
func (self *IINC) FetchOperands(reader *base.BytecodeReader) {
self.Index = uint(reader.ReadUint8())
self.Const = int32(reader.ReadInt8())
}
func (self *IINC) Execute(frame *rtda.Frame) {
localVars := frame.LocalVars()
val := localVars.GetInt(self.Index)
val += self.Const
localVars.SetInt(self.Index, val)
}
...
type DMUL struct{ base.NoOperandsInstruction }
func (self *DMUL) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
v2 := stack.PopDouble()
v1 := stack.PopDouble()
result := v1 * v2
stack.PushDouble(result)
}
...
type DNEG struct{ base.NoOperandsInstruction }
func (self *DNEG) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
val := stack.PopDouble()
stack.PushDouble(-val)
}
...
type DREM struct{ base.NoOperandsInstruction }
func (self *DREM) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
v2 := stack.PopDouble()
v1 := stack.PopDouble()
result := math.Mod(v1, v2) // todo
stack.PushDouble(result)
}
差不多,省略了很多
用于类型转换
gotype D2F struct{ base.NoOperandsInstruction }
func (self *D2F) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
d := stack.PopDouble()
f := float32(d)
stack.PushFloat(f)
}
基本类型转换类型都差不多
比较操作数栈顶两个值压入结果,还有一类是比较跳转,是if和while的基石
gotype DCMPG struct{ base.NoOperandsInstruction }
func (self *DCMPG) Execute(frame *rtda.Frame) {
_dcmp(frame, true)
}
type DCMPL struct{ base.NoOperandsInstruction }
func (self *DCMPL) Execute(frame *rtda.Frame) {
_dcmp(frame, false)
}
func _dcmp(frame *rtda.Frame, gFlag bool) {
stack := frame.OperandStack()
v2 := stack.PopDouble()
v1 := stack.PopDouble()
if v1 > v2 {
stack.PushInt(1)
} else if v1 == v2 {
stack.PushInt(0)
} else if v1 < v2 {
stack.PushInt(-1)
} else if gFlag {
stack.PushInt(1)
} else {
stack.PushInt(-1)
}
}
type LCMP struct{ base.NoOperandsInstruction }
func (self *LCMP) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
v2 := stack.PopLong()
v1 := stack.PopLong()
if v1 > v2 {
stack.PushInt(1)
} else if v1 == v2 {
stack.PushInt(0)
} else {
stack.PushInt(-1)
}
}
下面是比较跳转
go// Branch if reference comparison succeeds
type IF_ACMPEQ struct{ base.BranchInstruction } // 定义 IF_ACMPEQ 指令结构体,继承自 base.BranchInstruction
func (self *IF_ACMPEQ) Execute(frame *rtda.Frame) { // 实现 IF_ACMPEQ 指令的 Execute 方法
if _acmp(frame) { // 调用 _acmp 函数进行引用比较,如果相等则跳转
base.Branch(frame, self.Offset) // 执行跳转
}
}
type IF_ACMPNE struct{ base.BranchInstruction } // 定义 IF_ACMPNE 指令结构体,继承自 base.BranchInstruction
func (self *IF_ACMPNE) Execute(frame *rtda.Frame) { // 实现 IF_ACMPNE 指令的 Execute 方法
if !_acmp(frame) { // 调用 _acmp 函数进行引用比较,如果不相等则跳转
base.Branch(frame, self.Offset) // 执行跳转
}
}
func _acmp(frame *rtda.Frame) bool { // 定义 _acmp 函数,用于比较两个引用
stack := frame.OperandStack() // 获取当前帧的操作数栈
ref2 := stack.PopRef() // 弹出操作数栈的栈顶引用
ref1 := stack.PopRef() // 再次弹出操作数栈的栈顶引用
return ref1 == ref2 // 比较两个引用是否相等,返回比较结果
}
type IF_ICMPEQ struct{ base.BranchInstruction } // 定义 IF_ICMPEQ 指令结构体,继承自 base.BranchInstruction
func (self *IF_ICMPEQ) Execute(frame *rtda.Frame) { // 实现 IF_ICMPEQ 指令的 Execute 方法
if val1, val2 := _icmpPop(frame); val1 == val2 { // 调用 _icmpPop 函数获取两个整数值,如果相等则跳转
base.Branch(frame, self.Offset) // 执行跳转
}
}
type IF_ICMPNE struct{ base.BranchInstruction } // 定义 IF_ICMPNE 指令结构体,继承自 base.BranchInstruction
func (self *IF_ICMPNE) Execute(frame *rtda.Frame) { // 实现 IF_ICMPNE 指令的 Execute 方法
if val1, val2 := _icmpPop(frame); val1 != val2 { // 调用 _icmpPop 函数获取两个整数值,如果不相等则跳转
base.Branch(frame, self.Offset) // 执行跳转
}
}
type IF_ICMPLT struct{ base.BranchInstruction } // 定义 IF_ICMPLT 指令结构体,继承自 base.BranchInstruction
func (self *IF_ICMPLT) Execute(frame *rtda.Frame) { // 实现 IF_ICMPLT 指令的 Execute 方法
if val1, val2 := _icmpPop(frame); val1 < val2 { // 调用 _icmpPop 函数获取两个整数值,如果第一个小于第二个则跳转
base.Branch(frame, self.Offset) // 执行跳转
}
}
type IF_ICMPLE struct{ base.BranchInstruction } // 定义 IF_ICMPLE 指令结构体,继承自 base.BranchInstruction
func (self *IF_ICMPLE) Execute(frame *rtda.Frame) { // 实现 IF_ICMPLE 指令的 Execute 方法
if val1, val2 := _icmpPop(frame); val1 <= val2 { // 调用 _icmpPop 函数获取两个整数值,如果第一个小于等于第二个则跳转
base.Branch(frame, self.Offset) // 执行跳转
}
}
type IF_ICMPGT struct{ base.BranchInstruction } // 定义 IF_ICMPGT 指令结构体,继承自 base.BranchInstruction
func (self *IF_ICMPGT) Execute(frame *rtda.Frame) { // 实现 IF_ICMPGT 指令的 Execute 方法
if val1, val2 := _icmpPop(frame); val1 > val2 { // 调用 _icmpPop 函数获取两个整数值,如果第一个大于第二个则跳转
base.Branch(frame, self.Offset) // 执行跳转
}
}
type IF_ICMPGE struct{ base.BranchInstruction } // 定义 IF_ICMPGE 指令结构体,继承自 base.BranchInstruction
func (self *IF_ICMPGE) Execute(frame *rtda.Frame) { // 实现 IF_ICMPGE 指令的 Execute 方法
if val1, val2 := _icmpPop(frame); val1 >= val2 { // 调用 _icmpPop 函数获取两个整数值,如果第一个大于等于第二个则跳转
base.Branch(frame, self.Offset) // 执行跳转
}
}
func _icmpPop(frame *rtda.Frame) (val1, val2 int32) { // 定义 _icmpPop 函数,用于从操作数栈中弹出两个整数值
stack := frame.OperandStack() // 获取当前帧的操作数栈
val2 = stack.PopInt() // 弹出操作数栈的栈顶整数值
val1 = stack.PopInt() // 再次弹出操作数栈的栈顶整数值
return // 返回两个整数值
}
还有一个if_cond
gotype IFEQ struct{ base.BranchInstruction }
func (self *IFEQ) Execute(frame *rtda.Frame) {
val := frame.OperandStack().PopInt()
if val == 0 {
base.Branch(frame, self.Offset)
}
}
type IFNE struct{ base.BranchInstruction }
func (self *IFNE) Execute(frame *rtda.Frame) {
val := frame.OperandStack().PopInt()
if val != 0 {
base.Branch(frame, self.Offset)
}
}
type IFLT struct{ base.BranchInstruction }
func (self *IFLT) Execute(frame *rtda.Frame) {
val := frame.OperandStack().PopInt()
if val < 0 {
base.Branch(frame, self.Offset)
}
}
type IFLE struct{ base.BranchInstruction }
func (self *IFLE) Execute(frame *rtda.Frame) {
val := frame.OperandStack().PopInt()
if val <= 0 {
base.Branch(frame, self.Offset)
}
}
type IFGT struct{ base.BranchInstruction }
func (self *IFGT) Execute(frame *rtda.Frame) {
val := frame.OperandStack().PopInt()
if val > 0 {
base.Branch(frame, self.Offset)
}
}
type IFGE struct{ base.BranchInstruction }
func (self *IFGE) Execute(frame *rtda.Frame) {
val := frame.OperandStack().PopInt()
if val >= 0 {
base.Branch(frame, self.Offset)
}
}
总共有三条指令,goto,无条件跳转,tableswitch,lookupswitch,后两个是实现switch的方式,区别如下
tableswitch指令适用于case值是密集的、连续的情况。它通过一个跳转表来实现快速查找。tableswitch指令包含以下几个部分:
default offset:默认跳转偏移量,当没有匹配的case值时使用。
low:case值的最小值。
high:case值的最大值。
jump offsets:一个跳转偏移量数组,每个元素对应一个case值的跳转偏移量。
当执行tableswitch指令时,JVM会计算目标case值与low的差值,然后直接从跳转表中获取对应的跳转偏移量。
lookupswitch指令适用于case值是稀疏的、不连续的情况。它通过一个键值对列表来实现查找。lookupswitch指令包含以下几个部分:
default offset:默认跳转偏移量,当没有匹配的case值时使用。
npairs:键值对的数量。
match-offset pairs:一个键值对列表,每个键值对包含一个case值和一个跳转偏移量。
当执行lookupswitch指令时,JVM会遍历键值对列表,查找匹配的case值,并获取对应的跳转偏移量。
指令的选择是编译的时候按case值是密集或者松散选择的
看代码,goto指令很简单
gotype GOTO struct{ base.BranchInstruction }
func (self *GOTO) Execute(frame *rtda.Frame) {
base.Branch(frame, self.Offset)
}
tableswitch
gotype TABLE_SWITCH struct {
defaultOffset int32 // 默认跳转偏移量
low int32 // case值的最小值
high int32 // case值的最大值
jumpOffsets []int32 // 跳转偏移量数组
}
func (self *TABLE_SWITCH) FetchOperands(reader *base.BytecodeReader) {
reader.SkipPadding() // 跳过填充字节,确保对齐
self.defaultOffset = reader.ReadInt32() // 读取默认跳转偏移量
self.low = reader.ReadInt32() // 读取case值的最小值
self.high = reader.ReadInt32() // 读取case值的最大值
jumpOffsetsCount := self.high - self.low + 1 // 计算跳转偏移量的数量
self.jumpOffsets = reader.ReadInt32s(jumpOffsetsCount) // 读取跳转偏移量数组
}
func (self *TABLE_SWITCH) Execute(frame *rtda.Frame) {
index := frame.OperandStack().PopInt() // 从操作数栈中弹出一个整数
var offset int
if index >= self.low && index <= self.high { // 检查index是否在low和high之间
offset = int(self.jumpOffsets[index-self.low]) // 计算对应的跳转偏移量
} else {
offset = int(self.defaultOffset) // 使用默认跳转偏移量
}
base.Branch(frame, offset) // 执行跳转
}
lookupswitch
gotype LOOKUP_SWITCH struct {
defaultOffset int32 // 默认跳转偏移量
npairs int32 // 键值对的数量
matchOffsets []int32 // 匹配偏移量数组
}
func (self *LOOKUP_SWITCH) FetchOperands(reader *base.BytecodeReader) {
reader.SkipPadding() // 跳过填充字节,确保对齐
self.defaultOffset = reader.ReadInt32() // 读取默认跳转偏移量
self.npairs = reader.ReadInt32() // 读取键值对的数量
self.matchOffsets = reader.ReadInt32s(self.npairs * 2) // 读取匹配偏移量数组
}
func (self *LOOKUP_SWITCH) Execute(frame *rtda.Frame) {
key := frame.OperandStack().PopInt() // 从操作数栈中弹出一个整数
for i := int32(0); i < self.npairs*2; i += 2 { // 遍历键值对
if self.matchOffsets[i] == key { // 检查键是否匹配
offset := self.matchOffsets[i+1] // 获取对应的跳转偏移量
base.Branch(frame, int(offset)) // 执行跳转
return
}
}
base.Branch(frame, int(self.defaultOffset)) // 如果没有匹配的键,执行默认跳转
}
这里的扩展指令是指wide指令,ifnull,ifnotnull,goto_w,很多存储类指令和加载类指令和一些其他指令需要操作局部变量表,但是因为只用一字节索引所以最大只能256,倘若需要操作超过256索引的局部变量,就需要wide指令
wide <modified_instruction>
其中,<modified_instruction>是被“wide”指令扩展的指令。
wide iload 256 wide istore 256
代码如下
gotype WIDE struct {
modifiedInstruction base.Instruction // 被扩展的指令
}
func (self *WIDE) FetchOperands(reader *base.BytecodeReader) {
opcode := reader.ReadUint8() // 读取操作码
switch opcode {
case 0x15: // iload
inst := &loads.ILOAD{}
inst.Index = uint(reader.ReadUint16()) // 读取扩展的索引
self.modifiedInstruction = inst
case 0x16: // lload
inst := &loads.LLOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x17: // fload
inst := &loads.FLOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x18: // dload
inst := &loads.DLOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x19: // aload
inst := &loads.ALOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x36: // istore
inst := &stores.ISTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x37: // lstore
inst := &stores.LSTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x38: // fstore
inst := &stores.FSTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x39: // dstore
inst := &stores.DSTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x3a: // astore
inst := &stores.ASTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x84: // iinc
inst := &math.IINC{}
inst.Index = uint(reader.ReadUint16())
inst.Const = int32(reader.ReadInt16()) // 读取增量值
self.modifiedInstruction = inst
case 0xa9: // ret
panic("Unsupported opcode: 0xa9!") // 不支持的操作码
}
}
func (self *WIDE) Execute(frame *rtda.Frame) {
self.modifiedInstruction.Execute(frame) // 执行被扩展的指令
}
ifnull
go
type IFNULL struct{ base.BranchInstruction }
func (self *IFNULL) Execute(frame *rtda.Frame) {
ref := frame.OperandStack().PopRef()
if ref == nil {
base.Branch(frame, self.Offset)
}
}
type IFNONNULL struct{ base.BranchInstruction }
func (self *IFNONNULL) Execute(frame *rtda.Frame) {
ref := frame.OperandStack().PopRef()
if ref != nil {
base.Branch(frame, self.Offset)
}
}
goto_w
gotype GOTO_W struct {
offset int
}
func (self *GOTO_W) FetchOperands(reader *base.BytecodeReader) {
self.offset = int(reader.ReadInt32())
}
func (self *GOTO_W) Execute(frame *rtda.Frame) {
base.Branch(frame, self.offset)
}
上面实现了指令集,接下来先看看解释器代码
gofunc interpret(methodInfo *classfile.MemberInfo) {
codeAttr := methodInfo.CodeAttribute() // 获取方法的Code属性
maxLocals := codeAttr.MaxLocals() // 获取局部变量表的最大容量
maxStack := codeAttr.MaxStack() // 获取操作数栈的最大容量
bytecode := codeAttr.Code() // 获取字节码
thread := rtda.NewThread() // 创建一个新的线程
frame := thread.NewFrame(maxLocals, maxStack) // 为该线程创建一个新的帧
thread.PushFrame(frame) // 将帧推入线程的帧栈
defer catchErr(frame) // 注册一个延迟调用,用于捕获和处理异常
loop(thread, bytecode) // 进入解释循环
}
func catchErr(frame *rtda.Frame) {
if r := recover(); r != nil { // 捕获panic
fmt.Printf("LocalVars:%v\n", frame.LocalVars()) // 打印局部变量表
fmt.Printf("OperandStack:%v\n", frame.OperandStack()) // 打印操作数栈
panic(r) // 重新抛出panic
}
}
func loop(thread *rtda.Thread, bytecode []byte) {
frame := thread.PopFrame() // 从线程中弹出当前帧
reader := &base.BytecodeReader{} // 创建一个字节码读取器
for {
pc := frame.NextPC() // 获取下一个指令的PC
thread.SetPC(pc) // 设置线程的PC
// decode
reader.Reset(bytecode, pc) // 重置字节码读取器
opcode := reader.ReadUint8() // 读取操作码
inst := instructions.NewInstruction(opcode) // 根据操作码创建指令实例
inst.FetchOperands(reader) // 读取指令的操作数
frame.SetNextPC(reader.PC()) // 设置下一个指令的PC
// execute
fmt.Printf("pc:%2d inst:%T %v\n", pc, inst, inst) // 打印PC和指令信息
inst.Execute(frame) // 执行指令
}
}
CodeAttribute()使我们新实现的
gofunc (self *MemberInfo) CodeAttribute() *CodeAttribute {
for _, attrInfo := range self.attributes {
switch attrInfo.(type) {
case *CodeAttribute:
return attrInfo.(*CodeAttribute)
}
}
return nil
}
还有Thread的NewFarme
gofunc (self *Thread) NewFrame(maxLocals, maxStack uint) *Frame {
return newFrame(self, maxLocals, maxStack)
}
修改Frame结构体
gotype Frame struct {
lower *Frame // stack is implemented as linked list
localVars LocalVars
operandStack *OperandStack
thread *Thread
nextPC int // the next instruction after the call
}
还有instructions.NewInstruction
go
func NewInstruction(opcode byte) base.Instruction {
switch opcode {
case 0x00:
return nop
case 0x01:
return aconst_null
case 0x02:
return iconst_m1
case 0x03:
return iconst_0
case 0x04:
return iconst_1
case 0x05:
return iconst_2
case 0x06:
return iconst_3
case 0x07:
return iconst_4
case 0x08:
return iconst_5
case 0x09:
return lconst_0
return &LLOAD{}
case 0x17:
return &FLOAD{}
case 0x18:
return &DLOAD{}
case 0x19:
return &ALOAD{}
case 0x1a:
return iload_0
case 0x1b:
return iload_1
case 0x1c:
return iload_2
case 0x1d:
return iload_3
case 0x1e:
return lload_0
case 0x1f:
return lload_1
case 0x20:
return dup_x2
case 0x5c:
return dup2
case 0x5d:
return dup2_x1
case 0x5e:
return dup2_x2
case 0x5f:
return swap
case 0x60:
return iadd
case 0x61:
return ladd
case 0x62:
return fadd
case 0x63:
return dadd
case 0x64:
return isub
case 0x65:
return lsub
case 0x66:
return fsub
case 0x67:
return dsub
case 0x68:
return imul
case 0x69:
return lmul
case 0x6a:
return fmul
case 0x6b:
return dmul
case 0x6c:
return idiv
case 0x6d:
return ldiv
case 0x6e:
return fdiv
case 0x6f:
return ddiv
case 0x70:
return irem
case 0x71:
return lrem
case 0x72:
return frem
case 0x73:
return drem
case 0x74:
return ineg
case 0x75:
return lneg
case 0x76:
return fneg
case 0x77:
return dneg
case 0x78:
return ishl
case 0x79:
return lshl
case 0x7a:
return ishr
case 0x7b:
return lshr
case 0x7c:
return iushr
case 0x7d:
return lushr
case 0x7e:
return iand
case 0x7f:
return land
case 0x80:
return ior
case 0x81:
return lor
case 0x82:
return ixor
case 0x83:
return lxor
case 0x84:
return &IINC{}
case 0x85:
return i2l
case 0x86:
return i2f
case 0x87:
return i2d
case 0x88:
return l2i
case 0x89:
return l2f
case 0x8a:
return l2d
case 0x8b:
return f2i
case 0x8c:
return f2l
case 0x8d:
return f2d
case 0x8e:
return d2i
case 0x8f:
return d2l
case 0x90:
return d2f
case 0x91:
return i2b
case 0x92:
return i2c
case 0x93:
return i2s
case 0x94:
return lcmp
case 0x95:
return fcmpl
case 0x96:
return fcmpg
case 0x97:
return dcmpl
case 0x98:
return dcmpg
case 0x99:
return &IFEQ{}
case 0x9a:
return &IFNE{}
case 0x9b:
return &IFLT{}
case 0x9c:
return &IFGE{}
case 0x9d:
return &IFGT{}
case 0x9e:
return &IFLE{}
case 0x9f:
return &IF_ICMPEQ{}
case 0xa0:
return &IF_ICMPNE{}
case 0xa1:
return &IF_ICMPLT{}
case 0xa2:
return &IF_ICMPGE{}
case 0xa3:
return &IF_ICMPGT{}
case 0xa4:
return &IF_ICMPLE{}
case 0xa5:
...............................................
default:
panic(fmt.Errorf("Unsupported opcode: 0x%x!", opcode))
}
}
.....
整个原理到这就讲解完了
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!