|
|
@ -388,10 +388,7 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con |
|
|
|
{ |
|
|
|
if (_arrayType.getLocation() == ArrayType::Location::Storage) |
|
|
|
{ |
|
|
|
if (_arrayType.isByteArray()) |
|
|
|
m_context << u256(31) << eth::Instruction::ADD |
|
|
|
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV; |
|
|
|
else if (_arrayType.getBaseType()->getStorageSize() <= 1) |
|
|
|
if (_arrayType.getBaseType()->getStorageSize() <= 1) |
|
|
|
{ |
|
|
|
unsigned baseBytes = _arrayType.getBaseType()->getStorageBytes(); |
|
|
|
if (baseBytes == 0) |
|
|
@ -465,82 +462,61 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const |
|
|
|
|
|
|
|
m_context << legalAccess; |
|
|
|
// stack: <base_ref> <index>
|
|
|
|
if (_arrayType.isByteArray()) |
|
|
|
switch (location) |
|
|
|
{ |
|
|
|
case ArrayType::Location::Storage: |
|
|
|
// byte array index storage lvalue on stack (goal):
|
|
|
|
// <ref> <byte_number> = <base_ref + index / 32> <index % 32>
|
|
|
|
m_context << u256(32) << eth::Instruction::SWAP2; |
|
|
|
m_context << eth::Instruction::SWAP1; |
|
|
|
if (_arrayType.isDynamicallySized()) |
|
|
|
{ |
|
|
|
if (location == ArrayType::Location::Storage) |
|
|
|
CompilerUtils(m_context).computeHashStatic(); |
|
|
|
// stack: 32 index data_ref
|
|
|
|
else if (location == ArrayType::Location::Memory) |
|
|
|
m_context << u256(32) << eth::Instruction::ADD; |
|
|
|
} |
|
|
|
// stack: <index> <data_ref>
|
|
|
|
switch (location) |
|
|
|
{ |
|
|
|
case ArrayType::Location::CallData: |
|
|
|
if (!_arrayType.isByteArray()) |
|
|
|
m_context |
|
|
|
<< eth::Instruction::SWAP1 << _arrayType.getBaseType()->getCalldataEncodedSize() |
|
|
|
<< eth::Instruction::MUL; |
|
|
|
m_context << eth::Instruction::ADD; |
|
|
|
if (_arrayType.getBaseType()->isValueType()) |
|
|
|
CompilerUtils(m_context).loadFromMemoryDynamic( |
|
|
|
*_arrayType.getBaseType(), |
|
|
|
true, |
|
|
|
!_arrayType.isByteArray(), |
|
|
|
false |
|
|
|
); |
|
|
|
break; |
|
|
|
case ArrayType::Location::Storage: |
|
|
|
m_context << eth::Instruction::SWAP1; |
|
|
|
if (_arrayType.getBaseType()->getStorageBytes() <= 16) |
|
|
|
{ |
|
|
|
// stack: <data_ref> <index>
|
|
|
|
// goal:
|
|
|
|
// <ref> <byte_number> = <base_ref + index / itemsPerSlot> <(index % itemsPerSlot) * byteSize>
|
|
|
|
unsigned byteSize = _arrayType.getBaseType()->getStorageBytes(); |
|
|
|
solAssert(byteSize != 0, ""); |
|
|
|
unsigned itemsPerSlot = 32 / byteSize; |
|
|
|
m_context << u256(itemsPerSlot) << eth::Instruction::SWAP2; |
|
|
|
// stack: itemsPerSlot index data_ref
|
|
|
|
m_context |
|
|
|
<< eth::Instruction::DUP3 << eth::Instruction::DUP3 |
|
|
|
<< eth::Instruction::DIV << eth::Instruction::ADD |
|
|
|
// stack: 32 index (data_ref + index / 32)
|
|
|
|
// stack: itemsPerSlot index (data_ref + index / itemsPerSlot)
|
|
|
|
<< eth::Instruction::SWAP2 << eth::Instruction::SWAP1 |
|
|
|
<< eth::Instruction::MOD; |
|
|
|
break; |
|
|
|
case ArrayType::Location::CallData: |
|
|
|
// no lvalue, just retrieve the value
|
|
|
|
m_context |
|
|
|
<< eth::Instruction::ADD << eth::Instruction::CALLDATALOAD |
|
|
|
<< ((u256(0xff) << (256 - 8))) << eth::Instruction::AND; |
|
|
|
break; |
|
|
|
case ArrayType::Location::Memory: |
|
|
|
solAssert(false, "Memory lvalues not yet implemented."); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// stack: <base_ref> <index>
|
|
|
|
m_context << eth::Instruction::SWAP1; |
|
|
|
if (_arrayType.isDynamicallySized()) |
|
|
|
{ |
|
|
|
if (location == ArrayType::Location::Storage) |
|
|
|
CompilerUtils(m_context).computeHashStatic(); |
|
|
|
else if (location == ArrayType::Location::Memory) |
|
|
|
m_context << u256(32) << eth::Instruction::ADD; |
|
|
|
if (byteSize != 1) |
|
|
|
m_context << u256(byteSize) << eth::Instruction::MUL; |
|
|
|
} |
|
|
|
// stack: <index> <data_ref>
|
|
|
|
switch (location) |
|
|
|
else |
|
|
|
{ |
|
|
|
case ArrayType::Location::CallData: |
|
|
|
m_context |
|
|
|
<< eth::Instruction::SWAP1 << _arrayType.getBaseType()->getCalldataEncodedSize() |
|
|
|
<< eth::Instruction::MUL << eth::Instruction::ADD; |
|
|
|
if (_arrayType.getBaseType()->isValueType()) |
|
|
|
CompilerUtils(m_context).loadFromMemoryDynamic(*_arrayType.getBaseType(), true, true, false); |
|
|
|
break; |
|
|
|
case ArrayType::Location::Storage: |
|
|
|
m_context << eth::Instruction::SWAP1; |
|
|
|
if (_arrayType.getBaseType()->getStorageBytes() <= 16) |
|
|
|
{ |
|
|
|
// stack: <data_ref> <index>
|
|
|
|
// goal:
|
|
|
|
// <ref> <byte_number> = <base_ref + index / itemsPerSlot> <(index % itemsPerSlot) * byteSize>
|
|
|
|
unsigned byteSize = _arrayType.getBaseType()->getStorageBytes(); |
|
|
|
solAssert(byteSize != 0, ""); |
|
|
|
unsigned itemsPerSlot = 32 / byteSize; |
|
|
|
m_context << u256(itemsPerSlot) << eth::Instruction::SWAP2; |
|
|
|
// stack: itemsPerSlot index data_ref
|
|
|
|
m_context |
|
|
|
<< eth::Instruction::DUP3 << eth::Instruction::DUP3 |
|
|
|
<< eth::Instruction::DIV << eth::Instruction::ADD |
|
|
|
// stack: itemsPerSlot index (data_ref + index / itemsPerSlot)
|
|
|
|
<< eth::Instruction::SWAP2 << eth::Instruction::SWAP1 |
|
|
|
<< eth::Instruction::MOD |
|
|
|
<< u256(byteSize) << eth::Instruction::MUL; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (_arrayType.getBaseType()->getStorageSize() != 1) |
|
|
|
m_context << _arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL; |
|
|
|
m_context << eth::Instruction::ADD << u256(0); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ArrayType::Location::Memory: |
|
|
|
solAssert(false, "Memory lvalues not yet implemented."); |
|
|
|
if (_arrayType.getBaseType()->getStorageSize() != 1) |
|
|
|
m_context << _arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL; |
|
|
|
m_context << eth::Instruction::ADD << u256(0); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ArrayType::Location::Memory: |
|
|
|
solAssert(false, "Memory lvalues not yet implemented."); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|