mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #8863 from ethereum/nonReversedEncoder
Introduce non-reversed version of tupleEncoder.
This commit is contained in:
		
						commit
						f42dc70c9f
					
				| @ -37,7 +37,8 @@ using namespace solidity::frontend; | ||||
| string ABIFunctions::tupleEncoder( | ||||
| 	TypePointers const& _givenTypes, | ||||
| 	TypePointers const& _targetTypes, | ||||
| 	bool _encodeAsLibraryTypes | ||||
| 	bool _encodeAsLibraryTypes, | ||||
| 	bool _reversed | ||||
| ) | ||||
| { | ||||
| 	EncodingOptions options; | ||||
| @ -53,6 +54,8 @@ string ABIFunctions::tupleEncoder( | ||||
| 	for (auto const& t: _targetTypes) | ||||
| 		functionName += t->identifier() + "_"; | ||||
| 	functionName += options.toFunctionNameSuffix(); | ||||
| 	if (_reversed) | ||||
| 		functionName += "_reversed"; | ||||
| 
 | ||||
| 	return createFunction(functionName, [&]() { | ||||
| 		// Note that the values are in reverse due to the difference in calling semantics.
 | ||||
| @ -93,7 +96,10 @@ string ABIFunctions::tupleEncoder( | ||||
| 			stackPos += sizeOnStack; | ||||
| 		} | ||||
| 		solAssert(headPos == headSize_, ""); | ||||
| 		string valueParams = suffixedVariableNameList("value", stackPos, 0); | ||||
| 		string valueParams = | ||||
| 			_reversed ? | ||||
| 			suffixedVariableNameList("value", stackPos, 0) : | ||||
| 			suffixedVariableNameList("value", 0, stackPos); | ||||
| 		templ("valueParams", valueParams.empty() ? "" : ", " + valueParams); | ||||
| 		templ("encodeElements", encodeElements); | ||||
| 
 | ||||
| @ -103,7 +109,8 @@ string ABIFunctions::tupleEncoder( | ||||
| 
 | ||||
| string ABIFunctions::tupleEncoderPacked( | ||||
| 	TypePointers const& _givenTypes, | ||||
| 	TypePointers const& _targetTypes | ||||
| 	TypePointers const& _targetTypes, | ||||
| 	bool _reversed | ||||
| ) | ||||
| { | ||||
| 	EncodingOptions options; | ||||
| @ -119,6 +126,8 @@ string ABIFunctions::tupleEncoderPacked( | ||||
| 	for (auto const& t: _targetTypes) | ||||
| 		functionName += t->identifier() + "_"; | ||||
| 	functionName += options.toFunctionNameSuffix(); | ||||
| 	if (_reversed) | ||||
| 		functionName += "_reversed"; | ||||
| 
 | ||||
| 	return createFunction(functionName, [&]() { | ||||
| 		solAssert(!_givenTypes.empty(), ""); | ||||
| @ -157,7 +166,10 @@ string ABIFunctions::tupleEncoderPacked( | ||||
| 			encodeElements += elementTempl.render(); | ||||
| 			stackPos += sizeOnStack; | ||||
| 		} | ||||
| 		string valueParams = suffixedVariableNameList("value", stackPos, 0); | ||||
| 		string valueParams = | ||||
| 			_reversed ? | ||||
| 			suffixedVariableNameList("value", stackPos, 0) : | ||||
| 			suffixedVariableNameList("value", 0, stackPos); | ||||
| 		templ("valueParams", valueParams.empty() ? "" : ", " + valueParams); | ||||
| 		templ("encodeElements", encodeElements); | ||||
| 
 | ||||
|  | ||||
| @ -67,31 +67,53 @@ public: | ||||
| 
 | ||||
| 	/// @returns name of an assembly function to ABI-encode values of @a _givenTypes
 | ||||
| 	/// into memory, converting the types to @a _targetTypes on the fly.
 | ||||
| 	/// Parameters are: <headStart> <value_n> ... <value_1>, i.e.
 | ||||
| 	/// the layout on the stack is <value_1> ... <value_n> <headStart> with
 | ||||
| 	/// Parameters are: <headStart> <value_1> ... <value_n>, i.e.
 | ||||
| 	/// the layout on the stack is <value_n> ... <value_1> <headStart> with
 | ||||
| 	/// the top of the stack on the right.
 | ||||
| 	/// The values represent stack slots. If a type occupies more or less than one
 | ||||
| 	/// stack slot, it takes exactly that number of values.
 | ||||
| 	/// Returns a pointer to the end of the area written in memory.
 | ||||
| 	/// Does not allocate memory (does not change the free memory pointer), but writes
 | ||||
| 	/// to memory starting at $headStart and an unrestricted amount after that.
 | ||||
| 	/// If @reversed is true, the order of the variables after <headStart> is reversed.
 | ||||
| 	std::string tupleEncoder( | ||||
| 		TypePointers const& _givenTypes, | ||||
| 		TypePointers const& _targetTypes, | ||||
| 		bool _encodeAsLibraryTypes = false | ||||
| 		bool _encodeAsLibraryTypes = false, | ||||
| 		bool _reversed = false | ||||
| 	); | ||||
| 
 | ||||
| 	/// Specialization of tupleEncoder to _reversed = true
 | ||||
| 	std::string tupleEncoderReversed( | ||||
| 		TypePointers const& _givenTypes, | ||||
| 		TypePointers const& _targetTypes, | ||||
| 		bool _encodeAsLibraryTypes = false | ||||
| 	) { | ||||
| 		return tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes, true); | ||||
| 	} | ||||
| 
 | ||||
| 	/// @returns name of an assembly function to encode values of @a _givenTypes
 | ||||
| 	/// with packed encoding into memory, converting the types to @a _targetTypes on the fly.
 | ||||
| 	/// Parameters are: <memPos> <value_n> ... <value_1>, i.e.
 | ||||
| 	/// the layout on the stack is <value_1> ... <value_n> <memPos> with
 | ||||
| 	/// Parameters are: <memPos> <value_1> ... <value_n>, i.e.
 | ||||
| 	/// the layout on the stack is <value_n> ... <value_1> <memPos> with
 | ||||
| 	/// the top of the stack on the right.
 | ||||
| 	/// The values represent stack slots. If a type occupies more or less than one
 | ||||
| 	/// stack slot, it takes exactly that number of values.
 | ||||
| 	/// Returns a pointer to the end of the area written in memory.
 | ||||
| 	/// Does not allocate memory (does not change the free memory pointer), but writes
 | ||||
| 	/// to memory starting at memPos and an unrestricted amount after that.
 | ||||
| 	std::string tupleEncoderPacked(TypePointers const& _givenTypes, TypePointers const& _targetTypes); | ||||
| 	/// If @reversed is true, the order of the variables after <headStart> is reversed.
 | ||||
| 	std::string tupleEncoderPacked( | ||||
| 		TypePointers const& _givenTypes, | ||||
| 		TypePointers const& _targetTypes, | ||||
| 		bool _reversed = false | ||||
| 	); | ||||
| 
 | ||||
| 	/// Specialization of tupleEncoderPacked to _reversed = true
 | ||||
| 	std::string tupleEncoderPackedReversed(TypePointers const& _givenTypes, TypePointers const& _targetTypes) | ||||
| 	{ | ||||
| 		return tupleEncoderPacked(_givenTypes, _targetTypes, true); | ||||
| 	} | ||||
| 
 | ||||
| 	/// @returns name of an assembly function to ABI-decode values of @a _types
 | ||||
| 	/// into memory. If @a _fromMemory is true, decodes from memory instead of
 | ||||
|  | ||||
| @ -559,8 +559,8 @@ void CompilerUtils::abiEncodeV2( | ||||
| 
 | ||||
| 	string encoderName = | ||||
| 		_padToWordBoundaries ? | ||||
| 		m_context.abiFunctions().tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes) : | ||||
| 		m_context.abiFunctions().tupleEncoderPacked(_givenTypes, _targetTypes); | ||||
| 		m_context.abiFunctions().tupleEncoderReversed(_givenTypes, _targetTypes, _encodeAsLibraryTypes) : | ||||
| 		m_context.abiFunctions().tupleEncoderPackedReversed(_givenTypes, _targetTypes); | ||||
| 	m_context.callYulFunction(encoderName, sizeOnStack(_givenTypes) + 1, 1); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1122,13 +1122,12 @@ string YulUtilFunctions::mappingIndexAccessFunction(MappingType const& _mappingT | ||||
| 	return m_functionCollector.createFunction(functionName, [&]() { | ||||
| 		if (_mappingType.keyType()->isDynamicallySized()) | ||||
| 			return Whiskers(R"( | ||||
| 				function <functionName>(slot <comma> <key>) -> dataSlot { | ||||
| 					dataSlot := <hash>(slot <comma> <key>) | ||||
| 				function <functionName>(slot <?+key>,</+key> <key>) -> dataSlot { | ||||
| 					dataSlot := <hash>(<key> <?+key>,</+key> slot) | ||||
| 				} | ||||
| 			)") | ||||
| 			("functionName", functionName) | ||||
| 			("key", _keyType.sizeOnStack() > 0 ? "key" : "") | ||||
| 			("comma", _keyType.sizeOnStack() > 0 ? "," : "") | ||||
| 			("hash", packedHashFunction( | ||||
| 				{&_keyType, TypeProvider::uint256()}, | ||||
| 				{_mappingType.keyType(), TypeProvider::uint256()} | ||||
|  | ||||
| @ -479,10 +479,10 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) | ||||
| 			{ | ||||
| 				// <functionName>
 | ||||
| 				<callValueCheck> | ||||
| 				<assignToParams> <abiDecode>(4, calldatasize()) | ||||
| 				<assignToRetParams> <function>(<params>) | ||||
| 				<?+params>let <params> := </+params> <abiDecode>(4, calldatasize()) | ||||
| 				<?+retParams>let <retParams> := </+retParams> <function>(<params>) | ||||
| 				let memPos := <allocate>(0) | ||||
| 				let memEnd := <abiEncode>(memPos <comma> <retParams>) | ||||
| 				let memEnd := <abiEncode>(memPos <?+retParams>,</+retParams> <retParams>) | ||||
| 				return(memPos, sub(memEnd, memPos)) | ||||
| 			} | ||||
| 			</cases> | ||||
| @ -504,13 +504,11 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) | ||||
| 
 | ||||
| 		unsigned paramVars = make_shared<TupleType>(type->parameterTypes())->sizeOnStack(); | ||||
| 		unsigned retVars = make_shared<TupleType>(type->returnParameterTypes())->sizeOnStack(); | ||||
| 		templ["assignToParams"] = paramVars == 0 ? "" : "let " + suffixedVariableNameList("param_", 0, paramVars) + " := "; | ||||
| 		templ["assignToRetParams"] = retVars == 0 ? "" : "let " + suffixedVariableNameList("ret_", 0, retVars) + " := "; | ||||
| 
 | ||||
| 		ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector()); | ||||
| 		templ["abiDecode"] = abiFunctions.tupleDecoder(type->parameterTypes()); | ||||
| 		templ["params"] = suffixedVariableNameList("param_", 0, paramVars); | ||||
| 		templ["retParams"] = suffixedVariableNameList("ret_", retVars, 0); | ||||
| 		templ["retParams"] = suffixedVariableNameList("ret_", 0, retVars); | ||||
| 
 | ||||
| 		if (FunctionDefinition const* funDef = dynamic_cast<FunctionDefinition const*>(&type->declaration())) | ||||
| 			templ["function"] = m_context.enqueueFunctionForCodeGeneration(*funDef); | ||||
| @ -521,7 +519,6 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) | ||||
| 
 | ||||
| 		templ["allocate"] = m_utils.allocationFunction(); | ||||
| 		templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), false); | ||||
| 		templ["comma"] = retVars == 0 ? "" : ", "; | ||||
| 	} | ||||
| 	t("cases", functions); | ||||
| 	if (FunctionDefinition const* fallback = _contract.fallbackFunction()) | ||||
|  | ||||
| @ -741,8 +741,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) | ||||
| 			{ | ||||
| 				string vars = IRVariable(arg).commaSeparatedList(); | ||||
| 				if (!vars.empty()) | ||||
| 					// In reverse because abi_encode expects it like that.
 | ||||
| 					nonIndexedArgs = ", " + move(vars) + nonIndexedArgs; | ||||
| 					nonIndexedArgs += ", " + move(vars); | ||||
| 				nonIndexedArgTypes.push_back(arg.annotation().type); | ||||
| 				nonIndexedParamTypes.push_back(paramTypes[i]); | ||||
| 			} | ||||
| @ -1022,7 +1021,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) | ||||
| 		t("releaseTemporaryMemory", m_utils.releaseTemporaryMemoryFunction()); | ||||
| 		t("object", m_context.creationObjectName(*contract)); | ||||
| 		t("abiEncode", | ||||
| 			m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(),false) | ||||
| 			m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false) | ||||
| 		); | ||||
| 		t("constructorParams", constructorParams); | ||||
| 		t("value", functionType->valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); | ||||
|  | ||||
| @ -38,7 +38,7 @@ object \"C_10\" { | ||||
|                     abi_decode_tuple_(4, calldatasize()) | ||||
|                     let ret_0 :=  fun_f_9() | ||||
|                     let memPos := allocateMemory(0) | ||||
|                     let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos ,  ret_0) | ||||
|                     let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) | ||||
|                     return(memPos, sub(memEnd, memPos)) | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -38,7 +38,7 @@ object \"C_10\" { | ||||
|                     abi_decode_tuple_(4, calldatasize()) | ||||
|                     let ret_0 :=  fun_f_9() | ||||
|                     let memPos := allocateMemory(0) | ||||
|                     let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos ,  ret_0) | ||||
|                     let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0) | ||||
|                     return(memPos, sub(memEnd, memPos)) | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -38,7 +38,7 @@ object \"C_10\" { | ||||
|                     abi_decode_tuple_(4, calldatasize()) | ||||
|                     let ret_0 :=  fun_f_9() | ||||
|                     let memPos := allocateMemory(0) | ||||
|                     let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos ,  ret_0) | ||||
|                     let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) | ||||
|                     return(memPos, sub(memEnd, memPos)) | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -38,7 +38,7 @@ object \"C_10\" { | ||||
|                     abi_decode_tuple_(4, calldatasize()) | ||||
|                     let ret_0 :=  fun_f_9() | ||||
|                     let memPos := allocateMemory(0) | ||||
|                     let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos ,  ret_0) | ||||
|                     let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) | ||||
|                     return(memPos, sub(memEnd, memPos)) | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -38,7 +38,7 @@ object \"C_10\" { | ||||
|                     abi_decode_tuple_(4, calldatasize()) | ||||
|                     let ret_0 :=  fun_f_9() | ||||
|                     let memPos := allocateMemory(0) | ||||
|                     let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos ,  ret_0) | ||||
|                     let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) | ||||
|                     return(memPos, sub(memEnd, memPos)) | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -7,6 +7,8 @@ contract C { | ||||
|         return this.f(x); | ||||
|     } | ||||
| } | ||||
| // ==== | ||||
| // compileViaYul: also | ||||
| // ---- | ||||
| // g(uint256[][2][]): 0x20, 0x01, 0x20, 0x40, 0x60, 0x00, 0x00 -> 42 | ||||
| // g(uint256[][2][]): 0x20, 0x01, 0x20, 0x00, 0x00 -> 42 | ||||
|  | ||||
| @ -16,6 +16,8 @@ contract C { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // ==== | ||||
| // compileViaYul: also | ||||
| // ---- | ||||
| // f(uint256): 7 -> 8 | ||||
| // f2(uint256): 7 -> 8 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user