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
|
/// signature: (dataOffset, length, dataEnd) -> decodedArray
|
||||||
std::string abiDecodingFunctionArrayAvailableLength(ArrayType const& _type, bool _fromMemory);
|
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:
|
private:
|
||||||
/// Part of @a abiEncodingFunction for array target type and given calldata array.
|
/// 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
|
/// Uses calldatacopy and does not perform cleanup or validation and can therefore only
|
||||||
@ -245,8 +250,6 @@ private:
|
|||||||
std::string abiDecodingFunctionCalldataStruct(StructType const& _type);
|
std::string abiDecodingFunctionCalldataStruct(StructType const& _type);
|
||||||
/// Part of @a abiDecodingFunction for array types.
|
/// Part of @a abiDecodingFunction for array types.
|
||||||
std::string abiDecodingFunctionFunctionType(FunctionType const& _type, bool _fromMemory, bool _forUseOnStack);
|
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.
|
/// @returns the name of a function that retrieves an element from calldata.
|
||||||
std::string calldataAccessFunction(Type const& _type);
|
std::string calldataAccessFunction(Type const& _type);
|
||||||
|
|
||||||
|
@ -2992,14 +2992,16 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
solUnimplementedAssert(fromStructType.location() != DataLocation::Memory, "");
|
solUnimplementedAssert(fromStructType.location() != DataLocation::Memory, "");
|
||||||
|
|
||||||
if (fromStructType.location() == DataLocation::CallData)
|
if (fromStructType.location() == DataLocation::CallData)
|
||||||
{
|
|
||||||
solUnimplementedAssert(!fromStructType.isDynamicallyEncoded(), "");
|
|
||||||
body = Whiskers(R"(
|
body = Whiskers(R"(
|
||||||
converted := <abiDecode>(value, calldatasize())
|
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
|
else
|
||||||
{
|
{
|
||||||
solAssert(fromStructType.location() == DataLocation::Storage, "");
|
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