From 31b70377495fd0f9977f9a79302afdc7ae557053 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 2 May 2019 11:05:02 +0200 Subject: [PATCH] Move storage access functions to utils. --- libsolidity/codegen/ABIFunctions.cpp | 84 +----------------------- libsolidity/codegen/ABIFunctions.h | 22 ------- libsolidity/codegen/YulUtilFunctions.cpp | 80 ++++++++++++++++++++++ libsolidity/codegen/YulUtilFunctions.h | 22 +++++++ 4 files changed, 105 insertions(+), 103 deletions(-) diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index be9a67177..d0c197b1f 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -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 (value) -> cleaned { - - } - )"); - templ("functionName", functionName); - - unsigned storageBytes = _type.storageBytes(); - if (IntegerType const* type = dynamic_cast(&_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 (slot) -> value { - value := (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 (slot_value) -> value { - value := ((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), ""); diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index 1858917fa..a54b403d9 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -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); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 7ede6d6f0..e8ca19f2a 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -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 (slot) -> value { + value := (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 (slot_value) -> value { + value := ((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 (value) -> cleaned { + + } + )"); + templ("functionName", functionName); + + unsigned storageBytes = _type.storageBytes(); + if (IntegerType const* type = dynamic_cast(&_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"; diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 8deb29714..e22494b87 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -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