mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #10353 from ethereum/copyStructCalldata2MemSol2Yul
[Sol->Yul] Implementing copying dynamically encoded structs from calldata to memory
This commit is contained in:
		
						commit
						d2e2f3a994
					
				| @ -170,6 +170,11 @@ public: | ||||
| 	/// signature: (dataOffset, length, dataEnd) -> decodedArray
 | ||||
| 	std::string abiDecodingFunctionArrayAvailableLength(ArrayType const& _type, bool _fromMemory); | ||||
| 
 | ||||
| 	/// Internal decoding function that is also used by some copying routines.
 | ||||
| 	/// @returns the name of a function that decodes structs.
 | ||||
| 	/// signature: (dataStart, dataEnd) -> decodedStruct
 | ||||
| 	std::string abiDecodingFunctionStruct(StructType const& _type, bool _fromMemory); | ||||
| 
 | ||||
| private: | ||||
| 	/// Part of @a abiEncodingFunction for array target type and given calldata array.
 | ||||
| 	/// Uses calldatacopy and does not perform cleanup or validation and can therefore only
 | ||||
| @ -245,8 +250,6 @@ private: | ||||
| 	std::string abiDecodingFunctionCalldataStruct(StructType const& _type); | ||||
| 	/// Part of @a abiDecodingFunction for array types.
 | ||||
| 	std::string abiDecodingFunctionFunctionType(FunctionType const& _type, bool _fromMemory, bool _forUseOnStack); | ||||
| 	/// Part of @a abiDecodingFunction for struct types.
 | ||||
| 	std::string abiDecodingFunctionStruct(StructType const& _type, bool _fromMemory); | ||||
| 	/// @returns the name of a function that retrieves an element from calldata.
 | ||||
| 	std::string calldataAccessFunction(Type const& _type); | ||||
| 
 | ||||
|  | ||||
| @ -2992,14 +2992,16 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) | ||||
| 				solUnimplementedAssert(fromStructType.location() != DataLocation::Memory, ""); | ||||
| 
 | ||||
