From 2cdf44f65cdd15f31293ae2fa78d9996d6219af0 Mon Sep 17 00:00:00 2001
From: chriseth <chris@ethereum.org>
Date: Tue, 20 Feb 2018 10:13:58 +0100
Subject: Move the old ABI decoder code.

---
 libsolidity/codegen/CompilerUtils.cpp    |  99 +++++++++++++++++++++++++++++
 libsolidity/codegen/CompilerUtils.h      |   5 ++
 libsolidity/codegen/ContractCompiler.cpp | 103 +------------------------------
 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);
-- 
cgit v1.2.3