Use STATICCALL for pure function calls if EVM version supports it and 0.5.0 is activated.

This commit is contained in:
chriseth 2017-09-26 15:27:03 +02:00 committed by Alex Beregszaszi
parent 0df4c64884
commit b467116ea8
3 changed files with 13 additions and 3 deletions

View File

@ -2,8 +2,9 @@
Features: Features:
* C99/C++-style scoping rules (instead of JavaScript function scoping) take effect as experimental v0.5.0 feature. * C99/C++-style scoping rules (instead of JavaScript function scoping) take effect as experimental v0.5.0 feature.
* Code Generator: Assert that ``k != 0`` for ``molmod(a, b, k)`` and ``addmod(a, b, k)`` as experimental 0.5.0 feature. * Code Generator: Assert that ``k != 0`` for ``mulmod(a, b, k)`` and ``addmod(a, b, k)`` as experimental 0.5.0 feature.
* Code Generator: Do not retain any gas in calls (except if EVM version is set to homestead). * Code Generator: Do not retain any gas in calls (except if EVM version is set to homestead).
* Code Generator: Use ``STATICCALL`` opcode for calling ``view`` and ``pure`` functions as experimenal 0.5.0 feature.
* Interface: Provide ability to select target EVM version (homestead or byzantium, with byzantium being the default). * Interface: Provide ability to select target EVM version (homestead or byzantium, with byzantium being the default).
* Standard JSON: Reject badly formatted invalid JSON inputs. * Standard JSON: Reject badly formatted invalid JSON inputs.
* Type Checker: Disallow uninitialized storage pointers as experimental 0.5.0 feature. * Type Checker: Disallow uninitialized storage pointers as experimental 0.5.0 feature.

View File

@ -29,8 +29,8 @@ namespace solidity
enum class ExperimentalFeature enum class ExperimentalFeature
{ {
SMTChecker,
ABIEncoderV2, // new ABI encoder that makes use of JULIA ABIEncoderV2, // new ABI encoder that makes use of JULIA
SMTChecker,
V050, // v0.5.0 breaking changes V050, // v0.5.0 breaking changes
Test, Test,
TestOnlyAnalysis TestOnlyAnalysis
@ -45,8 +45,8 @@ static const std::map<ExperimentalFeature, bool> ExperimentalFeatureOnlyAnalysis
static const std::map<std::string, ExperimentalFeature> ExperimentalFeatureNames = static const std::map<std::string, ExperimentalFeature> ExperimentalFeatureNames =
{ {
{ "SMTChecker", ExperimentalFeature::SMTChecker },
{ "ABIEncoderV2", ExperimentalFeature::ABIEncoderV2 }, { "ABIEncoderV2", ExperimentalFeature::ABIEncoderV2 },
{ "SMTChecker", ExperimentalFeature::SMTChecker },
{ "v0.5.0", ExperimentalFeature::V050 }, { "v0.5.0", ExperimentalFeature::V050 },
{ "__test", ExperimentalFeature::Test }, { "__test", ExperimentalFeature::Test },
{ "__testOnlyAnalysis", ExperimentalFeature::TestOnlyAnalysis }, { "__testOnlyAnalysis", ExperimentalFeature::TestOnlyAnalysis },

View File

@ -1610,6 +1610,10 @@ void ExpressionCompiler::appendExternalFunctionCall(
bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall; bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall;
bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode; bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode;
bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall;
bool useStaticCall =
_functionType.stateMutability() <= StateMutability::View &&
m_context.experimentalFeatureActive(ExperimentalFeature::V050) &&
m_context.evmVersion().hasStaticCall();
unsigned retSize = 0; unsigned retSize = 0;
if (returnSuccessCondition) if (returnSuccessCondition)
@ -1738,6 +1742,8 @@ void ExpressionCompiler::appendExternalFunctionCall(
// [value,] addr, gas (stack top) // [value,] addr, gas (stack top)
if (isDelegateCall) if (isDelegateCall)
solAssert(!_functionType.valueSet(), "Value set for delegatecall"); solAssert(!_functionType.valueSet(), "Value set for delegatecall");
else if (useStaticCall)
solAssert(!_functionType.valueSet(), "Value set for staticcall");
else if (_functionType.valueSet()) else if (_functionType.valueSet())
m_context << dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos)); m_context << dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos));
else else
@ -1769,10 +1775,13 @@ void ExpressionCompiler::appendExternalFunctionCall(
gasNeededByCaller += eth::GasCosts::callNewAccountGas; // we never know gasNeededByCaller += eth::GasCosts::callNewAccountGas; // we never know
m_context << gasNeededByCaller << Instruction::GAS << Instruction::SUB; m_context << gasNeededByCaller << Instruction::GAS << Instruction::SUB;
} }
// Order is important here, STATICCALL might overlap with DELEGATECALL.
if (isDelegateCall) if (isDelegateCall)
m_context << Instruction::DELEGATECALL; m_context << Instruction::DELEGATECALL;
else if (isCallCode) else if (isCallCode)
m_context << Instruction::CALLCODE; m_context << Instruction::CALLCODE;
else if (useStaticCall)
m_context << Instruction::STATICCALL;
else else
m_context << Instruction::CALL; m_context << Instruction::CALL;