mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
parent
5caad351f8
commit
6e98243ead
@ -22,7 +22,6 @@
|
||||
#include "Assembly.h"
|
||||
#include <fstream>
|
||||
#include <libdevcore/Log.h>
|
||||
#include <libevmcore/Params.h>
|
||||
#include <libevmasm/CommonSubexpressionEliminator.h>
|
||||
#include <libevmasm/ControlFlowGraph.h>
|
||||
#include <libevmasm/BlockDeduplicator.h>
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "libevmasm/ConstantOptimiser.h"
|
||||
#include <libevmasm/Assembly.h>
|
||||
#include <libevmasm/GasMeter.h>
|
||||
#include <libevmcore/Params.h>
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
@ -70,12 +69,13 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
|
||||
|
||||
bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
|
||||
{
|
||||
EVMSchedule schedule; // TODO: make relevant to context.
|
||||
bigint gas = 0;
|
||||
for (AssemblyItem const& item: _items)
|
||||
if (item.type() == Push)
|
||||
gas += GasMeter::runGas(Instruction::PUSH1);
|
||||
gas += GasMeter::runGas(Instruction::PUSH1, schedule);
|
||||
else if (item.type() == Operation)
|
||||
gas += GasMeter::runGas(item.instruction());
|
||||
gas += GasMeter::runGas(item.instruction(), schedule);
|
||||
return gas;
|
||||
}
|
||||
|
||||
@ -85,11 +85,11 @@ bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const
|
||||
{
|
||||
bigint gas;
|
||||
for (auto b: _data)
|
||||
gas += b ? c_txDataNonZeroGas : c_txDataZeroGas;
|
||||
gas += b ? m_schedule.txDataNonZeroGas : m_schedule.txDataZeroGas;
|
||||
return gas;
|
||||
}
|
||||
else
|
||||
return c_createDataGas * dataSize();
|
||||
return m_schedule.createDataGas * dataSize();
|
||||
}
|
||||
|
||||
size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)
|
||||
@ -121,7 +121,7 @@ bigint LiteralMethod::gasNeeded()
|
||||
return combineGas(
|
||||
simpleRunGas({Instruction::PUSH1}),
|
||||
// PUSHX plus data
|
||||
(m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas) + dataGas(),
|
||||
(m_params.isCreation ? m_schedule.txDataNonZeroGas : m_schedule.createDataGas) + dataGas(),
|
||||
0
|
||||
);
|
||||
}
|
||||
@ -148,9 +148,9 @@ bigint CodeCopyMethod::gasNeeded()
|
||||
{
|
||||
return combineGas(
|
||||
// Run gas: we ignore memory increase costs
|
||||
simpleRunGas(m_copyRoutine) + c_copyGas,
|
||||
simpleRunGas(m_copyRoutine) + m_schedule.copyGas,
|
||||
// Data gas for copy routines: Some bytes are zero, but we ignore them.
|
||||
bytesRequired(m_copyRoutine) * (m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas),
|
||||
bytesRequired(m_copyRoutine) * (m_params.isCreation ? m_schedule.txDataNonZeroGas : m_schedule.createDataGas),
|
||||
// Data gas for data itself
|
||||
dataGas(toBigEndian(m_value))
|
||||
);
|
||||
@ -217,9 +217,9 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine)
|
||||
{
|
||||
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
|
||||
return combineGas(
|
||||
simpleRunGas(_routine) + numExps * (c_expGas + c_expByteGas),
|
||||
simpleRunGas(_routine) + numExps * (m_schedule.expGas + m_schedule.expByteGas),
|
||||
// Data gas for routine: Some bytes are zero, but we ignore them.
|
||||
bytesRequired(_routine) * (m_params.isCreation ? c_txDataNonZeroGas : c_createDataGas),
|
||||
bytesRequired(_routine) * (m_params.isCreation ? m_schedule.txDataNonZeroGas : m_schedule.createDataGas),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <vector>
|
||||
#include <libdevcore/CommonData.h>
|
||||
#include <libdevcore/CommonIO.h>
|
||||
#include <libethcore/ChainOperationParams.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -34,6 +35,8 @@ class AssemblyItem;
|
||||
using AssemblyItems = std::vector<AssemblyItem>;
|
||||
class Assembly;
|
||||
|
||||
// TODO: FIXME: HOMESTEAD: XXX: @chfast populate m_schedule from an ExtVMFace instance via ExtVMFace::evmSchedule.
|
||||
|
||||
/**
|
||||
* Abstract base class for one way to change how constants are represented in the code.
|
||||
*/
|
||||
@ -88,6 +91,7 @@ protected:
|
||||
|
||||
Params m_params;
|
||||
u256 const& m_value;
|
||||
EVMSchedule m_schedule;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -101,6 +105,8 @@ public:
|
||||
ConstantOptimisationMethod(_params, _value) {}
|
||||
virtual bigint gasNeeded() override;
|
||||
virtual void execute(Assembly&, AssemblyItems&) override {}
|
||||
|
||||
EVMSchedule m_schedule;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -115,6 +121,7 @@ public:
|
||||
|
||||
protected:
|
||||
AssemblyItems m_copyRoutine;
|
||||
EVMSchedule m_schedule;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -141,6 +148,7 @@ protected:
|
||||
bigint gasNeeded(AssemblyItems const& _routine);
|
||||
|
||||
AssemblyItems m_routine;
|
||||
EVMSchedule m_schedule;
|
||||
};
|
||||
|
||||
}
|
||||
|
42
GasMeter.cpp
42
GasMeter.cpp
@ -21,8 +21,6 @@
|
||||
|
||||
#include "GasMeter.h"
|
||||
#include <libevmasm/KnownState.h>
|
||||
#include <libevmcore/Params.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
@ -73,13 +71,13 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
|
||||
m_state->storageContent().count(slot) &&
|
||||
classes.knownNonZero(m_state->storageContent().at(slot))
|
||||
))
|
||||
gas += c_sstoreResetGas; //@todo take refunds into account
|
||||
gas += m_schedule.sstoreResetGas; //@todo take refunds into account
|
||||
else
|
||||
gas += c_sstoreSetGas;
|
||||
gas += m_schedule.sstoreSetGas;
|
||||
break;
|
||||
}
|
||||
case Instruction::SLOAD:
|
||||
gas += c_sloadGas;
|
||||
gas += m_schedule.sloadGas;
|
||||
break;
|
||||
case Instruction::RETURN:
|
||||
gas += memoryGas(0, -1);
|
||||
@ -98,18 +96,18 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
|
||||
}));
|
||||
break;
|
||||
case Instruction::SHA3:
|
||||
gas = c_sha3Gas;
|
||||
gas += wordGas(c_sha3WordGas, m_state->relativeStackElement(-1));
|
||||
gas = m_schedule.sha3Gas;
|
||||
gas += wordGas(m_schedule.sha3WordGas, m_state->relativeStackElement(-1));
|
||||
gas += memoryGas(0, -1);
|
||||
break;
|
||||
case Instruction::CALLDATACOPY:
|
||||
case Instruction::CODECOPY:
|
||||
gas += memoryGas(0, -2);
|
||||
gas += wordGas(c_copyGas, m_state->relativeStackElement(-2));
|
||||
gas += wordGas(m_schedule.copyGas, m_state->relativeStackElement(-2));
|
||||
break;
|
||||
case Instruction::EXTCODECOPY:
|
||||
gas += memoryGas(-1, -3);
|
||||
gas += wordGas(c_copyGas, m_state->relativeStackElement(-3));
|
||||
gas += wordGas(m_schedule.copyGas, m_state->relativeStackElement(-3));
|
||||
break;
|
||||
case Instruction::LOG0:
|
||||
case Instruction::LOG1:
|
||||
@ -118,38 +116,38 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
|
||||
case Instruction::LOG4:
|
||||
{
|
||||
unsigned n = unsigned(_item.instruction()) - unsigned(Instruction::LOG0);
|
||||
gas = c_logGas + c_logTopicGas * n;
|
||||
gas = m_schedule.logGas + m_schedule.logTopicGas * n;
|
||||
gas += memoryGas(0, -1);
|
||||
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
|
||||
gas += c_logDataGas * (*value);
|
||||
gas += m_schedule.logDataGas * (*value);
|
||||
else
|
||||
gas = GasConsumption::infinite();
|
||||
break;
|
||||
}
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
gas = c_callGas;
|
||||
gas = m_schedule.callGas;
|
||||
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0)))
|
||||
gas += (*value);
|
||||
else
|
||||
gas = GasConsumption::infinite();
|
||||
if (_item.instruction() != Instruction::CALLCODE)
|
||||
gas += c_callNewAccountGas; // We very rarely know whether the address exists.
|
||||
gas += m_schedule.callNewAccountGas; // We very rarely know whether the address exists.
|
||||
if (!classes.knownZero(m_state->relativeStackElement(-2)))
|
||||
gas += c_callValueTransferGas;
|
||||
gas += m_schedule.callValueTransferGas;
|
||||
gas += memoryGas(-3, -4);
|
||||
gas += memoryGas(-5, -6);
|
||||
break;
|
||||
case Instruction::CREATE:
|
||||
gas = c_createGas;
|
||||
gas = m_schedule.createGas;
|
||||
gas += memoryGas(-1, -2);
|
||||
break;
|
||||
case Instruction::EXP:
|
||||
gas = c_expGas;
|
||||
gas = m_schedule.expGas;
|
||||
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
|
||||
gas += c_expByteGas * (32 - (h256(*value).firstBitSet() / 8));
|
||||
gas += m_schedule.expByteGas * (32 - (h256(*value).firstBitSet() / 8));
|
||||
else
|
||||
gas += c_expByteGas * 32;
|
||||
gas += m_schedule.expByteGas * 32;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -182,10 +180,10 @@ GasMeter::GasConsumption GasMeter::memoryGas(ExpressionClasses::Id _position)
|
||||
return GasConsumption(u256(0));
|
||||
u256 previous = m_largestMemoryAccess;
|
||||
m_largestMemoryAccess = *value;
|
||||
auto memGas = [](u256 const& pos) -> u256
|
||||
auto memGas = [=](u256 const& pos) -> u256
|
||||
{
|
||||
u256 size = (pos + 31) / 32;
|
||||
return c_memoryGas * size + size * size / c_quadCoeffDiv;
|
||||
return m_schedule.memoryGas * size + size * size / m_schedule.quadCoeffDiv;
|
||||
};
|
||||
return memGas(*value) - memGas(previous);
|
||||
}
|
||||
@ -202,14 +200,14 @@ GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosS
|
||||
}));
|
||||
}
|
||||
|
||||
u256 GasMeter::runGas(Instruction _instruction)
|
||||
u256 GasMeter::runGas(Instruction _instruction, EVMSchedule const& _es)
|
||||
{
|
||||
if (_instruction == Instruction::JUMPDEST)
|
||||
return 1;
|
||||
|
||||
int tier = instructionInfo(_instruction).gasPriceTier;
|
||||
assertThrow(tier != InvalidTier, OptimizerException, "Invalid gas tier.");
|
||||
return c_tierStepGas[tier];
|
||||
return _es.tierStepGas[tier];
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <tuple>
|
||||
#include <libevmasm/ExpressionClasses.h>
|
||||
#include <libevmasm/AssemblyItem.h>
|
||||
#include <libethcore/ChainOperationParams.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -33,6 +34,8 @@ namespace eth
|
||||
|
||||
class KnownState;
|
||||
|
||||
// TODO: FIXME: HOMESTEAD: XXX: @chfast populate m_schedule from an ExtVMFace instance via ExtVMFace::evmSchedule.
|
||||
|
||||
/**
|
||||
* Class that helps computing the maximum gas consumption for instructions.
|
||||
* Has to be initialized with a certain known state that will be automatically updated for
|
||||
@ -66,7 +69,8 @@ public:
|
||||
|
||||
u256 const& largestMemoryAccess() const { return m_largestMemoryAccess; }
|
||||
|
||||
static u256 runGas(Instruction _instruction);
|
||||
u256 runGas(Instruction _instruction) const { return runGas(_instruction, m_schedule); }
|
||||
static u256 runGas(Instruction _instruction, EVMSchedule const& _es);
|
||||
|
||||
private:
|
||||
/// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise.
|
||||
@ -81,6 +85,8 @@ private:
|
||||
std::shared_ptr<KnownState> m_state;
|
||||
/// Largest point where memory was accessed since the creation of this object.
|
||||
u256 m_largestMemoryAccess;
|
||||
|
||||
EVMSchedule m_schedule;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& _str, GasMeter::GasConsumption const& _consumption)
|
||||
|
Loading…
Reference in New Issue
Block a user