Skip to content

Commit f2e6caf

Browse files
committed
eof: Use EOF ext*call in yul generator for statements.
1 parent 2f4795d commit f2e6caf

File tree

1 file changed

+55
-17
lines changed

1 file changed

+55
-17
lines changed

libsolidity/codegen/ir/IRGeneratorForStatements.cpp

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,11 +1622,16 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
16221622
Whiskers templ(R"(
16231623
let <gas> := 0
16241624
if iszero(<value>) { <gas> := <callStipend> }
1625-
let <success> := call(<gas>, <address>, <value>, 0, 0, 0, 0)
1625+
<?eof>
1626+
let <success> := iszero(extcall(<address>, 0, 0, <value>))
1627+
<!eof>
1628+
let <success> := call(<gas>, <address>, <value>, 0, 0, 0, 0)
1629+
</eof>
16261630
<?isTransfer>
16271631
if iszero(<success>) { <forwardingRevert>() }
16281632
</isTransfer>
16291633
)");
1634+
templ("eof", m_context.eofVersion().has_value());
16301635
templ("gas", m_context.newYulVariable());
16311636
templ("callStipend", toString(evmasm::GasCosts::callStipend));
16321637
templ("address", address);
@@ -1669,17 +1674,30 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
16691674
<?isECRecover>
16701675
mstore(0, 0)
16711676
</isECRecover>
1672-
let <success> := <call>(<gas>, <address> <?isCall>, 0</isCall>, <pos>, sub(<end>, <pos>), 0, 32)
1677+
<?eof>
1678+
// EOF always uses extstaticcall
1679+
let <success> := iszero(extstaticcall(<address>, <pos>, sub(<end>, <pos>)))
1680+
<!eof>
1681+
let <success> := <call>(<gas>, <address> <?isCall>, 0</isCall>, <pos>, sub(<end>, <pos>), 0, 32)
1682+
</eof>
16731683
if iszero(<success>) { <forwardingRevert>() }
1684+
<?eof>
1685+
if eq(returndatasize(), 32) { returndatacopy(0, 0, 32) }
1686+
</eof>
16741687
let <retVars> := <shl>(mload(0))
16751688
)");
1676-
templ("call", m_context.evmVersion().hasStaticCall() ? "staticcall" : "call");
1677-
templ("isCall", !m_context.evmVersion().hasStaticCall());
1689+
auto const eof = m_context.eofVersion().has_value();
1690+
if (!eof)
1691+
{
1692+
templ("call", m_context.evmVersion().hasStaticCall() ? "staticcall" : "call");
1693+
templ("isCall", !m_context.evmVersion().hasStaticCall());
1694+
}
16781695
templ("shl", m_utils.shiftLeftFunction(offset * 8));
16791696
templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
16801697
templ("pos", m_context.newYulVariable());
16811698
templ("end", m_context.newYulVariable());
16821699
templ("isECRecover", FunctionType::Kind::ECRecover == functionType->kind());
1700+
templ("eof", eof);
16831701
if (FunctionType::Kind::ECRecover == functionType->kind())
16841702
templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, parameterTypes));
16851703
else
@@ -2630,7 +2648,6 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26302648
argumentStrings += IRVariable(*arg).stackSlots();
26312649
}
26322650

2633-
26342651
if (!m_context.evmVersion().canOverchargeGasForCall())
26352652
{
26362653
// Touch the end of the output area so that we do not pay for memory resize during the call
@@ -2642,7 +2659,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26422659
}
26432660

26442661
// NOTE: When the expected size of returndata is static, we pass that in to the call opcode and it gets copied automatically.
2645-
// When it's dynamic, we get zero from estimatedReturnSize() instead and then we need an explicit returndatacopy().
2662+
// When it's dynamic, we get zero from estimatedReturnSize() instead and then we need an explicit returndatacopy().
26462663
Whiskers templ(R"(
26472664
<?checkExtcodesize>
26482665
if iszero(extcodesize(<address>)) { <revertNoCode>() }
@@ -2652,7 +2669,11 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26522669
mstore(<pos>, <shl28>(<funSel>))
26532670
let <end> := <encodeArgs>(add(<pos>, 4) <argumentString>)
26542671
2655-
let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <staticReturndataSize>)
2672+
<?eof>
2673+
let <success> := iszero(<call>(<address>, <pos>, sub(<end>, <pos>) <?hasValue>, <value></hasValue>))
2674+
<!eof>
2675+
let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <staticReturndataSize>)
2676+
</eof>
26562677
<?noTryCall>
26572678
if iszero(<success>) { <forwardingRevert>() }
26582679
</noTryCall>
@@ -2667,6 +2688,9 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26672688
if gt(<returnDataSizeVar>, returndatasize()) {
26682689
<returnDataSizeVar> := returndatasize()
26692690
}
2691+
<?eof>
2692+
returndatacopy(<pos>, 0, <returnDataSizeVar>)
2693+
</eof>
26702694
</supportsReturnData>
26712695
</isReturndataSizeDynamic>
26722696
@@ -2678,16 +2702,22 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26782702
}
26792703
)");
26802704
templ("revertNoCode", m_utils.revertReasonIfDebugFunction("Target contract does not contain code"));
2705+
auto const eof = m_context.eofVersion().has_value();
2706+
solAssert(!eof || !funType.gasSet());
2707+
templ("eof", eof);
26812708

