Browse Source

Some fixes for calldata arrays.

cl-refactor
chriseth 9 years ago
parent
commit
766c3ee37b
  1. 27
      libsolidity/ArrayUtils.cpp
  2. 9
      libsolidity/Compiler.cpp
  3. 7
      libsolidity/CompilerUtils.cpp

27
libsolidity/ArrayUtils.cpp

@ -39,11 +39,6 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top) // stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top)
solAssert(_targetType.location() == DataLocation::Storage, ""); solAssert(_targetType.location() == DataLocation::Storage, "");
if (_sourceType.location() == DataLocation::Memory)
solAssert(
_sourceType.getBaseType()->isValueType(),
"Copying arrays of non-value-types to storage not yet implemented."
);
IntegerType uint256(256); IntegerType uint256(256);
Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType()); Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType());
@ -139,14 +134,14 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
if (sourceBaseType->getCategory() == Type::Category::Array) if (sourceBaseType->getCategory() == Type::Category::Array)
{ {
solAssert(byteOffsetSize == 0, "Byte offset for array as base type."); solAssert(byteOffsetSize == 0, "Byte offset for array as base type.");
auto const& sourceBaseArrayType = dynamic_cast<ArrayType const&>(*sourceBaseType);
m_context << eth::Instruction::DUP3; m_context << eth::Instruction::DUP3;
if (sourceIsStorage) if (sourceIsStorage)
m_context << u256(0); m_context << u256(0);
else if (sourceBaseArrayType.location() == DataLocation::Memory)
m_context << eth::Instruction::MLOAD;
m_context << eth::dupInstruction(sourceIsStorage ? 4 : 3) << u256(0); m_context << eth::dupInstruction(sourceIsStorage ? 4 : 3) << u256(0);
copyArrayToStorage( copyArrayToStorage(dynamic_cast<ArrayType const&>(*targetBaseType), sourceBaseArrayType);
dynamic_cast<ArrayType const&>(*targetBaseType),
dynamic_cast<ArrayType const&>(*sourceBaseType)
);
m_context << eth::Instruction::POP << eth::Instruction::POP; m_context << eth::Instruction::POP << eth::Instruction::POP;
} }
else if (directCopy) else if (directCopy)
@ -193,11 +188,18 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
if (haveByteOffsetSource) if (haveByteOffsetSource)
incrementByteOffset(sourceBaseType->getStorageBytes(), 1, haveByteOffsetTarget ? 5 : 4); incrementByteOffset(sourceBaseType->getStorageBytes(), 1, haveByteOffsetTarget ? 5 : 4);
else else
{
m_context << eth::swapInstruction(2 + byteOffsetSize);
if (sourceIsStorage)
m_context << sourceBaseType->getStorageSize();
else if (_sourceType.location() == DataLocation::Memory)
m_context << sourceBaseType->memoryHeadSize();
else
m_context << sourceBaseType->getCalldataEncodedSize(true);
m_context m_context
<< eth::swapInstruction(2 + byteOffsetSize)
<< (sourceIsStorage ? sourceBaseType->getStorageSize() : sourceBaseType->getCalldataEncodedSize())
<< eth::Instruction::ADD << eth::Instruction::ADD
<< eth::swapInstruction(2 + byteOffsetSize); << eth::swapInstruction(2 + byteOffsetSize);
}
// increment target // increment target
if (haveByteOffsetTarget) if (haveByteOffsetTarget)
incrementByteOffset(targetBaseType->getStorageBytes(), byteOffsetSize, byteOffsetSize + 2); incrementByteOffset(targetBaseType->getStorageBytes(), byteOffsetSize, byteOffsetSize + 2);
@ -696,6 +698,9 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c
// out-of-bounds access throws exception // out-of-bounds access throws exception
m_context.appendConditionalJumpTo(m_context.errorTag()); m_context.appendConditionalJumpTo(m_context.errorTag());
} }
else if (location == DataLocation::CallData && _arrayType.isDynamicallySized())
// remove length if present
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
// stack: <base_ref> <index> // stack: <base_ref> <index>
m_context << eth::Instruction::SWAP1; m_context << eth::Instruction::SWAP1;

9
libsolidity/Compiler.cpp

@ -261,7 +261,7 @@ void Compiler::appendCalldataUnpacker(
{ {
// We do not check the calldata size, everything is zero-paddedd // We do not check the calldata size, everything is zero-paddedd
//@todo this does not yet support nested arrays //@todo this does not yet support nested dynamic arrays
if (_startOffset == u256(-1)) if (_startOffset == u256(-1))
_startOffset = u256(CompilerUtils::dataStartOffset); _startOffset = u256(CompilerUtils::dataStartOffset);
@ -279,6 +279,12 @@ void Compiler::appendCalldataUnpacker(
solAssert(!arrayType.getBaseType()->isDynamicallySized(), "Nested arrays not yet implemented."); solAssert(!arrayType.getBaseType()->isDynamicallySized(), "Nested arrays not yet implemented.");
if (_fromMemory) if (_fromMemory)
{ {
solAssert(
arrayType.getBaseType()->isValueType(),
"Nested memory arrays not yet implemented here."
);
// @todo If base type is an array or struct, it is still calldata-style encoded, so
// we would have to convert it like below.
solAssert(arrayType.location() == DataLocation::Memory, ""); solAssert(arrayType.location() == DataLocation::Memory, "");
// compute data pointer // compute data pointer
m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD; m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD;
@ -311,6 +317,7 @@ void Compiler::appendCalldataUnpacker(
} }
if (arrayType.location() == DataLocation::Memory) if (arrayType.location() == DataLocation::Memory)
{ {
// stack: calldata_ref [length] next_calldata
// copy to memory // copy to memory
// move calldata type up again // move calldata type up again
CompilerUtils(m_context).moveIntoStack(calldataType->getSizeOnStack()); CompilerUtils(m_context).moveIntoStack(calldataType->getSizeOnStack());

7
libsolidity/CompilerUtils.cpp

@ -390,6 +390,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos> // stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
if (targetType.getBaseType()->isValueType()) if (targetType.getBaseType()->isValueType())
{ {
solAssert(typeOnStack.getBaseType()->isValueType(), "");
copyToStackTop(2 + stackSize, stackSize); copyToStackTop(2 + stackSize, stackSize);
if (fromStorage) if (fromStorage)
m_context << u256(0); // add byte offset again m_context << u256(0); // add byte offset again
@ -406,11 +407,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
auto loopEnd = m_context.appendConditionalJump(); auto loopEnd = m_context.appendConditionalJump();
copyToStackTop(3 + stackSize, stackSize); copyToStackTop(3 + stackSize, stackSize);
copyToStackTop(2 + stackSize, 1); copyToStackTop(2 + stackSize, 1);
ArrayUtils(m_context).accessIndex(typeOnStack); ArrayUtils(m_context).accessIndex(typeOnStack, false);
MemoryItem(m_context, *typeOnStack.getBaseType(), true).retrieveValue(
SourceLocation(),
true
);
convertType(*typeOnStack.getBaseType(), *targetType.getBaseType(), _cleanupNeeded); convertType(*typeOnStack.getBaseType(), *targetType.getBaseType(), _cleanupNeeded);
storeInMemoryDynamic(*targetType.getBaseType(), true); storeInMemoryDynamic(*targetType.getBaseType(), true);
m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD; m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD;

Loading…
Cancel
Save