@@ -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+ !m_context.eofVersion ().has_value () &&
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,25 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
27472777 templ (" gas" , " sub(gas(), " + formatNumber (gasNeededByCaller) + " )" );
27482778 }
27492779 // Order is important here, STATICCALL might overlap with DELEGATECALL.
2750- if (isDelegateCall)
2751- templ (" call" , " delegatecall" );
2752- else if (useStaticCall)
2753- templ (" call" , " staticcall" );
2780+ if (!eof)
2781+ {
2782+ if (isDelegateCall)
2783+ templ (" call" , " delegatecall" );
2784+ else if (useStaticCall)
2785+ templ (" call" , " staticcall" );
2786+ else
2787+ templ (" call" , " call" );
2788+ }
27542789 else
2755- templ (" call" , " call" );
2790+ {
2791+ if (isDelegateCall)
2792+ templ (" call" , " extdelegatecall" );
2793+ else if (useStaticCall)
2794+ templ (" call" , " extstaticcall" );
2795+ else
2796+ templ (" call" , " extcall" );
2797+ }
2798+
27562799
27572800 templ (" forwardingRevert" , m_utils.forwardingRevertFunction ());
27582801
@@ -2791,13 +2834,21 @@ void IRGeneratorForStatements::appendBareCall(
27912834 let <length> := mload(<arg>)
27922835 </needsEncoding>
27932836
2794- let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2837+ <?eof>
2838+ let <success> := <call>(<address>, <pos>, <length> <?+value>, <value></+value>)
2839+ <success> := iszero(<success>)
2840+ <!eof>
2841+ let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2842+ </eof>
2843+
27952844 let <returndataVar> := <extractReturndataFunction>()
27962845 )" );
27972846
27982847 templ (" allocateUnbounded" , m_utils.allocateUnboundedFunction ());
27992848 templ (" pos" , m_context.newYulVariable ());
28002849 templ (" length" , m_context.newYulVariable ());
2850+ auto const eof = m_context.eofVersion ().has_value ();
2851+ templ (" eof" , eof);
28012852
28022853 templ (" arg" , IRVariable (*_arguments.front ()).commaSeparatedList ());
28032854 Type const & argType = type (*_arguments.front ());
@@ -2819,16 +2870,29 @@ void IRGeneratorForStatements::appendBareCall(
28192870 if (funKind == FunctionType::Kind::BareCall)
28202871 {
28212872 templ (" value" , funType.valueSet () ? IRVariable (_functionCall.expression ()).part (" value" ).name () : " 0" );
2822- templ (" call" , " call" );
2873+ if (eof)
2874+ templ (" call" , " extcall" );
2875+ else
2876+ templ (" call" , " call" );
28232877 }
28242878 else
28252879 {
28262880 solAssert (!funType.valueSet (), " Value set for delegatecall or staticcall." );
28272881 templ (" value" , " " );
28282882 if (funKind == FunctionType::Kind::BareStaticCall)
2829- templ (" call" , " staticcall" );
2883+ {
2884+ if (eof)
2885+ templ (" call" , " extstaticcall" );
2886+ else
2887+ templ (" call" , " staticcall" );
2888+ }
28302889 else
2831- templ (" call" , " delegatecall" );
2890+ {
2891+ if (eof)
2892+ templ (" call" , " extdelegatecall" );
2893+ else
2894+ templ (" call" , " delegatecall" );
2895+ }
28322896 }
28332897
28342898 if (funType.gasSet ())
0 commit comments