mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Extract subIDs from Dialect to allow it being const.
This commit is contained in:
		
							parent
							
								
									e20fbd388b
								
							
						
					
					
						commit
						7de150924c
					
				| @ -45,12 +45,13 @@ map<YulString, int> CompilabilityChecker::run( | ||||
| 
 | ||||
| 	solAssert(dynamic_cast<EVMDialect const*>(_dialect.get()), ""); | ||||
| 	shared_ptr<NoOutputEVMDialect> noOutputDialect = make_shared<NoOutputEVMDialect>(dynamic_pointer_cast<EVMDialect>(_dialect)); | ||||
| 	BuiltinContext builtinContext; | ||||
| 
 | ||||
| 	yul::AsmAnalysisInfo analysisInfo = | ||||
| 		yul::AsmAnalyzer::analyzeStrictAssertCorrect(noOutputDialect, _ast); | ||||
| 
 | ||||
| 	NoOutputAssembly assembly; | ||||
| 	CodeTransform transform(assembly, analysisInfo, _ast, *noOutputDialect, _optimizeStackAllocation); | ||||
| 	CodeTransform transform(assembly, analysisInfo, _ast, *noOutputDialect, builtinContext, _optimizeStackAllocation); | ||||
| 	try | ||||
| 	{ | ||||
| 		transform(_ast); | ||||
|  | ||||
| @ -185,11 +185,13 @@ void CodeGenerator::assemble( | ||||
| { | ||||
| 	EthAssemblyAdapter assemblyAdapter(_assembly); | ||||
| 	shared_ptr<EVMDialect> dialect = EVMDialect::strictAssemblyForEVM(_evmVersion); | ||||
| 	BuiltinContext builtinContext; | ||||
| 	CodeTransform transform( | ||||
| 		assemblyAdapter, | ||||
| 		_analysisInfo, | ||||
| 		_parsedData, | ||||
| 		*dialect, | ||||
| 		builtinContext, | ||||
| 		_optimizeStackAllocation, | ||||
| 		false, | ||||
| 		_identifierAccess, | ||||
|  | ||||
| @ -96,6 +96,7 @@ CodeTransform::CodeTransform( | ||||
| 	Block const& _block, | ||||
| 	bool _allowStackOpt, | ||||
| 	EVMDialect const& _dialect, | ||||
| 	BuiltinContext& _builtinContext, | ||||
| 	bool _evm15, | ||||
| 	ExternalIdentifierAccess const& _identifierAccess, | ||||
| 	bool _useNamedLabelsForFunctions, | ||||
| @ -105,6 +106,7 @@ CodeTransform::CodeTransform( | ||||
| 	m_assembly(_assembly), | ||||
| 	m_info(_analysisInfo), | ||||
| 	m_dialect(_dialect), | ||||
| 	m_builtinContext(_builtinContext), | ||||
| 	m_allowStackOpt(_allowStackOpt), | ||||
| 	m_evm15(_evm15), | ||||
| 	m_useNamedLabelsForFunctions(_useNamedLabelsForFunctions), | ||||
| @ -280,7 +282,7 @@ void CodeTransform::operator()(FunctionCall const& _call) | ||||
| 
 | ||||
| 	if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) | ||||
| 	{ | ||||
| 		builtin->generateCode(_call, m_assembly, [&]() { | ||||
| 		builtin->generateCode(_call, m_assembly, m_builtinContext, [&]() { | ||||
| 			for (auto const& arg: _call.arguments | boost::adaptors::reversed) | ||||
| 				visitExpression(arg); | ||||
| 			m_assembly.setSourceLocation(_call.location); | ||||
| @ -519,6 +521,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) | ||||
| 			_function.body, | ||||
| 			m_allowStackOpt, | ||||
| 			m_dialect, | ||||
| 			m_builtinContext, | ||||
| 			m_evm15, | ||||
| 			m_identifierAccess, | ||||
| 			m_useNamedLabelsForFunctions, | ||||
|  | ||||
| @ -121,6 +121,7 @@ public: | ||||
| 		AsmAnalysisInfo& _analysisInfo, | ||||
| 		Block const& _block, | ||||
| 		EVMDialect const& _dialect, | ||||
| 		BuiltinContext& _builtinContext, | ||||
| 		bool _allowStackOpt = false, | ||||
| 		bool _evm15 = false, | ||||
| 		ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess(), | ||||
| @ -131,6 +132,7 @@ public: | ||||
| 		_block, | ||||
| 		_allowStackOpt, | ||||
| 		_dialect, | ||||
| 		_builtinContext, | ||||
| 		_evm15, | ||||
| 		_identifierAccess, | ||||
| 		_useNamedLabelsForFunctions, | ||||
| @ -151,6 +153,7 @@ protected: | ||||
| 		Block const& _block, | ||||
| 		bool _allowStackOpt, | ||||
| 		EVMDialect const& _dialect, | ||||
| 		BuiltinContext& _builtinContext, | ||||
| 		bool _evm15, | ||||
| 		ExternalIdentifierAccess const& _identifierAccess, | ||||
| 		bool _useNamedLabelsForFunctions, | ||||
| @ -225,6 +228,7 @@ private: | ||||
| 	AsmAnalysisInfo& m_info; | ||||
| 	Scope* m_scope = nullptr; | ||||
| 	EVMDialect const& m_dialect; | ||||
| 	BuiltinContext& m_builtinContext; | ||||
| 	bool const m_allowStackOpt = true; | ||||
| 	bool const m_evm15 = false; | ||||
| 	bool const m_useNamedLabelsForFunctions = false; | ||||
|  | ||||
| @ -42,43 +42,52 @@ EVMDialect::EVMDialect(AsmFlavour _flavour, bool _objectAccess, langutil::EVMVer | ||||
| 	if (!m_objectAccess) | ||||
| 		return; | ||||
| 
 | ||||
| 	addFunction("datasize", 1, 1, true, true, true, [this]( | ||||
| 	addFunction("datasize", 1, 1, true, true, true, []( | ||||
| 		FunctionCall const& _call, | ||||
| 		AbstractAssembly& _assembly, | ||||
| 		BuiltinContext& _context, | ||||
| 		std::function<void()> | ||||
| 	) { | ||||
| 		yulAssert(m_currentObject, "No object available."); | ||||
| 		yulAssert(_context.currentObject, "No object available."); | ||||
| 		yulAssert(_call.arguments.size() == 1, ""); | ||||
| 		Expression const& arg = _call.arguments.front(); | ||||
| 		YulString dataName = boost::get<Literal>(arg).value; | ||||
| 		if (m_currentObject->name == dataName) | ||||
| 		if (_context.currentObject->name == dataName) | ||||
| 			_assembly.appendAssemblySize(); | ||||
| 		else | ||||
| 		{ | ||||
| 			yulAssert(m_subIDs.count(dataName) != 0, "Could not find assembly object <" + dataName.str() + ">."); | ||||
| 			_assembly.appendDataSize(m_subIDs.at(dataName)); | ||||
| 			yulAssert( | ||||
| 				_context.subIDs.count(dataName) != 0, | ||||
| 				"Could not find assembly object <" + dataName.str() + ">." | ||||
| 			); | ||||
| 			_assembly.appendDataSize(_context.subIDs.at(dataName)); | ||||
| 		} | ||||
| 	}); | ||||
| 	addFunction("dataoffset", 1, 1, true, true, true, [this]( | ||||
| 	addFunction("dataoffset", 1, 1, true, true, true, []( | ||||
| 		FunctionCall const& _call, | ||||
| 		AbstractAssembly& _assembly, | ||||
| 		BuiltinContext& _context, | ||||
| 		std::function<void()> | ||||
| 	) { | ||||
| 		yulAssert(m_currentObject, "No object available."); | ||||
| 		yulAssert(_context.currentObject, "No object available."); | ||||
| 		yulAssert(_call.arguments.size() == 1, ""); | ||||
| 		Expression const& arg = _call.arguments.front(); | ||||
| 		YulString dataName = boost::get<Literal>(arg).value; | ||||
| 		if (m_currentObject->name == dataName) | ||||
| 		if (_context.currentObject->name == dataName) | ||||
| 			_assembly.appendConstant(0); | ||||
| 		else | ||||
| 		{ | ||||
| 			yulAssert(m_subIDs.count(dataName) != 0, "Could not find assembly object <" + dataName.str() + ">."); | ||||
| 			_assembly.appendDataOffset(m_subIDs.at(dataName)); | ||||
| 			yulAssert( | ||||
| 				_context.subIDs.count(dataName) != 0, | ||||
| 				"Could not find assembly object <" + dataName.str() + ">." | ||||
| 			); | ||||
| 			_assembly.appendDataOffset(_context.subIDs.at(dataName)); | ||||
| 		} | ||||
| 	}); | ||||
| 	addFunction("datacopy", 3, 0, false, false, false, []( | ||||
| 		FunctionCall const&, | ||||
| 		AbstractAssembly& _assembly, | ||||
| 		BuiltinContext&, | ||||
| 		std::function<void()> _visitArguments | ||||
| 	) { | ||||
| 		_visitArguments(); | ||||
| @ -115,18 +124,6 @@ shared_ptr<yul::EVMDialect> EVMDialect::yulForEVM(langutil::EVMVersion _version) | ||||
| 	return make_shared<EVMDialect>(AsmFlavour::Yul, false, _version); | ||||
| } | ||||
| 
 | ||||
| void EVMDialect::setSubIDs(map<YulString, AbstractAssembly::SubID> _subIDs) | ||||
| { | ||||
| 	yulAssert(m_objectAccess, "Sub IDs set with dialect that does not support object access."); | ||||
| 	m_subIDs = std::move(_subIDs); | ||||
| } | ||||
| 
 | ||||
| void EVMDialect::setCurrentObject(Object const* _object) | ||||
| { | ||||
| 	yulAssert(m_objectAccess, "Current object set with dialect that does not support object access."); | ||||
| 	m_currentObject = _object; | ||||
| } | ||||
| 
 | ||||
| void EVMDialect::addFunction( | ||||
| 	string _name, | ||||
| 	size_t _params, | ||||
| @ -134,7 +131,7 @@ void EVMDialect::addFunction( | ||||
| 	bool _movable, | ||||
| 	bool _sideEffectFree, | ||||
| 	bool _literalArguments, | ||||
| 	std::function<void(FunctionCall const&, AbstractAssembly&, std::function<void()>)> _generateCode | ||||
| 	std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&, std::function<void()>)> _generateCode | ||||
| ) | ||||
| { | ||||
| 	YulString name{std::move(_name)}; | ||||
|  | ||||
| @ -35,14 +35,25 @@ using Type = YulString; | ||||
| struct FunctionCall; | ||||
| struct Object; | ||||
| 
 | ||||
| /**
 | ||||
|  * Context used during code generation. | ||||
|  */ | ||||
| struct BuiltinContext | ||||
| { | ||||
| 	Object const* currentObject = nullptr; | ||||
| 	/// Mapping from named objects to abstract assembly sub IDs.
 | ||||
| 	std::map<YulString, AbstractAssembly::SubID> subIDs; | ||||
| }; | ||||
| 
 | ||||
| struct BuiltinFunctionForEVM: BuiltinFunction | ||||
| { | ||||
| 	/// Function to generate code for the given function call and append it to the abstract
 | ||||
| 	/// assembly. The third parameter is called to visit (and generate code for) the arguments
 | ||||
| 	/// assembly. The fourth parameter is called to visit (and generate code for) the arguments
 | ||||
| 	/// from right to left.
 | ||||
| 	std::function<void(FunctionCall const&, AbstractAssembly&, std::function<void()>)> generateCode; | ||||
| 	std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&, std::function<void()>)> generateCode; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Yul dialect for EVM as a backend. | ||||
|  * The main difference is that the builtin functions take an AbstractAssembly for the | ||||
| @ -64,11 +75,6 @@ struct EVMDialect: public Dialect | ||||
| 
 | ||||
| 	bool providesObjectAccess() const { return m_objectAccess; } | ||||
| 
 | ||||
| 	/// Sets the mapping of current sub assembly IDs. Used during code generation.
 | ||||
| 	void setSubIDs(std::map<YulString, AbstractAssembly::SubID> _subIDs); | ||||
| 	/// Sets the current object. Used during code generation.
 | ||||
| 	void setCurrentObject(Object const* _object); | ||||
| 
 | ||||
| protected: | ||||
| 	void addFunction( | ||||
| 		std::string _name, | ||||
| @ -77,14 +83,11 @@ protected: | ||||
| 		bool _movable, | ||||
| 		bool _sideEffectFree, | ||||
| 		bool _literalArguments, | ||||
| 		std::function<void(FunctionCall const&, AbstractAssembly&, std::function<void()>)> _generateCode | ||||
| 		std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&, std::function<void()>)> _generateCode | ||||
| 	); | ||||
| 
 | ||||
| 	bool m_objectAccess; | ||||
| 	langutil::EVMVersion m_evmVersion; | ||||
| 	Object const* m_currentObject = nullptr; | ||||
| 	/// Mapping from named objects to abstract assembly sub IDs.
 | ||||
| 	std::map<YulString, AbstractAssembly::SubID> m_subIDs; | ||||
| 	std::map<YulString, BuiltinFunctionForEVM> m_functions; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -37,32 +37,27 @@ void EVMObjectCompiler::compile(Object& _object, AbstractAssembly& _assembly, EV | ||||
| 
 | ||||
| void EVMObjectCompiler::run(Object& _object, bool _optimize) | ||||
| { | ||||
| 	map<YulString, AbstractAssembly::SubID> subIDs; | ||||
| 	BuiltinContext context; | ||||
| 	context.currentObject = &_object; | ||||
| 
 | ||||
| 	for (auto& subNode: _object.subObjects) | ||||
| 		if (Object* subObject = dynamic_cast<Object*>(subNode.get())) | ||||
| 		{ | ||||
| 			auto subAssemblyAndID = m_assembly.createSubAssembly(); | ||||
| 			subIDs[subObject->name] = subAssemblyAndID.second; | ||||
| 			context.subIDs[subObject->name] = subAssemblyAndID.second; | ||||
| 			compile(*subObject, *subAssemblyAndID.first, m_dialect, m_evm15, _optimize); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			Data const& data = dynamic_cast<Data const&>(*subNode); | ||||
| 			subIDs[data.name] = m_assembly.appendData(data.data); | ||||
| 			context.subIDs[data.name] = m_assembly.appendData(data.data); | ||||
| 		} | ||||
| 
 | ||||
| 	if (m_dialect.providesObjectAccess()) | ||||
| 	{ | ||||
| 		m_dialect.setSubIDs(std::move(subIDs)); | ||||
| 		m_dialect.setCurrentObject(&_object); | ||||
| 	} | ||||
| 
 | ||||
| 	yulAssert(_object.analysisInfo, "No analysis info."); | ||||
| 	yulAssert(_object.code, "No code."); | ||||
| 	// We do not catch and re-throw the stack too deep exception here because it is a YulException,
 | ||||
| 	// which should be native to this part of the code.
 | ||||
| 	CodeTransform transform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, _optimize, m_evm15}; | ||||
| 	CodeTransform transform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, context, _optimize, m_evm15}; | ||||
| 	transform(*_object.code); | ||||
| 	yulAssert(transform.stackErrors().empty(), "Stack errors present but not thrown."); | ||||
| } | ||||
|  | ||||
| @ -149,7 +149,7 @@ NoOutputEVMDialect::NoOutputEVMDialect(shared_ptr<EVMDialect> const& _copyFrom): | ||||
| 	{ | ||||
| 		size_t parameters = fun.second.parameters.size(); | ||||
| 		size_t returns = fun.second.returns.size(); | ||||
| 		fun.second.generateCode = [=](FunctionCall const&, AbstractAssembly& _assembly, std::function<void()> _visitArguments) | ||||
| 		fun.second.generateCode = [=](FunctionCall const&, AbstractAssembly& _assembly, BuiltinContext&, std::function<void()> _visitArguments) | ||||
| 		{ | ||||
| 			_visitArguments(); | ||||
| 			for (size_t i = 0; i < parameters; i++) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user