Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EVM-Equivalence-YUL] Implement lazy stack #720

Draft
wants to merge 6 commits into
base: evm-equivalence-yul
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 70 additions & 83 deletions system-contracts/contracts/EvmInterpreterFunctions.template.yul
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function LAST_RETURNDATA_SIZE_OFFSET() -> offset {
}

function STACK_OFFSET() -> offset {
offset := add(LAST_RETURNDATA_SIZE_OFFSET(), 32)
offset := add(LAST_RETURNDATA_SIZE_OFFSET(), 64)
}

function BYTECODE_OFFSET() -> offset {
Expand Down Expand Up @@ -90,71 +90,62 @@ function readBytes(start, maxAcceptablePos,length) -> value {
value := shr(mul(8,sub(32,length)),mload(start))
}

function dupStackItem(sp, evmGas, position) -> newSp, evmGasLeft {
function dupStackItem(sp, evmGas, position, oldStackHead) -> newSp, evmGasLeft, stackHead {
evmGasLeft := chargeGas(evmGas, 3)
let tempSp := sub(sp, mul(0x20, sub(position, 1)))

if or(gt(tempSp, BYTECODE_OFFSET()), eq(tempSp, BYTECODE_OFFSET())) {
if or(iszero(lt(tempSp, BYTECODE_OFFSET())), lt(tempSp, STACK_OFFSET())) {
revertWithGas(evmGasLeft)
}

if lt(tempSp, STACK_OFFSET()) {
revertWithGas(evmGasLeft)
}

let dup := mload(tempSp)

mstore(sp, oldStackHead)
stackHead := mload(tempSp)
newSp := add(sp, 0x20)
mstore(newSp, dup)
}

function swapStackItem(sp, evmGas, position) -> evmGasLeft {
function swapStackItem(sp, evmGas, position, oldStackHead) -> evmGasLeft, stackHead {
evmGasLeft := chargeGas(evmGas, 3)
let tempSp := sub(sp, mul(0x20, position))

if or(gt(tempSp, BYTECODE_OFFSET()), eq(tempSp, BYTECODE_OFFSET())) {
if lt(tempSp, STACK_OFFSET()) {
revertWithGas(evmGasLeft)
}

if lt(tempSp, STACK_OFFSET()) {
revertWithGas(evmGasLeft)
}


let s2 := mload(sp)
let s1 := mload(tempSp)

mstore(sp, s1)
mstore(tempSp, s2)
stackHead := mload(tempSp)
mstore(tempSp, oldStackHead)
}

function popStackItem(sp, evmGasLeft) -> a, newSp {
function popStackItem(sp, evmGasLeft, oldStackHead) -> a, newSp, stackHead {
// We can not return any error here, because it would break compatibility
if lt(sp, STACK_OFFSET()) {
revertWithGas(evmGasLeft)
}

a := mload(sp)
a := oldStackHead
newSp := sub(sp, 0x20)
stackHead := mload(newSp)
}

function pushStackItem(sp, item, evmGasLeft) -> newSp {
if or(gt(sp, BYTECODE_OFFSET()), eq(sp, BYTECODE_OFFSET())) {
function pushStackItem(sp, item, evmGasLeft, oldStackHead) -> newSp, stackHead {
if iszero(lt(sp, BYTECODE_OFFSET())) {
revertWithGas(evmGasLeft)
}

mstore(sp, oldStackHead)
stackHead := item
newSp := add(sp, 0x20)
mstore(newSp, item)
}

function popStackItemWithoutCheck(sp) -> a, newSp {
a := mload(sp)
function popStackItemWithoutCheck(sp, oldStackHead) -> a, newSp, stackHead {
a := oldStackHead
newSp := sub(sp, 0x20)
stackHead := mload(newSp)
}

function pushStackItemWithoutCheck(sp, item) -> newSp {
function pushStackItemWithoutCheck(sp, item, oldStackHead) -> newSp, stackHead {
mstore(sp, oldStackHead)
stackHead := item
newSp := add(sp, 0x20)
mstore(newSp, item)
}

function popStackCheck(sp, evmGasLeft, numInputs) {
Expand Down Expand Up @@ -862,16 +853,15 @@ function _saveReturndataAfterZkEVMCall() {
mstore(lastRtSzOffset, returndatasize())
}

function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp {
function performStaticCall(oldSp, evmGasLeft, oldStackHead) -> extraCost, sp, stackHead {
let gasToPass,addr, argsOffset, argsSize, retOffset, retSize

popStackCheck(oldSp, evmGasLeft, 6)
gasToPass, sp := popStackItemWithoutCheck(oldSp)
addr, sp := popStackItemWithoutCheck(sp)
argsOffset, sp := popStackItemWithoutCheck(sp)
argsSize, sp := popStackItemWithoutCheck(sp)
retOffset, sp := popStackItemWithoutCheck(sp)
retSize, sp := popStackItemWithoutCheck(sp)
gasToPass, sp, stackHead := popStackItemWithoutCheck(oldSp, oldStackHead)
addr, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
argsOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
argsSize, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
retOffset, sp, retSize := popStackItemWithoutCheck(sp, stackHead)

addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff)

Expand Down Expand Up @@ -929,7 +919,7 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp {
extraCost := add(extraCost, precompileCost)
}

sp := pushStackItem(sp, success, evmGasLeft)
stackHead := success
}
function capGas(evmGasLeft,oldGasToPass) -> gasToPass {
let maxGasToPass := sub(evmGasLeft, shr(6, evmGasLeft)) // evmGasLeft >> 6 == evmGasLeft/64
Expand Down Expand Up @@ -993,17 +983,16 @@ function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize
}
}

function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp {
function performCall(oldSp, evmGasLeft, isStatic, oldStackHead) -> extraCost, sp, stackHead {
let gasToPass,addr,value,argsOffset,argsSize,retOffset,retSize

popStackCheck(oldSp, evmGasLeft, 7)
gasToPass, sp := popStackItemWithoutCheck(oldSp)
addr, sp := popStackItemWithoutCheck(sp)
value, sp := popStackItemWithoutCheck(sp)
argsOffset, sp := popStackItemWithoutCheck(sp)
argsSize, sp := popStackItemWithoutCheck(sp)
retOffset, sp := popStackItemWithoutCheck(sp)
retSize, sp := popStackItemWithoutCheck(sp)
gasToPass, sp, stackHead := popStackItemWithoutCheck(oldSp, oldStackHead)
addr, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
value, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
argsOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
argsSize, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
retOffset, sp, retSize := popStackItemWithoutCheck(sp, stackHead)

addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff)

Expand Down Expand Up @@ -1062,22 +1051,21 @@ function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp {
default {
extraCost := add(extraCost, precompileCost)
}
sp := pushStackItem(sp,success, evmGasLeft)
stackHead := success
}

function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost {
function delegateCall(oldSp, oldIsStatic, evmGasLeft, oldStackHead) -> sp, isStatic, extraCost, stackHead {
let addr, gasToPass, argsOffset, argsSize, retOffset, retSize

sp := oldSp
isStatic := oldIsStatic

popStackCheck(sp, evmGasLeft, 6)
gasToPass, sp := popStackItemWithoutCheck(sp)
addr, sp := popStackItemWithoutCheck(sp)
argsOffset, sp := popStackItemWithoutCheck(sp)
argsSize, sp := popStackItemWithoutCheck(sp)
retOffset, sp := popStackItemWithoutCheck(sp)
retSize, sp := popStackItemWithoutCheck(sp)
gasToPass, sp, stackHead := popStackItemWithoutCheck(sp, oldStackHead)
addr, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
argsOffset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
argsSize, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
retOffset, sp, retSize := popStackItemWithoutCheck(sp, stackHead)

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

Expand Down Expand Up @@ -1125,7 +1113,7 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost
default {
extraCost := add(extraCost, precompileCost)
}
sp := pushStackItem(sp, success, evmGasLeft)
stackHead := success
}

function getMessageCallGas (
Expand Down Expand Up @@ -1218,7 +1206,7 @@ function _fetchConstructorReturnGas() -> gasLeft {
gasLeft := mload(0)
}

function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGasLeftOld) -> result, evmGasLeft {
function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGasLeftOld, oldStackHead) -> result, evmGasLeft, stackHead {
pop($llvm_AlwaysInline_llvm$_warmAddress(addr))

_eraseReturndataPointer()
Expand All @@ -1232,10 +1220,10 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa
offset := add(MEM_OFFSET_INNER(), offset)

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)))
sp, stackHead := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x80)), oldStackHead)
sp, stackHead := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x60)), stackHead)
sp, stackHead := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x40)), stackHead)
sp, stackHead := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x20)), stackHead)

