mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Split memcopy into three functions.
This commit is contained in:
parent
4184525d4a
commit
bfa4f45116
@ -335,9 +335,14 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
if (baseSize > 1)
|
if (baseSize > 1)
|
||||||
m_context << u256(baseSize) << Instruction::MUL;
|
m_context << u256(baseSize) << Instruction::MUL;
|
||||||
// stack: <target> <source> <size>
|
// stack: <target> <source> <size>
|
||||||
//@TODO do not use ::CALL if less than 32 bytes?
|
|
||||||
m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::DUP4;
|
m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::DUP4;
|
||||||
utils.memoryCopy();
|
// We can resort to copying full 32 bytes only if
|
||||||
|
// - the length is known to be a multiple of 32 or
|
||||||
|
// - we will pad to full 32 bytes later anyway.
|
||||||
|
if (((baseSize % 32) == 0) || _padToWordBoundaries)
|
||||||
|
utils.memoryCopy32();
|
||||||
|
else
|
||||||
|
utils.memoryCopy();
|
||||||
|
|
||||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||||
// stack: <target> <size>
|
// stack: <target> <size>
|
||||||
|
@ -298,61 +298,73 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
|
|||||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::memoryCopy(bool _useIdentityPrecompile)
|
void CompilerUtils::memoryCopyPrecompile()
|
||||||
{
|
{
|
||||||
//@TODO do not use ::CALL if less than 32 bytes?
|
|
||||||
|
|
||||||
// Stack here: size target source
|
// Stack here: size target source
|
||||||
|
|
||||||
if (!_useIdentityPrecompile)
|
m_context.appendInlineAssembly(R"(
|
||||||
{
|
{
|
||||||
m_context.appendInlineAssembly(R"(
|
let words := div(add(len, 31), 32)
|
||||||
{
|
let cost := add(15, mul(3, words))
|
||||||
// expects three locals: src, dst, len
|
jumpi(invalidJumpLabel, iszero(call(cost, $identityContractAddress, 0, src, len, dst, len)))
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
{ "len", "dst", "src" },
|
||||||
|
map<string, string> {
|
||||||
|
{ "$identityContractAddress", toString(identityContractAddress) }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_context << Instruction::POP << Instruction::POP << Instruction::POP;
|
||||||
|
}
|
||||||
|
|
||||||
// copy 32 bytes at once
|
void CompilerUtils::memoryCopy32()
|
||||||
start32:
|
{
|
||||||
jumpi(end32, lt(len, 32))
|
// Stack here: size target source
|
||||||
mstore(dst, mload(src))
|
|
||||||
dst := add(dst, 32)
|
|
||||||
src := add(src, 32)
|
|
||||||
len := sub(len, 32)
|
|
||||||
jump(start32)
|
|
||||||
end32:
|
|
||||||
|
|
||||||
// copy the remainder (0 < len < 32)
|
m_context.appendInlineAssembly(R"(
|
||||||
let mask := sub(exp(256, sub(32, len)), 1)
|
{
|
||||||
let srcpart := and(mload(src), not(mask))
|
jumpi(end, eq(len, 0))
|
||||||
let dstpart := and(mload(dst), mask)
|
start:
|
||||||
mstore(dst, or(srcpart, dstpart))
|
mstore(dst, mload(src))
|
||||||
}
|
jumpi(end, iszero(gt(len, 32)))
|
||||||
)",
|
dst := add(dst, 32)
|
||||||
{ "len", "dst", "src" }
|
src := add(src, 32)
|
||||||
);
|
len := sub(len, 32)
|
||||||
m_context << Instruction::POP;
|
jump(start)
|
||||||
m_context << Instruction::POP;
|
end:
|
||||||
m_context << Instruction::POP;
|
}
|
||||||
return;
|
)",
|
||||||
}
|
{ "len", "dst", "src" }
|
||||||
else
|
);
|
||||||
{
|
m_context << Instruction::POP << Instruction::POP << Instruction::POP;
|
||||||
m_context.appendInlineAssembly(R"(
|
}
|
||||||
{
|
|
||||||
let words := div(add(len, 31), 32)
|
void CompilerUtils::memoryCopy()
|
||||||
let cost := add(15, mul(3, words))
|
{
|
||||||
jump(invalidJumpLabel, iszero(call(cost, $identityContractAddress, 0, src, len, dst, len)))
|
// Stack here: size target source
|
||||||
}
|
|
||||||
)",
|
m_context.appendInlineAssembly(R"(
|
||||||
{ "len", "dst", "src" },
|
{
|
||||||
map<string, string> {
|
// copy 32 bytes at once
|
||||||
{ "$identityContractAddress", toString(identityContractAddress) }
|
start32:
|
||||||
}
|
jumpi(end32, lt(len, 32))
|
||||||
);
|
mstore(dst, mload(src))
|
||||||
m_context << Instruction::POP;
|
dst := add(dst, 32)
|
||||||
m_context << Instruction::POP;
|
src := add(src, 32)
|
||||||
m_context << Instruction::POP;
|
len := sub(len, 32)
|
||||||
return;
|
jump(start32)
|
||||||
}
|
end32:
|
||||||
|
|
||||||
|
// copy the remainder (0 < len < 32)
|
||||||
|
let mask := sub(exp(256, sub(32, len)), 1)
|
||||||
|
let srcpart := and(mload(src), not(mask))
|
||||||
|
let dstpart := and(mload(dst), mask)
|
||||||
|
mstore(dst, or(srcpart, dstpart))
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
{ "len", "dst", "src" }
|
||||||
|
);
|
||||||
|
m_context << Instruction::POP << Instruction::POP << Instruction::POP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::splitExternalFunctionType(bool _leftAligned)
|
void CompilerUtils::splitExternalFunctionType(bool _leftAligned)
|
||||||
|
@ -112,7 +112,15 @@ public:
|
|||||||
/// Uses a CALL to the identity contract to perform a memory-to-memory copy.
|
/// Uses a CALL to the identity contract to perform a memory-to-memory copy.
|
||||||
/// Stack pre: <size> <target> <source>
|
/// Stack pre: <size> <target> <source>
|
||||||
/// Stack post:
|
/// Stack post:
|
||||||
void memoryCopy(bool _useIdentityPrecompile = false);
|
void memoryCopyPrecompile();
|
||||||
|
/// Copies full 32 byte words in memory (regions cannot overlap), i.e. may copy more than length.
|
||||||
|
/// Stack pre: <size> <target> <source>
|
||||||
|
/// Stack post:
|
||||||
|
void memoryCopy32();
|
||||||
|
/// Copies data in memory (regions cannot overlap).
|
||||||
|
/// Stack pre: <size> <target> <source>
|
||||||
|
/// Stack post:
|
||||||
|
void memoryCopy();
|
||||||
|
|
||||||
/// Converts the combined and left-aligned (right-aligned if @a _rightAligned is true)
|
/// Converts the combined and left-aligned (right-aligned if @a _rightAligned is true)
|
||||||
/// external function type <address><function identifier> into two stack slots:
|
/// external function type <address><function identifier> into two stack slots:
|
||||||
|
Loading…
Reference in New Issue
Block a user