编辑
2024-08-01
后端
00
请注意,本文编写于 282 天前,最后修改于 282 天前,其中某些信息可能已经过时。

目录

const系列指令
加载类指令
存储指令
栈指令
数学指令
类型转换指令
比较指令
控制指令
tableswitch
lookupswitch
扩展指令

第五章讲的是指令集和解释器,这张主要讲解了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类

  • 常量类
  • 加载类
  • 存储类
  • 操作数栈类
  • 数学类
  • 转换类
  • 比较类
  • 控制类
  • 引用类
  • 扩展类
  • 保留类

网上也有分为以下的

  • 加载与存储指令
  • 算术指令
  • 类型转换指令
  • 对象的创建与访问指令
  • 方法调用和返回指令
  • 操作数栈管理指令
  • 控制转移指令

我们按书上得来,建立以下结构

image.png

了解了上面指令集相关内容,来了解一下解释器,虚拟机无非是一个不断解释执行命令的机器,按对应的指令实现不同的操作,我们可以用一下伪代码来了解一下常见的解释器的逻辑

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里面很难看,所以我们用接口来实现对应的指令,每个指令都是接口的实现,这样就变成了以下的样子

go
func 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对象,管理字节码

go
package 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 }

const系列指令

作用是把操作码中隐藏的的常量压入操作数栈的栈顶

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加载的代码

go
type 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) }

差不多,省略了很多

类型转换指令

用于类型转换

go
type 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的基石

go
type 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

go
type 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

tableswitch指令适用于case值是密集的、连续的情况。它通过一个跳转表来实现快速查找。tableswitch指令包含以下几个部分:

  • default offset:默认跳转偏移量,当没有匹配的case值时使用。

  • low:case值的最小值。

  • high:case值的最大值。

  • jump offsets:一个跳转偏移量数组,每个元素对应一个case值的跳转偏移量。

当执行tableswitch指令时,JVM会计算目标case值与low的差值,然后直接从跳转表中获取对应的跳转偏移量。

lookupswitch

lookupswitch指令适用于case值是稀疏的、不连续的情况。它通过一个键值对列表来实现查找。lookupswitch指令包含以下几个部分:

  • default offset:默认跳转偏移量,当没有匹配的case值时使用。

  • npairs:键值对的数量。

  • match-offset pairs:一个键值对列表,每个键值对包含一个case值和一个跳转偏移量。

当执行lookupswitch指令时,JVM会遍历键值对列表,查找匹配的case值,并获取对应的跳转偏移量。

指令的选择是编译的时候按case值是密集或者松散选择的

看代码,goto指令很简单

go
type GOTO struct{ base.BranchInstruction } func (self *GOTO) Execute(frame *rtda.Frame) { base.Branch(frame, self.Offset) }

tableswitch

go
type 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

go
type 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

代码如下

go
type 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

go
type 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) }

上面实现了指令集,接下来先看看解释器代码

go
func 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()使我们新实现的

go
func (self *MemberInfo) CodeAttribute() *CodeAttribute { for _, attrInfo := range self.attributes { switch attrInfo.(type) { case *CodeAttribute: return attrInfo.(*CodeAttribute) } } return nil }

还有Thread的NewFarme

go
func (self *Thread) NewFrame(maxLocals, maxStack uint) *Frame { return newFrame(self, maxLocals, maxStack) }

修改Frame结构体

go
type 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 许可协议。转载请注明出处!