mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Move the old ABI decoder code.
This commit is contained in:
parent
2b2527f31c
commit
2cdf44f65c
@ -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(
|
void CompilerUtils::encodeToMemory(
|
||||||
TypePointers const& _givenTypes,
|
TypePointers const& _givenTypes,
|
||||||
TypePointers const& _targetTypes,
|
TypePointers const& _targetTypes,
|
||||||
|
@ -88,6 +88,11 @@ public:
|
|||||||
/// Stack post: (memory_offset+length)
|
/// Stack post: (memory_offset+length)
|
||||||
void storeInMemoryDynamic(Type const& _type, bool _padToWords = true);
|
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
|
/// 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.
|
/// 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.
|
/// Removes the values from the stack and leaves the updated memory pointer.
|
||||||
|
@ -280,7 +280,7 @@ void ContractCompiler::appendConstructor(FunctionDefinition const& _constructor)
|
|||||||
m_context << Instruction::DUP2 << Instruction::ADD;
|
m_context << Instruction::DUP2 << Instruction::ADD;
|
||||||
CompilerUtils(m_context).storeFreeMemoryPointer();
|
CompilerUtils(m_context).storeFreeMemoryPointer();
|
||||||
// stack: <memptr>
|
// stack: <memptr>
|
||||||
appendCalldataUnpacker(FunctionType(_constructor).parameterTypes(), true);
|
CompilerUtils(m_context).abiDecode(FunctionType(_constructor).parameterTypes(), true);
|
||||||
}
|
}
|
||||||
_constructor.accept(*this);
|
_constructor.accept(*this);
|
||||||
}
|
}
|
||||||
@ -367,7 +367,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
|||||||
{
|
{
|
||||||
// Parameter for calldataUnpacker
|
// Parameter for calldataUnpacker
|
||||||
m_context << CompilerUtils::dataStartOffset;
|
m_context << CompilerUtils::dataStartOffset;
|
||||||
appendCalldataUnpacker(functionType->parameterTypes());
|
CompilerUtils(m_context).abiDecode(functionType->parameterTypes());
|
||||||
}
|
}
|
||||||
m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration()));
|
m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration()));
|
||||||
m_context << returnTag;
|
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)
|
void ContractCompiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary)
|
||||||
{
|
{
|
||||||
CompilerUtils utils(m_context);
|
CompilerUtils utils(m_context);
|
||||||
|
@ -90,10 +90,6 @@ private:
|
|||||||
void appendDelegatecallCheck();
|
void appendDelegatecallCheck();
|
||||||
void appendFunctionSelector(ContractDefinition const& _contract);
|
void appendFunctionSelector(ContractDefinition const& _contract);
|
||||||
void appendCallValueCheck();
|
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 appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary);
|
||||||
|
|
||||||
void registerStateVariables(ContractDefinition const& _contract);
|
void registerStateVariables(ContractDefinition const& _contract);
|
||||||
|
Loading…
Reference in New Issue
Block a user