mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Bugfix.
This commit is contained in:
parent
a27b063c10
commit
7a84e9c875
@ -50,9 +50,8 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
// stack layout: [source_ref] [source length] target_ref (top)
|
// stack layout: [source_ref] [source length] target_ref (top)
|
||||||
solAssert(_targetType.location() == DataLocation::Storage, "");
|
solAssert(_targetType.location() == DataLocation::Storage, "");
|
||||||
|
|
||||||
Type const* uint256 = TypeProvider::uint256();
|
Type const* targetBaseType = _targetType.baseType();
|
||||||
Type const* targetBaseType = _targetType.isByteArrayOrString() ? uint256 : _targetType.baseType();
|
Type const* sourceBaseType = _sourceType.baseType();
|
||||||
Type const* sourceBaseType = _sourceType.isByteArrayOrString() ? uint256 : _sourceType.baseType();
|
|
||||||
|
|
||||||
// TODO unroll loop for small sizes
|
// TODO unroll loop for small sizes
|
||||||
|
|
||||||
@ -68,7 +67,38 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
for (unsigned i = _sourceType.sizeOnStack(); i > 0; --i)
|
for (unsigned i = _sourceType.sizeOnStack(); i > 0; --i)
|
||||||
m_context << swapInstruction(i);
|
m_context << swapInstruction(i);
|
||||||
// stack: target_ref source_ref [source_length]
|
// stack: target_ref source_ref [source_length]
|
||||||
// stack: target_ref source_ref [source_length]
|
|
||||||
|
if (_targetType.isByteArrayOrString())
|
||||||
|
{
|
||||||
|
// stack: target_ref source_ref [source_length]
|
||||||
|
if (fromCalldata && _sourceType.isDynamicallySized())
|
||||||
|
{
|
||||||
|
// stack: target_ref source_ref source_length
|
||||||
|
m_context << Instruction::SWAP1;
|
||||||
|
// stack: target_ref source_length source_ref
|
||||||
|
m_context << Instruction::DUP3;
|
||||||
|
// stack: target_ref source_length source_ref target_ref
|
||||||
|
m_context.callYulFunction(
|
||||||
|
m_context.utilFunctions().copyByteArrayToStorageFunction(_sourceType, _targetType),
|
||||||
|
3,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// stack: target_ref source_ref
|
||||||
|
m_context << Instruction::DUP2;
|
||||||
|
// stack: target_ref source_ref target_ref
|
||||||
|
m_context.callYulFunction(
|
||||||
|
m_context.utilFunctions().copyByteArrayToStorageFunction(_sourceType, _targetType),
|
||||||
|
2,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// stack: target_ref
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// retrieve source length
|
// retrieve source length
|
||||||
if (_sourceType.location() != DataLocation::CallData || !_sourceType.isDynamicallySized())
|
if (_sourceType.location() != DataLocation::CallData || !_sourceType.isDynamicallySized())
|
||||||
retrieveLength(_sourceType); // otherwise, length is already there
|
retrieveLength(_sourceType); // otherwise, length is already there
|
||||||
@ -97,10 +127,11 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
utils.retrieveLength(_targetType);
|
utils.retrieveLength(_targetType);
|
||||||
// stack: target_ref source_ref source_length target_ref target_length
|
// stack: target_ref source_ref source_length target_ref target_length
|
||||||
if (_targetType.isDynamicallySized())
|
if (_targetType.isDynamicallySized())
|
||||||
|
{
|
||||||
// store new target length
|
// store new target length
|
||||||
if (!_targetType.isByteArrayOrString())
|
solAssert(!_targetType.isByteArrayOrString());
|
||||||
// Otherwise, length will be stored below.
|
_context << Instruction::DUP3 << Instruction::DUP3 << Instruction::SSTORE;
|
||||||
_context << Instruction::DUP3 << Instruction::DUP3 << Instruction::SSTORE;
|
}
|
||||||
if (sourceBaseType->category() == Type::Category::Mapping)
|
if (sourceBaseType->category() == Type::Category::Mapping)
|
||||||
{
|
{
|
||||||
solAssert(targetBaseType->category() == Type::Category::Mapping, "");
|
solAssert(targetBaseType->category() == Type::Category::Mapping, "");
|
||||||
@ -125,51 +156,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
// stack: target_ref target_data_end source_length target_data_pos source_ref
|
// stack: target_ref target_data_end source_length target_data_pos source_ref
|
||||||
|
|
||||||
evmasm::AssemblyItem copyLoopEndWithoutByteOffset = _context.newTag();
|
evmasm::AssemblyItem copyLoopEndWithoutByteOffset = _context.newTag();
|
||||||
|
solAssert(!_targetType.isByteArrayOrString());
|
||||||
// special case for short byte arrays: Store them together with their length.
|
|
||||||
if (_targetType.isByteArrayOrString())
|
|
||||||
{
|
|
||||||
// stack: target_ref target_data_end source_length target_data_pos source_ref
|
|
||||||
_context << Instruction::DUP3;
|
|
||||||
evmasm::AssemblyItem nonEmptyByteArray = _context.appendConditionalJump();
|
|
||||||
// Empty source, just zero out the main slot.
|
|
||||||
_context << u256(0) << Instruction::DUP6 << Instruction::SSTORE;
|
|
||||||
_context.appendJumpTo(copyLoopEndWithoutByteOffset);
|
|
||||||
|
|
||||||
_context << nonEmptyByteArray;
|
|
||||||
// Non-empty source.
|
|
||||||
// stack: target_ref target_data_end source_length target_data_pos source_ref
|
|
||||||
_context << Instruction::DUP3 << u256(31) << Instruction::LT;
|
|
||||||
evmasm::AssemblyItem longByteArray = _context.appendConditionalJump();
|
|
||||||
// store the short byte array
|
|
||||||
solAssert(_sourceType.isByteArrayOrString(), "");
|
|
||||||
if (_sourceType.location() == DataLocation::Storage)
|
|
||||||
{
|
|
||||||
// just copy the slot, it contains length and data
|
|
||||||
_context << Instruction::DUP1 << Instruction::SLOAD;
|
|
||||||
_context << Instruction::DUP6 << Instruction::SSTORE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_context << Instruction::DUP1;
|
|
||||||
CompilerUtils(_context).loadFromMemoryDynamic(*sourceBaseType, fromCalldata, true, false);
|
|
||||||
// stack: target_ref target_data_end source_length target_data_pos source_ref value
|
|
||||||
// clear the lower-order byte - which will hold the length
|
|
||||||
_context << u256(0xff) << Instruction::NOT << Instruction::AND;
|
|
||||||
// fetch the length and shift it left by one
|
|
||||||
_context << Instruction::DUP4 << Instruction::DUP1 << Instruction::ADD;
|
|
||||||
// combine value and length and store them
|
|
||||||
_context << Instruction::OR << Instruction::DUP6 << Instruction::SSTORE;
|
|
||||||
}
|
|
||||||
// end of special case, jump right into cleaning target data area
|
|
||||||
_context.appendJumpTo(copyLoopEndWithoutByteOffset);
|
|
||||||
_context << longByteArray;
|
|
||||||
// Store length (2*length+1)
|
|
||||||
_context << Instruction::DUP3 << Instruction::DUP1 << Instruction::ADD;
|
|
||||||
_context << u256(1) << Instruction::ADD;
|
|
||||||
_context << Instruction::DUP6 << Instruction::SSTORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip copying if source length is zero
|
// skip copying if source length is zero
|
||||||
_context << Instruction::DUP3 << Instruction::ISZERO;
|
_context << Instruction::DUP3 << Instruction::ISZERO;
|
||||||
_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset);
|
_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset);
|
||||||
|
@ -25,12 +25,13 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
// compileViaYul: false
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor() ->
|
// constructor() ->
|
||||||
// gas legacy: 616124
|
// gas irOptimized: 520903
|
||||||
// gas legacyOptimized: 450817
|
// gas legacy: 731840
|
||||||
// h() -> 0x20, 0x40, 0x00, 2
|
// gas legacyOptimized: 494859
|
||||||
|
// h() -> 0x20, 0x40, 0x00, 0
|
||||||
// ~ emit ev0(uint256[],uint256): 0x40, 0x21, 0x02, 0x00, 0x00
|
// ~ emit ev0(uint256[],uint256): 0x40, 0x21, 0x02, 0x00, 0x00
|
||||||
// g() -> 0x20, 0x40, 0, 0x42
|
// g() -> 0x20, 0x40, 0, 0x00
|
||||||
// f(bytes): 0x20, 33, 0, -1 -> 0x20, 0x22, 0, 0xffff000000000000000000000000000000000000000000000000000000000000
|
// f(bytes): 0x20, 33, 0, -1 -> 0x20, 0x22, 0, 0xff00000000000000000000000000000000000000000000000000000000000000
|
||||||
|
Loading…
Reference in New Issue
Block a user