aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Compiler.cpp11
-rw-r--r--CompilerContext.cpp16
-rw-r--r--CompilerContext.h9
-rw-r--r--CompilerUtils.cpp1
-rw-r--r--ExpressionCompiler.cpp24
-rw-r--r--LValue.cpp119
-rw-r--r--Types.cpp99
-rw-r--r--Types.h25
8 files changed, 199 insertions, 105 deletions
diff --git a/Compiler.cpp b/Compiler.cpp
index 0f4e89de..db61cc4a 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -274,10 +274,19 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
void Compiler::registerStateVariables(ContractDefinition const& _contract)
{
+ vector<VariableDeclaration const*> variables;
for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.getLinearizedBaseContracts()))
for (ASTPointer<VariableDeclaration> const& variable: contract->getStateVariables())
if (!variable->isConstant())
- m_context.addStateVariable(*variable);
+ variables.push_back(variable.get());
+ TypePointers types;
+ for (auto variable: variables)
+ types.push_back(variable->getType());
+ StorageOffsets offsets;
+ offsets.computeOffsets(types);
+ for (size_t index = 0; index < variables.size(); ++index)
+ if (auto const* offset = offsets.getOffset(index))
+ m_context.addStateVariable(*variables[index], offset->first, offset->second);
}
void Compiler::initializeStateVariables(ContractDefinition const& _contract)
diff --git a/CompilerContext.cpp b/CompilerContext.cpp
index f2bb1de2..7cade367 100644
--- a/CompilerContext.cpp
+++ b/CompilerContext.cpp
@@ -37,15 +37,13 @@ void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaratio
m_magicGlobals.insert(&_declaration);
}
-void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
+void CompilerContext::addStateVariable(
+ VariableDeclaration const& _declaration,
+ u256 const& _storageOffset,
+ unsigned _byteOffset
+)
{
- m_stateVariables[&_declaration] = m_stateVariablesSize;
- bigint newSize = bigint(m_stateVariablesSize) + _declaration.getType()->getStorageSize();
- if (newSize >= bigint(1) << 256)
- BOOST_THROW_EXCEPTION(TypeError()
- << errinfo_comment("State variable does not fit in storage.")
- << errinfo_sourceLocation(_declaration.getLocation()));
- m_stateVariablesSize = u256(newSize);
+ m_stateVariables[&_declaration] = make_pair(_storageOffset, _byteOffset);
}
void CompilerContext::startFunction(Declaration const& _function)
@@ -170,7 +168,7 @@ unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
return m_asm.deposit() - _offset - 1;
}
-u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const
+pair<u256, unsigned> CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const
{
auto it = m_stateVariables.find(&_declaration);
solAssert(it != m_stateVariables.end(), "Variable not found in storage.");
diff --git a/CompilerContext.h b/CompilerContext.h
index 76923a77..87f90d4c 100644
--- a/CompilerContext.h
+++ b/CompilerContext.h
@@ -24,6 +24,7 @@
#include <ostream>
#include <stack>
+#include <utility>
#include <libevmcore/Instruction.h>
#include <libevmcore/Assembly.h>
#include <libsolidity/ASTForward.h>
@@ -42,7 +43,7 @@ class CompilerContext
{
public:
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
- void addStateVariable(VariableDeclaration const& _declaration);
+ void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset);
void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
void removeVariable(VariableDeclaration const& _declaration);
void addAndInitializeVariable(VariableDeclaration const& _declaration);
@@ -82,7 +83,7 @@ public:
/// Converts an offset relative to the current stack height to a value that can be used later
/// with baseToCurrentStackOffset to point to the same stack element.
unsigned currentToBaseStackOffset(unsigned _offset) const;
- u256 getStorageLocationOfVariable(Declaration const& _declaration) const;
+ std::pair<u256, unsigned> getStorageLocationOfVariable(Declaration const& _declaration) const;
/// Appends a JUMPI instruction to a new tag and @returns the tag
eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); }
@@ -144,10 +145,8 @@ private:
std::set<Declaration const*> m_magicGlobals;
/// Other already compiled contracts to be used in contract creation calls.
std::map<ContractDefinition const*, bytes const*> m_compiledContracts;
- /// Size of the state variables, offset of next variable to be added.
- u256 m_stateVariablesSize = 0;
/// Storage offsets of state variables
- std::map<Declaration const*, u256> m_stateVariables;
+ std::map<Declaration const*, std::pair<u256, unsigned>> m_stateVariables;
/// Offsets of local variables on the stack (relative to stack base).
std::map<Declaration const*, unsigned> m_localVariables;
/// Labels pointing to the entry points of functions.
diff --git a/CompilerUtils.cpp b/CompilerUtils.cpp
index 5fc8bd8f..511254fa 100644
--- a/CompilerUtils.cpp
+++ b/CompilerUtils.cpp
@@ -199,7 +199,6 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
return numBytes;
}
-
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
{
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 6f533129..a0a688bb 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -67,9 +67,10 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
length += CompilerUtils(m_context).storeInMemory(length, *paramType, true);
// retrieve the position of the variable
- m_context << m_context.getStorageLocationOfVariable(_varDecl);
- TypePointer returnType = _varDecl.getType();
+ auto const& location = m_context.getStorageLocationOfVariable(_varDecl);
+ m_context << location.first;
+ TypePointer returnType = _varDecl.getType();
for (TypePointer const& paramType: paramTypes)
{
// move offset to memory
@@ -81,7 +82,6 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
returnType = dynamic_cast<MappingType const&>(*returnType).getValueType();
}
- m_context << u256(0); // @todo
unsigned retSizeOnStack = 0;
solAssert(accessorType.getReturnParameterTypes().size() >= 1, "");
if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get()))
@@ -93,21 +93,20 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{
if (types[i]->getCategory() == Type::Category::Mapping)
continue;
- m_context
- << eth::Instruction::DUP2 << structType->getStorageOffsetOfMember(names[i])
- << eth::Instruction::ADD;
- m_context << u256(0); //@todo
+ pair<u256, unsigned> const& offsets = structType->getStorageOffsetsOfMember(names[i]);
+ m_context << eth::Instruction::DUP1 << u256(offsets.first) << eth::Instruction::ADD << u256(offsets.second);
StorageItem(m_context, *types[i]).retrieveValue(SourceLocation(), true);
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
- m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1;
+ m_context << eth::Instruction::SWAP1;
retSizeOnStack += types[i]->getSizeOnStack();
}
- m_context << eth::Instruction::POP << eth::Instruction::POP;
+ m_context << eth::Instruction::POP;
}
else
{
// simple value
solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
+ m_context << u256(location.second);
StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true);
retSizeOnStack = returnType->getSizeOnStack();
}
@@ -666,10 +665,9 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case Type::Category::Struct:
{
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
- m_context << eth::Instruction::POP; //@todo
- m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD;
- //@todo
- m_context << u256(0);
+ m_context << eth::Instruction::POP; // structs always align to new slot
+ pair<u256, unsigned> const& offsets = type.getStorageOffsetsOfMember(member);
+ m_context << offsets.first << eth::Instruction::ADD << u256(offsets.second);
setLValueToStorageItem(_memberAccess);
break;
}
diff --git a/LValue.cpp b/LValue.cpp
index 8e618e87..234072bc 100644
--- a/LValue.cpp
+++ b/LValue.cpp
@@ -77,7 +77,8 @@ void StackVariable::setToZero(SourceLocation const& _location, bool) const
StorageItem::StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration):
StorageItem(_compilerContext, *_declaration.getType())
{
- m_context << m_context.getStorageLocationOfVariable(_declaration) << u256(0);
+ auto const& location = m_context.getStorageLocationOfVariable(_declaration);
+ m_context << location.first << u256(location.second);
}
StorageItem::StorageItem(CompilerContext& _compilerContext, Type const& _type):
@@ -86,7 +87,6 @@ StorageItem::StorageItem(CompilerContext& _compilerContext, Type const& _type):
if (m_dataType.isValueType())
{
solAssert(m_dataType.getStorageSize() == m_dataType.getSizeOnStack(), "");
- //@todo the meaning of getStorageSize() probably changes
solAssert(m_dataType.getStorageSize() == 1, "Invalid storage size.");
}
}
@@ -98,12 +98,18 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
return; // no distinction between value and reference for non-value types
if (!_remove)
CompilerUtils(m_context).copyToStackTop(sizeOnStack(), sizeOnStack());
- m_context
- << eth::Instruction::SWAP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1
- << u256(2) << eth::Instruction::EXP << eth::Instruction::SWAP1 << eth::Instruction::DIV;
- //@todo higher order bits might be dirty. Is this bad?
- //@todo this does not work for types that are left-aligned on the stack.
- // make those types right-aligned?
+ if (m_dataType.getStorageBytes() == 32)
+ m_context << eth::Instruction::POP << eth::Instruction::SLOAD;
+ else
+ {
+ m_context
+ << eth::Instruction::SWAP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1
+ << u256(0x100) << eth::Instruction::EXP << eth::Instruction::SWAP1 << eth::Instruction::DIV;
+ if (m_dataType.getCategory() == Type::Category::FixedBytes)
+ m_context << (u256(0x1) << (256 - 8 * m_dataType.getStorageBytes())) << eth::Instruction::MUL;
+ else
+ m_context << ((u256(0x1) << (8 * m_dataType.getStorageBytes())) - 1) << eth::Instruction::AND;
+ }
}
void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const
@@ -111,12 +117,43 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
// stack: value storage_key storage_offset
if (m_dataType.isValueType())
{
- //@todo OR the value into the storage like it is done for ByteArrayElement
- m_context
- << u256(2) << eth::Instruction::EXP << eth::Instruction::DUP3 << eth::Instruction::MUL
- << eth::Instruction::SWAP1 << eth::Instruction::SSTORE;
- if (_move)
+ solAssert(m_dataType.getStorageBytes() <= 32, "Invalid storage bytes size.");
+ solAssert(m_dataType.getStorageBytes() > 0, "Invalid storage bytes size.");
+ if (m_dataType.getStorageBytes() == 32)
+ {
+ // offset should be zero
m_context << eth::Instruction::POP;
+ if (!_move)
+ m_context << eth::Instruction::DUP2 << eth::Instruction::SWAP1;
+ m_context << eth::Instruction::SSTORE;
+ }
+ else
+ {
+ // OR the value into the other values in the storage slot
+ m_context << u256(0x100) << eth::Instruction::EXP;
+ // stack: value storage_ref multiplier
+ // fetch old value
+ m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD;
+ // stack: value storege_ref multiplier old_full_value
+ // clear bytes in old value
+ m_context
+ << eth::Instruction::DUP2 << ((u256(1) << (8 * m_dataType.getStorageBytes())) - 1)
+ << eth::Instruction::MUL;
+ m_context << eth::Instruction::NOT << eth::Instruction::AND;
+ // stack: value storage_ref multiplier cleared_value
+ m_context
+ << eth::Instruction::SWAP1 << eth::Instruction::DUP4;
+ // stack: value storage_ref cleared_value multiplier value
+ if (m_dataType.getCategory() == Type::Category::FixedBytes)
+ m_context
+ << (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(m_dataType).getNumBytes()))
+ << eth::Instruction::SWAP1 << eth::Instruction::DIV;
+ m_context << eth::Instruction::MUL << eth::Instruction::OR;
+ // stack: value storage_ref updated_value
+ m_context << eth::Instruction::SWAP1 << eth::Instruction::SSTORE;
+ if (_move)
+ m_context << eth::Instruction::POP;
+ }
}
else
{
@@ -134,28 +171,31 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
else if (m_dataType.getCategory() == Type::Category::Struct)
{
// stack layout: source_ref source_offset target_ref target_offset
+ // note that we have structs, so offsets should be zero and are ignored
auto const& structType = dynamic_cast<StructType const&>(m_dataType);
solAssert(structType == _sourceType, "Struct assignment with conversion.");
for (auto const& member: structType.getMembers())
{
- //@todo actually use offsets
// assign each member that is not a mapping
TypePointer const& memberType = member.second;
if (memberType->getCategory() == Type::Category::Mapping)
continue;
- m_context << structType.getStorageOffsetOfMember(member.first)
- << eth::Instruction::DUP5 << eth::Instruction::DUP2 << eth::Instruction::ADD;
- m_context << u256(0); // zero offset
- // stack: source_ref source_off target_ref target_off member_offset source_member_ref source_member_off
+ pair<u256, unsigned> const& offsets = structType.getStorageOffsetsOfMember(member.first);
+ m_context
+ << offsets.first << u256(offsets.second)
+ << eth::Instruction::DUP6 << eth::Instruction::DUP3
+ << eth::Instruction::ADD << eth::Instruction::DUP2;
+ // stack: source_ref source_off target_ref target_off member_slot_offset member_byte_offset source_member_ref source_member_off
StorageItem(m_context, *memberType).retrieveValue(_location, true);
// stack: source_ref source_off target_ref target_off member_offset source_value...
- solAssert(2 + memberType->getSizeOnStack() <= 16, "Stack too deep.");
- m_context << eth::dupInstruction(3 + memberType->getSizeOnStack())
- << eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::Instruction::ADD;
- // stack: source_ref source_off target_ref target_off member_offset source_value... target_member_ref
- m_context << u256(0); // zero offset
+ solAssert(4 + memberType->getSizeOnStack() <= 16, "Stack too deep.");
+ m_context
+ << eth::dupInstruction(4 + memberType->getSizeOnStack())
+ << eth::dupInstruction(3 + memberType->getSizeOnStack()) << eth::Instruction::ADD
+ << eth::dupInstruction(2 + memberType->getSizeOnStack());
+ // stack: source_ref source_off target_ref target_off member_slot_offset member_byte_offset source_value... target_member_ref target_member_byte_off
StorageItem(m_context, *memberType).storeValue(*memberType, _location, true);
- m_context << eth::Instruction::POP;
+ m_context << eth::Instruction::POP << eth::Instruction::POP;
}
if (_move)
m_context
@@ -185,6 +225,7 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
else if (m_dataType.getCategory() == Type::Category::Struct)
{
// stack layout: storage_key storage_offset
+ // @todo this can be improved for packed types
auto const& structType = dynamic_cast<StructType const&>(m_dataType);
for (auto const& member: structType.getMembers())
{
@@ -192,11 +233,10 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
TypePointer const& memberType = member.second;
if (memberType->getCategory() == Type::Category::Mapping)
continue;
- // @todo actually use offset
+ pair<u256, unsigned> const& offsets = structType.getStorageOffsetsOfMember(member.first);
m_context
- << structType.getStorageOffsetOfMember(member.first)
- << eth::Instruction::DUP3 << eth::Instruction::ADD;
- m_context << u256(0);
+ << offsets.first << eth::Instruction::DUP3 << eth::Instruction::ADD
+ << u256(offsets.second);
StorageItem(m_context, *memberType).setToZero();
}
if (_removeReference)
@@ -208,7 +248,28 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
// @todo actually use offset
if (!_removeReference)
CompilerUtils(m_context).copyToStackTop(sizeOnStack(), sizeOnStack());
- m_context << eth::Instruction::POP << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE;
+ if (m_dataType.getStorageBytes() == 32)
+ {
+ // offset should be zero
+ m_context
+ << eth::Instruction::POP << u256(0)
+ << eth::Instruction::SWAP1 << eth::Instruction::SSTORE;
+ }
+ else
+ {
+ m_context << u256(0x100) << eth::Instruction::EXP;
+ // stack: storage_ref multiplier
+ // fetch old value
+ m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD;
+ // stack: storege_ref multiplier old_full_value
+ // clear bytes in old value
+ m_context
+ << eth::Instruction::SWAP1 << ((u256(1) << (8 * m_dataType.getStorageBytes())) - 1)
+ << eth::Instruction::MUL;
+ m_context << eth::Instruction::NOT << eth::Instruction::AND;
+ // stack: storage_ref cleared_value
+ m_context << eth::Instruction::SWAP1 << eth::Instruction::SSTORE;
+ }
}
}
diff --git a/Types.cpp b/Types.cpp
index 500ae9b0..147eff1e 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -35,54 +35,72 @@ namespace dev
namespace solidity
{
-std::pair<u256, unsigned> const* MemberList::getMemberStorageOffset(string const& _name) const
+void StorageOffsets::computeOffsets(TypePointers const& _types)
{
- if (!m_storageOffsets)
+ bigint slotOffset = 0;
+ unsigned byteOffset = 0;
+ map<size_t, pair<u256, unsigned>> offsets;
+ for (size_t i = 0; i < _types.size(); ++i)
{
- bigint slotOffset = 0;
- unsigned byteOffset = 0;
- map<string, pair<u256, unsigned>> offsets;
- for (auto const& nameAndType: m_memberTypes)
+ TypePointer const& type = _types[i];
+ if (!type->canBeStored())
+ continue;
+ if (byteOffset + type->getStorageBytes() > 32)
{
- 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)
+ // 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."));
- m_storageSize = u256(slotOffset);
- m_storageOffsets.reset(new decltype(offsets)(move(offsets)));
+ offsets[i] = 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 (m_storageOffsets->count(_name))
- return &((*m_storageOffsets)[_name]);
+ if (byteOffset > 0)
+ ++slotOffset;
+ if (slotOffset >= bigint(1) << 256)
+ BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Object too large for storage."));
+ m_storageSize = u256(slotOffset);
+ swap(m_offsets, offsets);
+}
+
+pair<u256, unsigned> const* StorageOffsets::getOffset(size_t _index) const
+{
+ if (m_offsets.count(_index))
+ return &m_offsets.at(_index);
else
return nullptr;
}
+std::pair<u256, unsigned> const* MemberList::getMemberStorageOffset(string const& _name) const
+{
+ if (!m_storageOffsets)
+ {
+ TypePointers memberTypes;
+ memberTypes.reserve(m_memberTypes.size());
+ for (auto const& nameAndType: m_memberTypes)
+ memberTypes.push_back(nameAndType.second);
+ m_storageOffsets.reset(new StorageOffsets());
+ m_storageOffsets->computeOffsets(memberTypes);
+ }
+ for (size_t index = 0; index < m_memberTypes.size(); ++index)
+ if (m_memberTypes[index].first == _name)
+ return m_storageOffsets->getOffset(index);
+ return nullptr;
+}
+
u256 const& MemberList::getStorageSize() const
{
// trigger lazy computation
getMemberStorageOffset("");
- return m_storageSize;
+ return m_storageOffsets->getStorageSize();
}
TypePointer Type::fromElementaryTypeName(Token::Value _typeToken)
@@ -830,18 +848,11 @@ MemberList const& StructType::getMembers() const
return *m_members;
}
-u256 StructType::getStorageOffsetOfMember(string const& _name) const
+pair<u256, unsigned> const& StructType::getStorageOffsetsOfMember(string const& _name) const
{
-
- //@todo cache member offset?
- u256 offset;
- for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
- {
- if (variable->getName() == _name)
- return offset;
- offset += variable->getType()->getStorageSize();
- }
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested."));
+ auto const* offsets = getMembers().getMemberStorageOffset(_name);
+ solAssert(offsets, "Storage offset of non-existing member requested.");
+ return *offsets;
}
TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const
diff --git a/Types.h b/Types.h
index 5e497078..cc7a0e24 100644
--- a/Types.h
+++ b/Types.h
@@ -43,6 +43,26 @@ using TypePointer = std::shared_ptr<Type const>;
using FunctionTypePointer = std::shared_ptr<FunctionType const>;
using TypePointers = std::vector<TypePointer>;
+
+/**
+ * Helper class to compute storage offsets of members of structs and contracts.
+ */
+class StorageOffsets
+{
+public:
+ /// Resets the StorageOffsets objects and determines the position in storage for each
+ /// of the elements of @a _types.
+ void computeOffsets(TypePointers const& _types);
+ /// @returns the offset of the given member, might be null if the member is not part of storage.
+ std::pair<u256, unsigned> const* getOffset(size_t _index) const;
+ /// @returns the total number of slots occupied by all members.
+ u256 const& getStorageSize() const { return m_storageSize; }
+
+private:
+ u256 m_storageSize;
+ std::map<size_t, std::pair<u256, unsigned>> m_offsets;
+};
+
/**
* List of members of a type.
*/
@@ -71,8 +91,7 @@ public:
private:
MemberMap m_memberTypes;
- mutable u256 m_storageSize = 0;
- mutable std::unique_ptr<std::map<std::string, std::pair<u256, unsigned>>> m_storageOffsets;
+ mutable std::unique_ptr<StorageOffsets> m_storageOffsets;
};
/**
@@ -411,7 +430,7 @@ public:
virtual MemberList const& getMembers() const override;
- u256 getStorageOffsetOfMember(std::string const& _name) const;
+ std::pair<u256, unsigned> const& getStorageOffsetsOfMember(std::string const& _name) const;
private:
StructDefinition const& m_struct;