@@ -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,29 @@ 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+ let <success> := iszero(<call>(<address>, <pos>, sub(<end>, <pos>) <?isCall>, 0</isCall>))
1679+ <!eof>
1680+ let <success> := <call>(<gas>, <address> <?isCall>, 0</isCall>, <pos>, sub(<end>, <pos>), 0, 32)
1681+ </eof>
16731682 if iszero(<success>) { <forwardingRevert>() }
1683+ <?eof>
1684+ if eq(returndatasize(), 32) { returndatacopy(0, 0, 32) }
1685+ </eof>
16741686 let <retVars> := <shl>(mload(0))
16751687 )" );
1676- templ (" call" , m_context.evmVersion ().hasStaticCall () ? " staticcall" : " call" );
1688+ auto const eof = m_context.eofVersion ().has_value ();
1689+ if (!eof)
1690+ templ (" call" , m_context.evmVersion ().hasStaticCall () ? " staticcall" : " call" );
1691+ else
1692+ templ (" call" , " extstaticcall" ); // EOF always has static call
16771693 templ (" isCall" , !m_context.evmVersion ().hasStaticCall ());
16781694 templ (" shl" , m_utils.shiftLeftFunction (offset * 8 ));
16791695 templ (" allocateUnbounded" , m_utils.allocateUnboundedFunction ());
16801696 templ (" pos" , m_context.newYulVariable ());
16811697 templ (" end" , m_context.newYulVariable ());
16821698 templ (" isECRecover" , FunctionType::Kind::ECRecover == functionType->kind ());
1699+ templ (" eof" , eof);
16831700 if (FunctionType::Kind::ECRecover == functionType->kind ())
16841701 templ (" encodeArgs" , m_context.abiFunctions ().tupleEncoder (argumentTypes, parameterTypes));
16851702 else
@@ -1844,7 +1861,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
18441861 solAssert (dynamic_cast <AddressType const &>(*_memberAccess.expression ().annotation ().type ).stateMutability () == StateMutability::Payable);
18451862 define (IRVariable{_memberAccess}.part (" address" ), _memberAccess.expression ());
18461863 }
1847- else if (std::set<std::string>{" call" , " callcode" , " delegatecall" , " staticcall" }.count (member))
1864+ else if (std::set<std::string>{" call" , " extcall " , " callcode" , " delegatecall" , " extdelegatecall " , " staticcall" , " extstaticcall " }.count (member))
18481865 define (IRVariable{_memberAccess}.part (" address" ), _memberAccess.expression ());
18491866 else
18501867 solAssert (false , " Invalid member access to address" );
@@ -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,21 @@ 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+ templ (" eof" , eof);
26812707
26822708 // We do not need to check extcodesize if we expect return data: If there is no
26832709 // code, the call will return empty data and the ABI decoder will revert.
26842710 size_t encodedHeadSize = 0 ;
26852711 for (auto const & t: returnInfo.returnTypes )
26862712 encodedHeadSize += t->decodingType ()->calldataHeadSize ();
26872713 bool const checkExtcodesize =
2688- encodedHeadSize == 0 ||
2689- !m_context.evmVersion ().supportsReturndata () ||
2690- m_context.revertStrings () >= RevertStrings::Debug;
2714+ !m_context.eofVersion ().has_value () &&
2715+ (
2716+ encodedHeadSize == 0 ||
2717+ !m_context.evmVersion ().supportsReturndata () ||
2718+ m_context.revertStrings () >= RevertStrings::Debug
2719+ );
26912720 templ (" checkExtcodesize" , checkExtcodesize);
26922721
26932722 templ (" pos" , m_context.newYulVariable ());
@@ -2747,12 +2776,25 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
27472776 templ (" gas" , " sub(gas(), " + formatNumber (gasNeededByCaller) + " )" );
27482777 }
27492778 // Order is important here, STATICCALL might overlap with DELEGATECALL.
2750- if (isDelegateCall)
2751- templ (" call" , " delegatecall" );
2752- else if (useStaticCall)
2753- templ (" call" , " staticcall" );
2779+ if (!eof)
2780+ {
2781+ if (isDelegateCall)
2782+ templ (" call" , " delegatecall" );
2783+ else if (useStaticCall)
2784+ templ (" call" , " staticcall" );
2785+ else
2786+ templ (" call" , " call" );
2787+ }
27542788 else
2755- templ (" call" , " call" );
2789+ {
2790+ if (isDelegateCall)
2791+ templ (" call" , " extdelegatecall" );
2792+ else if (useStaticCall)
2793+ templ (" call" , " extstaticcall" );
2794+ else
2795+ templ (" call" , " extcall" );
2796+ }
2797+
27562798
27572799 templ (" forwardingRevert" , m_utils.forwardingRevertFunction ());
27582800
@@ -2791,13 +2833,21 @@ void IRGeneratorForStatements::appendBareCall(
27912833 let <length> := mload(<arg>)
27922834 </needsEncoding>
27932835
2794- let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2836+ <?eof>
2837+ let <success> := <call>(<address>, <pos>, <length> <?+value>, <value></+value>)
2838+ <success> := iszero(<success>)
2839+ <!eof>
2840+ let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2841+ </eof>
2842+
27952843 let <returndataVar> := <extractReturndataFunction>()
27962844 )" );
27972845
27982846 templ (" allocateUnbounded" , m_utils.allocateUnboundedFunction ());
27992847 templ (" pos" , m_context.newYulVariable ());
28002848 templ (" length" , m_context.newYulVariable ());
2849+ auto const eof = m_context.eofVersion ().has_value ();
2850+ templ (" eof" , eof);
28012851
28022852 templ (" arg" , IRVariable (*_arguments.front ()).commaSeparatedList ());
28032853 Type const & argType = type (*_arguments.front ());
@@ -2819,16 +2869,29 @@ void IRGeneratorForStatements::appendBareCall(
28192869 if (funKind == FunctionType::Kind::BareCall)
28202870 {
28212871 templ (" value" , funType.valueSet () ? IRVariable (_functionCall.expression ()).part (" value" ).name () : " 0" );
2822- templ (" call" , " call" );
2872+ if (eof)
2873+ templ (" call" , " extcall" );
2874+ else
2875+ templ (" call" , " call" );
28232876 }
28242877 else
28252878 {
28262879 solAssert (!funType.valueSet (), " Value set for delegatecall or staticcall." );
28272880 templ (" value" , " " );
28282881 if (funKind == FunctionType::Kind::BareStaticCall)
2829- templ (" call" , " staticcall" );
2882+ {
2883+ if (eof)
2884+ templ (" call" , " extstaticcall" );
2885+ else
2886+ templ (" call" , " staticcall" );
2887+ }
28302888 else
2831- templ (" call" , " delegatecall" );
2889+ {
2890+ if (eof)
2891+ templ (" call" , " extdelegatecall" );
2892+ else
2893+ templ (" call" , " delegatecall" );
2894+ }
28322895 }
28332896
28342897 if (funType.gasSet ())
0 commit comments