Skip to content

Commit

Permalink
Merge pull request #729 from matter-labs/vv-small-interpreter-optimiz…
Browse files Browse the repository at this point in the history
…ations

[EVM-Equivalence-YUL] Interpeter optimizations
  • Loading branch information
jrchatruc authored Aug 23, 2024
2 parents 18d1d3a + 2c9b719 commit 5cdc5dd
Show file tree
Hide file tree
Showing 3 changed files with 369 additions and 312 deletions.
184 changes: 102 additions & 82 deletions system-contracts/contracts/EvmInterpreterFunctions.template.yul
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ function popStackCheck(sp, evmGasLeft, numInputs) {
}
}

function pushStackCheck(sp, evmGasLeft, numInputs) {
if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) {
revertWithGas(evmGasLeft)
}
}

function getCodeAddress() -> addr {
addr := verbatim_0i_1o("code_source")
}
Expand Down Expand Up @@ -470,6 +476,13 @@ function getGasForPrecompiles(addr, argsOffset, argsSize) -> gasToCharge {
}
}

function checkMemOverflowByOffset(offset, evmGasLeft) {
if gt(offset, MAX_POSSIBLE_MEM()) {
mstore(0, evmGasLeft)
revert(0, 32)
}
}

function checkMemOverflow(location, evmGasLeft) {
if gt(location, MAX_MEMORY_FRAME()) {
mstore(0, evmGasLeft)
Expand Down Expand Up @@ -592,29 +605,34 @@ function getNewAddress(addr) -> newAddr {
if iszero(nonce) {
nonceEncoded := 128
}
// The nonce has 4 bytes
if gt(nonce, 0xFFFFFF) {
nonceEncoded := shl(32, 0x84)
nonceEncoded := add(nonceEncoded, nonce)
nonceEncodedLength := 5
}
// The nonce has 3 bytes
if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) {
nonceEncoded := shl(24, 0x83)
nonceEncoded := add(nonceEncoded, nonce)
nonceEncodedLength := 4
}
// The nonce has 2 bytes
if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) {
nonceEncoded := shl(16, 0x82)
switch gt(nonce, 0xFFFF)
case 1 {
switch gt(nonce, 0xFFFFFF)
case 1 {
// The nonce has 4 bytes
nonceEncoded := shl(32, 0x84)
nonceEncodedLength := 5
}
default {
// The nonce has 3 bytes
nonceEncoded := shl(24, 0x83)
nonceEncodedLength := 4
}
nonceEncoded := add(nonceEncoded, nonce)
nonceEncodedLength := 3
}
// The nonce has 1 byte and it's in [0x80, 0xFF]
if and(gt(nonce, 0x7F), lt(nonce, 0x100)) {
nonceEncoded := shl(8, 0x81)
nonceEncoded := add(nonceEncoded, nonce)
nonceEncodedLength := 2
default {
// The nonce has 2 bytes
if gt(nonce, 0xFF) {
nonceEncoded := shl(16, 0x82)
nonceEncoded := add(nonceEncoded, nonce)
nonceEncodedLength := 3
}
// The nonce has 1 byte and it's in [0x80, 0xFF]
if and(gt(nonce, 0x7F), lt(nonce, 0x100)) {
nonceEncoded := shl(8, 0x81)
nonceEncoded := add(nonceEncoded, nonce)
nonceEncodedLength := 2
}
}

listLength := add(21, nonceEncodedLength)
Expand Down Expand Up @@ -857,11 +875,11 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp {

addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff)

checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft)
checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft)
checkOverflow(argsOffset,argsSize, evmGasLeft)
checkOverflow(retOffset, retSize, evmGasLeft)

checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft)
checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft)
checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft)
checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft)

extraCost := 0
if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) {
Expand All @@ -879,16 +897,9 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp {

let frameGasLeft
let success
if _isEVM(addr) {
_pushEVMFrame(gasToPass, true)
success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0)

frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize)
_popEVMFrame()
}

// zkEVM native
if iszero(_isEVM(addr)) {
switch _isEVM(addr)
case 0 {
// zkEVM native
gasToPass := _getZkEVMGas(gasToPass, addr)
let zkevmGasBefore := gas()
success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize)
Expand All @@ -901,6 +912,13 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp {
frameGasLeft := sub(gasToPass, gasUsed)
}
}
default {
_pushEVMFrame(gasToPass, true)
success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0)

frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize)
_popEVMFrame()
}

