diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/ast/Types.cpp | 12 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 1 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 34 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 1 |
4 files changed, 46 insertions, 2 deletions
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 808b0c55..19a1b9d1 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2065,6 +2065,16 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con } } +TypePointer FunctionType::encodingType() const +{ + // Only external functions can be encoded, internal functions cannot leave code boundaries. + if (m_location == Location::External) + // This looks like bytes24, but bytes24 is stored differently on the stack. + return shared_from_this(); + else + return TypePointer(); +} + TypePointer FunctionType::interfaceType(bool _inLibrary) const { if (m_location != Location::External && m_location != Location::Internal) @@ -2072,7 +2082,7 @@ TypePointer FunctionType::interfaceType(bool _inLibrary) const if (_inLibrary) return shared_from_this(); else - return make_shared<FixedBytesType>(storageBytes()); + return make_shared<IntegerType>(8 * storageBytes()); } bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes, TypePointer const& _selfType) const diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 358c7efc..691ddf29 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -901,6 +901,7 @@ public: virtual bool canLiveOutsideStorage() const override { return m_location == Location::Internal || m_location == Location::External; } virtual unsigned sizeOnStack() const override; virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; + virtual TypePointer encodingType() const override; virtual TypePointer interfaceType(bool _inLibrary) const override; /// @returns TypePointer of a new FunctionType object. All input/return parameters are an diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 58d1caa9..38a7a23b 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -133,6 +133,17 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound m_context << u256(str->value().size()); m_context << Instruction::ADD; } + else if ( + _type.category() == Type::Category::Function && + dynamic_cast<FunctionType const&>(_type).location() == FunctionType::Location::External + ) + { + solAssert(_padToWordBoundaries, "Non-padded store for function not implemented."); + m_context << u256(0xffffffffUL) << Instruction::AND << (u256(1) << 160) << Instruction::MUL << Instruction::SWAP1; + m_context << ((u256(1) << 160) - 1) << Instruction::AND << Instruction::OR; + m_context << Instruction::DUP2 << Instruction::MSTORE; + m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD; + } else { unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); @@ -206,7 +217,8 @@ void CompilerUtils::encodeToMemory( else if ( _givenTypes[i]->dataStoredIn(DataLocation::Storage) || _givenTypes[i]->dataStoredIn(DataLocation::CallData) || - _givenTypes[i]->category() == Type::Category::StringLiteral + _givenTypes[i]->category() == Type::Category::StringLiteral || + _givenTypes[i]->category() == Type::Category::Function ) type = _givenTypes[i]; // delay conversion else @@ -678,6 +690,14 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp void CompilerUtils::pushZeroValue(Type const& _type) { + if (auto const* funType = dynamic_cast<FunctionType const*>(&_type)) + { + if (funType->location() == FunctionType::Location::Internal) + { + m_context << m_context.errorTag(); + return; + } + } auto const* referenceType = dynamic_cast<ReferenceType const*>(&_type); if (!referenceType || referenceType->location() == DataLocation::Storage) { @@ -839,6 +859,18 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda } } + if (auto const* funType = dynamic_cast<FunctionType const*>(&_type)) + { + if (funType->location() == FunctionType::Location::External) + { + // We have to split the right-aligned <function identifier><address> into two stack slots: + // address (right aligned), function identifier (right aligned) + m_context << Instruction::DUP1 << ((u256(1) << 160) - 1) << Instruction::AND << Instruction::SWAP1; + m_context << (u256(1) << 160) << Instruction::SWAP1 << Instruction::DIV; + m_context << u256(0xffffffffUL) << Instruction::AND; + } + } + return numBytes; } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 2aec3055..9cd893e8 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -293,6 +293,7 @@ void ContractCompiler::appendCalldataUnpacker(TypePointers const& _typeParameter { // stack: v1 v2 ... v(k-1) base_offset current_offset TypePointer type = parameterType->decodingType(); + solAssert(type, "No decoding type found."); if (type->category() == Type::Category::Array) { auto const& arrayType = dynamic_cast<ArrayType const&>(*type); |