diff options
author | Yoichi Hirai <i@yoichihirai.com> | 2016-12-13 05:39:47 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-13 05:39:47 +0800 |
commit | 1c3605362d6018f5ab72cc84c7511fb49c15d126 (patch) | |
tree | 0dd967a78fc37b9efc49fb7f71578a0fb52432f0 /libsolidity/codegen/CompilerUtils.cpp | |
parent | c111d6e27e7a951d49e587d0984fc8c24898c18f (diff) | |
parent | 81d7e0233aa24a2d38103b2bf746cef5eb12a893 (diff) | |
download | dexon-solidity-1c3605362d6018f5ab72cc84c7511fb49c15d126.tar dexon-solidity-1c3605362d6018f5ab72cc84c7511fb49c15d126.tar.gz dexon-solidity-1c3605362d6018f5ab72cc84c7511fb49c15d126.tar.bz2 dexon-solidity-1c3605362d6018f5ab72cc84c7511fb49c15d126.tar.lz dexon-solidity-1c3605362d6018f5ab72cc84c7511fb49c15d126.tar.xz dexon-solidity-1c3605362d6018f5ab72cc84c7511fb49c15d126.tar.zst dexon-solidity-1c3605362d6018f5ab72cc84c7511fb49c15d126.zip |
Merge pull request #1468 from ethereum/memcpy-assembly
Implement memcpy without the identity precompile
Diffstat (limited to 'libsolidity/codegen/CompilerUtils.cpp')
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 77 |
1 files changed, 64 insertions, 13 deletions
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 7c159ff7..da2e78e8 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -298,22 +298,73 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type) m_context << Instruction::SWAP1 << Instruction::POP; } +void CompilerUtils::memoryCopyPrecompile() +{ + // Stack here: size target source + + m_context.appendInlineAssembly(R"( + { + let words := div(add(len, 31), 32) + let cost := add(15, mul(3, words)) + 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; +} + +void CompilerUtils::memoryCopy32() +{ + // Stack here: size target source + + m_context.appendInlineAssembly(R"( + { + jumpi(end, eq(len, 0)) + start: + mstore(dst, mload(src)) + jumpi(end, iszero(gt(len, 32))) + dst := add(dst, 32) + src := add(src, 32) + len := sub(len, 32) + jump(start) + end: + } + )", + { "len", "dst", "src" } + ); + m_context << Instruction::POP << Instruction::POP << Instruction::POP; +} + void CompilerUtils::memoryCopy() { // Stack here: size target source - // stack for call: outsize target size source value contract gas - //@TODO do not use ::CALL if less than 32 bytes? - m_context << Instruction::DUP3 << Instruction::SWAP1; - m_context << u256(0) << u256(identityContractAddress); - // compute gas costs - m_context << u256(32) << Instruction::DUP5 << u256(31) << Instruction::ADD; - static unsigned c_identityGas = 15; - static unsigned c_identityWordGas = 3; - m_context << Instruction::DIV << u256(c_identityWordGas) << Instruction::MUL; - m_context << u256(c_identityGas) << Instruction::ADD; - m_context << Instruction::CALL; - m_context << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + + m_context.appendInlineAssembly(R"( + { + // copy 32 bytes at once + start32: + jumpi(end32, lt(len, 32)) + 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) + 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) |