Skip to content

Commit

Permalink
Optimize constant optimization.
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseth committed Jan 12, 2017
1 parent f1a4976 commit da5e171
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 37 deletions.
76 changes: 47 additions & 29 deletions libevmasm/ConstantOptimiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
for (AssemblyItem const& item: _items)
if (item.type() == Push)
pushes[item]++;
map<u256, AssemblyItems> pendingReplacements;
for (auto it: pushes)
{
AssemblyItem const& item = it.first;
Expand All @@ -53,17 +54,22 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
bigint copyGas = copy.gasNeeded();
ComputeMethod compute(params, item.data());
bigint computeGas = compute.gasNeeded();
AssemblyItems replacement;
if (copyGas < literalGas && copyGas < computeGas)
{
copy.execute(_assembly, _items);
replacement = copy.execute(_assembly);
optimisations++;
}
else if (computeGas < literalGas && computeGas < copyGas)
{
compute.execute(_assembly, _items);
replacement = compute.execute(_assembly);
optimisations++;
}
if (!replacement.empty())
pendingReplacements[item.data()] = replacement;
}
if (!pendingReplacements.empty())
replaceConstants(_items, pendingReplacements);
return optimisations;
}

Expand Down Expand Up @@ -101,18 +107,24 @@ size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)

void ConstantOptimisationMethod::replaceConstants(
AssemblyItems& _items,
AssemblyItems const& _replacement
) const
map<u256, AssemblyItems> const& _replacements
)
{
assertThrow(_items.size() > 0, OptimizerException, "");
for (size_t i = 0; i < _items.size(); ++i)
AssemblyItems replaced;
for (AssemblyItem const& item: _items)
{
if (_items.at(i) != AssemblyItem(m_value))
continue;
_items[i] = _replacement[0];
_items.insert(_items.begin() + i + 1, _replacement.begin() + 1, _replacement.end());
i += _replacement.size() - 1;
if (item.type() == Push)
{
auto it = _replacements.find(item.data());
if (it != _replacements.end())
{
replaced += it->second;
continue;
}
}
replaced.push_back(item);
}
_items = std::move(replaced);
}

bigint LiteralMethod::gasNeeded()
Expand All @@ -128,38 +140,44 @@ bigint LiteralMethod::gasNeeded()
CodeCopyMethod::CodeCopyMethod(Params const& _params, u256 const& _value):
ConstantOptimisationMethod(_params, _value)
{
m_copyRoutine = AssemblyItems{
u256(0),
Instruction::DUP1,
Instruction::MLOAD, // back up memory
u256(32),
AssemblyItem(PushData, u256(1) << 16), // has to be replaced
Instruction::DUP4,
Instruction::CODECOPY,
Instruction::DUP2,
Instruction::MLOAD,
Instruction::SWAP2,
Instruction::MSTORE
};
}

bigint CodeCopyMethod::gasNeeded()
{
return combineGas(
// Run gas: we ignore memory increase costs
simpleRunGas(m_copyRoutine) + GasCosts::copyGas,
simpleRunGas(copyRoutine()) + GasCosts::copyGas,
// Data gas for copy routines: Some bytes are zero, but we ignore them.
bytesRequired(m_copyRoutine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
// Data gas for data itself
dataGas(toBigEndian(m_value))
);
}

void CodeCopyMethod::execute(Assembly& _assembly, AssemblyItems& _items)
AssemblyItems CodeCopyMethod::execute(Assembly& _assembly)
{
bytes data = toBigEndian(m_value);
m_copyRoutine[4] = _assembly.newData(data);
replaceConstants(_items, m_copyRoutine);
AssemblyItems actualCopyRoutine = copyRoutine();
actualCopyRoutine[4] = _assembly.newData(data);
return actualCopyRoutine;
}

AssemblyItems const& CodeCopyMethod::copyRoutine() const
{
AssemblyItems static copyRoutine{
u256(0),
Instruction::DUP1,
Instruction::MLOAD, // back up memory
u256(32),
AssemblyItem(PushData, u256(1) << 16), // has to be replaced
Instruction::DUP4,
Instruction::CODECOPY,
Instruction::DUP2,
Instruction::MLOAD,
Instruction::SWAP2,
Instruction::MSTORE
};
return copyRoutine;
}

AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
Expand Down
19 changes: 11 additions & 8 deletions libevmasm/ConstantOptimiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ class ConstantOptimisationMethod
explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value):
m_params(_params), m_value(_value) {}
virtual bigint gasNeeded() = 0;
virtual void execute(Assembly& _assembly, AssemblyItems& _items) = 0;
/// Executes the method, potentially appending to the assembly and returns a vector of
/// assembly items the constant should be relpaced with in one sweep.
/// If the vector is empty, the constants will not be deleted.
virtual AssemblyItems execute(Assembly& _assembly) = 0;

protected:
size_t dataSize() const { return std::max<size_t>(1, dev::bytesRequired(m_value)); }
Expand All @@ -83,8 +86,8 @@ class ConstantOptimisationMethod
return m_params.runs * _runGas + m_params.multiplicity * _repeatedDataGas + _uniqueDataGas;
}

/// Replaces the constant by the code given in @a _replacement.
void replaceConstants(AssemblyItems& _items, AssemblyItems const& _replacement) const;
/// Replaces all constants i by the code given in @a _replacement[i].
static void replaceConstants(AssemblyItems& _items, std::map<u256, AssemblyItems> const& _replacement);

Params m_params;
u256 const& m_value;
Expand All @@ -100,7 +103,7 @@ class LiteralMethod: public ConstantOptimisationMethod
explicit LiteralMethod(Params const& _params, u256 const& _value):
ConstantOptimisationMethod(_params, _value) {}
virtual bigint gasNeeded() override;
virtual void execute(Assembly&, AssemblyItems&) override {}
virtual AssemblyItems execute(Assembly&) override { return AssemblyItems{}; }
};

/**
Expand All @@ -111,10 +114,10 @@ class CodeCopyMethod: public ConstantOptimisationMethod
public:
explicit CodeCopyMethod(Params const& _params, u256 const& _value);
virtual bigint gasNeeded() override;
virtual void execute(Assembly& _assembly, AssemblyItems& _items) override;
virtual AssemblyItems execute(Assembly& _assembly) override;

protected:
AssemblyItems m_copyRoutine;
AssemblyItems const& copyRoutine() const;
};

/**
Expand All @@ -130,9 +133,9 @@ class ComputeMethod: public ConstantOptimisationMethod
}

virtual bigint gasNeeded() override { return gasNeeded(m_routine); }
virtual void execute(Assembly&, AssemblyItems& _items) override
virtual AssemblyItems execute(Assembly&) override
{
replaceConstants(_items, m_routine);
return m_routine;
}

protected:
Expand Down

0 comments on commit da5e171

Please sign in to comment.