漫谈Stack-Based VM的设计(1)
Stack-based VM(栈式虚拟机)是一种用栈结构来管理指令执行和内存操作的虚拟机模型。可以把它想象成一个"叠盘子"的机器——每次操作都从栈顶取数据,结果也放回栈顶,使用者不需要关心数据存储在哪里。
它的核心特点是:所有算术运算、逻辑运算、函数调用等操作,都通过压栈(push)和弹栈(pop)来完成。比如计算"1+2",会先把1和2压入栈,然后执行加法指令,从栈顶弹出两个数相加,再把结果3压回栈顶。这种设计让指令集变得非常简洁(每条指令通常只有操作码,不需要指定操作数地址),但相比寄存器式VM,因为频繁的栈操作会产生额外开销,执行效率相对较低。
很多编程语言的运行时环境都采用这种模型,因为它实现简单、跨平台性好,适合作为中间表示层。
这里说的"栈"指的是操作数栈(operand stack),用于临时存放计算过程中的数据,和程序调用栈(call stack)是分开的。
怎么设计一个最小的VM
VM 的本质
一个 VM 至少需要三样东西:指令序列(Bytecode)、执行状态(State)、解释循环(Fetch → Decode → Execute)。
所以最小 VM 可以被描述为:
while (true):
instr = code[ip]
ip++
execute(instr)
区别只在于:状态如何组织。
为什么选择 Stack-Based?
在 Stack-Based VM 中,核心状态是一个操作数栈(Operand Stack)和一个指令指针(IP)。指令隐式地从栈中取操作数、把结果放回栈中。
例如:
PUSH 1
PUSH 2
ADD
执行过程:
stack: []
PUSH 1 -> [1]
PUSH 2 -> [1, 2]
ADD -> pop 2, pop 1, push 3 -> [3]
Stack-Based VM 最重要的特点:指令不需要显式指定操作数位置。
关于 Stack-Based VM 的 PUSH、POP 和 DUP 指令
为什么在很多 Stack-Based VM 的指令中看不到 PUSH 指令?
Stack-Based VM 一定存在 push 行为,只是:push 往往是"指令的副作用",而不是一个独立、频繁出现的显式操作。所以不会单独设计一个 PUSH 指令。