aboutsummaryrefslogtreecommitdiffstats
path: root/LValue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LValue.cpp')
-rw-r--r--LValue.cpp74
1 files changed, 45 insertions, 29 deletions
diff --git a/LValue.cpp b/LValue.cpp
index 7eec478b..f3be8678 100644
--- a/LValue.cpp
+++ b/LValue.cpp
@@ -47,6 +47,7 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
errinfo_sourceLocation(_location) <<
errinfo_comment("Stack too deep, try removing local variables.")
);
+ solAssert(stackPos + 1 >= m_size, "Size and stack pos mismatch.");
for (unsigned i = 0; i < m_size; ++i)
m_context << eth::dupInstruction(stackPos + 1);
}
@@ -175,6 +176,7 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const
{
+ CompilerUtils utils(m_context);
// stack: value storage_key storage_offset
if (m_dataType.isValueType())
{
@@ -238,52 +240,66 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
dynamic_cast<ArrayType const&>(m_dataType),
dynamic_cast<ArrayType const&>(_sourceType));
if (_move)
- CompilerUtils(m_context).popStackElement(_sourceType);
+ utils.popStackElement(_sourceType);
}
else if (m_dataType.getCategory() == Type::Category::Struct)
{
- // stack layout: source_ref source_offset target_ref target_offset
+ // 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);
+ auto const& sourceType = dynamic_cast<StructType const&>(_sourceType);
solAssert(
- structType.structDefinition() ==
- dynamic_cast<StructType const&>(_sourceType).structDefinition(),
+ structType.structDefinition() == sourceType.structDefinition(),
"Struct assignment with conversion."
);
+ solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported.");
for (auto const& member: structType.getMembers())
{
// assign each member that is not a mapping
TypePointer const& memberType = member.type;
if (memberType->getCategory() == Type::Category::Mapping)
continue;
+ TypePointer sourceMemberType = sourceType.getMemberType(member.name);
+ if (sourceType.location() == DataLocation::Storage)
+ {
+ // stack layout: source_ref source_offset target_ref target_offset
+ pair<u256, unsigned> const& offsets = sourceType.getStorageOffsetsOfMember(member.name);
+ m_context << offsets.first << eth::Instruction::DUP5 << eth::Instruction::ADD;
+ m_context << u256(offsets.second);
+ // stack: source_ref source_off target_ref target_off source_member_ref source_member_off
+ StorageItem(m_context, *sourceMemberType).retrieveValue(_location, true);
+ // stack: source_ref source_off target_ref target_off source_value...
+ }
+ else
+ {
+ solAssert(sourceType.location() == DataLocation::Memory, "");
+ // stack layout: source_ref target_ref target_offset
+ TypePointer sourceMemberType = sourceType.getMemberType(member.name);
+ m_context << sourceType.memoryOffsetOfMember(member.name);
+ m_context << eth::Instruction::DUP4 << eth::Instruction::ADD;
+ MemoryItem(m_context, *sourceMemberType).retrieveValue(_location, true);
+ // stack layout: source_ref target_ref target_offset source_value...
+ }
+ unsigned stackSize = sourceMemberType->getSizeOnStack();
pair<u256, unsigned> const& offsets = structType.getStorageOffsetsOfMember(member.name);
- 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(
- 4 + memberType->getSizeOnStack() <= 16,
- "Stack too deep, try removing local varibales."
- );
- 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 << eth::Instruction::POP;
+ m_context << eth::dupInstruction(2 + stackSize) << offsets.first << eth::Instruction::ADD;
+ m_context << u256(offsets.second);
+ // stack: source_ref [source_off] target_ref target_off source_value... target_member_ref target_member_byte_off
+ StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true);
}
+ // stack layout: source_ref [source_offset] target_ref target_offset
+ unsigned sourceStackSize = sourceType.getSizeOnStack();
if (_move)
- m_context
- << eth::Instruction::POP << eth::Instruction::POP
- << eth::Instruction::POP << eth::Instruction::POP;
- else
- m_context
- << eth::Instruction::SWAP2 << eth::Instruction::POP
- << eth::Instruction::SWAP2 << eth::Instruction::POP;
+ utils.popStackSlots(2 + sourceType.getSizeOnStack());
+ else if (sourceType.getSizeOnStack() >= 1)
+ {
+ // remove the source ref
+ solAssert(sourceStackSize <= 2, "");
+ m_context << eth::swapInstruction(sourceStackSize);
+ if (sourceStackSize == 2)
+ m_context << eth::Instruction::POP;
+ m_context << eth::Instruction::SWAP2 << eth::Instruction::POP;
+ }
}
else
BOOST_THROW_EXCEPTION(