Alert Source Discuss
🚧 Stagnant Standards Track: Core

EIP-3337: 帧指针支持内存加载和存储操作

Authors Nick Johnson (@arachnid)
Created 2021-03-06
Discussion Link https://ethereum-magicians.org/t/eips-3336-and-3337-improving-the-evms-memory-model/5482
Requires EIP-3336

简单总结

引入了四个新的操作码,用于从内存加载数据和将数据存储到由帧指针偏移的内存。

摘要

这个 EIP 引入了四个新的操作码,MLOADFPMSTOREFPGETFPSETFP,允许更有效地进行内存访问,内存地址由用户控制的量(称为“帧指针”)偏移。 这使得编译器能够更有效地将临时数据(如局部变量)卸载到内存中,而不是 EVM 的计算堆栈中,这有很多好处,包括有效地消除了对函数中局部变量数量的限制。

动机

在大多数常用的 VM 中,临时数据(如局部变量、函数参数和返回地址)存储在称为堆栈的内存区域中。 与 EVM 的计算堆栈相比,这片内存区域是随机可访问的,因此可以存储任意数量的数据,这些数据可以从它们保持在作用域内的任何位置引用。 尽管这种模型在当前的 EVM 设计中是可能的,但由于内存的线性模型(在 EIP-3336 中讨论了)以及由于缺乏在其他架构中常见的相对内存访问操作码,使得它变得困难。 这个 EIP 提出了新的操作码,允许这种形式的内存使用,而不会给 EVM 实现者或运行时效率带来不必要的负担。

在当前的 EVM 模型中,希望使用这种模式的编译器必须将帧指针(指向当前内存堆栈帧的开始或结束)存储在内存中,并在每次要引用它时加载它。 例如,从由帧指针偏移的内存中加载一个值需要以下操作序列:

Opcode Gas used
PUSHn x 3
PUSH1 0 3
MLOAD 3
ADD 3
MLOAD 3

这总共消耗 15 个 gas,并且每次被引用时占用至少 7 个字节的字节码。 相比之下,在这个 EIP 之后,等效的操作序列是:

Opcode Gas used
PUSH1 x 3
MLOADFP 3

这仅消耗 6 个 gas,并且占用至少 3 个字节的字节码。 EVM 实现所需的工作量是等效的,与常规 MLOAD 相比,仅需一个额外的加法运算。 将值存储在堆栈上的替代方法需要 3 个 gas 和 1 个字节的字节码才能执行 DUPn 操作,但现在最多只有两倍的效率,而不是 5 倍的效率,这使得将值存储在内存中成为一种可行的替代方案。

同样,在这个 EIP 之前,一个帧指针相关的存储需要以下操作序列: | Opcode | Gas used | |———–|———-| | PUSHn x | 3 | | PUSH1 0 | 3 | | MLOAD | 3 | | ADD | 3 | | MSTORE | 3 |

这消耗 15 个 gas 和至少 7 个字节的字节码。 在这个 EIP 之后,等效的操作序列是:

Opcode Gas used
PUSHn x 3
MSTOREFP 3

仅消耗 6 个 gas 和至少 3 个字节的字节码,同时再次仅要求 EVM 实现执行一个额外的加法运算。 将值存储在堆栈上的替代方法需要 6 个 gas 和 2 个字节的字节码来执行 SWAPn POP 序列,这使得它不比内存存储更有效。

规范

参数

Constant Value
FORK_BLOCK TBD

对于 block.number >= FORK_BLOCK 的区块,以下更改适用。

帧指针

引入了一个新的 EVM 内部状态变量,称为“帧指针”。 这是一个有符号整数,从 0 开始。

SETFP 操作码

引入了一个新的操作码 SETFP,值为 0x5c。 此操作码的成本为 G_low (3 gas),并从堆栈中获取一个参数。 该参数作为帧指针的新值存储。

GETFP 操作码

引入了一个新的操作码 GETFP,值为 0x5d。 此操作码的成本为 G_low (3 gas),并且不接受任何参数。 它获取帧指针的当前值并将其推送到堆栈。

MLOADFP 操作码

引入了一个新的操作码 MLOADFP,值为 0x5e。 除了在从内存加载数据之前将帧指针的值添加到地址之外,此操作码在所有方面的行为都与 MLOAD 相同。 尝试从负地址加载数据应被视为与无效操作码相同,消耗所有 gas 并恢复当前执行上下文。

MSTOREFP 操作码

引入了一个新的操作码 MSTOREFP,值为 0x5f。 除了在将数据存储到内存之前将帧指针的值添加到地址之外,此操作码在所有方面的行为都与 MSTORE 相同。 尝试将数据存储到负地址应被视为与无效操作码相同,消耗所有 gas 并恢复当前执行上下文。

理由

新操作码的成本

新操作码 MLOADFPMSTOREFP 的成本反映了 MLOADMSTORE 的成本。 它们的成本通常是等效的,但有一个额外的加法运算例外,这产生的成本可以忽略不计。

新操作码 SETFPGETFP 的成本基于其他常见的低成本操作码,例如 PUSHPOP

缺少 MSTORE8FP

未包含 MSTORE8FP 操作码,因为预计它将很少使用,并且希望最小化指令集的大小并为将来使用保留操作码。

向后兼容性

此 EIP 专门引入了新的操作码,因此不应影响任何现有程序,除非它们假设这些操作码未定义,我们认为情况并非如此。

安全考虑

DoS 风险通过正确地为操作码定价以反映当前的执行成本来缓解。 没有其他安全考虑因素与此 EIP 相关。

版权

版权和相关权利已通过 CC0 放弃。

Citation

Please cite this document as:

Nick Johnson (@arachnid), "EIP-3337: 帧指针支持内存加载和存储操作 [DRAFT]," Ethereum Improvement Proposals, no. 3337, March 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3337.