mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Define stack slot names in types.
This commit is contained in:
parent
e786650bef
commit
6abe0a50b1
@ -151,6 +151,8 @@ util::Result<TypePointers> transformParametersToExternal(TypePointers const& _pa
|
||||
void Type::clearCache() const
|
||||
{
|
||||
m_members.clear();
|
||||
m_stackSlots.reset();
|
||||
m_stackSize.reset();
|
||||
}
|
||||
|
||||
void StorageOffsets::computeOffsets(TypePointers const& _types)
|
||||
@ -1701,15 +1703,14 @@ u256 ArrayType::storageSize() const
|
||||
return max<u256>(1, u256(size));
|
||||
}
|
||||
|
||||
unsigned ArrayType::sizeOnStack() const
|
||||
vector<tuple<string, TypePointer>> ArrayType::makeStackSlots() const
|
||||
{
|
||||
if (m_location == DataLocation::CallData)
|
||||
// offset [length] (stack top)
|
||||
return 1 + (isDynamicallySized() ? 1 : 0);
|
||||
if (m_location == DataLocation::CallData && isDynamicallySized())
|
||||
return {std::make_tuple("offset", TypeProvider::uint256()), std::make_tuple("length", TypeProvider::uint256())};
|
||||
else
|
||||
// storage slot or memory offset
|
||||
// byte offset inside storage value is omitted
|
||||
return 1;
|
||||
return {std::make_tuple(string(), nullptr)};
|
||||
}
|
||||
|
||||
string ArrayType::toString(bool _short) const
|
||||
@ -1891,6 +1892,11 @@ string ArraySliceType::toString(bool _short) const
|
||||
return m_arrayType.toString(_short) + " slice";
|
||||
}
|
||||
|
||||
std::vector<std::tuple<std::string, TypePointer>> ArraySliceType::makeStackSlots() const
|
||||
{
|
||||
return {{"offset", TypeProvider::uint256()}, {"length", TypeProvider::uint256()}};
|
||||
}
|
||||
|
||||
string ContractType::richIdentifier() const
|
||||
{
|
||||
return (m_super ? "t_super" : "t_contract") + parenthesizeUserIdentifier(m_contract.name()) + to_string(m_contract.id());
|
||||
@ -1989,6 +1995,14 @@ vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVar
|
||||
return variablesAndOffsets;
|
||||
}
|
||||
|
||||
vector<tuple<string, TypePointer>> ContractType::makeStackSlots() const
|
||||
{
|
||||
if (m_super)
|
||||
return {};
|
||||
else
|
||||
return {make_tuple("address", isPayable() ? TypeProvider::payableAddress() :TypeProvider::address())};
|
||||
}
|
||||
|
||||
void StructType::clearCache() const
|
||||
{
|
||||
Type::clearCache();
|
||||
@ -2422,12 +2436,17 @@ u256 TupleType::storageSize() const
|
||||
solAssert(false, "Storage size of non-storable tuple type requested.");
|
||||
}
|
||||
|
||||
unsigned TupleType::sizeOnStack() const
|
||||
vector<tuple<string, TypePointer>> TupleType::makeStackSlots() const
|
||||
{
|
||||
unsigned size = 0;
|
||||
vector<tuple<string, TypePointer>> slots;
|
||||
unsigned i = 1;
|
||||
for (auto const& t: components())
|
||||
size += t ? t->sizeOnStack() : 0;
|
||||
return size;
|
||||
{
|
||||
if (t)
|
||||
slots.emplace_back("component_" + std::to_string(i), t);
|
||||
++i;
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
|
||||
TypePointer TupleType::mobileType() const
|
||||
@ -2883,8 +2902,9 @@ unsigned FunctionType::storageBytes() const
|
||||
solAssert(false, "Storage size of non-storable function type requested.");
|
||||
}
|
||||
|
||||
unsigned FunctionType::sizeOnStack() const
|
||||
vector<tuple<string, TypePointer>> FunctionType::makeStackSlots() const
|
||||
{
|
||||
vector<tuple<string, TypePointer>> slots;
|
||||
Kind kind = m_kind;
|
||||
if (m_kind == Kind::SetGas || m_kind == Kind::SetValue)
|
||||
{
|
||||
@ -2892,39 +2912,42 @@ unsigned FunctionType::sizeOnStack() const
|
||||
kind = dynamic_cast<FunctionType const&>(*m_returnParameterTypes.front()).m_kind;
|
||||
}
|
||||
|
||||
unsigned size = 0;
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case Kind::External:
|
||||
case Kind::DelegateCall:
|
||||
size = 2;
|
||||
slots = {make_tuple("address", TypeProvider::address()), make_tuple("functionIdentifier", TypeProvider::fixedBytes(4))};
|
||||
break;
|
||||
case Kind::BareCall:
|
||||
case Kind::BareCallCode:
|
||||
case Kind::BareDelegateCall:
|
||||
case Kind::BareStaticCall:
|
||||
case Kind::Transfer:
|
||||
case Kind::Send:
|
||||
slots = {make_tuple("address", TypeProvider::address())};
|
||||
break;
|
||||
case Kind::Internal:
|
||||
slots = {make_tuple(string(), nullptr)};
|
||||
break;
|
||||
case Kind::ArrayPush:
|
||||
case Kind::ArrayPop:
|
||||
case Kind::ByteArrayPush:
|
||||
case Kind::Transfer:
|
||||
case Kind::Send:
|
||||
size = 1;
|
||||
slots = {make_tuple(string(), nullptr)};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_gasSet)
|
||||
size++;
|
||||
slots.emplace_back("gas", TypeProvider::uint256());
|
||||
if (m_valueSet)
|
||||
size++;
|
||||
slots.emplace_back("value", TypeProvider::uint256());
|
||||
if (m_saltSet)
|
||||
size++;
|
||||
slots.emplace_back("salt", TypeProvider::uint256());
|
||||
if (bound())
|
||||
size += m_parameterTypes.front()->sizeOnStack();
|
||||
return size;
|
||||
for (auto const& [boundName, boundType]: m_parameterTypes.front()->stackSlots())
|
||||
slots.emplace_back("self_" + boundName, boundType);
|
||||
return slots;
|
||||
}
|
||||
|
||||
FunctionTypePointer FunctionType::interfaceFunctionType() const
|
||||
@ -3418,12 +3441,12 @@ u256 TypeType::storageSize() const
|
||||
solAssert(false, "Storage size of non-storable type type requested.");
|
||||
}
|
||||
|
||||
unsigned TypeType::sizeOnStack() const
|
||||
vector<tuple<string, TypePointer>> TypeType::makeStackSlots() const
|
||||
{
|
||||
if (auto contractType = dynamic_cast<ContractType const*>(m_actualType))
|
||||
if (contractType->contractDefinition().isLibrary())
|
||||
return 1;
|
||||
return 0;
|
||||
return {make_tuple("address", TypeProvider::address())};
|
||||
return {};
|
||||
}
|
||||
|
||||
MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _currentScope) const
|
||||
|
@ -259,7 +259,26 @@ public:
|
||||
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
|
||||
/// i.e. it behaves differently in lvalue context and in value context.
|
||||
virtual bool isValueType() const { return false; }
|
||||
virtual unsigned sizeOnStack() const { return 1; }
|
||||
std::vector<std::tuple<std::string, TypePointer>> const& stackSlots() const
|
||||
{
|
||||
if (!m_stackSlots)
|
||||
m_stackSlots = makeStackSlots();
|
||||
return *m_stackSlots;
|
||||
}
|
||||
unsigned sizeOnStack() const
|
||||
{
|
||||
if (!m_stackSize)
|
||||
{
|
||||
size_t sizeOnStack = 0;
|
||||
for (auto const& slot: stackSlots())
|
||||
if (std::get<1>(slot))
|
||||
sizeOnStack += std::get<1>(slot)->sizeOnStack();
|
||||
else
|
||||
++sizeOnStack;
|
||||
m_stackSize = sizeOnStack;
|
||||
}
|
||||
return *m_stackSize;
|
||||
}
|
||||
/// If it is possible to initialize such a value in memory by just writing zeros
|
||||
/// of the size memoryHeadSize().
|
||||
virtual bool hasSimpleZeroValueInMemory() const { return true; }
|
||||
@ -336,9 +355,16 @@ protected:
|
||||
{
|
||||
return MemberList::MemberMap();
|
||||
}
|
||||
virtual std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const
|
||||
{
|
||||
return {std::make_tuple(std::string(), nullptr)};
|
||||
}
|
||||
|
||||
|
||||
/// List of member types (parameterised by scape), will be lazy-initialized.
|
||||
mutable std::map<ContractDefinition const*, std::unique_ptr<MemberList>> m_members;
|
||||
mutable std::optional<std::vector<std::tuple<std::string, TypePointer>>> m_stackSlots;
|
||||
mutable std::optional<size_t> m_stackSize;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -562,7 +588,6 @@ public:
|
||||
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
unsigned sizeOnStack() const override { return 0; }
|
||||
|
||||
std::string toString(bool) const override;
|
||||
TypePointer mobileType() const override;
|
||||
@ -571,6 +596,8 @@ public:
|
||||
|
||||
std::string const& value() const { return m_value; }
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override { return {}; }
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
@ -725,7 +752,6 @@ public:
|
||||
bool isDynamicallyEncoded() const override;
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
|
||||
unsigned sizeOnStack() const override;
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||
@ -756,6 +782,8 @@ public:
|
||||
|
||||
void clearCache() const override;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
|
||||
private:
|
||||
/// String is interpreted as a subtype of Bytes.
|
||||
enum class ArrayKind { Ordinary, Bytes, String };
|
||||
@ -785,7 +813,6 @@ public:
|
||||
bool isDynamicallySized() const override { return true; }
|
||||
bool isDynamicallyEncoded() const override { return true; }
|
||||
bool canLiveOutsideStorage() const override { return m_arrayType.canLiveOutsideStorage(); }
|
||||
unsigned sizeOnStack() const override { return 2; }
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
/// @returns true if this is valid to be stored in calldata
|
||||
@ -796,6 +823,8 @@ public:
|
||||
|
||||
std::unique_ptr<ReferenceType> copyForLocation(DataLocation, bool) const override { solAssert(false, ""); }
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
|
||||
private:
|
||||
ArrayType const& m_arrayType;
|
||||
};
|
||||
@ -825,7 +854,6 @@ public:
|
||||
unsigned storageBytes() const override { solAssert(!isSuper(), ""); return 20; }
|
||||
bool leftAligned() const override { solAssert(!isSuper(), ""); return false; }
|
||||
bool canLiveOutsideStorage() const override { return !isSuper(); }
|
||||
unsigned sizeOnStack() const override { return m_super ? 0 : 1; }
|
||||
bool isValueType() const override { return !isSuper(); }
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
@ -856,7 +884,8 @@ public:
|
||||
/// @returns a list of all state variables (including inherited) of the contract and their
|
||||
/// offsets in storage.
|
||||
std::vector<std::tuple<VariableDeclaration const*, u256, unsigned>> stateVariables() const;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
|
||||
private:
|
||||
ContractDefinition const& m_contract;
|
||||
/// If true, this is a special "super" type of m_contract containing only members that m_contract inherited
|
||||
@ -989,7 +1018,6 @@ public:
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
unsigned sizeOnStack() const override;
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
TypePointer mobileType() const override;
|
||||
/// Converts components to their temporary types and performs some wildcard matching.
|
||||
@ -997,6 +1025,8 @@ public:
|
||||
|
||||
std::vector<TypePointer> const& components() const { return m_components; }
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
|
||||
private:
|
||||
std::vector<TypePointer> const m_components;
|
||||
};
|
||||
@ -1158,7 +1188,6 @@ public:
|
||||
unsigned storageBytes() const override;
|
||||
bool isValueType() const override { return true; }
|
||||
bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
||||
unsigned sizeOnStack() const override;
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
TypePointer encodingType() const override;
|
||||
@ -1252,6 +1281,8 @@ public:
|
||||
/// @param _bound if true, the function type is set to be bound.
|
||||
FunctionTypePointer asCallableFunction(bool _inLibrary, bool _bound = false) const;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
|
||||
private:
|
||||
static TypePointers parseElementaryTypeVector(strings const& _types);
|
||||
|
||||
@ -1321,12 +1352,13 @@ public:
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
unsigned sizeOnStack() const override;
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
|
||||
private:
|
||||
TypePointer m_actualType;
|
||||
};
|
||||
@ -1346,12 +1378,13 @@ public:
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
unsigned sizeOnStack() const override { return 0; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override { return {}; }
|
||||
private:
|
||||
TypePointers m_parameterTypes;
|
||||
};
|
||||
@ -1374,11 +1407,12 @@ public:
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
unsigned sizeOnStack() const override { return 0; }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override { return {}; }
|
||||
private:
|
||||
SourceUnit const& m_sourceUnit;
|
||||
};
|
||||
@ -1413,7 +1447,6 @@ public:
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
unsigned sizeOnStack() const override { return 0; }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
@ -1422,6 +1455,8 @@ public:
|
||||
|
||||
TypePointer typeArgument() const;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override { return {}; }
|
||||
private:
|
||||
Kind m_kind;
|
||||
/// Contract type used for contract metadata magic.
|
||||
@ -1445,7 +1480,6 @@ public:
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool isValueType() const override { return true; }
|
||||
unsigned sizeOnStack() const override { return 1; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string toString(bool) const override { return "inaccessible dynamic type"; }
|
||||
TypePointer decodingType() const override;
|
||||
|
Loading…
Reference in New Issue
Block a user