| 42 | using namespace solidity::langutil; |
| 43 | |
| 44 | void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const |
| 45 | { |
| 46 | // this copies source to target and also clears target if it was larger |
| 47 | // need to leave "target_ref target_byte_off" on the stack at the end |
| 48 | |
| 49 | // stack layout: source_ref [source length] target_ref (top) |
| 50 | solAssert(_targetType.location() == DataLocation::Storage, ""); |
| 51 | |
| 52 | // TODO unroll loop for small sizes |
| 53 | |
| 54 | bool fromCalldata = _sourceType.location() == DataLocation::CallData; |
| 55 | bool haveSourceLengthOnStack = fromCalldata && _sourceType.isDynamicallySized(); |
| 56 | |
| 57 | for (unsigned i = _sourceType.sizeOnStack(); i > 0; --i) |
| 58 | m_context << swapInstruction(i); |
| 59 | // stack: target_ref source_ref [source_length] |
| 60 | |
| 61 | if (_sourceType.baseType()->category() == Type::Category::Array) |
| 62 | { |
| 63 | // TODO: This limitation can now be removed since we use Yul utility functions that handle nested arrays correctly. |
| 64 | // The old inline assembly implementation couldn't handle nested calldata dynamic arrays, but the Yul functions |
| 65 | // support them through recursive calls. We keep this check temporarily for backward compatibility. |
| 66 | auto const& sourceBaseArrayType = dynamic_cast<ArrayType const&>(*_sourceType.baseType()); |
| 67 | solUnimplementedAssert( |
| 68 | !fromCalldata || |
| 69 | !_sourceType.isDynamicallyEncoded() || |
| 70 | !sourceBaseArrayType.isDynamicallySized(), |
| 71 | "Copying nested calldata dynamic arrays to storage is not implemented in the old code generator." |
| 72 | ); |
| 73 | } |
| 74 | else |
| 75 | { |
| 76 | // TODO: This limitation can now be removed since we use Yul utility functions that handle non-value types correctly. |
| 77 | // The old inline assembly implementation couldn't handle copying arrays of non-value types from memory or calldata to storage, |
| 78 | // but the Yul functions support them. We keep this check temporarily for backward compatibility. |
| 79 | bool fromMemoryOrCalldata = _sourceType.location() == DataLocation::Memory || _sourceType.location() == DataLocation::CallData; |
| 80 | solUnimplementedAssert( |
| 81 | _sourceType.baseType()->isValueType() || !fromMemoryOrCalldata, |
| 82 | "Copying of type " + _sourceType.toString(false) + " to storage is not supported in legacy (only supported by the IR pipeline). " + |
| 83 | "Hint: try compiling with `--via-ir` (CLI) or the equivalent `viaIR: true` (Standard JSON)." |
| 84 | ); |
| 85 | } |
| 86 | |
| 87 | if (haveSourceLengthOnStack) |
| 88 | { |
| 89 | // stack: target_ref source_ref source_length |
| 90 | m_context << Instruction::SWAP1; |
| 91 | // stack: target_ref source_length source_ref |
| 92 | m_context << Instruction::DUP3; |
| 93 | // stack: target_ref source_length source_ref target_ref |
| 94 | } |
| 95 | else |
| 96 | { |
| 97 | // stack: target_ref source_ref |
| 98 | m_context << Instruction::DUP2; |
| 99 | // stack: target_ref source_ref target_ref |
| 100 | } |
| 101 |
no test coverage detected