mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Split calldataEncodedSize into calldataEncodedSize, calldataEncodedTailSize and calldataHeadSize and fix all usages.
This commit is contained in:
committed by
Daniel Kirchner
parent
d44f680a51
commit
15631a7fbe
+46
-25
@@ -1647,15 +1647,13 @@ bool ArrayType::validForCalldata() const
|
||||
if (auto arrayBaseType = dynamic_cast<ArrayType const*>(baseType()))
|
||||
if (!arrayBaseType->validForCalldata())
|
||||
return false;
|
||||
return unlimitedCalldataEncodedSize(true) <= numeric_limits<unsigned>::max();
|
||||
return isDynamicallySized() || unlimitedStaticCalldataSize(true) <= numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
bigint ArrayType::unlimitedCalldataEncodedSize(bool _padded) const
|
||||
bigint ArrayType::unlimitedStaticCalldataSize(bool _padded) const
|
||||
{
|
||||
if (isDynamicallySized())
|
||||
return 32;
|
||||
// Array elements are always padded.
|
||||
bigint size = bigint(length()) * (isByteArray() ? 1 : baseType()->calldataEncodedSize(true));
|
||||
solAssert(!isDynamicallySized(), "");
|
||||
bigint size = bigint(length()) * calldataStride();
|
||||
if (_padded)
|
||||
size = ((size + 31) / 32) * 32;
|
||||
return size;
|
||||
@@ -1663,7 +1661,20 @@ bigint ArrayType::unlimitedCalldataEncodedSize(bool _padded) const
|
||||
|
||||
unsigned ArrayType::calldataEncodedSize(bool _padded) const
|
||||
{
|
||||
bigint size = unlimitedCalldataEncodedSize(_padded);
|
||||
solAssert(!isDynamicallyEncoded(), "");
|
||||
bigint size = unlimitedStaticCalldataSize(_padded);
|
||||
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned.");
|
||||
return unsigned(size);
|
||||
}
|
||||
|
||||
unsigned ArrayType::calldataEncodedTailSize() const
|
||||
{
|
||||
solAssert(isDynamicallyEncoded(), "");
|
||||
if (isDynamicallySized())
|
||||
// We do not know the dynamic length itself, but at least the uint256 containing the
|
||||
// length must still be present.
|
||||
return 32;
|
||||
bigint size = unlimitedStaticCalldataSize(false);
|
||||
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned.");
|
||||
return unsigned(size);
|
||||
}
|
||||
@@ -1832,10 +1843,11 @@ TypeResult ArrayType::interfaceType(bool _inLibrary) const
|
||||
return result;
|
||||
}
|
||||
|
||||
u256 ArrayType::memorySize() const
|
||||
u256 ArrayType::memoryDataSize() const
|
||||
{
|
||||
solAssert(!isDynamicallySized(), "");
|
||||
solAssert(m_location == DataLocation::Memory, "");
|
||||
solAssert(!isByteArray(), "");
|
||||
bigint size = bigint(m_length) * m_baseType->memoryHeadSize();
|
||||
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit u256.");
|
||||
return u256(size);
|
||||
@@ -1992,20 +2004,33 @@ bool StructType::operator==(Type const& _other) const
|
||||
return ReferenceType::operator==(other) && other.m_struct == m_struct;
|
||||
}
|
||||
|
||||
|
||||
unsigned StructType::calldataEncodedSize(bool) const
|
||||
{
|
||||
solAssert(!isDynamicallyEncoded(), "");
|
||||
|
||||
unsigned size = 0;
|
||||
for (auto const& member: members(nullptr))
|
||||
if (!member.type->canLiveOutsideStorage())
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
// Struct members are always padded.
|
||||
unsigned memberSize = member.type->calldataEncodedSize(true);
|
||||
if (memberSize == 0)
|
||||
return 0;
|
||||
size += memberSize;
|
||||
}
|
||||
{
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
// Struct members are always padded.
|
||||
size += member.type->calldataEncodedSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
unsigned StructType::calldataEncodedTailSize() const
|
||||
{
|
||||
solAssert(isDynamicallyEncoded(), "");
|
||||
|
||||
unsigned size = 0;
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
// Struct members are always padded.
|
||||
size += member.type->calldataHeadSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -2017,12 +2042,8 @@ unsigned StructType::calldataOffsetOfMember(std::string const& _member) const
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
if (member.name == _member)
|
||||
return offset;
|
||||
{
|
||||
// Struct members are always padded.
|
||||
unsigned memberSize = member.type->calldataEncodedSize(true);
|
||||
solAssert(memberSize != 0, "");
|
||||
offset += memberSize;
|
||||
}
|
||||
// Struct members are always padded.
|
||||
offset += member.type->calldataHeadSize();
|
||||
}
|
||||
solAssert(false, "Struct member not found.");
|
||||
}
|
||||
@@ -2040,7 +2061,7 @@ bool StructType::isDynamicallyEncoded() const
|
||||
return false;
|
||||
}
|
||||
|
||||
u256 StructType::memorySize() const
|
||||
u256 StructType::memoryDataSize() const
|
||||
{
|
||||
u256 size;
|
||||
for (auto const& t: memoryMemberTypes())
|
||||
|
||||
+34
-12
@@ -208,16 +208,32 @@ public:
|
||||
virtual bool operator==(Type const& _other) const { return category() == _other.category(); }
|
||||
virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); }
|
||||
|
||||
/// @returns number of bytes used by this type when encoded for CALL. If it is a dynamic type,
|
||||
/// returns the size of the pointer (usually 32). Returns 0 if the type cannot be encoded
|
||||
/// in calldata.
|
||||
/// @returns number of bytes used by this type when encoded for CALL. Cannot be used for
|
||||
/// dynamically encoded types.
|
||||
/// Always returns a value greater than zero and throws if the type cannot be encoded in calldata
|
||||
/// (or is dynamically encoded).
|
||||
/// If @a _padded then it is assumed that each element is padded to a multiple of 32 bytes.
|
||||
virtual unsigned calldataEncodedSize(bool _padded) const { (void)_padded; return 0; }
|
||||
virtual unsigned calldataEncodedSize(bool _padded) const { (void)_padded; solAssert(false, ""); }
|
||||
/// Convenience version of @see calldataEncodedSize(bool)
|
||||
unsigned calldataEncodedSize() const { return calldataEncodedSize(true); }
|
||||
/// @returns the distance between two elements of this type in a calldata array, tuple or struct.
|
||||
/// For statically encoded types this is the same as calldataEncodedSize(true).
|
||||
/// For dynamically encoded types this is the distance between two tail pointers, i.e. 32.
|
||||
/// Always returns a value greater than zero and throws if the type cannot be encoded in calldata.
|
||||
unsigned calldataHeadSize() const { return isDynamicallyEncoded() ? 32 : calldataEncodedSize(true); }
|
||||
/// @returns the (minimal) size of the calldata tail for this type. Can only be used for
|
||||
/// dynamically encoded types. For dynamically-sized arrays this is 32 (the size of the length),
|
||||
/// for statically-sized, but dynamically encoded arrays this is 32*length(), for structs
|
||||
/// this is the sum of the calldataHeadSize's of its members.
|
||||
/// Always returns a value greater than zero and throws if the type cannot be encoded in calldata
|
||||
/// (or is not dynamically encoded).
|
||||
virtual unsigned calldataEncodedTailSize() const { solAssert(false, ""); }
|
||||
/// @returns the size of this data type in bytes when stored in memory. For memory-reference
|
||||
/// types, this is the size of the memory pointer.
|
||||
virtual unsigned memoryHeadSize() const { return calldataEncodedSize(); }
|
||||
/// Convenience version of @see calldataEncodedSize(bool)
|
||||
unsigned calldataEncodedSize() const { return calldataEncodedSize(true); }
|
||||
/// @returns the size of this data type in bytes when stored in memory. For memory-reference
|
||||
/// types, this is the size of the actual data area, if it is statically-sized.
|
||||
virtual u256 memoryDataSize() const { return calldataEncodedSize(); }
|
||||
/// @returns true if the type is a dynamic array
|
||||
virtual bool isDynamicallySized() const { return false; }
|
||||
/// @returns true if the type is dynamically encoded in the ABI
|
||||
@@ -634,6 +650,10 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
unsigned memoryHeadSize() const override { return 32; }
|
||||
u256 memoryDataSize() const override = 0;
|
||||
|
||||
unsigned calldataEncodedSize(bool) const override = 0;
|
||||
unsigned calldataEncodedTailSize() const override = 0;
|
||||
|
||||
/// @returns a copy of this type with location (recursively) changed to @a _location,
|
||||
/// whereas isPointer is only shallowly changed - the deep copy is always a bound reference.
|
||||
@@ -701,7 +721,8 @@ public:
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
unsigned calldataEncodedSize(bool _padded) const override;
|
||||
unsigned calldataEncodedSize(bool) const override;
|
||||
unsigned calldataEncodedTailSize() const override;
|
||||
bool isDynamicallySized() const override { return m_hasDynamicLength; }
|
||||
bool isDynamicallyEncoded() const override;
|
||||
u256 storageSize() const override;
|
||||
@@ -724,12 +745,12 @@ public:
|
||||
bool isString() const { return m_arrayKind == ArrayKind::String; }
|
||||
Type const* baseType() const { solAssert(!!m_baseType, ""); return m_baseType; }
|
||||
u256 const& length() const { return m_length; }
|
||||
u256 memorySize() const;
|
||||
u256 memoryDataSize() const override;
|
||||
|
||||
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||
|
||||
/// The offset to advance in calldata to move from one array element to the next.
|
||||
unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataEncodedSize(); }
|
||||
unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataHeadSize(); }
|
||||
/// The offset to advance in memory to move from one array element to the next.
|
||||
unsigned memoryStride() const { return isByteArray() ? 1 : m_baseType->memoryHeadSize(); }
|
||||
/// The offset to advance in storage to move from one array element to the next.
|
||||
@@ -741,7 +762,7 @@ private:
|
||||
/// String is interpreted as a subtype of Bytes.
|
||||
enum class ArrayKind { Ordinary, Bytes, String };
|
||||
|
||||
bigint unlimitedCalldataEncodedSize(bool _padded) const;
|
||||
bigint unlimitedStaticCalldataSize(bool _padded) const;
|
||||
|
||||
///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
|
||||
ArrayKind m_arrayKind = ArrayKind::Ordinary;
|
||||
@@ -829,9 +850,10 @@ public:
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
unsigned calldataEncodedSize(bool _padded) const override;
|
||||
unsigned calldataEncodedSize(bool) const override;
|
||||
unsigned calldataEncodedTailSize() const override;
|
||||
bool isDynamicallyEncoded() const override;
|
||||
u256 memorySize() const;
|
||||
u256 memoryDataSize() const override;
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
Reference in New Issue
Block a user