// Selector
mstore(sub(offset, 0x80), 0x5b16a23c)
Expand Down Expand Up @@ -1280,13 +1268,13 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa
let back

// skipping check since we pushed exactly 4 items earlier
back, sp := popStackItemWithoutCheck(sp)
back, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
mstore(sub(offset, 0x20), back)
back, sp := popStackItemWithoutCheck(sp)
back, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
mstore(sub(offset, 0x40), back)
back, sp := popStackItemWithoutCheck(sp)
back, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
mstore(sub(offset, 0x60), back)
back, sp := popStackItemWithoutCheck(sp)
back, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
mstore(sub(offset, 0x80), back)
}

Expand Down Expand Up @@ -1329,15 +1317,15 @@ function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) {
}
}

function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp {
function performExtCodeCopy(evmGas,oldSp, oldStackHead) -> evmGasLeft, sp, stackHead {
evmGasLeft := chargeGas(evmGas, 100)

let addr, dest, offset, len
popStackCheck(oldSp, evmGasLeft, 4)
addr, sp := popStackItemWithoutCheck(oldSp)
dest, sp := popStackItemWithoutCheck(sp)
offset, sp := popStackItemWithoutCheck(sp)
len, sp := popStackItemWithoutCheck(sp)
addr, sp, stackHead := popStackItemWithoutCheck(oldSp, oldStackHead)
dest, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
offset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
len, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)

// dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost
// minimum_word_size = (size + 31) / 32
Expand All @@ -1359,7 +1347,7 @@ function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp {
}
}

