Make KnownState work with all instructions.

This commit is contained in:
chriseth 2015-04-30 15:31:16 +02:00
parent 867101e409
commit a2e3bcbd0c
4 changed files with 83 additions and 6 deletions

View File

@ -57,12 +57,15 @@ ExpressionClasses::Id ExpressionClasses::find(
exp.arguments = _arguments; exp.arguments = _arguments;
exp.sequenceNumber = _sequenceNumber; exp.sequenceNumber = _sequenceNumber;
if (SemanticInformation::isDeterministic(_item))
{
if (SemanticInformation::isCommutativeOperation(_item)) if (SemanticInformation::isCommutativeOperation(_item))
sort(exp.arguments.begin(), exp.arguments.end()); sort(exp.arguments.begin(), exp.arguments.end());
auto it = m_expressions.find(exp); auto it = m_expressions.find(exp);
if (it != m_expressions.end()) if (it != m_expressions.end())
return it->id; return it->id;
}
if (_copyItem) if (_copyItem)
exp.item = storeItem(_item); exp.item = storeItem(_item);
@ -286,7 +289,11 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr,
{ {
static Rules rules; static Rules rules;
if (!_expr.item || _expr.item->type() != Operation) if (
!_expr.item ||
_expr.item->type() != Operation ||
!SemanticInformation::isDeterministic(*_expr.item)
)
return -1; return -1;
for (auto const& rule: rules.rules()) for (auto const& rule: rules.rules())

View File

@ -101,6 +101,7 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
vector<Id> arguments(info.args); vector<Id> arguments(info.args);
for (int i = 0; i < info.args; ++i) for (int i = 0; i < info.args; ++i)
arguments[i] = stackElement(m_stackHeight - i, _item.getLocation()); arguments[i] = stackElement(m_stackHeight - i, _item.getLocation());
if (_item.instruction() == Instruction::SSTORE) if (_item.instruction() == Instruction::SSTORE)
op = storeInStorage(arguments[0], arguments[1], _item.getLocation()); op = storeInStorage(arguments[0], arguments[1], _item.getLocation());
else if (_item.instruction() == Instruction::SLOAD) else if (_item.instruction() == Instruction::SLOAD)
@ -121,11 +122,17 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
applySha3(arguments.at(0), arguments.at(1), _item.getLocation()) applySha3(arguments.at(0), arguments.at(1), _item.getLocation())
); );
else else
{
if (SemanticInformation::invalidatesMemory(_item.instruction()))
resetMemory();
if (SemanticInformation::invalidatesStorage(_item.instruction()))
resetStorage();
setStackElement( setStackElement(
m_stackHeight + _item.deposit(), m_stackHeight + _item.deposit(),
m_expressionClasses->find(_item, arguments, _copyItem) m_expressionClasses->find(_item, arguments, _copyItem)
); );
} }
}
m_stackHeight += _item.deposit(); m_stackHeight += _item.deposit();
} }
return op; return op;

View File

@ -122,3 +122,57 @@ bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
return false; return false;
} }
} }
bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
{
if (_item.type() != Operation)
return true;
assertThrow(!altersControlFlow(_item), OptimizerException, "");
switch (_item.instruction())
{
case Instruction::CALL:
case Instruction::CALLCODE:
case Instruction::CREATE:
case Instruction::GAS:
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::EXTCODESIZE:
return false;
default:
return true;
}
}
bool SemanticInformation::invalidatesMemory(Instruction _instruction)
{
switch (_instruction)
{
case Instruction::CALLDATACOPY:
case Instruction::CODECOPY:
case Instruction::EXTCODECOPY:
case Instruction::MSTORE:
case Instruction::MSTORE8:
case Instruction::CALL:
case Instruction::CALLCODE:
return true;
default:
return false;
}
}
bool SemanticInformation::invalidatesStorage(Instruction _instruction)
{
switch (_instruction)
{
case Instruction::CALL:
case Instruction::CALLCODE:
case Instruction::CREATE:
case Instruction::SSTORE:
return true;
default:
return false;
}
}

View File

@ -23,6 +23,7 @@
#pragma once #pragma once
#include <libevmcore/Instruction.h>
namespace dev namespace dev
{ {
@ -45,6 +46,14 @@ struct SemanticInformation
static bool isSwapInstruction(AssemblyItem const& _item); static bool isSwapInstruction(AssemblyItem const& _item);
static bool isJumpInstruction(AssemblyItem const& _item); static bool isJumpInstruction(AssemblyItem const& _item);
static bool altersControlFlow(AssemblyItem const& _item); static bool altersControlFlow(AssemblyItem const& _item);
/// @returns false if the value put on the stack by _item depends on anything else than
/// the information in the current block header, memory, storage or stack.
/// @note should not be called for instructions that alter the control flow.
static bool isDeterministic(AssemblyItem const& _item);
/// @returns true if the given instruction modifies memory.
static bool invalidatesMemory(Instruction _instruction);
/// @returns true if the given instruction modifies storage (even indirectly).
static bool invalidatesStorage(Instruction _instruction);
}; };
} }