Merge pull request #7393 from ethereum/develop

Merge develop into 0.6.0
This commit is contained in:
chriseth 2019-09-10 12:27:02 +02:00 committed by GitHub
commit acf10ef60f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 310 additions and 77 deletions

View File

@ -22,7 +22,7 @@ defaults:
name: Build
command: |
set -ex
if [ "$CIRCLE_BRANCH" = release -o -n "$CIRCLE_TAG" ]; then echo -n > prerelease.txt; else date -u +"nightly.%Y.%-m.%-d" > prerelease.txt; fi
if [ "$CIRCLE_BRANCH" = release -o -n "$CIRCLE_TAG" -o -n "$FORCE_RELEASE" ]; then echo -n > prerelease.txt; else date -u +"nightly.%Y.%-m.%-d" > prerelease.txt; fi
echo -n "$CIRCLE_SHA1" > commit_hash.txt
mkdir -p build
cd build
@ -151,6 +151,11 @@ defaults:
requires:
- b_ubu
- workflow_ubuntu1904_release: &workflow_ubuntu1904_release
<<: *workflow_trigger_on_tags
requires:
- b_ubu_release
- workflow_ubuntu1904_codecov: &workflow_ubuntu1904_codecov
<<: *workflow_trigger_on_tags
requires:
@ -284,6 +289,11 @@ jobs:
- store_artifacts: *artifacts_solc
- persist_to_workspace: *artifacts_executables
b_ubu_release: &build_ubuntu1904_release
<<: *build_ubuntu1904
environment:
FORCE_RELEASE: ON
b_ubu18: &build_ubuntu1804
docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1804
@ -485,6 +495,9 @@ jobs:
t_ubu_soltest: &t_ubu_soltest
<<: *test_ubuntu1904
t_ubu_release_soltest: &t_ubu_release_soltest
<<: *t_ubu_soltest
t_ubu_cli: &t_ubu_cli
docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904
@ -498,6 +511,9 @@ jobs:
- store_test_results: *store_test_results
- store_artifacts: *artifacts_test_results
t_ubu_release_cli: &t_ubu_release_cli
<<: *t_ubu_cli
t_ubu_asan_cli:
<<: *t_ubu_cli
environment:
@ -617,6 +633,11 @@ workflows:
- t_ubu_cli: *workflow_ubuntu1904
- t_ubu_soltest: *workflow_ubuntu1904
# Ubuntu fake release build and tests
- b_ubu_release: *workflow_trigger_on_tags
- t_ubu_release_cli: *workflow_ubuntu1904_release
- t_ubu_release_soltest: *workflow_ubuntu1904_release
# ASan build and tests
- b_ubu_asan: *workflow_trigger_on_tags
- t_ubu_asan_constantinople: *workflow_ubuntu1904_asan

View File

@ -32,6 +32,7 @@ Compiler Features:
* ABI Output: Change sorting order of functions from selector to kind, name.
* Optimizer: Add rule that replaces the BYTE opcode by 0 if the first argument is larger than 31.
* Yul Optimizer: Take side-effect-freeness of user-defined functions into account.
* Yul Optimizer: Remove redundant mload/sload operations.
Bugfixes:

View File

@ -407,7 +407,7 @@ should:
* open on the same line as the declaration
* close on their own line at the same indentation level as the beginning of the
declaration.
* The opening brace should be proceeded by a single space.
* The opening brace should be preceded by a single space.
Yes::
@ -1141,4 +1141,4 @@ added looks like the one below::
It is recommended that Solidity contracts are fully annontated using `NatSpec <natspec>`_ for all public interfaces (everything in the ABI).
Please see the section about `NatSpec <natspec>`_ for a detailed explanation.
Please see the section about `NatSpec <natspec>`_ for a detailed explanation.

View File

@ -188,6 +188,12 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
case Instruction::BALANCE:
gas = GasCosts::balanceGas(m_evmVersion);
break;
case Instruction::CHAINID:
gas = runGas(Instruction::CHAINID);
break;
case Instruction::SELFBALANCE:
gas = runGas(Instruction::SELFBALANCE);
break;
default:
gas = runGas(_item.instruction());
break;

View File

