@@ -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