diff options
author | chriseth <c@ethdev.com> | 2015-07-08 07:13:56 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-07-09 23:10:58 +0800 |
commit | 46dde467e777c8339a5b58e877bd886bab9a15b9 (patch) | |
tree | 984cf47267a295f22cd349ab52a0c42bc4d8ca34 /CompilerUtils.cpp | |
parent | aa6182ab87989ed50df2ec779237a2b708ccfd12 (diff) | |
download | dexon-solidity-46dde467e777c8339a5b58e877bd886bab9a15b9.tar dexon-solidity-46dde467e777c8339a5b58e877bd886bab9a15b9.tar.gz dexon-solidity-46dde467e777c8339a5b58e877bd886bab9a15b9.tar.bz2 dexon-solidity-46dde467e777c8339a5b58e877bd886bab9a15b9.tar.lz dexon-solidity-46dde467e777c8339a5b58e877bd886bab9a15b9.tar.xz dexon-solidity-46dde467e777c8339a5b58e877bd886bab9a15b9.tar.zst dexon-solidity-46dde467e777c8339a5b58e877bd886bab9a15b9.zip |
Flexible string literals, convertible to bytesX, bytes and string.
Diffstat (limited to 'CompilerUtils.cpp')
-rw-r--r-- | CompilerUtils.cpp | 138 |
1 files changed, 107 insertions, 31 deletions
diff --git a/CompilerUtils.cpp b/CompilerUtils.cpp index ed6a6cf7..297e6aa0 100644 --- a/CompilerUtils.cpp +++ b/CompilerUtils.cpp @@ -113,6 +113,16 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound 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); @@ -169,7 +179,8 @@ void CompilerUtils::encodeToMemory( TypePointer type = targetType; if ( _givenTypes[i]->dataStoredIn(DataLocation::Storage) || - _givenTypes[i]->dataStoredIn(DataLocation::CallData) + _givenTypes[i]->dataStoredIn(DataLocation::CallData) || + _givenTypes[i]->getCategory() == Type::Category::StringLiteral ) type = _givenTypes[i]; // delay conversion else @@ -192,36 +203,48 @@ void CompilerUtils::encodeToMemory( solAssert(!!targetType, "Externalable type expected."); if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace) { - solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type."); - auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]); // 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; - // 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::DUP3 << eth::Instruction::SLOAD; + // 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(arrayType.location() == DataLocation::Memory, ""); - m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD; + 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::DUP3 << 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'''> } - // 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++; } @@ -269,22 +292,22 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp // 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.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV; - if (targetIntegerType.getNumBits() < typeOnStack.getNumBytes() * 8) - convertType(IntegerType(typeOnStack.getNumBytes() * 8), _targetType, _cleanupNeeded); + 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.getNumBytes() < typeOnStack.getNumBytes()) + if (targetType.numBytes() < typeOnStack.numBytes()) { - if (targetType.getNumBytes() == 0) + if (targetType.numBytes() == 0) m_context << eth::Instruction::DUP1 << eth::Instruction::XOR; else { - m_context << (u256(1) << (256 - targetType.getNumBytes() * 8)); + m_context << (u256(1) << (256 - targetType.numBytes() * 8)); m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2; m_context << eth::Instruction::DIV << eth::Instruction::MUL; } @@ -306,9 +329,9 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp // 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.getNumBytes() * 8 > typeOnStack->getNumBits()) + if (targetBytesType.numBytes() * 8 > typeOnStack->getNumBits()) cleanHigherOrderBits(*typeOnStack); - m_context << (u256(1) << (256 - targetBytesType.getNumBytes() * 8)) << eth::Instruction::MUL; + m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << eth::Instruction::MUL; } else if (targetTypeCategory == Type::Category::Enum) // just clean @@ -340,6 +363,37 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp } } 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, ""); @@ -606,6 +660,28 @@ void CompilerUtils::computeHashStatic() 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); |