@ -81,6 +81,8 @@ std::map<std::string, Instruction> const dev::eth::c_instructions =
{ "NUMBER", Instruction::NUMBER },
{ "DIFFICULTY", Instruction::DIFFICULTY },
{ "GASLIMIT", Instruction::GASLIMIT },
{ "CHAINID", Instruction::CHAINID },
{ "SELFBALANCE", Instruction::SELFBALANCE },
{ "POP", Instruction::POP },
{ "MLOAD", Instruction::MLOAD },
{ "MSTORE", Instruction::MSTORE },
@ -225,6 +227,8 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1, false, Tier::Base } },
{ Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1, false, Tier::Base } },
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1, false, Tier::Base } },
{ Instruction::CHAINID, { "CHAINID", 0, 0, 1, false, Tier::Base } },
{ Instruction::SELFBALANCE, { "SELFBALANCE", 0, 0, 1, false, Tier::Low } },
{ Instruction::POP, { "POP", 0, 1, 0, false, Tier::Base } },
{ Instruction::MLOAD, { "MLOAD", 0, 1, 1, true, Tier::VeryLow } },
{ Instruction::MSTORE, { "MSTORE", 0, 2, 0, true, Tier::VeryLow } },

View File

@ -90,6 +90,8 @@ enum class Instruction: uint8_t
NUMBER, ///< get the block's number
DIFFICULTY, ///< get the block's difficulty
GASLIMIT, ///< get the block's gas limit
CHAINID, ///< get the config's chainid param
SELFBALANCE, ///< get balance of the current account
POP = 0x50, ///< remove item from stack
MLOAD, ///< load word from memory

View File

@ -271,9 +271,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
Instruction::ADDRESS,
Instruction::CALLER,
Instruction::ORIGIN,
Instruction::COINBASE,
Instruction::CREATE,
Instruction::CREATE2
Instruction::COINBASE
})
{
u256 const mask = (u256(1) << 160) - 1;
@ -288,6 +286,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
false
});
}
return rules;
}
@ -565,8 +564,48 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart8(
return rules;
}
template <class Pattern>
std::vector<SimplificationRule<Pattern>> simplificationRuleListPart9(
Pattern,
Pattern,
Pattern,
Pattern W,
Pattern X,
Pattern Y,
Pattern Z
)
{
std::vector<SimplificationRule<Pattern>> rules;
u256 const mask = (u256(1) << 160) - 1;
// CREATE
rules.push_back({
{Instruction::AND, {{Instruction::CREATE, {W, X, Y}}, mask}},
[=]() -> Pattern { return {Instruction::CREATE, {W, X, Y}}; },
false
});
rules.push_back({
{Instruction::AND, {{mask, {Instruction::CREATE, {W, X, Y}}}}},
[=]() -> Pattern { return {Instruction::CREATE, {W, X, Y}}; },
false
});
// CREATE2
rules.push_back({
{Instruction::AND, {{Instruction::CREATE2, {W, X, Y, Z}}, mask}},
[=]() -> Pattern { return {Instruction::CREATE2, {W, X, Y, Z}}; },
false
});
rules.push_back({
{Instruction::AND, {{mask, {Instruction::CREATE2, {W, X, Y, Z}}}}},
[=]() -> Pattern { return {Instruction::CREATE2, {W, X, Y, Z}}; },
false
});
return rules;
}
/// @returns a list of simplification rules given certain match placeholders.
/// A, B and C should represent constants, X and Y arbitrary expressions.
/// A, B and C should represent constants, W, X, Y, and Z arbitrary expressions.
/// The simplifications should never change the order of evaluation of
/// arbitrary operations.
template <class Pattern>
@ -574,19 +613,22 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
Pattern A,
Pattern B,
Pattern C,
Pattern W,
Pattern X,
Pattern Y
Pattern Y,
Pattern Z
)
{
std::vector<SimplificationRule<Pattern>> rules;
rules += simplificationRuleListPart1(A, B, C, X, Y);
rules += simplificationRuleListPart2(A, B, C, X, Y);
rules += simplificationRuleListPart3(A, B, C, X, Y);
rules += simplificationRuleListPart4(A, B, C, X, Y);
rules += simplificationRuleListPart5(A, B, C, X, Y);
rules += simplificationRuleListPart6(A, B, C, X, Y);
rules += simplificationRuleListPart7(A, B, C, X, Y);
rules += simplificationRuleListPart8(A, B, C, X, Y);
rules += simplificationRuleListPart1(A, B, C, W, X);
rules += simplificationRuleListPart2(A, B, C, W, X);
rules += simplificationRuleListPart3(A, B, C, W, X);
rules += simplificationRuleListPart4(A, B, C, W, X);
rules += simplificationRuleListPart5(A, B, C, W, X);
rules += simplificationRuleListPart6(A, B, C, W, X);
rules += simplificationRuleListPart7(A, B, C, W, X);
rules += simplificationRuleListPart8(A, B, C, W, X);
rules += simplificationRuleListPart9(A, B, C, W, X, Y, Z);
return rules;
}

