diff options
author | chriseth <c@ethdev.com> | 2016-10-14 18:27:46 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2016-11-16 21:37:17 +0800 |
commit | 95d7555e3c0e8fc4826114a336e0e717fe7a1a2d (patch) | |
tree | 062dccd55852a8f0c768d16c9a6715f75c7b8c0f | |
parent | 6f19559de02e0bf2b53e743678d53a4ea0414eae (diff) | |
download | dexon-solidity-95d7555e3c0e8fc4826114a336e0e717fe7a1a2d.tar.gz dexon-solidity-95d7555e3c0e8fc4826114a336e0e717fe7a1a2d.tar.zst dexon-solidity-95d7555e3c0e8fc4826114a336e0e717fe7a1a2d.zip |
External functions in storage.
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 28 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.h | 7 | ||||
-rw-r--r-- | libsolidity/codegen/LValue.cpp | 32 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 28 |
4 files changed, 76 insertions, 19 deletions
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 38a7a23b..8a06268c 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -139,8 +139,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound ) { 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; + combineExternalFunctionType(); m_context << Instruction::DUP2 << Instruction::MSTORE; m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD; } @@ -316,6 +315,21 @@ void CompilerUtils::memoryCopy() m_context << Instruction::POP; // ignore return value } +void CompilerUtils::splitExternalFunctionType() +{ + // 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; +} + +void CompilerUtils::combineExternalFunctionType() +{ + m_context << u256(0xffffffffUL) << Instruction::AND << (u256(1) << 160) << Instruction::MUL << Instruction::SWAP1; + m_context << ((u256(1) << 160) - 1) << Instruction::AND << Instruction::OR; +} + void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) { // For a type extension, we need to remove all higher-order bits that we might have ignored in @@ -860,16 +874,8 @@ 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; - } - } + splitExternalFunctionType(); return numBytes; } diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index da74dc90..0c9adf29 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -114,6 +114,13 @@ public: /// Stack post: void memoryCopy(); + /// Converts the combined and right-aligned external function type + /// <function identifier><address> into two stack slots: + /// address (right aligned), function identifier (right aligned) + void splitExternalFunctionType(); + /// Performs the opposite operation of splitExternalFunctionType() + void combineExternalFunctionType(); + /// Appends code for an implicit or explicit type conversion. This includes erasing higher /// order bits (@see appendHighBitCleanup) when widening integer but also copy to memory /// if a reference type is converted from calldata or storage to memory. diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 69a80b6a..98ab6d41 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -153,7 +153,8 @@ StorageItem::StorageItem(CompilerContext& _compilerContext, Type const& _type): { if (m_dataType->isValueType()) { - solAssert(m_dataType->storageSize() == m_dataType->sizeOnStack(), ""); + if (m_dataType->category() != Type::Category::Function) + solAssert(m_dataType->storageSize() == m_dataType->sizeOnStack(), ""); solAssert(m_dataType->storageSize() == 1, "Invalid storage size."); } } @@ -189,8 +190,16 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const dynamic_cast<IntegerType const&>(*m_dataType).isSigned() ) m_context << u256(m_dataType->storageBytes() - 1) << Instruction::SIGNEXTEND; + else if ( + m_dataType->category() == Type::Category::Function && + dynamic_cast<FunctionType const&>(*m_dataType).location() == FunctionType::Location::External + ) + CompilerUtils(m_context).splitExternalFunctionType(); else + { + solAssert(m_dataType->sizeOnStack() == 1, ""); m_context << ((u256(0x1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::AND; + } } } @@ -204,6 +213,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc solAssert(m_dataType->storageBytes() > 0, "Invalid storage bytes size."); if (m_dataType->storageBytes() == 32) { + solAssert(m_dataType->sizeOnStack() == 1, "Invalid stack size."); // offset should be zero m_context << Instruction::POP; if (!_move) @@ -222,16 +232,23 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc m_context << Instruction::DUP2 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::MUL; - m_context << Instruction::NOT << Instruction::AND; - // stack: value storage_ref multiplier cleared_value - m_context - << Instruction::SWAP1 << Instruction::DUP4; + m_context << Instruction::NOT << Instruction::AND << Instruction::SWAP1; + // stack: value storage_ref cleared_value multiplier + utils.copyToStackTop(4, m_dataType->sizeOnStack()); // stack: value storage_ref cleared_value multiplier value - if (m_dataType->category() == Type::Category::FixedBytes) + if ( + m_dataType->category() == Type::Category::Function && + dynamic_cast<FunctionType const&>(*m_dataType).location() == FunctionType::Location::External + ) + // Combine the two-item function type into a single stack slot. + utils.combineExternalFunctionType(); + else if (m_dataType->category() == Type::Category::FixedBytes) m_context << (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes())) << Instruction::SWAP1 << Instruction::DIV; else + { + solAssert(m_dataType->sizeOnStack() == 1, "Invalid stack size for opaque type."); // remove the higher order bits m_context << (u256(1) << (8 * (32 - m_dataType->storageBytes()))) @@ -239,11 +256,12 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc << Instruction::DUP2 << Instruction::MUL << Instruction::DIV; + } m_context << Instruction::MUL << Instruction::OR; // stack: value storage_ref updated_value m_context << Instruction::SWAP1 << Instruction::SSTORE; if (_move) - m_context << Instruction::POP; + utils.popStackElement(*m_dataType); } } else diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 709e63b2..b1529f8f 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -7695,7 +7695,33 @@ BOOST_AUTO_TEST_CASE(store_function) BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(9))); } -// TODO: arrays, libraries +BOOST_AUTO_TEST_CASE(function_type_library_internal) +{ + char const* sourceCode = R"( + library Utils { + function reduce(uint[] memory array, function(uint, uint) returns (uint) f, uint init) internal returns (uint) { + for (uint i = 0; i < array.length; i++) { + init = f(array[i], init); + } + return init; + } + function sum(uint a, uint b) internal returns (uint) { + return a + b; + } + } + contract C { + function f(uint[] x) returns (uint) { + return Utils.reduce(x, Utils.sum, 0); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f(uint256[])", 0x20, 3, u256(1), u256(7), u256(3)) == encodeArgs(u256(11))); +} + + +// TODO: arrays, libraries with external functions BOOST_AUTO_TEST_CASE(shift_constant_left) { |