mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
returndatacopy and bugfix.
This commit is contained in:
parent
b09a8c62bb
commit
1013419597
@ -78,12 +78,10 @@ void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
|||||||
ignoreMemory
|
ignoreMemory
|
||||||
};
|
};
|
||||||
rse(_ast);
|
rse(_ast);
|
||||||
if (
|
|
||||||
auto evmDialect = dynamic_cast<EVMDialect const*>(&_context.dialect);
|
auto evmDialect = dynamic_cast<EVMDialect const*>(&_context.dialect);
|
||||||
evmDialect && evmDialect->providesObjectAccess()
|
if (evmDialect && evmDialect->providesObjectAccess())
|
||||||
)
|
rse.clearActive(Location::Memory);
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
rse.markActiveAsUsed(Location::Memory);
|
rse.markActiveAsUsed(Location::Memory);
|
||||||
rse.markActiveAsUsed(Location::Storage);
|
rse.markActiveAsUsed(Location::Storage);
|
||||||
@ -168,25 +166,30 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
|
|||||||
yulAssert(isCandidateForRemoval == (isStorageWrite || (!m_ignoreMemory && isMemoryWrite)));
|
yulAssert(isCandidateForRemoval == (isStorageWrite || (!m_ignoreMemory && isMemoryWrite)));
|
||||||
if (isCandidateForRemoval)
|
if (isCandidateForRemoval)
|
||||||
{
|
{
|
||||||
// TODO what is this special case?
|
if (*instruction == Instruction::RETURNDATACOPY)
|
||||||
//State initialState = State::Undecided;
|
{
|
||||||
// if (*instruction == Instruction::RETURNDATACOPY)
|
// Out-of-bounds access to the returndata buffer results in a revert,
|
||||||
// {
|
// so we are careful not to remove a potentially reverting call to a builtin.
|
||||||
// initialState = State::Used;
|
// The only way the Solidity compiler uses `returndatacopy` is
|
||||||
// auto startOffset = identifierNameIfSSA(funCall->arguments.at(1));
|
// `returndatacopy(X, 0, returndatasize())`, so we only allow to remove this pattern
|
||||||
// auto length = identifierNameIfSSA(funCall->arguments.at(2));
|
// (which is guaranteed to never cause an out-of-bounds revert).
|
||||||
// KnowledgeBase knowledge(m_dialect, [this](YulString _var) { return util::valueOrNullptr(m_ssaValues, _var); });
|
bool allowReturndatacopyToBeRemoved = false;
|
||||||
// if (length && startOffset)
|
auto startOffset = identifierNameIfSSA(funCall->arguments.at(1));
|
||||||
// {
|
auto length = identifierNameIfSSA(funCall->arguments.at(2));
|
||||||
// FunctionCall const* lengthCall = get_if<FunctionCall>(m_ssaValues.at(*length).value);
|
KnowledgeBase knowledge(m_dialect, [this](YulString _var) { return util::valueOrNullptr(m_ssaValues, _var); });
|
||||||
// if (
|
if (length && startOffset)
|
||||||
// knowledge.knownToBeZero(*startOffset) &&
|
{
|
||||||
// lengthCall &&
|
FunctionCall const* lengthCall = get_if<FunctionCall>(m_ssaValues.at(*length).value);
|
||||||
// toEVMInstruction(m_dialect, lengthCall->functionName.name) == Instruction::RETURNDATASIZE
|
if (
|
||||||
// )
|
knowledge.knownToBeZero(*startOffset) &&
|
||||||
// initialState = State::Undecided;
|
lengthCall &&
|
||||||
// }
|
toEVMInstruction(m_dialect, lengthCall->functionName.name) == Instruction::RETURNDATASIZE
|
||||||
// }
|
)
|
||||||
|
allowReturndatacopyToBeRemoved = true;
|
||||||
|
}
|
||||||
|
if (!allowReturndatacopyToBeRemoved)
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_allStores.insert(&_statement);
|
m_allStores.insert(&_statement);
|
||||||
vector<Operation> operations = operationsFromFunctionCall(*funCall);
|
vector<Operation> operations = operationsFromFunctionCall(*funCall);
|
||||||
yulAssert(operations.size() == 1, "");
|
yulAssert(operations.size() == 1, "");
|
||||||
@ -198,11 +201,6 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnusedStoreEliminator::finalizeFunctionDefinition(FunctionDefinition const&)
|
|
||||||
{
|
|
||||||
markActiveAsUsed();
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFunctionCall(
|
vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFunctionCall(
|
||||||
FunctionCall const& _functionCall
|
FunctionCall const& _functionCall
|
||||||
) const
|
) const
|
||||||
|
@ -98,14 +98,17 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<Statement const*>& activeMemoryStores() { return m_activeStores["m"_yulstring]; }
|
std::set<Statement const*>& activeMemoryStores() { return m_activeStores["m"_yulstring]; }
|
||||||
std::set<Statement const*>& activeStorageStores() { return m_activeStores["m"_yulstring]; }
|
std::set<Statement const*>& activeStorageStores() { return m_activeStores["s"_yulstring]; }
|
||||||
|
|
||||||
void shortcutNestedLoop(ActiveStores const&) override
|
void shortcutNestedLoop(ActiveStores const&) override
|
||||||
{
|
{
|
||||||
// We might only need to do this for newly introduced stores in the loop.
|
// We might only need to do this for newly introduced stores in the loop.
|
||||||
markActiveAsUsed();
|
markActiveAsUsed();
|
||||||
}
|
}
|
||||||
void finalizeFunctionDefinition(FunctionDefinition const&) override;
|
void finalizeFunctionDefinition(FunctionDefinition const&) override
|
||||||
|
{
|
||||||
|
markActiveAsUsed();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Operation> operationsFromFunctionCall(FunctionCall const& _functionCall) const;
|
std::vector<Operation> operationsFromFunctionCall(FunctionCall const& _functionCall) const;
|
||||||
void applyOperation(Operation const& _operation);
|
void applyOperation(Operation const& _operation);
|
||||||
|
@ -39,8 +39,7 @@
|
|||||||
// }
|
// }
|
||||||
// if calldataload(2)
|
// if calldataload(2)
|
||||||
// {
|
// {
|
||||||
// let _17 := 7
|
// mstore8(2, 7)
|
||||||
// let _18 := 2
|
|
||||||
// calldatacopy(0, 0, 3)
|
// calldatacopy(0, 0, 3)
|
||||||
// }
|
// }
|
||||||
// if calldataload(3)
|
// if calldataload(3)
|
||||||
|
Loading…
Reference in New Issue
Block a user