mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Refactor abi encoding functions to prepare implementing calldata arrays and structs.
This commit is contained in:
parent
b0cb330397
commit
d82157d46a
@ -1106,11 +1106,9 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
|||||||
_to.identifier() +
|
_to.identifier() +
|
||||||
_options.toFunctionNameSuffix();
|
_options.toFunctionNameSuffix();
|
||||||
|
|
||||||
solUnimplementedAssert(!_from.dataStoredIn(DataLocation::CallData), "Encoding struct from calldata is not yet supported.");
|
|
||||||
solAssert(&_from.structDefinition() == &_to.structDefinition(), "");
|
solAssert(&_from.structDefinition() == &_to.structDefinition(), "");
|
||||||
|
|
||||||
return createFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
bool fromStorage = _from.location() == DataLocation::Storage;
|
|
||||||
bool dynamic = _to.isDynamicallyEncoded();
|
bool dynamic = _to.isDynamicallyEncoded();
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
||||||
@ -1121,7 +1119,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
|||||||
{
|
{
|
||||||
// <memberName>
|
// <memberName>
|
||||||
<preprocess>
|
<preprocess>
|
||||||
let memberValue := <retrieveValue>
|
let <memberValues> := <retrieveValue>
|
||||||
<encode>
|
<encode>
|
||||||
}
|
}
|
||||||
</members>
|
</members>
|
||||||
@ -1139,7 +1137,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
|||||||
else
|
else
|
||||||
templ("assignEnd", "");
|
templ("assignEnd", "");
|
||||||
// to avoid multiple loads from the same slot for subsequent members
|
// to avoid multiple loads from the same slot for subsequent members
|
||||||
templ("init", fromStorage ? "let slotValue := 0" : "");
|
templ("init", _from.dataStoredIn(DataLocation::Storage) ? "let slotValue := 0" : "");
|
||||||
u256 previousSlotOffset(-1);
|
u256 previousSlotOffset(-1);
|
||||||
u256 encodingOffset = 0;
|
u256 encodingOffset = 0;
|
||||||
vector<map<string, string>> members;
|
vector<map<string, string>> members;
|
||||||
@ -1159,7 +1157,9 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
|||||||
members.push_back({});
|
members.push_back({});
|
||||||
members.back()["preprocess"] = "";
|
members.back()["preprocess"] = "";
|
||||||
|
|
||||||
if (fromStorage)
|
switch (_from.location())
|
||||||
|
{
|
||||||
|
case DataLocation::Storage:
|
||||||
{
|
{
|
||||||
solAssert(memberTypeFrom->isValueType() == memberTypeTo->isValueType(), "");
|
solAssert(memberTypeFrom->isValueType() == memberTypeTo->isValueType(), "");
|
||||||
u256 storageSlotOffset;
|
u256 storageSlotOffset;
|
||||||
@ -1180,11 +1180,18 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
|||||||
solAssert(intraSlotOffset == 0, "");
|
solAssert(intraSlotOffset == 0, "");
|
||||||
members.back()["retrieveValue"] = "add(value, " + toCompactHexWithPrefix(storageSlotOffset) + ")";
|
members.back()["retrieveValue"] = "add(value, " + toCompactHexWithPrefix(storageSlotOffset) + ")";
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
case DataLocation::Memory:
|
||||||
{
|
{
|
||||||
string sourceOffset = toCompactHexWithPrefix(_from.memoryOffsetOfMember(member.name));
|
string sourceOffset = toCompactHexWithPrefix(_from.memoryOffsetOfMember(member.name));
|
||||||
members.back()["retrieveValue"] = "mload(add(value, " + sourceOffset + "))";
|
members.back()["retrieveValue"] = "mload(add(value, " + sourceOffset + "))";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DataLocation::CallData:
|
||||||
|
solUnimplementedAssert(false, "Encoding struct from calldata is not yet supported.");
|
||||||
|
default:
|
||||||
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
EncodingOptions subOptions(_options);
|
EncodingOptions subOptions(_options);
|
||||||
@ -1192,10 +1199,14 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
|||||||
// Like with arrays, struct members are always padded.
|
// Like with arrays, struct members are always padded.
|
||||||
subOptions.padded = true;
|
subOptions.padded = true;
|
||||||
|
|
||||||
|
string memberValues = m_utils.suffixedVariableNameList("memberValue", 0, numVariablesForType(*memberTypeFrom, subOptions));
|
||||||
|
members.back()["memberValues"] = memberValues;
|
||||||
|
|
||||||
string encode;
|
string encode;
|
||||||
if (_options.dynamicInplace)
|
if (_options.dynamicInplace)
|
||||||
encode = Whiskers{"pos := <encode>(memberValue, pos)"}
|
encode = Whiskers{"pos := <encode>(<memberValues>, pos)"}
|
||||||
("encode", abiEncodeAndReturnUpdatedPosFunction(*memberTypeFrom, *memberTypeTo, subOptions))
|
("encode", abiEncodeAndReturnUpdatedPosFunction(*memberTypeFrom, *memberTypeTo, subOptions))
|
||||||
|
("memberValues", memberValues)
|
||||||
.render();
|
.render();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1203,10 +1214,11 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
|||||||
dynamicMember ?
|
dynamicMember ?
|
||||||
string(R"(
|
string(R"(
|
||||||
mstore(add(pos, <encodingOffset>), sub(tail, pos))
|
mstore(add(pos, <encodingOffset>), sub(tail, pos))
|
||||||
tail := <abiEncode>(memberValue, tail)
|
tail := <abiEncode>(<memberValues>, tail)
|
||||||
)") :
|
)") :
|
||||||
"<abiEncode>(memberValue, add(pos, <encodingOffset>))"
|
"<abiEncode>(<memberValues>, add(pos, <encodingOffset>))"
|
||||||
);
|
);
|
||||||
|
encodeTempl("memberValues", memberValues);
|
||||||
encodeTempl("encodingOffset", toCompactHexWithPrefix(encodingOffset));
|
encodeTempl("encodingOffset", toCompactHexWithPrefix(encodingOffset));
|
||||||
encodingOffset += dynamicMember ? 0x20 : memberTypeTo->calldataEncodedSize();
|
encodingOffset += dynamicMember ? 0x20 : memberTypeTo->calldataEncodedSize();
|
||||||
encodeTempl("abiEncode", abiEncodingFunction(*memberTypeFrom, *memberTypeTo, subOptions));
|
encodeTempl("abiEncode", abiEncodingFunction(*memberTypeFrom, *memberTypeTo, subOptions));
|
||||||
|
@ -330,8 +330,9 @@ string YulUtilFunctions::arrayDataAreaFunction(ArrayType const& _type)
|
|||||||
{
|
{
|
||||||
string functionName = "array_dataslot_" + _type.identifier();
|
string functionName = "array_dataslot_" + _type.identifier();
|
||||||
return m_functionCollector->createFunction(functionName, [&]() {
|
return m_functionCollector->createFunction(functionName, [&]() {
|
||||||
if (_type.dataStoredIn(DataLocation::Memory))
|
switch (_type.location())
|
||||||
{
|
{
|
||||||
|
case DataLocation::Memory:
|
||||||
if (_type.isDynamicallySized())
|
if (_type.isDynamicallySized())
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(memPtr) -> dataPtr {
|
function <functionName>(memPtr) -> dataPtr {
|
||||||
@ -348,9 +349,7 @@ string YulUtilFunctions::arrayDataAreaFunction(ArrayType const& _type)
|
|||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
.render();
|
.render();
|
||||||
}
|
case DataLocation::Storage:
|
||||||
else if (_type.dataStoredIn(DataLocation::Storage))
|
|
||||||
{
|
|
||||||
if (_type.isDynamicallySized())
|
if (_type.isDynamicallySized())
|
||||||
{
|
{
|
||||||
Whiskers w(R"(
|
Whiskers w(R"(
|
||||||
@ -372,10 +371,21 @@ string YulUtilFunctions::arrayDataAreaFunction(ArrayType const& _type)
|
|||||||
w("functionName", functionName);
|
w("functionName", functionName);
|
||||||
return w.render();
|
return w.render();
|
||||||
}
|
}
|
||||||
}
|
case DataLocation::CallData:
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Not used for calldata
|
// Calldata arrays are stored as offset of the data area and length
|
||||||
|
// on the stack, so the offset already points to the data area.
|
||||||
|
// This might change, if calldata arrays are stored in a single
|
||||||
|
// stack slot at some point.
|
||||||
|
Whiskers w(R"(
|
||||||
|
function <functionName>(slot) -> dataSlot {
|
||||||
|
dataSlot := slot
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
w("functionName", functionName);
|
||||||
|
return w.render();
|
||||||
|
}
|
||||||
|
default:
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -384,19 +394,13 @@ string YulUtilFunctions::arrayDataAreaFunction(ArrayType const& _type)
|
|||||||
string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type)
|
string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type)
|
||||||
{
|
{
|
||||||
solAssert(!_type.isByteArray(), "");
|
solAssert(!_type.isByteArray(), "");
|
||||||
solAssert(
|
if (_type.dataStoredIn(DataLocation::Storage))
|
||||||
_type.location() == DataLocation::Memory ||
|
solAssert(_type.baseType()->storageBytes() > 16, "");
|
||||||
_type.location() == DataLocation::Storage,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
solAssert(
|
|
||||||
_type.location() == DataLocation::Memory ||
|
|
||||||
_type.baseType()->storageBytes() > 16,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
string functionName = "array_nextElement_" + _type.identifier();
|
string functionName = "array_nextElement_" + _type.identifier();
|
||||||
return m_functionCollector->createFunction(functionName, [&]() {
|
return m_functionCollector->createFunction(functionName, [&]() {
|
||||||
if (_type.location() == DataLocation::Memory)
|
switch (_type.location())
|
||||||
|
{
|
||||||
|
case DataLocation::Memory:
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(memPtr) -> nextPtr {
|
function <functionName>(memPtr) -> nextPtr {
|
||||||
nextPtr := add(memPtr, 0x20)
|
nextPtr := add(memPtr, 0x20)
|
||||||
@ -404,7 +408,7 @@ string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type)
|
|||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
.render();
|
.render();
|
||||||
else if (_type.location() == DataLocation::Storage)
|
case DataLocation::Storage:
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(slot) -> nextSlot {
|
function <functionName>(slot) -> nextSlot {
|
||||||
nextSlot := add(slot, 1)
|
nextSlot := add(slot, 1)
|
||||||
@ -412,8 +416,18 @@ string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type)
|
|||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
.render();
|
.render();
|
||||||
else
|
case DataLocation::CallData:
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>(calldataPtr) -> nextPtr {
|
||||||
|
nextPtr := add(calldataPtr, <stride>)
|
||||||
|
}
|
||||||
|
)")
|
||||||
|
("stride", toCompactHexWithPrefix(_type.baseType()->isDynamicallyEncoded() ? 32 : _type.baseType()->calldataEncodedSize()))
|
||||||
|
("functionName", functionName)
|
||||||
|
.render();
|
||||||
|
default:
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,11 +79,11 @@ public:
|
|||||||
/// The function reverts for too large lengths.
|
/// The function reverts for too large lengths.
|
||||||
std::string arrayAllocationSizeFunction(ArrayType const& _type);
|
std::string arrayAllocationSizeFunction(ArrayType const& _type);
|
||||||
/// @returns the name of a function that converts a storage slot number
|
/// @returns the name of a function that converts a storage slot number
|
||||||
/// or a memory pointer to the slot number / memory pointer for the data position of an array
|
/// a memory pointer or a calldata pointer to the slot number / memory pointer / calldata pointer
|
||||||
/// which is stored in that slot / memory area.
|
/// for the data position of an array which is stored in that slot / memory area / calldata area.
|
||||||
std::string arrayDataAreaFunction(ArrayType const& _type);
|
std::string arrayDataAreaFunction(ArrayType const& _type);
|
||||||
/// @returns the name of a function that advances an array data pointer to the next element.
|
/// @returns the name of a function that advances an array data pointer to the next element.
|
||||||
/// Only works for memory arrays and storage arrays that store one item per slot.
|
/// Only works for memory arrays, calldata arrays and storage arrays that store one item per slot.
|
||||||
std::string nextArrayElementFunction(ArrayType const& _type);
|
std::string nextArrayElementFunction(ArrayType const& _type);
|
||||||
|
|
||||||
/// @returns the name of a function that allocates memory.
|
/// @returns the name of a function that allocates memory.
|
||||||
|
Loading…
Reference in New Issue
Block a user