Leo的技术日志

虚拟机

漫谈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 指令。