aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp99
-rw-r--r--libsolidity/codegen/CompilerUtils.h5
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp103
-rw-r--r--libsolidity/codegen/ContractCompiler.h4
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);