EVM 的主栈人尽皆知:1024 层封顶,一切运算数都从它进出,每一层调用帧自配一条。但”函数调用”需要的是另一样东西——调用点得记住回来时的位置,主栈装不下这种记性,硬装也行:手工把返回地址压栈、跳转、到了终点再弹回来。2019 年 10 月的 EIP-2315 想把这件事正规化:给 EVM 加一条专职的返回栈。
两个操作码的极简设计
提案只引入两个操作码。RJUMPSUB(0x5f)执行两步:把”下一条指令地址”(当前 PC 加 3,因为偏移字段占两字节)压上返回栈,再把 PC 加上一个双字节补码有符号相对偏移完成跳转。RETURNSUB(0x5e)只做一步:弹返回栈,写回 PC。偏移编码是 MSB 优先的双字节有符号数,正负皆可,规范给 RJUMPSUB 定 low 档 gas、RETURNSUB 定 verylow 档——比手工在跳转表上模拟函数调用的惯用写法便宜,因为省掉了主栈进出与跳表查找。

关键取舍:不进共识的栈
规范里最要紧的一句是:返回栈的实际状态对 EVM 代码不可观察,也不属于共识内容。弹出值无需验证,因为它们只可能被 RJUMPSUB 和 RETURNSUB 改写。这个设计把改动半径压到最小——共识层不用新增状态、不用改状态根,客户端各自维护一条执行期影子栈即可。它要解决的问题却真实:主链 EVM 里合约内复用逻辑至今靠 JUMP 配跳转表实现——同一段逻辑要三处调用,就得手工压三次返回地址、跳三次、跳回来时再靠运气保证栈形没变,没有廉价的原生”调用并返回”,反编译工具也很难从字节码里还原函数边界。而 2315 的抽象在概念上几乎免费:不碰状态、不碰共识、每条指令一档 gas,是教科书里”最小可证明正确”的样板设计。
为什么它停在半路
EIP-2315 从未在任何一次主网升级中激活,EIP 仓库现在的状态是 Withdrawn(撤回),撤回理由一栏写明:本提案已被 EOF 系列提案取代。EOF(以太坊对象格式)把代码从”指令与数据混排的裸字节”升级为带魔数头、分段、先验证后执行的容器,它的组件清单就写进 2315 自己的元数据里:3540 定义保留格式的容器头、3670 给代码定下先验证再执行的规矩、4200 引入带立即数的相对跳转——2315 是那栋楼的早期一根承重柱,柱子的设计天然围着楼走。其中 4200 贡献了带立即数的相对跳转指令 RJUMP、RJUMPI 与 RJUMPV,把”跳去哪”从栈上取数改为编码在指令里,它自己的元数据又依赖 3540 的容器头与 3670 的先验证后执行——四份文件环环相扣,任何一环单独上链都会失去配套。而楼本身没能按期落成:2025 年 5 月的布拉格升级与同年 12 月的大阪升级,公开激活清单里都没有 EOF 相关提案,容器化路线暂时搁置,2315 与 4200 分别躺在撤回区与停滞区。今天主网的函数级复用仍是两种形态:同一合约内部靠跳转表模拟,跨合约调用走 CALL 系列操作码——那是带完整 1024 层主栈的新调用帧,多一次地址查找、多一层 gas 缓冲扣减,重得多也贵得多,它的设计目的是隔离信任边界而不是加速复用。顺带记住调用帧的另一条家规:帧与帧之间不能直接摸对方的栈,传参取结果都要走内存里的临时区,这正是”同合约子程序”与”跨合约调用”成本差距的根源。读协议考古文章时可以把这条线记牢:返回栈方案、EOF 容器、CALL 帧栈,是三个不同层级的”函数调用”答案,谁都不等于谁。本文只讨论机制,不构成任何投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。