aboutsummaryrefslogtreecommitdiffstats
path: root/CompilerUtils.cpp
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-06-25 23:51:01 +0800
committerchriseth <c@ethdev.com>2015-06-27 01:15:00 +0800
commit37e7f1f10d597efb7773417779e32f0533b6ba1b (patch)
tree7ad95be5d1c6f51b3fbad577de4494665c6eb7d3 /CompilerUtils.cpp
parent342ca948661a3f2088b3025b5f15c97d3a53f86e (diff)
downloaddexon-solidity-37e7f1f10d597efb7773417779e32f0533b6ba1b.tar
dexon-solidity-37e7f1f10d597efb7773417779e32f0533b6ba1b.tar.gz
dexon-solidity-37e7f1f10d597efb7773417779e32f0533b6ba1b.tar.bz2
dexon-solidity-37e7f1f10d597efb7773417779e32f0533b6ba1b.tar.lz
dexon-solidity-37e7f1f10d597efb7773417779e32f0533b6ba1b.tar.xz
dexon-solidity-37e7f1f10d597efb7773417779e32f0533b6ba1b.tar.zst
dexon-solidity-37e7f1f10d597efb7773417779e32f0533b6ba1b.zip
Do not copy reference types to memory in-place.
Diffstat (limited to 'CompilerUtils.cpp')
-rw-r--r--CompilerUtils.cpp182
1 files changed, 125 insertions, 57 deletions
diff --git a/CompilerUtils.cpp b/CompilerUtils.cpp
index 47a9a354..b07e14c6 100644
--- a/CompilerUtils.cpp
+++ b/CompilerUtils.cpp
@@ -54,6 +54,13 @@ void CompilerUtils::storeFreeMemoryPointer()
m_context << u256(freeMemoryPointer) << eth::Instruction::MSTORE;
}
+void CompilerUtils::allocateMemory()
+{
+ fetchFreeMemoryPointer();
+ m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD;
+ storeFreeMemoryPointer();
+}
+
void CompilerUtils::toSizeAfterFreeMemoryPointer()
{
fetchFreeMemoryPointer();
@@ -101,17 +108,20 @@ void CompilerUtils::storeInMemory(unsigned _offset)
void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries)
{
- if (_type.getCategory() == Type::Category::Array)
- ArrayUtils(m_context).copyArrayToMemory(
- dynamic_cast<ArrayType const&>(_type),
- _padToWordBoundaries
- );
+ if (auto ref = dynamic_cast<ReferenceType const*>(&_type))
+ {
+ solAssert(ref->location() == DataLocation::Memory, "");
+ storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
+ }
else
{
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
if (numBytes > 0)
{
- solAssert(_type.getSizeOnStack() == 1, "Memory store of types with stack size != 1 not implemented.");
+ solAssert(
+ _type.getSizeOnStack() == 1,
+ "Memory store of types with stack size != 1 not implemented."
+ );
m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE;
m_context << u256(numBytes) << eth::Instruction::ADD;
}
@@ -164,7 +174,10 @@ void CompilerUtils::encodeToMemory(
type = _givenTypes[i]; // delay conversion
else
convertType(*_givenTypes[i], *targetType, true);
- storeInMemoryDynamic(*type, _padToWordBoundaries);
+ if (auto arrayType = dynamic_cast<ArrayType const*>(type.get()))
+ ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
+ else
+ storeInMemoryDynamic(*type, _padToWordBoundaries);
}
stackPos += _givenTypes[i]->getSizeOnStack();
}
@@ -207,7 +220,7 @@ void CompilerUtils::encodeToMemory(
m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP;
// stack: ... <end_of_mem''> <value...>
// copy data part
- storeInMemoryDynamic(arrayType, true);
+ ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries);
// stack: ... <end_of_mem'''>
thisDynPointer++;
@@ -349,63 +362,67 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
{
// stack: <source ref> (variably sized)
unsigned stackSize = typeOnStack.getSizeOnStack();
- fetchFreeMemoryPointer();
- moveIntoStack(stackSize);
- // stack: <mem start> <source ref> (variably sized)
- if (targetType.isDynamicallySized())
+ bool fromStorage = (typeOnStack.location() == DataLocation::Storage);
+ if (fromStorage)
{
- bool fromStorage = (typeOnStack.location() == DataLocation::Storage);
- // store length
- if (fromStorage)
- {
- stackSize--;
- // remove storage offset, as requested by ArrayUtils::retrieveLength
- m_context << eth::Instruction::POP;
- }
- ArrayUtils(m_context).retrieveLength(typeOnStack);
- // Stack: <mem start> <source ref> <length>
- m_context << eth::dupInstruction(2 + stackSize) << eth::Instruction::MSTORE;
- m_context << eth::dupInstruction(1 + stackSize) << u256(0x20);
- m_context << eth::Instruction::ADD;
- moveIntoStack(stackSize);
- if (fromStorage)
- {
- m_context << u256(0);
- stackSize++;
- }
+ stackSize--;
+ // remove storage offset, as requested by ArrayUtils::retrieveLength
+ m_context << eth::Instruction::POP;
}
- else
+ ArrayUtils(m_context).retrieveLength(typeOnStack);
+
+ // allocate memory
+ // stack: <source ref> (variably sized) <length>
+ m_context << eth::Instruction::DUP1;
+ ArrayUtils(m_context).convertLengthToSize(targetType, true);
+ // stack: <source ref> (variably sized) <length> <size>
+ if (targetType.isDynamicallySized())
+ m_context << u256(0x20) << eth::Instruction::ADD;
+ allocateMemory();
+ // stack: <source ref> (variably sized) <length> <mem start>
+ m_context << eth::Instruction::DUP1;
+ moveIntoStack(2 + stackSize);
+ if (targetType.isDynamicallySized())
{
- m_context << eth::dupInstruction(1 + stackSize);
- moveIntoStack(stackSize);
+ m_context << eth::Instruction::DUP2;
+ storeInMemoryDynamic(IntegerType(256));
}
- // Stack: <mem start> <mem data start> <value>
- // Store data part.
- storeInMemoryDynamic(typeOnStack);
- // Stack <mem start> <mem end>
- storeFreeMemoryPointer();
- }
- else if (typeOnStack.location() == DataLocation::CallData)
- {
- // Stack: <offset> [<length>]
- // length is present if dynamically sized
- fetchFreeMemoryPointer();
- moveIntoStack(typeOnStack.getSizeOnStack());
- // stack: memptr calldataoffset [<length>]
- if (typeOnStack.isDynamicallySized())
+ // stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
+ if (targetType.getBaseType()->isValueType())
{
- solAssert(targetType.isDynamicallySized(), "");
- m_context << eth::Instruction::DUP3 << eth::Instruction::DUP2;
- storeInMemoryDynamic(IntegerType(256));
- moveIntoStack(typeOnStack.getSizeOnStack());
+ copyToStackTop(2 + stackSize, stackSize);
+ if (fromStorage)
+ m_context << u256(0); // add byte offset again
+ ArrayUtils(m_context).copyArrayToMemory(typeOnStack);
}
else
- m_context << eth::Instruction::DUP2 << eth::Instruction::SWAP1;
- // stack: mem_ptr mem_data_ptr calldataoffset [<length>]
- storeInMemoryDynamic(typeOnStack);
- storeFreeMemoryPointer();
+ {
+ m_context << u256(0) << eth::Instruction::SWAP1;
+ // stack: <mem start> <source ref> (variably sized) <length> <counter> <mem data pos>
+ auto repeat = m_context.newTag();
+ m_context << repeat;
+ m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3;
+ m_context << eth::Instruction::LT << eth::Instruction::ISZERO;
+ auto loopEnd = m_context.appendConditionalJump();
+ copyToStackTop(3 + stackSize, stackSize);
+ copyToStackTop(2 + stackSize, 1);
+ ArrayUtils(m_context).accessIndex(typeOnStack);
+ MemoryItem(m_context, *typeOnStack.getBaseType(), true).retrieveValue(
+ SourceLocation(),
+ true
+ );
+ convertType(*typeOnStack.getBaseType(), *targetType.getBaseType(), _cleanupNeeded);
+ storeInMemoryDynamic(*targetType.getBaseType(), true);
+ m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD;
+ m_context << eth::Instruction::SWAP1;
+ m_context.appendJumpTo(repeat);
+ m_context << loopEnd;
+ m_context << eth::Instruction::POP;
+ }
+ // stack: <mem start> <source ref> (variably sized) <length> <mem data pos updated>
+ popStackSlots(2 + stackSize);
+ // Stack: <mem start>
}
- // nothing to do for memory to memory
break;
}
default:
@@ -444,6 +461,57 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
}
}
+void CompilerUtils::pushZeroValue(const Type& _type)
+{
+ auto const* referenceType = dynamic_cast<ReferenceType const*>(&_type);
+ if (!referenceType || referenceType->location() == DataLocation::Storage)
+ {
+ for (size_t i = 0; i < _type.getSizeOnStack(); ++i)
+ m_context << u256(0);
+ return;
+ }
+ solAssert(referenceType->location() == DataLocation::Memory, "");
+
+ m_context << u256(max(32u, _type.getCalldataEncodedSize()));
+ allocateMemory();
+ m_context << eth::Instruction::DUP1;
+
+ if (auto structType = dynamic_cast<StructType const*>(&_type))
+ for (auto const& member: structType->getMembers())
+ {
+ pushZeroValue(*member.type);
+ storeInMemoryDynamic(*member.type);
+ }
+ else if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
+ {
+ if (arrayType->isDynamicallySized())
+ {
+ // zero length
+ m_context << u256(0);
+ storeInMemoryDynamic(IntegerType(256));
+ }
+ else if (arrayType->getLength() > 0)
+ {
+ m_context << arrayType->getLength() << eth::Instruction::SWAP1;
+ // stack: items_to_do memory_pos
+ auto repeat = m_context.newTag();
+ m_context << repeat;
+ pushZeroValue(*arrayType->getBaseType());
+ storeInMemoryDynamic(*arrayType->getBaseType());
+ m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1;
+ m_context << eth::Instruction::SUB << eth::Instruction::SWAP1;
+ m_context << eth::Instruction::DUP2;
+ m_context.appendConditionalJumpTo(repeat);
+ m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
+ }
+ }
+ else
+ solAssert(false, "Requested initialisation for unknown type: " + _type.toString());
+
+ // remove the updated memory pointer
+ m_context << eth::Instruction::POP;
+}
+
void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
{
unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable));