aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-10-14 18:27:46 +0800
committerchriseth <c@ethdev.com>2016-11-16 21:37:17 +0800
commit95d7555e3c0e8fc4826114a336e0e717fe7a1a2d (patch)
tree062dccd55852a8f0c768d16c9a6715f75c7b8c0f
parent6f19559de02e0bf2b53e743678d53a4ea0414eae (diff)
downloaddexon-solidity-95d7555e3c0e8fc4826114a336e0e717fe7a1a2d.tar.gz
dexon-solidity-95d7555e3c0e8fc4826114a336e0e717fe7a1a2d.tar.zst
dexon-solidity-95d7555e3c0e8fc4826114a336e0e717fe7a1a2d.zip
External functions in storage.
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp28
-rw-r--r--libsolidity/codegen/CompilerUtils.h7
-rw-r--r--libsolidity/codegen/LValue.cpp32
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp28
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)
{