aboutsummaryrefslogtreecommitdiffstats
path: root/src/CompilerUtils.cpp
diff options
context:
space:
mode:
authorLefteris Karapetsas <lefteris@refu.co>2015-08-19 20:57:25 +0800
committerLefteris Karapetsas <lefteris@refu.co>2015-08-19 20:57:25 +0800
commit1690f1c947b1b1bfaf84d0a586d2a56ffed11f37 (patch)
treecbf27ebb57b629ae7a4a10cc1342a359481de7d3 /src/CompilerUtils.cpp
parent2f41438715137e7f123481b2ca8e163a4d35bd78 (diff)
downloaddexon-solidity-1690f1c947b1b1bfaf84d0a586d2a56ffed11f37.tar
dexon-solidity-1690f1c947b1b1bfaf84d0a586d2a56ffed11f37.tar.gz
dexon-solidity-1690f1c947b1b1bfaf84d0a586d2a56ffed11f37.tar.bz2
dexon-solidity-1690f1c947b1b1bfaf84d0a586d2a56ffed11f37.tar.lz
dexon-solidity-1690f1c947b1b1bfaf84d0a586d2a56ffed11f37.tar.xz
dexon-solidity-1690f1c947b1b1bfaf84d0a586d2a56ffed11f37.tar.zst
dexon-solidity-1690f1c947b1b1bfaf84d0a586d2a56ffed11f37.zip
Add CMakeLists.txt for libsolidity
Diffstat (limited to 'src/CompilerUtils.cpp')
-rw-r--r--src/CompilerUtils.cpp734
1 files changed, 0 insertions, 734 deletions
diff --git a/src/CompilerUtils.cpp b/src/CompilerUtils.cpp
deleted file mode 100644
index 49247581..00000000
--- a/src/CompilerUtils.cpp
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- This file is part of cpp-ethereum.
-
- cpp-ethereum is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- cpp-ethereum is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2014
- * Routines used by both the compiler and the expression compiler.
- */
-
-#include <libsolidity/CompilerUtils.h>
-#include <libsolidity/AST.h>
-#include <libevmcore/Instruction.h>
-#include <libevmcore/Params.h>
-#include <libsolidity/ArrayUtils.h>
-#include <libsolidity/LValue.h>
-
-using namespace std;
-
-namespace dev
-{
-namespace solidity
-{
-
-const unsigned CompilerUtils::dataStartOffset = 4;
-const size_t CompilerUtils::freeMemoryPointer = 64;
-const unsigned CompilerUtils::identityContractAddress = 4;
-
-void CompilerUtils::initialiseFreeMemoryPointer()
-{
- m_context << u256(freeMemoryPointer + 32);
- storeFreeMemoryPointer();
-}
-
-void CompilerUtils::fetchFreeMemoryPointer()
-{
- m_context << u256(freeMemoryPointer) << eth::Instruction::MLOAD;
-}
-
-void CompilerUtils::storeFreeMemoryPointer()
-{
- m_context << u256(freeMemoryPointer) << eth::Instruction::MSTORE;
-}
-
-void CompilerUtils::allocateMemory()
-{
- fetchFreeMemoryPointer();
- m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD;
- storeFreeMemoryPointer();
-}
-
-void CompilerUtils::toSizeAfterFreeMemoryPointer()
-{
- fetchFreeMemoryPointer();
- m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::SUB;
- m_context << eth::Instruction::SWAP1;
-}
-
-unsigned CompilerUtils::loadFromMemory(
- unsigned _offset,
- Type const& _type,
- bool _fromCalldata,
- bool _padToWordBoundaries
-)
-{
- solAssert(_type.getCategory() != Type::Category::Array, "Unable to statically load dynamic type.");
- m_context << u256(_offset);
- return loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries);
-}
-
-void CompilerUtils::loadFromMemoryDynamic(
- Type const& _type,
- bool _fromCalldata,
- bool _padToWordBoundaries,
- bool _keepUpdatedMemoryOffset
-)
-{
- solAssert(_type.getCategory() != Type::Category::Array, "Arrays not yet implemented.");
- if (_keepUpdatedMemoryOffset)
- m_context << eth::Instruction::DUP1;
- unsigned numBytes = loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries);
- if (_keepUpdatedMemoryOffset)
- {
- // update memory counter
- moveToStackTop(_type.getSizeOnStack());
- m_context << u256(numBytes) << eth::Instruction::ADD;
- }
-}
-
-void CompilerUtils::storeInMemory(unsigned _offset)
-{
- unsigned numBytes = prepareMemoryStore(IntegerType(256), true);
- if (numBytes > 0)
- m_context << u256(_offset) << eth::Instruction::MSTORE;
-}
-
-void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries)
-{
- if (auto ref = dynamic_cast<ReferenceType const*>(&_type))
- {
- solAssert(ref->location() == DataLocation::Memory, "");
- storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
- }
- else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
- {
- m_context << eth::Instruction::DUP1;
- storeStringData(bytesConstRef(str->value()));
- if (_padToWordBoundaries)
- m_context << u256(((str->value().size() + 31) / 32) * 32);
- else
- m_context << u256(str->value().size());
- m_context << eth::Instruction::ADD;
- }
- else
- {
- unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
- if (numBytes > 0)
- {
- solAssert(
- _type.getSizeOnStack() == 1,
- "Memory store of types with stack size != 1 not implemented."
- );
- m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE;
- m_context << u256(numBytes) << eth::Instruction::ADD;
- }
- }
-}
-
-void CompilerUtils::encodeToMemory(
- TypePointers const& _givenTypes,
- TypePointers const& _targetTypes,
- bool _padToWordBoundaries,
- bool _copyDynamicDataInPlace
-)
-{
- // stack: <v1> <v2> ... <vn> <mem>
- TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
- solAssert(targetTypes.size() == _givenTypes.size(), "");
- for (TypePointer& t: targetTypes)
- t = t->mobileType()->externalType();
-
- // Stack during operation:
- // <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
- // The values dyn_head_i are added during the first loop and they point to the head part
- // of the ith dynamic parameter, which is filled once the dynamic parts are processed.
-
- // store memory start pointer
- m_context << eth::Instruction::DUP1;
-
- unsigned argSize = CompilerUtils::getSizeOnStack(_givenTypes);
- unsigned stackPos = 0; // advances through the argument values
- unsigned dynPointers = 0; // number of dynamic head pointers on the stack
- for (size_t i = 0; i < _givenTypes.size(); ++i)
- {
- TypePointer targetType = targetTypes[i];
- solAssert(!!targetType, "Externalable type expected.");
- if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
- {
- // leave end_of_mem as dyn head pointer
- m_context << eth::Instruction::DUP1 << u256(32) << eth::Instruction::ADD;
- dynPointers++;
- }
- else
- {
- copyToStackTop(argSize - stackPos + dynPointers + 2, _givenTypes[i]->getSizeOnStack());
- solAssert(!!targetType, "Externalable type expected.");
- TypePointer type = targetType;
- if (
- _givenTypes[i]->dataStoredIn(DataLocation::Storage) ||
- _givenTypes[i]->dataStoredIn(DataLocation::CallData) ||
- _givenTypes[i]->getCategory() == Type::Category::StringLiteral
- )
- type = _givenTypes[i]; // delay conversion
- else
- convertType(*_givenTypes[i], *targetType, true);
- if (auto arrayType = dynamic_cast<ArrayType const*>(type.get()))
- ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
- else
- storeInMemoryDynamic(*type, _padToWordBoundaries);
- }
- stackPos += _givenTypes[i]->getSizeOnStack();
- }
-
- // now copy the dynamic part
- // Stack: <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
- stackPos = 0;
- unsigned thisDynPointer = 0;
- for (size_t i = 0; i < _givenTypes.size(); ++i)
- {
- TypePointer targetType = targetTypes[i];
- solAssert(!!targetType, "Externalable type expected.");
- if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
- {
- // copy tail pointer (=mem_end - mem_start) to memory
- m_context << eth::dupInstruction(2 + dynPointers) << eth::Instruction::DUP2;
- m_context << eth::Instruction::SUB;
- m_context << eth::dupInstruction(2 + dynPointers - thisDynPointer);
- m_context << eth::Instruction::MSTORE;
- // stack: ... <end_of_mem>
- if (_givenTypes[i]->getCategory() == Type::Category::StringLiteral)
- {
- auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
- m_context << u256(strType.value().size());
- storeInMemoryDynamic(IntegerType(256), true);
- // stack: ... <end_of_mem'>
- storeInMemoryDynamic(strType, _padToWordBoundaries);
- }
- else
- {
- solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type.");
- auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]);
- // now copy the array
- copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.getSizeOnStack());
- // stack: ... <end_of_mem> <value...>
- // copy length to memory
- m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack());
- if (arrayType.location() == DataLocation::CallData)
- m_context << eth::Instruction::DUP2; // length is on stack
- else if (arrayType.location() == DataLocation::Storage)
- m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD;
- else
- {
- solAssert(arrayType.location() == DataLocation::Memory, "");
- m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD;
- }
- // stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
- storeInMemoryDynamic(IntegerType(256), true);
- // stack: ... <end_of_mem> <value...> <end_of_mem''>
- // copy the new memory pointer
- m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP;
- // stack: ... <end_of_mem''> <value...>
- // copy data part
- ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries);
- // stack: ... <end_of_mem'''>
- }
-
- thisDynPointer++;
- }
- stackPos += _givenTypes[i]->getSizeOnStack();
- }
-
- // remove unneeded stack elements (and retain memory pointer)
- m_context << eth::swapInstruction(argSize + dynPointers + 1);
- popStackSlots(argSize + dynPointers + 1);
-}
-
-void CompilerUtils::memoryCopy()
-{
- // Stack here: size target source
- // stack for call: outsize target size source value contract gas
- //@TODO do not use ::CALL if less than 32 bytes?
- m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1;
- m_context << u256(0) << u256(identityContractAddress);
- // compute gas costs
- m_context << u256(32) << eth::Instruction::DUP5 << u256(31) << eth::Instruction::ADD;
- m_context << eth::Instruction::DIV << u256(eth::c_identityWordGas) << eth::Instruction::MUL;
- m_context << u256(eth::c_identityGas) << eth::Instruction::ADD;
- m_context << eth::Instruction::CALL;
- m_context << eth::Instruction::POP; // ignore return value
-}
-
-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
- // previous operations.
- // @todo: store in the AST whether the operand might have "dirty" higher order bits
-
- if (_typeOnStack == _targetType && !_cleanupNeeded)
- return;
- Type::Category stackTypeCategory = _typeOnStack.getCategory();
- Type::Category targetTypeCategory = _targetType.getCategory();
-
- switch (stackTypeCategory)
- {
- case Type::Category::FixedBytes:
- {
- FixedBytesType const& typeOnStack = dynamic_cast<FixedBytesType const&>(_typeOnStack);
- if (targetTypeCategory == Type::Category::Integer)
- {
- // conversion from bytes to integer. no need to clean the high bit
- // only to shift right because of opposite alignment
- IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
- m_context << (u256(1) << (256 - typeOnStack.numBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
- if (targetIntegerType.getNumBits() < typeOnStack.numBytes() * 8)
- convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
- }
- else
- {
- // clear lower-order bytes for conversion to shorter bytes - we always clean
- solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
- FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
- if (targetType.numBytes() < typeOnStack.numBytes())
- {
- if (targetType.numBytes() == 0)
- m_context << eth::Instruction::DUP1 << eth::Instruction::XOR;
- else
- {
- m_context << (u256(1) << (256 - targetType.numBytes() * 8));
- m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2;
- m_context << eth::Instruction::DIV << eth::Instruction::MUL;
- }
- }
- }
- }
- break;
- case Type::Category::Enum:
- solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Enum, "");
- break;
- case Type::Category::Integer:
- case Type::Category::Contract:
- case Type::Category::IntegerConstant:
- if (targetTypeCategory == Type::Category::FixedBytes)
- {
- solAssert(stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::IntegerConstant,
- "Invalid conversion to FixedBytesType requested.");
- // conversion from bytes to string. no need to clean the high bit
- // only to shift left because of opposite alignment
- FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
- if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
- if (targetBytesType.numBytes() * 8 > typeOnStack->getNumBits())
- cleanHigherOrderBits(*typeOnStack);
- m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << eth::Instruction::MUL;
- }
- else if (targetTypeCategory == Type::Category::Enum)
- // just clean
- convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
- else
- {
- solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, "");
- IntegerType addressType(0, IntegerType::Modifier::Address);
- IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
- ? dynamic_cast<IntegerType const&>(_targetType) : addressType;
- if (stackTypeCategory == Type::Category::IntegerConstant)
- {
- IntegerConstantType const& constType = dynamic_cast<IntegerConstantType const&>(_typeOnStack);
- // We know that the stack is clean, we only have to clean for a narrowing conversion
- // where cleanup is forced.
- if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded)
- cleanHigherOrderBits(targetType);
- }
- else
- {
- IntegerType const& typeOnStack = stackTypeCategory == Type::Category::Integer
- ? dynamic_cast<IntegerType const&>(_typeOnStack) : addressType;
- // Widening: clean up according to source type width
- // Non-widening and force: clean up according to target type bits
- if (targetType.getNumBits() > typeOnStack.getNumBits())
- cleanHigherOrderBits(typeOnStack);
- else if (_cleanupNeeded)
- cleanHigherOrderBits(targetType);
- }
- }
- break;
- case Type::Category::StringLiteral:
- {
- auto const& literalType = dynamic_cast<StringLiteralType const&>(_typeOnStack);
- string const& value = literalType.value();
- bytesConstRef data(value);
- if (targetTypeCategory == Type::Category::FixedBytes)
- {
- solAssert(data.size() <= 32, "");
- m_context << h256::Arith(h256(data, h256::AlignLeft));
- }
- else if (targetTypeCategory == Type::Category::Array)
- {
- auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
- solAssert(arrayType.isByteArray(), "");
- u256 storageSize(32 + ((data.size() + 31) / 32) * 32);
- m_context << storageSize;
- allocateMemory();
- // stack: mempos
- m_context << eth::Instruction::DUP1 << u256(data.size());
- storeInMemoryDynamic(IntegerType(256));
- // stack: mempos datapos
- storeStringData(data);
- break;
- }
- else
- solAssert(
- false,
- "Invalid conversion from string literal to " + _targetType.toString(false) + " requested."
- );
- break;
- }
- case Type::Category::Array:
- {
- solAssert(targetTypeCategory == stackTypeCategory, "");
- ArrayType const& typeOnStack = dynamic_cast<ArrayType const&>(_typeOnStack);
- ArrayType const& targetType = dynamic_cast<ArrayType const&>(_targetType);
- switch (targetType.location())
- {
- case DataLocation::Storage:
- // Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
- solAssert(
- (targetType.isPointer() || (typeOnStack.isByteArray() && targetType.isByteArray())) &&
- typeOnStack.location() == DataLocation::Storage,
- "Invalid conversion to storage type."
- );
- break;
- case DataLocation::Memory:
- {
- // Copy the array to a free position in memory, unless it is already in memory.
- if (typeOnStack.location() != DataLocation::Memory)
- {
- // stack: <source ref> (variably sized)
- unsigned stackSize = typeOnStack.getSizeOnStack();
- ArrayUtils(m_context).retrieveLength(typeOnStack);
-
- // allocate memory
- // stack: <source ref> (variably sized) <length>
- m_context << eth::Instruction::DUP1;
- ArrayUtils(m_context).convertLengthToSize(targetType, true);
- // stack: <source ref> (variably sized) <length> <size>
- if (targetType.isDynamicallySized())
- m_context << u256(0x20) << eth::Instruction::ADD;
- allocateMemory();
- // stack: <source ref> (variably sized) <length> <mem start>
- m_context << eth::Instruction::DUP1;
- moveIntoStack(2 + stackSize);
- if (targetType.isDynamicallySized())
- {
- m_context << eth::Instruction::DUP2;
- storeInMemoryDynamic(IntegerType(256));
- }
- // stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
- if (targetType.getBaseType()->isValueType())
- {
- solAssert(typeOnStack.getBaseType()->isValueType(), "");
- copyToStackTop(2 + stackSize, stackSize);
- ArrayUtils(m_context).copyArrayToMemory(typeOnStack);
- }
- else
- {
- m_context << u256(0) << eth::Instruction::SWAP1;
- // stack: <mem start> <source ref> (variably sized) <length> <counter> <mem data pos>
- auto repeat = m_context.newTag();
- m_context << repeat;
- m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3;
- m_context << eth::Instruction::LT << eth::Instruction::ISZERO;
- auto loopEnd = m_context.appendConditionalJump();
- copyToStackTop(3 + stackSize, stackSize);
- copyToStackTop(2 + stackSize, 1);
- ArrayUtils(m_context).accessIndex(typeOnStack, false);
- if (typeOnStack.location() == DataLocation::Storage)
- StorageItem(m_context, *typeOnStack.getBaseType()).retrieveValue(SourceLocation(), true);
- convertType(*typeOnStack.getBaseType(), *targetType.getBaseType(), _cleanupNeeded);
- storeInMemoryDynamic(*targetType.getBaseType(), true);
- m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD;
- m_context << eth::Instruction::SWAP1;
- m_context.appendJumpTo(repeat);
- m_context << loopEnd;
- m_context << eth::Instruction::POP;
- }
- // stack: <mem start> <source ref> (variably sized) <length> <mem data pos updated>
- popStackSlots(2 + stackSize);
- // Stack: <mem start>
- }
- break;
- }
- case DataLocation::CallData:
- solAssert(
- targetType.isByteArray() &&
- typeOnStack.isByteArray() &&
- typeOnStack.location() == DataLocation::CallData,
- "Invalid conversion to calldata type.");
- break;
- default:
- solAssert(
- false,
- "Invalid type conversion " +
- _typeOnStack.toString(false) +
- " to " +
- _targetType.toString(false) +
- " requested."
- );
- }
- break;
- }
- case Type::Category::Struct:
- {
- solAssert(targetTypeCategory == stackTypeCategory, "");
- auto& targetType = dynamic_cast<StructType const&>(_targetType);
- auto& typeOnStack = dynamic_cast<StructType const&>(_typeOnStack);
- solAssert(
- targetType.location() != DataLocation::CallData &&
- typeOnStack.location() != DataLocation::CallData
- , "");
- switch (targetType.location())
- {
- case DataLocation::Storage:
- // Other cases are done explicitly in LValue::storeValue, and only possible by assignment.
- solAssert(
- targetType.isPointer() &&
- typeOnStack.location() == DataLocation::Storage,
- "Invalid conversion to storage type."
- );
- break;
- case DataLocation::Memory:
- // Copy the array to a free position in memory, unless it is already in memory.
- if (typeOnStack.location() != DataLocation::Memory)
- {
- solAssert(typeOnStack.location() == DataLocation::Storage, "");
- // stack: <source ref>
- m_context << typeOnStack.memorySize();
- allocateMemory();
- m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
- // stack: <memory ptr> <source ref> <memory ptr>
- for (auto const& member: typeOnStack.getMembers())
- {
- if (!member.type->canLiveOutsideStorage())
- continue;
- pair<u256, unsigned> const& offsets = typeOnStack.getStorageOffsetsOfMember(member.name);
- m_context << offsets.first << eth::Instruction::DUP3 << eth::Instruction::ADD;
- m_context << u256(offsets.second);
- StorageItem(m_context, *member.type).retrieveValue(SourceLocation(), true);
- TypePointer targetMemberType = targetType.getMemberType(member.name);
- solAssert(!!targetMemberType, "Member not found in target type.");
- convertType(*member.type, *targetMemberType, true);
- storeInMemoryDynamic(*targetMemberType, true);
- }
- m_context << eth::Instruction::POP << eth::Instruction::POP;
- }
- break;
- case DataLocation::CallData:
- solAssert(false, "Invalid type conversion target location CallData.");
- break;
- }
- break;
- }
- default:
- // All other types should not be convertible to non-equal types.
- solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");
- break;
- }
-}
-
-void CompilerUtils::pushZeroValue(const Type& _type)
-{
- auto const* referenceType = dynamic_cast<ReferenceType const*>(&_type);
- if (!referenceType || referenceType->location() == DataLocation::Storage)
- {
- for (size_t i = 0; i < _type.getSizeOnStack(); ++i)
- m_context << u256(0);
- return;
- }
- solAssert(referenceType->location() == DataLocation::Memory, "");
-
- m_context << u256(max(32u, _type.getCalldataEncodedSize()));
- allocateMemory();
- m_context << eth::Instruction::DUP1;
-
- if (auto structType = dynamic_cast<StructType const*>(&_type))
- for (auto const& member: structType->getMembers())
- {
- pushZeroValue(*member.type);
- storeInMemoryDynamic(*member.type);
- }
- else if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
- {
- if (arrayType->isDynamicallySized())
- {
- // zero length
- m_context << u256(0);
- storeInMemoryDynamic(IntegerType(256));
- }
- else if (arrayType->getLength() > 0)
- {
- m_context << arrayType->getLength() << eth::Instruction::SWAP1;
- // stack: items_to_do memory_pos
- auto repeat = m_context.newTag();
- m_context << repeat;
- pushZeroValue(*arrayType->getBaseType());
- storeInMemoryDynamic(*arrayType->getBaseType());
- m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1;
- m_context << eth::Instruction::SUB << eth::Instruction::SWAP1;
- m_context << eth::Instruction::DUP2;
- m_context.appendConditionalJumpTo(repeat);
- m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
- }
- }
- else
- solAssert(false, "Requested initialisation for unknown type: " + _type.toString());
-
- // remove the updated memory pointer
- m_context << eth::Instruction::POP;
-}
-
-void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
-{
- unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable));
- unsigned const size = _variable.getType()->getSizeOnStack();
- solAssert(stackPosition >= size, "Variable size and position mismatch.");
- // move variable starting from its top end in the stack
- if (stackPosition - size + 1 > 16)
- BOOST_THROW_EXCEPTION(
- CompilerError() <<
- errinfo_sourceLocation(_variable.getLocation()) <<
- errinfo_comment("Stack too deep, try removing local variables.")
- );
- for (unsigned i = 0; i < size; ++i)
- m_context << eth::swapInstruction(stackPosition - size + 1) << eth::Instruction::POP;
-}
-
-void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
-{
- solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables.");
- for (unsigned i = 0; i < _itemSize; ++i)
- m_context << eth::dupInstruction(_stackDepth);
-}
-
-void CompilerUtils::moveToStackTop(unsigned _stackDepth)
-{
- solAssert(_stackDepth <= 15, "Stack too deep, try removing local variables.");
- for (unsigned i = 0; i < _stackDepth; ++i)
- m_context << eth::swapInstruction(1 + i);
-}
-
-void CompilerUtils::moveIntoStack(unsigned _stackDepth)
-{
- solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables.");
- for (unsigned i = _stackDepth; i > 0; --i)
- m_context << eth::swapInstruction(i);
-}
-
-void CompilerUtils::popStackElement(Type const& _type)
-{
- popStackSlots(_type.getSizeOnStack());
-}
-
-void CompilerUtils::popStackSlots(size_t _amount)
-{
- for (size_t i = 0; i < _amount; ++i)
- m_context << eth::Instruction::POP;
-}
-
-unsigned CompilerUtils::getSizeOnStack(vector<shared_ptr<Type const>> const& _variableTypes)
-{
- unsigned size = 0;
- for (shared_ptr<Type const> const& type: _variableTypes)
- size += type->getSizeOnStack();
- return size;
-}
-
-void CompilerUtils::computeHashStatic()
-{
- storeInMemory(0);
- m_context << u256(32) << u256(0) << eth::Instruction::SHA3;
-}
-
-void CompilerUtils::storeStringData(bytesConstRef _data)
-{
- //@todo provide both alternatives to the optimiser
- // stack: mempos
- if (_data.size() <= 128)
- {
- for (unsigned i = 0; i < _data.size(); i += 32)
- {
- m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
- storeInMemoryDynamic(IntegerType(256));
- }
- m_context << eth::Instruction::POP;
- }
- else
- {
- // stack: mempos mempos_data
- m_context.appendData(_data.toBytes());
- m_context << u256(_data.size()) << eth::Instruction::SWAP2;
- m_context << eth::Instruction::CODECOPY;
- }
-}
-
-unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
-{
- unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
- bool leftAligned = _type.getCategory() == Type::Category::FixedBytes;
- if (numBytes == 0)
- m_context << eth::Instruction::POP << u256(0);
- else
- {
- solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
- m_context << (_fromCalldata ? eth::Instruction::CALLDATALOAD : eth::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 << eth::Instruction::SWAP1 << eth::Instruction::DIV;
- if (leftAligned)
- m_context << shiftFactor << eth::Instruction::MUL;
- }
- }
-
- return numBytes;
-}
-
-void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack)
-{
- if (_typeOnStack.getNumBits() == 256)
- return;
- else if (_typeOnStack.isSigned())
- m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND;
- else
- m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
-}
-
-unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
-{
- unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
- bool leftAligned = _type.getCategory() == Type::Category::FixedBytes;
- if (numBytes == 0)
- m_context << eth::Instruction::POP;
- else
- {
- solAssert(numBytes <= 32, "Memory store of more than 32 bytes requested.");
- if (numBytes != 32 && !leftAligned && !_padToWordBoundaries)
- // shift the value accordingly before storing
- m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
- }
- return numBytes;
-}
-
-}
-}