Some fixes for calldata arrays.

This commit is contained in:
chriseth
2015-06-26 20:27:56 +02:00
parent 37e7f1f10d
commit 109b4eafb9
3 changed files with 26 additions and 17 deletions
+16 -11
View File
@@ -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)
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);
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)
{
solAssert(byteOffsetSize == 0, "Byte offset for array as base type.");
auto const& sourceBaseArrayType = dynamic_cast<ArrayType const&>(*sourceBaseType);
m_context << eth::Instruction::DUP3;
if (sourceIsStorage)
m_context << u256(0);
else if (sourceBaseArrayType.location() == DataLocation::Memory)
m_context << eth::Instruction::MLOAD;
m_context << eth::dupInstruction(sourceIsStorage ? 4 : 3) << u256(0);
copyArrayToStorage(
dynamic_cast<ArrayType const&>(*targetBaseType),
dynamic_cast<ArrayType const&>(*sourceBaseType)
);
copyArrayToStorage(dynamic_cast<ArrayType const&>(*targetBaseType), sourceBaseArrayType);
m_context << eth::Instruction::POP << eth::Instruction::POP;
}
else if (directCopy)
@@ -193,11 +188,18 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
if (haveByteOffsetSource)
incrementByteOffset(sourceBaseType->getStorageBytes(), 1, haveByteOffsetTarget ? 5 : 4);
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
<< eth::swapInstruction(2 + byteOffsetSize)
<< (sourceIsStorage ? sourceBaseType->getStorageSize() : sourceBaseType->getCalldataEncodedSize())
<< eth::Instruction::ADD
<< eth::swapInstruction(2 + byteOffsetSize);
}
// increment target
if (haveByteOffsetTarget)
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
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>
m_context << eth::Instruction::SWAP1;