@@ -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
@@ -1844,7 +1862,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
18441862 solAssert (dynamic_cast <AddressType const &>(*_memberAccess.expression ().annotation ().type ).stateMutability () == StateMutability::Payable);
18451863 define (IRVariable{_memberAccess}.part (" address" ), _memberAccess.expression ());
18461864 }
1847- else if (std::set<std::string>{" call" , " callcode" , " delegatecall" , " staticcall" }.count (member))
1865+ else if (std::set<std::string>{" call" , " extcall " , " callcode" , " delegatecall" , " extdelegatecall " , " staticcall" , " extstaticcall " }.count (member))
18481866 define (IRVariable{_memberAccess}.part (" address" ), _memberAccess.expression ());
18491867 else
18501868 solAssert (false , " Invalid member access to address" );
@@ -2642,7 +2660,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26422660 }
26432661
26442662 // 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().
2663+ // When it's dynamic, we get zero from estimatedReturnSize() instead and then we need an explicit returndatacopy().
26462664 Whiskers templ (R"(
26472665 <?checkExtcodesize>
26482666 if iszero(extcodesize(<address>)) { <revertNoCode>() }
@@ -2652,7 +2670,11 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26522670 mstore(<pos>, <shl28>(<funSel>))
26532671 let <end> := <encodeArgs>(add(<pos>, 4) <argumentString>)
26542672
2655- let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <staticReturndataSize>)
2673+ <?eof>
2674+ let <success> := iszero(<call>(<address>, <pos>, sub(<end>, <pos>) <?hasValue>, <value></hasValue>))
2675+ <!eof>
2676+ let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <staticReturndataSize>)
2677+ </eof>
26562678 <?noTryCall>
26572679 if iszero(<success>) { <forwardingRevert>() }
26582680 </noTryCall>
@@ -2667,6 +2689,9 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26672689 if gt(<returnDataSizeVar>, returndatasize()) {
26682690 <returnDataSizeVar> := returndatasize()
26692691 }
2692+ <?eof>
2693+ returndatacopy(<pos>, 0, <returnDataSizeVar>)
2694+ </eof>
26702695 </supportsReturnData>
26712696 </isReturndataSizeDynamic>
26722697
@@ -2678,16 +2703,21 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
26782703 }
26792704 )" );
26802705 templ (" revertNoCode" , m_utils.revertReasonIfDebugFunction (" Target contract does not contain code" ));
2706+ auto const eof = m_context.eofVersion ().has_value ();
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 ());
@@ -2747,12 +2777,13 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
27472777 templ (" gas" , " sub(gas(), " + formatNumber (gasNeededByCaller) + " )" );
27482778 }
27492779 // Order is important here, STATICCALL might overlap with DELEGATECALL.
2780+ std::string const callPrefix = eof ? " ext" : " " ;
27502781 if (isDelegateCall)
2751- templ (" call" , " delegatecall" );
2782+ templ (" call" , callPrefix + " delegatecall" );
27522783 else if (useStaticCall)
2753- templ (" call" , " staticcall" );
2784+ templ (" call" , callPrefix + " staticcall" );
27542785 else
2755- templ (" call" , " call" );
2786+ templ (" call" , callPrefix + " call" );
27562787
27572788 templ (" forwardingRevert" , m_utils.forwardingRevertFunction ());
27582789
@@ -2791,13 +2822,21 @@ void IRGeneratorForStatements::appendBareCall(
27912822 let <length> := mload(<arg>)
27922823 </needsEncoding>
27932824
2794- let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2825+ <?eof>
2826+ let <success> := <call>(<address>, <pos>, <length> <?+value>, <value></+value>)
2827+ <success> := iszero(<success>)
2828+ <!eof>
2829+ let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2830+ </eof>
2831+
27952832 let <returndataVar> := <extractReturndataFunction>()
27962833 )" );
27972834
27982835 templ (" allocateUnbounded" , m_utils.allocateUnboundedFunction ());
27992836 templ (" pos" , m_context.newYulVariable ());
28002837 templ (" length" , m_context.newYulVariable ());
2838+ auto const eof = m_context.eofVersion ().has_value ();
2839+ templ (" eof" , eof);
28012840
28022841 templ (" arg" , IRVariable (*_arguments.front ()).commaSeparatedList ());
28032842 Type const & argType = type (*_arguments.front ());
@@ -2816,19 +2855,20 @@ void IRGeneratorForStatements::appendBareCall(
28162855
28172856 templ (" address" , IRVariable (_functionCall.expression ()).part (" address" ).name ());
28182857
2858+ std::string const callPrefix = eof ? " ext" : " " ;
28192859 if (funKind == FunctionType::Kind::BareCall)
28202860 {
28212861 templ (" value" , funType.valueSet () ? IRVariable (_functionCall.expression ()).part (" value" ).name () : " 0" );
2822- templ (" call" , " call" );
2862+ templ (" call" , callPrefix + " call" );
28232863 }
28242864 else
28252865 {
28262866 solAssert (!funType.valueSet (), " Value set for delegatecall or staticcall." );
28272867 templ (" value" , " " );
28282868 if (funKind == FunctionType::Kind::BareStaticCall)
2829- templ (" call" , " staticcall" );
2869+ templ (" call" , callPrefix + " staticcall" );
28302870 else
2831- templ (" call" , " delegatecall" );
2871+ templ (" call" , callPrefix + " delegatecall" );
28322872 }
28332873
28342874 if (funType.gasSet ())
0 commit comments