mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Tests apart from new one work fine.
This commit is contained in:
parent
9cc7402c95
commit
421dcf4c1a
@ -252,7 +252,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
|
|||||||
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
||||||
fallback->accept(*this);
|
fallback->accept(*this);
|
||||||
m_context << returnTag;
|
m_context << returnTag;
|
||||||
appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes());
|
appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_context << eth::Instruction::STOP; // function not found
|
m_context << eth::Instruction::STOP; // function not found
|
||||||
@ -268,7 +268,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
|
|||||||
appendCalldataUnpacker(functionType->parameterTypes());
|
appendCalldataUnpacker(functionType->parameterTypes());
|
||||||
m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration()));
|
m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration()));
|
||||||
m_context << returnTag;
|
m_context << returnTag;
|
||||||
appendReturnValuePacker(functionType->returnParameterTypes());
|
appendReturnValuePacker(functionType->returnParameterTypes(), _contract.isLibrary());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +283,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
|
|||||||
for (TypePointer const& parameterType: _typeParameters)
|
for (TypePointer const& parameterType: _typeParameters)
|
||||||
{
|
{
|
||||||
// stack: v1 v2 ... v(k-1) base_offset current_offset
|
// stack: v1 v2 ... v(k-1) base_offset current_offset
|
||||||
TypePointer type = parameterType->encodingType();
|
TypePointer type = parameterType->decodingType();
|
||||||
if (type->category() == Type::Category::Array)
|
if (type->category() == Type::Category::Array)
|
||||||
{
|
{
|
||||||
auto const& arrayType = dynamic_cast<ArrayType const&>(*type);
|
auto const& arrayType = dynamic_cast<ArrayType const&>(*type);
|
||||||
@ -340,7 +340,6 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
|
|||||||
CompilerUtils(m_context).moveToStackTop(1 + arrayType.sizeOnStack());
|
CompilerUtils(m_context).moveToStackTop(1 + arrayType.sizeOnStack());
|
||||||
m_context << eth::Instruction::SWAP1;
|
m_context << eth::Instruction::SWAP1;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -354,7 +353,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
|
|||||||
m_context << eth::Instruction::POP << eth::Instruction::POP;
|
m_context << eth::Instruction::POP << eth::Instruction::POP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
|
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary)
|
||||||
{
|
{
|
||||||
CompilerUtils utils(m_context);
|
CompilerUtils utils(m_context);
|
||||||
if (_typeParameters.empty())
|
if (_typeParameters.empty())
|
||||||
@ -364,7 +363,7 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
|
|||||||
utils.fetchFreeMemoryPointer();
|
utils.fetchFreeMemoryPointer();
|
||||||
//@todo optimization: if we return a single memory array, there should be enough space before
|
//@todo optimization: if we return a single memory array, there should be enough space before
|
||||||
// its data to add the needed parts and we avoid a memory copy.
|
// its data to add the needed parts and we avoid a memory copy.
|
||||||
utils.encodeToMemory(_typeParameters, _typeParameters);
|
utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary);
|
||||||
utils.toSizeAfterFreeMemoryPointer();
|
utils.toSizeAfterFreeMemoryPointer();
|
||||||
m_context << eth::Instruction::RETURN;
|
m_context << eth::Instruction::RETURN;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ private:
|
|||||||
/// From memory if @a _fromMemory is true, otherwise from call data.
|
/// From memory if @a _fromMemory is true, otherwise from call data.
|
||||||
/// Expects source offset on the stack, which is removed.
|
/// Expects source offset on the stack, which is removed.
|
||||||
void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false);
|
void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false);
|
||||||
void appendReturnValuePacker(TypePointers const& _typeParameters);
|
void appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary);
|
||||||
|
|
||||||
void registerStateVariables(ContractDefinition const& _contract);
|
void registerStateVariables(ContractDefinition const& _contract);
|
||||||
void initializeStateVariables(ContractDefinition const& _contract);
|
void initializeStateVariables(ContractDefinition const& _contract);
|
||||||
|
@ -153,14 +153,15 @@ void CompilerUtils::encodeToMemory(
|
|||||||
TypePointers const& _givenTypes,
|
TypePointers const& _givenTypes,
|
||||||
TypePointers const& _targetTypes,
|
TypePointers const& _targetTypes,
|
||||||
bool _padToWordBoundaries,
|
bool _padToWordBoundaries,
|
||||||
bool _copyDynamicDataInPlace
|
bool _copyDynamicDataInPlace,
|
||||||
|
bool _encodeAsLibraryTypes
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// stack: <v1> <v2> ... <vn> <mem>
|
// stack: <v1> <v2> ... <vn> <mem>
|
||||||
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
|
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
|
||||||
solAssert(targetTypes.size() == _givenTypes.size(), "");
|
solAssert(targetTypes.size() == _givenTypes.size(), "");
|
||||||
for (TypePointer& t: targetTypes)
|
for (TypePointer& t: targetTypes)
|
||||||
t = t->mobileType()->encodingType();
|
t = t->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType();
|
||||||
|
|
||||||
// Stack during operation:
|
// Stack during operation:
|
||||||
// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
|
// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
|
||||||
|
@ -91,13 +91,16 @@ public:
|
|||||||
/// @param _padToWordBoundaries if false, all values are concatenated without padding.
|
/// @param _padToWordBoundaries if false, all values are concatenated without padding.
|
||||||
/// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length)
|
/// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length)
|
||||||
/// together with fixed-length data.
|
/// together with fixed-length data.
|
||||||
|
/// @param _encodeAsLibraryTypes if true, encodes for a library function, e.g. does not
|
||||||
|
/// convert storage pointer types to memory types.
|
||||||
/// @note the locations of target reference types are ignored, because it will always be
|
/// @note the locations of target reference types are ignored, because it will always be
|
||||||
/// memory.
|
/// memory.
|
||||||
void encodeToMemory(
|
void encodeToMemory(
|
||||||
TypePointers const& _givenTypes = {},
|
TypePointers const& _givenTypes = {},
|
||||||
TypePointers const& _targetTypes = {},
|
TypePointers const& _targetTypes = {},
|
||||||
bool _padToWordBoundaries = true,
|
bool _padToWordBoundaries = true,
|
||||||
bool _copyDynamicDataInPlace = false
|
bool _copyDynamicDataInPlace = false,
|
||||||
|
bool _encodeAsLibraryTypes = false
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Uses a CALL to the identity contract to perform a memory-to-memory copy.
|
/// Uses a CALL to the identity contract to perform a memory-to-memory copy.
|
||||||
|
@ -109,42 +109,40 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
|||||||
// As an exception, "storage" is allowed for library functions.
|
// As an exception, "storage" is allowed for library functions.
|
||||||
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
|
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
|
||||||
{
|
{
|
||||||
if (_variable.isCallableParameter())
|
if (_variable.isExternalCallableParameter())
|
||||||
{
|
{
|
||||||
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
|
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
|
||||||
if (_variable.isExternalCallableParameter())
|
if (contract.isLibrary())
|
||||||
{
|
{
|
||||||
if (contract.isLibrary())
|
if (loc == Location::Memory)
|
||||||
{
|
|
||||||
if (loc == Location::Memory)
|
|
||||||
BOOST_THROW_EXCEPTION(_variable.createTypeError(
|
|
||||||
"Location has to be calldata or storage for external "
|
|
||||||
"library functions (remove the \"memory\" keyword)."
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// force location of external function parameters (not return) to calldata
|
|
||||||
if (loc != Location::Default)
|
|
||||||
BOOST_THROW_EXCEPTION(_variable.createTypeError(
|
|
||||||
"Location has to be calldata for external functions "
|
|
||||||
"(remove the \"memory\" or \"storage\" keyword)."
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if (loc == Location::Default)
|
|
||||||
type = ref->copyForLocation(DataLocation::CallData, true);
|
|
||||||
}
|
|
||||||
else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
|
|
||||||
{
|
|
||||||
// force locations of public or external function (return) parameters to memory
|
|
||||||
if (loc == Location::Storage && !contract.isLibrary())
|
|
||||||
BOOST_THROW_EXCEPTION(_variable.createTypeError(
|
BOOST_THROW_EXCEPTION(_variable.createTypeError(
|
||||||
"Location has to be memory for publicly visible functions "
|
"Location has to be calldata or storage for external "
|
||||||
"(remove the \"storage\" keyword)."
|
"library functions (remove the \"memory\" keyword)."
|
||||||
));
|
));
|
||||||
if (loc == Location::Default)
|
|
||||||
type = ref->copyForLocation(DataLocation::Memory, true);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// force location of external function parameters (not return) to calldata
|
||||||
|
if (loc != Location::Default)
|
||||||
|
BOOST_THROW_EXCEPTION(_variable.createTypeError(
|
||||||
|
"Location has to be calldata for external functions "
|
||||||
|
"(remove the \"memory\" or \"storage\" keyword)."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (loc == Location::Default)
|
||||||
|
type = ref->copyForLocation(DataLocation::CallData, true);
|
||||||
|
}
|
||||||
|
else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
|
||||||
|
{
|
||||||
|
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
|
||||||
|
// force locations of public or external function (return) parameters to memory
|
||||||
|
if (loc == Location::Storage && !contract.isLibrary())
|
||||||
|
BOOST_THROW_EXCEPTION(_variable.createTypeError(
|
||||||
|
"Location has to be memory for publicly visible functions "
|
||||||
|
"(remove the \"storage\" keyword)."
|
||||||
|
));
|
||||||
|
if (loc == Location::Default || !contract.isLibrary())
|
||||||
|
type = ref->copyForLocation(DataLocation::Memory, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -847,6 +847,14 @@ TypePointer ArrayType::encodingType() const
|
|||||||
return this->copyForLocation(DataLocation::Memory, true);
|
return this->copyForLocation(DataLocation::Memory, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePointer ArrayType::decodingType() const
|
||||||
|
{
|
||||||
|
if (location() == DataLocation::Storage)
|
||||||
|
return make_shared<IntegerType>(256);
|
||||||
|
else
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
|
||||||
TypePointer ArrayType::interfaceType(bool _inLibrary) const
|
TypePointer ArrayType::interfaceType(bool _inLibrary) const
|
||||||
{
|
{
|
||||||
if (_inLibrary && location() == DataLocation::Storage)
|
if (_inLibrary && location() == DataLocation::Storage)
|
||||||
|
@ -230,6 +230,8 @@ public:
|
|||||||
/// This for example returns address for contract types.
|
/// This for example returns address for contract types.
|
||||||
/// If there is no such type, returns an empty shared pointer.
|
/// If there is no such type, returns an empty shared pointer.
|
||||||
virtual TypePointer encodingType() const { return TypePointer(); }
|
virtual TypePointer encodingType() const { return TypePointer(); }
|
||||||
|
/// @returns a (simpler) type that is used when decoding this type in calldata.
|
||||||
|
virtual TypePointer decodingType() const { return encodingType(); }
|
||||||
/// @returns a type that will be used outside of Solidity for e.g. function signatures.
|
/// @returns a type that will be used outside of Solidity for e.g. function signatures.
|
||||||
/// This for example returns address for contract types.
|
/// This for example returns address for contract types.
|
||||||
/// If there is no such type, returns an empty shared pointer.
|
/// If there is no such type, returns an empty shared pointer.
|
||||||
@ -504,6 +506,7 @@ public:
|
|||||||
return isString() ? EmptyMemberList : s_arrayTypeMemberList;
|
return isString() ? EmptyMemberList : s_arrayTypeMemberList;
|
||||||
}
|
}
|
||||||
virtual TypePointer encodingType() const override;
|
virtual TypePointer encodingType() const override;
|
||||||
|
virtual TypePointer decodingType() const override;
|
||||||
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
||||||
|
|
||||||
/// @returns true if this is a byte array or a string
|
/// @returns true if this is a byte array or a string
|
||||||
|
Loading…
Reference in New Issue
Block a user