mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Compute packing offsets.
This commit is contained in:
parent
fff3f98f58
commit
7f64584b7f
95
Types.cpp
95
Types.cpp
@ -35,6 +35,56 @@ namespace dev
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
std::pair<u256, unsigned> const* MemberList::getMemberStorageOffset(string const& _name) const
|
||||
{
|
||||
if (!m_storageOffsets)
|
||||
{
|
||||
bigint slotOffset = 0;
|
||||
unsigned byteOffset = 0;
|
||||
map<string, pair<u256, unsigned>> offsets;
|
||||
for (auto const& nameAndType: m_memberTypes)
|
||||
{
|
||||
TypePointer const& type = nameAndType.second;
|
||||
if (!type->canBeStored())
|
||||
continue;
|
||||
if (byteOffset + type->getStorageBytes() > 32)
|
||||
{
|
||||
// would overflow, go to next slot
|
||||
++slotOffset;
|
||||
byteOffset = 0;
|
||||
}
|
||||
if (slotOffset >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Object too large for storage."));
|
||||
offsets[nameAndType.first] = make_pair(u256(slotOffset), byteOffset);
|
||||
solAssert(type->getStorageSize() >= 1, "Invalid storage size.");
|
||||
if (type->getStorageSize() == 1 && byteOffset + type->getStorageBytes() <= 32)
|
||||
byteOffset += type->getStorageBytes();
|
||||
else
|
||||
{
|
||||
slotOffset += type->getStorageSize();
|
||||
byteOffset = 0;
|
||||
}
|
||||
}
|
||||
if (byteOffset > 0)
|
||||
++slotOffset;
|
||||
if (slotOffset >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Object too large for storage."));
|
||||
m_storageSize = u256(slotOffset);
|
||||
m_storageOffsets.reset(new decltype(offsets)(move(offsets)));
|
||||
}
|
||||
if (m_storageOffsets->count(_name))
|
||||
return &((*m_storageOffsets)[_name]);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u256 const& MemberList::getStorageSize() const
|
||||
{
|
||||
// trigger lazy computation
|
||||
getMemberStorageOffset("");
|
||||
return m_storageSize;
|
||||
}
|
||||
|
||||
TypePointer Type::fromElementaryTypeName(Token::Value _typeToken)
|
||||
{
|
||||
char const* tokenCstr = Token::toString(_typeToken);
|
||||
@ -751,12 +801,7 @@ bool StructType::operator==(Type const& _other) const
|
||||
|
||||
u256 StructType::getStorageSize() const
|
||||
{
|
||||
bigint size = 0;
|
||||
for (pair<string, TypePointer> const& member: getMembers())
|
||||
size += member.second->getStorageSize();
|
||||
if (size >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Struct too large for storage."));
|
||||
return max<u256>(1, u256(size));
|
||||
return max<u256>(1, getMembers().getStorageSize());
|
||||
}
|
||||
|
||||
bool StructType::canLiveOutsideStorage() const
|
||||
@ -787,6 +832,7 @@ MemberList const& StructType::getMembers() const
|
||||
|
||||
u256 StructType::getStorageOffsetOfMember(string const& _name) const
|
||||
{
|
||||
|
||||
//@todo cache member offset?
|
||||
u256 offset;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
|
||||
@ -811,6 +857,15 @@ bool EnumType::operator==(Type const& _other) const
|
||||
return other.m_enum == m_enum;
|
||||
}
|
||||
|
||||
unsigned EnumType::getStorageBytes() const
|
||||
{
|
||||
size_t elements = m_enum.getMembers().size();
|
||||
if (elements <= 1)
|
||||
return 1;
|
||||
else
|
||||
return dev::bytesRequired(elements - 1);
|
||||
}
|
||||
|
||||
string EnumType::toString() const
|
||||
{
|
||||
return string("enum ") + m_enum.getName();
|
||||
@ -955,6 +1010,13 @@ string FunctionType::toString() const
|
||||
return name + ")";
|
||||
}
|
||||
|
||||
u256 FunctionType::getStorageSize() const
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(
|
||||
InternalCompilerError()
|
||||
<< errinfo_comment("Storage size of non-storable function type requested."));
|
||||
}
|
||||
|
||||
unsigned FunctionType::getSizeOnStack() const
|
||||
{
|
||||
Location location = m_location;
|
||||
@ -1077,6 +1139,13 @@ string MappingType::toString() const
|
||||
return "mapping(" + getKeyType()->toString() + " => " + getValueType()->toString() + ")";
|
||||
}
|
||||
|
||||
u256 VoidType::getStorageSize() const
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(
|
||||
InternalCompilerError()
|
||||
<< errinfo_comment("Storage size of non-storable void type requested."));
|
||||
}
|
||||
|
||||
bool TypeType::operator==(Type const& _other) const
|
||||
{
|
||||
if (_other.getCategory() != getCategory())
|
||||
@ -1085,6 +1154,13 @@ bool TypeType::operator==(Type const& _other) const
|
||||
return *getActualType() == *other.getActualType();
|
||||
}
|
||||
|
||||
u256 TypeType::getStorageSize() const
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(
|
||||
InternalCompilerError()
|
||||
<< errinfo_comment("Storage size of non-storable type type requested."));
|
||||
}
|
||||
|
||||
MemberList const& TypeType::getMembers() const
|
||||
{
|
||||
// We need to lazy-initialize it because of recursive references.
|
||||
@ -1122,6 +1198,13 @@ ModifierType::ModifierType(const ModifierDefinition& _modifier)
|
||||
swap(params, m_parameterTypes);
|
||||
}
|
||||
|
||||
u256 ModifierType::getStorageSize() const
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(
|
||||
InternalCompilerError()
|
||||
<< errinfo_comment("Storage size of non-storable type type requested."));
|
||||
}
|
||||
|
||||
bool ModifierType::operator==(Type const& _other) const
|
||||
{
|
||||
if (_other.getCategory() != getCategory())
|
||||
|
30
Types.h
30
Types.h
@ -60,12 +60,19 @@ public:
|
||||
return it.second;
|
||||
return TypePointer();
|
||||
}
|
||||
/// @returns the offset of the given member in storage slots and bytes inside a slot or
|
||||
/// a nullptr if the member is not part of storage.
|
||||
std::pair<u256, unsigned> const* getMemberStorageOffset(std::string const& _name) const;
|
||||
/// @returns the number of storage slots occupied by the members.
|
||||
u256 const& getStorageSize() const;
|
||||
|
||||
MemberMap::const_iterator begin() const { return m_memberTypes.begin(); }
|
||||
MemberMap::const_iterator end() const { return m_memberTypes.end(); }
|
||||
|
||||
private:
|
||||
MemberMap m_memberTypes;
|
||||
mutable u256 m_storageSize = 0;
|
||||
mutable std::unique_ptr<std::map<std::string, std::pair<u256, unsigned>>> m_storageOffsets;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -97,6 +104,8 @@ public:
|
||||
/// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
|
||||
static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
|
||||
|
||||
/// Calculates the
|
||||
|
||||
virtual Category getCategory() const = 0;
|
||||
virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
|
||||
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
@ -126,9 +135,15 @@ public:
|
||||
unsigned getCalldataEncodedSize() const { return getCalldataEncodedSize(true); }
|
||||
/// @returns true if the type is dynamically encoded in calldata
|
||||
virtual bool isDynamicallySized() const { return false; }
|
||||
/// @returns number of bytes required to hold this value in storage.
|
||||
/// @returns the number of storage slots required to hold this value in storage.
|
||||
/// For dynamically "allocated" types, it returns the size of the statically allocated head,
|
||||
virtual u256 getStorageSize() const { return 1; }
|
||||
/// Multiple small types can be packed into a single storage slot. If such a packing is possible
|
||||
/// this function @returns the size in bytes smaller than 32. Data is moved to the next slot if
|
||||
/// it does not fit.
|
||||
/// In order to avoid computation at runtime of whether such moving is necessary, structs and
|
||||
/// array data (not each element) always start a new slot.
|
||||
virtual unsigned getStorageBytes() const { return 32; }
|
||||
/// Returns true if the type can be stored in storage.
|
||||
virtual bool canBeStored() const { return true; }
|
||||
/// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
|
||||
@ -179,6 +194,7 @@ public:
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
|
||||
virtual unsigned getCalldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_bits / 8; }
|
||||
virtual unsigned getStorageBytes() const override { return m_bits / 8; }
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; }
|
||||
@ -251,6 +267,7 @@ public:
|
||||
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
|
||||
|
||||
virtual unsigned getCalldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
|
||||
virtual unsigned getStorageBytes() const override { return m_bytes; }
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
virtual std::string toString() const override { return "bytes" + dev::toString(m_bytes); }
|
||||
@ -275,6 +292,7 @@ public:
|
||||
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
|
||||
|
||||
virtual unsigned getCalldataEncodedSize(bool _padded) const { return _padded ? 32 : 1; }
|
||||
virtual unsigned getStorageBytes() const override { return 1; }
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
virtual std::string toString() const override { return "bool"; }
|
||||
@ -348,6 +366,7 @@ public:
|
||||
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
virtual unsigned getStorageBytes() const override { return 20; }
|
||||
virtual bool isValueType() const override { return true; }
|
||||
virtual std::string toString() const override;
|
||||
|
||||
@ -411,6 +430,7 @@ public:
|
||||
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
virtual unsigned getSizeOnStack() const override { return 1; }
|
||||
virtual unsigned getStorageBytes() const override;
|
||||
virtual std::string toString() const override;
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
@ -480,7 +500,7 @@ public:
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
virtual std::string toString() const override;
|
||||
virtual bool canBeStored() const override { return false; }
|
||||
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); }
|
||||
virtual u256 getStorageSize() const override;
|
||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||
virtual unsigned getSizeOnStack() const override;
|
||||
virtual MemberList const& getMembers() const override;
|
||||
@ -565,7 +585,7 @@ public:
|
||||
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
|
||||
virtual std::string toString() const override { return "void"; }
|
||||
virtual bool canBeStored() const override { return false; }
|
||||
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); }
|
||||
virtual u256 getStorageSize() const override;
|
||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||
virtual unsigned getSizeOnStack() const override { return 0; }
|
||||
};
|
||||
@ -585,7 +605,7 @@ public:
|
||||
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
virtual bool canBeStored() const override { return false; }
|
||||
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); }
|
||||
virtual u256 getStorageSize() const override;
|
||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||
virtual unsigned getSizeOnStack() const override { return 0; }
|
||||
virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
|
||||
@ -611,7 +631,7 @@ public:
|
||||
|
||||
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
|
||||
virtual bool canBeStored() const override { return false; }
|
||||
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); }
|
||||
virtual u256 getStorageSize() const override;
|
||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||
virtual unsigned getSizeOnStack() const override { return 0; }
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
|
Loading…
Reference in New Issue
Block a user