View File

@ -172,6 +172,7 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
case Instruction::PC:
case Instruction::MSIZE: // depends on previous writes and reads, not only on content
case Instruction::BALANCE: // depends on previous calls
case Instruction::SELFBALANCE: // depends on previous calls
case Instruction::EXTCODESIZE:
case Instruction::EXTCODEHASH:
case Instruction::RETURNDATACOPY: // depends on previous calls
@ -194,6 +195,7 @@ bool SemanticInformation::movable(Instruction _instruction)
{
case Instruction::KECCAK256:
case Instruction::BALANCE:
case Instruction::SELFBALANCE:
case Instruction::EXTCODESIZE:
case Instruction::EXTCODEHASH:
case Instruction::RETURNDATASIZE:
@ -265,6 +267,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
switch (_instruction)
{
case Instruction::ADDRESS:
case Instruction::SELFBALANCE:
case Instruction::BALANCE:
case Instruction::ORIGIN:
case Instruction::CALLER:

View File

@ -83,15 +83,19 @@ Rules::Rules()
Pattern B(Push);
Pattern C(Push);
// Anything.
Pattern W;
Pattern X;
Pattern Y;
Pattern Z;
A.setMatchGroup(1, m_matchGroups);
B.setMatchGroup(2, m_matchGroups);
C.setMatchGroup(3, m_matchGroups);
X.setMatchGroup(4, m_matchGroups);
Y.setMatchGroup(5, m_matchGroups);
W.setMatchGroup(4, m_matchGroups);
X.setMatchGroup(5, m_matchGroups);
Y.setMatchGroup(6, m_matchGroups);
Z.setMatchGroup(7, m_matchGroups);
addRules(simplificationRuleList(A, B, C, X, Y));
addRules(simplificationRuleList(A, B, C, W, X, Y, Z));
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
}

View File

@ -40,6 +40,10 @@ bool EVMVersion::hasOpcode(Instruction _opcode) const
return hasCreate2();
case Instruction::EXTCODEHASH:
return hasExtCodeHash();
case Instruction::CHAINID:
return hasChainID();
case Instruction::SELFBALANCE:
return hasSelfBalance();
default:
return true;
}

View File

@ -84,6 +84,8 @@ public:
bool hasBitwiseShifting() const { return *this >= constantinople(); }
bool hasCreate2() const { return *this >= constantinople(); }
bool hasExtCodeHash() const { return *this >= constantinople(); }
bool hasChainID() const { return *this >= istanbul(); }
bool hasSelfBalance() const { return *this >= istanbul(); }
bool hasOpcode(dev::eth::Instruction _opcode) const;

View File

