mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6648 from ethereum/moveStorageFunctions
Move storage access functions to yul utils.
This commit is contained in:
commit
cbc1b97760
@ -255,39 +255,6 @@ string ABIFunctions::EncodingOptions::toFunctionNameSuffix() const
|
||||
return suffix;
|
||||
}
|
||||
|
||||
string ABIFunctions::cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes)
|
||||
{
|
||||
solAssert(_type.isValueType(), "");
|
||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||
|
||||
string functionName = string("cleanup_from_storage_") + (_splitFunctionTypes ? "split_" : "") + _type.identifier();
|
||||
return createFunction(functionName, [&] {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(value) -> cleaned {
|
||||
<body>
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
|
||||
unsigned storageBytes = _type.storageBytes();
|
||||
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
|
||||
if (type->isSigned() && storageBytes != 32)
|
||||
{
|
||||
templ("body", "cleaned := signextend(" + to_string(storageBytes - 1) + ", value)");
|
||||
return templ.render();
|
||||
}
|
||||
|
||||
if (storageBytes == 32)
|
||||
templ("body", "cleaned := value");
|
||||
else if (_type.leftAligned())
|
||||
templ("body", "cleaned := " + m_utils.shiftLeftFunction(256 - 8 * storageBytes) + "(value)");
|
||||
else
|
||||
templ("body", "cleaned := and(value, " + toCompactHexWithPrefix((u256(1) << (8 * storageBytes)) - 1) + ")");
|
||||
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
|
||||
string ABIFunctions::abiEncodingFunction(
|
||||
Type const& _from,
|
||||
Type const& _to,
|
||||
@ -609,7 +576,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
|
||||
break;
|
||||
case DataLocation::Storage:
|
||||
if (_from.baseType()->isValueType())
|
||||
templ("arrayElementAccess", readFromStorage(*_from.baseType(), 0, false) + "(srcPtr)");
|
||||
templ("arrayElementAccess", m_utils.readFromStorage(*_from.baseType(), 0, false) + "(srcPtr)");
|
||||
else
|
||||
templ("arrayElementAccess", "srcPtr");
|
||||
break;
|
||||
@ -806,7 +773,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
|
||||
items[i]["inRange"] = "1";
|
||||
else
|
||||
items[i]["inRange"] = "0";
|
||||
items[i]["extractFromSlot"] = extractFromStorageValue(*_from.baseType(), i * storageBytes, false);
|
||||
items[i]["extractFromSlot"] = m_utils.extractFromStorageValue(*_from.baseType(), i * storageBytes, false);
|
||||
}
|
||||
templ("items", items);
|
||||
return templ.render();
|
||||
@ -893,7 +860,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
||||
members.back()["preprocess"] = "slotValue := sload(add(value, " + toCompactHexWithPrefix(storageSlotOffset) + "))";
|
||||
previousSlotOffset = storageSlotOffset;
|
||||
}
|
||||
members.back()["retrieveValue"] = extractFromStorageValue(*memberTypeFrom, intraSlotOffset, false) + "(slotValue)";
|
||||
members.back()["retrieveValue"] = m_utils.extractFromStorageValue(*memberTypeFrom, intraSlotOffset, false) + "(slotValue)";
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1400,51 +1367,6 @@ string ABIFunctions::abiDecodingFunctionFunctionType(FunctionType const& _type,
|
||||
});
|
||||
}
|
||||
|
||||
string ABIFunctions::readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
||||
{
|
||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||
string functionName =
|
||||
"read_from_storage_" +
|
||||
string(_splitFunctionTypes ? "split_" : "") +
|
||||
"offset_" +
|
||||
to_string(_offset) +
|
||||
_type.identifier();
|
||||
return m_functionCollector->createFunction(functionName, [&] {
|
||||
solAssert(_type.sizeOnStack() == 1, "");
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot) -> value {
|
||||
value := <extract>(sload(slot))
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("extract", extractFromStorageValue(_type, _offset, false))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string ABIFunctions::extractFromStorageValue(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
||||
{
|
||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||
|
||||
string functionName =
|
||||
"extract_from_storage_value_" +
|
||||
string(_splitFunctionTypes ? "split_" : "") +
|
||||
"offset_" +
|
||||
to_string(_offset) +
|
||||
_type.identifier();
|
||||
return m_functionCollector->createFunction(functionName, [&] {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot_value) -> value {
|
||||
value := <cleanupStorage>(<shr>(slot_value))
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("shr", m_utils.shiftRightFunction(_offset * 8))
|
||||
("cleanupStorage", cleanupFromStorageFunction(_type, false))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string ABIFunctions::calldataAccessFunction(Type const& _type)
|
||||
{
|
||||
solAssert(_type.isValueType() || _type.dataStoredIn(DataLocation::CallData), "");
|
||||
|
@ -128,15 +128,6 @@ private:
|
||||
std::string toFunctionNameSuffix() const;
|
||||
};
|
||||
|
||||
/// Performs cleanup after reading from a potentially compressed storage slot.
|
||||
/// The function does not perform any validation, it just masks or sign-extends
|
||||
/// higher order bytes or left-aligns (in case of bytesNN).
|
||||
/// The storage cleanup expects the value to be right-aligned with potentially
|
||||
/// dirty higher order bytes.
|
||||
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||
/// single variable.
|
||||
std::string cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes);
|
||||
|
||||
/// @returns the name of the ABI encoding function with the given type
|
||||
/// and queues the generation of the function to the requested functions.
|
||||
/// @param _fromStack if false, the input value was just loaded from storage
|
||||
@ -231,19 +222,6 @@ private:
|
||||
/// Part of @a abiDecodingFunction for array types.
|
||||
std::string abiDecodingFunctionFunctionType(FunctionType const& _type, bool _fromMemory, bool _forUseOnStack);
|
||||
|
||||
/// @returns a function that reads a value type from storage.
|
||||
/// Performs bit mask/sign extend cleanup and appropriate left / right shift, but not validation.
|
||||
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||
/// single variable.
|
||||
std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes);
|
||||
|
||||
/// @returns a function that extracts a value type from storage slot that has been
|
||||
/// retrieved already.
|
||||
/// Performs bit mask/sign extend cleanup and appropriate left / right shift, but not validation.
|
||||
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||
/// single variable.
|
||||
std::string extractFromStorageValue(Type const& _type, size_t _offset, bool _splitFunctionTypes);
|
||||
|
||||
/// @returns the name of a function that retrieves an element from calldata.
|
||||
std::string calldataAccessFunction(Type const& _type);
|
||||
|
||||
|
@ -461,6 +461,86 @@ string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
||||
{
|
||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||
string functionName =
|
||||
"read_from_storage_" +
|
||||
string(_splitFunctionTypes ? "split_" : "") +
|
||||
"offset_" +
|
||||
to_string(_offset) +
|
||||
"_" +
|
||||
_type.identifier();
|
||||
return m_functionCollector->createFunction(functionName, [&] {
|
||||
solAssert(_type.sizeOnStack() == 1, "");
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot) -> value {
|
||||
value := <extract>(sload(slot))
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("extract", extractFromStorageValue(_type, _offset, false))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::extractFromStorageValue(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
||||
{
|
||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||
|
||||
string functionName =
|
||||
"extract_from_storage_value_" +
|
||||
string(_splitFunctionTypes ? "split_" : "") +
|
||||
"offset_" +
|
||||
to_string(_offset) +
|
||||
_type.identifier();
|
||||
return m_functionCollector->createFunction(functionName, [&] {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot_value) -> value {
|
||||
value := <cleanupStorage>(<shr>(slot_value))
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("shr", shiftRightFunction(_offset * 8))
|
||||
("cleanupStorage", cleanupFromStorageFunction(_type, false))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes)
|
||||
{
|
||||
solAssert(_type.isValueType(), "");
|
||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||
|
||||
string functionName = string("cleanup_from_storage_") + (_splitFunctionTypes ? "split_" : "") + _type.identifier();
|
||||
return m_functionCollector->createFunction(functionName, [&] {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(value) -> cleaned {
|
||||
<body>
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
|
||||
unsigned storageBytes = _type.storageBytes();
|
||||
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
|
||||
if (type->isSigned() && storageBytes != 32)
|
||||
{
|
||||
templ("body", "cleaned := signextend(" + to_string(storageBytes - 1) + ", value)");
|
||||
return templ.render();
|
||||
}
|
||||
|
||||
if (storageBytes == 32)
|
||||
templ("body", "cleaned := value");
|
||||
else if (_type.leftAligned())
|
||||
templ("body", "cleaned := " + shiftLeftFunction(256 - 8 * storageBytes) + "(value)");
|
||||
else
|
||||
templ("body", "cleaned := and(value, " + toCompactHexWithPrefix((u256(1) << (8 * storageBytes)) - 1) + ")");
|
||||
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::allocationFunction()
|
||||
{
|
||||
string functionName = "allocateMemory";
|
||||
|
@ -88,6 +88,28 @@ public:
|
||||
/// Only works for memory arrays, calldata arrays and storage arrays that store one item per slot.
|
||||
std::string nextArrayElementFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns a function that reads a value type from storage.
|
||||
/// Performs bit mask/sign extend cleanup and appropriate left / right shift, but not validation.
|
||||
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||
/// single variable.
|
||||
std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes);
|
||||
|
||||
/// @returns a function that extracts a value type from storage slot that has been
|
||||
/// retrieved already.
|
||||
/// Performs bit mask/sign extend cleanup and appropriate left / right shift, but not validation.
|
||||
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||
/// single variable.
|
||||
std::string extractFromStorageValue(Type const& _type, size_t _offset, bool _splitFunctionTypes);
|
||||
|
||||
/// Performs cleanup after reading from a potentially compressed storage slot.
|
||||
/// The function does not perform any validation, it just masks or sign-extends
|
||||
/// higher order bytes or left-aligns (in case of bytesNN).
|
||||
/// The storage cleanup expects the value to be right-aligned with potentially
|
||||
/// dirty higher order bytes.
|
||||
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||
/// single variable.
|
||||
std::string cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes);
|
||||
|
||||
/// @returns the name of a function that allocates memory.
|
||||
/// Modifies the "free memory pointer"
|
||||
/// Arguments: size
|
||||
|
Loading…
Reference in New Issue
Block a user