function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp {
function performCreate(evmGas,oldSp,isStatic, oldStackHead) -> evmGasLeft, sp, stackHead {
evmGasLeft := chargeGas(evmGas, 32000)

if isStatic {
Expand All @@ -1369,9 +1357,8 @@ function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp {
let value, offset, size

popStackCheck(oldSp, evmGasLeft, 3)
value, sp := popStackItemWithoutCheck(oldSp)
offset, sp := popStackItemWithoutCheck(sp)
size, sp := popStackItemWithoutCheck(sp)
value, sp, stackHead := popStackItemWithoutCheck(oldSp, oldStackHead)
offset, sp, size := popStackItemWithoutCheck(sp, stackHead)

checkOverflow(offset, size, evmGasLeft)
checkMemOverflowByOffset(add(offset, size), evmGasLeft)
Expand All @@ -1397,14 +1384,14 @@ function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp {
let addr := getNewAddress(address())

let result
result, evmGasLeft := $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGasLeft)
result, evmGasLeft, stackHead := $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGasLeft, stackHead)

switch result
case 0 { sp := pushStackItem(sp, 0, evmGasLeft) }
default { sp := pushStackItem(sp, addr, evmGasLeft) }
case 0 { stackHead := 0 }
default { stackHead := addr }
}

function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr{
function performCreate2(evmGas, oldSp, isStatic, oldStackHead) -> evmGasLeft, sp, result, addr, stackHead {
evmGasLeft := chargeGas(evmGas, 32000)

if isStatic {
Expand All @@ -1414,10 +1401,10 @@ function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr
let value, offset, size, salt

popStackCheck(oldSp, evmGasLeft, 4)
value, sp := popStackItemWithoutCheck(oldSp)
offset, sp := popStackItemWithoutCheck(sp)
size, sp := popStackItemWithoutCheck(sp)
salt, sp := popStackItemWithoutCheck(sp)
value, sp, stackHead := popStackItemWithoutCheck(oldSp, oldStackHead)
offset, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
size, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)
salt, sp, stackHead := popStackItemWithoutCheck(sp, stackHead)

checkOverflow(offset, size, evmGasLeft)
checkMemOverflowByOffset(add(offset, size), evmGasLeft)
Expand Down Expand Up @@ -1453,5 +1440,5 @@ function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
)

result, evmGasLeft := $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGasLeft)
result, evmGasLeft, stackHead := $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGasLeft, stackHead)
}
Loading
Loading