/*
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 .
*/
// SPDX-License-Identifier: GPL-3.0
/**
* @author Christian
* @date 2014
* Routines used by both the compiler and the expression compiler.
*/
#pragma once
#include
#include
#include
#include
#include
namespace solidity::frontend
{
class Type; // forward
class CompilerUtils
{
public:
explicit CompilerUtils(CompilerContext& _context): m_context(_context)
{}
/// Stores the initial value of the free-memory-pointer at its position;
void initialiseFreeMemoryPointer();
/// Copies the free memory pointer to the stack.
/// Stack pre:
/// Stack post:
void fetchFreeMemoryPointer();
/// Stores the free memory pointer from the stack.
/// Stack pre:
/// Stack post:
void storeFreeMemoryPointer();
/// Allocates a number of bytes in memory as given on the stack.
/// Stack pre:
/// Stack post:
void allocateMemory();
/// Allocates a number of bytes in memory as given on the stack.
/// Stack pre:
/// Stack post:
void allocateMemory(u256 const& size);
/// Appends code that transforms memptr to (memptr - free_memptr) memptr
/// Stack pre:
/// Stack post:
void toSizeAfterFreeMemoryPointer();
/// Appends code that performs a revert, providing the given string data.
/// Will also append an error signature corresponding to Error(string).
/// @param _argumentType the type of the string argument, will be converted to memory string.
/// Stack pre: string data
/// Stack post:
void revertWithStringData(Type const& _argumentType);
void revertWithError(
std::string const& _errorName,
std::vector const& _parameterTypes,
std::vector const& _argumentTypes
);
/// Allocates a new array and copies the return data to it.
/// If the EVM does not support return data, creates an empty array.
void returnDataToArray();
/// Computes the absolute calldata offset of a tail given a base reference and the (absolute)
/// offset of the tail pointer. Performs bounds checks. If @a _type is a dynamically sized array it also
/// returns the array length on the stack.
/// Stack pre: base_ref tail_ptr
/// Stack post: tail_ref [length]
void accessCalldataTail(Type const& _type);
/// Loads data from memory to the stack.
/// @param _offset offset in memory (or calldata)
/// @param _type data type to load
/// @param _fromCalldata if true, load from calldata, not from memory
/// @param _padToWords if true, assume the data is padded to full words (32 bytes)
/// @returns the number of bytes consumed in memory.
unsigned loadFromMemory(
unsigned _offset,
Type const& _type = *TypeProvider::uint256(),
bool _fromCalldata = false,
bool _padToWords = false
);
/// Dynamic version of @see loadFromMemory, expects the memory offset on the stack.
/// Stack pre: memory_offset
/// Stack post: value... (memory_offset+length)
void loadFromMemoryDynamic(
Type const& _type,
bool _fromCalldata = false,
bool _padToWords = true,
bool _keepUpdatedMemoryOffset = true
);
/// Stores a 256 bit integer from stack in memory.
/// @param _offset offset in memory
void storeInMemory(unsigned _offset);
/// Dynamic version of @see storeInMemory, expects the memory offset below the value on the stack
/// and also updates that. For reference types, only copies the data pointer. Fails for
/// non-memory-references. For string literals no value is available on the stack.
/// @param _padToWords if true, adds zeros to pad to multiple of 32 bytes. Array elements
/// are always padded (except for byte arrays), regardless of this parameter.
/// @param _cleanup if true, adds code to cleanup the value before storing it.
/// Stack pre: memory_offset value...
/// Stack post: (memory_offset+length)
void storeInMemoryDynamic(Type const& _type, bool _padToWords = true, bool _cleanup = true);
/// Creates code that unpacks the arguments according to their types specified by a vector of TypePointers.
/// From memory if @a _fromMemory is true, otherwise from call data.
/// Calls revert if the supplied size is shorter than the static data requirements
/// or if dynamic data pointers reach outside of the area.
/// Also has a hard cap of 0x100000000 for any given length/offset field.
/// Stack pre:
/// Stack post: ...
void abiDecode(TypePointers const& _typeParameters, bool _fromMemory = false);
/// Copies values (of types @a _givenTypes) given on the stack to a location in memory given
/// at the stack top, encoding them according to the ABI as the given types @a _targetTypes.
/// Removes the values from the stack and leaves the updated memory pointer.
/// Stack pre: ...
/// Stack post:
/// Does not touch the memory-free pointer.
/// @param _padToWords if false, all values are concatenated without padding.
/// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length)
/// together with fixed-length data.
/// @param _encodeAsLibraryTypes if true, encodes for a library function, e.g. does not
/// convert storage pointer types to memory types.
/// @note the locations of target reference types are ignored, because it will always be
/// memory.
void encodeToMemory(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _padToWords,
bool _copyDynamicDataInPlace,
bool _encodeAsLibraryTypes = false
);
/// Special case of @a encodeToMemory which assumes tight packing, e.g. no zero padding
/// and dynamic data is encoded in-place.
/// Stack pre: ...
/// Stack post:
void packedEncode(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _encodeAsLibraryTypes = false
)
{
encodeToMemory(_givenTypes, _targetTypes, false, true, _encodeAsLibraryTypes);
}
/// Special case of @a encodeToMemory which assumes that everything is padded to words
/// and dynamic data is not copied in place (i.e. a proper ABI encoding).
/// Stack pre: ...
/// Stack post:
void abiEncode(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _encodeAsLibraryTypes = false
)
{
encodeToMemory(_givenTypes, _targetTypes, true, false, _encodeAsLibraryTypes);
}
/// Special case of @a encodeToMemory which assumes that everything is padded to words
/// and dynamic data is not copied in place (i.e. a proper ABI encoding).
/// Uses a new, less tested encoder implementation.
/// Stack pre: ...
/// Stack post:
void abiEncodeV2(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _encodeAsLibraryTypes = false,
bool _padToWordBoundaries = true
);
/// Decodes data from ABI encoding into internal encoding. If @a _fromMemory is set to true,
/// the data is taken from memory instead of from calldata.
/// Can allocate memory.
/// Stack pre:
/// Stack post: ...
void abiDecodeV2(TypePointers const& _parameterTypes, bool _fromMemory = false);
/// Zero-initialises (the data part of) an already allocated memory array.
/// Length has to be nonzero!
/// Stack pre:
/// Stack post:
void zeroInitialiseMemoryArray(ArrayType const& _type);
/// Copies full 32 byte words in memory (regions cannot overlap), i.e. may copy more than length.
/// Length can be zero, in this case, it copies nothing.
/// Stack pre: