0%

《动手写虚拟机》跳转

前面完成了加减乘除运算,这篇文章来完成跳转

在所有高级语言中,都有if判断语句,实际上if语句编译到汇编就是跳转指令

下面实现3个跳转指令 JMP、JEQ、JNE,三者的实现方式一样,都是通过修改IP(instructionPoint)实现的

JMP、JEQ、JNE三个指令后面都有一个参数,是指跳转到哪个位置执行

JMP表示无条件跳转

JEQ是相等(从栈帧中pop出两个数,判断是否相等)则跳转

JNE是不相等则跳转

下面是实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
case JMP:
if len(instruction.args) < 1 {
panic(fmt.Errorf("instruction error - %v", instruction))
}
targetPos, err := instruction.args[0].GetNumber()
if err != nil {
panic(err)
}
vm.instructionPointer = int64(targetPos) - 1
case JNE:
currentStackFrame := vm.stack.GetTopStackFrame()
v1 := currentStackFrame.Pop().data
v2 := currentStackFrame.Pop().data
if !reflect.DeepEqual(v1, v2) {
if len(instruction.args) < 1 {
panic(fmt.Errorf("instruction error - %v", instruction))
}
targetPos, err := instruction.args[0].GetNumber()
if err != nil {
panic(err)
}
vm.instructionPointer = int64(targetPos) - 1
}
case JEQ:
currentStackFrame := vm.stack.GetTopStackFrame()
v1 := currentStackFrame.Pop().data
v2 := currentStackFrame.Pop().data
if reflect.DeepEqual(v1, v2) {
if len(instruction.args) < 1 {
panic(fmt.Errorf("instruction error - %v", instruction))
}
targetPos, err := instruction.args[0].GetNumber()
if err != nil {
panic(err)
}
vm.instructionPointer = int64(targetPos) - 1
}

因为比较的类型可能是字符串,也有可能是数字类型,而栈帧中的是interface类型

所以我直接使用 reflect.DeepEqual 来实现比较的,既方便又准确

开源地址

go-vm

下篇预告

CALL调用以及RET返回




微信关注我,及时接收最新技术文章