mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #5227 from ethereum/doNotRemoveExternallyUsedFunction
Prevent externally used functions from being removed.
This commit is contained in:
commit
f2f72ff7ee
@ -49,7 +49,7 @@ string ABIFunctions::tupleEncoder(
|
|||||||
if (_encodeAsLibraryTypes)
|
if (_encodeAsLibraryTypes)
|
||||||
functionName += "_library";
|
functionName += "_library";
|
||||||
|
|
||||||
return createFunction(functionName, [&]() {
|
return createExternallyUsedFunction(functionName, [&]() {
|
||||||
solAssert(!_givenTypes.empty(), "");
|
solAssert(!_givenTypes.empty(), "");
|
||||||
|
|
||||||
// Note that the values are in reverse due to the difference in calling semantics.
|
// Note that the values are in reverse due to the difference in calling semantics.
|
||||||
@ -113,7 +113,7 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory)
|
|||||||
|
|
||||||
solAssert(!_types.empty(), "");
|
solAssert(!_types.empty(), "");
|
||||||
|
|
||||||
return createFunction(functionName, [&]() {
|
return createExternallyUsedFunction(functionName, [&]() {
|
||||||
TypePointers decodingTypes;
|
TypePointers decodingTypes;
|
||||||
for (auto const& t: _types)
|
for (auto const& t: _types)
|
||||||
decodingTypes.emplace_back(t->decodingType());
|
decodingTypes.emplace_back(t->decodingType());
|
||||||
@ -176,13 +176,13 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
string ABIFunctions::requestedFunctions()
|
pair<string, set<string>> ABIFunctions::requestedFunctions()
|
||||||
{
|
{
|
||||||
string result;
|
string result;
|
||||||
for (auto const& f: m_requestedFunctions)
|
for (auto const& f: m_requestedFunctions)
|
||||||
result += f.second;
|
result += f.second;
|
||||||
m_requestedFunctions.clear();
|
m_requestedFunctions.clear();
|
||||||
return result;
|
return make_pair(result, std::move(m_externallyUsedFunctions));
|
||||||
}
|
}
|
||||||
|
|
||||||
string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
||||||
@ -1697,6 +1697,13 @@ string ABIFunctions::createFunction(string const& _name, function<string ()> con
|
|||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string ABIFunctions::createExternallyUsedFunction(string const& _name, function<string ()> const& _creator)
|
||||||
|
{
|
||||||
|
string name = createFunction(_name, _creator);
|
||||||
|
m_externallyUsedFunctions.insert(name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
size_t ABIFunctions::headSize(TypePointers const& _targetTypes)
|
size_t ABIFunctions::headSize(TypePointers const& _targetTypes)
|
||||||
{
|
{
|
||||||
size_t headSize = 0;
|
size_t headSize = 0;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <set>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace dev {
|
namespace dev {
|
||||||
@ -80,8 +81,11 @@ public:
|
|||||||
/// stack slot, it takes exactly that number of values.
|
/// stack slot, it takes exactly that number of values.
|
||||||
std::string tupleDecoder(TypePointers const& _types, bool _fromMemory = false);
|
std::string tupleDecoder(TypePointers const& _types, bool _fromMemory = false);
|
||||||
|
|
||||||
/// @returns concatenation of all generated functions.
|
/// @returns concatenation of all generated functions and a set of the
|
||||||
std::string requestedFunctions();
|
/// externally used functions.
|
||||||
|
/// Clears the internal list, i.e. calling it again will result in an
|
||||||
|
/// empty return value.
|
||||||
|
std::pair<std::string, std::set<std::string>> requestedFunctions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @returns the name of the cleanup function for the given type and
|
/// @returns the name of the cleanup function for the given type and
|
||||||
@ -224,12 +228,17 @@ private:
|
|||||||
/// cases.
|
/// cases.
|
||||||
std::string createFunction(std::string const& _name, std::function<std::string()> const& _creator);
|
std::string createFunction(std::string const& _name, std::function<std::string()> const& _creator);
|
||||||
|
|
||||||
|
/// Helper function that uses @a _creator to create a function and add it to
|
||||||
|
/// @a m_requestedFunctions if it has not been created yet and returns @a _name in both
|
||||||
|
/// cases. Also adds it to the list of externally used functions.
|
||||||
|
std::string createExternallyUsedFunction(std::string const& _name, std::function<std::string()> const& _creator);
|
||||||
|
|
||||||
/// @returns the size of the static part of the encoding of the given types.
|
/// @returns the size of the static part of the encoding of the given types.
|
||||||
static size_t headSize(TypePointers const& _targetTypes);
|
static size_t headSize(TypePointers const& _targetTypes);
|
||||||
|
|
||||||
/// Map from function name to code for a multi-use function.
|
/// Map from function name to code for a multi-use function.
|
||||||
std::map<std::string, std::string> m_requestedFunctions;
|
std::map<std::string, std::string> m_requestedFunctions;
|
||||||
|
std::set<std::string> m_externallyUsedFunctions;
|
||||||
EVMVersion m_evmVersion;
|
EVMVersion m_evmVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -313,6 +313,7 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node)
|
|||||||
void CompilerContext::appendInlineAssembly(
|
void CompilerContext::appendInlineAssembly(
|
||||||
string const& _assembly,
|
string const& _assembly,
|
||||||
vector<string> const& _localVariables,
|
vector<string> const& _localVariables,
|
||||||
|
set<string> const&,
|
||||||
bool _system
|
bool _system
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -206,10 +206,12 @@ public:
|
|||||||
/// Appends inline assembly (strict mode).
|
/// Appends inline assembly (strict mode).
|
||||||
/// @a _replacements are string-matching replacements that are performed prior to parsing the inline assembly.
|
/// @a _replacements are string-matching replacements that are performed prior to parsing the inline assembly.
|
||||||
/// @param _localVariables assigns stack positions to variables with the last one being the stack top
|
/// @param _localVariables assigns stack positions to variables with the last one being the stack top
|
||||||
|
/// @param _externallyUsedFunctions a set of function names that are not to be renamed or removed.
|
||||||
/// @param _system if true, this is a "system-level" assembly where all functions use named labels.
|
/// @param _system if true, this is a "system-level" assembly where all functions use named labels.
|
||||||
void appendInlineAssembly(
|
void appendInlineAssembly(
|
||||||
std::string const& _assembly,
|
std::string const& _assembly,
|
||||||
std::vector<std::string> const& _localVariables = std::vector<std::string>(),
|
std::vector<std::string> const& _localVariables = std::vector<std::string>(),
|
||||||
|
std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>(),
|
||||||
bool _system = false
|
bool _system = false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -874,9 +874,9 @@ void ContractCompiler::appendMissingFunctions()
|
|||||||
solAssert(m_context.nextFunctionToCompile() != function, "Compiled the wrong function?");
|
solAssert(m_context.nextFunctionToCompile() != function, "Compiled the wrong function?");
|
||||||
}
|
}
|
||||||
m_context.appendMissingLowLevelFunctions();
|
m_context.appendMissingLowLevelFunctions();
|
||||||
string abiFunctions = m_context.abiFunctions().requestedFunctions();
|
auto abiFunctions = m_context.abiFunctions().requestedFunctions();
|
||||||
if (!abiFunctions.empty())
|
if (!abiFunctions.first.empty())
|
||||||
m_context.appendInlineAssembly("{" + move(abiFunctions) + "}", {}, true);
|
m_context.appendInlineAssembly("{" + move(abiFunctions.first) + "}", {}, abiFunctions.second, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContractCompiler::appendModifierOrFunctionCode()
|
void ContractCompiler::appendModifierOrFunctionCode()
|
||||||
|
@ -34,6 +34,9 @@ using Scope = dev::solidity::assembly::Scope;
|
|||||||
|
|
||||||
string Disambiguator::translateIdentifier(string const& _originalName)
|
string Disambiguator::translateIdentifier(string const& _originalName)
|
||||||
{
|
{
|
||||||
|
if ((m_externallyUsedIdentifiers.count(_originalName)))
|
||||||
|
return _originalName;
|
||||||
|
|
||||||
assertThrow(!m_scopes.empty() && m_scopes.back(), OptimizerException, "");
|
assertThrow(!m_scopes.empty() && m_scopes.back(), OptimizerException, "");
|
||||||
Scope::Identifier const* id = m_scopes.back()->lookup(_originalName);
|
Scope::Identifier const* id = m_scopes.back()->lookup(_originalName);
|
||||||
assertThrow(id, OptimizerException, "");
|
assertThrow(id, OptimizerException, "");
|
||||||
|
@ -43,9 +43,14 @@ namespace yul
|
|||||||
class Disambiguator: public ASTCopier
|
class Disambiguator: public ASTCopier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Disambiguator(solidity::assembly::AsmAnalysisInfo const& _analysisInfo):
|
explicit Disambiguator(
|
||||||
m_info(_analysisInfo)
|
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
|
||||||
{}
|
std::set<std::string> const& _externallyUsedIdentifiers = {}
|
||||||
|
):
|
||||||
|
m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers)
|
||||||
|
{
|
||||||
|
m_nameDispenser.m_usedNames = m_externallyUsedIdentifiers;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void enterScope(Block const& _block) override;
|
virtual void enterScope(Block const& _block) override;
|
||||||
@ -58,6 +63,7 @@ protected:
|
|||||||
void leaveScopeInternal(solidity::assembly::Scope& _scope);
|
void leaveScopeInternal(solidity::assembly::Scope& _scope);
|
||||||
|
|
||||||
solidity::assembly::AsmAnalysisInfo const& m_info;
|
solidity::assembly::AsmAnalysisInfo const& m_info;
|
||||||
|
std::set<std::string> const& m_externallyUsedIdentifiers;
|
||||||
|
|
||||||
std::vector<solidity::assembly::Scope*> m_scopes;
|
std::vector<solidity::assembly::Scope*> m_scopes;
|
||||||
std::map<void const*, std::string> m_translations;
|
std::map<void const*, std::string> m_translations;
|
||||||
|
@ -33,12 +33,14 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace dev::yul;
|
using namespace dev::yul;
|
||||||
|
|
||||||
UnusedPruner::UnusedPruner(Block& _ast)
|
UnusedPruner::UnusedPruner(Block& _ast, set<string> const& _externallyUsedFunctions)
|
||||||
{
|
{
|
||||||
ReferencesCounter counter;
|
ReferencesCounter counter;
|
||||||
counter(_ast);
|
counter(_ast);
|
||||||
|
|
||||||
m_references = counter.references();
|
m_references = counter.references();
|
||||||
|
for (auto const& f: _externallyUsedFunctions)
|
||||||
|
++m_references[f];
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnusedPruner::operator()(Block& _block)
|
void UnusedPruner::operator()(Block& _block)
|
||||||
@ -89,11 +91,11 @@ void UnusedPruner::operator()(Block& _block)
|
|||||||
ASTModifier::operator()(_block);
|
ASTModifier::operator()(_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnusedPruner::runUntilStabilised(Block& _ast)
|
void UnusedPruner::runUntilStabilised(Block& _ast, set<string> const& _externallyUsedFunctions)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
UnusedPruner pruner(_ast);
|
UnusedPruner pruner(_ast, _externallyUsedFunctions);
|
||||||
pruner(_ast);
|
pruner(_ast);
|
||||||
if (!pruner.shouldRunAgain())
|
if (!pruner.shouldRunAgain())
|
||||||
return;
|
return;
|
||||||
|
@ -44,7 +44,7 @@ namespace yul
|
|||||||
class UnusedPruner: public ASTModifier
|
class UnusedPruner: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit UnusedPruner(Block& _ast);
|
explicit UnusedPruner(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>());
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
virtual void operator()(Block& _block) override;
|
virtual void operator()(Block& _block) override;
|
||||||
@ -53,7 +53,7 @@ public:
|
|||||||
bool shouldRunAgain() const { return m_shouldRunAgain; }
|
bool shouldRunAgain() const { return m_shouldRunAgain; }
|
||||||
|
|
||||||
// Run the pruner until the code does not change anymore.
|
// Run the pruner until the code does not change anymore.
|
||||||
static void runUntilStabilised(Block& _ast);
|
static void runUntilStabilised(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool used(std::string const& _name) const;
|
bool used(std::string const& _name) const;
|
||||||
|
@ -86,7 +86,7 @@ pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::yul::test::p
|
|||||||
assembly::Block dev::yul::test::disambiguate(string const& _source, bool _yul)
|
assembly::Block dev::yul::test::disambiguate(string const& _source, bool _yul)
|
||||||
{
|
{
|
||||||
auto result = parse(_source, _yul);
|
auto result = parse(_source, _yul);
|
||||||
return boost::get<Block>(Disambiguator(*result.second)(*result.first));
|
return boost::get<Block>(Disambiguator(*result.second, {})(*result.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
string dev::yul::test::format(string const& _source, bool _yul)
|
string dev::yul::test::format(string const& _source, bool _yul)
|
||||||
|
Loading…
Reference in New Issue
Block a user