强制类型转换
从操作栈弹出数据,用go的类型强制转换,再将其压入回栈
// Convert int to byte
type I2B struct{ base.NoOperandsInstruction }
func (self *I2B) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
i := stack.PopInt()
b := int32(int8(i))
stack.PushInt(b)
}
// Convert int to char
type I2C struct{ base.NoOperandsInstruction }
func (self *I2C) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
i := stack.PopInt()
c := int32(uint16(i))
stack.PushInt(c)
}
// Convert int to short
type I2S struct{ base.NoOperandsInstruction }
func (self *I2S) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
i := stack.PopInt()
s := int32(int16(i))
stack.PushInt(s)
}
// Convert int to long
type I2L struct{ base.NoOperandsInstruction }
func (self *I2L) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
i := stack.PopInt()
l := int64(i)
stack.PushLong(l)
}
// Convert int to float
type I2F struct{ base.NoOperandsInstruction }
func (self *I2F) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
i := stack.PopInt()
f := float32(i)
stack.PushFloat(f)
}
// Convert int to double
type I2D struct{ base.NoOperandsInstruction }
func (self *I2D) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
i := stack.PopInt()
d := float64(i)
stack.PushDouble(d)
}
CMP系列
- LCMP 两个Long比较
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)
}
}
- FCMP fcmpg和fcmpl指令用于比较float变量
// Compare float
type FCMPG struct{ base.NoOperandsInstruction }
func (self *FCMPG) Execute(frame *rtda.Frame) {
_fcmp(frame, true)
}
type FCMPL struct{ base.NoOperandsInstruction }
func (self *FCMPL) Execute(frame *rtda.Frame) {
_fcmp(frame, false)
}
func _fcmp(frame *rtda.Frame, gFlag bool) {
stack := frame.OperandStack()
v2 := stack.PopFloat()
v1 := stack.PopFloat()
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)
}
}
- cmpg和dcmpl指令用来比较double变量, 这两条指令和fcmpg、fcmpl指令除了比较的变量类型不同之外,代码基本上完全一样,这里就不详细介绍了
if指令
// if<cond> 指令操作数栈顶的int变量弹出 然后跟0进行比较 满足条件则跳转
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)
}
}
其中的base.Branch的实现如下,使用pc+offset实现了代码的跳转
func Branch(frame *rtda.Frame, offset int) {
pc := frame.Thread().PC()
nextPC := pc + offset
frame.SetNextPC(nextPC)
}
if_icmp指令
比较两个Int是否相同
// Branch if int comparison succeeds
type IF_ICMPEQ struct{ base.BranchInstruction }
func (self *IF_ICMPEQ) Execute(frame *rtda.Frame) {
if val1, val2 := _icmpPop(frame); val1 == val2 {
base.Branch(frame, self.Offset)
}
}
type IF_ICMPNE struct{ base.BranchInstruction }
func (self *IF_ICMPNE) Execute(frame *rtda.Frame) {
if val1, val2 := _icmpPop(frame); val1 != val2 {
base.Branch(frame, self.Offset)
}
}
func _icmpPop(frame *rtda.Frame) (val1, val2 int32) {
stack := frame.OperandStack()
val2 = stack.PopInt()
val1 = stack.PopInt()
return
}
if_acmp指令
比较两个引用是否相同
// Branch if reference comparison succeeds
type IF_ACMPEQ struct{ base.BranchInstruction }
func (self *IF_ACMPEQ) Execute(frame *rtda.Frame) {
if _acmp(frame) {
base.Branch(frame, self.Offset)
}
}
type IF_ACMPNE struct{ base.BranchInstruction }
func (self *IF_ACMPNE) Execute(frame *rtda.Frame) {
if !_acmp(frame) {
base.Branch(frame, self.Offset)
}
}
func _acmp(frame *rtda.Frame) bool {
stack := frame.OperandStack()
ref2 := stack.PopRef()
ref1 := stack.PopRef()
return ref1 == ref2 // todo
}
GOTO
goto指令进行无条件跳转
func (self *GOTO) Execute(frame *rtda.Frame) {
base.Branch(frame, self.Offset)
}
SWITCH
Java语言中的switch-case语句有两种实现方式:
- 如果case值可以编码成一个索引表,则实现成tableswitch指令
int chooseNear(int i) {
switch (i) {
case 0: return 0;
case 1: return 1;
case 2: return 2;
default: return -1;
}
}
先从操作数栈中弹出一个int变量,然后看它是否在low和high给定的范围之内。如果在,则从jumpOffsets表中查出偏移量进行跳转,否则按照defaultOffset跳转
// 连续 case
type TABLE_SWITCH struct {
defalutOffset int32
low int32
high int32
jumpOffsets []int32
}
func (self *TABLE_SWITCH) FetchOperands(reader *base.BytecodeReader) {
reader.SkipPadding()
self.defalutOffset = reader.ReadInt32()
self.low = reader.ReadInt32()
self.high = reader.ReadInt32()
jumpOffsetCount := self.high - self.low + 1 // 获取跳转
self.jumpOffsets = reader.ReadInt32s(jumpOffsetCount) // 获取跳转范围
}
func (self *TABLE_SWITCH) Execute(frame *rtda.Frame) {
index := frame.OperandStack().PopInt()
var offset int
if index >= self.low && index <= self.high {
offset = int(self.jumpOffsets[index-self.low])
} else {
offset = int(self.defalutOffset)
}
base.Branch(frame, offset)
}
- 否则实现成lookupswitch指令
int chooseFar(int i) {
switch (i) {
case -100: return -1;
case 0: return 0;
case 100: return 1;
default: return -1;
}
}
matchOffsets有点像Map,它的key是case值,value是跳转偏移量。Execute()方法先从操作数栈中弹出一个int变量,然后用它查找matchOffsets,看是否能找到匹配的key。如果能,则按照value给出的偏移量跳转,否则按照defaultOffset跳转
// 不连续 case
type LOOKUP_SWITCH struct {
defalutOffset int32
npairs int32
matchOffsets []int32
}
func (self *LOOKUP_SWITCH) FetchOperands(reader *base.BytecodeReader) {
reader.SkipPadding()
self.defalutOffset = reader.ReadInt32()
self.npairs = reader.ReadInt32()
self.matchOffsets = reader.ReadInt32s(self.npairs * 2) // first:key second:value
}
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.defalutOffset))
}
扩展指令
wide指令
加载类指令、存储类指令、ret指令和iinc指令需要按索引访问局部变量表,索引以uint8的形式存在字节码中。对于大部分方法来说,局部变量表大小都不会超过256,所以用一字节来表示索引就够了。但是如果有方法的局部变量表超过这限制呢?Java虚拟机规范定义了wide指令来扩展前述指令
type WIDE struct {
modifiedInstruction base.Instruction
}
func (self *WIDE) FetchOperands(reader *base.BytecodeReader) {
opcode := reader.ReadUint8()
switch opcode {
case 0x15:
inst := &loads.ILOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x16:
inst := &loads.LLOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x17:
inst := &loads.FLOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x18:
inst := &loads.DLOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x19:
inst := &loads.ALOAD{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x36:
inst := &stores.ISTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x37:
inst := &stores.LSTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x38:
inst := &stores.FSTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x39:
inst := &stores.DSTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x3a:
inst := &stores.ASTORE{}
inst.Index = uint(reader.ReadUint16())
self.modifiedInstruction = inst
case 0x84:
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指令
根据引用是否是null进行跳转,ifnull和ifnonnull指令把栈顶的引用弹出
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 指令
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)
}