diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 58033292e..ce81ba5f2 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -736,6 +736,13 @@ public: TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override; + /// The offset to advance in calldata to move from one array element to the next. + unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataEncodedSize(); } + /// The offset to advance in memory to move from one array element to the next. + unsigned memoryStride() const { return isByteArray() ? 1 : m_baseType->memoryHeadSize(); } + /// The offset to advance in storage to move from one array element to the next. + unsigned storageStride() const { return isByteArray() ? 1 : m_baseType->storageBytes(); } + private: /// String is interpreted as a subtype of Bytes. enum class ArrayKind { Ordinary, Bytes, String }; diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 65fc154af..39189046f 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -623,7 +623,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1; // stack: data_pos_end data_pos - if (_type.isByteArray() || _type.baseType()->storageBytes() < 32) + if (_type.storageStride() < 32) clearStorageLoop(make_shared(256)); else clearStorageLoop(_type.baseType()); @@ -769,7 +769,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const // stack: ref new_length data_pos new_size delete_end _context << Instruction::SWAP2 << Instruction::ADD; // stack: ref new_length delete_end delete_start - if (_type.isByteArray() || _type.baseType()->storageBytes() < 32) + if (_type.storageStride() < 32) ArrayUtils(_context).clearStorageLoop(make_shared(256)); else ArrayUtils(_context).clearStorageLoop(_type.baseType()); diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index f8c8b3a88..7650b1195 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -243,7 +243,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem gt(add(array_data_start, mul(array_length, )), input_end) ) { revert(0, 0) } })"); - templ("item_size", to_string(arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true))); + templ("item_size", to_string(arrayType.calldataStride())); m_context.appendInlineAssembly(templ.render(), {"input_end", "base_offset", "offset", "ptr"}); // stack: v1 v2 ... v(k-1) input_end base_offset current_offset v(k) moveIntoStack(3); @@ -279,11 +279,10 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem // stack: input_end base_offset next_pointer array_length data_pointer m_context << Instruction::SWAP2; // stack: input_end base_offset data_pointer array_length next_pointer - unsigned itemSize = arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true); m_context.appendInlineAssembly(R"({ if or( gt(array_length, 0x100000000), - gt(add(data_ptr, mul(array_length, )" + to_string(itemSize) + R"()), input_end) + gt(add(data_ptr, mul(array_length, )" + to_string(arrayType.calldataStride()) + R"()), input_end) ) { revert(0, 0) } })", {"input_end", "base_offset", "data_ptr", "array_length", "next_ptr"}); } @@ -517,7 +516,7 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type) codecopy(memptr, codesize(), size) memptr := add(memptr, size) })"); - templ("element_size", to_string(_type.isByteArray() ? 1 : _type.baseType()->memoryHeadSize())); + templ("element_size", to_string(_type.memoryStride())); m_context.appendInlineAssembly(templ.render(), {"length", "memptr"}); } else