| 108 | } |
| 109 | |
| 110 | void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWordBoundaries) const |
| 111 | { |
| 112 | solUnimplementedAssert( |
| 113 | !_sourceType.baseType()->isDynamicallySized(), |
| 114 | "Nested dynamic arrays not implemented here." |
| 115 | ); |
| 116 | CompilerUtils utils(m_context); |
| 117 | |
| 118 | if (_sourceType.location() == DataLocation::CallData) |
| 119 | { |
| 120 | if (!_sourceType.isDynamicallySized()) |
| 121 | m_context << _sourceType.length(); |
| 122 | if (!_sourceType.isByteArrayOrString()) |
| 123 | convertLengthToSize(_sourceType); |
| 124 | |
| 125 | std::string routine = "calldatacopy(target, source, len)\n"; |
| 126 | if (_padToWordBoundaries) |
| 127 | routine += R"( |
| 128 | // Set padding suffix to zero |
| 129 | mstore(add(target, len), 0) |
| 130 | len := and(add(len, 0x1f), not(0x1f)) |
| 131 | )"; |
| 132 | routine += "target := add(target, len)\n"; |
| 133 | m_context.appendInlineAssembly("{" + routine + "}", {"target", "source", "len"}); |
| 134 | m_context << Instruction::POP << Instruction::POP; |
| 135 | } |
| 136 | else if (_sourceType.location() == DataLocation::Memory) |
| 137 | { |
| 138 | retrieveLength(_sourceType); |
| 139 | // stack: target source length |
| 140 | if (!_sourceType.baseType()->isValueType()) |
| 141 | { |
| 142 | // copy using a loop |
| 143 | m_context << u256(0) << Instruction::SWAP3; |
| 144 | // stack: counter source length target |
| 145 | auto repeat = m_context.newTag(); |
| 146 | m_context << repeat; |
| 147 | m_context << Instruction::DUP2 << Instruction::DUP5; |
| 148 | m_context << Instruction::LT << Instruction::ISZERO; |
| 149 | auto loopEnd = m_context.appendConditionalJump(); |
| 150 | m_context << Instruction::DUP3 << Instruction::DUP5; |
| 151 | accessIndex(_sourceType, false); |
| 152 | MemoryItem(m_context, *_sourceType.baseType(), true).retrieveValue(SourceLocation(), true); |
| 153 | if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType())) |
| 154 | copyArrayToMemory(*baseArray, _padToWordBoundaries); |
| 155 | else |
| 156 | utils.storeInMemoryDynamic(*_sourceType.baseType()); |
| 157 | m_context << Instruction::SWAP3 << u256(1) << Instruction::ADD; |
| 158 | m_context << Instruction::SWAP3; |
| 159 | m_context.appendJumpTo(repeat); |
| 160 | m_context << loopEnd; |
| 161 | m_context << Instruction::SWAP3; |
| 162 | utils.popStackSlots(3); |
| 163 | // stack: updated_target_pos |
| 164 | return; |
| 165 | } |
| 166 | |
| 167 | // memcpy using the built-in contract |
no test coverage detected