2019-03-05 16:20:28 +00:00
/*
This file is part of solidity .
solidity is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
solidity is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with solidity . If not , see < http : //www.gnu.org/licenses/>.
*/
/**
* Component that can generate various useful Yul functions .
*/
# pragma once
# include <liblangutil/EVMVersion.h>
# include <libsolidity/codegen/MultiUseYulFunctionCollector.h>
2020-01-22 14:48:56 +00:00
# include <libsolidity/interface/DebugSettings.h>
2019-03-05 16:20:28 +00:00
# include <memory>
# include <string>
2019-05-02 20:33:47 +00:00
# include <vector>
2019-03-05 16:20:28 +00:00
2019-12-11 16:31:36 +00:00
namespace solidity : : frontend
2019-03-05 16:20:28 +00:00
{
class Type ;
class ArrayType ;
2019-05-02 10:48:34 +00:00
class MappingType ;
2019-05-23 14:12:32 +00:00
class IntegerType ;
2020-03-02 20:42:46 +00:00
class StructType ;
2019-03-05 16:20:28 +00:00
/**
* Component that can generate various useful Yul functions .
*/
class YulUtilFunctions
{
public :
explicit YulUtilFunctions (
langutil : : EVMVersion _evmVersion ,
2020-01-22 14:48:56 +00:00
RevertStrings _revertStrings ,
2020-03-02 17:08:19 +00:00
MultiUseYulFunctionCollector & _functionCollector
2019-03-05 16:20:28 +00:00
) :
m_evmVersion ( _evmVersion ) ,
2020-01-22 14:48:56 +00:00
m_revertStrings ( _revertStrings ) ,
2020-03-02 17:08:19 +00:00
m_functionCollector ( _functionCollector )
2019-03-05 16:20:28 +00:00
{ }
/// @returns a function that combines the address and selector to a single value
/// for use in the ABI.
std : : string combineExternalFunctionIdFunction ( ) ;
/// @returns a function that splits the address and selector from a single value
/// for use in the ABI.
std : : string splitExternalFunctionIdFunction ( ) ;
/// @returns a function that copies raw bytes of dynamic length from calldata
/// or memory to memory.
/// Pads with zeros and might write more than exactly length.
std : : string copyToMemoryFunction ( bool _fromCalldata ) ;
2019-04-30 17:08:02 +00:00
// @returns the name of a function that has the equivalent logic of an
// `assert` or `require` call.
std : : string requireOrAssertFunction ( bool _assert , Type const * _messageType = nullptr ) ;
2019-03-05 16:20:28 +00:00
/// @returns the name of a function that takes a (cleaned) value of the given value type and
/// left-aligns it, usually for use in non-padded encoding.
std : : string leftAlignFunction ( Type const & _type ) ;
std : : string shiftLeftFunction ( size_t _numBits ) ;
2019-06-17 13:26:40 +00:00
std : : string shiftLeftFunctionDynamic ( ) ;
2019-03-05 16:20:28 +00:00
std : : string shiftRightFunction ( size_t _numBits ) ;
2019-06-17 13:26:40 +00:00
std : : string shiftRightFunctionDynamic ( ) ;
2019-03-18 10:39:15 +00:00
2019-06-13 15:31:38 +00:00
/// @returns the name of a function which replaces the
2019-04-30 16:32:56 +00:00
/// _numBytes bytes starting at byte position _shiftBytes (counted from the least significant
/// byte) by the _numBytes least significant bytes of `toInsert`.
2019-06-13 15:31:38 +00:00
/// signature: (value, toInsert) -> result
2019-04-30 16:32:56 +00:00
std : : string updateByteSliceFunction ( size_t _numBytes , size_t _shiftBytes ) ;
2019-06-05 17:32:30 +00:00
/// signature: (value, shiftBytes, toInsert) -> result
2019-06-17 13:26:40 +00:00
std : : string updateByteSliceFunctionDynamic ( size_t _numBytes ) ;
2019-06-05 17:32:30 +00:00
2019-03-05 16:20:28 +00:00
/// @returns the name of a function that rounds its input to the next multiple
/// of 32 or the input if it is a multiple of 32.
2019-06-13 15:31:38 +00:00
/// signature: (value) -> result
2019-03-05 16:20:28 +00:00
std : : string roundUpFunction ( ) ;
2019-06-13 15:31:38 +00:00
/// signature: (x, y) -> sum
2019-06-12 09:24:19 +00:00
std : : string overflowCheckedIntAddFunction ( IntegerType const & _type ) ;
2019-03-18 10:21:41 +00:00
2019-06-13 15:31:38 +00:00
/// signature: (x, y) -> product
2019-06-12 12:06:13 +00:00
std : : string overflowCheckedIntMulFunction ( IntegerType const & _type ) ;
2019-05-20 14:42:27 +00:00
2019-05-23 14:12:32 +00:00
/// @returns name of function to perform division on integers.
/// Checks for division by zero and the special case of
/// signed division of the smallest number by -1.
std : : string overflowCheckedIntDivFunction ( IntegerType const & _type ) ;
2019-06-12 14:27:26 +00:00
/// @returns name of function to perform modulo on integers.
/// Reverts for modulo by zero.
std : : string checkedIntModFunction ( IntegerType const & _type ) ;
2019-05-08 19:25:47 +00:00
/// @returns computes the difference between two values.
/// Assumes the input to be in range for the type.
2019-06-13 15:31:38 +00:00
/// signature: (x, y) -> diff
2019-06-12 11:07:06 +00:00
std : : string overflowCheckedIntSubFunction ( IntegerType const & _type ) ;
2019-05-08 19:25:47 +00:00
2019-06-13 15:31:38 +00:00
/// @returns the name of a function that fetches the length of the given
/// array
/// signature: (array) -> length
2019-03-05 16:20:28 +00:00
std : : string arrayLengthFunction ( ArrayType const & _type ) ;
2019-06-06 12:07:40 +00:00
/// @returns the name of a function that resizes a storage array
/// signature: (array, newLen)
std : : string resizeDynamicArrayFunction ( ArrayType const & _type ) ;
2019-11-07 20:22:58 +00:00
/// @returns the name of a function that reduces the size of a storage array by one element
/// signature: (array)
std : : string storageArrayPopFunction ( ArrayType const & _type ) ;
/// @returns the name of a function that pushes an element to a storage array
2019-11-28 17:05:11 +00:00
/// signature: (array, value)
2019-11-07 20:22:58 +00:00
std : : string storageArrayPushFunction ( ArrayType const & _type ) ;
2019-11-28 17:49:28 +00:00
/// @returns the name of a function that pushes the base type's zero element to a storage array and returns storage slot and offset of the added element.
2019-11-28 17:05:11 +00:00
/// signature: (array) -> slot, offset
std : : string storageArrayPushZeroFunction ( ArrayType const & _type ) ;
2019-06-06 12:07:40 +00:00
/// @returns the name of a function that will clear the storage area given
2019-07-10 10:41:31 +00:00
/// by the start and end (exclusive) parameters (slots).
2019-06-06 12:07:40 +00:00
/// signature: (start, end)
std : : string clearStorageRangeFunction ( Type const & _type ) ;
2019-07-10 10:41:31 +00:00
/// @returns the name of a function that will clear the given storage array
/// signature: (slot) ->
std : : string clearStorageArrayFunction ( ArrayType const & _type ) ;
2019-06-06 12:07:40 +00:00
/// Returns the name of a function that will convert a given length to the
/// size in memory (number of storage slots or calldata/memory bytes) it
/// will require.
/// signature: (length) -> size
std : : string arrayConvertLengthToSize ( ArrayType const & _type ) ;
2019-03-05 16:20:28 +00:00
/// @returns the name of a function that computes the number of bytes required
/// to store an array in memory given its length (internally encoded, not ABI encoded).
/// The function reverts for too large lengths.
std : : string arrayAllocationSizeFunction ( ArrayType const & _type ) ;
2020-03-02 20:42:46 +00:00
2019-03-05 16:20:28 +00:00
/// @returns the name of a function that converts a storage slot number
2019-03-15 17:26:17 +00:00
/// a memory pointer or a calldata pointer to the slot number / memory pointer / calldata pointer
/// for the data position of an array which is stored in that slot / memory area / calldata area.
2019-03-05 16:20:28 +00:00
std : : string arrayDataAreaFunction ( ArrayType const & _type ) ;
2019-06-13 15:22:24 +00:00
/// @returns the name of a function that returns the slot and offset for the
/// given array and index
/// signature: (array, index) -> slot, offset
std : : string storageArrayIndexAccessFunction ( ArrayType const & _type ) ;
2019-06-27 11:36:06 +00:00
/// @returns the name of a function that returns the memory address for the
/// given array base ref and index.
/// Causes invalid opcode on out of range access.
/// signature: (baseRef, index) -> address
std : : string memoryArrayIndexAccessFunction ( ArrayType const & _type ) ;
/// @returns the name of a function that returns the calldata address for the
/// given array base ref and index.
2020-02-11 16:43:43 +00:00
/// signature: (baseRef, index) -> offset[, length]
2019-06-27 11:36:06 +00:00
std : : string calldataArrayIndexAccessFunction ( ArrayType const & _type ) ;
2020-03-06 19:59:34 +00:00
/// @returns the name of a function that returns offset and length for array slice
/// for the given array offset, length and start and end indices for slice
/// signature: (arrayOffset, arrayLength, sliceStart, sliceEnd) -> offset, length
std : : string calldataArrayIndexRangeAccess ( ArrayType const & _type ) ;
2020-02-11 16:43:43 +00:00
/// @returns the name of a function that follows a calldata tail while performing
/// bounds checks.
/// signature: (baseRef, tailPointer) -> offset[, length]
std : : string accessCalldataTailFunction ( Type const & _type ) ;
2019-03-05 16:20:28 +00:00
/// @returns the name of a function that advances an array data pointer to the next element.
2019-06-19 02:46:05 +00:00
/// Only works for memory arrays, calldata arrays and storage arrays that every item occupies one or multiple full slots.
2019-03-05 16:20:28 +00:00
std : : string nextArrayElementFunction ( ArrayType const & _type ) ;
2019-05-02 10:48:34 +00:00
/// @returns the name of a function that performs index access for mappings.
/// @param _mappingType the type of the mapping
/// @param _keyType the type of the value provided
std : : string mappingIndexAccessFunction ( MappingType const & _mappingType , Type const & _keyType ) ;
2019-05-02 09:05:02 +00:00
/// @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 ) ;
2019-06-17 13:26:40 +00:00
std : : string readFromStorageDynamic ( Type const & _type , bool _splitFunctionTypes ) ;
2019-05-02 09:05:02 +00:00
2019-06-27 11:36:06 +00:00
/// @returns a function that reads a value type from memory.
/// signature: (addr) -> value
std : : string readFromMemory ( Type const & _type ) ;
/// @returns a function that reads a value type from calldata.
/// Reverts on invalid input.
/// signature: (addr) -> value
std : : string readFromCalldata ( Type const & _type ) ;
2019-05-02 09:05:02 +00:00
/// @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 ) ;
2019-06-17 13:26:40 +00:00
std : : string extractFromStorageValueDynamic ( Type const & _type , bool _splitFunctionTypes ) ;
2019-06-05 17:32:30 +00:00
/// 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
/// runtime parameter.
/// signature: (slot, [offset,] value)
2019-10-28 10:39:30 +00:00
std : : string updateStorageValueFunction ( Type const & _type , std : : optional < unsigned > const & _offset = std : : optional < unsigned > ( ) ) ;
2019-05-02 09:05:02 +00:00
2019-06-27 11:36:06 +00:00
/// Returns the name of a function that will write the given value to
/// the specified address.
/// Performs a cleanup before writing for value types.
/// signature: (memPtr, value) ->
std : : string writeToMemoryFunction ( Type const & _type ) ;
2019-05-02 09:05:02 +00:00
/// 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 ) ;
2019-04-30 16:32:56 +00:00
/// @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
/// to fit the number of bytes in storage.
/// The resulting value might still have dirty higher order bits.
std : : string prepareStoreFunction ( Type const & _type ) ;
2019-03-05 16:20:28 +00:00
/// @returns the name of a function that allocates memory.
/// Modifies the "free memory pointer"
/// Arguments: size
/// Return value: pointer
std : : string allocationFunction ( ) ;
2020-03-02 20:42:46 +00:00
/// @returns the name of a function that zeroes an array.
/// signature: (dataStart, dataSizeInBytes) ->
std : : string zeroMemoryArrayFunction ( ArrayType const & _type ) ;
/// @returns the name of a function that zeroes a chunk of memory.
/// signature: (dataStart, dataSizeInBytes) ->
std : : string zeroMemoryFunction ( Type const & _type ) ;
/// @returns the name of a function that zeroes an array
/// where the base does not have simple zero value in memory.
/// signature: (dataStart, dataSizeInBytes) ->
std : : string zeroComplexMemoryArrayFunction ( ArrayType const & _type ) ;
/// @returns the name of a function that allocates and zeroes a memory array.
2019-06-27 11:36:06 +00:00
/// For dynamic arrays it adds space for length and stores it.
/// signature: (length) -> memPtr
2020-03-02 20:42:46 +00:00
std : : string allocateAndInitializeMemoryArrayFunction ( ArrayType const & _type ) ;
/// @returns the name of a function that allocates and zeroes a memory struct.
/// signature: (members) -> memPtr
std : : string allocateAndInitializeMemoryStructFunction ( StructType const & _type ) ;
2019-06-27 11:36:06 +00:00
2019-04-09 13:30:54 +00:00
/// @returns the name of the function that converts a value of type @a _from
/// to a value of type @a _to. The resulting vale is guaranteed to be in range
/// (i.e. "clean"). Asserts on failure.
///
/// This is used for data being encoded or general type conversions in the code.
std : : string conversionFunction ( Type const & _from , Type const & _to ) ;
/// @returns the name of the cleanup function for the given type and
/// adds its implementation to the requested functions.
/// The cleanup function defers to the validator function with "assert"
/// if there is no reasonable way to clean a value.
std : : string cleanupFunction ( Type const & _type ) ;
/// @returns the name of the validator function for the given type and
/// adds its implementation to the requested functions.
/// @param _revertOnFailure if true, causes revert on invalid data,
/// otherwise an assertion failure.
///
/// This is used for data decoded from external sources.
std : : string validatorFunction ( Type const & _type , bool _revertOnFailure = false ) ;
2019-05-02 20:33:47 +00:00
std : : string packedHashFunction ( std : : vector < Type const * > const & _givenTypes , std : : vector < Type const * > const & _targetTypes ) ;
2019-05-06 17:48:31 +00:00
/// @returns the name of a function that reverts and uses returndata (if available)
/// as reason string.
std : : string forwardingRevertFunction ( ) ;
2019-05-13 13:26:55 +00:00
std : : string incrementCheckedFunction ( Type const & _type ) ;
std : : string decrementCheckedFunction ( Type const & _type ) ;
2019-05-16 16:59:29 +00:00
std : : string negateNumberCheckedFunction ( Type const & _type ) ;
2019-05-22 10:25:00 +00:00
/// @returns the name of a function that returns the zero value for the
2020-03-02 20:42:46 +00:00
/// provided type.
/// @param _splitFunctionTypes if false, returns two zeroes
std : : string zeroValueFunction ( Type const & _type , bool _splitFunctionTypes = true ) ;
2019-07-10 10:41:31 +00:00
/// @returns the name of a function that will set the given storage item to
/// zero
/// signature: (slot, offset) ->
std : : string storageSetToZeroFunction ( Type const & _type ) ;
2020-01-22 14:48:56 +00:00
/// If revertStrings is debug, @returns inline assembly code that
/// stores @param _message in memory position 0 and reverts.
/// Otherwise returns "revert(0, 0)".
static std : : string revertReasonIfDebug ( RevertStrings revertStrings , std : : string const & _message = " " ) ;
std : : string revertReasonIfDebug ( std : : string const & _message = " " ) ;
2019-05-13 13:26:55 +00:00
private :
2019-05-02 14:24:54 +00:00
/// Special case of conversionFunction - handles everything that does not
/// use exactly one variable to hold the value.
std : : string conversionFunctionSpecial ( Type const & _from , Type const & _to ) ;
2019-06-27 11:36:06 +00:00
std : : string readFromMemoryOrCalldata ( Type const & _type , bool _fromCalldata ) ;
2019-03-05 16:20:28 +00:00
langutil : : EVMVersion m_evmVersion ;
2020-01-22 14:48:56 +00:00
RevertStrings m_revertStrings ;
2020-03-02 17:08:19 +00:00
MultiUseYulFunctionCollector & m_functionCollector ;
2019-03-05 16:20:28 +00:00
} ;
}