aboutsummaryrefslogtreecommitdiffstats
path: root/libevmasm
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-03-01 19:06:36 +0800
committerchriseth <chris@ethereum.org>2018-03-05 18:36:33 +0800
commit6ec4517929e8c0eca022f4771ba217db5d80beed (patch)
treeece2e275ee9bb190d33e05cef5cc549b21abf8e3 /libevmasm
parent5a54cd5c708227ad6982b06de7b799ece5065917 (diff)
downloaddexon-solidity-6ec4517929e8c0eca022f4771ba217db5d80beed.tar
dexon-solidity-6ec4517929e8c0eca022f4771ba217db5d80beed.tar.gz
dexon-solidity-6ec4517929e8c0eca022f4771ba217db5d80beed.tar.bz2
dexon-solidity-6ec4517929e8c0eca022f4771ba217db5d80beed.tar.lz
dexon-solidity-6ec4517929e8c0eca022f4771ba217db5d80beed.tar.xz
dexon-solidity-6ec4517929e8c0eca022f4771ba217db5d80beed.tar.zst
dexon-solidity-6ec4517929e8c0eca022f4771ba217db5d80beed.zip
Use EVM version in gas meter and optimizer.
Diffstat (limited to 'libevmasm')
-rw-r--r--libevmasm/Assembly.cpp4
-rw-r--r--libevmasm/Assembly.h5
-rw-r--r--libevmasm/ConstantOptimiser.cpp11
-rw-r--r--libevmasm/ConstantOptimiser.h4
-rw-r--r--libevmasm/GasMeter.cpp32
-rw-r--r--libevmasm/GasMeter.h44
-rw-r--r--libevmasm/PathGasMeter.cpp6
-rw-r--r--libevmasm/PathGasMeter.h8
8 files changed, 83 insertions, 31 deletions
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index b9fedf26..bd4ebf59 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -353,7 +353,7 @@ void Assembly::injectStart(AssemblyItem const& _i)
m_items.insert(m_items.begin(), _i);
}
-Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs)
+Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation, size_t _runs)
{
OptimiserSettings settings;
settings.isCreation = _isCreation;
@@ -365,6 +365,7 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs)
settings.runCSE = true;
settings.runConstantOptimiser = true;
}
+ settings.evmVersion = _evmVersion;
settings.expectedExecutionsPerDeployment = _runs;
optimise(settings);
return *this;
@@ -482,6 +483,7 @@ map<u256, u256> Assembly::optimiseInternal(
ConstantOptimisationMethod::optimiseConstants(
_settings.isCreation,
_settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment,
+ _settings.evmVersion,
*this,
m_items
);
diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h
index 885192e4..367c6daa 100644
--- a/libevmasm/Assembly.h
+++ b/libevmasm/Assembly.h
@@ -23,6 +23,8 @@
#include <libevmasm/LinkerObject.h>
#include <libevmasm/Exceptions.h>
+#include <libsolidity/interface/EVMVersion.h>
+
#include <libdevcore/Common.h>
#include <libdevcore/Assertions.h>
#include <libdevcore/SHA3.h>
@@ -107,6 +109,7 @@ public:
bool runDeduplicate = false;
bool runCSE = false;
bool runConstantOptimiser = false;
+ solidity::EVMVersion evmVersion;
/// This specifies an estimate on how often each opcode in this assembly will be executed,
/// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage.
size_t expectedExecutionsPerDeployment = 200;
@@ -120,7 +123,7 @@ public:
/// @a _runs specifes an estimate on how often each opcode in this assembly will be executed,
/// i.e. use a small value to optimise for size and a large value to optimise for runtime.
/// If @a _enable is not set, will perform some simple peephole optimizations.
- Assembly& optimise(bool _enable, bool _isCreation = true, size_t _runs = 200);
+ Assembly& optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation = true, size_t _runs = 200);
/// Create a text representation of the assembly.
std::string assemblyString(
diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp
index 2efd2dc9..d0b6843c 100644
--- a/libevmasm/ConstantOptimiser.cpp
+++ b/libevmasm/ConstantOptimiser.cpp
@@ -29,6 +29,7 @@ using namespace dev::eth;
unsigned ConstantOptimisationMethod::optimiseConstants(
bool _isCreation,
size_t _runs,
+ solidity::EVMVersion _evmVersion,
Assembly& _assembly,
AssemblyItems& _items
)
@@ -48,6 +49,7 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
params.multiplicity = it.second;
params.isCreation = _isCreation;
params.runs = _runs;
+ params.evmVersion = _evmVersion;
LiteralMethod lit(params, item.data());
bigint literalGas = lit.gasNeeded();
CodeCopyMethod copy(params, item.data());
@@ -80,7 +82,12 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
if (item.type() == Push)
gas += GasMeter::runGas(Instruction::PUSH1);
else if (item.type() == Operation)
- gas += GasMeter::runGas(item.instruction());
+ {
+ if (item.instruction() == Instruction::EXP)
+ gas += GasCosts::expGas;
+ else
+ gas += GasMeter::runGas(item.instruction());
+ }
return gas;
}
@@ -286,7 +293,7 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
{
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
return combineGas(
- simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas),
+ simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)),
// Data gas for routine: Some bytes are zero, but we ignore them.
bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
0
diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h
index c450b0b4..9b60b26b 100644
--- a/libevmasm/ConstantOptimiser.h
+++ b/libevmasm/ConstantOptimiser.h
@@ -23,6 +23,8 @@
#include <libevmasm/Exceptions.h>
+#include <libsolidity/interface/EVMVersion.h>
+
#include <libdevcore/Assertions.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h>
@@ -50,6 +52,7 @@ public:
static unsigned optimiseConstants(
bool _isCreation,
size_t _runs,
+ solidity::EVMVersion _evmVersion,
Assembly& _assembly,
AssemblyItems& _items
);
@@ -59,6 +62,7 @@ public:
bool isCreation; ///< Whether this is called during contract creation or runtime.
size_t runs; ///< Estimated number of calls per opcode oven the lifetime of the contract.
size_t multiplicity; ///< Number of times the constant appears in the code.
+ solidity::EVMVersion evmVersion; ///< Version of the EVM
};
explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value):
diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp
index 543f1cbc..caa06fc0 100644
--- a/libevmasm/GasMeter.cpp
+++ b/libevmasm/GasMeter.cpp
@@ -61,7 +61,6 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
case Operation:
{
ExpressionClasses& classes = m_state->expressionClasses();
- gas = runGas(_item.instruction());
switch (_item.instruction())
{
case Instruction::SSTORE:
@@ -72,26 +71,29 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
m_state->storageContent().count(slot) &&
classes.knownNonZero(m_state->storageContent().at(slot))
))
- gas += GasCosts::sstoreResetGas; //@todo take refunds into account
+ gas = GasCosts::sstoreResetGas; //@todo take refunds into account
else
- gas += GasCosts::sstoreSetGas;
+ gas = GasCosts::sstoreSetGas;
break;
}
case Instruction::SLOAD:
- gas += GasCosts::sloadGas;
+ gas = GasCosts::sloadGas(m_evmVersion);
break;
case Instruction::RETURN:
case Instruction::REVERT:
+ gas = runGas(_item.instruction());
gas += memoryGas(0, -1);
break;
case Instruction::MLOAD:
case Instruction::MSTORE:
+ gas = runGas(_item.instruction());
gas += memoryGas(classes.find(Instruction::ADD, {
m_state->relativeStackElement(0),
classes.find(AssemblyItem(32))
}));
break;
case Instruction::MSTORE8:
+ gas = runGas(_item.instruction());
gas += memoryGas(classes.find(Instruction::ADD, {
m_state->relativeStackElement(0),
classes.find(AssemblyItem(1))
@@ -105,10 +107,15 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
case Instruction::CALLDATACOPY:
case Instruction::CODECOPY:
case Instruction::RETURNDATACOPY:
+ gas = runGas(_item.instruction());
gas += memoryGas(0, -2);
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-2));
break;
+ case Instruction::EXTCODESIZE:
+ gas = GasCosts::extCodeGas(m_evmVersion);
+ break;
case Instruction::EXTCODECOPY:
+ gas = GasCosts::extCodeGas(m_evmVersion);
gas += memoryGas(-1, -3);
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-3));
break;
@@ -137,7 +144,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
gas = GasConsumption::infinite();
else
{
- gas = GasCosts::callGas;
+ gas = GasCosts::callGas(m_evmVersion);
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0)))
gas += (*value);
else
@@ -155,7 +162,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
break;
}
case Instruction::SELFDESTRUCT:
- gas = GasCosts::selfdestructGas;
+ gas = GasCosts::selfdestructGas(m_evmVersion);
gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
break;
case Instruction::CREATE:
@@ -172,11 +179,15 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
case Instruction::EXP:
gas = GasCosts::expGas;
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
- gas += GasCosts::expByteGas * (32 - (h256(*value).firstBitSet() / 8));
+ gas += GasCosts::expByteGas(m_evmVersion) * (32 - (h256(*value).firstBitSet() / 8));
else
- gas += GasCosts::expByteGas * 32;
+ gas += GasCosts::expByteGas(m_evmVersion) * 32;
+ break;
+ case Instruction::BALANCE:
+ gas = GasCosts::balanceGas(m_evmVersion);
break;
default:
+ gas = runGas(_item.instruction());
break;
}
break;
@@ -241,12 +252,9 @@ unsigned GasMeter::runGas(Instruction _instruction)
case Tier::Mid: return GasCosts::tier4Gas;
case Tier::High: return GasCosts::tier5Gas;
case Tier::Ext: return GasCosts::tier6Gas;
- case Tier::Special: return GasCosts::tier7Gas;
- case Tier::ExtCode: return GasCosts::extCodeGas;
- case Tier::Balance: return GasCosts::balanceGas;
default: break;
}
- assertThrow(false, OptimizerException, "Invalid gas tier.");
+ assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction).name);
return 0;
}
diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h
index 2c3ecf5a..b131802f 100644
--- a/libevmasm/GasMeter.h
+++ b/libevmasm/GasMeter.h
@@ -21,11 +21,14 @@
#pragma once
-#include <ostream>
-#include <tuple>
#include <libevmasm/ExpressionClasses.h>
#include <libevmasm/AssemblyItem.h>
+#include <libsolidity/interface/EVMVersion.h>
+
+#include <ostream>
+#include <tuple>
+
namespace dev
{
namespace eth
@@ -44,13 +47,25 @@ namespace GasCosts
static unsigned const tier5Gas = 10;
static unsigned const tier6Gas = 20;
static unsigned const tier7Gas = 0;
- static unsigned const extCodeGas = 700;
- static unsigned const balanceGas = 400;
+ inline unsigned extCodeGas(EVMVersion _evmVersion)
+ {
+ return _evmVersion >= EVMVersion::tangerineWhistle() ? 700 : 20;
+ }
+ inline unsigned balanceGas(EVMVersion _evmVersion)
+ {
+ return _evmVersion >= EVMVersion::tangerineWhistle() ? 400 : 20;
+ }
static unsigned const expGas = 10;
- static unsigned const expByteGas = 50;
+ inline unsigned expByteGas(EVMVersion _evmVersion)
+ {
+ return _evmVersion >= EVMVersion::spuriousDragon() ? 50 : 10;
+ }
static unsigned const keccak256Gas = 30;
static unsigned const keccak256WordGas = 6;
- static unsigned const sloadGas = 200;
+ inline unsigned sloadGas(EVMVersion _evmVersion)
+ {
+ return _evmVersion >= EVMVersion::tangerineWhistle() ? 200 : 50;
+ }
static unsigned const sstoreSetGas = 20000;
static unsigned const sstoreResetGas = 5000;
static unsigned const sstoreRefundGas = 15000;
@@ -59,11 +74,17 @@ namespace GasCosts
static unsigned const logDataGas = 8;
static unsigned const logTopicGas = 375;
static unsigned const createGas = 32000;
- static unsigned const callGas = 700;
+ inline unsigned callGas(EVMVersion _evmVersion)
+ {
+ return _evmVersion >= EVMVersion::tangerineWhistle() ? 700 : 40;
+ }
static unsigned const callStipend = 2300;
static unsigned const callValueTransferGas = 9000;
static unsigned const callNewAccountGas = 25000;
- static unsigned const selfdestructGas = 5000;
+ inline unsigned selfdestructGas(EVMVersion _evmVersion)
+ {
+ return _evmVersion >= EVMVersion::tangerineWhistle() ? 5000 : 0;
+ }
static unsigned const selfdestructRefundGas = 24000;
static unsigned const memoryGas = 3;
static unsigned const quadCoeffDiv = 512;
@@ -100,8 +121,8 @@ public:
};
/// Constructs a new gas meter given the current state.
- explicit GasMeter(std::shared_ptr<KnownState> const& _state, u256 const& _largestMemoryAccess = 0):
- m_state(_state), m_largestMemoryAccess(_largestMemoryAccess) {}
+ GasMeter(std::shared_ptr<KnownState> const& _state, solidity::EVMVersion _evmVersion, u256 const& _largestMemoryAccess = 0):
+ m_state(_state), m_evmVersion(_evmVersion), m_largestMemoryAccess(_largestMemoryAccess) {}
/// @returns an upper bound on the gas consumed by the given instruction and updates
/// the state.
@@ -110,6 +131,8 @@ public:
u256 const& largestMemoryAccess() const { return m_largestMemoryAccess; }
+ /// @returns gas costs for simple instructions with constant gas costs (that do not
+ /// change with EVM versions)
static unsigned runGas(Instruction _instruction);
private:
@@ -123,6 +146,7 @@ private:
GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize);
std::shared_ptr<KnownState> m_state;
+ EVMVersion m_evmVersion;
/// Largest point where memory was accessed since the creation of this object.
u256 m_largestMemoryAccess;
};
diff --git a/libevmasm/PathGasMeter.cpp b/libevmasm/PathGasMeter.cpp
index c56e2f8b..3fe682b7 100644
--- a/libevmasm/PathGasMeter.cpp
+++ b/libevmasm/PathGasMeter.cpp
@@ -27,8 +27,8 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
-PathGasMeter::PathGasMeter(AssemblyItems const& _items):
- m_items(_items)
+PathGasMeter::PathGasMeter(AssemblyItems const& _items, solidity::EVMVersion _evmVersion):
+ m_items(_items), m_evmVersion(_evmVersion)
{
for (size_t i = 0; i < m_items.size(); ++i)
if (m_items[i].type() == Tag)
@@ -59,7 +59,7 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem()
m_queue.pop_back();
shared_ptr<KnownState> state = path->state;
- GasMeter meter(state, path->largestMemoryAccess);
+ GasMeter meter(state, m_evmVersion, path->largestMemoryAccess);
ExpressionClasses& classes = state->expressionClasses();
GasMeter::GasConsumption gas = path->gas;
size_t index = path->index;
diff --git a/libevmasm/PathGasMeter.h b/libevmasm/PathGasMeter.h
index 4826eac2..2527d7fb 100644
--- a/libevmasm/PathGasMeter.h
+++ b/libevmasm/PathGasMeter.h
@@ -21,10 +21,13 @@
#pragma once
+#include <libevmasm/GasMeter.h>
+
+#include <libsolidity/interface/EVMVersion.h>
+
#include <set>
#include <vector>
#include <memory>
-#include <libevmasm/GasMeter.h>
namespace dev
{
@@ -50,7 +53,7 @@ struct GasPath
class PathGasMeter
{
public:
- explicit PathGasMeter(AssemblyItems const& _items);
+ explicit PathGasMeter(AssemblyItems const& _items, solidity::EVMVersion _evmVersion);
GasMeter::GasConsumption estimateMax(size_t _startIndex, std::shared_ptr<KnownState> const& _state);
@@ -60,6 +63,7 @@ private:
std::vector<std::unique_ptr<GasPath>> m_queue;
std::map<u256, size_t> m_tagPositions;
AssemblyItems const& m_items;
+ solidity::EVMVersion m_evmVersion;
};
}