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