|
|
@ -38,10 +38,10 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons |
|
|
|
// need to leave "target_ref target_byte_off" on the stack at the end
|
|
|
|
|
|
|
|
// stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top)
|
|
|
|
solAssert(_targetType.location() == ReferenceType::Location::Storage, ""); |
|
|
|
solAssert(_targetType.location() == DataLocation::Storage, ""); |
|
|
|
solAssert( |
|
|
|
_sourceType.location() == ReferenceType::Location::CallData || |
|
|
|
_sourceType.location() == ReferenceType::Location::Storage, |
|
|
|
_sourceType.location() == DataLocation::CallData || |
|
|
|
_sourceType.location() == DataLocation::Storage, |
|
|
|
"Given array location not implemented." |
|
|
|
); |
|
|
|
|
|
|
@ -51,7 +51,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons |
|
|
|
|
|
|
|
// TODO unroll loop for small sizes
|
|
|
|
|
|
|
|
bool sourceIsStorage = _sourceType.location() == ReferenceType::Location::Storage; |
|
|
|
bool sourceIsStorage = _sourceType.location() == DataLocation::Storage; |
|
|
|
bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType; |
|
|
|
bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->getStorageBytes() <= 16; |
|
|
|
bool haveByteOffsetTarget = !directCopy && targetBaseType->getStorageBytes() <= 16; |
|
|
@ -69,7 +69,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons |
|
|
|
m_context << eth::Instruction::POP; |
|
|
|
// stack: target_ref source_ref [source_length]
|
|
|
|
// retrieve source length
|
|
|
|
if (_sourceType.location() != ReferenceType::Location::CallData || !_sourceType.isDynamicallySized()) |
|
|
|
if (_sourceType.location() != DataLocation::CallData || !_sourceType.isDynamicallySized()) |
|
|
|
retrieveLength(_sourceType); // otherwise, length is already there
|
|
|
|
// stack: target_ref source_ref source_length
|
|
|
|
m_context << eth::Instruction::DUP3; |
|
|
@ -82,7 +82,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons |
|
|
|
if (sourceBaseType->getCategory() == Type::Category::Mapping) |
|
|
|
{ |
|
|
|
solAssert(targetBaseType->getCategory() == Type::Category::Mapping, ""); |
|
|
|
solAssert(_sourceType.location() == ReferenceType::Location::Storage, ""); |
|
|
|
solAssert(_sourceType.location() == DataLocation::Storage, ""); |
|
|
|
// nothing to copy
|
|
|
|
m_context |
|
|
|
<< eth::Instruction::POP << eth::Instruction::POP |
|
|
@ -106,7 +106,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons |
|
|
|
eth::AssemblyItem copyLoopEndWithoutByteOffset = m_context.newTag(); |
|
|
|
m_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset); |
|
|
|
|
|
|
|
if (_sourceType.location() == ReferenceType::Location::Storage && _sourceType.isDynamicallySized()) |
|
|
|
if (_sourceType.location() == DataLocation::Storage && _sourceType.isDynamicallySized()) |
|
|
|
CompilerUtils(m_context).computeHashStatic(); |
|
|
|
// stack: target_ref target_data_end source_length target_data_pos source_data_pos
|
|
|
|
m_context << eth::Instruction::SWAP2; |
|
|
@ -155,7 +155,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons |
|
|
|
// checking is easier.
|
|
|
|
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
|
|
|
|
m_context << eth::dupInstruction(3 + byteOffsetSize); |
|
|
|
if (_sourceType.location() == ReferenceType::Location::Storage) |
|
|
|
if (_sourceType.location() == DataLocation::Storage) |
|
|
|
{ |
|
|
|
if (haveByteOffsetSource) |
|
|
|
m_context << eth::Instruction::DUP2; |
|
|
@ -231,7 +231,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons |
|
|
|
void ArrayUtils::clearArray(ArrayType const& _type) const |
|
|
|
{ |
|
|
|
unsigned stackHeightStart = m_context.getStackHeight(); |
|
|
|
solAssert(_type.location() == ReferenceType::Location::Storage, ""); |
|
|
|
solAssert(_type.location() == DataLocation::Storage, ""); |
|
|
|
if (_type.getBaseType()->getStorageBytes() < 32) |
|
|
|
{ |
|
|
|
solAssert(_type.getBaseType()->isValueType(), "Invalid storage size for non-value type."); |
|
|
@ -286,7 +286,7 @@ void ArrayUtils::clearArray(ArrayType const& _type) const |
|
|
|
|
|
|
|
void ArrayUtils::clearDynamicArray(ArrayType const& _type) const |
|
|
|
{ |
|
|
|
solAssert(_type.location() == ReferenceType::Location::Storage, ""); |
|
|
|
solAssert(_type.location() == DataLocation::Storage, ""); |
|
|
|
solAssert(_type.isDynamicallySized(), ""); |
|
|
|
|
|
|
|
unsigned stackHeightStart = m_context.getStackHeight(); |
|
|
@ -314,7 +314,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const |
|
|
|
|
|
|
|
void ArrayUtils::resizeDynamicArray(const ArrayType& _type) const |
|
|
|
{ |
|
|
|
solAssert(_type.location() == ReferenceType::Location::Storage, ""); |
|
|
|
solAssert(_type.location() == DataLocation::Storage, ""); |
|
|
|
solAssert(_type.isDynamicallySized(), ""); |
|
|
|
if (!_type.isByteArray() && _type.getBaseType()->getStorageBytes() < 32) |
|
|
|
solAssert(_type.getBaseType()->isValueType(), "Invalid storage size for non-value type."); |
|
|
@ -399,7 +399,7 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const |
|
|
|
|
|
|
|
void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) const |
|
|
|
{ |
|
|
|
if (_arrayType.location() == ReferenceType::Location::Storage) |
|
|
|
if (_arrayType.location() == DataLocation::Storage) |
|
|
|
{ |
|
|
|
if (_arrayType.getBaseType()->getStorageSize() <= 1) |
|
|
|
{ |
|
|
@ -437,13 +437,13 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const |
|
|
|
m_context << eth::Instruction::DUP1; |
|
|
|
switch (_arrayType.location()) |
|
|
|
{ |
|
|
|
case ReferenceType::Location::CallData: |
|
|
|
case DataLocation::CallData: |
|
|
|
// length is stored on the stack
|
|
|
|
break; |
|
|
|
case ReferenceType::Location::Memory: |
|
|
|
case DataLocation::Memory: |
|
|
|
m_context << eth::Instruction::MLOAD; |
|
|
|
break; |
|
|
|
case ReferenceType::Location::Storage: |
|
|
|
case DataLocation::Storage: |
|
|
|
m_context << eth::Instruction::SLOAD; |
|
|
|
break; |
|
|
|
} |
|
|
@ -452,16 +452,16 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const |
|
|
|
|
|
|
|
void ArrayUtils::accessIndex(ArrayType const& _arrayType) const |
|
|
|
{ |
|
|
|
ReferenceType::Location location = _arrayType.location(); |
|
|
|
DataLocation location = _arrayType.location(); |
|
|
|
eth::Instruction load = |
|
|
|
location == ReferenceType::Location::Storage ? eth::Instruction::SLOAD : |
|
|
|
location == ReferenceType::Location::Memory ? eth::Instruction::MLOAD : |
|
|
|
location == DataLocation::Storage ? eth::Instruction::SLOAD : |
|
|
|
location == DataLocation::Memory ? eth::Instruction::MLOAD : |
|
|
|
eth::Instruction::CALLDATALOAD; |
|
|
|
|
|
|
|
// retrieve length
|
|
|
|
if (!_arrayType.isDynamicallySized()) |
|
|
|
m_context << _arrayType.getLength(); |
|
|
|
else if (location == ReferenceType::Location::CallData) |
|
|
|
else if (location == DataLocation::CallData) |
|
|
|
// length is stored on the stack
|
|
|
|
m_context << eth::Instruction::SWAP1; |
|
|
|
else |
|
|
@ -476,20 +476,20 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const |
|
|
|
m_context << eth::Instruction::SWAP1; |
|
|
|
if (_arrayType.isDynamicallySized()) |
|
|
|
{ |
|
|
|
if (location == ReferenceType::Location::Storage) |
|
|
|
if (location == DataLocation::Storage) |
|
|
|
CompilerUtils(m_context).computeHashStatic(); |
|
|
|
else if (location == ReferenceType::Location::Memory) |
|
|
|
else if (location == DataLocation::Memory) |
|
|
|
m_context << u256(32) << eth::Instruction::ADD; |
|
|
|
} |
|
|
|
// stack: <index> <data_ref>
|
|
|
|
switch (location) |
|
|
|
{ |
|
|
|
case ReferenceType::Location::CallData: |
|
|
|
case DataLocation::CallData: |
|
|
|
if (!_arrayType.isByteArray()) |
|
|
|
m_context |
|
|
|
<< eth::Instruction::SWAP1 |
|
|
|
<< _arrayType.getBaseType()->getCalldataEncodedSize() |
|
|
|
<< eth::Instruction::MUL; |
|
|
|
{ |
|
|
|
m_context << eth::Instruction::SWAP1; |
|
|
|
m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL; |
|
|
|
} |
|
|
|
m_context << eth::Instruction::ADD; |
|
|
|
if (_arrayType.getBaseType()->isValueType()) |
|
|
|
CompilerUtils(m_context).loadFromMemoryDynamic( |
|
|
@ -499,7 +499,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const |
|
|
|
false |
|
|
|
); |
|
|
|
break; |
|
|
|
case ReferenceType::Location::Storage: |
|
|
|
case DataLocation::Storage: |
|
|
|
m_context << eth::Instruction::SWAP1; |
|
|
|
if (_arrayType.getBaseType()->getStorageBytes() <= 16) |
|
|
|
{ |
|
|
@ -527,7 +527,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const |
|
|
|
m_context << eth::Instruction::ADD << u256(0); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ReferenceType::Location::Memory: |
|
|
|
case DataLocation::Memory: |
|
|
|
solAssert(false, "Memory lvalues not yet implemented."); |
|
|
|
} |
|
|
|
} |
|
|
|