let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize)
switch iszero(precompileCost)
Expand Down Expand Up @@ -935,7 +953,31 @@ function getMaxExpansionMemory(retOffset,retSize,argsOffset,argsSize) -> maxExpa
function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{
gasToPassNew := gasToPass
let is_evm := _isEVM(addr)
if isStatic {

switch isStatic
case 0 {
switch is_evm
case 0 {
// zkEVM native
gasToPassNew := _getZkEVMGas(gasToPassNew, addr)
let zkevmGasBefore := gas()
success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize)
_saveReturndataAfterZkEVMCall()
let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas()))

frameGasLeft := 0
if gt(gasToPassNew, gasUsed) {
frameGasLeft := sub(gasToPassNew, gasUsed)
}
}
default {
_pushEVMFrame(gasToPassNew, isStatic)
success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0)
frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize)
_popEVMFrame()
}
}
default {
if value {
revertWithGas(gasToPassNew)
}
Expand All @@ -949,27 +991,6 @@ function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize
retSize
)
}

if and(is_evm, iszero(isStatic)) {
_pushEVMFrame(gasToPassNew, isStatic)
success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0)
frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize)
_popEVMFrame()
}

// zkEVM native
if and(iszero(is_evm), iszero(isStatic)) {
gasToPassNew := _getZkEVMGas(gasToPassNew, addr)
let zkevmGasBefore := gas()
success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize)
_saveReturndataAfterZkEVMCall()
let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas()))

frameGasLeft := 0
if gt(gasToPassNew, gasUsed) {
frameGasLeft := sub(gasToPassNew, gasUsed)
}
}
}

function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp {
Expand Down Expand Up @@ -1060,11 +1081,11 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost

// addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff)

checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft)
checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft)
checkOverflow(argsOffset, argsSize, evmGasLeft)
checkOverflow(retOffset, retSize, evmGasLeft)

checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft)
checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft)
checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft)
checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft)

if iszero(_isEVM(addr)) {
revertWithGas(evmGasLeft)
Expand Down Expand Up @@ -1148,16 +1169,9 @@ function _performStaticCall(
_outputOffset,
_outputLen
) -> success, _gasLeft {
if _calleeIsEVM {
_pushEVMFrame(_calleeGas, true)
success := staticcall(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0)

_gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen)
_popEVMFrame()
}

// zkEVM native
if iszero(_calleeIsEVM) {
switch _calleeIsEVM
case 0 {
// zkEVM native
_calleeGas := _getZkEVMGas(_calleeGas, _callee)
let zkevmGasBefore := gas()
success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen)
Expand All @@ -1171,6 +1185,13 @@ function _performStaticCall(
_gasLeft := sub(_calleeGas, gasUsed)
}
}
default {
_pushEVMFrame(_calleeGas, true)
success := staticcall(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0)

_gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen)
_popEVMFrame()
}
}

function isAddrEmpty(addr) -> isEmpty {
Expand Down Expand Up @@ -1210,10 +1231,11 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa

offset := add(MEM_OFFSET_INNER(), offset)

sp := pushStackItem(sp, mload(sub(offset, 0x80)), evmGasLeftOld)
sp := pushStackItem(sp, mload(sub(offset, 0x60)), evmGasLeftOld)
sp := pushStackItem(sp, mload(sub(offset, 0x40)), evmGasLeftOld)
sp := pushStackItem(sp, mload(sub(offset, 0x20)), evmGasLeftOld)
pushStackCheck(sp, evmGasLeftOld, 4)
sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x80)))
sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x60)))
sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x40)))
sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x20)))

// Selector
mstore(sub(offset, 0x80), 0x5b16a23c)
Expand Down Expand Up @@ -1257,7 +1279,7 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa

let back

popStackCheck(sp, evmGasLeft, 4)
// skipping check since we pushed exactly 4 items earlier
back, sp := popStackItemWithoutCheck(sp)
mstore(sub(offset, 0x20), back)
back, sp := popStackItemWithoutCheck(sp)
Expand Down Expand Up @@ -1351,9 +1373,8 @@ function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp {
offset, sp := popStackItemWithoutCheck(sp)
size, sp := popStackItemWithoutCheck(sp)

checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft)

checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft)
checkOverflow(offset, size, evmGasLeft)
checkMemOverflowByOffset(add(offset, size), evmGasLeft)

if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) {
revertWithGas(evmGasLeft)
Expand Down Expand Up @@ -1398,9 +1419,8 @@ function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr
size, sp := popStackItemWithoutCheck(sp)
salt, sp := popStackItemWithoutCheck(sp)

checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft)

checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft)
checkOverflow(offset, size, evmGasLeft)
checkMemOverflowByOffset(add(offset, size), evmGasLeft)

if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) {
revertWithGas(evmGasLeft)
Expand Down
Loading

0 comments on commit 5cdc5dd

Please sign in to comment.