| 				if (fromStructType.location() == DataLocation::CallData) | ||||
| 				{ | ||||
| 					solUnimplementedAssert(!fromStructType.isDynamicallyEncoded(), ""); | ||||
| 					body = Whiskers(R"( | ||||
| 						converted := <abiDecode>(value, calldatasize()) | ||||
| 					)")("abiDecode", ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).tupleDecoder( | ||||
| 						{&toStructType} | ||||
| 					)).render(); | ||||
| 				} | ||||
| 					)") | ||||
| 					( | ||||
| 						"abiDecode", | ||||
| 						ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).abiDecodingFunctionStruct( | ||||
| 							toStructType, | ||||
| 							false | ||||
| 						) | ||||
| 					).render(); | ||||
| 				else | ||||
| 				{ | ||||
| 					solAssert(fromStructType.location() == DataLocation::Storage, ""); | ||||
|  | ||||
| @ -0,0 +1,49 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| contract C { | ||||
|     struct S { | ||||
|         uint128 p1; | ||||
|         uint256[][2] a; | ||||
|         uint32 p2; | ||||
|     } | ||||
| 
 | ||||
|     struct S1 { | ||||
|         uint128 u; | ||||
|         S s; | ||||
|     } | ||||
| 
 | ||||
|     struct S2 { | ||||
|         S[2] array; | ||||
|     } | ||||
| 
 | ||||
|     function f1(S1 calldata c) internal returns(S1 calldata) { | ||||
|         return c; | ||||
|     } | ||||
| 
 | ||||
|     function f(S1 calldata c, uint32 p) external returns(uint32, uint128, uint256, uint256, uint32) { | ||||
|         S1 memory m = f1(c); | ||||
|         assert(m.s.a[0][0] == c.s.a[0][0]); | ||||
|         assert(m.s.a[1][1] == c.s.a[1][1]); | ||||
|         return (p, m.s.p1, m.s.a[0][0], m.s.a[1][1], m.s.p2); | ||||
|     } | ||||
| 
 | ||||
|     function g(S2 calldata c) external returns(uint128, uint256, uint256, uint32) { | ||||
|         S2 memory m = c; | ||||
|         assert(m.array[0].a[0][0] == c.array[0].a[0][0]); | ||||
|         assert(m.array[0].a[1][1] == c.array[0].a[1][1]); | ||||
|         return (m.array[1].p1, m.array[1].a[0][0], m.array[1].a[1][1], m.array[1].p2); | ||||
|     } | ||||
| 
 | ||||
|     function h(S1 calldata c, uint32 p) external returns(uint32, uint128, uint256, uint256, uint32) { | ||||
|         S memory m = c.s; | ||||
|         assert(m.a[0][0] == c.s.a[0][0]); | ||||
|         assert(m.a[1][1] == c.s.a[1][1]); | ||||
|         return (p, m.p1, m.a[0][0], m.a[1][1], m.p2); | ||||
|     } | ||||
| } | ||||
| // ==== | ||||
| // compileViaYul: true | ||||
| // ---- | ||||
| // f((uint128, (uint128, uint256[][2], uint32)), uint32): 0x40, 44, 11, 0x40, 22, 0x60, 33, 0x40, 0x40, 2, 1, 2 -> 44, 22, 1, 2, 33 | ||||
| // g(((uint128, uint256[][2], uint32)[2])): 0x20, 0x20, 0x40, 0x40, 22, 0x60, 33, 0x40, 0x40, 2, 1, 2 -> 22, 1, 2, 33 | ||||
| // h((uint128, (uint128, uint256[][2], uint32)), uint32): 0x40, 44, 11, 0x40, 22, 0x60, 33, 0x40, 0x40, 2, 1, 2 -> 44, 22, 1, 2, 33 | ||||
| @ -0,0 +1,29 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| struct S { | ||||
|     uint128 p1; | ||||
|     uint256[][2] a; | ||||
|     uint32 p2; | ||||
| } | ||||
| struct S1 { | ||||
|     uint128 u; | ||||
|     S s; | ||||
| } | ||||
| 
 | ||||
| library L { | ||||
|     function f(S1 memory m, uint32 p) external returns(uint32, uint128, uint256, uint256, uint32) { | ||||
|         return (p, m.s.p1, m.s.a[0][0], m.s.a[1][1], m.s.p2); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| contract C { | ||||
| 
 | ||||
|     function f(S1 calldata c, uint32 p) external returns(uint32, uint128, uint256, uint256, uint32) { | ||||
|         return L.f(c, p); | ||||
|     } | ||||
| } | ||||
| // ==== | ||||
| // compileViaYul: true | ||||
| // ---- | ||||
| // library: L | ||||
| // f((uint128, (uint128, uint256[][2], uint32)), uint32): 0x40, 44, 11, 0x40, 22, 0x60, 33, 0x40, 0x40, 2, 1, 2 -> 44, 22, 1, 2, 33 | ||||
| @ -0,0 +1,23 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| contract C { | ||||
|     struct S { | ||||
|         uint128 p1; | ||||
|         uint256[][2] a; | ||||
|         uint32 p2; | ||||
|     } | ||||
| 
 | ||||
|     function g(uint32 p1, S memory s) internal returns(uint32, uint128, uint256, uint256, uint32) { | ||||
|         s.p1++; | ||||
|         s.a[0][1]++; | ||||
|         return (p1, s.p1, s.a[0][0], s.a[1][1], s.p2); | ||||
|     } | ||||
| 
 | ||||
|     function f(uint32 p1, S calldata c) external returns(uint32, uint128, uint256, uint256, uint32) { | ||||
|         return g(p1, c); | ||||
|     } | ||||
| } | ||||
| // ==== | ||||
| // compileViaYul: true | ||||
| // ---- | ||||
| // f(uint32, (uint128, uint256[][2], uint32)): 55, 0x40, 77, 0x60, 88, 0x40, 0x40, 2, 1, 2 -> 55, 78, 1, 2, 88 | ||||
| @ -0,0 +1,22 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| contract C { | ||||
|     struct S { | ||||
|         uint128 p1; | ||||
|         uint256[][2] a; | ||||
|         uint32 p2; | ||||
|     } | ||||
| 
 | ||||
|     function f(uint32 p1, S calldata c) external returns(uint32, uint128, uint256, uint256, uint32) { | ||||
|         S memory m; | ||||
|         uint32 p2; | ||||
|         (p2, m) = (p1, c); | ||||
|         m.p1++; | ||||
|         m.a[0][1]++; | ||||
|         return (p2, m.p1, m.a[0][0], m.a[1][1], m.p2); | ||||
|     } | ||||
| } | ||||
| // ==== | ||||
| // compileViaYul: true | ||||
| // ---- | ||||
| // f(uint32, (uint128, uint256[][2], uint32)): 55, 0x40, 77, 0x60, 88, 0x40, 0x40, 2, 1, 2 -> 55, 78, 1, 2, 88 | ||||
| @ -0,0 +1,23 @@ | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| contract C { | ||||
|     struct S { | ||||
|         uint128 p1; | ||||
|         uint256[][2] a; | ||||
|         uint32 p2; | ||||
|     } | ||||
|     function f(uint32 p1, S calldata c) external returns(uint32, uint128, uint256, uint256, uint32) { | ||||
|         S memory s = c; | ||||
|         assert(s.a[0][0] == c.a[0][0]); | ||||
|         assert(s.a[1][1] == c.a[1][1]); | ||||
|         s.p1++; | ||||
|         assert(s.p1 != c.p1); | ||||
|         s.a[0][1]++; | ||||
|         assert(s.a[0][1] != c.a[0][1]); | ||||
|         return (p1, s.p1, s.a[0][0], s.a[1][1], s.p2); | ||||
|     } | ||||
| } | ||||
| // ==== | ||||
| // compileViaYul: true | ||||
| // ---- | ||||
| // f(uint32, (uint128, uint256[][2], uint32)): 55, 0x40, 77, 0x60, 88, 0x40, 0x40, 2, 1, 2 -> 55, 78, 1, 2, 88 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user