mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12205 from ethereum/optimizeextocedsizecheck
Skip extcodesize check if return data is expected.
This commit is contained in:
commit
4f8719326c
Changelog.md
docs
libsolidity/codegen
test
cmdlineTests
standard_debug_info_in_evm_asm_via_ir_location
standard_debug_info_in_yul_location
libsolidity/semanticTests
abiEncoderV1
abiEncoderV2
abi_encode_calldata_slice.solabi_encode_v2_in_function_inherited_in_v1_contract.solabi_encode_v2_in_modifier_used_in_v1_contract.solcalldata_array.sol
arithmetics
array
constructor
freeFunctions
functionCall
creation_function_call_no_args.solexternal_call_at_construction_time.solexternal_call_to_nonexisting.solexternal_call_to_nonexisting_debugstrings.solfailed_create.solprecompile_extcodesize_check.sol
functionTypes
immutable
inheritance
address_overload_resolution.solinherited_function_calldata_calldata_interface.solinherited_function_calldata_memory_interface.solmember_notation_ctor.sol
interface_inheritance_conversions.solsalted_create
smoke
various
@ -5,6 +5,7 @@ Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Code Generator: Skip existence check for external contract if return data is expected. In this case, the ABI decoder will revert if the contract does not exist.
|
||||
* Commandline Interface: Accept nested brackets in step sequences passed to ``--yul-optimizations``.
|
||||
* Commandline Interface: Add ``--debug-info`` option for selecting how much extra debug information should be included in the produced EVM assembly and Yul code.
|
||||
* Commandline Interface: Use different colors when printing errors, warnings and infos.
|
||||
|
@ -114,10 +114,19 @@ otherwise, the ``value`` option would not be available.
|
||||
Due to the fact that the EVM considers a call to a non-existing contract to
|
||||
always succeed, Solidity uses the ``extcodesize`` opcode to check that
|
||||
the contract that is about to be called actually exists (it contains code)
|
||||
and causes an exception if it does not.
|
||||
and causes an exception if it does not. This check is skipped if the return
|
||||
data will be decoded after the call and thus the ABI decoder will catch the
|
||||
case of a non-existing contract.
|
||||
|
||||
Note that this check is not performed in case of :ref:`low-level calls <address_related>` which
|
||||
operate on addresses rather than contract instances.
|
||||
|
||||
.. note::
|
||||
Be careful when using high-level calls to
|
||||
:ref:`precompiled contracts <precompiledContracts>`,
|
||||
since the compiler considers them non-existing according to the
|
||||
above logic even though they execute code and can return data.
|
||||
|
||||
Function calls also cause exceptions if the called contract itself
|
||||
throws an exception or goes out of gas.
|
||||
|
||||
|
@ -565,3 +565,24 @@ contracts, the Ether is forever lost.
|
||||
If you want to deactivate your contracts, you should instead **disable** them
|
||||
by changing some internal state which causes all functions to revert. This
|
||||
makes it impossible to use the contract, as it returns Ether immediately.
|
||||
|
||||
|
||||
.. index:: ! precompiled contracts, ! precompiles, ! contract;precompiled
|
||||
|
||||
.. _precompiledContracts:
|
||||
|
||||
Precompiled Contracts
|
||||
=====================
|
||||
|
||||
There is a small set of contract addresses that are special:
|
||||
The address range between ``1`` and (including) ``8`` contains
|
||||
"precompiled contracts" that can be called as any other contract
|
||||
but their behaviour (and their gas consumption) is not defined
|
||||
by EVM code stored at that address (they do not contain code)
|
||||
but instead is implemented in the EVM execution environment itself.
|
||||
|
||||
Different EVM-compatible chains might use a different set of
|
||||
precompiled contracts. It might also be possible that new
|
||||
precompiled contracts are added to the Ethereum main chain in the future,
|
||||
but you can reasonabyly expect them to always be in the range between
|
||||
``1`` and ``0xffff`` (inclusive).
|
@ -2630,9 +2630,21 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
// Check the target contract exists (has code) for non-low-level calls.
|
||||
if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall)
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO;
|
||||
m_context.appendConditionalRevert(false, "Target contract does not contain code");
|
||||
existenceChecked = true;
|
||||
size_t encodedHeadSize = 0;
|
||||
for (auto const& t: returnTypes)
|
||||
encodedHeadSize += t->decodingType()->calldataHeadSize();
|
||||
// We do not need to check extcodesize if we expect return data, since if there is no
|
||||
// code, the call will return empty data and the ABI decoder will revert.
|
||||
if (
|
||||
encodedHeadSize == 0 ||
|
||||
!haveReturndatacopy ||
|
||||
m_context.revertStrings() >= RevertStrings::Debug
|
||||
)
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO;
|
||||
m_context.appendConditionalRevert(false, "Target contract does not contain code");
|
||||
existenceChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_functionType.gasSet())
|
||||
|
@ -2451,8 +2451,10 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
||||
appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
|
||||
}
|
||||
|
||||
Whiskers templ(R"(if iszero(extcodesize(<address>)) { <revertNoCode>() }
|
||||
|
||||
Whiskers templ(R"(
|
||||
<?checkExtcodesize>
|
||||
if iszero(extcodesize(<address>)) { <revertNoCode>() }
|
||||
</checkExtcodesize>
|
||||
// storage for arguments and returned data
|
||||
let <pos> := <allocateUnbounded>()
|
||||
mstore(<pos>, <shl28>(<funSel>))
|
||||
@ -2477,6 +2479,18 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
||||
}
|
||||
)");
|
||||
templ("revertNoCode", m_utils.revertReasonIfDebugFunction("Target contract does not contain code"));
|
||||
|
||||
// We do not need to check extcodesize if we expect return data: If there is no
|
||||
// code, the call will return empty data and the ABI decoder will revert.
|
||||
size_t encodedHeadSize = 0;
|
||||
for (auto const& t: returnInfo.returnTypes)
|
||||
encodedHeadSize += t->decodingType()->calldataHeadSize();
|
||||
bool const checkExtcodesize =
|
||||
encodedHeadSize == 0 ||
|
||||
!m_context.evmVersion().supportsReturndata() ||
|
||||
m_context.revertStrings() >= RevertStrings::Debug;
|
||||
templ("checkExtcodesize", checkExtcodesize);
|
||||
|
||||
templ("pos", m_context.newYulVariable());
|
||||
templ("end", m_context.newYulVariable());
|
||||
if (_functionCall.annotation().tryCall)
|
||||
@ -2532,6 +2546,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
||||
u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10;
|
||||
if (funType.valueSet())
|
||||
gasNeededByCaller += evmasm::GasCosts::callValueTransferGas;
|
||||
if (!checkExtcodesize)
|
||||
gasNeededByCaller += evmasm::GasCosts::callNewAccountGas; // we never know
|
||||
templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")");
|
||||
}
|
||||
// Order is important here, STATICCALL might overlap with DELEGATECALL.
|
||||
|
@ -285,27 +285,18 @@ sub_0: assembly {
|
||||
dup2
|
||||
dup2
|
||||
sstore
|
||||
/* \"C\":403:407 this */
|
||||
address
|
||||
/* \"C\":403:411 this.f() */
|
||||
extcodesize
|
||||
iszero
|
||||
tag_43
|
||||
jumpi
|
||||
/* \"C\":79:428 contract C... */
|
||||
mload(0x40)
|
||||
shl(0xe4, 0x026121ff)
|
||||
/* \"C\":403:411 this.f() */
|
||||
dup2
|
||||
mstore
|
||||
0x20
|
||||
/* \"C\":79:428 contract C... */
|
||||
/* \"C\":403:407 this */
|
||||
dup2
|
||||
/* \"C\":403:411 this.f() */
|
||||
0x04
|
||||
/* \"C\":79:428 contract C... */
|
||||
dup2
|
||||
/* \"C\":403:407 this */
|
||||
dup2
|
||||
address
|
||||
/* \"C\":403:411 this.f() */
|
||||
gas
|
||||
@ -313,38 +304,38 @@ sub_0: assembly {
|
||||
swap2
|
||||
dup3
|
||||
iszero
|
||||
tag_45
|
||||
tag_43
|
||||
jumpi
|
||||
dup1
|
||||
swap3
|
||||
tag_47
|
||||
tag_45
|
||||
jumpi
|
||||
/* \"C\":304:341 modifier m()... */
|
||||
tag_48:
|
||||
tag_46:
|
||||
/* \"C\":392:411 stateVar + this.f() */
|
||||
pop
|
||||
pop
|
||||
tag_49
|
||||
tag_47
|
||||
swap1
|
||||
/* \"C\":392:422 stateVar + this.f() + immutVar */
|
||||
tag_50
|
||||
tag_48
|
||||
/* \"C\":392:411 stateVar + this.f() */
|
||||
swap3
|
||||
tag_5
|
||||
jump\t// in
|
||||
tag_49:
|
||||
tag_47:
|
||||
/* \"C\":414:422 immutVar */
|
||||
immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\")
|
||||
/* \"C\":392:422 stateVar + this.f() + immutVar */
|
||||
swap1
|
||||
tag_5
|
||||
jump\t// in
|
||||
tag_50:
|
||||
tag_48:
|
||||
/* \"C\":304:341 modifier m()... */
|
||||
swap1
|
||||
jump\t// out
|
||||
/* \"C\":403:411 this.f() */
|
||||
tag_47:
|
||||
tag_45:
|
||||
/* \"C\":79:428 contract C... */
|
||||
swap1
|
||||
swap2
|
||||
@ -366,18 +357,18 @@ sub_0: assembly {
|
||||
dup4
|
||||
lt
|
||||
or
|
||||
tag_51
|
||||
tag_49
|
||||
jumpi
|
||||
pop
|
||||
swap2
|
||||
/* \"C\":403:411 this.f() */
|
||||
tag_53
|
||||
tag_51
|
||||
/* \"C\":392:411 stateVar + this.f() */
|
||||
tag_49
|
||||
tag_47
|
||||
/* \"C\":79:428 contract C... */
|
||||
swap3
|
||||
/* \"C\":392:422 stateVar + this.f() + immutVar */
|
||||
tag_50
|
||||
tag_48
|
||||
/* \"C\":79:428 contract C... */
|
||||
swap5
|
||||
0x40
|
||||
@ -389,14 +380,14 @@ sub_0: assembly {
|
||||
swap1
|
||||
tag_7
|
||||
jump\t// in
|
||||
tag_53:
|
||||
tag_51:
|
||||
swap2
|
||||
dup2
|
||||
swap4
|
||||
pop
|
||||
jump(tag_48)
|
||||
jump(tag_46)
|
||||
/* \"C\":79:428 contract C... */
|
||||
tag_51:
|
||||
tag_49:
|
||||
shl(0xe0, 0x4e487b71)
|
||||
dup2
|
||||
mstore
|
||||
@ -416,7 +407,7 @@ sub_0: assembly {
|
||||
/* \"C\":79:428 contract C... */
|
||||
revert
|
||||
/* \"C\":403:411 this.f() */
|
||||
tag_45:
|
||||
tag_43:
|
||||
/* \"C\":79:428 contract C... */
|
||||
swap4
|
||||
pop
|
||||
@ -431,20 +422,12 @@ sub_0: assembly {
|
||||
returndatacopy
|
||||
returndatasize
|
||||
swap1
|
||||
revert
|
||||
/* \"C\":403:411 this.f() */
|
||||
tag_43:
|
||||
/* \"C\":79:428 contract C... */
|
||||
swap2
|
||||
pop
|
||||
pop
|
||||
dup1
|
||||
revert
|
||||
tag_41:
|
||||
tag_54
|
||||
tag_52
|
||||
tag_3
|
||||
jump\t// in
|
||||
tag_54:
|
||||
tag_52:
|
||||
jump(tag_42)
|
||||
tag_7:
|
||||
swap1
|
||||
@ -453,12 +436,12 @@ sub_0: assembly {
|
||||
swap2
|
||||
sub
|
||||
slt
|
||||
tag_55
|
||||
tag_53
|
||||
jumpi
|
||||
mload
|
||||
swap1
|
||||
jump\t// out
|
||||
tag_55:
|
||||
tag_53:
|
||||
pop
|
||||
pop
|
||||
0x00
|
||||
@ -795,27 +778,18 @@ sub_0: assembly {
|
||||
dup2
|
||||
dup2
|
||||
sstore
|
||||
/* \"C\":403:407 this */
|
||||
address
|
||||
/* \"C\":403:411 this.f() */
|
||||
extcodesize
|
||||
iszero
|
||||
tag_43
|
||||
jumpi
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
mload(0x40)
|
||||
shl(0xe4, 0x026121ff)
|
||||
/* \"C\":403:411 this.f() */
|
||||
dup2
|
||||
mstore
|
||||
0x20
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
/* \"C\":403:407 this */
|
||||
dup2
|
||||
/* \"C\":403:411 this.f() */
|
||||
0x04
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
dup2
|
||||
/* \"C\":403:407 this */
|
||||
dup2
|
||||
address
|
||||
/* \"C\":403:411 this.f() */
|
||||
gas
|
||||
@ -823,38 +797,38 @@ sub_0: assembly {
|
||||
swap2
|
||||
dup3
|
||||
iszero
|
||||
tag_45
|
||||
tag_43
|
||||
jumpi
|
||||
dup1
|
||||
swap3
|
||||
tag_47
|
||||
tag_45
|
||||
jumpi
|
||||
/* \"C\":304:341 modifier m()... */
|
||||
tag_48:
|
||||
tag_46:
|
||||
/* \"C\":392:411 stateVar + this.f() */
|
||||
pop
|
||||
pop
|
||||
tag_49
|
||||
tag_47
|
||||
swap1
|
||||
/* \"C\":392:422 stateVar + this.f() + immutVar */
|
||||
tag_50
|
||||
tag_48
|
||||
/* \"C\":392:411 stateVar + this.f() */
|
||||
swap3
|
||||
tag_5
|
||||
jump\t// in
|
||||
tag_49:
|
||||
tag_47:
|
||||
/* \"C\":414:422 immutVar */
|
||||
immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\")
|
||||
/* \"C\":392:422 stateVar + this.f() + immutVar */
|
||||
swap1
|
||||
tag_5
|
||||
jump\t// in
|
||||
tag_50:
|
||||
tag_48:
|
||||
/* \"C\":304:341 modifier m()... */
|
||||
swap1
|
||||
jump\t// out
|
||||
/* \"C\":403:411 this.f() */
|
||||
tag_47:
|
||||
tag_45:
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
swap1
|
||||
swap2
|
||||
@ -876,18 +850,18 @@ sub_0: assembly {
|
||||
dup4
|
||||
lt
|
||||
or
|
||||
tag_51
|
||||
tag_49
|
||||
jumpi
|
||||
pop
|
||||
swap2
|
||||
/* \"C\":403:411 this.f() */
|
||||
tag_53
|
||||
tag_51
|
||||
/* \"C\":392:411 stateVar + this.f() */
|
||||
tag_49
|
||||
tag_47
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
swap3
|
||||
/* \"C\":392:422 stateVar + this.f() + immutVar */
|
||||
tag_50
|
||||
tag_48
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
swap5
|
||||
0x40
|
||||
@ -899,14 +873,14 @@ sub_0: assembly {
|
||||
swap1
|
||||
tag_7
|
||||
jump\t// in
|
||||
tag_53:
|
||||
tag_51:
|
||||
swap2
|
||||
dup2
|
||||
swap4
|
||||
pop
|
||||
jump(tag_48)
|
||||
jump(tag_46)
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
tag_51:
|
||||
tag_49:
|
||||
shl(0xe0, 0x4e487b71)
|
||||
dup2
|
||||
mstore
|
||||
@ -926,7 +900,7 @@ sub_0: assembly {
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
revert
|
||||
/* \"C\":403:411 this.f() */
|
||||
tag_45:
|
||||
tag_43:
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
swap4
|
||||
pop
|
||||
@ -941,20 +915,12 @@ sub_0: assembly {
|
||||
returndatacopy
|
||||
returndatasize
|
||||
swap1
|
||||
revert
|
||||
/* \"C\":403:411 this.f() */
|
||||
tag_43:
|
||||
/* \"D\":91:166 contract D is C(3)... */
|
||||
swap2
|
||||
pop
|
||||
pop
|
||||
dup1
|
||||
revert
|
||||
tag_41:
|
||||
tag_54
|
||||
tag_52
|
||||
tag_3
|
||||
jump\t// in
|
||||
tag_54:
|
||||
tag_52:
|
||||
jump(tag_42)
|
||||
tag_7:
|
||||
swap1
|
||||
@ -963,12 +929,12 @@ sub_0: assembly {
|
||||
swap2
|
||||
sub
|
||||
slt
|
||||
tag_55
|
||||
tag_53
|
||||
jumpi
|
||||
mload
|
||||
swap1
|
||||
jump\t// out
|
||||
tag_55:
|
||||
tag_53:
|
||||
pop
|
||||
pop
|
||||
0x00
|
||||
|
@ -526,7 +526,6 @@ object \"C_54\" {
|
||||
let expr_46_address := convert_t_contract$_C_$54_to_t_address(expr_45_address)
|
||||
let expr_46_functionSelector := 0x26121ff0
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
if iszero(extcodesize(expr_46_address)) { revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() }
|
||||
|
||||
// storage for arguments and returned data
|
||||
let _10 := allocate_unbounded()
|
||||
@ -640,7 +639,7 @@ object \"C_54\" {
|
||||
case 0x26121ff0 {
|
||||
if callvalue() { revert(_1, _1) }
|
||||
abi_decode(calldatasize())
|
||||
let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_566(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\"))
|
||||
let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_556(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\"))
|
||||
/// @src 0:79:435 \"contract C...\"
|
||||
let memPos := mload(64)
|
||||
return(memPos, sub(abi_encode_int256(memPos, ret), memPos))
|
||||
@ -664,7 +663,7 @@ object \"C_54\" {
|
||||
if callvalue() { revert(_1, _1) }
|
||||
abi_decode(calldatasize())
|
||||
let memPos_3 := mload(64)
|
||||
return(memPos_3, sub(abi_encode_int256_565(memPos_3), memPos_3))
|
||||
return(memPos_3, sub(abi_encode_int256_555(memPos_3), memPos_3))
|
||||
}
|
||||
}
|
||||
revert(0, 0)
|
||||
@ -673,7 +672,7 @@ object \"C_54\" {
|
||||
{
|
||||
if slt(add(dataEnd, not(3)), 0) { revert(0, 0) }
|
||||
}
|
||||
function abi_encode_int256_565(headStart) -> tail
|
||||
function abi_encode_int256_555(headStart) -> tail
|
||||
{
|
||||
tail := add(headStart, 32)
|
||||
mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29)
|
||||
@ -690,7 +689,7 @@ object \"C_54\" {
|
||||
mstore(4, 0x11)
|
||||
revert(0, 0x24)
|
||||
}
|
||||
function checked_add_int256_566(y) -> sum
|
||||
function checked_add_int256_556(y) -> sum
|
||||
{
|
||||
if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() }
|
||||
sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 0:79:435 \"contract C...\" */ y)
|
||||
@ -712,13 +711,6 @@ object \"C_54\" {
|
||||
let ret := add(_3, 1)
|
||||
sstore(_2, ret)
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
if iszero(extcodesize(/** @src 0:410:414 \"this\" */ address()))
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
{
|
||||
/// @src 0:79:435 \"contract C...\"
|
||||
revert(_2, _2)
|
||||
}
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
let _4 := /** @src 0:79:435 \"contract C...\" */ mload(64)
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
mstore(_4, /** @src 0:79:435 \"contract C...\" */ shl(228, 0x026121ff))
|
||||
@ -1359,7 +1351,6 @@ object \"D_72\" {
|
||||
let expr_46_address := convert_t_contract$_C_$54_to_t_address(expr_45_address)
|
||||
let expr_46_functionSelector := 0x26121ff0
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
if iszero(extcodesize(expr_46_address)) { revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() }
|
||||
|
||||
// storage for arguments and returned data
|
||||
let _10 := allocate_unbounded()
|
||||
@ -1481,7 +1472,7 @@ object \"D_72\" {
|
||||
case 0x26121ff0 {
|
||||
if callvalue() { revert(_1, _1) }
|
||||
abi_decode(calldatasize())
|
||||
let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_566(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\"))
|
||||
let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_556(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\"))
|
||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||
let memPos := mload(64)
|
||||
return(memPos, sub(abi_encode_int256(memPos, ret), memPos))
|
||||
@ -1505,7 +1496,7 @@ object \"D_72\" {
|
||||
if callvalue() { revert(_1, _1) }
|
||||
abi_decode(calldatasize())
|
||||
let memPos_3 := mload(64)
|
||||
return(memPos_3, sub(abi_encode_int256_565(memPos_3), memPos_3))
|
||||
return(memPos_3, sub(abi_encode_int256_555(memPos_3), memPos_3))
|
||||
}
|
||||
}
|
||||
revert(0, 0)
|
||||
@ -1514,7 +1505,7 @@ object \"D_72\" {
|
||||
{
|
||||
if slt(add(dataEnd, not(3)), 0) { revert(0, 0) }
|
||||
}
|
||||
function abi_encode_int256_565(headStart) -> tail
|
||||
function abi_encode_int256_555(headStart) -> tail
|
||||
{
|
||||
tail := add(headStart, 32)
|
||||
mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29)
|
||||
@ -1531,7 +1522,7 @@ object \"D_72\" {
|
||||
mstore(4, 0x11)
|
||||
revert(0, 0x24)
|
||||
}
|
||||
function checked_add_int256_566(y) -> sum
|
||||
function checked_add_int256_556(y) -> sum
|
||||
{
|
||||
if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() }
|
||||
sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 1:91:166 \"contract D is C(3)...\" */ y)
|
||||
@ -1553,13 +1544,6 @@ object \"D_72\" {
|
||||
let ret := add(_3, 1)
|
||||
sstore(_2, ret)
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
if iszero(extcodesize(/** @src 0:410:414 \"this\" */ address()))
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
{
|
||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||
revert(_2, _2)
|
||||
}
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
let _4 := /** @src 1:91:166 \"contract D is C(3)...\" */ mload(64)
|
||||
/// @src 0:410:418 \"this.f()\"
|
||||
mstore(_4, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(228, 0x026121ff))
|
||||
|
@ -60,10 +60,10 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test_bytes() ->
|
||||
// gas irOptimized: 377545
|
||||
// gas legacy: 423563
|
||||
// gas legacyOptimized: 331391
|
||||
// gas irOptimized: 373483
|
||||
// gas legacy: 418955
|
||||
// gas legacyOptimized: 326783
|
||||
// test_uint256() ->
|
||||
// gas irOptimized: 528726
|
||||
// gas legacy: 591392
|
||||
// gas legacyOptimized: 456137
|
||||
// gas irOptimized: 524664
|
||||
// gas legacy: 586784
|
||||
// gas legacyOptimized: 451529
|
||||
|
@ -26,6 +26,6 @@ contract C {
|
||||
// ----
|
||||
// library: L
|
||||
// f() -> 8, 7, 1, 2, 7, 12
|
||||
// gas irOptimized: 167580
|
||||
// gas legacy: 169475
|
||||
// gas legacyOptimized: 167397
|
||||
// gas irOptimized: 167446
|
||||
// gas legacy: 169347
|
||||
// gas legacyOptimized: 167269
|
||||
|
@ -61,10 +61,10 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test_bytes() ->
|
||||
// gas irOptimized: 377545
|
||||
// gas legacy: 423563
|
||||
// gas legacyOptimized: 331391
|
||||
// gas irOptimized: 373483
|
||||
// gas legacy: 418955
|
||||
// gas legacyOptimized: 326783
|
||||
// test_uint256() ->
|
||||
// gas irOptimized: 528726
|
||||
// gas legacy: 591392
|
||||
// gas legacyOptimized: 456137
|
||||
// gas irOptimized: 524664
|
||||
// gas legacy: 586784
|
||||
// gas legacyOptimized: 451529
|
||||
|
@ -32,6 +32,6 @@ contract C is B {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 77
|
||||
// gas irOptimized: 120044
|
||||
// gas legacy: 155221
|
||||
// gas legacyOptimized: 111678
|
||||
// gas irOptimized: 119931
|
||||
// gas legacy: 155093
|
||||
// gas legacyOptimized: 111550
|
||||
|
@ -40,5 +40,5 @@ contract C is B {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 5, 10
|
||||
// gas irOptimized: 87578
|
||||
// gas legacy: 99137
|
||||
// gas irOptimized: 87337
|
||||
// gas legacy: 98881
|
||||
|
@ -21,6 +21,6 @@ contract C {
|
||||
// f(uint256[][1]): 32, 32, 0 -> true
|
||||
// f(uint256[][1]): 32, 32, 1, 42 -> true
|
||||
// f(uint256[][1]): 32, 32, 8, 421, 422, 423, 424, 425, 426, 427, 428 -> true
|
||||
// gas irOptimized: 172204
|
||||
// gas legacy: 141900
|
||||
// gas legacyOptimized: 121788
|
||||
// gas irOptimized: 171964
|
||||
// gas legacy: 141644
|
||||
// gas legacyOptimized: 121532
|
||||
|
@ -18,4 +18,4 @@ contract D {
|
||||
// ----
|
||||
// f() -> FAILURE, hex"4e487b71", 0x11
|
||||
// g(), 100 wei -> 1
|
||||
// gas legacy: 101918
|
||||
// gas legacy: 101790
|
||||
|
@ -21,6 +21,6 @@ contract B {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2, 3, 4, 5, 6, 1000, 1001, 1002, 1003, 1004
|
||||
// gas irOptimized: 130328
|
||||
// gas legacy: 235199
|
||||
// gas legacyOptimized: 133119
|
||||
// gas irOptimized: 130097
|
||||
// gas legacy: 234943
|
||||
// gas legacyOptimized: 132863
|
||||
|
@ -45,6 +45,6 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 5, 6, 7
|
||||
// gas irOptimized: 302321
|
||||
// gas legacy: 462080
|
||||
// gas legacyOptimized: 294938
|
||||
// gas irOptimized: 290947
|
||||
// gas legacy: 452172
|
||||
// gas legacyOptimized: 285017
|
||||
|
@ -26,6 +26,6 @@ contract Main {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1
|
||||
// gas irOptimized: 113776
|
||||
// gas legacy: 126852
|
||||
// gas legacyOptimized: 114079
|
||||
// gas irOptimized: 113581
|
||||
// gas legacy: 126596
|
||||
// gas legacyOptimized: 113823
|
||||
|
@ -26,6 +26,6 @@ contract Creator {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256,address[]): 7, 0x40, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -> 7, 8
|
||||
// gas irOptimized: 456873
|
||||
// gas legacy: 590939
|
||||
// gas legacyOptimized: 448582
|
||||
// gas irOptimized: 456668
|
||||
// gas legacy: 590683
|
||||
// gas legacyOptimized: 448326
|
||||
|
@ -26,6 +26,6 @@ contract Creator {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256,bytes): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> 7, "h"
|
||||
// gas irOptimized: 308702
|
||||
// gas legacy: 429173
|
||||
// gas legacyOptimized: 298384
|
||||
// gas irOptimized: 308497
|
||||
// gas legacy: 428917
|
||||
// gas legacyOptimized: 298128
|
||||
|
@ -19,4 +19,4 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 16
|
||||
// gas legacy: 103744
|
||||
// gas legacy: 103488
|
||||
|
@ -15,4 +15,4 @@ contract D {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2
|
||||
// gas legacy: 101754
|
||||
// gas legacy: 101626
|
||||
|
@ -13,4 +13,4 @@ contract D {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2
|
||||
// gas legacy: 101727
|
||||
// gas legacy: 101599
|
||||
|
@ -0,0 +1,26 @@
|
||||
// This tests skipping the extcodesize check.
|
||||
|
||||
contract T {
|
||||
constructor() { this.f(); }
|
||||
function f() external {}
|
||||
}
|
||||
contract U {
|
||||
constructor() { this.f(); }
|
||||
function f() external returns (uint) {}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f(uint c) external returns (uint) {
|
||||
if (c == 0) new T();
|
||||
else if (c == 1) new U();
|
||||
return 1 + c;
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256): 0 -> FAILURE
|
||||
// f(uint256): 1 -> FAILURE
|
||||
// f(uint256): 2 -> 3
|
@ -0,0 +1,36 @@
|
||||
// This tests skipping the extcodesize check.
|
||||
|
||||
interface I {
|
||||
function a() external pure;
|
||||
function b() external;
|
||||
function c() external payable;
|
||||
function x() external returns (uint);
|
||||
function y() external returns (string memory);
|
||||
}
|
||||
contract C {
|
||||
I i = I(address(0xcafecafe));
|
||||
constructor() payable {}
|
||||
function f(uint c) external returns (uint) {
|
||||
if (c == 0) i.a();
|
||||
else if (c == 1) i.b();
|
||||
else if (c == 2) i.c();
|
||||
else if (c == 3) i.c{value: 1}();
|
||||
else if (c == 4) i.x();
|
||||
else if (c == 5) i.y();
|
||||
return 1 + c;
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(), 1 ether ->
|
||||
// gas legacy: 465314
|
||||
// gas legacyOptimized: 510004
|
||||
// f(uint256): 0 -> FAILURE
|
||||
// f(uint256): 1 -> FAILURE
|
||||
// f(uint256): 2 -> FAILURE
|
||||
// f(uint256): 3 -> FAILURE
|
||||
// f(uint256): 4 -> FAILURE
|
||||
// f(uint256): 5 -> FAILURE
|
||||
// f(uint256): 6 -> 7
|
@ -0,0 +1,37 @@
|
||||
// This tests skipping the extcodesize check.
|
||||
|
||||
interface I {
|
||||
function a() external pure;
|
||||
function b() external;
|
||||
function c() external payable;
|
||||
function x() external returns (uint);
|
||||
function y() external returns (string memory);
|
||||
}
|
||||
contract C {
|
||||
I i = I(address(0xcafecafe));
|
||||
constructor() payable {}
|
||||
function f(uint c) external returns (uint) {
|
||||
if (c == 0) i.a();
|
||||
else if (c == 1) i.b();
|
||||
else if (c == 2) i.c();
|
||||
else if (c == 3) i.c{value: 1}();
|
||||
else if (c == 4) i.x();
|
||||
else if (c == 5) i.y();
|
||||
return 1 + c;
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// compileViaYul: also
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// constructor(), 1 ether ->
|
||||
// gas legacyOptimized: 510004
|
||||
// f(uint256): 0 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code"
|
||||
// f(uint256): 1 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code"
|
||||
// f(uint256): 2 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code"
|
||||
// f(uint256): 3 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code"
|
||||
// f(uint256): 4 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code"
|
||||
// f(uint256): 5 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code"
|
||||
// f(uint256): 6 -> 7
|
@ -18,17 +18,17 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(), 20 wei
|
||||
// gas irOptimized: 220113
|
||||
// gas legacy: 288299
|
||||
// gas legacyOptimized: 177933
|
||||
// gas irOptimized: 218775
|
||||
// gas legacy: 294569
|
||||
// gas legacyOptimized: 174699
|
||||
// f(uint256): 20 -> 1370859564726510389319704988634906228201275401179
|
||||
// x() -> 1
|
||||
// f(uint256): 20 -> FAILURE
|
||||
// x() -> 1
|
||||
// stack(uint256): 1023 -> FAILURE
|
||||
// gas irOptimized: 345821
|
||||
// gas legacy: 535367
|
||||
// gas legacyOptimized: 354656
|
||||
// gas irOptimized: 296769
|
||||
// gas legacy: 483942
|
||||
// gas legacyOptimized: 298807
|
||||
// x() -> 1
|
||||
// stack(uint256): 10 -> 693016686122178122849713379390321835634789309880
|
||||
// x() -> 2
|
||||
|
@ -1,13 +1,21 @@
|
||||
interface Identity {
|
||||
function selectorAndAppendValue(uint value) external pure returns (uint);
|
||||
}
|
||||
interface ReturnMoreData {
|
||||
function f(uint value) external pure returns (uint, uint, uint);
|
||||
}
|
||||
contract C {
|
||||
Identity constant i = Identity(address(0x0004));
|
||||
function testHighLevel() external pure returns (bool) {
|
||||
// Should fail because `extcodesize(4) = 0`
|
||||
// Works because the extcodesize check is skipped
|
||||
// and the precompiled contract returns actual data.
|
||||
i.selectorAndAppendValue(5);
|
||||
return true;
|
||||
}
|
||||
function testHighLevel2() external pure returns (uint, uint, uint) {
|
||||
// Fails because the identity contract does not return enough data.
|
||||
return ReturnMoreData(address(4)).f(2);
|
||||
}
|
||||
function testLowLevel() external view returns (uint value) {
|
||||
(bool success, bytes memory ret) =
|
||||
address(4).staticcall(
|
||||
@ -18,8 +26,9 @@ contract C {
|
||||
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// EVMVersion: >=constantinople
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// testHighLevel() -> FAILURE
|
||||
// testHighLevel() -> true
|
||||
// testLowLevel() -> 0xc76596d400000000000000000000000000000000000000000000000000000000
|
||||
// testHighLevel2() -> FAILURE
|
||||
|
@ -28,6 +28,6 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// t() -> 9
|
||||
// gas irOptimized: 99186
|
||||
// gas legacy: 159083
|
||||
// gas legacyOptimized: 108916
|
||||
// gas irOptimized: 99064
|
||||
// gas legacy: 158955
|
||||
// gas legacyOptimized: 108788
|
||||
|
@ -29,8 +29,8 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 3, 7, 5
|
||||
// gas irOptimized: 127592
|
||||
// gas legacy: 151590
|
||||
// gas legacyOptimized: 125422
|
||||
// gas irOptimized: 127387
|
||||
// gas legacy: 151334
|
||||
// gas legacyOptimized: 125166
|
||||
// x() -> 7
|
||||
// y() -> 5
|
||||
|
@ -23,8 +23,8 @@ contract D {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 1
|
||||
// gas irOptimized: 77164
|
||||
// gas legacy: 115012
|
||||
// gas irOptimized: 77051
|
||||
// gas legacy: 114884
|
||||
// g() -> 5
|
||||
// gas irOptimized: 77231
|
||||
// gas legacy: 115558
|
||||
// gas irOptimized: 77106
|
||||
// gas legacy: 115430
|
||||
|
@ -25,5 +25,5 @@ contract B {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 42
|
||||
// gas irOptimized: 80945
|
||||
// gas legacy: 125609
|
||||
// gas irOptimized: 80813
|
||||
// gas legacy: 125481
|
||||
|
@ -25,6 +25,6 @@ contract B {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 42
|
||||
// gas irOptimized: 111913
|
||||
// gas legacy: 185181
|
||||
// gas legacyOptimized: 114726
|
||||
// gas irOptimized: 111781
|
||||
// gas legacy: 185053
|
||||
// gas legacyOptimized: 114598
|
||||
|
@ -22,6 +22,6 @@ contract A {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g(int256): -1 -> -1
|
||||
// gas legacy: 103622
|
||||
// gas legacy: 103494
|
||||
// g(int256): 10 -> 10
|
||||
// gas legacy: 103250
|
||||
// gas legacy: 103122
|
||||
|
@ -37,10 +37,10 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// convertParent() -> 1
|
||||
// gas irOptimized: 85640
|
||||
// gas irOptimized: 85524
|
||||
// convertSubA() -> 1, 2
|
||||
// gas irOptimized: 86395
|
||||
// gas legacy: 99303
|
||||
// gas irOptimized: 86155
|
||||
// gas legacy: 99047
|
||||
// convertSubB() -> 1, 3
|
||||
// gas irOptimized: 86338
|
||||
// gas legacy: 99237
|
||||
// gas irOptimized: 86098
|
||||
// gas legacy: 98981
|
||||
|
@ -22,6 +22,6 @@ contract A {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(), 10 ether -> 3007, 3008, 3009
|
||||
// gas irOptimized: 273275
|
||||
// gas legacy: 422885
|
||||
// gas legacyOptimized: 287856
|
||||
// gas irOptimized: 272947
|
||||
// gas legacy: 422501
|
||||
// gas legacyOptimized: 287472
|
||||
|
@ -27,5 +27,5 @@ contract D {
|
||||
// stateDecimal() -> right(42)
|
||||
// stateBytes() -> left(0x4200ef)
|
||||
// internalStateDecimal() -> 0x20
|
||||
// gas legacy: 101807
|
||||
// gas legacy: 101679
|
||||
// update(bool,uint256,bytes32): false, -23, left(0x2300ef) -> false, -23, left(0x2300ef)
|
||||
|
@ -42,4 +42,4 @@ contract C {
|
||||
// testRuntime() -> true
|
||||
// gas legacy: 101579
|
||||
// testCreation() -> true
|
||||
// gas legacy: 102137
|
||||
// gas legacy: 102009
|
||||
|
@ -26,4 +26,4 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 7
|
||||
// gas legacy: 102392
|
||||
// gas legacy: 102264
|
||||
|
@ -27,5 +27,5 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 9, 7
|
||||
// gas legacy: 130016
|
||||
// gas legacy: 129760
|
||||
// t2() -> 9
|
||||
|
@ -22,6 +22,6 @@ contract C {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 2, 6
|
||||
// gas irOptimized: 178953
|
||||
// gas legacy: 180890
|
||||
// gas legacyOptimized: 179609
|
||||
// gas irOptimized: 178835
|
||||
// gas legacy: 180762
|
||||
// gas legacyOptimized: 179481
|
||||
|
@ -36,12 +36,12 @@ contract D {
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x1 # This should work, next should throw #
|
||||
// gas legacy: 103844
|
||||
// gas legacy: 103716
|
||||
// fview() -> FAILURE
|
||||
// gas irOptimized: 98438627
|
||||
// gas legacy: 98438803
|
||||
// gas legacyOptimized: 98438596
|
||||
// gas irOptimized: 98438625
|
||||
// gas legacy: 98438801
|
||||
// gas legacyOptimized: 98438594
|
||||
// fpure() -> FAILURE
|
||||
// gas irOptimized: 98438627
|
||||
// gas legacy: 98438803
|
||||
// gas legacyOptimized: 98438597
|
||||
// gas irOptimized: 98438626
|
||||
// gas legacy: 98438801
|
||||
// gas legacyOptimized: 98438595
|
||||
|
Loading…
Reference in New Issue
Block a user