mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6965 from sifmelcara/6881-preparation
Clean up and refactor array element access related code
This commit is contained in:
commit
9a707ea6e9
@ -414,7 +414,8 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
|
||||
fromArrayType.isByteArray() ||
|
||||
*fromArrayType.baseType() == *TypeProvider::uint256() ||
|
||||
*fromArrayType.baseType() == FixedBytesType(32),
|
||||
"");
|
||||
""
|
||||
);
|
||||
solAssert(fromArrayType.calldataStride() == toArrayType.memoryStride(), "");
|
||||
|
||||
solAssert(
|
||||
|
@ -1055,28 +1055,27 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
|
||||
switch (location)
|
||||
{
|
||||
case DataLocation::Memory:
|
||||
// stack: <base_ref> <index>
|
||||
if (!_arrayType.isByteArray())
|
||||
m_context << u256(_arrayType.memoryHeadSize()) << Instruction::MUL;
|
||||
if (_arrayType.isDynamicallySized())
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
if (_keepReference)
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << Instruction::ADD;
|
||||
break;
|
||||
case DataLocation::CallData:
|
||||
if (!_arrayType.isByteArray())
|
||||
{
|
||||
if (location == DataLocation::CallData)
|
||||
{
|
||||
if (_arrayType.baseType()->isDynamicallyEncoded())
|
||||
m_context << u256(0x20);
|
||||
else
|
||||
m_context << _arrayType.baseType()->calldataEncodedSize();
|
||||
}
|
||||
if (_arrayType.baseType()->isDynamicallyEncoded())
|
||||
m_context << u256(0x20);
|
||||
else
|
||||
m_context << u256(_arrayType.memoryHeadSize());
|
||||
m_context << _arrayType.baseType()->calldataEncodedSize();
|
||||
m_context << Instruction::MUL;
|
||||
}
|
||||
// stack: <base_ref> <index * size>
|
||||
|
||||
if (location == DataLocation::Memory && _arrayType.isDynamicallySized())
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
|
||||
if (_keepReference)
|
||||
m_context << Instruction::DUP2;
|
||||
|
||||
m_context << Instruction::ADD;
|
||||
break;
|
||||
case DataLocation::Storage:
|
||||
@ -1132,6 +1131,50 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayUtils::accessCallDataArrayElement(ArrayType const& _arrayType, bool _doBoundsCheck) const
|
||||
{
|
||||
solAssert(_arrayType.location() == DataLocation::CallData, "");
|
||||
if (_arrayType.baseType()->isDynamicallyEncoded())
|
||||
{
|
||||
// stack layout: <base_ref> <length> <index>
|
||||
ArrayUtils(m_context).accessIndex(_arrayType, _doBoundsCheck, true);
|
||||
// stack layout: <base_ref> <ptr_to_tail>
|
||||
|
||||
CompilerUtils(m_context).accessCalldataTail(*_arrayType.baseType());
|
||||
// stack layout: <tail_ref> [length]
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayUtils(m_context).accessIndex(_arrayType, _doBoundsCheck);
|
||||
if (_arrayType.baseType()->isValueType())
|
||||
{
|
||||
solAssert(_arrayType.baseType()->storageBytes() <= 32, "");
|
||||
if (
|
||||
!_arrayType.isByteArray() &&
|
||||
_arrayType.baseType()->storageBytes() < 32 &&
|
||||
m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)
|
||||
)
|
||||
{
|
||||
m_context << u256(32);
|
||||
CompilerUtils(m_context).abiDecodeV2({_arrayType.baseType()}, false);
|
||||
}
|
||||
else
|
||||
CompilerUtils(m_context).loadFromMemoryDynamic(
|
||||
*_arrayType.baseType(),
|
||||
true,
|
||||
!_arrayType.isByteArray(),
|
||||
false
|
||||
);
|
||||
}
|
||||
else
|
||||
solAssert(
|
||||
_arrayType.baseType()->category() == Type::Category::Struct ||
|
||||
_arrayType.baseType()->category() == Type::Category::Array,
|
||||
"Invalid statically sized non-value base type on array access."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayUtils::incrementByteOffset(unsigned _byteSize, unsigned _byteOffsetPosition, unsigned _storageOffsetPosition) const
|
||||
{
|
||||
solAssert(_byteSize < 32, "");
|
||||
|
@ -104,6 +104,10 @@ public:
|
||||
/// Stack post (storage): [reference] storage_slot byte_offset
|
||||
/// Stack post: [reference] memory/calldata_offset
|
||||
void accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck = true, bool _keepReference = false) const;
|
||||
/// Access calldata array's element and put it on stack.
|
||||
/// Stack pre: reference [length] index
|
||||
/// Stack post: value
|
||||
void accessCallDataArrayElement(ArrayType const& _arrayType, bool _doBoundsCheck = true) const;
|
||||
|
||||
private:
|
||||
/// Adds the given number of bytes to a storage byte offset counter and also increments
|
||||
|
@ -816,7 +816,12 @@ void CompilerUtils::convertType(
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract || targetTypeCategory == Type::Category::Address, "");
|
||||
solAssert(
|
||||
targetTypeCategory == Type::Category::Integer ||
|
||||
targetTypeCategory == Type::Category::Contract ||
|
||||
targetTypeCategory == Type::Category::Address,
|
||||
""
|
||||
);
|
||||
IntegerType addressType(160);
|
||||
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
|
||||
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
|
||||
@ -923,7 +928,6 @@ void CompilerUtils::convertType(
|
||||
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
|
||||
if (targetType.baseType()->isValueType())
|
||||
{
|
||||
solAssert(typeOnStack.baseType()->isValueType(), "");
|
||||
copyToStackTop(2 + stackSize, stackSize);
|
||||
ArrayUtils(m_context).copyArrayToMemory(typeOnStack);
|
||||
}
|
||||
@ -957,10 +961,11 @@ void CompilerUtils::convertType(
|
||||
}
|
||||
case DataLocation::CallData:
|
||||
solAssert(
|
||||
targetType.isByteArray() &&
|
||||
typeOnStack.isByteArray() &&
|
||||
typeOnStack.location() == DataLocation::CallData,
|
||||
"Invalid conversion to calldata type.");
|
||||
targetType.isByteArray() &&
|
||||
typeOnStack.isByteArray() &&
|
||||
typeOnStack.location() == DataLocation::CallData,
|
||||
"Invalid conversion to calldata type."
|
||||
);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -54,7 +54,13 @@ class StackHeightChecker
|
||||
public:
|
||||
explicit StackHeightChecker(CompilerContext const& _context):
|
||||
m_context(_context), stackHeight(m_context.stackHeight()) {}
|
||||
void check() { solAssert(m_context.stackHeight() == stackHeight, std::string("I sense a disturbance in the stack: ") + to_string(m_context.stackHeight()) + " vs " + to_string(stackHeight)); }
|
||||
void check()
|
||||
{
|
||||
solAssert(
|
||||
m_context.stackHeight() == stackHeight,
|
||||
std::string("I sense a disturbance in the stack: ") + to_string(m_context.stackHeight()) + " vs " + to_string(stackHeight)
|
||||
);
|
||||
}
|
||||
private:
|
||||
CompilerContext const& m_context;
|
||||
unsigned stackHeight;
|
||||
@ -893,9 +899,9 @@ bool ContractCompiler::visit(VariableDeclarationStatement const& _variableDeclar
|
||||
|
||||
// Local variable slots are reserved when their declaration is visited,
|
||||
// and freed in the end of their scope.
|
||||
for (auto _decl: _variableDeclarationStatement.declarations())
|
||||
if (_decl)
|
||||
appendStackVariableInitialisation(*_decl);
|
||||
for (auto decl: _variableDeclarationStatement.declarations())
|
||||
if (decl)
|
||||
appendStackVariableInitialisation(*decl);
|
||||
|
||||
StackHeightChecker checker(m_context);
|
||||
if (Expression const* expression = _variableDeclarationStatement.initialValue())
|
||||
|
@ -1588,45 +1588,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
setLValue<MemoryItem>(_indexAccess, *_indexAccess.annotation().type, !arrayType.isByteArray());
|
||||
break;
|
||||
case DataLocation::CallData:
|
||||
if (arrayType.baseType()->isDynamicallyEncoded())
|
||||
{
|
||||
// stack layout: <base_ref> <length> <index>
|
||||
ArrayUtils(m_context).accessIndex(arrayType, true, true);
|
||||
// stack layout: <base_ref> <ptr_to_tail>
|
||||
|
||||
CompilerUtils(m_context).accessCalldataTail(*arrayType.baseType());
|
||||
// stack layout: <tail_ref> [length]
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayUtils(m_context).accessIndex(arrayType, true);
|
||||
if (arrayType.baseType()->isValueType())
|
||||
{
|
||||
solAssert(arrayType.baseType()->storageBytes() <= 32, "");
|
||||
if (
|
||||
!arrayType.isByteArray() &&
|
||||
arrayType.baseType()->storageBytes() < 32 &&
|
||||
m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)
|
||||
)
|
||||
{
|
||||
m_context << u256(32);
|
||||
CompilerUtils(m_context).abiDecodeV2({arrayType.baseType()}, false);
|
||||
}
|
||||
else
|
||||
CompilerUtils(m_context).loadFromMemoryDynamic(
|
||||
*arrayType.baseType(),
|
||||
true,
|
||||
!arrayType.isByteArray(),
|
||||
false
|
||||
);
|
||||
}
|
||||
else
|
||||
solAssert(
|
||||
arrayType.baseType()->category() == Type::Category::Struct ||
|
||||
arrayType.baseType()->category() == Type::Category::Array,
|
||||
"Invalid statically sized non-value base type on array access."
|
||||
);
|
||||
}
|
||||
ArrayUtils(m_context).accessCallDataArrayElement(arrayType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user