Tests apart from new one work fine.

This commit is contained in:
chriseth 2015-10-02 22:34:47 +02:00
parent 9cc7402c95
commit 421dcf4c1a
7 changed files with 52 additions and 40 deletions

View File

@ -252,7 +252,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
eth::AssemblyItem returnTag = m_context.pushNewTag();
fallback->accept(*this);
m_context << returnTag;
appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes());
appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary());
}
else
m_context << eth::Instruction::STOP; // function not found
@ -268,7 +268,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
appendCalldataUnpacker(functionType->parameterTypes());
m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration()));
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)
{
// stack: v1 v2 ... v(k-1) base_offset current_offset
TypePointer type = parameterType->encodingType();
TypePointer type = parameterType->decodingType();
if (type->category() == Type::Category::Array)
{
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());
m_context << eth::Instruction::SWAP1;
}
break;
}
else
{
@ -354,7 +353,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
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);
if (_typeParameters.empty())
@ -364,7 +363,7 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
utils.fetchFreeMemoryPointer();
//@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.
utils.encodeToMemory(_typeParameters, _typeParameters);
utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary);
utils.toSizeAfterFreeMemoryPointer();
m_context << eth::Instruction::RETURN;
}

View File

@ -87,7 +87,7 @@ private:
/// 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);
void appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary);
void registerStateVariables(ContractDefinition const& _contract);
void initializeStateVariables(ContractDefinition const& _contract);

View File

@ -153,14 +153,15 @@ void CompilerUtils::encodeToMemory(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _padToWordBoundaries,
bool _copyDynamicDataInPlace
bool _copyDynamicDataInPlace,
bool _encodeAsLibraryTypes
)
{
// stack: <v1> <v2> ... <vn> <mem>
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
solAssert(targetTypes.size() == _givenTypes.size(), "");
for (TypePointer& t: targetTypes)
t = t->mobileType()->encodingType();
t = t->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType();
// Stack during operation:
// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>

View File

@ -91,13 +91,16 @@ public:
/// @param _padToWordBoundaries if false, all values are concatenated without padding.
/// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length)
/// 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
/// memory.
void encodeToMemory(
TypePointers const& _givenTypes = {},
TypePointers const& _targetTypes = {},
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.

View File

@ -109,42 +109,40 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
// As an exception, "storage" is allowed for library functions.
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());
if (_variable.isExternalCallableParameter())
if (contract.isLibrary())
{
if (contract.isLibrary())
{
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())
if (loc == Location::Memory)
BOOST_THROW_EXCEPTION(_variable.createTypeError(
"Location has to be memory for publicly visible functions "
"(remove the \"storage\" keyword)."
"Location has to be calldata or storage for external "
"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
{

View File

@ -847,6 +847,14 @@ TypePointer ArrayType::encodingType() const
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
{
if (_inLibrary && location() == DataLocation::Storage)

View File

@ -230,6 +230,8 @@ public:
/// This for example returns address for contract types.
/// If there is no such type, returns an empty shared pointer.
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.
/// This for example returns address for contract types.
/// If there is no such type, returns an empty shared pointer.
@ -504,6 +506,7 @@ public:
return isString() ? EmptyMemberList : s_arrayTypeMemberList;
}
virtual TypePointer encodingType() const override;
virtual TypePointer decodingType() const override;
virtual TypePointer interfaceType(bool _inLibrary) const override;
/// @returns true if this is a byte array or a string