@ -732,6 +732,14 @@ void AsmAnalyzer::warnOnInstructions(dev::eth::Instruction _instr, SourceLocatio
{
errorForVM("only available for Constantinople-compatible");
}
else if (_instr == dev::eth::Instruction::CHAINID && !m_evmVersion.hasChainID())
{
errorForVM("only available for Istanbul-compatible");
}
else if (_instr == dev::eth::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
{
errorForVM("only available for Istanbul-compatible");
}
else if (
_instr == dev::eth::Instruction::JUMP ||
_instr == dev::eth::Instruction::JUMPI ||

View File

@ -297,7 +297,7 @@ void DataFlowAnalyzer::clearValues(set<YulString> _variables)
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
{
SideEffectsCollector sideEffects(m_dialect, _block);
SideEffectsCollector sideEffects(m_dialect, _block, &m_functionSideEffects);
if (sideEffects.invalidatesStorage())
m_storage.clear();
if (sideEffects.invalidatesMemory())
@ -306,7 +306,7 @@ void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Expression const& _expr)
{
SideEffectsCollector sideEffects(m_dialect, _expr);
SideEffectsCollector sideEffects(m_dialect, _expr, &m_functionSideEffects);
if (sideEffects.invalidatesStorage())
m_storage.clear();
if (sideEffects.invalidatesMemory())

View File

@ -23,6 +23,8 @@
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/SideEffects.h>
#include <libyul/AsmData.h>
using namespace std;
@ -32,35 +34,53 @@ using namespace yul;
void LoadResolver::run(Dialect const& _dialect, Block& _ast)
{
bool containsMSize = MSizeFinder::containsMSize(_dialect, _ast);
LoadResolver{_dialect, !containsMSize}(_ast);
LoadResolver{
_dialect,
SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast)),
!containsMSize
}(_ast);
}
void LoadResolver::visit(Expression& _e)
{
DataFlowAnalyzer::visit(_e);
if (!dynamic_cast<EVMDialect const*>(&m_dialect))
return;
if (_e.type() == typeid(FunctionCall))
{
FunctionCall const& funCall = boost::get<FunctionCall>(_e);
if (auto const* builtin = dynamic_cast<EVMDialect const&>(m_dialect).builtin(funCall.functionName.name))
if (!builtin->parameters.empty() && funCall.arguments.at(0).type() == typeid(Identifier))
{
YulString key = boost::get<Identifier>(funCall.arguments.at(0)).name;
if (
builtin->instruction == dev::eth::Instruction::SLOAD &&
m_storage.values.count(key)
)
{
_e = Identifier{locationOf(_e), m_storage.values[key]};
return;
}
else if (
m_optimizeMLoad &&
builtin->instruction == dev::eth::Instruction::MLOAD &&
m_memory.values.count(key)
)
{
_e = Identifier{locationOf(_e), m_memory.values[key]};
return;
}
}
if (builtin->instruction)
tryResolve(_e, *builtin->instruction, funCall.arguments);
}
else if (_e.type() == typeid(FunctionalInstruction))
{
FunctionalInstruction const& instruction = boost::get<FunctionalInstruction>(_e);
tryResolve(_e, instruction.instruction, instruction.arguments);
}
}
void LoadResolver::tryResolve(
Expression& _e,
dev::eth::Instruction _instruction,
vector<Expression> const& _arguments
)
{
if (_arguments.empty() || _arguments.at(0).type() != typeid(Identifier))
return;
YulString key = boost::get<Identifier>(_arguments.at(0)).name;
if (
_instruction == dev::eth::Instruction::SLOAD &&
m_storage.values.count(key)
)
_e = Identifier{locationOf(_e), m_storage.values[key]};
else if (
m_optimizeMLoad &&
_instruction == dev::eth::Instruction::MLOAD &&
m_memory.values.count(key)
)
_e = Identifier{locationOf(_e), m_memory.values[key]};
}

View File

@ -22,11 +22,13 @@
#pragma once
#include <libyul/optimiser/DataFlowAnalyzer.h>
#include <libevmasm/Instruction.h>
namespace yul
{
struct EVMDialect;
struct BuiltinFunctionForEVM;
/**
* Optimisation stage that replaces expressions of type ``sload(x)`` and ``mload(x)`` by the value
@ -39,11 +41,16 @@ struct EVMDialect;
class LoadResolver: public DataFlowAnalyzer
{
public:
/// Run the load resolver on the given complete AST.
static void run(Dialect const& _dialect, Block& _ast);
private:
LoadResolver(Dialect const& _dialect, bool _optimizeMLoad):
DataFlowAnalyzer(_dialect),
LoadResolver(
Dialect const& _dialect,
std::map<YulString, SideEffects> _functionSideEffects,
bool _optimizeMLoad
):
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)),
m_optimizeMLoad(_optimizeMLoad)
{}
@ -51,6 +58,12 @@ protected:
using ASTModifier::visit;
void visit(Expression& _e) override;
void tryResolve(
Expression& _e,
dev::eth::Instruction _instruction,
std::vector<Expression> const& _arguments
);
bool m_optimizeMLoad = false;
};

View File

@ -51,8 +51,12 @@ SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Statement co
visit(_statement);
}
SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Block const& _ast):
SideEffectsCollector(_dialect)
SideEffectsCollector::SideEffectsCollector(
Dialect const& _dialect,
Block const& _ast,
map<YulString, SideEffects> const* _functionSideEffects
):
SideEffectsCollector(_dialect, _functionSideEffects)
{
operator()(_ast);
}

View File

@ -47,7 +47,11 @@ public:
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
);
SideEffectsCollector(Dialect const& _dialect, Statement const& _statement);
SideEffectsCollector(Dialect const& _dialect, Block const& _ast);
SideEffectsCollector(
Dialect const& _dialect,
Block const& _ast,
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
);
using ASTWalker::operator();
void operator()(FunctionalInstruction const& _functionalInstruction) override;

View File

@ -97,15 +97,19 @@ SimplificationRules::SimplificationRules()
Pattern B(PatternKind::Constant);
Pattern C(PatternKind::Constant);
// Anything.
Pattern W;
Pattern X;
Pattern Y;
Pattern Z;
A.setMatchGroup(1, m_matchGroups);
B.setMatchGroup(2, m_matchGroups);
C.setMatchGroup(3, m_matchGroups);
X.setMatchGroup(4, m_matchGroups);
Y.setMatchGroup(5, m_matchGroups);
W.setMatchGroup(4, m_matchGroups);
X.setMatchGroup(5, m_matchGroups);
Y.setMatchGroup(6, m_matchGroups);
Z.setMatchGroup(7, m_matchGroups);
addRules(simplificationRuleList(A, B, C, X, Y));
addRules(simplificationRuleList(A, B, C, W, X, Y, Z));
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
}

View File

@ -45,6 +45,7 @@
#include <libyul/optimiser/StructuralSimplifier.h>
#include <libyul/optimiser/RedundantAssignEliminator.h>
#include <libyul/optimiser/VarNameCleaner.h>
#include <libyul/optimiser/LoadResolver.h>
#include <libyul/optimiser/Metrics.h>
#include <libyul/backends/evm/ConstantOptimiser.h>
#include <libyul/AsmAnalysis.h>
@ -118,6 +119,7 @@ void OptimiserSuite::run(
ExpressionSimplifier::run(_dialect, ast);
CommonSubexpressionEliminator::run(_dialect, ast);
LoadResolver::run(_dialect, ast);
}
{
@ -132,6 +134,7 @@ void OptimiserSuite::run(
{
// simplify again
LoadResolver::run(_dialect, ast);
CommonSubexpressionEliminator::run(_dialect, ast);
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
}
@ -161,6 +164,7 @@ void OptimiserSuite::run(
RedundantAssignEliminator::run(_dialect, ast);
RedundantAssignEliminator::run(_dialect, ast);
CommonSubexpressionEliminator::run(_dialect, ast);
LoadResolver::run(_dialect, ast);
}
{
@ -176,6 +180,7 @@ void OptimiserSuite::run(
SSATransform::run(ast, dispenser);
RedundantAssignEliminator::run(_dialect, ast);
RedundantAssignEliminator::run(_dialect, ast);
LoadResolver::run(_dialect, ast);
ExpressionSimplifier::run(_dialect, ast);
StructuralSimplifier{_dialect}(ast);
BlockFlattener{}(ast);

View File

@ -90,9 +90,12 @@ case $(uname -s) in
10.14)
echo "Installing solidity dependencies on macOS 10.14 Mojave."
;;
10.15)
echo "Installing solidity dependencies on macOS 10.15 Catalina."
;;
*)
echo "Unsupported macOS version."
echo "We only support Mavericks, Yosemite, El Capitan, Sierra, High Sierra and Mojave."
echo "We only support Mavericks, Yosemite, El Capitan, Sierra, High Sierra, Mojave, and Catalina."
exit 1
;;
esac

View File

@ -299,6 +299,8 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
"(NUMBER)",
"(DIFFICULTY)",
"(GASLIMIT)",
"(CHAINID)",
"(SELFBALANCE)",
"(POP 0)",
"(MLOAD 0)",
"(MSTORE 0 0)",

View File

@ -9,6 +9,9 @@ contract C {
function g(bool _value) public pure {
require(_value, "Value is false.");
}
function h() public pure returns (uint) {
assert(false);
}
}
// ====
// EVMVersion: >homestead
@ -17,3 +20,4 @@ contract C {
// e() -> FAILURE, hex"08c379a0", 0x20, 19, "Transaction failed."
// f(bool): false -> FAILURE, hex"08c379a0", 0x20, 0
// g(bool): false -> FAILURE, hex"08c379a0", 0x20, 15, "Value is false."
// h() -> FAILURE

View File

@ -126,8 +126,11 @@ string TestFunctionCall::format(
{
boost::optional<ParameterList> abiParams;
if (isFailure && !output.empty())
abiParams = boost::make_optional(ContractABIUtils::failureParameters(output));
if (isFailure)
{
if (!output.empty())
abiParams = boost::make_optional(ContractABIUtils::failureParameters(output));
}
else
abiParams = ContractABIUtils::parametersFromJsonOutputs(
_errorReporter,

View File

@ -0,0 +1,12 @@
{
let a := and(create2(0, 0, 0x20, 0), 0xffffffffffffffffffffffffffffffffffffffff)
let b := and(0xffffffffffffffffffffffffffffffffffffffff, create2(0, 0, 0x20, 0))
}
// ====
// step: expressionSimplifier
// EVMVersion: >=constantinople
// ----
// {
// let a := create2(0, 0, 0x20, 0)
// let b := create2(0, 0, 0x20, 0)
// }

View File

@ -0,0 +1,11 @@
{
let a := and(create(0, 0, 0x20), 0xffffffffffffffffffffffffffffffffffffffff)
let b := and(0xffffffffffffffffffffffffffffffffffffffff, create(0, 0, 0x20))
}
// ====
// step: expressionSimplifier
// ----
// {
// let a := create(0, 0, 0x20)
// let b := create(0, 0, 0x20)
// }

View File

@ -21,11 +21,10 @@
// ----
// {
// {
// let _1 := 0x40
// mstore(_1, add(mload(_1), 0x20))
// let p := mload(_1)
// mstore(_1, add(p, _1))
// mstore(add(p, 96), 2)
// mstore(_1, 0x20)
// let _1 := mload(0x40)
// mstore(0x40, add(_1, 0x20))
// mstore(0x40, add(_1, 96))
// mstore(add(_1, 128), 2)
// mstore(0x40, 0x20)
// }
// }

View File

@ -10,6 +10,6 @@
// {
// sstore(4, 5)
// sstore(4, 3)
// sstore(8, sload(4))
// sstore(8, 3)
// }
// }

View File

@ -0,0 +1,18 @@
{
sstore(0, 123213)
for {let x := 0 let y} lt(x, sload(0)) {
x := add(x, 1)} {y := add(x, y)
}
}
// ====
// step: loadResolver
// ----
// {
// let _1 := 123213
// let _2 := 0
// sstore(_2, _1)
// let x := _2
// let y
// for { } lt(x, _1) { x := add(x, 1) }
// { y := add(x, y) }
// }

View File

@ -31,5 +31,5 @@
// mstore8(calldataload(_5), 4)
// sstore(_5, mload(_2))
// mstore(_2, _17)
// sstore(_5, mload(_2))
// sstore(_5, _17)
// }

View File

@ -0,0 +1,28 @@
{
function stores() { mstore(0, 1) }
function reads() { sstore(9, mload(7)) }
mstore(2, 9)
reads()
sstore(0, mload(2))
stores()
sstore(0, mload(2))
}
// ====
// step: loadResolver
// ----
// {
// function stores()
// { mstore(0, 1) }
// function reads()
// { sstore(9, mload(7)) }
// let _6 := 9
// let _7 := 2
// mstore(_7, _6)
// reads()
// let _9 := _6
// let _10 := 0
// sstore(_10, _9)
// stores()
// sstore(_10, mload(_7))
// }

View File

@ -63,8 +63,6 @@ void ProtoConverter::visitType(
std::string varName, paramName;
createDeclAndParamList(_type, _dataType, varName, paramName);
addCheckedVarDef(_dataType, varName, paramName, _value);
// Update right padding of type
m_isLastParamRightPadded = isDataTypeBytesOrString(_dataType);
}
void ProtoConverter::appendVarDeclToOutput(
@ -451,6 +449,8 @@ void ProtoConverter::visit(DynamicByteArrayType const& _x)
isBytes
)
);
// Update right padding of type
m_isLastDynParamRightPadded = true;
}
// TODO: Implement struct visitor
@ -658,23 +658,23 @@ void ProtoConverter::visit(ArrayType const& _x)
{
case ArrayType::kInty:
baseType = getIntTypeAsString(_x.inty());
m_isLastParamRightPadded = false;
m_isLastDynParamRightPadded = false;
break;
case ArrayType::kByty:
baseType = getFixedByteTypeAsString(_x.byty());
m_isLastParamRightPadded = false;
m_isLastDynParamRightPadded = false;
break;
case ArrayType::kAdty:
baseType = getAddressTypeAsString(_x.adty());
m_isLastParamRightPadded = false;
m_isLastDynParamRightPadded = false;
break;
case ArrayType::kBoolty:
baseType = getBoolTypeAsString();
m_isLastParamRightPadded = false;
m_isLastDynParamRightPadded = false;
break;
case ArrayType::kDynbytesty:
baseType = bytesArrayTypeAsString(_x.dynbytesty());
m_isLastParamRightPadded = true;
m_isLastDynParamRightPadded = true;
break;
case ArrayType::kStty:
case ArrayType::BASE_TYPE_ONEOF_NOT_SET:
@ -861,7 +861,7 @@ void ProtoConverter::visit(TestFunction const& _x)
)")
("parameterNames", dev::suffixedVariableNameList(s_varNamePrefix, 0, m_varCounter))
("invalidLengthFuzz", std::to_string(_x.invalid_encoding_length()))
("isRightPadded", isLastParamRightPadded() ? "true" : "false")
("isRightPadded", isLastDynParamRightPadded() ? "true" : "false")
("atLeastOneVar", m_varCounter > 0)
.render();
}

View File

@ -103,7 +103,7 @@ public:
m_counter(0),
m_varCounter(0),
m_returnValue(1),
m_isLastParamRightPadded(false)
m_isLastDynParamRightPadded(false)
{}
ProtoConverter(ProtoConverter const&) = delete;
@ -274,9 +274,9 @@ private:
return ((isValueType(_dataType) || m_isStateVar) ? "" : "memory");
}
bool isLastParamRightPadded()
bool isLastDynParamRightPadded()
{
return m_isLastParamRightPadded;
return m_isLastDynParamRightPadded;
}
// Static declarations
@ -466,10 +466,10 @@ private:
unsigned m_varCounter;
/// Monotonically increasing return value for error reporting
unsigned m_returnValue;
/// Flag that indicates if last parameter passed to a function call
/// is of a type that is going to be right padded by the ABI
/// encoder.
bool m_isLastParamRightPadded;
/// Flag that indicates if last dynamically encoded parameter
/// passed to a function call is of a type that is going to be
/// right padded by the ABI encoder.
bool m_isLastDynParamRightPadded;
static unsigned constexpr s_maxArrayLength = 4;
static unsigned constexpr s_maxArrayDimensions = 4;
static unsigned constexpr s_maxDynArrayLength = 256;

View File

@ -180,6 +180,8 @@ u256 EVMInstructionInterpreter::eval(
return m_state.address;
case Instruction::BALANCE:
return m_state.balance;
case Instruction::SELFBALANCE:
return m_state.selfbalance;
case Instruction::ORIGIN:
return m_state.origin;
case Instruction::CALLER:
@ -208,6 +210,8 @@ u256 EVMInstructionInterpreter::eval(
return 0;
case Instruction::GASPRICE:
return m_state.gasprice;
case Instruction::CHAINID:
return m_state.chainid;
case Instruction::EXTCODESIZE:
return u256(keccak256(h256(arg[0]))) & 0xffffff;
case Instruction::EXTCODEHASH:

View File

@ -70,6 +70,7 @@ struct InterpreterState
std::map<dev::h256, dev::h256> storage;
dev::u160 address = 0x11111111;
dev::u256 balance = 0x22222222;
dev::u256 selfbalance = 0x22223333;
dev::u160 origin = 0x33333333;
dev::u160 caller = 0x44444444;
dev::u256 callvalue = 0x55555555;
@ -81,6 +82,7 @@ struct InterpreterState
dev::u256 blockNumber = 1024;
dev::u256 difficulty = 0x9999999;
dev::u256 gaslimit = 4000000;
dev::u256 chainid = 0x01;
/// Log of changes / effects. Sholud be structured data in the future.
std::vector<std::string> trace;
/// This is actually an input parameter that more or less limits the runtime.