| 2937 | } |
| 2938 | |
| 2939 | std::string YulUtilFunctions::updateStorageValueFunction( |
| 2940 | Type const& _fromType, |
| 2941 | Type const& _toType, |
| 2942 | VariableDeclaration::Location _location, |
| 2943 | std::optional<unsigned> const& _offset |
| 2944 | ) |
| 2945 | { |
| 2946 | solAssert( |
| 2947 | _location == VariableDeclaration::Location::Transient || |
| 2948 | _location == VariableDeclaration::Location::Unspecified, |
| 2949 | "Variable location can only be transient or plain storage" |
| 2950 | ); |
| 2951 | |
| 2952 | std::string const functionName = |
| 2953 | "update_" + |
| 2954 | (_location == VariableDeclaration::Location::Transient ? "transient_"s : "") + |
| 2955 | "storage_value_" + |
| 2956 | (_offset.has_value() ? ("offset_" + std::to_string(*_offset)) + "_" : "") + |
| 2957 | _fromType.identifier() + |
| 2958 | "_to_" + |
| 2959 | _toType.identifier(); |
| 2960 | |
| 2961 | return m_functionCollector.createFunction(functionName, [&] { |
| 2962 | if (_toType.isValueType()) |
| 2963 | { |
| 2964 | solAssert(_fromType.isImplicitlyConvertibleTo(_toType), ""); |
| 2965 | solAssert(_toType.storageBytes() <= 32, "Invalid storage bytes size."); |
| 2966 | solAssert(_toType.storageBytes() > 0, "Invalid storage bytes size."); |
| 2967 | |
| 2968 | return Whiskers(R"( |
| 2969 | function <functionName>(slot, <offset><fromValues>) { |
| 2970 | let <toValues> := <convert>(<fromValues>) |
| 2971 | <storeOpcode>(slot, <update>(<loadOpcode>(slot), <offset><prepare>(<toValues>))) |
| 2972 | } |
| 2973 | |
| 2974 | )") |
| 2975 | ("functionName", functionName) |
| 2976 | ("update", |
| 2977 | _offset.has_value() ? |
| 2978 | updateByteSliceFunction(_toType.storageBytes(), *_offset) : |
| 2979 | updateByteSliceFunctionDynamic(_toType.storageBytes()) |
| 2980 | ) |
| 2981 | ("offset", _offset.has_value() ? "" : "offset, ") |
| 2982 | ("convert", conversionFunction(_fromType, _toType)) |
| 2983 | ("fromValues", suffixedVariableNameList("value_", 0, _fromType.sizeOnStack())) |
| 2984 | ("toValues", suffixedVariableNameList("convertedValue_", 0, _toType.sizeOnStack())) |
| 2985 | ("storeOpcode", _location == VariableDeclaration::Location::Transient ? "tstore" : "sstore") |
| 2986 | ("loadOpcode", _location == VariableDeclaration::Location::Transient ? "tload" : "sload") |
| 2987 | ("prepare", prepareStoreFunction(_toType)) |
| 2988 | .render(); |
| 2989 | } |
| 2990 | |
| 2991 | solAssert(_location != VariableDeclaration::Location::Transient); |
| 2992 | auto const* toReferenceType = dynamic_cast<ReferenceType const*>(&_toType); |
| 2993 | auto const* fromReferenceType = dynamic_cast<ReferenceType const*>(&_fromType); |
| 2994 | solAssert(toReferenceType, ""); |
| 2995 | |
| 2996 | if (!fromReferenceType) |
no test coverage detected