26822709
// We do not need to check extcodesize if we expect return data: If there is no
26832710
// code, the call will return empty data and the ABI decoder will revert.
26842711
size_t encodedHeadSize = 0;
26852712
for (auto const& t: returnInfo.returnTypes)
26862713
encodedHeadSize += t->decodingType()->calldataHeadSize();
26872714
bool const checkExtcodesize =
2688-
encodedHeadSize == 0 ||
2689-
!m_context.evmVersion().supportsReturndata() ||
2690-
m_context.revertStrings() >= RevertStrings::Debug;
2715+
!eof &&
2716+
(
2717+
encodedHeadSize == 0 ||
2718+
!m_context.evmVersion().supportsReturndata() ||
2719+
m_context.revertStrings() >= RevertStrings::Debug
2720+
);
26912721
templ("checkExtcodesize", checkExtcodesize);
26922722

26932723
templ("pos", m_context.newYulVariable());
@@ -2748,11 +2778,11 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
27482778
}
27492779
// Order is important here, STATICCALL might overlap with DELEGATECALL.
27502780
if (isDelegateCall)
2751-
templ("call", "delegatecall");
2781+
templ("call", eof ? "extdelegatecall" : "delegatecall");
27522782
else if (useStaticCall)
2753-
templ("call", "staticcall");
2783+
templ("call", eof ? "extstaticcall" : "staticcall");
27542784
else
2755-
templ("call", "call");
2785+
templ("call", eof ? "extcall" : "call");
27562786

27572787
templ("forwardingRevert", m_utils.forwardingRevertFunction());
27582788

@@ -2791,13 +2821,20 @@ void IRGeneratorForStatements::appendBareCall(
27912821
let <length> := mload(<arg>)
27922822
</needsEncoding>
27932823
2794-
let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2824+
<?eof>
2825+
let <success> := iszero(<call>(<address>, <pos>, <length> <?+value>, <value></+value>))
2826+
<!eof>
2827+
let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2828+
</eof>
2829+
27952830
let <returndataVar> := <extractReturndataFunction>()
27962831
)");
27972832

27982833
templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
27992834
templ("pos", m_context.newYulVariable());
28002835
templ("length", m_context.newYulVariable());
2836+
auto const eof = m_context.eofVersion().has_value();
2837+
templ("eof", eof);
28012838

28022839
templ("arg", IRVariable(*_arguments.front()).commaSeparatedList());
28032840
Type const& argType = type(*_arguments.front());
@@ -2819,18 +2856,19 @@ void IRGeneratorForStatements::appendBareCall(
28192856
if (funKind == FunctionType::Kind::BareCall)
28202857
{
28212858
templ("value", funType.valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0");
2822-
templ("call", "call");
2859+
templ("call", eof ? "extcall" : "call");
28232860
}
28242861
else
28252862
{
28262863
solAssert(!funType.valueSet(), "Value set for delegatecall or staticcall.");
28272864
templ("value", "");
28282865
if (funKind == FunctionType::Kind::BareStaticCall)
2829-
templ("call", "staticcall");
2866+
templ("call", eof ? "extstaticcall" : "staticcall");
28302867
else
2831-
templ("call", "delegatecall");
2868+
templ("call", eof ? "extdelegatecall" : "delegatecall");
28322869
}
28332870

2871+
solAssert(!eof || !funType.gasSet());
28342872
if (funType.gasSet())
28352873
templ("gas", IRVariable(_functionCall.expression()).part("gas").name());
28362874
else if (m_context.evmVersion().canOverchargeGasForCall())

0 commit comments

Comments
 (0)