aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen/CompilerUtils.cpp
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2016-11-18 00:32:21 +0800
committerGitHub <noreply@github.com>2016-11-18 00:32:21 +0800
commitb46a14f4a8e128c08336763abf8bbf7c111f464d (patch)
treeee20fa35cbc19eddcddd1013e745b387e7371be3 /libsolidity/codegen/CompilerUtils.cpp
parentc811691861eb51520d9fd51d56770f14990b0320 (diff)
parent2c14a96820233809db4360b39f5f02039be5730a (diff)
downloaddexon-solidity-b46a14f4a8e128c08336763abf8bbf7c111f464d.tar
dexon-solidity-b46a14f4a8e128c08336763abf8bbf7c111f464d.tar.gz
dexon-solidity-b46a14f4a8e128c08336763abf8bbf7c111f464d.tar.bz2
dexon-solidity-b46a14f4a8e128c08336763abf8bbf7c111f464d.tar.lz
dexon-solidity-b46a14f4a8e128c08336763abf8bbf7c111f464d.tar.xz
dexon-solidity-b46a14f4a8e128c08336763abf8bbf7c111f464d.tar.zst
dexon-solidity-b46a14f4a8e128c08336763abf8bbf7c111f464d.zip
Merge pull request #1122 from ethereum/firstClassFunctions
Functions as first-class types.
Diffstat (limited to 'libsolidity/codegen/CompilerUtils.cpp')
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp94
1 files changed, 81 insertions, 13 deletions
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 58d1caa9..bfe5386b 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -133,6 +133,16 @@ 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
+ )
+ {
+ solUnimplementedAssert(_padToWordBoundaries, "Non-padded store for function not implemented.");
+ combineExternalFunctionType(true);
+ m_context << Instruction::DUP2 << Instruction::MSTORE;
+ m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD;
+ }
else
{
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
@@ -206,7 +216,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
@@ -304,6 +315,49 @@ void CompilerUtils::memoryCopy()
m_context << Instruction::POP; // ignore return value
}
+void CompilerUtils::splitExternalFunctionType(bool _leftAligned)
+{
+ // We have to split the left-aligned <address><function identifier> into two stack slots:
+ // address (right aligned), function identifier (right aligned)
+ if (_leftAligned)
+ {
+ m_context << Instruction::DUP1 << (u256(1) << (64 + 32)) << Instruction::SWAP1 << Instruction::DIV;
+ // <input> <address>
+ m_context << Instruction::SWAP1 << (u256(1) << 64) << Instruction::SWAP1 << Instruction::DIV;
+ }
+ else
+ {
+ m_context << Instruction::DUP1 << (u256(1) << 32) << Instruction::SWAP1 << Instruction::DIV;
+ m_context << ((u256(1) << 160) - 1) << Instruction::AND << Instruction::SWAP1;
+ }
+ m_context << u256(0xffffffffUL) << Instruction::AND;
+}
+
+void CompilerUtils::combineExternalFunctionType(bool _leftAligned)
+{
+ // <address> <function_id>
+ m_context << u256(0xffffffffUL) << Instruction::AND << Instruction::SWAP1;
+ if (!_leftAligned)
+ m_context << ((u256(1) << 160) - 1) << Instruction::AND;
+ m_context << (u256(1) << 32) << Instruction::MUL;
+ m_context << Instruction::OR;
+ if (_leftAligned)
+ m_context << (u256(1) << 64) << Instruction::MUL;
+}
+
+void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function)
+{
+ m_context << m_context.functionEntryLabel(_function).pushTag();
+ // If there is a runtime context, we have to merge both labels into the same
+ // stack slot in case we store it in storage.
+ if (CompilerContext* rtc = m_context.runtimeContext())
+ m_context <<
+ (u256(1) << 32) <<
+ Instruction::MUL <<
+ rtc->functionEntryLabel(_function).toSubAssemblyTag(m_context.runtimeSub()) <<
+ 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
@@ -678,6 +732,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)
{
@@ -822,21 +884,27 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries);
- bool leftAligned = _type.category() == Type::Category::FixedBytes;
+ bool isExternalFunctionType = false;
+ if (auto const* funType = dynamic_cast<FunctionType const*>(&_type))
+ if (funType->location() == FunctionType::Location::External)
+ isExternalFunctionType = true;
if (numBytes == 0)
+ {
m_context << Instruction::POP << u256(0);
- else
+ return numBytes;
+ }
+ solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
+ m_context << (_fromCalldata ? Instruction::CALLDATALOAD : Instruction::MLOAD);
+ if (isExternalFunctionType)
+ splitExternalFunctionType(true);
+ else if (numBytes != 32)
{
- solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
- m_context << (_fromCalldata ? Instruction::CALLDATALOAD : Instruction::MLOAD);
- if (numBytes != 32)
- {
- // add leading or trailing zeros by dividing/multiplying depending on alignment
- u256 shiftFactor = u256(1) << ((32 - numBytes) * 8);
- m_context << shiftFactor << Instruction::SWAP1 << Instruction::DIV;
- if (leftAligned)
- m_context << shiftFactor << Instruction::MUL;
- }
+ bool leftAligned = _type.category() == Type::Category::FixedBytes;
+ // add leading or trailing zeros by dividing/multiplying depending on alignment
+ u256 shiftFactor = u256(1) << ((32 - numBytes) * 8);
+ m_context << shiftFactor << Instruction::SWAP1 << Instruction::DIV;
+ if (leftAligned)
+ m_context << shiftFactor << Instruction::MUL;
}
return numBytes;