diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index f640c2180..88e3c39fd 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -802,7 +802,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( items[i]["inRange"] = "1"; else items[i]["inRange"] = "0"; - items[i]["extractFromSlot"] = m_utils.extractFromStorageValue(*_from.baseType(), i * storageBytes, false); + items[i]["extractFromSlot"] = m_utils.extractFromStorageValue(*_from.baseType(), i * storageBytes); } templ("items", items); return templ.render(); @@ -888,7 +888,7 @@ string ABIFunctions::abiEncodingFunctionStruct( members.back()["preprocess"] = "slotValue := sload(add(value, " + toCompactHexWithPrefix(storageSlotOffset) + "))"; previousSlotOffset = storageSlotOffset; } - members.back()["retrieveValue"] = m_utils.extractFromStorageValue(*memberTypeFrom, intraSlotOffset, false) + "(slotValue)"; + members.back()["retrieveValue"] = m_utils.extractFromStorageValue(*memberTypeFrom, intraSlotOffset) + "(slotValue)"; } else { diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index c9b23dec2..cacc6f010 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2059,58 +2059,47 @@ string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes) { solAssert(_type.isValueType(), ""); - return readFromStorageValueTypeDynamic(_type, _splitFunctionTypes); + return readFromStorageValueType(_type, {}, _splitFunctionTypes); } -string YulUtilFunctions::readFromStorageValueType(Type const& _type, size_t _offset, bool _splitFunctionTypes) +string YulUtilFunctions::readFromStorageValueType(Type const& _type, optional _offset, bool _splitFunctionTypes) { solAssert(_type.isValueType(), ""); - if (_type.category() == Type::Category::Function) - solUnimplementedAssert(!_splitFunctionTypes, ""); string functionName = "read_from_storage_" + - string(_splitFunctionTypes ? "split_" : "") + - "offset_" + - to_string(_offset) + + string(_splitFunctionTypes ? "split_" : "") + ( + _offset.has_value() ? + "offset_" + to_string(*_offset) : + "dynamic" + ) + "_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&] { - solAssert(_type.sizeOnStack() == 1, ""); - return Whiskers(R"( - function (slot) -> value { - value := (sload(slot)) + Whiskers templ(R"( + function (slot, offset) -> addr, selectorvalue { + let value := (sload(slot), offset) + + addr, selector := (value) + } - )") - ("functionName", functionName) - ("extract", extractFromStorageValue(_type, _offset, false)) - .render(); + )"); + templ("functionName", functionName); + templ("dynamic", !_offset.has_value()); + if (_offset.has_value()) + templ("extract", extractFromStorageValue(_type, *_offset)); + else + templ("extract", extractFromStorageValueDynamic(_type)); + auto const* funType = dynamic_cast(&_type); + bool split = _splitFunctionTypes && funType && funType->kind() == FunctionType::Kind::External; + templ("split", split); + if (split) + templ("splitFunction", splitExternalFunctionIdFunction()); + return templ.render(); }); } -string YulUtilFunctions::readFromStorageValueTypeDynamic(Type const& _type, bool _splitFunctionTypes) -{ - solAssert(_type.isValueType(), ""); - if (_type.category() == Type::Category::Function) - solUnimplementedAssert(!_splitFunctionTypes, ""); - string functionName = - "read_from_storage_value_type_dynamic" + - string(_splitFunctionTypes ? "split_" : "") + - "_" + - _type.identifier(); - return m_functionCollector.createFunction(functionName, [&] { - solAssert(_type.sizeOnStack() == 1, ""); - return Whiskers(R"( - function (slot, offset) -> value { - value := (sload(slot), offset) - } - )") - ("functionName", functionName) - ("extract", extractFromStorageValueDynamic(_type, _splitFunctionTypes)) - .render(); - }); -} string YulUtilFunctions::readFromStorageReferenceType(Type const& _type) { solUnimplementedAssert(_type.category() == Type::Category::Struct, ""); @@ -2343,9 +2332,7 @@ string YulUtilFunctions::updateStorageValueFunction( string YulUtilFunctions::writeToMemoryFunction(Type const& _type) { - string const functionName = - string("write_to_memory_") + - _type.identifier(); + string const functionName = "write_to_memory_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&] { solAssert(!dynamic_cast(&_type), ""); @@ -2399,14 +2386,10 @@ string YulUtilFunctions::writeToMemoryFunction(Type const& _type) }); } -string YulUtilFunctions::extractFromStorageValueDynamic(Type const& _type, bool _splitFunctionTypes) +string YulUtilFunctions::extractFromStorageValueDynamic(Type const& _type) { - if (_type.category() == Type::Category::Function) - solUnimplementedAssert(!_splitFunctionTypes, ""); - string functionName = "extract_from_storage_value_dynamic" + - string(_splitFunctionTypes ? "split_" : "") + _type.identifier(); return m_functionCollector.createFunction(functionName, [&] { return Whiskers(R"( @@ -2416,21 +2399,14 @@ string YulUtilFunctions::extractFromStorageValueDynamic(Type const& _type, bool )") ("functionName", functionName) ("shr", shiftRightFunctionDynamic()) - ("cleanupStorage", cleanupFromStorageFunction(_type, _splitFunctionTypes)) + ("cleanupStorage", cleanupFromStorageFunction(_type)) .render(); }); } -string YulUtilFunctions::extractFromStorageValue(Type const& _type, size_t _offset, bool _splitFunctionTypes) +string YulUtilFunctions::extractFromStorageValue(Type const& _type, size_t _offset) { - solUnimplementedAssert(!_splitFunctionTypes, ""); - - string functionName = - "extract_from_storage_value_" + - string(_splitFunctionTypes ? "split_" : "") + - "offset_" + - to_string(_offset) + - _type.identifier(); + string functionName = "extract_from_storage_value_offset_" + to_string(_offset) + _type.identifier(); return m_functionCollector.createFunction(functionName, [&] { return Whiskers(R"( function (slot_value) -> value { @@ -2439,18 +2415,16 @@ string YulUtilFunctions::extractFromStorageValue(Type const& _type, size_t _offs )") ("functionName", functionName) ("shr", shiftRightFunction(_offset * 8)) - ("cleanupStorage", cleanupFromStorageFunction(_type, _splitFunctionTypes)) + ("cleanupStorage", cleanupFromStorageFunction(_type)) .render(); }); } -string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes) +string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type) { solAssert(_type.isValueType(), ""); - if (_type.category() == Type::Category::Function) - solUnimplementedAssert(!_splitFunctionTypes, ""); - string functionName = string("cleanup_from_storage_") + (_splitFunctionTypes ? "split_" : "") + _type.identifier(); + string functionName = string("cleanup_from_storage_") + _type.identifier(); return m_functionCollector.createFunction(functionName, [&] { Whiskers templ(R"( function (value) -> cleaned { diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 28467dceb..d496d9642 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -266,10 +266,10 @@ public: /// @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); - std::string extractFromStorageValueDynamic(Type const& _type, bool _splitFunctionTypes); + /// + /// For external function types, input and output is in "compressed"/"unsplit" form. + std::string extractFromStorageValue(Type const& _type, size_t _offset); + std::string extractFromStorageValueDynamic(Type const& _type); /// Returns the name of a function will write the given value to /// the specified slot and offset. If offset is not given, it is expected as @@ -292,9 +292,8 @@ public: /// 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); + /// For external functions, input and output is in "compressed"/"unsplit" form. + std::string cleanupFromStorageFunction(Type const& _type); /// @returns the name of a function that prepares a value of the given type /// for being stored in storage. This usually includes cleanup and right-alignment @@ -440,8 +439,8 @@ private: /// 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 readFromStorageValueType(Type const& _type, size_t _offset, bool _splitFunctionTypes); - std::string readFromStorageValueTypeDynamic(Type const& _type, bool _splitFunctionTypes); + /// @param _offset if provided, read from static offset, otherwise offset is a parameter of the Yul function. + std::string readFromStorageValueType(Type const& _type, std::optional _offset, bool _splitFunctionTypes); /// @returns a function that reads a reference type from storage to memory (performing a deep copy). std::string readFromStorageReferenceType(Type const& _type); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 6d0c856be..a24e3c0dd 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -2733,7 +2733,7 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) define(result) << _storage.slot << "\n"; else if (std::holds_alternative(_storage.offset)) define(result) << - m_utils.readFromStorageDynamic(_lvalue.type, false) << + m_utils.readFromStorageDynamic(_lvalue.type, true) << "(" << _storage.slot << ", " << @@ -2741,7 +2741,7 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) ")\n"; else define(result) << - m_utils.readFromStorage(_lvalue.type, std::get(_storage.offset), false) << + m_utils.readFromStorage(_lvalue.type, std::get(_storage.offset), true) << "(" << _storage.slot << ")\n"; diff --git a/test/libsolidity/semanticTests/functionTypes/store_function.sol b/test/libsolidity/semanticTests/functionTypes/store_function.sol index a09404fce..d7b285802 100644 --- a/test/libsolidity/semanticTests/functionTypes/store_function.sol +++ b/test/libsolidity/semanticTests/functionTypes/store_function.sol @@ -24,5 +24,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // t() -> 9 diff --git a/test/libsolidity/semanticTests/storage/packed_functions.sol b/test/libsolidity/semanticTests/storage/packed_functions.sol index 4a49a614f..32597923b 100644 --- a/test/libsolidity/semanticTests/storage/packed_functions.sol +++ b/test/libsolidity/semanticTests/storage/packed_functions.sol @@ -39,6 +39,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // set() -> // t1() -> 7