Use IRVariable's in IR code generation and implement tuples.

This commit is contained in:
Daniel Kirchner
2020-02-12 12:36:14 +01:00
parent 6abe0a50b1
commit 3c9f18b749
20 changed files with 855 additions and 649 deletions
+25 -17
View File
@@ -151,7 +151,7 @@ util::Result<TypePointers> transformParametersToExternal(TypePointers const& _pa
void Type::clearCache() const
{
m_members.clear();
m_stackSlots.reset();
m_stackItems.reset();
m_stackSize.reset();
}
@@ -1703,14 +1703,22 @@ u256 ArrayType::storageSize() const
return max<u256>(1, u256(size));
}
vector<tuple<string, TypePointer>> ArrayType::makeStackSlots() const
vector<tuple<string, TypePointer>> ArrayType::makeStackItems() const
{
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 {std::make_tuple(string(), nullptr)};
switch (m_location)
{
case DataLocation::CallData:
if (isDynamicallySized())
return {std::make_tuple("offset", TypeProvider::uint256()), std::make_tuple("length", TypeProvider::uint256())};
else
return {std::make_tuple("offset", TypeProvider::uint256())};
case DataLocation::Memory:
return {std::make_tuple("mpos", TypeProvider::uint256())};
case DataLocation::Storage:
// byte offset inside storage value is omitted
return {std::make_tuple("slot", TypeProvider::uint256())};
}
solAssert(false, "");
}
string ArrayType::toString(bool _short) const
@@ -1892,7 +1900,7 @@ string ArraySliceType::toString(bool _short) const
return m_arrayType.toString(_short) + " slice";
}
std::vector<std::tuple<std::string, TypePointer>> ArraySliceType::makeStackSlots() const
std::vector<std::tuple<std::string, TypePointer>> ArraySliceType::makeStackItems() const
{
return {{"offset", TypeProvider::uint256()}, {"length", TypeProvider::uint256()}};
}
@@ -1995,12 +2003,12 @@ vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVar
return variablesAndOffsets;
}
vector<tuple<string, TypePointer>> ContractType::makeStackSlots() const
vector<tuple<string, TypePointer>> ContractType::makeStackItems() const
{
if (m_super)
return {};
else
return {make_tuple("address", isPayable() ? TypeProvider::payableAddress() :TypeProvider::address())};
return {make_tuple("address", isPayable() ? TypeProvider::payableAddress() : TypeProvider::address())};
}
void StructType::clearCache() const
@@ -2436,7 +2444,7 @@ u256 TupleType::storageSize() const
solAssert(false, "Storage size of non-storable tuple type requested.");
}
vector<tuple<string, TypePointer>> TupleType::makeStackSlots() const
vector<tuple<string, TypePointer>> TupleType::makeStackItems() const
{
vector<tuple<string, TypePointer>> slots;
unsigned i = 1;
@@ -2902,7 +2910,7 @@ unsigned FunctionType::storageBytes() const
solAssert(false, "Storage size of non-storable function type requested.");
}
vector<tuple<string, TypePointer>> FunctionType::makeStackSlots() const
vector<tuple<string, TypePointer>> FunctionType::makeStackItems() const
{
vector<tuple<string, TypePointer>> slots;
Kind kind = m_kind;
@@ -2927,12 +2935,12 @@ vector<tuple<string, TypePointer>> FunctionType::makeStackSlots() const
slots = {make_tuple("address", TypeProvider::address())};
break;
case Kind::Internal:
slots = {make_tuple(string(), nullptr)};
slots = {make_tuple("functionIdentifier", TypeProvider::uint256())};
break;
case Kind::ArrayPush:
case Kind::ArrayPop:
case Kind::ByteArrayPush:
slots = {make_tuple(string(), nullptr)};
slots = {make_tuple("slot", TypeProvider::uint256())};
break;
default:
break;
@@ -2945,7 +2953,7 @@ vector<tuple<string, TypePointer>> FunctionType::makeStackSlots() const
if (m_saltSet)
slots.emplace_back("salt", TypeProvider::uint256());
if (bound())
for (auto const& [boundName, boundType]: m_parameterTypes.front()->stackSlots())
for (auto const& [boundName, boundType]: m_parameterTypes.front()->stackItems())
slots.emplace_back("self_" + boundName, boundType);
return slots;
}
@@ -3441,7 +3449,7 @@ u256 TypeType::storageSize() const
solAssert(false, "Storage size of non-storable type type requested.");
}
vector<tuple<string, TypePointer>> TypeType::makeStackSlots() const
vector<tuple<string, TypePointer>> TypeType::makeStackItems() const
{
if (auto contractType = dynamic_cast<ContractType const*>(m_actualType))
if (contractType->contractDefinition().isLibrary())
+26 -17
View File
@@ -259,18 +259,25 @@ 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; }
std::vector<std::tuple<std::string, TypePointer>> const& stackSlots() const
/// @returns a list of named and typed stack items that determine the layout of this type on the stack.
/// A stack item either has an empty name and type ``nullptr`` referring to a single stack slot, or
/// has a non-empty name and a valid type referring to the stack layout of that type.
/// The complete layout of a type on the stack can be obtained from its stack items recursively as follows:
/// - Each unnamed stack item is untyped (its type is ``nullptr``) and contributes exactly one stack slot.
/// - Each named stack item is typed and contributes the stack slots given by the stack items of its type.
std::vector<std::tuple<std::string, TypePointer>> const& stackItems() const
{
if (!m_stackSlots)
m_stackSlots = makeStackSlots();
return *m_stackSlots;
if (!m_stackItems)
m_stackItems = makeStackItems();
return *m_stackItems;
}
/// Total number of stack slots occupied by this type. This is the sum of ``sizeOnStack`` of all ``stackItems()``.
unsigned sizeOnStack() const
{
if (!m_stackSize)
{
size_t sizeOnStack = 0;
for (auto const& slot: stackSlots())
for (auto const& slot: stackItems())
if (std::get<1>(slot))
sizeOnStack += std::get<1>(slot)->sizeOnStack();
else
@@ -355,7 +362,9 @@ protected:
{
return MemberList::MemberMap();
}
virtual std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const
/// Generates the stack items to be returned by ``stackItems()``. Defaults
/// to exactly one unnamed and untyped stack item referring to a single stack slot.
virtual std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const
{
return {std::make_tuple(std::string(), nullptr)};
}
@@ -363,7 +372,7 @@ protected:
/// 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<std::vector<std::tuple<std::string, TypePointer>>> m_stackItems;
mutable std::optional<size_t> m_stackSize;
};
@@ -597,7 +606,7 @@ public:
std::string const& value() const { return m_value; }
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override { return {}; }
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override { return {}; }
private:
std::string m_value;
};
@@ -783,7 +792,7 @@ public:
void clearCache() const override;
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
private:
/// String is interpreted as a subtype of Bytes.
enum class ArrayKind { Ordinary, Bytes, String };
@@ -824,7 +833,7 @@ public:
std::unique_ptr<ReferenceType> copyForLocation(DataLocation, bool) const override { solAssert(false, ""); }
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
private:
ArrayType const& m_arrayType;
};
@@ -885,7 +894,7 @@ public:
/// offsets in storage.
std::vector<std::tuple<VariableDeclaration const*, u256, unsigned>> stateVariables() const;
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() 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
@@ -1026,7 +1035,7 @@ public:
std::vector<TypePointer> const& components() const { return m_components; }
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
private:
std::vector<TypePointer> const m_components;
};
@@ -1282,7 +1291,7 @@ public:
FunctionTypePointer asCallableFunction(bool _inLibrary, bool _bound = false) const;
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
private:
static TypePointers parseElementaryTypeVector(strings const& _types);
@@ -1358,7 +1367,7 @@ public:
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override;
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
private:
TypePointer m_actualType;
};
@@ -1384,7 +1393,7 @@ public:
std::string toString(bool _short) const override;
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override { return {}; }
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override { return {}; }
private:
TypePointers m_parameterTypes;
};
@@ -1412,7 +1421,7 @@ public:
std::string toString(bool _short) const override;
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override { return {}; }
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override { return {}; }
private:
SourceUnit const& m_sourceUnit;
};
@@ -1456,7 +1465,7 @@ public:
TypePointer typeArgument() const;
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackSlots() const override { return {}; }
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override { return {}; }
private:
Kind m_kind;
/// Contract type used for contract metadata magic.