| 244 | } |
| 245 | |
| 246 | void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMemory) |
| 247 | { |
| 248 | /// Stack: <source_offset> <length> |
| 249 | if (m_context.useABICoderV2()) |
| 250 | { |
| 251 | // Use the new Yul-based decoding function |
| 252 | auto stackHeightBefore = m_context.stackHeight(); |
| 253 | abiDecodeV2(_typeParameters, _fromMemory); |
| 254 | solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2); |
| 255 | return; |
| 256 | } |
| 257 | |
| 258 | //@todo this does not yet support nested dynamic arrays |
| 259 | size_t encodedSize = 0; |
| 260 | for (auto const& t: _typeParameters) |
| 261 | encodedSize += t->decodingType()->calldataHeadSize(); |
| 262 | |
| 263 | Whiskers templ(R"({ |
| 264 | if lt(len, <encodedSize>) { <revertString> } |
| 265 | })"); |
| 266 | templ("encodedSize", std::to_string(encodedSize)); |
| 267 | templ("revertString", m_context.revertReasonIfDebug("Calldata too short")); |
| 268 | m_context.appendInlineAssembly(templ.render(), {"len"}); |
| 269 | |
| 270 | m_context << Instruction::DUP2 << Instruction::ADD; |
| 271 | m_context << Instruction::SWAP1; |
| 272 | /// Stack: <input_end> <source_offset> |
| 273 | |
| 274 | // Retain the offset pointer as base_offset, the point from which the data offsets are computed. |
| 275 | m_context << Instruction::DUP1; |
| 276 | for (Type const* parameterType: _typeParameters) |
| 277 | { |
| 278 | // stack: v1 v2 ... v(k-1) input_end base_offset current_offset |
| 279 | Type const* type = parameterType->decodingType(); |
| 280 | solUnimplementedAssert(type, "No decoding type found."); |
| 281 | if (type->category() == Type::Category::Array) |
| 282 | { |
| 283 | auto const& arrayType = dynamic_cast<ArrayType const&>(*type); |
| 284 | solUnimplementedAssert(!arrayType.baseType()->isDynamicallyEncoded(), "Nested arrays not yet implemented."); |
| 285 | if (_fromMemory) |
| 286 | { |
| 287 | solUnimplementedAssert( |
| 288 | arrayType.baseType()->isValueType(), |
| 289 | "Nested memory arrays not yet implemented here." |
| 290 | ); |
| 291 | // @todo If base type is an array or struct, it is still calldata-style encoded, so |
| 292 | // we would have to convert it like below. |
| 293 | solAssert(arrayType.location() == DataLocation::Memory); |
| 294 | if (arrayType.isDynamicallySized()) |
| 295 | { |
| 296 | // compute data pointer |
| 297 | m_context << Instruction::DUP1 << Instruction::MLOAD; |
| 298 | // stack: v1 v2 ... v(k-1) input_end base_offset current_offset data_offset |
| 299 | |
| 300 | fetchFreeMemoryPointer(); |
| 301 | // stack: v1 v2 ... v(k-1) input_end base_offset current_offset data_offset dstmem |
| 302 | moveIntoStack(4); |
| 303 | // stack: v1 v2 ... v(k-1) dstmem input_end base_offset current_offset data_offset |
no test coverage detected