diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 99 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.h | 5 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 103 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.h | 4 |
4 files changed, 106 insertions, 105 deletions
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 533aca5c..704d8da8 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -159,6 +159,105 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound } } +void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMemory) +{ + // We do not check the calldata size, everything is zero-padded + + if (m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) + { + // Use the new JULIA-based decoding function + auto stackHeightBefore = m_context.stackHeight(); + abiDecodeV2(_typeParameters, _fromMemory); + solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 1, ""); + return; + } + + //@todo this does not yet support nested dynamic arrays + + // Retain the offset pointer as base_offset, the point from which the data offsets are computed. + m_context << Instruction::DUP1; + for (TypePointer const& parameterType: _typeParameters) + { + // stack: v1 v2 ... v(k-1) base_offset current_offset + TypePointer type = parameterType->decodingType(); + solUnimplementedAssert(type, "No decoding type found."); + if (type->category() == Type::Category::Array) + { + auto const& arrayType = dynamic_cast<ArrayType const&>(*type); + solUnimplementedAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented."); + if (_fromMemory) + { + solUnimplementedAssert( + arrayType.baseType()->isValueType(), + "Nested memory arrays not yet implemented here." + ); + // @todo If base type is an array or struct, it is still calldata-style encoded, so + // we would have to convert it like below. + solAssert(arrayType.location() == DataLocation::Memory, ""); + if (arrayType.isDynamicallySized()) + { + // compute data pointer + m_context << Instruction::DUP1 << Instruction::MLOAD; + m_context << Instruction::DUP3 << Instruction::ADD; + m_context << Instruction::SWAP2 << Instruction::SWAP1; + m_context << u256(0x20) << Instruction::ADD; + } + else + { + m_context << Instruction::SWAP1 << Instruction::DUP2; + m_context << u256(arrayType.calldataEncodedSize(true)) << Instruction::ADD; + } + } + else + { + // first load from calldata and potentially convert to memory if arrayType is memory + TypePointer calldataType = arrayType.copyForLocation(DataLocation::CallData, false); + if (calldataType->isDynamicallySized()) + { + // put on stack: data_pointer length + loadFromMemoryDynamic(IntegerType(256), !_fromMemory); + // stack: base_offset data_offset next_pointer + m_context << Instruction::SWAP1 << Instruction::DUP3 << Instruction::ADD; + // stack: base_offset next_pointer data_pointer + // retrieve length + loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); + // stack: base_offset next_pointer length data_pointer + m_context << Instruction::SWAP2; + // stack: base_offset data_pointer length next_pointer + } + else + { + // leave the pointer on the stack + m_context << Instruction::DUP1; + m_context << u256(calldataType->calldataEncodedSize()) << Instruction::ADD; + } + if (arrayType.location() == DataLocation::Memory) + { + // stack: base_offset calldata_ref [length] next_calldata + // copy to memory + // move calldata type up again + moveIntoStack(calldataType->sizeOnStack()); + convertType(*calldataType, arrayType, false, false, true); + // fetch next pointer again + moveToStackTop(arrayType.sizeOnStack()); + } + // move base_offset up + moveToStackTop(1 + arrayType.sizeOnStack()); + m_context << Instruction::SWAP1; + } + } + else + { + solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); + loadFromMemoryDynamic(*type, !_fromMemory, true); + moveToStackTop(1 + type->sizeOnStack()); + m_context << Instruction::SWAP1; + } + // stack: v1 v2 ... v(k-1) v(k) base_offset mem_offset + } + m_context << Instruction::POP << Instruction::POP; +} + void CompilerUtils::encodeToMemory( TypePointers const& _givenTypes, TypePointers const& _targetTypes, diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index 3cde281b..9fc97b9e 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -88,6 +88,11 @@ public: /// Stack post: (memory_offset+length) void storeInMemoryDynamic(Type const& _type, bool _padToWords = true); + /// Creates code that unpacks the arguments according to their types specified by a vector of TypePointers. + /// From memory if @a _fromMemory is true, otherwise from call data. + /// Expects source offset on the stack, which is removed. + void abiDecode(TypePointers const& _typeParameters, bool _fromMemory = false); + /// Copies values (of types @a _givenTypes) given on the stack to a location in memory given /// at the stack top, encoding them according to the ABI as the given types @a _targetTypes. /// Removes the values from the stack and leaves the updated memory pointer. diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 95d6c8b5..480db98e 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -280,7 +280,7 @@ void ContractCompiler::appendConstructor(FunctionDefinition const& _constructor) m_context << Instruction::DUP2 << Instruction::ADD; CompilerUtils(m_context).storeFreeMemoryPointer(); // stack: <memptr> - appendCalldataUnpacker(FunctionType(_constructor).parameterTypes(), true); + CompilerUtils(m_context).abiDecode(FunctionType(_constructor).parameterTypes(), true); } _constructor.accept(*this); } @@ -367,7 +367,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac { // Parameter for calldataUnpacker m_context << CompilerUtils::dataStartOffset; - appendCalldataUnpacker(functionType->parameterTypes()); + CompilerUtils(m_context).abiDecode(functionType->parameterTypes()); } m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration())); m_context << returnTag; @@ -382,105 +382,6 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac } } -void ContractCompiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) -{ - // We do not check the calldata size, everything is zero-padded - - if (m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) - { - // Use the new JULIA-based decoding function - auto stackHeightBefore = m_context.stackHeight(); - CompilerUtils(m_context).abiDecodeV2(_typeParameters, _fromMemory); - solAssert(m_context.stackHeight() - stackHeightBefore == CompilerUtils(m_context).sizeOnStack(_typeParameters) - 1, ""); - return; - } - - //@todo this does not yet support nested dynamic arrays - - // Retain the offset pointer as base_offset, the point from which the data offsets are computed. - m_context << Instruction::DUP1; - for (TypePointer const& parameterType: _typeParameters) - { - // stack: v1 v2 ... v(k-1) base_offset current_offset - TypePointer type = parameterType->decodingType(); - solUnimplementedAssert(type, "No decoding type found."); - if (type->category() == Type::Category::Array) - { - auto const& arrayType = dynamic_cast<ArrayType const&>(*type); - solUnimplementedAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented."); - if (_fromMemory) - { - solUnimplementedAssert( - arrayType.baseType()->isValueType(), - "Nested memory arrays not yet implemented here." - ); - // @todo If base type is an array or struct, it is still calldata-style encoded, so - // we would have to convert it like below. - solAssert(arrayType.location() == DataLocation::Memory, ""); - if (arrayType.isDynamicallySized()) - { - // compute data pointer - m_context << Instruction::DUP1 << Instruction::MLOAD; - m_context << Instruction::DUP3 << Instruction::ADD; - m_context << Instruction::SWAP2 << Instruction::SWAP1; - m_context << u256(0x20) << Instruction::ADD; - } - else - { - m_context << Instruction::SWAP1 << Instruction::DUP2; - m_context << u256(arrayType.calldataEncodedSize(true)) << Instruction::ADD; - } - } - else - { - // first load from calldata and potentially convert to memory if arrayType is memory - TypePointer calldataType = arrayType.copyForLocation(DataLocation::CallData, false); - if (calldataType->isDynamicallySized()) - { - // put on stack: data_pointer length - CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory); - // stack: base_offset data_offset next_pointer - m_context << Instruction::SWAP1 << Instruction::DUP3 << Instruction::ADD; - // stack: base_offset next_pointer data_pointer - // retrieve length - CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); - // stack: base_offset next_pointer length data_pointer - m_context << Instruction::SWAP2; - // stack: base_offset data_pointer length next_pointer - } - else - { - // leave the pointer on the stack - m_context << Instruction::DUP1; - m_context << u256(calldataType->calldataEncodedSize()) << Instruction::ADD; - } - if (arrayType.location() == DataLocation::Memory) - { - // stack: base_offset calldata_ref [length] next_calldata - // copy to memory - // move calldata type up again - CompilerUtils(m_context).moveIntoStack(calldataType->sizeOnStack()); - CompilerUtils(m_context).convertType(*calldataType, arrayType, false, false, true); - // fetch next pointer again - CompilerUtils(m_context).moveToStackTop(arrayType.sizeOnStack()); - } - // move base_offset up - CompilerUtils(m_context).moveToStackTop(1 + arrayType.sizeOnStack()); - m_context << Instruction::SWAP1; - } - } - else - { - solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); - CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true); - CompilerUtils(m_context).moveToStackTop(1 + type->sizeOnStack()); - m_context << Instruction::SWAP1; - } - // stack: v1 v2 ... v(k-1) v(k) base_offset mem_offset - } - m_context << Instruction::POP << Instruction::POP; -} - void ContractCompiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary) { CompilerUtils utils(m_context); diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 8559ea58..e04a56fb 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -90,10 +90,6 @@ private: void appendDelegatecallCheck(); void appendFunctionSelector(ContractDefinition const& _contract); void appendCallValueCheck(); - /// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers. - /// From memory if @a _fromMemory is true, otherwise from call data. - /// Expects source offset on the stack, which is removed. - void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false); void appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary); void registerStateVariables(ContractDefinition const& _contract); |