reduce unnecessary solidity:: namespace

This commit is contained in:
Dimitry 2016-04-04 15:41:35 +04:00
parent d43d4347bf
commit d2cee6f9c6
14 changed files with 658 additions and 658 deletions

View File

@ -106,7 +106,7 @@ BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++()
{ {
if (it == end) if (it == end)
return *this; return *this;
if (SemanticInformation::altersControlFlow(*it) && *it != AssemblyItem(solidity::Instruction::JUMPI)) if (SemanticInformation::altersControlFlow(*it) && *it != AssemblyItem(Instruction::JUMPI))
it = end; it = end;
else else
{ {

View File

@ -84,13 +84,13 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
break; break;
case Instruction::MLOAD: case Instruction::MLOAD:
case Instruction::MSTORE: case Instruction::MSTORE:
gas += memoryGas(classes.find(solidity::Instruction::ADD, { gas += memoryGas(classes.find(Instruction::ADD, {
m_state->relativeStackElement(0), m_state->relativeStackElement(0),
classes.find(AssemblyItem(32)) classes.find(AssemblyItem(32))
})); }));
break; break;
case Instruction::MSTORE8: case Instruction::MSTORE8:
gas += memoryGas(classes.find(solidity::Instruction::ADD, { gas += memoryGas(classes.find(Instruction::ADD, {
m_state->relativeStackElement(0), m_state->relativeStackElement(0),
classes.find(AssemblyItem(1)) classes.find(AssemblyItem(1))
})); }));
@ -198,7 +198,7 @@ GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosS
if (classes.knownZero(m_state->relativeStackElement(_stackPosSize))) if (classes.knownZero(m_state->relativeStackElement(_stackPosSize)))
return GasConsumption(0); return GasConsumption(0);
else else
return memoryGas(classes.find(solidity::Instruction::ADD, { return memoryGas(classes.find(Instruction::ADD, {
m_state->relativeStackElement(_stackPosOffset), m_state->relativeStackElement(_stackPosOffset),
m_state->relativeStackElement(_stackPosSize) m_state->relativeStackElement(_stackPosSize)
})); }));

View File

@ -76,7 +76,7 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem()
bool branchStops = false; bool branchStops = false;
jumpTags.clear(); jumpTags.clear();
AssemblyItem const& item = m_items.at(index); AssemblyItem const& item = m_items.at(index);
if (item.type() == Tag || item == AssemblyItem(solidity::Instruction::JUMPDEST)) if (item.type() == Tag || item == AssemblyItem(Instruction::JUMPDEST))
{ {
// Do not allow any backwards jump. This is quite restrictive but should work for // Do not allow any backwards jump. This is quite restrictive but should work for
// the simplest things. // the simplest things.
@ -84,14 +84,14 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem()
return GasMeter::GasConsumption::infinite(); return GasMeter::GasConsumption::infinite();
path->visitedJumpdests.insert(index); path->visitedJumpdests.insert(index);
} }
else if (item == AssemblyItem(solidity::Instruction::JUMP)) else if (item == AssemblyItem(Instruction::JUMP))
{ {
branchStops = true; branchStops = true;
jumpTags = state->tagsInExpression(state->relativeStackElement(0)); jumpTags = state->tagsInExpression(state->relativeStackElement(0));
if (jumpTags.empty()) // unknown jump destination if (jumpTags.empty()) // unknown jump destination
return GasMeter::GasConsumption::infinite(); return GasMeter::GasConsumption::infinite();
} }
else if (item == AssemblyItem(solidity::Instruction::JUMPI)) else if (item == AssemblyItem(Instruction::JUMPI))
{ {
ExpressionClasses::Id condition = state->relativeStackElement(-1); ExpressionClasses::Id condition = state->relativeStackElement(-1);
if (classes.knownNonZero(condition) || !classes.knownZero(condition)) if (classes.knownNonZero(condition) || !classes.knownZero(condition))

View File

@ -147,7 +147,7 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
} }
} }
bool SemanticInformation::invalidatesMemory(solidity::Instruction _instruction) bool SemanticInformation::invalidatesMemory(Instruction _instruction)
{ {
switch (_instruction) switch (_instruction)
{ {

View File

@ -595,7 +595,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (!varDecl->isLocalVariable()) if (!varDecl->isLocalVariable())
return false; // only local variables are inline-assemlby lvalues return false; // only local variables are inline-assemlby lvalues
for (unsigned i = 0; i < declaration->type()->sizeOnStack(); ++i) for (unsigned i = 0; i < declaration->type()->sizeOnStack(); ++i)
_assembly.append(solidity::Instruction::POP); // remove value just to verify the stack height _assembly.append(Instruction::POP); // remove value just to verify the stack height
} }
else else
return false; return false;

View File

@ -56,7 +56,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// stack: source_ref [source_length] target_ref // stack: source_ref [source_length] target_ref
// store target_ref // store target_ref
for (unsigned i = _sourceType.sizeOnStack(); i > 0; --i) for (unsigned i = _sourceType.sizeOnStack(); i > 0; --i)
m_context << solidity::swapInstruction(i); m_context << swapInstruction(i);
// stack: target_ref source_ref [source_length] // stack: target_ref source_ref [source_length]
// stack: target_ref source_ref [source_length] // stack: target_ref source_ref [source_length]
// retrieve source length // retrieve source length
@ -65,12 +65,12 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
if (_sourceType.location() == DataLocation::Memory && _sourceType.isDynamicallySized()) if (_sourceType.location() == DataLocation::Memory && _sourceType.isDynamicallySized())
{ {
// increment source pointer to point to data // increment source pointer to point to data
m_context << solidity::Instruction::SWAP1 << u256(0x20); m_context << Instruction::SWAP1 << u256(0x20);
m_context << solidity::Instruction::ADD << Instruction::SWAP1; m_context << Instruction::ADD << Instruction::SWAP1;
} }
// stack: target_ref source_ref source_length // stack: target_ref source_ref source_length
m_context << solidity::Instruction::DUP3; m_context << Instruction::DUP3;
// stack: target_ref source_ref source_length target_ref // stack: target_ref source_ref source_length target_ref
retrieveLength(_targetType); retrieveLength(_targetType);
// stack: target_ref source_ref source_length target_ref target_length // stack: target_ref source_ref source_length target_ref target_length
@ -78,28 +78,28 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// store new target length // store new target length
if (!_targetType.isByteArray()) if (!_targetType.isByteArray())
// Otherwise, length will be stored below. // Otherwise, length will be stored below.
m_context << solidity::Instruction::DUP3 << solidity::Instruction::DUP3 << solidity::Instruction::SSTORE; m_context << Instruction::DUP3 << Instruction::DUP3 << Instruction::SSTORE;
if (sourceBaseType->category() == Type::Category::Mapping) if (sourceBaseType->category() == Type::Category::Mapping)
{ {
solAssert(targetBaseType->category() == Type::Category::Mapping, ""); solAssert(targetBaseType->category() == Type::Category::Mapping, "");
solAssert(_sourceType.location() == DataLocation::Storage, ""); solAssert(_sourceType.location() == DataLocation::Storage, "");
// nothing to copy // nothing to copy
m_context m_context
<< solidity::Instruction::POP << solidity::Instruction::POP << Instruction::POP << Instruction::POP
<< solidity::Instruction::POP << solidity::Instruction::POP; << Instruction::POP << Instruction::POP;
return; return;
} }
// stack: target_ref source_ref source_length target_ref target_length // stack: target_ref source_ref source_length target_ref target_length
// compute hashes (data positions) // compute hashes (data positions)
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
if (_targetType.isDynamicallySized()) if (_targetType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
// stack: target_ref source_ref source_length target_length target_data_pos // stack: target_ref source_ref source_length target_length target_data_pos
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
convertLengthToSize(_targetType); convertLengthToSize(_targetType);
m_context << solidity::Instruction::DUP2 << solidity::Instruction::ADD; m_context << Instruction::DUP2 << Instruction::ADD;
// stack: target_ref source_ref source_length target_data_pos target_data_end // stack: target_ref source_ref source_length target_data_pos target_data_end
m_context << solidity::Instruction::SWAP3; m_context << Instruction::SWAP3;
// stack: target_ref target_data_end source_length target_data_pos source_ref // stack: target_ref target_data_end source_length target_data_pos source_ref
eth::AssemblyItem copyLoopEndWithoutByteOffset = m_context.newTag(); eth::AssemblyItem copyLoopEndWithoutByteOffset = m_context.newTag();
@ -108,47 +108,47 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
if (_targetType.isByteArray()) if (_targetType.isByteArray())
{ {
// stack: target_ref target_data_end source_length target_data_pos source_ref // stack: target_ref target_data_end source_length target_data_pos source_ref
m_context << solidity::Instruction::DUP3 << u256(31) << solidity::Instruction::LT; m_context << Instruction::DUP3 << u256(31) << Instruction::LT;
eth::AssemblyItem longByteArray = m_context.appendConditionalJump(); eth::AssemblyItem longByteArray = m_context.appendConditionalJump();
// store the short byte array // store the short byte array
solAssert(_sourceType.isByteArray(), ""); solAssert(_sourceType.isByteArray(), "");
if (_sourceType.location() == DataLocation::Storage) if (_sourceType.location() == DataLocation::Storage)
{ {
// just copy the slot, it contains length and data // just copy the slot, it contains length and data
m_context << solidity::Instruction::DUP1 << solidity::Instruction::SLOAD; m_context << Instruction::DUP1 << Instruction::SLOAD;
m_context << solidity::Instruction::DUP6 << solidity::Instruction::SSTORE; m_context << Instruction::DUP6 << Instruction::SSTORE;
} }
else else
{ {
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, fromCalldata, true, false); CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, fromCalldata, true, false);
// stack: target_ref target_data_end source_length target_data_pos source_ref value // stack: target_ref target_data_end source_length target_data_pos source_ref value
// clear the lower-order byte - which will hold the length // clear the lower-order byte - which will hold the length
m_context << u256(0xff) << solidity::Instruction::NOT << solidity::Instruction::AND; m_context << u256(0xff) << Instruction::NOT << Instruction::AND;
// fetch the length and shift it left by one // fetch the length and shift it left by one
m_context << solidity::Instruction::DUP4 << solidity::Instruction::DUP1 << solidity::Instruction::ADD; m_context << Instruction::DUP4 << Instruction::DUP1 << Instruction::ADD;
// combine value and length and store them // combine value and length and store them
m_context << solidity::Instruction::OR << solidity::Instruction::DUP6 << solidity::Instruction::SSTORE; m_context << Instruction::OR << Instruction::DUP6 << Instruction::SSTORE;
} }
// end of special case, jump right into cleaning target data area // end of special case, jump right into cleaning target data area
m_context.appendJumpTo(copyLoopEndWithoutByteOffset); m_context.appendJumpTo(copyLoopEndWithoutByteOffset);
m_context << longByteArray; m_context << longByteArray;
// Store length (2*length+1) // Store length (2*length+1)
m_context << solidity::Instruction::DUP3 << solidity::Instruction::DUP1 << solidity::Instruction::ADD; m_context << Instruction::DUP3 << Instruction::DUP1 << Instruction::ADD;
m_context << u256(1) << solidity::Instruction::ADD; m_context << u256(1) << Instruction::ADD;
m_context << solidity::Instruction::DUP6 << solidity::Instruction::SSTORE; m_context << Instruction::DUP6 << Instruction::SSTORE;
} }
// skip copying if source length is zero // skip copying if source length is zero
m_context << solidity::Instruction::DUP3 << solidity::Instruction::ISZERO; m_context << Instruction::DUP3 << Instruction::ISZERO;
m_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset); m_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset);
if (_sourceType.location() == DataLocation::Storage && _sourceType.isDynamicallySized()) if (_sourceType.location() == DataLocation::Storage && _sourceType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
// stack: target_ref target_data_end source_length target_data_pos source_data_pos // stack: target_ref target_data_end source_length target_data_pos source_data_pos
m_context << solidity::Instruction::SWAP2; m_context << Instruction::SWAP2;
convertLengthToSize(_sourceType); convertLengthToSize(_sourceType);
m_context << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << Instruction::DUP3 << Instruction::ADD;
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
if (haveByteOffsetTarget) if (haveByteOffsetTarget)
m_context << u256(0); m_context << u256(0);
@ -159,8 +159,8 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
m_context << copyLoopStart; m_context << copyLoopStart;
// check for loop condition // check for loop condition
m_context m_context
<< solidity::dupInstruction(3 + byteOffsetSize) << solidity::dupInstruction(2 + byteOffsetSize) << dupInstruction(3 + byteOffsetSize) << dupInstruction(2 + byteOffsetSize)
<< solidity::Instruction::GT << solidity::Instruction::ISZERO; << Instruction::GT << Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.appendConditionalJump(); eth::AssemblyItem copyLoopEnd = m_context.appendConditionalJump();
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
// copy // copy
@ -168,19 +168,19 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
{ {
solAssert(byteOffsetSize == 0, "Byte offset for array as base type."); solAssert(byteOffsetSize == 0, "Byte offset for array as base type.");
auto const& sourceBaseArrayType = dynamic_cast<ArrayType const&>(*sourceBaseType); auto const& sourceBaseArrayType = dynamic_cast<ArrayType const&>(*sourceBaseType);
m_context << solidity::Instruction::DUP3; m_context << Instruction::DUP3;
if (sourceBaseArrayType.location() == DataLocation::Memory) if (sourceBaseArrayType.location() == DataLocation::Memory)
m_context << solidity::Instruction::MLOAD; m_context << Instruction::MLOAD;
m_context << solidity::Instruction::DUP3; m_context << Instruction::DUP3;
copyArrayToStorage(dynamic_cast<ArrayType const&>(*targetBaseType), sourceBaseArrayType); copyArrayToStorage(dynamic_cast<ArrayType const&>(*targetBaseType), sourceBaseArrayType);
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
else if (directCopy) else if (directCopy)
{ {
solAssert(byteOffsetSize == 0, "Byte offset for direct copy."); solAssert(byteOffsetSize == 0, "Byte offset for direct copy.");
m_context m_context
<< solidity::Instruction::DUP3 << solidity::Instruction::SLOAD << Instruction::DUP3 << Instruction::SLOAD
<< solidity::Instruction::DUP3 << solidity::Instruction::SSTORE; << Instruction::DUP3 << Instruction::SSTORE;
} }
else else
{ {
@ -188,11 +188,11 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// We might copy too much if there is padding at the last element, but this way end // We might copy too much if there is padding at the last element, but this way end
// checking is easier. // checking is easier.
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
m_context << solidity::dupInstruction(3 + byteOffsetSize); m_context << dupInstruction(3 + byteOffsetSize);
if (_sourceType.location() == DataLocation::Storage) if (_sourceType.location() == DataLocation::Storage)
{ {
if (haveByteOffsetSource) if (haveByteOffsetSource)
m_context << solidity::Instruction::DUP2; m_context << Instruction::DUP2;
else else
m_context << u256(0); m_context << u256(0);
StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true); StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true);
@ -207,9 +207,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
"Stack too deep, try removing local variables." "Stack too deep, try removing local variables."
); );
// fetch target storage reference // fetch target storage reference
m_context << solidity::dupInstruction(2 + byteOffsetSize + sourceBaseType->sizeOnStack()); m_context << dupInstruction(2 + byteOffsetSize + sourceBaseType->sizeOnStack());
if (haveByteOffsetTarget) if (haveByteOffsetTarget)
m_context << solidity::dupInstruction(1 + byteOffsetSize + sourceBaseType->sizeOnStack()); m_context << dupInstruction(1 + byteOffsetSize + sourceBaseType->sizeOnStack());
else else
m_context << u256(0); m_context << u256(0);
StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true); StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
@ -220,7 +220,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
incrementByteOffset(sourceBaseType->storageBytes(), 1, haveByteOffsetTarget ? 5 : 4); incrementByteOffset(sourceBaseType->storageBytes(), 1, haveByteOffsetTarget ? 5 : 4);
else else
{ {
m_context << solidity::swapInstruction(2 + byteOffsetSize); m_context << swapInstruction(2 + byteOffsetSize);
if (sourceIsStorage) if (sourceIsStorage)
m_context << sourceBaseType->storageSize(); m_context << sourceBaseType->storageSize();
else if (_sourceType.location() == DataLocation::Memory) else if (_sourceType.location() == DataLocation::Memory)
@ -228,44 +228,44 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
else else
m_context << sourceBaseType->calldataEncodedSize(true); m_context << sourceBaseType->calldataEncodedSize(true);
m_context m_context
<< solidity::Instruction::ADD << Instruction::ADD
<< solidity::swapInstruction(2 + byteOffsetSize); << swapInstruction(2 + byteOffsetSize);
} }
// increment target // increment target
if (haveByteOffsetTarget) if (haveByteOffsetTarget)
incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2); incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2);
else else
m_context m_context
<< solidity::swapInstruction(1 + byteOffsetSize) << swapInstruction(1 + byteOffsetSize)
<< targetBaseType->storageSize() << targetBaseType->storageSize()
<< solidity::Instruction::ADD << Instruction::ADD
<< solidity::swapInstruction(1 + byteOffsetSize); << swapInstruction(1 + byteOffsetSize);
m_context.appendJumpTo(copyLoopStart); m_context.appendJumpTo(copyLoopStart);
m_context << copyLoopEnd; m_context << copyLoopEnd;
if (haveByteOffsetTarget) if (haveByteOffsetTarget)
{ {
// clear elements that might be left over in the current slot in target // clear elements that might be left over in the current slot in target
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end target_byte_offset [source_byte_offset] // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end target_byte_offset [source_byte_offset]
m_context << solidity::dupInstruction(byteOffsetSize) << solidity::Instruction::ISZERO; m_context << dupInstruction(byteOffsetSize) << Instruction::ISZERO;
eth::AssemblyItem copyCleanupLoopEnd = m_context.appendConditionalJump(); eth::AssemblyItem copyCleanupLoopEnd = m_context.appendConditionalJump();
m_context << solidity::dupInstruction(2 + byteOffsetSize) << solidity::dupInstruction(1 + byteOffsetSize); m_context << dupInstruction(2 + byteOffsetSize) << dupInstruction(1 + byteOffsetSize);
StorageItem(m_context, *targetBaseType).setToZero(SourceLocation(), true); StorageItem(m_context, *targetBaseType).setToZero(SourceLocation(), true);
incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2); incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2);
m_context.appendJumpTo(copyLoopEnd); m_context.appendJumpTo(copyLoopEnd);
m_context << copyCleanupLoopEnd; m_context << copyCleanupLoopEnd;
m_context << solidity::Instruction::POP; // might pop the source, but then target is popped next m_context << Instruction::POP; // might pop the source, but then target is popped next
} }
if (haveByteOffsetSource) if (haveByteOffsetSource)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
m_context << copyLoopEndWithoutByteOffset; m_context << copyLoopEndWithoutByteOffset;
// zero-out leftovers in target // zero-out leftovers in target
// stack: target_ref target_data_end source_data_pos target_data_pos_updated source_data_end // stack: target_ref target_data_end source_data_pos target_data_pos_updated source_data_end
m_context << solidity::Instruction::POP << solidity::Instruction::SWAP1 << solidity::Instruction::POP; m_context << Instruction::POP << Instruction::SWAP1 << Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated // stack: target_ref target_data_end target_data_pos_updated
clearStorageLoop(*targetBaseType); clearStorageLoop(*targetBaseType);
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWordBoundaries) const void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWordBoundaries) const
@ -285,13 +285,13 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
if (!_sourceType.isDynamicallySized()) if (!_sourceType.isDynamicallySized())
m_context << _sourceType.length(); m_context << _sourceType.length();
if (baseSize > 1) if (baseSize > 1)
m_context << u256(baseSize) << solidity::Instruction::MUL; m_context << u256(baseSize) << Instruction::MUL;
// stack: target source_offset source_len // stack: target source_offset source_len
m_context << solidity::Instruction::DUP1 << solidity::Instruction::DUP3 << solidity::Instruction::DUP5; m_context << Instruction::DUP1 << Instruction::DUP3 << Instruction::DUP5;
// stack: target source_offset source_len source_len source_offset target // stack: target source_offset source_len source_len source_offset target
m_context << solidity::Instruction::CALLDATACOPY; m_context << Instruction::CALLDATACOPY;
m_context << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << Instruction::DUP3 << Instruction::ADD;
m_context << solidity::Instruction::SWAP2 << solidity::Instruction::POP << solidity::Instruction::POP; m_context << Instruction::SWAP2 << Instruction::POP << Instruction::POP;
} }
else if (_sourceType.location() == DataLocation::Memory) else if (_sourceType.location() == DataLocation::Memory)
{ {
@ -300,25 +300,25 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
if (!_sourceType.baseType()->isValueType()) if (!_sourceType.baseType()->isValueType())
{ {
// copy using a loop // copy using a loop
m_context << u256(0) << solidity::Instruction::SWAP3; m_context << u256(0) << Instruction::SWAP3;
// stack: counter source length target // stack: counter source length target
auto repeat = m_context.newTag(); auto repeat = m_context.newTag();
m_context << repeat; m_context << repeat;
m_context << solidity::Instruction::DUP2 << solidity::Instruction::DUP5; m_context << Instruction::DUP2 << Instruction::DUP5;
m_context << solidity::Instruction::LT << solidity::Instruction::ISZERO; m_context << Instruction::LT << Instruction::ISZERO;
auto loopEnd = m_context.appendConditionalJump(); auto loopEnd = m_context.appendConditionalJump();
m_context << solidity::Instruction::DUP3 << solidity::Instruction::DUP5; m_context << Instruction::DUP3 << Instruction::DUP5;
accessIndex(_sourceType, false); accessIndex(_sourceType, false);
MemoryItem(m_context, *_sourceType.baseType(), true).retrieveValue(SourceLocation(), true); MemoryItem(m_context, *_sourceType.baseType(), true).retrieveValue(SourceLocation(), true);
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get())) if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get()))
copyArrayToMemory(*baseArray, _padToWordBoundaries); copyArrayToMemory(*baseArray, _padToWordBoundaries);
else else
utils.storeInMemoryDynamic(*_sourceType.baseType()); utils.storeInMemoryDynamic(*_sourceType.baseType());
m_context << solidity::Instruction::SWAP3 << u256(1) << solidity::Instruction::ADD; m_context << Instruction::SWAP3 << u256(1) << Instruction::ADD;
m_context << solidity::Instruction::SWAP3; m_context << Instruction::SWAP3;
m_context.appendJumpTo(repeat); m_context.appendJumpTo(repeat);
m_context << loopEnd; m_context << loopEnd;
m_context << solidity::Instruction::SWAP3; m_context << Instruction::SWAP3;
utils.popStackSlots(3); utils.popStackSlots(3);
// stack: updated_target_pos // stack: updated_target_pos
return; return;
@ -328,18 +328,18 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
if (_sourceType.isDynamicallySized()) if (_sourceType.isDynamicallySized())
{ {
// change pointer to data part // change pointer to data part
m_context << solidity::Instruction::SWAP1 << u256(32) << solidity::Instruction::ADD; m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD;
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
} }
// convert length to size // convert length to size
if (baseSize > 1) if (baseSize > 1)
m_context << u256(baseSize) << solidity::Instruction::MUL; m_context << u256(baseSize) << Instruction::MUL;
// stack: <target> <source> <size> // stack: <target> <source> <size>
//@TODO do not use ::CALL if less than 32 bytes? //@TODO do not use ::CALL if less than 32 bytes?
m_context << solidity::Instruction::DUP1 << solidity::Instruction::DUP4 << solidity::Instruction::DUP4; m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::DUP4;
utils.memoryCopy(); utils.memoryCopy();
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::POP; m_context << Instruction::SWAP1 << Instruction::POP;
// stack: <target> <size> // stack: <target> <size>
bool paddingNeeded = false; bool paddingNeeded = false;
@ -350,43 +350,43 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
if (paddingNeeded) if (paddingNeeded)
{ {
// stack: <target> <size> // stack: <target> <size>
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::DUP2 << solidity::Instruction::ADD; m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD;
// stack: <length> <target + size> // stack: <length> <target + size>
m_context << solidity::Instruction::SWAP1 << u256(31) << solidity::Instruction::AND; m_context << Instruction::SWAP1 << u256(31) << Instruction::AND;
// stack: <target + size> <remainder = size % 32> // stack: <target + size> <remainder = size % 32>
eth::AssemblyItem skip = m_context.newTag(); eth::AssemblyItem skip = m_context.newTag();
if (_sourceType.isDynamicallySized()) if (_sourceType.isDynamicallySized())
{ {
m_context << solidity::Instruction::DUP1 << solidity::Instruction::ISZERO; m_context << Instruction::DUP1 << Instruction::ISZERO;
m_context.appendConditionalJumpTo(skip); m_context.appendConditionalJumpTo(skip);
} }
// round off, load from there. // round off, load from there.
// stack <target + size> <remainder = size % 32> // stack <target + size> <remainder = size % 32>
m_context << solidity::Instruction::DUP1 << solidity::Instruction::DUP3; m_context << Instruction::DUP1 << Instruction::DUP3;
m_context << solidity::Instruction::SUB; m_context << Instruction::SUB;
// stack: target+size remainder <target + size - remainder> // stack: target+size remainder <target + size - remainder>
m_context << solidity::Instruction::DUP1 << solidity::Instruction::MLOAD; m_context << Instruction::DUP1 << Instruction::MLOAD;
// Now we AND it with ~(2**(8 * (32 - remainder)) - 1) // Now we AND it with ~(2**(8 * (32 - remainder)) - 1)
m_context << u256(1); m_context << u256(1);
m_context << solidity::Instruction::DUP4 << u256(32) << solidity::Instruction::SUB; m_context << Instruction::DUP4 << u256(32) << Instruction::SUB;
// stack: ...<v> 1 <32 - remainder> // stack: ...<v> 1 <32 - remainder>
m_context << u256(0x100) << solidity::Instruction::EXP << solidity::Instruction::SUB; m_context << u256(0x100) << Instruction::EXP << Instruction::SUB;
m_context << solidity::Instruction::NOT << solidity::Instruction::AND; m_context << Instruction::NOT << Instruction::AND;
// stack: target+size remainder target+size-remainder <v & ...> // stack: target+size remainder target+size-remainder <v & ...>
m_context << solidity::Instruction::DUP2 << solidity::Instruction::MSTORE; m_context << Instruction::DUP2 << Instruction::MSTORE;
// stack: target+size remainder target+size-remainder // stack: target+size remainder target+size-remainder
m_context << u256(32) << solidity::Instruction::ADD; m_context << u256(32) << Instruction::ADD;
// stack: target+size remainder <new_padded_end> // stack: target+size remainder <new_padded_end>
m_context << solidity::Instruction::SWAP2 << solidity::Instruction::POP; m_context << Instruction::SWAP2 << Instruction::POP;
if (_sourceType.isDynamicallySized()) if (_sourceType.isDynamicallySized())
m_context << skip.tag(); m_context << skip.tag();
// stack <target + "size"> <remainder = size % 32> // stack <target + "size"> <remainder = size % 32>
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
else else
// stack: <target> <size> // stack: <target> <size>
m_context << solidity::Instruction::ADD; m_context << Instruction::ADD;
} }
else else
{ {
@ -398,48 +398,48 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
retrieveLength(_sourceType); retrieveLength(_sourceType);
// stack here: memory_offset storage_offset length // stack here: memory_offset storage_offset length
// jump to end if length is zero // jump to end if length is zero
m_context << solidity::Instruction::DUP1 << solidity::Instruction::ISZERO; m_context << Instruction::DUP1 << Instruction::ISZERO;
eth::AssemblyItem loopEnd = m_context.appendConditionalJump(); eth::AssemblyItem loopEnd = m_context.appendConditionalJump();
// Special case for tightly-stored byte arrays // Special case for tightly-stored byte arrays
if (_sourceType.isByteArray()) if (_sourceType.isByteArray())
{ {
// stack here: memory_offset storage_offset length // stack here: memory_offset storage_offset length
m_context << solidity::Instruction::DUP1 << u256(31) << solidity::Instruction::LT; m_context << Instruction::DUP1 << u256(31) << Instruction::LT;
eth::AssemblyItem longByteArray = m_context.appendConditionalJump(); eth::AssemblyItem longByteArray = m_context.appendConditionalJump();
// store the short byte array (discard lower-order byte) // store the short byte array (discard lower-order byte)
m_context << u256(0x100) << solidity::Instruction::DUP1; m_context << u256(0x100) << Instruction::DUP1;
m_context << solidity::Instruction::DUP4 << solidity::Instruction::SLOAD; m_context << Instruction::DUP4 << Instruction::SLOAD;
m_context << solidity::Instruction::DIV << solidity::Instruction::MUL; m_context << Instruction::DIV << Instruction::MUL;
m_context << solidity::Instruction::DUP4 << solidity::Instruction::MSTORE; m_context << Instruction::DUP4 << Instruction::MSTORE;
// stack here: memory_offset storage_offset length // stack here: memory_offset storage_offset length
// add 32 or length to memory offset // add 32 or length to memory offset
m_context << solidity::Instruction::SWAP2; m_context << Instruction::SWAP2;
if (_padToWordBoundaries) if (_padToWordBoundaries)
m_context << u256(32); m_context << u256(32);
else else
m_context << solidity::Instruction::DUP3; m_context << Instruction::DUP3;
m_context << solidity::Instruction::ADD; m_context << Instruction::ADD;
m_context << solidity::Instruction::SWAP2; m_context << Instruction::SWAP2;
m_context.appendJumpTo(loopEnd); m_context.appendJumpTo(loopEnd);
m_context << longByteArray; m_context << longByteArray;
} }
// compute memory end offset // compute memory end offset
if (baseSize > 1) if (baseSize > 1)
// convert length to memory size // convert length to memory size
m_context << u256(baseSize) << solidity::Instruction::MUL; m_context << u256(baseSize) << Instruction::MUL;
m_context << solidity::Instruction::DUP3 << solidity::Instruction::ADD << solidity::Instruction::SWAP2; m_context << Instruction::DUP3 << Instruction::ADD << Instruction::SWAP2;
if (_sourceType.isDynamicallySized()) if (_sourceType.isDynamicallySized())
{ {
// actual array data is stored at SHA3(storage_offset) // actual array data is stored at SHA3(storage_offset)
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
utils.computeHashStatic(); utils.computeHashStatic();
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
} }
// stack here: memory_end_offset storage_data_offset memory_offset // stack here: memory_end_offset storage_data_offset memory_offset
bool haveByteOffset = !_sourceType.isByteArray() && storageBytes <= 16; bool haveByteOffset = !_sourceType.isByteArray() && storageBytes <= 16;
if (haveByteOffset) if (haveByteOffset)
m_context << u256(0) << solidity::Instruction::SWAP1; m_context << u256(0) << Instruction::SWAP1;
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart; m_context << loopStart;
@ -447,20 +447,20 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
if (_sourceType.isByteArray()) if (_sourceType.isByteArray())
{ {
// Packed both in storage and memory. // Packed both in storage and memory.
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SLOAD; m_context << Instruction::DUP2 << Instruction::SLOAD;
m_context << solidity::Instruction::DUP2 << solidity::Instruction::MSTORE; m_context << Instruction::DUP2 << Instruction::MSTORE;
// increment storage_data_offset by 1 // increment storage_data_offset by 1
m_context << solidity::Instruction::SWAP1 << u256(1) << solidity::Instruction::ADD; m_context << Instruction::SWAP1 << u256(1) << Instruction::ADD;
// increment memory offset by 32 // increment memory offset by 32
m_context << solidity::Instruction::SWAP1 << u256(32) << solidity::Instruction::ADD; m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD;
} }
else else
{ {
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
if (haveByteOffset) if (haveByteOffset)
m_context << solidity::Instruction::DUP3 << solidity::Instruction::DUP3; m_context << Instruction::DUP3 << Instruction::DUP3;
else else
m_context << solidity::Instruction::DUP2 << u256(0); m_context << Instruction::DUP2 << u256(0);
StorageItem(m_context, *_sourceType.baseType()).retrieveValue(SourceLocation(), true); StorageItem(m_context, *_sourceType.baseType()).retrieveValue(SourceLocation(), true);
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get())) if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get()))
copyArrayToMemory(*baseArray, _padToWordBoundaries); copyArrayToMemory(*baseArray, _padToWordBoundaries);
@ -471,29 +471,29 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
incrementByteOffset(storageBytes, 2, 3); incrementByteOffset(storageBytes, 2, 3);
else else
{ {
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
m_context << storageSize << solidity::Instruction::ADD; m_context << storageSize << Instruction::ADD;
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
} }
} }
// check for loop condition // check for loop condition
m_context << solidity::Instruction::DUP1 << solidity::dupInstruction(haveByteOffset ? 5 : 4); m_context << Instruction::DUP1 << dupInstruction(haveByteOffset ? 5 : 4);
m_context << solidity::Instruction::GT; m_context << Instruction::GT;
m_context.appendConditionalJumpTo(loopStart); m_context.appendConditionalJumpTo(loopStart);
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
if (haveByteOffset) if (haveByteOffset)
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::POP; m_context << Instruction::SWAP1 << Instruction::POP;
if (_padToWordBoundaries && baseSize % 32 != 0) if (_padToWordBoundaries && baseSize % 32 != 0)
{ {
// memory_end_offset - start is the actual length (we want to compute the ceil of). // memory_end_offset - start is the actual length (we want to compute the ceil of).
// memory_offset - start is its next multiple of 32, but it might be off by 32. // memory_offset - start is its next multiple of 32, but it might be off by 32.
// so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31 // so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31
m_context << solidity::Instruction::DUP3 << solidity::Instruction::SWAP1 << solidity::Instruction::SUB; m_context << Instruction::DUP3 << Instruction::SWAP1 << Instruction::SUB;
m_context << u256(31) << solidity::Instruction::AND; m_context << u256(31) << Instruction::AND;
m_context << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << Instruction::DUP3 << Instruction::ADD;
m_context << solidity::Instruction::SWAP2; m_context << Instruction::SWAP2;
} }
m_context << loopEnd << solidity::Instruction::POP << solidity::Instruction::POP; m_context << loopEnd << Instruction::POP << Instruction::POP;
} }
} }
@ -509,20 +509,20 @@ void ArrayUtils::clearArray(ArrayType const& _type) const
if (_type.baseType()->isValueType()) if (_type.baseType()->isValueType())
solAssert(_type.baseType()->storageSize() <= 1, "Invalid size for value type."); solAssert(_type.baseType()->storageSize() <= 1, "Invalid size for value type.");
m_context << solidity::Instruction::POP; // remove byte offset m_context << Instruction::POP; // remove byte offset
if (_type.isDynamicallySized()) if (_type.isDynamicallySized())
clearDynamicArray(_type); clearDynamicArray(_type);
else if (_type.length() == 0 || _type.baseType()->category() == Type::Category::Mapping) else if (_type.length() == 0 || _type.baseType()->category() == Type::Category::Mapping)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
else if (_type.baseType()->isValueType() && _type.storageSize() <= 5) else if (_type.baseType()->isValueType() && _type.storageSize() <= 5)
{ {
// unroll loop for small arrays @todo choose a good value // unroll loop for small arrays @todo choose a good value
// Note that we loop over storage slots here, not elements. // Note that we loop over storage slots here, not elements.
for (unsigned i = 1; i < _type.storageSize(); ++i) for (unsigned i = 1; i < _type.storageSize(); ++i)
m_context m_context
<< u256(0) << solidity::Instruction::DUP2 << solidity::Instruction::SSTORE << u256(0) << Instruction::DUP2 << Instruction::SSTORE
<< u256(1) << solidity::Instruction::ADD; << u256(1) << Instruction::ADD;
m_context << u256(0) << solidity::Instruction::SWAP1 << solidity::Instruction::SSTORE; m_context << u256(0) << Instruction::SWAP1 << Instruction::SSTORE;
} }
else if (!_type.baseType()->isValueType() && _type.length() <= 4) else if (!_type.baseType()->isValueType() && _type.length() <= 4)
{ {
@ -533,22 +533,22 @@ void ArrayUtils::clearArray(ArrayType const& _type) const
m_context << u256(0); m_context << u256(0);
StorageItem(m_context, *_type.baseType()).setToZero(SourceLocation(), false); StorageItem(m_context, *_type.baseType()).setToZero(SourceLocation(), false);
m_context m_context
<< solidity::Instruction::POP << Instruction::POP
<< u256(_type.baseType()->storageSize()) << solidity::Instruction::ADD; << u256(_type.baseType()->storageSize()) << Instruction::ADD;
} }
m_context << u256(0); m_context << u256(0);
StorageItem(m_context, *_type.baseType()).setToZero(SourceLocation(), true); StorageItem(m_context, *_type.baseType()).setToZero(SourceLocation(), true);
} }
else else
{ {
m_context << solidity::Instruction::DUP1 << _type.length(); m_context << Instruction::DUP1 << _type.length();
convertLengthToSize(_type); convertLengthToSize(_type);
m_context << solidity::Instruction::ADD << solidity::Instruction::SWAP1; m_context << Instruction::ADD << Instruction::SWAP1;
if (_type.baseType()->storageBytes() < 32) if (_type.baseType()->storageBytes() < 32)
clearStorageLoop(IntegerType(256)); clearStorageLoop(IntegerType(256));
else else
clearStorageLoop(*_type.baseType()); clearStorageLoop(*_type.baseType());
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
solAssert(m_context.stackHeight() == stackHeightStart - 2, ""); solAssert(m_context.stackHeight() == stackHeightStart - 2, "");
} }
@ -561,15 +561,15 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
// fetch length // fetch length
retrieveLength(_type); retrieveLength(_type);
// set length to zero // set length to zero
m_context << u256(0) << solidity::Instruction::DUP3 << solidity::Instruction::SSTORE; m_context << u256(0) << Instruction::DUP3 << Instruction::SSTORE;
// Special case: short byte arrays are stored togeher with their length // Special case: short byte arrays are stored togeher with their length
eth::AssemblyItem endTag = m_context.newTag(); eth::AssemblyItem endTag = m_context.newTag();
if (_type.isByteArray()) if (_type.isByteArray())
{ {
// stack: ref old_length // stack: ref old_length
m_context << solidity::Instruction::DUP1 << u256(31) << solidity::Instruction::LT; m_context << Instruction::DUP1 << u256(31) << Instruction::LT;
eth::AssemblyItem longByteArray = m_context.appendConditionalJump(); eth::AssemblyItem longByteArray = m_context.appendConditionalJump();
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
m_context.appendJumpTo(endTag); m_context.appendJumpTo(endTag);
m_context.adjustStackOffset(1); // needed because of jump m_context.adjustStackOffset(1); // needed because of jump
m_context << longByteArray; m_context << longByteArray;
@ -577,11 +577,11 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
// stack: ref old_length // stack: ref old_length
convertLengthToSize(_type); convertLengthToSize(_type);
// compute data positions // compute data positions
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
// stack: len data_pos // stack: len data_pos
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::DUP2 << solidity::Instruction::ADD m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD
<< solidity::Instruction::SWAP1; << Instruction::SWAP1;
// stack: data_pos_end data_pos // stack: data_pos_end data_pos
if (_type.isByteArray() || _type.baseType()->storageBytes() < 32) if (_type.isByteArray() || _type.baseType()->storageBytes() < 32)
clearStorageLoop(IntegerType(256)); clearStorageLoop(IntegerType(256));
@ -589,7 +589,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
clearStorageLoop(*_type.baseType()); clearStorageLoop(*_type.baseType());
// cleanup // cleanup
m_context << endTag; m_context << endTag;
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const
@ -614,13 +614,13 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const
eth::AssemblyItem regularPath = m_context.newTag(); eth::AssemblyItem regularPath = m_context.newTag();
// We start by a large case-distinction about the old and new length of the byte array. // We start by a large case-distinction about the old and new length of the byte array.
m_context << solidity::Instruction::DUP3 << solidity::Instruction::SLOAD; m_context << Instruction::DUP3 << Instruction::SLOAD;
// stack: ref new_length current_length ref_value // stack: ref new_length current_length ref_value
solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3"); solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3");
m_context << solidity::Instruction::DUP2 << u256(31) << solidity::Instruction::LT; m_context << Instruction::DUP2 << u256(31) << Instruction::LT;
eth::AssemblyItem currentIsLong = m_context.appendConditionalJump(); eth::AssemblyItem currentIsLong = m_context.appendConditionalJump();
m_context << solidity::Instruction::DUP3 << u256(31) << solidity::Instruction::LT; m_context << Instruction::DUP3 << u256(31) << Instruction::LT;
eth::AssemblyItem newIsLong = m_context.appendConditionalJump(); eth::AssemblyItem newIsLong = m_context.appendConditionalJump();
// Here: short -> short // Here: short -> short
@ -628,17 +628,17 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const
// Compute 1 << (256 - 8 * new_size) // Compute 1 << (256 - 8 * new_size)
eth::AssemblyItem shortToShort = m_context.newTag(); eth::AssemblyItem shortToShort = m_context.newTag();
m_context << shortToShort; m_context << shortToShort;
m_context << solidity::Instruction::DUP3 << u256(8) << solidity::Instruction::MUL; m_context << Instruction::DUP3 << u256(8) << Instruction::MUL;
m_context << u256(0x100) << solidity::Instruction::SUB; m_context << u256(0x100) << Instruction::SUB;
m_context << u256(2) << solidity::Instruction::EXP; m_context << u256(2) << Instruction::EXP;
// Divide and multiply by that value, clearing bits. // Divide and multiply by that value, clearing bits.
m_context << solidity::Instruction::DUP1 << solidity::Instruction::SWAP2; m_context << Instruction::DUP1 << Instruction::SWAP2;
m_context << solidity::Instruction::DIV << solidity::Instruction::MUL; m_context << Instruction::DIV << Instruction::MUL;
// Insert 2*length. // Insert 2*length.
m_context << solidity::Instruction::DUP3 << solidity::Instruction::DUP1 << solidity::Instruction::ADD; m_context << Instruction::DUP3 << Instruction::DUP1 << Instruction::ADD;
m_context << solidity::Instruction::OR; m_context << Instruction::OR;
// Store. // Store.
m_context << solidity::Instruction::DUP4 << solidity::Instruction::SSTORE; m_context << Instruction::DUP4 << Instruction::SSTORE;
solAssert(m_context.stackHeight() - stackHeightStart == 3 - 2, "3"); solAssert(m_context.stackHeight() - stackHeightStart == 3 - 2, "3");
m_context.appendJumpTo(resizeEnd); m_context.appendJumpTo(resizeEnd);
@ -649,24 +649,24 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const
// stack: ref new_length current_length ref_value // stack: ref new_length current_length ref_value
solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3"); solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3");
// Zero out lower-order byte. // Zero out lower-order byte.
m_context << u256(0xff) << solidity::Instruction::NOT << solidity::Instruction::AND; m_context << u256(0xff) << Instruction::NOT << Instruction::AND;
// Store at data location. // Store at data location.
m_context << solidity::Instruction::DUP4; m_context << Instruction::DUP4;
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
m_context << solidity::Instruction::SSTORE; m_context << Instruction::SSTORE;
// stack: ref new_length current_length // stack: ref new_length current_length
// Store new length: Compule 2*length + 1 and store it. // Store new length: Compule 2*length + 1 and store it.
m_context << solidity::Instruction::DUP2 << solidity::Instruction::DUP1 << solidity::Instruction::ADD; m_context << Instruction::DUP2 << Instruction::DUP1 << Instruction::ADD;
m_context << u256(1) << solidity::Instruction::ADD; m_context << u256(1) << Instruction::ADD;
// stack: ref new_length current_length 2*new_length+1 // stack: ref new_length current_length 2*new_length+1
m_context << solidity::Instruction::DUP4 << solidity::Instruction::SSTORE; m_context << Instruction::DUP4 << Instruction::SSTORE;
solAssert(m_context.stackHeight() - stackHeightStart == 3 - 2, "3"); solAssert(m_context.stackHeight() - stackHeightStart == 3 - 2, "3");
m_context.appendJumpTo(resizeEnd); m_context.appendJumpTo(resizeEnd);
m_context.adjustStackOffset(1); // we have to do that because of the jumps m_context.adjustStackOffset(1); // we have to do that because of the jumps
m_context << currentIsLong; m_context << currentIsLong;
m_context << solidity::Instruction::DUP3 << u256(31) << solidity::Instruction::LT; m_context << Instruction::DUP3 << u256(31) << Instruction::LT;
m_context.appendConditionalJumpTo(regularPath); m_context.appendConditionalJumpTo(regularPath);
// Here: long -> short // Here: long -> short
@ -675,51 +675,51 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const
// stack: ref new_length current_length ref_value // stack: ref new_length current_length ref_value
solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3"); solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3");
m_context << solidity::Instruction::POP << solidity::Instruction::DUP3; m_context << Instruction::POP << Instruction::DUP3;
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
m_context << solidity::Instruction::DUP1 << solidity::Instruction::SLOAD << solidity::Instruction::SWAP1; m_context << Instruction::DUP1 << Instruction::SLOAD << Instruction::SWAP1;
// stack: ref new_length current_length first_word data_location // stack: ref new_length current_length first_word data_location
m_context << solidity::Instruction::DUP3; m_context << Instruction::DUP3;
convertLengthToSize(_type); convertLengthToSize(_type);
m_context << solidity::Instruction::DUP2 << solidity::Instruction::ADD << solidity::Instruction::SWAP1; m_context << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1;
// stack: ref new_length current_length first_word data_location_end data_location // stack: ref new_length current_length first_word data_location_end data_location
clearStorageLoop(IntegerType(256)); clearStorageLoop(IntegerType(256));
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
// stack: ref new_length current_length first_word // stack: ref new_length current_length first_word
solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3"); solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3");
m_context.appendJumpTo(shortToShort); m_context.appendJumpTo(shortToShort);
m_context << regularPath; m_context << regularPath;
// stack: ref new_length current_length ref_value // stack: ref new_length current_length ref_value
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
// Change of length for a regular array (i.e. length at location, data at sha3(location)). // Change of length for a regular array (i.e. length at location, data at sha3(location)).
// stack: ref new_length old_length // stack: ref new_length old_length
// store new length // store new length
m_context << solidity::Instruction::DUP2; m_context << Instruction::DUP2;
if (_type.isByteArray()) if (_type.isByteArray())
// For a "long" byte array, store length as 2*length+1 // For a "long" byte array, store length as 2*length+1
m_context << solidity::Instruction::DUP1 << solidity::Instruction::ADD << u256(1) << solidity::Instruction::ADD; m_context << Instruction::DUP1 << Instruction::ADD << u256(1) << Instruction::ADD;
m_context<< solidity::Instruction::DUP4 << solidity::Instruction::SSTORE; m_context<< Instruction::DUP4 << Instruction::SSTORE;
// skip if size is not reduced // skip if size is not reduced
m_context << solidity::Instruction::DUP2 << solidity::Instruction::DUP2 m_context << Instruction::DUP2 << Instruction::DUP2
<< solidity::Instruction::ISZERO << solidity::Instruction::GT; << Instruction::ISZERO << Instruction::GT;
m_context.appendConditionalJumpTo(resizeEnd); m_context.appendConditionalJumpTo(resizeEnd);
// size reduced, clear the end of the array // size reduced, clear the end of the array
// stack: ref new_length old_length // stack: ref new_length old_length
convertLengthToSize(_type); convertLengthToSize(_type);
m_context << solidity::Instruction::DUP2; m_context << Instruction::DUP2;
convertLengthToSize(_type); convertLengthToSize(_type);
// stack: ref new_length old_size new_size // stack: ref new_length old_size new_size
// compute data positions // compute data positions
m_context << solidity::Instruction::DUP4; m_context << Instruction::DUP4;
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
// stack: ref new_length old_size new_size data_pos // stack: ref new_length old_size new_size data_pos
m_context << solidity::Instruction::SWAP2 << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << Instruction::SWAP2 << Instruction::DUP3 << Instruction::ADD;
// stack: ref new_length data_pos new_size delete_end // stack: ref new_length data_pos new_size delete_end
m_context << solidity::Instruction::SWAP2 << solidity::Instruction::ADD; m_context << Instruction::SWAP2 << Instruction::ADD;
// stack: ref new_length delete_end delete_start // stack: ref new_length delete_end delete_start
if (_type.isByteArray() || _type.baseType()->storageBytes() < 32) if (_type.isByteArray() || _type.baseType()->storageBytes() < 32)
clearStorageLoop(IntegerType(256)); clearStorageLoop(IntegerType(256));
@ -728,7 +728,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const
m_context << resizeEnd; m_context << resizeEnd;
// cleanup // cleanup
m_context << solidity::Instruction::POP << solidity::Instruction::POP << solidity::Instruction::POP; m_context << Instruction::POP << Instruction::POP << Instruction::POP;
solAssert(m_context.stackHeight() == stackHeightStart - 2, ""); solAssert(m_context.stackHeight() == stackHeightStart - 2, "");
} }
@ -737,35 +737,35 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const
unsigned stackHeightStart = m_context.stackHeight(); unsigned stackHeightStart = m_context.stackHeight();
if (_type.category() == Type::Category::Mapping) if (_type.category() == Type::Category::Mapping)
{ {
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
return; return;
} }
// stack: end_pos pos // stack: end_pos pos
// jump to and return from the loop to allow for duplicate code removal // jump to and return from the loop to allow for duplicate code removal
eth::AssemblyItem returnTag = m_context.pushNewTag(); eth::AssemblyItem returnTag = m_context.pushNewTag();
m_context << solidity::Instruction::SWAP2 << solidity::Instruction::SWAP1; m_context << Instruction::SWAP2 << Instruction::SWAP1;
// stack: <return tag> end_pos pos // stack: <return tag> end_pos pos
eth::AssemblyItem loopStart = m_context.appendJumpToNew(); eth::AssemblyItem loopStart = m_context.appendJumpToNew();
m_context << loopStart; m_context << loopStart;
// check for loop condition // check for loop condition
m_context << solidity::Instruction::DUP1 << solidity::Instruction::DUP3 m_context << Instruction::DUP1 << Instruction::DUP3
<< solidity::Instruction::GT << solidity::Instruction::ISZERO; << Instruction::GT << Instruction::ISZERO;
eth::AssemblyItem zeroLoopEnd = m_context.newTag(); eth::AssemblyItem zeroLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(zeroLoopEnd); m_context.appendConditionalJumpTo(zeroLoopEnd);
// delete // delete
m_context << u256(0); m_context << u256(0);
StorageItem(m_context, _type).setToZero(SourceLocation(), false); StorageItem(m_context, _type).setToZero(SourceLocation(), false);
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
// increment // increment
m_context << u256(1) << solidity::Instruction::ADD; m_context << u256(1) << Instruction::ADD;
m_context.appendJumpTo(loopStart); m_context.appendJumpTo(loopStart);
// cleanup // cleanup
m_context << zeroLoopEnd; m_context << zeroLoopEnd;
m_context << solidity::Instruction::POP << solidity::Instruction::SWAP1; m_context << Instruction::POP << Instruction::SWAP1;
// "return" // "return"
m_context << solidity::Instruction::JUMP; m_context << Instruction::JUMP;
m_context << returnTag; m_context << returnTag;
solAssert(m_context.stackHeight() == stackHeightStart - 1, ""); solAssert(m_context.stackHeight() == stackHeightStart - 1, "");
@ -779,17 +779,17 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con
{ {
unsigned baseBytes = _arrayType.baseType()->storageBytes(); unsigned baseBytes = _arrayType.baseType()->storageBytes();
if (baseBytes == 0) if (baseBytes == 0)
m_context << solidity::Instruction::POP << u256(1); m_context << Instruction::POP << u256(1);
else if (baseBytes <= 16) else if (baseBytes <= 16)
{ {
unsigned itemsPerSlot = 32 / baseBytes; unsigned itemsPerSlot = 32 / baseBytes;
m_context m_context
<< u256(itemsPerSlot - 1) << solidity::Instruction::ADD << u256(itemsPerSlot - 1) << Instruction::ADD
<< u256(itemsPerSlot) << solidity::Instruction::SWAP1 << solidity::Instruction::DIV; << u256(itemsPerSlot) << Instruction::SWAP1 << Instruction::DIV;
} }
} }
else else
m_context << _arrayType.baseType()->storageSize() << solidity::Instruction::MUL; m_context << _arrayType.baseType()->storageSize() << Instruction::MUL;
} }
else else
{ {
@ -799,12 +799,12 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con
m_context << _arrayType.baseType()->memoryHeadSize(); m_context << _arrayType.baseType()->memoryHeadSize();
else else
m_context << _arrayType.baseType()->calldataEncodedSize(); m_context << _arrayType.baseType()->calldataEncodedSize();
m_context << solidity::Instruction::MUL; m_context << Instruction::MUL;
} }
else if (_pad) else if (_pad)
m_context << u256(31) << solidity::Instruction::ADD m_context << u256(31) << Instruction::ADD
<< u256(32) << solidity::Instruction::DUP1 << u256(32) << Instruction::DUP1
<< solidity::Instruction::SWAP2 << solidity::Instruction::DIV << solidity::Instruction::MUL; << Instruction::SWAP2 << Instruction::DIV << Instruction::MUL;
} }
} }
@ -814,27 +814,27 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType, unsigned _stackDept
m_context << _arrayType.length(); m_context << _arrayType.length();
else else
{ {
m_context << solidity::dupInstruction(1 + _stackDepth); m_context << dupInstruction(1 + _stackDepth);
switch (_arrayType.location()) switch (_arrayType.location())
{ {
case DataLocation::CallData: case DataLocation::CallData:
// length is stored on the stack // length is stored on the stack
break; break;
case DataLocation::Memory: case DataLocation::Memory:
m_context << solidity::Instruction::MLOAD; m_context << Instruction::MLOAD;
break; break;
case DataLocation::Storage: case DataLocation::Storage:
m_context << solidity::Instruction::SLOAD; m_context << Instruction::SLOAD;
if (_arrayType.isByteArray()) if (_arrayType.isByteArray())
{ {
// Retrieve length both for in-place strings and off-place strings: // Retrieve length both for in-place strings and off-place strings:
// Computes (x & (0x100 * (ISZERO (x & 1)) - 1)) / 2 // Computes (x & (0x100 * (ISZERO (x & 1)) - 1)) / 2
// i.e. for short strings (x & 1 == 0) it does (x & 0xff) / 2 and for long strings it // i.e. for short strings (x & 1 == 0) it does (x & 0xff) / 2 and for long strings it
// computes (x & (-1)) / 2, which is equivalent to just x / 2. // computes (x & (-1)) / 2, which is equivalent to just x / 2.
m_context << u256(1) << solidity::Instruction::DUP2 << u256(1) << solidity::Instruction::AND; m_context << u256(1) << Instruction::DUP2 << u256(1) << Instruction::AND;
m_context << solidity::Instruction::ISZERO << u256(0x100) << solidity::Instruction::MUL; m_context << Instruction::ISZERO << u256(0x100) << Instruction::MUL;
m_context << solidity::Instruction::SUB << solidity::Instruction::AND; m_context << Instruction::SUB << Instruction::AND;
m_context << u256(2) << solidity::Instruction::SWAP1 << solidity::Instruction::DIV; m_context << u256(2) << Instruction::SWAP1 << Instruction::DIV;
} }
break; break;
} }
@ -852,34 +852,34 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c
ArrayUtils::retrieveLength(_arrayType, 1); ArrayUtils::retrieveLength(_arrayType, 1);
// Stack: ref [length] index length // Stack: ref [length] index length
// check out-of-bounds access // check out-of-bounds access
m_context << solidity::Instruction::DUP2 << solidity::Instruction::LT << solidity::Instruction::ISZERO; m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO;
// out-of-bounds access throws exception // out-of-bounds access throws exception
m_context.appendConditionalJumpTo(m_context.errorTag()); m_context.appendConditionalJumpTo(m_context.errorTag());
} }
if (location == DataLocation::CallData && _arrayType.isDynamicallySized()) if (location == DataLocation::CallData && _arrayType.isDynamicallySized())
// remove length if present // remove length if present
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::POP; m_context << Instruction::SWAP1 << Instruction::POP;
// stack: <base_ref> <index> // stack: <base_ref> <index>
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
// stack: <index> <base_ref> // stack: <index> <base_ref>
switch (location) switch (location)
{ {
case DataLocation::Memory: case DataLocation::Memory:
if (_arrayType.isDynamicallySized()) if (_arrayType.isDynamicallySized())
m_context << u256(32) << solidity::Instruction::ADD; m_context << u256(32) << Instruction::ADD;
// fall-through // fall-through
case DataLocation::CallData: case DataLocation::CallData:
if (!_arrayType.isByteArray()) if (!_arrayType.isByteArray())
{ {
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
if (location == DataLocation::CallData) if (location == DataLocation::CallData)
m_context << _arrayType.baseType()->calldataEncodedSize(); m_context << _arrayType.baseType()->calldataEncodedSize();
else else
m_context << u256(_arrayType.memoryHeadSize()); m_context << u256(_arrayType.memoryHeadSize());
m_context << solidity::Instruction::MUL; m_context << Instruction::MUL;
} }
m_context << solidity::Instruction::ADD; m_context << Instruction::ADD;
break; break;
case DataLocation::Storage: case DataLocation::Storage:
{ {
@ -887,16 +887,16 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c
if (_arrayType.isByteArray()) if (_arrayType.isByteArray())
{ {
// Special case of short byte arrays. // Special case of short byte arrays.
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SLOAD; m_context << Instruction::DUP2 << Instruction::SLOAD;
m_context << u256(1) << solidity::Instruction::AND << solidity::Instruction::ISZERO; m_context << u256(1) << Instruction::AND << Instruction::ISZERO;
// No action needed for short byte arrays. // No action needed for short byte arrays.
m_context.appendConditionalJumpTo(endTag); m_context.appendConditionalJumpTo(endTag);
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
} }
if (_arrayType.isDynamicallySized()) if (_arrayType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
if (_arrayType.baseType()->storageBytes() <= 16) if (_arrayType.baseType()->storageBytes() <= 16)
{ {
// stack: <data_ref> <index> // stack: <data_ref> <index>
@ -905,22 +905,22 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c
unsigned byteSize = _arrayType.baseType()->storageBytes(); unsigned byteSize = _arrayType.baseType()->storageBytes();
solAssert(byteSize != 0, ""); solAssert(byteSize != 0, "");
unsigned itemsPerSlot = 32 / byteSize; unsigned itemsPerSlot = 32 / byteSize;
m_context << u256(itemsPerSlot) << solidity::Instruction::SWAP2; m_context << u256(itemsPerSlot) << Instruction::SWAP2;
// stack: itemsPerSlot index data_ref // stack: itemsPerSlot index data_ref
m_context m_context
<< solidity::Instruction::DUP3 << solidity::Instruction::DUP3 << Instruction::DUP3 << Instruction::DUP3
<< solidity::Instruction::DIV << solidity::Instruction::ADD << Instruction::DIV << Instruction::ADD
// stack: itemsPerSlot index (data_ref + index / itemsPerSlot) // stack: itemsPerSlot index (data_ref + index / itemsPerSlot)
<< solidity::Instruction::SWAP2 << solidity::Instruction::SWAP1 << Instruction::SWAP2 << Instruction::SWAP1
<< solidity::Instruction::MOD; << Instruction::MOD;
if (byteSize != 1) if (byteSize != 1)
m_context << u256(byteSize) << solidity::Instruction::MUL; m_context << u256(byteSize) << Instruction::MUL;
} }
else else
{ {
if (_arrayType.baseType()->storageSize() != 1) if (_arrayType.baseType()->storageSize() != 1)
m_context << _arrayType.baseType()->storageSize() << solidity::Instruction::MUL; m_context << _arrayType.baseType()->storageSize() << Instruction::MUL;
m_context << solidity::Instruction::ADD << u256(0); m_context << Instruction::ADD << u256(0);
} }
m_context << endTag; m_context << endTag;
break; break;
@ -942,27 +942,27 @@ void ArrayUtils::incrementByteOffset(unsigned _byteSize, unsigned _byteOffsetPos
// byteOffset = 0; // byteOffset = 0;
// } // }
if (_byteOffsetPosition > 1) if (_byteOffsetPosition > 1)
m_context << solidity::swapInstruction(_byteOffsetPosition - 1); m_context << swapInstruction(_byteOffsetPosition - 1);
m_context << u256(_byteSize) << solidity::Instruction::ADD; m_context << u256(_byteSize) << Instruction::ADD;
if (_byteOffsetPosition > 1) if (_byteOffsetPosition > 1)
m_context << solidity::swapInstruction(_byteOffsetPosition - 1); m_context << swapInstruction(_byteOffsetPosition - 1);
// compute, X := (byteOffset + byteSize - 1) / 32, should be 1 iff byteOffset + bytesize > 32 // compute, X := (byteOffset + byteSize - 1) / 32, should be 1 iff byteOffset + bytesize > 32
m_context m_context
<< u256(32) << solidity::dupInstruction(1 + _byteOffsetPosition) << u256(_byteSize - 1) << u256(32) << dupInstruction(1 + _byteOffsetPosition) << u256(_byteSize - 1)
<< solidity::Instruction::ADD << solidity::Instruction::DIV; << Instruction::ADD << Instruction::DIV;
// increment storage offset if X == 1 (just add X to it) // increment storage offset if X == 1 (just add X to it)
// stack: X // stack: X
m_context m_context
<< solidity::swapInstruction(_storageOffsetPosition) << solidity::dupInstruction(_storageOffsetPosition + 1) << swapInstruction(_storageOffsetPosition) << dupInstruction(_storageOffsetPosition + 1)
<< solidity::Instruction::ADD << solidity::swapInstruction(_storageOffsetPosition); << Instruction::ADD << swapInstruction(_storageOffsetPosition);
// stack: X // stack: X
// set source_byte_offset to zero if X == 1 (using source_byte_offset *= 1 - X) // set source_byte_offset to zero if X == 1 (using source_byte_offset *= 1 - X)
m_context << u256(1) << solidity::Instruction::SUB; m_context << u256(1) << Instruction::SUB;
// stack: 1 - X // stack: 1 - X
if (_byteOffsetPosition == 1) if (_byteOffsetPosition == 1)
m_context << solidity::Instruction::MUL; m_context << Instruction::MUL;
else else
m_context m_context
<< solidity::dupInstruction(_byteOffsetPosition + 1) << solidity::Instruction::MUL << dupInstruction(_byteOffsetPosition + 1) << Instruction::MUL
<< solidity::swapInstruction(_byteOffsetPosition) << solidity::Instruction::POP; << swapInstruction(_byteOffsetPosition) << Instruction::POP;
} }

View File

@ -92,8 +92,8 @@ void Compiler::compileClone(
m_runtimeSub = size_t(runtimeSub.data()); m_runtimeSub = size_t(runtimeSub.data());
// stack contains sub size // stack contains sub size
m_context << solidity::Instruction::DUP1 << runtimeSub << u256(0) << solidity::Instruction::CODECOPY; m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY;
m_context << u256(0) << solidity::Instruction::RETURN; m_context << u256(0) << Instruction::RETURN;
appendFunctionsWithoutCode(); appendFunctionsWithoutCode();
@ -164,8 +164,8 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
m_runtimeSub = size_t(runtimeSub.data()); m_runtimeSub = size_t(runtimeSub.data());
// stack contains sub size // stack contains sub size
m_context << solidity::Instruction::DUP1 << runtimeSub << u256(0) << solidity::Instruction::CODECOPY; m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY;
m_context << u256(0) << solidity::Instruction::RETURN; m_context << u256(0) << Instruction::RETURN;
// note that we have to include the functions again because of absolute jump labels // note that we have to include the functions again because of absolute jump labels
appendFunctionsWithoutCode(); appendFunctionsWithoutCode();
@ -208,15 +208,15 @@ void Compiler::appendConstructor(FunctionDefinition const& _constructor)
// argument size is dynamic, use CODESIZE to determine it // argument size is dynamic, use CODESIZE to determine it
m_context.appendProgramSize(); // program itself m_context.appendProgramSize(); // program itself
// CODESIZE is program plus manually added arguments // CODESIZE is program plus manually added arguments
m_context << solidity::Instruction::CODESIZE << solidity::Instruction::SUB; m_context << Instruction::CODESIZE << Instruction::SUB;
} }
else else
m_context << u256(argumentSize); m_context << u256(argumentSize);
// stack: <memptr> <argument size> // stack: <memptr> <argument size>
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
m_context.appendProgramSize(); m_context.appendProgramSize();
m_context << solidity::Instruction::DUP4 << solidity::Instruction::CODECOPY; m_context << Instruction::DUP4 << Instruction::CODECOPY;
m_context << solidity::Instruction::DUP2 << solidity::Instruction::ADD; m_context << Instruction::DUP2 << Instruction::ADD;
CompilerUtils(m_context).storeFreeMemoryPointer(); CompilerUtils(m_context).storeFreeMemoryPointer();
// stack: <memptr> // stack: <memptr>
appendCalldataUnpacker(FunctionType(_constructor).parameterTypes(), true); appendCalldataUnpacker(FunctionType(_constructor).parameterTypes(), true);
@ -235,7 +235,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
// ether with constant gas // ether with constant gas
if (interfaceFunctions.size() > 5 || fallback) if (interfaceFunctions.size() > 5 || fallback)
{ {
m_context << solidity::Instruction::CALLDATASIZE << solidity::Instruction::ISZERO; m_context << Instruction::CALLDATASIZE << Instruction::ISZERO;
m_context.appendConditionalJumpTo(notFound); m_context.appendConditionalJumpTo(notFound);
} }
@ -247,7 +247,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
for (auto const& it: interfaceFunctions) for (auto const& it: interfaceFunctions)
{ {
callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag())); callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag()));
m_context << solidity::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << solidity::Instruction::EQ; m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << Instruction::EQ;
m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first)); m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first));
} }
m_context.appendJumpTo(notFound); m_context.appendJumpTo(notFound);
@ -264,7 +264,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
// Reject invalid library calls and ether sent to a library. // Reject invalid library calls and ether sent to a library.
m_context.appendJumpTo(m_context.errorTag()); m_context.appendJumpTo(m_context.errorTag());
else else
m_context << solidity::Instruction::STOP; // function not found m_context << Instruction::STOP; // function not found
for (auto const& it: interfaceFunctions) for (auto const& it: interfaceFunctions)
{ {
@ -288,7 +288,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
//@todo this does not yet support nested dynamic arrays //@todo this does not yet support nested dynamic arrays
// Retain the offset pointer as base_offset, the point from which the data offsets are computed. // Retain the offset pointer as base_offset, the point from which the data offsets are computed.
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
for (TypePointer const& parameterType: _typeParameters) for (TypePointer const& parameterType: _typeParameters)
{ {
// stack: v1 v2 ... v(k-1) base_offset current_offset // stack: v1 v2 ... v(k-1) base_offset current_offset
@ -309,15 +309,15 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
if (arrayType.isDynamicallySized()) if (arrayType.isDynamicallySized())
{ {
// compute data pointer // compute data pointer
m_context << solidity::Instruction::DUP1 << solidity::Instruction::MLOAD; m_context << Instruction::DUP1 << Instruction::MLOAD;
m_context << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << Instruction::DUP3 << Instruction::ADD;
m_context << solidity::Instruction::SWAP2 << solidity::Instruction::SWAP1; m_context << Instruction::SWAP2 << Instruction::SWAP1;
m_context << u256(0x20) << solidity::Instruction::ADD; m_context << u256(0x20) << Instruction::ADD;
} }
else else
{ {
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
m_context << u256(arrayType.calldataEncodedSize(true)) << solidity::Instruction::ADD; m_context << u256(arrayType.calldataEncodedSize(true)) << Instruction::ADD;
} }
} }
else else
@ -329,19 +329,19 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
// put on stack: data_pointer length // put on stack: data_pointer length
CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory); CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory);
// stack: base_offset data_offset next_pointer // stack: base_offset data_offset next_pointer
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << Instruction::SWAP1 << Instruction::DUP3 << Instruction::ADD;
// stack: base_offset next_pointer data_pointer // stack: base_offset next_pointer data_pointer
// retrieve length // retrieve length
CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true);
// stack: base_offset next_pointer length data_pointer // stack: base_offset next_pointer length data_pointer
m_context << solidity::Instruction::SWAP2; m_context << Instruction::SWAP2;
// stack: base_offset data_pointer length next_pointer // stack: base_offset data_pointer length next_pointer
} }
else else
{ {
// leave the pointer on the stack // leave the pointer on the stack
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
m_context << u256(calldataType->calldataEncodedSize()) << solidity::Instruction::ADD; m_context << u256(calldataType->calldataEncodedSize()) << Instruction::ADD;
} }
if (arrayType.location() == DataLocation::Memory) if (arrayType.location() == DataLocation::Memory)
{ {
@ -355,7 +355,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
} }
// move base_offset up // move base_offset up
CompilerUtils(m_context).moveToStackTop(1 + arrayType.sizeOnStack()); CompilerUtils(m_context).moveToStackTop(1 + arrayType.sizeOnStack());
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
} }
} }
else else
@ -363,18 +363,18 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString());
CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true); CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true);
CompilerUtils(m_context).moveToStackTop(1 + type->sizeOnStack()); CompilerUtils(m_context).moveToStackTop(1 + type->sizeOnStack());
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
} }
// stack: v1 v2 ... v(k-1) v(k) base_offset mem_offset // stack: v1 v2 ... v(k-1) v(k) base_offset mem_offset
} }
m_context << solidity::Instruction::POP << solidity::Instruction::POP; m_context << Instruction::POP << Instruction::POP;
} }
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary) void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary)
{ {
CompilerUtils utils(m_context); CompilerUtils utils(m_context);
if (_typeParameters.empty()) if (_typeParameters.empty())
m_context << solidity::Instruction::STOP; m_context << Instruction::STOP;
else else
{ {
utils.fetchFreeMemoryPointer(); utils.fetchFreeMemoryPointer();
@ -382,7 +382,7 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool
// its data to add the needed parts and we avoid a memory copy. // its data to add the needed parts and we avoid a memory copy.
utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary); utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary);
utils.toSizeAfterFreeMemoryPointer(); utils.toSizeAfterFreeMemoryPointer();
m_context << solidity::Instruction::RETURN; m_context << Instruction::RETURN;
} }
} }
@ -476,12 +476,12 @@ bool Compiler::visit(FunctionDefinition const& _function)
while (stackLayout.back() != int(stackLayout.size() - 1)) while (stackLayout.back() != int(stackLayout.size() - 1))
if (stackLayout.back() < 0) if (stackLayout.back() < 0)
{ {
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
stackLayout.pop_back(); stackLayout.pop_back();
} }
else else
{ {
m_context << solidity::swapInstruction(stackLayout.size() - stackLayout.back() - 1); m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1);
swap(stackLayout[stackLayout.back()], stackLayout.back()); swap(stackLayout[stackLayout.back()], stackLayout.back());
} }
//@todo assert that everything is in place now //@todo assert that everything is in place now
@ -532,7 +532,7 @@ bool Compiler::visit(InlineAssembly const& _inlineAssembly)
errinfo_comment("Stack too deep, try removing local variables.") errinfo_comment("Stack too deep, try removing local variables.")
); );
for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i) for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i)
_assembly.append(solidity::dupInstruction(stackDiff)); _assembly.append(dupInstruction(stackDiff));
} }
else else
{ {
@ -572,8 +572,8 @@ bool Compiler::visit(InlineAssembly const& _inlineAssembly)
errinfo_comment("Stack too deep, try removing local variables.") errinfo_comment("Stack too deep, try removing local variables.")
); );
for (unsigned i = 0; i < size; ++i) { for (unsigned i = 0; i < size; ++i) {
_assembly.append(solidity::swapInstruction(stackDiff)); _assembly.append(swapInstruction(stackDiff));
_assembly.append(solidity::Instruction::POP); _assembly.append(Instruction::POP);
} }
} }
return true; return true;
@ -588,7 +588,7 @@ bool Compiler::visit(IfStatement const& _ifStatement)
StackHeightChecker checker(m_context); StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, _ifStatement); CompilerContext::LocationSetter locationSetter(m_context, _ifStatement);
compileExpression(_ifStatement.condition()); compileExpression(_ifStatement.condition());
m_context << solidity::Instruction::ISZERO; m_context << Instruction::ISZERO;
eth::AssemblyItem falseTag = m_context.appendConditionalJump(); eth::AssemblyItem falseTag = m_context.appendConditionalJump();
eth::AssemblyItem endTag = falseTag; eth::AssemblyItem endTag = falseTag;
_ifStatement.trueStatement().accept(*this); _ifStatement.trueStatement().accept(*this);
@ -615,7 +615,7 @@ bool Compiler::visit(WhileStatement const& _whileStatement)
m_context << loopStart; m_context << loopStart;
compileExpression(_whileStatement.condition()); compileExpression(_whileStatement.condition());
m_context << solidity::Instruction::ISZERO; m_context << Instruction::ISZERO;
m_context.appendConditionalJumpTo(loopEnd); m_context.appendConditionalJumpTo(loopEnd);
_whileStatement.body().accept(*this); _whileStatement.body().accept(*this);
@ -649,7 +649,7 @@ bool Compiler::visit(ForStatement const& _forStatement)
if (_forStatement.condition()) if (_forStatement.condition())
{ {
compileExpression(*_forStatement.condition()); compileExpression(*_forStatement.condition());
m_context << solidity::Instruction::ISZERO; m_context << Instruction::ISZERO;
m_context.appendConditionalJumpTo(loopEnd); m_context.appendConditionalJumpTo(loopEnd);
} }
@ -710,7 +710,7 @@ bool Compiler::visit(Return const& _return)
CompilerUtils(m_context).moveToStackVariable(*retVariable); CompilerUtils(m_context).moveToStackVariable(*retVariable);
} }
for (unsigned i = 0; i < m_stackCleanupForReturn; ++i) for (unsigned i = 0; i < m_stackCleanupForReturn; ++i)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
m_context.appendJumpTo(m_returnTag); m_context.appendJumpTo(m_returnTag);
m_context.adjustStackOffset(m_stackCleanupForReturn); m_context.adjustStackOffset(m_stackCleanupForReturn);
return false; return false;
@ -831,7 +831,7 @@ void Compiler::appendModifierOrFunctionCode()
modifier.body().accept(*this); modifier.body().accept(*this);
for (unsigned i = 0; i < c_stackSurplus; ++i) for (unsigned i = 0; i < c_stackSurplus; ++i)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
m_stackCleanupForReturn -= c_stackSurplus; m_stackCleanupForReturn -= c_stackSurplus;
} }
} }
@ -855,20 +855,20 @@ eth::Assembly Compiler::cloneRuntime()
{ {
eth::EVMSchedule schedule; eth::EVMSchedule schedule;
eth::Assembly a; eth::Assembly a;
a << solidity::Instruction::CALLDATASIZE; a << Instruction::CALLDATASIZE;
a << u256(0) << solidity::Instruction::DUP1 << solidity::Instruction::CALLDATACOPY; a << u256(0) << Instruction::DUP1 << Instruction::CALLDATACOPY;
//@todo adjust for larger return values, make this dynamic. //@todo adjust for larger return values, make this dynamic.
a << u256(0x20) << u256(0) << solidity::Instruction::CALLDATASIZE; a << u256(0x20) << u256(0) << Instruction::CALLDATASIZE;
a << u256(0); a << u256(0);
// this is the address which has to be substituted by the linker. // this is the address which has to be substituted by the linker.
//@todo implement as special "marker" AssemblyItem. //@todo implement as special "marker" AssemblyItem.
a << u256("0xcafecafecafecafecafecafecafecafecafecafe"); a << u256("0xcafecafecafecafecafecafecafecafecafecafe");
a << u256(schedule.callGas + 10) << solidity::Instruction::GAS << solidity::Instruction::SUB; a << u256(schedule.callGas + 10) << Instruction::GAS << Instruction::SUB;
a << solidity::Instruction::DELEGATECALL; a << Instruction::DELEGATECALL;
//Propagate error condition (if DELEGATECALL pushes 0 on stack). //Propagate error condition (if DELEGATECALL pushes 0 on stack).
a << solidity::Instruction::ISZERO; a << Instruction::ISZERO;
a.appendJumpI(a.errorTag()); a.appendJumpI(a.errorTag());
//@todo adjust for larger return values, make this dynamic. //@todo adjust for larger return values, make this dynamic.
a << u256(0x20) << u256(0) << solidity::Instruction::RETURN; a << u256(0x20) << u256(0) << Instruction::RETURN;
return a; return a;
} }

View File

@ -166,7 +166,7 @@ pair<u256, unsigned> CompilerContext::storageLocationOfVariable(const Declaratio
CompilerContext& CompilerContext::appendJump(eth::AssemblyItem::JumpType _jumpType) CompilerContext& CompilerContext::appendJump(eth::AssemblyItem::JumpType _jumpType)
{ {
eth::AssemblyItem item(solidity::Instruction::JUMP); eth::AssemblyItem item(Instruction::JUMP);
item.setJumpType(_jumpType); item.setJumpType(_jumpType);
return *this << item; return *this << item;
} }
@ -182,7 +182,7 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node)
void CompilerContext::injectVersionStampIntoSub(size_t _subIndex) void CompilerContext::injectVersionStampIntoSub(size_t _subIndex)
{ {
eth::Assembly& sub = m_asm.sub(_subIndex); eth::Assembly& sub = m_asm.sub(_subIndex);
sub.injectStart(solidity::Instruction::POP); sub.injectStart(Instruction::POP);
sub.injectStart(fromBigEndian<u256>(binaryVersion())); sub.injectStart(fromBigEndian<u256>(binaryVersion()));
} }

View File

@ -126,7 +126,7 @@ public:
/// Append elements to the current instruction list and adjust @a m_stackOffset. /// Append elements to the current instruction list and adjust @a m_stackOffset.
CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; } CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; }
CompilerContext& operator<<(solidity::Instruction _instruction) { m_asm.append(_instruction); return *this; } CompilerContext& operator<<(Instruction _instruction) { m_asm.append(_instruction); return *this; }
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; }
CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; }

View File

@ -45,26 +45,26 @@ void CompilerUtils::initialiseFreeMemoryPointer()
void CompilerUtils::fetchFreeMemoryPointer() void CompilerUtils::fetchFreeMemoryPointer()
{ {
m_context << u256(freeMemoryPointer) << solidity::Instruction::MLOAD; m_context << u256(freeMemoryPointer) << Instruction::MLOAD;
} }
void CompilerUtils::storeFreeMemoryPointer() void CompilerUtils::storeFreeMemoryPointer()
{ {
m_context << u256(freeMemoryPointer) << solidity::Instruction::MSTORE; m_context << u256(freeMemoryPointer) << Instruction::MSTORE;
} }
void CompilerUtils::allocateMemory() void CompilerUtils::allocateMemory()
{ {
fetchFreeMemoryPointer(); fetchFreeMemoryPointer();
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::DUP2 << solidity::Instruction::ADD; m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD;
storeFreeMemoryPointer(); storeFreeMemoryPointer();
} }
void CompilerUtils::toSizeAfterFreeMemoryPointer() void CompilerUtils::toSizeAfterFreeMemoryPointer()
{ {
fetchFreeMemoryPointer(); fetchFreeMemoryPointer();
m_context << solidity::Instruction::DUP1 << solidity::Instruction::SWAP2 << solidity::Instruction::SUB; m_context << Instruction::DUP1 << Instruction::SWAP2 << Instruction::SUB;
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
} }
unsigned CompilerUtils::loadFromMemory( unsigned CompilerUtils::loadFromMemory(
@ -87,7 +87,7 @@ void CompilerUtils::loadFromMemoryDynamic(
) )
{ {
if (_keepUpdatedMemoryOffset) if (_keepUpdatedMemoryOffset)
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type)) if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
{ {
@ -95,7 +95,7 @@ void CompilerUtils::loadFromMemoryDynamic(
solAssert(!_fromCalldata, ""); solAssert(!_fromCalldata, "");
solAssert(_padToWordBoundaries, ""); solAssert(_padToWordBoundaries, "");
if (_keepUpdatedMemoryOffset) if (_keepUpdatedMemoryOffset)
m_context << arrayType->memorySize() << solidity::Instruction::ADD; m_context << arrayType->memorySize() << Instruction::ADD;
} }
else else
{ {
@ -104,7 +104,7 @@ void CompilerUtils::loadFromMemoryDynamic(
{ {
// update memory counter // update memory counter
moveToStackTop(_type.sizeOnStack()); moveToStackTop(_type.sizeOnStack());
m_context << u256(numBytes) << solidity::Instruction::ADD; m_context << u256(numBytes) << Instruction::ADD;
} }
} }
} }
@ -113,7 +113,7 @@ void CompilerUtils::storeInMemory(unsigned _offset)
{ {
unsigned numBytes = prepareMemoryStore(IntegerType(256), true); unsigned numBytes = prepareMemoryStore(IntegerType(256), true);
if (numBytes > 0) if (numBytes > 0)
m_context << u256(_offset) << solidity::Instruction::MSTORE; m_context << u256(_offset) << Instruction::MSTORE;
} }
void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries) void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries)
@ -125,13 +125,13 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
} }
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type)) else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
{ {
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
storeStringData(bytesConstRef(str->value())); storeStringData(bytesConstRef(str->value()));
if (_padToWordBoundaries) if (_padToWordBoundaries)
m_context << u256(((str->value().size() + 31) / 32) * 32); m_context << u256(((str->value().size() + 31) / 32) * 32);
else else
m_context << u256(str->value().size()); m_context << u256(str->value().size());
m_context << solidity::Instruction::ADD; m_context << Instruction::ADD;
} }
else else
{ {
@ -142,8 +142,8 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
_type.sizeOnStack() == 1, _type.sizeOnStack() == 1,
"Memory store of types with stack size != 1 not implemented." "Memory store of types with stack size != 1 not implemented."
); );
m_context << solidity::Instruction::DUP2 << solidity::Instruction::MSTORE; m_context << Instruction::DUP2 << Instruction::MSTORE;
m_context << u256(numBytes) << solidity::Instruction::ADD; m_context << u256(numBytes) << Instruction::ADD;
} }
} }
} }
@ -168,7 +168,7 @@ void CompilerUtils::encodeToMemory(
// of the ith dynamic parameter, which is filled once the dynamic parts are processed. // of the ith dynamic parameter, which is filled once the dynamic parts are processed.
// store memory start pointer // store memory start pointer
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
unsigned argSize = CompilerUtils::sizeOnStack(_givenTypes); unsigned argSize = CompilerUtils::sizeOnStack(_givenTypes);
unsigned stackPos = 0; // advances through the argument values unsigned stackPos = 0; // advances through the argument values
@ -180,7 +180,7 @@ void CompilerUtils::encodeToMemory(
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace) if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
{ {
// leave end_of_mem as dyn head pointer // leave end_of_mem as dyn head pointer
m_context << solidity::Instruction::DUP1 << u256(32) << solidity::Instruction::ADD; m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
dynPointers++; dynPointers++;
} }
else else
@ -222,10 +222,10 @@ void CompilerUtils::encodeToMemory(
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace) if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
{ {
// copy tail pointer (=mem_end - mem_start) to memory // copy tail pointer (=mem_end - mem_start) to memory
m_context << solidity::dupInstruction(2 + dynPointers) << solidity::Instruction::DUP2; m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2;
m_context << solidity::Instruction::SUB; m_context << Instruction::SUB;
m_context << solidity::dupInstruction(2 + dynPointers - thisDynPointer); m_context << dupInstruction(2 + dynPointers - thisDynPointer);
m_context << solidity::Instruction::MSTORE; m_context << Instruction::MSTORE;
// stack: ... <end_of_mem> // stack: ... <end_of_mem>
if (_givenTypes[i]->category() == Type::Category::StringLiteral) if (_givenTypes[i]->category() == Type::Category::StringLiteral)
{ {
@ -243,13 +243,13 @@ void CompilerUtils::encodeToMemory(
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.sizeOnStack()); copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.sizeOnStack());
// stack: ... <end_of_mem> <value...> // stack: ... <end_of_mem> <value...>
// copy length to memory // copy length to memory
m_context << solidity::dupInstruction(1 + arrayType.sizeOnStack()); m_context << dupInstruction(1 + arrayType.sizeOnStack());
ArrayUtils(m_context).retrieveLength(arrayType, 1); ArrayUtils(m_context).retrieveLength(arrayType, 1);
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length> // stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
storeInMemoryDynamic(IntegerType(256), true); storeInMemoryDynamic(IntegerType(256), true);
// stack: ... <end_of_mem> <value...> <end_of_mem''> // stack: ... <end_of_mem> <value...> <end_of_mem''>
// copy the new memory pointer // copy the new memory pointer
m_context << solidity::swapInstruction(arrayType.sizeOnStack() + 1) << solidity::Instruction::POP; m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP;
// stack: ... <end_of_mem''> <value...> // stack: ... <end_of_mem''> <value...>
// copy data part // copy data part
ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries); ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries);
@ -262,7 +262,7 @@ void CompilerUtils::encodeToMemory(
} }
// remove unneeded stack elements (and retain memory pointer) // remove unneeded stack elements (and retain memory pointer)
m_context << solidity::swapInstruction(argSize + dynPointers + 1); m_context << swapInstruction(argSize + dynPointers + 1);
popStackSlots(argSize + dynPointers + 1); popStackSlots(argSize + dynPointers + 1);
} }
@ -272,11 +272,11 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
m_context << repeat; m_context << repeat;
pushZeroValue(*_type.baseType()); pushZeroValue(*_type.baseType());
storeInMemoryDynamic(*_type.baseType()); storeInMemoryDynamic(*_type.baseType());
m_context << solidity::Instruction::SWAP1 << u256(1) << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1 << u256(1) << Instruction::SWAP1;
m_context << solidity::Instruction::SUB << solidity::Instruction::SWAP1; m_context << Instruction::SUB << Instruction::SWAP1;
m_context << solidity::Instruction::DUP2; m_context << Instruction::DUP2;
m_context.appendConditionalJumpTo(repeat); m_context.appendConditionalJumpTo(repeat);
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::POP; m_context << Instruction::SWAP1 << Instruction::POP;
} }
void CompilerUtils::memoryCopy() void CompilerUtils::memoryCopy()
@ -284,16 +284,16 @@ void CompilerUtils::memoryCopy()
// Stack here: size target source // Stack here: size target source
// stack for call: outsize target size source value contract gas // stack for call: outsize target size source value contract gas
//@TODO do not use ::CALL if less than 32 bytes? //@TODO do not use ::CALL if less than 32 bytes?
m_context << solidity::Instruction::DUP3 << solidity::Instruction::SWAP1; m_context << Instruction::DUP3 << Instruction::SWAP1;
m_context << u256(0) << u256(identityContractAddress); m_context << u256(0) << u256(identityContractAddress);
// compute gas costs // compute gas costs
m_context << u256(32) << solidity::Instruction::DUP5 << u256(31) << solidity::Instruction::ADD; m_context << u256(32) << Instruction::DUP5 << u256(31) << Instruction::ADD;
static unsigned c_identityGas = 3; static unsigned c_identityGas = 3;
static unsigned c_identityWordGas = 15; static unsigned c_identityWordGas = 15;
m_context << solidity::Instruction::DIV << u256(c_identityWordGas) << solidity::Instruction::MUL; m_context << Instruction::DIV << u256(c_identityWordGas) << Instruction::MUL;
m_context << u256(c_identityGas) << solidity::Instruction::ADD; m_context << u256(c_identityGas) << Instruction::ADD;
m_context << solidity::Instruction::CALL; m_context << Instruction::CALL;
m_context << solidity::Instruction::POP; // ignore return value m_context << Instruction::POP; // ignore return value
} }
void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded)
@ -317,7 +317,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
// conversion from bytes to integer. no need to clean the high bit // conversion from bytes to integer. no need to clean the high bit
// only to shift right because of opposite alignment // only to shift right because of opposite alignment
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType); IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
m_context << (u256(1) << (256 - typeOnStack.numBytes() * 8)) << solidity::Instruction::SWAP1 << solidity::Instruction::DIV; m_context << (u256(1) << (256 - typeOnStack.numBytes() * 8)) << Instruction::SWAP1 << Instruction::DIV;
if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8) if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8)
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded); convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
} }
@ -329,12 +329,12 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
if (targetType.numBytes() < typeOnStack.numBytes()) if (targetType.numBytes() < typeOnStack.numBytes())
{ {
if (targetType.numBytes() == 0) if (targetType.numBytes() == 0)
m_context << solidity::Instruction::DUP1 << solidity::Instruction::XOR; m_context << Instruction::DUP1 << Instruction::XOR;
else else
{ {
m_context << (u256(1) << (256 - targetType.numBytes() * 8)); m_context << (u256(1) << (256 - targetType.numBytes() * 8));
m_context << solidity::Instruction::DUP1 << solidity::Instruction::SWAP2; m_context << Instruction::DUP1 << Instruction::SWAP2;
m_context << solidity::Instruction::DIV << solidity::Instruction::MUL; m_context << Instruction::DIV << Instruction::MUL;
} }
} }
} }
@ -356,7 +356,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack)) if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
if (targetBytesType.numBytes() * 8 > typeOnStack->numBits()) if (targetBytesType.numBytes() * 8 > typeOnStack->numBits())
cleanHigherOrderBits(*typeOnStack); cleanHigherOrderBits(*typeOnStack);
m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << solidity::Instruction::MUL; m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << Instruction::MUL;
} }
else if (targetTypeCategory == Type::Category::Enum) else if (targetTypeCategory == Type::Category::Enum)
// just clean // just clean
@ -406,7 +406,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
m_context << storageSize; m_context << storageSize;
allocateMemory(); allocateMemory();
// stack: mempos // stack: mempos
m_context << solidity::Instruction::DUP1 << u256(data.size()); m_context << Instruction::DUP1 << u256(data.size());
storeInMemoryDynamic(IntegerType(256)); storeInMemoryDynamic(IntegerType(256));
// stack: mempos datapos // stack: mempos datapos
storeStringData(data); storeStringData(data);
@ -445,18 +445,18 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
// allocate memory // allocate memory
// stack: <source ref> (variably sized) <length> // stack: <source ref> (variably sized) <length>
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
ArrayUtils(m_context).convertLengthToSize(targetType, true); ArrayUtils(m_context).convertLengthToSize(targetType, true);
// stack: <source ref> (variably sized) <length> <size> // stack: <source ref> (variably sized) <length> <size>
if (targetType.isDynamicallySized()) if (targetType.isDynamicallySized())
m_context << u256(0x20) << solidity::Instruction::ADD; m_context << u256(0x20) << Instruction::ADD;
allocateMemory(); allocateMemory();
// stack: <source ref> (variably sized) <length> <mem start> // stack: <source ref> (variably sized) <length> <mem start>
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
moveIntoStack(2 + stackSize); moveIntoStack(2 + stackSize);
if (targetType.isDynamicallySized()) if (targetType.isDynamicallySized())
{ {
m_context << solidity::Instruction::DUP2; m_context << Instruction::DUP2;
storeInMemoryDynamic(IntegerType(256)); storeInMemoryDynamic(IntegerType(256));
} }
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos> // stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
@ -468,12 +468,12 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
} }
else else
{ {
m_context << u256(0) << solidity::Instruction::SWAP1; m_context << u256(0) << Instruction::SWAP1;
// stack: <mem start> <source ref> (variably sized) <length> <counter> <mem data pos> // stack: <mem start> <source ref> (variably sized) <length> <counter> <mem data pos>
auto repeat = m_context.newTag(); auto repeat = m_context.newTag();
m_context << repeat; m_context << repeat;
m_context << solidity::Instruction::DUP3 << solidity::Instruction::DUP3; m_context << Instruction::DUP3 << Instruction::DUP3;
m_context << solidity::Instruction::LT << solidity::Instruction::ISZERO; m_context << Instruction::LT << Instruction::ISZERO;
auto loopEnd = m_context.appendConditionalJump(); auto loopEnd = m_context.appendConditionalJump();
copyToStackTop(3 + stackSize, stackSize); copyToStackTop(3 + stackSize, stackSize);
copyToStackTop(2 + stackSize, 1); copyToStackTop(2 + stackSize, 1);
@ -482,11 +482,11 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
StorageItem(m_context, *typeOnStack.baseType()).retrieveValue(SourceLocation(), true); StorageItem(m_context, *typeOnStack.baseType()).retrieveValue(SourceLocation(), true);
convertType(*typeOnStack.baseType(), *targetType.baseType(), _cleanupNeeded); convertType(*typeOnStack.baseType(), *targetType.baseType(), _cleanupNeeded);
storeInMemoryDynamic(*targetType.baseType(), true); storeInMemoryDynamic(*targetType.baseType(), true);
m_context << solidity::Instruction::SWAP1 << u256(1) << solidity::Instruction::ADD; m_context << Instruction::SWAP1 << u256(1) << Instruction::ADD;
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
m_context.appendJumpTo(repeat); m_context.appendJumpTo(repeat);
m_context << loopEnd; m_context << loopEnd;
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos updated> // stack: <mem start> <source ref> (variably sized) <length> <mem data pos updated>
popStackSlots(2 + stackSize); popStackSlots(2 + stackSize);
@ -540,14 +540,14 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
// stack: <source ref> // stack: <source ref>
m_context << typeOnStack.memorySize(); m_context << typeOnStack.memorySize();
allocateMemory(); allocateMemory();
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::DUP2; m_context << Instruction::SWAP1 << Instruction::DUP2;
// stack: <memory ptr> <source ref> <memory ptr> // stack: <memory ptr> <source ref> <memory ptr>
for (auto const& member: typeOnStack.members(nullptr)) for (auto const& member: typeOnStack.members(nullptr))
{ {
if (!member.type->canLiveOutsideStorage()) if (!member.type->canLiveOutsideStorage())
continue; continue;
pair<u256, unsigned> const& offsets = typeOnStack.storageOffsetsOfMember(member.name); pair<u256, unsigned> const& offsets = typeOnStack.storageOffsetsOfMember(member.name);
m_context << offsets.first << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
m_context << u256(offsets.second); m_context << u256(offsets.second);
StorageItem(m_context, *member.type).retrieveValue(SourceLocation(), true); StorageItem(m_context, *member.type).retrieveValue(SourceLocation(), true);
TypePointer targetMemberType = targetType.memberType(member.name); TypePointer targetMemberType = targetType.memberType(member.name);
@ -555,7 +555,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
convertType(*member.type, *targetMemberType, true); convertType(*member.type, *targetMemberType, true);
storeInMemoryDynamic(*targetMemberType, true); storeInMemoryDynamic(*targetMemberType, true);
} }
m_context << solidity::Instruction::POP << solidity::Instruction::POP; m_context << Instruction::POP << Instruction::POP;
} }
break; break;
case DataLocation::CallData: case DataLocation::CallData:
@ -602,13 +602,13 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
// Move it back into its place. // Move it back into its place.
for (unsigned j = 0; j < min(sourceSize, targetSize); ++j) for (unsigned j = 0; j < min(sourceSize, targetSize); ++j)
m_context << m_context <<
solidity::swapInstruction(depth + targetSize - sourceSize) << swapInstruction(depth + targetSize - sourceSize) <<
solidity::Instruction::POP; Instruction::POP;
// Value shrank // Value shrank
for (unsigned j = targetSize; j < sourceSize; ++j) for (unsigned j = targetSize; j < sourceSize; ++j)
{ {
moveToStackTop(depth - 1, 1); moveToStackTop(depth - 1, 1);
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
// Value grew // Value grew
if (targetSize > sourceSize) if (targetSize > sourceSize)
@ -639,7 +639,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
m_context << u256(max(32u, _type.calldataEncodedSize())); m_context << u256(max(32u, _type.calldataEncodedSize()));
allocateMemory(); allocateMemory();
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
if (auto structType = dynamic_cast<StructType const*>(&_type)) if (auto structType = dynamic_cast<StructType const*>(&_type))
for (auto const& member: structType->members(nullptr)) for (auto const& member: structType->members(nullptr))
@ -657,7 +657,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
} }
else if (arrayType->length() > 0) else if (arrayType->length() > 0)
{ {
m_context << arrayType->length() << solidity::Instruction::SWAP1; m_context << arrayType->length() << Instruction::SWAP1;
// stack: items_to_do memory_pos // stack: items_to_do memory_pos
zeroInitialiseMemoryArray(*arrayType); zeroInitialiseMemoryArray(*arrayType);
// stack: updated_memory_pos // stack: updated_memory_pos
@ -667,7 +667,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
solAssert(false, "Requested initialisation for unknown type: " + _type.toString()); solAssert(false, "Requested initialisation for unknown type: " + _type.toString());
// remove the updated memory pointer // remove the updated memory pointer
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
@ -683,14 +683,14 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
errinfo_comment("Stack too deep, try removing local variables.") errinfo_comment("Stack too deep, try removing local variables.")
); );
for (unsigned i = 0; i < size; ++i) for (unsigned i = 0; i < size; ++i)
m_context << solidity::swapInstruction(stackPosition - size + 1) << solidity::Instruction::POP; m_context << swapInstruction(stackPosition - size + 1) << Instruction::POP;
} }
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize) void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
{ {
solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables."); solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables.");
for (unsigned i = 0; i < _itemSize; ++i) for (unsigned i = 0; i < _itemSize; ++i)
m_context << solidity::dupInstruction(_stackDepth); m_context << dupInstruction(_stackDepth);
} }
void CompilerUtils::moveToStackTop(unsigned _stackDepth, unsigned _itemSize) void CompilerUtils::moveToStackTop(unsigned _stackDepth, unsigned _itemSize)
@ -712,14 +712,14 @@ void CompilerUtils::rotateStackUp(unsigned _items)
{ {
solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables."); solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables.");
for (unsigned i = 1; i < _items; ++i) for (unsigned i = 1; i < _items; ++i)
m_context << solidity::swapInstruction(_items - i); m_context << swapInstruction(_items - i);
} }
void CompilerUtils::rotateStackDown(unsigned _items) void CompilerUtils::rotateStackDown(unsigned _items)
{ {
solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables."); solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables.");
for (unsigned i = 1; i < _items; ++i) for (unsigned i = 1; i < _items; ++i)
m_context << solidity::swapInstruction(i); m_context << swapInstruction(i);
} }
void CompilerUtils::popStackElement(Type const& _type) void CompilerUtils::popStackElement(Type const& _type)
@ -730,7 +730,7 @@ void CompilerUtils::popStackElement(Type const& _type)
void CompilerUtils::popStackSlots(size_t _amount) void CompilerUtils::popStackSlots(size_t _amount)
{ {
for (size_t i = 0; i < _amount; ++i) for (size_t i = 0; i < _amount; ++i)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _variableTypes) unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _variableTypes)
@ -744,7 +744,7 @@ unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _varia
void CompilerUtils::computeHashStatic() void CompilerUtils::computeHashStatic()
{ {
storeInMemory(0); storeInMemory(0);
m_context << u256(32) << u256(0) << solidity::Instruction::SHA3; m_context << u256(32) << u256(0) << Instruction::SHA3;
} }
void CompilerUtils::storeStringData(bytesConstRef _data) void CompilerUtils::storeStringData(bytesConstRef _data)
@ -758,14 +758,14 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft)); m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
storeInMemoryDynamic(IntegerType(256)); storeInMemoryDynamic(IntegerType(256));
} }
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
else else
{ {
// stack: mempos mempos_data // stack: mempos mempos_data
m_context.appendData(_data.toBytes()); m_context.appendData(_data.toBytes());
m_context << u256(_data.size()) << solidity::Instruction::SWAP2; m_context << u256(_data.size()) << Instruction::SWAP2;
m_context << solidity::Instruction::CODECOPY; m_context << Instruction::CODECOPY;
} }
} }
@ -774,18 +774,18 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries); unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries);
bool leftAligned = _type.category() == Type::Category::FixedBytes; bool leftAligned = _type.category() == Type::Category::FixedBytes;
if (numBytes == 0) if (numBytes == 0)
m_context << solidity::Instruction::POP << u256(0); m_context << Instruction::POP << u256(0);
else else
{ {
solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested."); solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
m_context << (_fromCalldata ? solidity::Instruction::CALLDATALOAD : solidity::Instruction::MLOAD); m_context << (_fromCalldata ? Instruction::CALLDATALOAD : Instruction::MLOAD);
if (numBytes != 32) if (numBytes != 32)
{ {
// add leading or trailing zeros by dividing/multiplying depending on alignment // add leading or trailing zeros by dividing/multiplying depending on alignment
u256 shiftFactor = u256(1) << ((32 - numBytes) * 8); u256 shiftFactor = u256(1) << ((32 - numBytes) * 8);
m_context << shiftFactor << solidity::Instruction::SWAP1 << solidity::Instruction::DIV; m_context << shiftFactor << Instruction::SWAP1 << Instruction::DIV;
if (leftAligned) if (leftAligned)
m_context << shiftFactor << solidity::Instruction::MUL; m_context << shiftFactor << Instruction::MUL;
} }
} }
@ -797,9 +797,9 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack)
if (_typeOnStack.numBits() == 256) if (_typeOnStack.numBits() == 256)
return; return;
else if (_typeOnStack.isSigned()) else if (_typeOnStack.isSigned())
m_context << u256(_typeOnStack.numBits() / 8 - 1) << solidity::Instruction::SIGNEXTEND; m_context << u256(_typeOnStack.numBits() / 8 - 1) << Instruction::SIGNEXTEND;
else else
m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << solidity::Instruction::AND; m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << Instruction::AND;
} }
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
@ -807,13 +807,13 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBou
unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries); unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries);
bool leftAligned = _type.category() == Type::Category::FixedBytes; bool leftAligned = _type.category() == Type::Category::FixedBytes;
if (numBytes == 0) if (numBytes == 0)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
else else
{ {
solAssert(numBytes <= 32, "Memory store of more than 32 bytes requested."); solAssert(numBytes <= 32, "Memory store of more than 32 bytes requested.");
if (numBytes != 32 && !leftAligned && !_padToWordBoundaries) if (numBytes != 32 && !leftAligned && !_padToWordBoundaries)
// shift the value accordingly before storing // shift the value accordingly before storing
m_context << (u256(1) << ((32 - numBytes) * 8)) << solidity::Instruction::MUL; m_context << (u256(1) << ((32 - numBytes) * 8)) << Instruction::MUL;
} }
return numBytes; return numBytes;
} }

View File

@ -75,7 +75,7 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co
utils().convertType(*_varDecl.value()->annotation().type, *_varDecl.annotation().type); utils().convertType(*_varDecl.value()->annotation().type, *_varDecl.annotation().type);
// append return // append return
m_context << solidity::dupInstruction(_varDecl.annotation().type->sizeOnStack() + 1); m_context << dupInstruction(_varDecl.annotation().type->sizeOnStack() + 1);
m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
} }
@ -103,13 +103,13 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
"Accessors for mapping with dynamically-sized keys not yet implemented." "Accessors for mapping with dynamically-sized keys not yet implemented."
); );
// pop offset // pop offset
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
// move storage offset to memory. // move storage offset to memory.
utils().storeInMemory(32); utils().storeInMemory(32);
// move key to memory. // move key to memory.
utils().copyToStackTop(paramTypes.size() - i, 1); utils().copyToStackTop(paramTypes.size() - i, 1);
utils().storeInMemory(0); utils().storeInMemory(0);
m_context << u256(64) << u256(0) << solidity::Instruction::SHA3; m_context << u256(64) << u256(0) << Instruction::SHA3;
// push offset // push offset
m_context << u256(0); m_context << u256(0);
returnType = mappingType->valueType(); returnType = mappingType->valueType();
@ -117,7 +117,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get())) else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
{ {
// pop offset // pop offset
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
utils().copyToStackTop(paramTypes.size() - i + 1, 1); utils().copyToStackTop(paramTypes.size() - i + 1, 1);
ArrayUtils(m_context).accessIndex(*arrayType); ArrayUtils(m_context).accessIndex(*arrayType);
returnType = arrayType->baseType(); returnType = arrayType->baseType();
@ -127,12 +127,12 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
} }
// remove index arguments. // remove index arguments.
if (paramTypes.size() == 1) if (paramTypes.size() == 1)
m_context << solidity::Instruction::SWAP2 << solidity::Instruction::POP << solidity::Instruction::SWAP1; m_context << Instruction::SWAP2 << Instruction::POP << Instruction::SWAP1;
else if (paramTypes.size() >= 2) else if (paramTypes.size() >= 2)
{ {
m_context << solidity::swapInstruction(paramTypes.size()); m_context << swapInstruction(paramTypes.size());
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
m_context << solidity::swapInstruction(paramTypes.size()); m_context << swapInstruction(paramTypes.size());
utils().popStackSlots(paramTypes.size() - 1); utils().popStackSlots(paramTypes.size() - 1);
} }
unsigned retSizeOnStack = 0; unsigned retSizeOnStack = 0;
@ -141,7 +141,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get())) if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get()))
{ {
// remove offset // remove offset
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
auto const& names = accessorType.returnParameterNames(); auto const& names = accessorType.returnParameterNames();
// struct // struct
for (size_t i = 0; i < names.size(); ++i) for (size_t i = 0; i < names.size(); ++i)
@ -152,7 +152,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
if (!arrayType->isByteArray()) if (!arrayType->isByteArray())
continue; continue;
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]); pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
m_context << solidity::Instruction::DUP1 << u256(offsets.first) << solidity::Instruction::ADD << u256(offsets.second); m_context << Instruction::DUP1 << u256(offsets.first) << Instruction::ADD << u256(offsets.second);
TypePointer memberType = structType->memberType(names[i]); TypePointer memberType = structType->memberType(names[i]);
StorageItem(m_context, *memberType).retrieveValue(SourceLocation(), true); StorageItem(m_context, *memberType).retrieveValue(SourceLocation(), true);
utils().convertType(*memberType, *returnTypes[i]); utils().convertType(*memberType, *returnTypes[i]);
@ -160,7 +160,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
retSizeOnStack += returnTypes[i]->sizeOnStack(); retSizeOnStack += returnTypes[i]->sizeOnStack();
} }
// remove slot // remove slot
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
else else
{ {
@ -172,7 +172,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
} }
solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), ""); solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), "");
solAssert(retSizeOnStack <= 15, "Stack is too deep."); solAssert(retSizeOnStack <= 15, "Stack is too deep.");
m_context << solidity::dupInstruction(retSizeOnStack + 1); m_context << dupInstruction(retSizeOnStack + 1);
m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
} }
@ -226,7 +226,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables."); solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables.");
// value [lvalue_ref] updated_value // value [lvalue_ref] updated_value
for (unsigned i = 0; i < itemSize; ++i) for (unsigned i = 0; i < itemSize; ++i)
m_context << solidity::swapInstruction(itemSize + lvalueSize) << solidity::Instruction::POP; m_context << swapInstruction(itemSize + lvalueSize) << Instruction::POP;
} }
} }
m_currentLValue->storeValue(*type, _assignment.location()); m_currentLValue->storeValue(*type, _assignment.location());
@ -243,7 +243,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array."); solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array.");
m_context << max(u256(32u), arrayType.memorySize()); m_context << max(u256(32u), arrayType.memorySize());
utils().allocateMemory(); utils().allocateMemory();
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
for (auto const& component: _tuple.components()) for (auto const& component: _tuple.components())
{ {
@ -252,7 +252,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
utils().storeInMemoryDynamic(*arrayType.baseType(), true); utils().storeInMemoryDynamic(*arrayType.baseType(), true);
} }
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
else else
{ {
@ -298,13 +298,13 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
switch (_unaryOperation.getOperator()) switch (_unaryOperation.getOperator())
{ {
case Token::Not: // ! case Token::Not: // !
m_context << solidity::Instruction::ISZERO; m_context << Instruction::ISZERO;
break; break;
case Token::BitNot: // ~ case Token::BitNot: // ~
m_context << solidity::Instruction::NOT; m_context << Instruction::NOT;
break; break;
case Token::After: // after case Token::After: // after
m_context << solidity::Instruction::TIMESTAMP << solidity::Instruction::ADD; m_context << Instruction::TIMESTAMP << Instruction::ADD;
break; break;
case Token::Delete: // delete case Token::Delete: // delete
solAssert(!!m_currentLValue, "LValue not retrieved."); solAssert(!!m_currentLValue, "LValue not retrieved.");
@ -319,20 +319,20 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
{ {
// store value for later // store value for later
solAssert(_unaryOperation.annotation().type->sizeOnStack() == 1, "Stack size != 1 not implemented."); solAssert(_unaryOperation.annotation().type->sizeOnStack() == 1, "Stack size != 1 not implemented.");
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
if (m_currentLValue->sizeOnStack() > 0) if (m_currentLValue->sizeOnStack() > 0)
for (unsigned i = 1 + m_currentLValue->sizeOnStack(); i > 0; --i) for (unsigned i = 1 + m_currentLValue->sizeOnStack(); i > 0; --i)
m_context << solidity::swapInstruction(i); m_context << swapInstruction(i);
} }
m_context << u256(1); m_context << u256(1);
if (_unaryOperation.getOperator() == Token::Inc) if (_unaryOperation.getOperator() == Token::Inc)
m_context << solidity::Instruction::ADD; m_context << Instruction::ADD;
else else
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::SUB; m_context << Instruction::SWAP1 << Instruction::SUB;
// Stack for prefix: [ref...] (*ref)+-1 // Stack for prefix: [ref...] (*ref)+-1
// Stack for postfix: *ref [ref...] (*ref)+-1 // Stack for postfix: *ref [ref...] (*ref)+-1
for (unsigned i = m_currentLValue->sizeOnStack(); i > 0; --i) for (unsigned i = m_currentLValue->sizeOnStack(); i > 0; --i)
m_context << solidity::swapInstruction(i); m_context << swapInstruction(i);
m_currentLValue->storeValue( m_currentLValue->storeValue(
*_unaryOperation.annotation().type, _unaryOperation.location(), *_unaryOperation.annotation().type, _unaryOperation.location(),
!_unaryOperation.isPrefixOperation()); !_unaryOperation.isPrefixOperation());
@ -342,7 +342,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
// unary add, so basically no-op // unary add, so basically no-op
break; break;
case Token::Sub: // - case Token::Sub: // -
m_context << u256(0) << solidity::Instruction::SUB; m_context << u256(0) << Instruction::SUB;
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " +
@ -452,7 +452,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << max(u256(32u), structType.memorySize()); m_context << max(u256(32u), structType.memorySize());
utils().allocateMemory(); utils().allocateMemory();
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
{ {
@ -460,7 +460,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().convertType(*arguments[i]->annotation().type, *functionType->parameterTypes()[i]); utils().convertType(*arguments[i]->annotation().type, *functionType->parameterTypes()[i]);
utils().storeInMemoryDynamic(*functionType->parameterTypes()[i]); utils().storeInMemoryDynamic(*functionType->parameterTypes()[i]);
} }
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
else else
{ {
@ -518,21 +518,21 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
// pushes size // pushes size
eth::AssemblyItem subroutine = m_context.addSubroutine(assembly); eth::AssemblyItem subroutine = m_context.addSubroutine(assembly);
m_context << solidity::Instruction::DUP1 << subroutine; m_context << Instruction::DUP1 << subroutine;
m_context << solidity::Instruction::DUP4 << solidity::Instruction::CODECOPY; m_context << Instruction::DUP4 << Instruction::CODECOPY;
m_context << solidity::Instruction::ADD; m_context << Instruction::ADD;
utils().encodeToMemory(argumentTypes, function.parameterTypes()); utils().encodeToMemory(argumentTypes, function.parameterTypes());
// now on stack: memory_end_ptr // now on stack: memory_end_ptr
// need: size, offset, endowment // need: size, offset, endowment
utils().toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
if (function.valueSet()) if (function.valueSet())
m_context << solidity::dupInstruction(3); m_context << dupInstruction(3);
else else
m_context << u256(0); m_context << u256(0);
m_context << solidity::Instruction::CREATE; m_context << Instruction::CREATE;
if (function.valueSet()) if (function.valueSet())
m_context << solidity::swapInstruction(1) << solidity::Instruction::POP; m_context << swapInstruction(1) << Instruction::POP;
break; break;
} }
case Location::SetGas: case Location::SetGas:
@ -546,9 +546,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// Its values of gasSet and valueSet is equal to the original function's though. // Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0); unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
if (stackDepth > 0) if (stackDepth > 0)
m_context << solidity::swapInstruction(stackDepth); m_context << swapInstruction(stackDepth);
if (function.gasSet()) if (function.gasSet())
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
break; break;
} }
case Location::SetValue: case Location::SetValue:
@ -557,7 +557,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// Note that function is not the original function, but the ".value" function. // Note that function is not the original function, but the ".value" function.
// Its values of gasSet and valueSet is equal to the original function's though. // Its values of gasSet and valueSet is equal to the original function's though.
if (function.valueSet()) if (function.valueSet())
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
arguments.front()->accept(*this); arguments.front()->accept(*this);
break; break;
case Location::Send: case Location::Send:
@ -586,7 +586,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case Location::Selfdestruct: case Location::Selfdestruct:
arguments.front()->accept(*this); arguments.front()->accept(*this);
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), true); utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), true);
m_context << solidity::Instruction::SUICIDE; m_context << Instruction::SUICIDE;
break; break;
case Location::SHA3: case Location::SHA3:
{ {
@ -599,7 +599,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true); utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true);
utils().toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
m_context << solidity::Instruction::SHA3; m_context << Instruction::SHA3;
break; break;
} }
case Location::Log0: case Location::Log0:
@ -622,7 +622,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
false, false,
true); true);
utils().toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
m_context << solidity::logInstruction(logNumber); m_context << logInstruction(logNumber);
break; break;
} }
case Location::Event: case Location::Event:
@ -646,7 +646,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
true true
); );
utils().toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
m_context << solidity::Instruction::SHA3; m_context << Instruction::SHA3;
} }
else else
utils().convertType( utils().convertType(
@ -676,14 +676,14 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes); utils().encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes);
// need: topic1 ... topicn memsize memstart // need: topic1 ... topicn memsize memstart
utils().toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
m_context << solidity::logInstruction(numIndexed); m_context << logInstruction(numIndexed);
break; break;
} }
case Location::BlockHash: case Location::BlockHash:
{ {
arguments[0]->accept(*this); arguments[0]->accept(*this);
utils().convertType(*arguments[0]->annotation().type, *function.parameterTypes()[0], true); utils().convertType(*arguments[0]->annotation().type, *function.parameterTypes()[0], true);
m_context << solidity::Instruction::BLOCKHASH; m_context << Instruction::BLOCKHASH;
break; break;
} }
case Location::AddMod: case Location::AddMod:
@ -695,9 +695,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().convertType(*arguments[2 - i]->annotation().type, IntegerType(256)); utils().convertType(*arguments[2 - i]->annotation().type, IntegerType(256));
} }
if (function.location() == Location::AddMod) if (function.location() == Location::AddMod)
m_context << solidity::Instruction::ADDMOD; m_context << Instruction::ADDMOD;
else else
m_context << solidity::Instruction::MULMOD; m_context << Instruction::MULMOD;
break; break;
} }
case Location::ECRecover: case Location::ECRecover:
@ -710,7 +710,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{Location::RIPEMD160, 3}}; {Location::RIPEMD160, 3}};
m_context << contractAddresses.find(function.location())->second; m_context << contractAddresses.find(function.location())->second;
for (unsigned i = function.sizeOnStack(); i > 0; --i) for (unsigned i = function.sizeOnStack(); i > 0; --i)
m_context << solidity::swapInstruction(i); m_context << swapInstruction(i);
appendExternalFunctionCall(function, arguments); appendExternalFunctionCall(function, arguments);
break; break;
} }
@ -727,13 +727,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
make_shared<ArrayType>(DataLocation::Storage); make_shared<ArrayType>(DataLocation::Storage);
// get the current length // get the current length
ArrayUtils(m_context).retrieveLength(*arrayType); ArrayUtils(m_context).retrieveLength(*arrayType);
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
// stack: ArrayReference currentLength currentLength // stack: ArrayReference currentLength currentLength
m_context << u256(1) << solidity::Instruction::ADD; m_context << u256(1) << Instruction::ADD;
// stack: ArrayReference currentLength newLength // stack: ArrayReference currentLength newLength
m_context << solidity::Instruction::DUP3 << solidity::Instruction::DUP2; m_context << Instruction::DUP3 << Instruction::DUP2;
ArrayUtils(m_context).resizeDynamicArray(*arrayType); ArrayUtils(m_context).resizeDynamicArray(*arrayType);
m_context << solidity::Instruction::SWAP2 << solidity::Instruction::SWAP1; m_context << Instruction::SWAP2 << Instruction::SWAP1;
// stack: newLength ArrayReference oldLength // stack: newLength ArrayReference oldLength
ArrayUtils(m_context).accessIndex(*arrayType, false); ArrayUtils(m_context).accessIndex(*arrayType, false);
@ -766,36 +766,36 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// Stack: requested_length // Stack: requested_length
// Allocate at max(MSIZE, freeMemoryPointer) // Allocate at max(MSIZE, freeMemoryPointer)
utils().fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
m_context << solidity::Instruction::DUP1 << solidity::Instruction::MSIZE; m_context << Instruction::DUP1 << Instruction::MSIZE;
m_context << solidity::Instruction::LT; m_context << Instruction::LT;
auto initialise = m_context.appendConditionalJump(); auto initialise = m_context.appendConditionalJump();
// Free memory pointer does not point to empty memory, use MSIZE. // Free memory pointer does not point to empty memory, use MSIZE.
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
m_context << solidity::Instruction::MSIZE; m_context << Instruction::MSIZE;
m_context << initialise; m_context << initialise;
// Stack: requested_length memptr // Stack: requested_length memptr
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
// Stack: memptr requested_length // Stack: memptr requested_length
// store length // store length
m_context << solidity::Instruction::DUP1 << solidity::Instruction::DUP3 << solidity::Instruction::MSTORE; m_context << Instruction::DUP1 << Instruction::DUP3 << Instruction::MSTORE;
// Stack: memptr requested_length // Stack: memptr requested_length
// update free memory pointer // update free memory pointer
m_context << solidity::Instruction::DUP1 << arrayType.baseType()->memoryHeadSize(); m_context << Instruction::DUP1 << arrayType.baseType()->memoryHeadSize();
m_context << solidity::Instruction::MUL << u256(32) << solidity::Instruction::ADD; m_context << Instruction::MUL << u256(32) << Instruction::ADD;
m_context << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << Instruction::DUP3 << Instruction::ADD;
utils().storeFreeMemoryPointer(); utils().storeFreeMemoryPointer();
// Stack: memptr requested_length // Stack: memptr requested_length
// We only have to initialise if the base type is a not a value type. // We only have to initialise if the base type is a not a value type.
if (dynamic_cast<ReferenceType const*>(arrayType.baseType().get())) if (dynamic_cast<ReferenceType const*>(arrayType.baseType().get()))
{ {
m_context << solidity::Instruction::DUP2 << u256(32) << solidity::Instruction::ADD; m_context << Instruction::DUP2 << u256(32) << Instruction::ADD;
utils().zeroInitialiseMemoryArray(arrayType); utils().zeroInitialiseMemoryArray(arrayType);
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
else else
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
break; break;
} }
default: default:
@ -876,7 +876,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
IntegerType(0, IntegerType::Modifier::Address), IntegerType(0, IntegerType::Modifier::Address),
true true
); );
m_context << solidity::Instruction::BALANCE; m_context << Instruction::BALANCE;
} }
else if ((set<string>{"send", "call", "callcode", "delegatecall"}).count(member)) else if ((set<string>{"send", "call", "callcode", "delegatecall"}).count(member))
utils().convertType( utils().convertType(
@ -894,30 +894,30 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case Type::Category::Magic: case Type::Category::Magic:
// we can ignore the kind of magic and only look at the name of the member // we can ignore the kind of magic and only look at the name of the member
if (member == "coinbase") if (member == "coinbase")
m_context << solidity::Instruction::COINBASE; m_context << Instruction::COINBASE;
else if (member == "timestamp") else if (member == "timestamp")
m_context << solidity::Instruction::TIMESTAMP; m_context << Instruction::TIMESTAMP;
else if (member == "difficulty") else if (member == "difficulty")
m_context << solidity::Instruction::DIFFICULTY; m_context << Instruction::DIFFICULTY;
else if (member == "number") else if (member == "number")
m_context << solidity::Instruction::NUMBER; m_context << Instruction::NUMBER;
else if (member == "gaslimit") else if (member == "gaslimit")
m_context << solidity::Instruction::GASLIMIT; m_context << Instruction::GASLIMIT;
else if (member == "sender") else if (member == "sender")
m_context << solidity::Instruction::CALLER; m_context << Instruction::CALLER;
else if (member == "value") else if (member == "value")
m_context << solidity::Instruction::CALLVALUE; m_context << Instruction::CALLVALUE;
else if (member == "origin") else if (member == "origin")
m_context << solidity::Instruction::ORIGIN; m_context << Instruction::ORIGIN;
else if (member == "gas") else if (member == "gas")
m_context << solidity::Instruction::GAS; m_context << Instruction::GAS;
else if (member == "gasprice") else if (member == "gasprice")
m_context << solidity::Instruction::GASPRICE; m_context << Instruction::GASPRICE;
else if (member == "data") else if (member == "data")
m_context << u256(0) << solidity::Instruction::CALLDATASIZE; m_context << u256(0) << Instruction::CALLDATASIZE;
else if (member == "sig") else if (member == "sig")
m_context << u256(0) << solidity::Instruction::CALLDATALOAD m_context << u256(0) << Instruction::CALLDATALOAD
<< (u256(0xffffffff) << (256 - 32)) << solidity::Instruction::AND; << (u256(0xffffffff) << (256 - 32)) << Instruction::AND;
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member."));
break; break;
@ -929,13 +929,13 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case DataLocation::Storage: case DataLocation::Storage:
{ {
pair<u256, unsigned> const& offsets = type.storageOffsetsOfMember(member); pair<u256, unsigned> const& offsets = type.storageOffsetsOfMember(member);
m_context << offsets.first << solidity::Instruction::ADD << u256(offsets.second); m_context << offsets.first << Instruction::ADD << u256(offsets.second);
setLValueToStorageItem(_memberAccess); setLValueToStorageItem(_memberAccess);
break; break;
} }
case DataLocation::Memory: case DataLocation::Memory:
{ {
m_context << type.memoryOffsetOfMember(member) << solidity::Instruction::ADD; m_context << type.memoryOffsetOfMember(member) << Instruction::ADD;
setLValue<MemoryItem>(_memberAccess, *_memberAccess.annotation().type); setLValue<MemoryItem>(_memberAccess, *_memberAccess.annotation().type);
break; break;
} }
@ -986,13 +986,13 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
switch (type.location()) switch (type.location())
{ {
case DataLocation::CallData: case DataLocation::CallData:
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::POP; m_context << Instruction::SWAP1 << Instruction::POP;
break; break;
case DataLocation::Storage: case DataLocation::Storage:
setLValue<StorageArrayLength>(_memberAccess, type); setLValue<StorageArrayLength>(_memberAccess, type);
break; break;
case DataLocation::Memory: case DataLocation::Memory:
m_context << solidity::Instruction::MLOAD; m_context << Instruction::MLOAD;
break; break;
} }
} }
@ -1046,7 +1046,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
false, false,
true true
); );
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
utils().storeInMemoryDynamic(IntegerType(256)); utils().storeInMemoryDynamic(IntegerType(256));
utils().toSizeAfterFreeMemoryPointer(); utils().toSizeAfterFreeMemoryPointer();
} }
@ -1054,12 +1054,12 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
{ {
m_context << u256(0); // memory position m_context << u256(0); // memory position
appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression()); appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression());
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
utils().storeInMemoryDynamic(IntegerType(256)); utils().storeInMemoryDynamic(IntegerType(256));
m_context << u256(0); m_context << u256(0);
} }
m_context << solidity::Instruction::SHA3; m_context << Instruction::SHA3;
m_context << u256(0); m_context << u256(0);
setLValueToStorageItem(_indexAccess); setLValueToStorageItem(_indexAccess);
} }
@ -1109,12 +1109,12 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
// stack layout: <value> <index> // stack layout: <value> <index>
// check out-of-bounds access // check out-of-bounds access
m_context << u256(fixedBytesType.numBytes()); m_context << u256(fixedBytesType.numBytes());
m_context << solidity::Instruction::DUP2 << solidity::Instruction::LT << solidity::Instruction::ISZERO; m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO;
// out-of-bounds access throws exception // out-of-bounds access throws exception
m_context.appendConditionalJumpTo(m_context.errorTag()); m_context.appendConditionalJumpTo(m_context.errorTag());
m_context << solidity::Instruction::BYTE; m_context << Instruction::BYTE;
m_context << (u256(1) << (256 - 8)) << solidity::Instruction::MUL; m_context << (u256(1) << (256 - 8)) << Instruction::MUL;
} }
else if (baseType.category() == Type::Category::TypeType) else if (baseType.category() == Type::Category::TypeType)
{ {
@ -1139,11 +1139,11 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
case Type::Category::Contract: case Type::Category::Contract:
// "this" or "super" // "this" or "super"
if (!dynamic_cast<ContractType const&>(*magicVar->type()).isSuper()) if (!dynamic_cast<ContractType const&>(*magicVar->type()).isSuper())
m_context << solidity::Instruction::ADDRESS; m_context << Instruction::ADDRESS;
break; break;
case Type::Category::Integer: case Type::Category::Integer:
// "now" // "now"
m_context << solidity::Instruction::TIMESTAMP; m_context << Instruction::TIMESTAMP;
break; break;
default: default:
break; break;
@ -1208,11 +1208,11 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO
solAssert(c_op == Token::Or || c_op == Token::And, ""); solAssert(c_op == Token::Or || c_op == Token::And, "");
_binaryOperation.leftExpression().accept(*this); _binaryOperation.leftExpression().accept(*this);
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
if (c_op == Token::And) if (c_op == Token::And)
m_context << solidity::Instruction::ISZERO; m_context << Instruction::ISZERO;
eth::AssemblyItem endLabel = m_context.appendConditionalJump(); eth::AssemblyItem endLabel = m_context.appendConditionalJump();
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
_binaryOperation.rightExpression().accept(*this); _binaryOperation.rightExpression().accept(*this);
m_context << endLabel; m_context << endLabel;
} }
@ -1221,9 +1221,9 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
{ {
if (_operator == Token::Equal || _operator == Token::NotEqual) if (_operator == Token::Equal || _operator == Token::NotEqual)
{ {
m_context << solidity::Instruction::EQ; m_context << Instruction::EQ;
if (_operator == Token::NotEqual) if (_operator == Token::NotEqual)
m_context << solidity::Instruction::ISZERO; m_context << Instruction::ISZERO;
} }
else else
{ {
@ -1235,19 +1235,19 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
{ {
case Token::GreaterThanOrEqual: case Token::GreaterThanOrEqual:
m_context << m_context <<
(isSigned ? solidity::Instruction::SLT : solidity::Instruction::LT) << (isSigned ? Instruction::SLT : Instruction::LT) <<
solidity::Instruction::ISZERO; Instruction::ISZERO;
break; break;
case Token::LessThanOrEqual: case Token::LessThanOrEqual:
m_context << m_context <<
(isSigned ? solidity::Instruction::SGT : solidity::Instruction::GT) << (isSigned ? Instruction::SGT : Instruction::GT) <<
solidity::Instruction::ISZERO; Instruction::ISZERO;
break; break;
case Token::GreaterThan: case Token::GreaterThan:
m_context << (isSigned ? solidity::Instruction::SGT : solidity::Instruction::GT); m_context << (isSigned ? Instruction::SGT : Instruction::GT);
break; break;
case Token::LessThan: case Token::LessThan:
m_context << (isSigned ? solidity::Instruction::SLT : solidity::Instruction::LT); m_context << (isSigned ? Instruction::SLT : Instruction::LT);
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator."));
@ -1275,22 +1275,22 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
switch (_operator) switch (_operator)
{ {
case Token::Add: case Token::Add:
m_context << solidity::Instruction::ADD; m_context << Instruction::ADD;
break; break;
case Token::Sub: case Token::Sub:
m_context << solidity::Instruction::SUB; m_context << Instruction::SUB;
break; break;
case Token::Mul: case Token::Mul:
m_context << solidity::Instruction::MUL; m_context << Instruction::MUL;
break; break;
case Token::Div: case Token::Div:
m_context << (c_isSigned ? solidity::Instruction::SDIV : solidity::Instruction::DIV); m_context << (c_isSigned ? Instruction::SDIV : Instruction::DIV);
break; break;
case Token::Mod: case Token::Mod:
m_context << (c_isSigned ? solidity::Instruction::SMOD : solidity::Instruction::MOD); m_context << (c_isSigned ? Instruction::SMOD : Instruction::MOD);
break; break;
case Token::Exp: case Token::Exp:
m_context << solidity::Instruction::EXP; m_context << Instruction::EXP;
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator."));
@ -1302,13 +1302,13 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator)
switch (_operator) switch (_operator)
{ {
case Token::BitOr: case Token::BitOr:
m_context << solidity::Instruction::OR; m_context << Instruction::OR;
break; break;
case Token::BitAnd: case Token::BitAnd:
m_context << solidity::Instruction::AND; m_context << Instruction::AND;
break; break;
case Token::BitXor: case Token::BitXor:
m_context << solidity::Instruction::XOR; m_context << Instruction::XOR;
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown bit operator.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown bit operator."));
@ -1392,7 +1392,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
true true
); );
for (unsigned i = 0; i < gasValueSize; ++i) for (unsigned i = 0; i < gasValueSize; ++i)
m_context << solidity::swapInstruction(gasValueSize - i); m_context << swapInstruction(gasValueSize - i);
gasStackPos++; gasStackPos++;
valueStackPos++; valueStackPos++;
} }
@ -1411,7 +1411,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
utils().fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
if (!_functionType.isBareCall() || manualFunctionId) if (!_functionType.isBareCall() || manualFunctionId)
{ {
m_context << solidity::dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes)); m_context << dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes));
utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false); utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false);
} }
// If the function takes arbitrary parameters, copy dynamic length data in place. // If the function takes arbitrary parameters, copy dynamic length data in place.
@ -1437,21 +1437,21 @@ void ExpressionCompiler::appendExternalFunctionCall(
// put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input> // put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input>
m_context << u256(retSize); m_context << u256(retSize);
utils().fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
m_context << solidity::Instruction::DUP1 << solidity::Instruction::DUP4 << solidity::Instruction::SUB; m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::SUB;
m_context << solidity::Instruction::DUP2; m_context << Instruction::DUP2;
// CALL arguments: outSize, outOff, inSize, inOff (already present up to here) // CALL arguments: outSize, outOff, inSize, inOff (already present up to here)
// [value,] addr, gas (stack top) // [value,] addr, gas (stack top)
if (isDelegateCall) if (isDelegateCall)
solAssert(!_functionType.valueSet(), "Value set for delegatecall"); solAssert(!_functionType.valueSet(), "Value set for delegatecall");
else if (_functionType.valueSet()) else if (_functionType.valueSet())
m_context << solidity::dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos)); m_context << dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos));
else else
m_context << u256(0); m_context << u256(0);
m_context << solidity::dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos)); m_context << dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos));
if (_functionType.gasSet()) if (_functionType.gasSet())
m_context << solidity::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); m_context << dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
else else
{ {
eth::EVMSchedule schedule; eth::EVMSchedule schedule;
@ -1464,15 +1464,15 @@ void ExpressionCompiler::appendExternalFunctionCall(
gasNeededByCaller += schedule.callNewAccountGas; // we never know gasNeededByCaller += schedule.callNewAccountGas; // we never know
m_context << m_context <<
gasNeededByCaller << gasNeededByCaller <<
solidity::Instruction::GAS << Instruction::GAS <<
solidity::Instruction::SUB; Instruction::SUB;
} }
if (isDelegateCall) if (isDelegateCall)
m_context << solidity::Instruction::DELEGATECALL; m_context << Instruction::DELEGATECALL;
else if (isCallCode) else if (isCallCode)
m_context << solidity::Instruction::CALLCODE; m_context << Instruction::CALLCODE;
else else
m_context << solidity::Instruction::CALL; m_context << Instruction::CALL;
unsigned remainsSize = unsigned remainsSize =
2 + // contract address, input_memory_end 2 + // contract address, input_memory_end
@ -1481,11 +1481,11 @@ void ExpressionCompiler::appendExternalFunctionCall(
(!_functionType.isBareCall() || manualFunctionId); (!_functionType.isBareCall() || manualFunctionId);
if (returnSuccessCondition) if (returnSuccessCondition)
m_context << solidity::swapInstruction(remainsSize); m_context << swapInstruction(remainsSize);
else else
{ {
//Propagate error condition (if CALL pushes 0 on stack). //Propagate error condition (if CALL pushes 0 on stack).
m_context << solidity::Instruction::ISZERO; m_context << Instruction::ISZERO;
m_context.appendConditionalJumpTo(m_context.errorTag()); m_context.appendConditionalJumpTo(m_context.errorTag());
} }
@ -1515,7 +1515,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
if (memoryNeeded) if (memoryNeeded)
utils().storeFreeMemoryPointer(); utils().storeFreeMemoryPointer();
else else
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
} }

View File

@ -49,7 +49,7 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
); );
solAssert(stackPos + 1 >= m_size, "Size and stack pos mismatch."); solAssert(stackPos + 1 >= m_size, "Size and stack pos mismatch.");
for (unsigned i = 0; i < m_size; ++i) for (unsigned i = 0; i < m_size; ++i)
m_context << solidity::dupInstruction(stackPos + 1); m_context << dupInstruction(stackPos + 1);
} }
void StackVariable::storeValue(Type const&, SourceLocation const& _location, bool _move) const void StackVariable::storeValue(Type const&, SourceLocation const& _location, bool _move) const
@ -63,7 +63,7 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo
); );
else if (stackDiff > 0) else if (stackDiff > 0)
for (unsigned i = 0; i < m_size; ++i) for (unsigned i = 0; i < m_size; ++i)
m_context << solidity::swapInstruction(stackDiff) << solidity::Instruction::POP; m_context << swapInstruction(stackDiff) << Instruction::POP;
if (!_move) if (!_move)
retrieveValue(_location); retrieveValue(_location);
} }
@ -85,11 +85,11 @@ void MemoryItem::retrieveValue(SourceLocation const&, bool _remove) const
if (m_dataType->isValueType()) if (m_dataType->isValueType())
{ {
if (!_remove) if (!_remove)
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
CompilerUtils(m_context).loadFromMemoryDynamic(*m_dataType, false, m_padded, false); CompilerUtils(m_context).loadFromMemoryDynamic(*m_dataType, false, m_padded, false);
} }
else else
m_context << solidity::Instruction::MLOAD; m_context << Instruction::MLOAD;
} }
void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool _move) const void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool _move) const
@ -109,13 +109,13 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool
{ {
solAssert(m_dataType->calldataEncodedSize(false) == 1, "Invalid non-padded type."); solAssert(m_dataType->calldataEncodedSize(false) == 1, "Invalid non-padded type.");
if (m_dataType->category() == Type::Category::FixedBytes) if (m_dataType->category() == Type::Category::FixedBytes)
m_context << u256(0) << solidity::Instruction::BYTE; m_context << u256(0) << Instruction::BYTE;
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::MSTORE8; m_context << Instruction::SWAP1 << Instruction::MSTORE8;
} }
else else
{ {
utils.storeInMemoryDynamic(*m_dataType, m_padded); utils.storeInMemoryDynamic(*m_dataType, m_padded);
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
} }
else else
@ -124,10 +124,10 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool
solAssert(m_dataType->sizeOnStack() == 1, ""); solAssert(m_dataType->sizeOnStack() == 1, "");
if (!_move) if (!_move)
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SWAP1; m_context << Instruction::DUP2 << Instruction::SWAP1;
// stack: [value] value lvalue // stack: [value] value lvalue
// only store the reference // only store the reference
m_context << solidity::Instruction::MSTORE; m_context << Instruction::MSTORE;
} }
} }
@ -135,10 +135,10 @@ void MemoryItem::setToZero(SourceLocation const&, bool _removeReference) const
{ {
CompilerUtils utils(m_context); CompilerUtils utils(m_context);
if (!_removeReference) if (!_removeReference)
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
utils.pushZeroValue(*m_dataType); utils.pushZeroValue(*m_dataType);
utils.storeInMemoryDynamic(*m_dataType, m_padded); utils.storeInMemoryDynamic(*m_dataType, m_padded);
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
StorageItem::StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration): StorageItem::StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration):
@ -165,29 +165,29 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
{ {
solAssert(m_dataType->sizeOnStack() == 1, "Invalid storage ref size."); solAssert(m_dataType->sizeOnStack() == 1, "Invalid storage ref size.");
if (_remove) if (_remove)
m_context << solidity::Instruction::POP; // remove byte offset m_context << Instruction::POP; // remove byte offset
else else
m_context << solidity::Instruction::DUP2; m_context << Instruction::DUP2;
return; return;
} }
if (!_remove) if (!_remove)
CompilerUtils(m_context).copyToStackTop(sizeOnStack(), sizeOnStack()); CompilerUtils(m_context).copyToStackTop(sizeOnStack(), sizeOnStack());
if (m_dataType->storageBytes() == 32) if (m_dataType->storageBytes() == 32)
m_context << solidity::Instruction::POP << solidity::Instruction::SLOAD; m_context << Instruction::POP << Instruction::SLOAD;
else else
{ {
m_context m_context
<< solidity::Instruction::SWAP1 << solidity::Instruction::SLOAD << solidity::Instruction::SWAP1 << Instruction::SWAP1 << Instruction::SLOAD << Instruction::SWAP1
<< u256(0x100) << solidity::Instruction::EXP << solidity::Instruction::SWAP1 << solidity::Instruction::DIV; << u256(0x100) << Instruction::EXP << Instruction::SWAP1 << Instruction::DIV;
if (m_dataType->category() == Type::Category::FixedBytes) if (m_dataType->category() == Type::Category::FixedBytes)
m_context << (u256(0x1) << (256 - 8 * m_dataType->storageBytes())) << solidity::Instruction::MUL; m_context << (u256(0x1) << (256 - 8 * m_dataType->storageBytes())) << Instruction::MUL;
else if ( else if (
m_dataType->category() == Type::Category::Integer && m_dataType->category() == Type::Category::Integer &&
dynamic_cast<IntegerType const&>(*m_dataType).isSigned() dynamic_cast<IntegerType const&>(*m_dataType).isSigned()
) )
m_context << u256(m_dataType->storageBytes() - 1) << solidity::Instruction::SIGNEXTEND; m_context << u256(m_dataType->storageBytes() - 1) << Instruction::SIGNEXTEND;
else else
m_context << ((u256(0x1) << (8 * m_dataType->storageBytes())) - 1) << solidity::Instruction::AND; m_context << ((u256(0x1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::AND;
} }
} }
@ -202,32 +202,32 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
if (m_dataType->storageBytes() == 32) if (m_dataType->storageBytes() == 32)
{ {
// offset should be zero // offset should be zero
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
if (!_move) if (!_move)
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SWAP1; m_context << Instruction::DUP2 << Instruction::SWAP1;
m_context << solidity::Instruction::SSTORE; m_context << Instruction::SSTORE;
} }
else else
{ {
// OR the value into the other values in the storage slot // OR the value into the other values in the storage slot
m_context << u256(0x100) << solidity::Instruction::EXP; m_context << u256(0x100) << Instruction::EXP;
// stack: value storage_ref multiplier // stack: value storage_ref multiplier
// fetch old value // fetch old value
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SLOAD; m_context << Instruction::DUP2 << Instruction::SLOAD;
// stack: value storege_ref multiplier old_full_value // stack: value storege_ref multiplier old_full_value
// clear bytes in old value // clear bytes in old value
m_context m_context
<< solidity::Instruction::DUP2 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::DUP2 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1)
<< solidity::Instruction::MUL; << Instruction::MUL;
m_context << solidity::Instruction::NOT << solidity::Instruction::AND; m_context << Instruction::NOT << Instruction::AND;
// stack: value storage_ref multiplier cleared_value // stack: value storage_ref multiplier cleared_value
m_context m_context
<< solidity::Instruction::SWAP1 << solidity::Instruction::DUP4; << Instruction::SWAP1 << Instruction::DUP4;
// stack: value storage_ref cleared_value multiplier value // stack: value storage_ref cleared_value multiplier value
if (m_dataType->category() == Type::Category::FixedBytes) if (m_dataType->category() == Type::Category::FixedBytes)
m_context m_context
<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes())) << (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes()))
<< solidity::Instruction::SWAP1 << solidity::Instruction::DIV; << Instruction::SWAP1 << Instruction::DIV;
else if ( else if (
m_dataType->category() == Type::Category::Integer && m_dataType->category() == Type::Category::Integer &&
dynamic_cast<IntegerType const&>(*m_dataType).isSigned() dynamic_cast<IntegerType const&>(*m_dataType).isSigned()
@ -235,15 +235,15 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
// remove the higher order bits // remove the higher order bits
m_context m_context
<< (u256(1) << (8 * (32 - m_dataType->storageBytes()))) << (u256(1) << (8 * (32 - m_dataType->storageBytes())))
<< solidity::Instruction::SWAP1 << Instruction::SWAP1
<< solidity::Instruction::DUP2 << Instruction::DUP2
<< solidity::Instruction::MUL << Instruction::MUL
<< solidity::Instruction::DIV; << Instruction::DIV;
m_context << solidity::Instruction::MUL << solidity::Instruction::OR; m_context << Instruction::MUL << Instruction::OR;
// stack: value storage_ref updated_value // stack: value storage_ref updated_value
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::SSTORE; m_context << Instruction::SWAP1 << Instruction::SSTORE;
if (_move) if (_move)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
} }
else else
@ -253,19 +253,19 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
"Wrong type conversation for assignment."); "Wrong type conversation for assignment.");
if (m_dataType->category() == Type::Category::Array) if (m_dataType->category() == Type::Category::Array)
{ {
m_context << solidity::Instruction::POP; // remove byte offset m_context << Instruction::POP; // remove byte offset
ArrayUtils(m_context).copyArrayToStorage( ArrayUtils(m_context).copyArrayToStorage(
dynamic_cast<ArrayType const&>(*m_dataType), dynamic_cast<ArrayType const&>(*m_dataType),
dynamic_cast<ArrayType const&>(_sourceType) dynamic_cast<ArrayType const&>(_sourceType)
); );
if (_move) if (_move)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
else if (m_dataType->category() == Type::Category::Struct) else if (m_dataType->category() == Type::Category::Struct)
{ {
// stack layout: source_ref target_ref target_offset // stack layout: source_ref target_ref target_offset
// note that we have structs, so offset should be zero and are ignored // note that we have structs, so offset should be zero and are ignored
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
auto const& structType = dynamic_cast<StructType const&>(*m_dataType); auto const& structType = dynamic_cast<StructType const&>(*m_dataType);
auto const& sourceType = dynamic_cast<StructType const&>(_sourceType); auto const& sourceType = dynamic_cast<StructType const&>(_sourceType);
solAssert( solAssert(
@ -284,7 +284,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
{ {
// stack layout: source_ref target_ref // stack layout: source_ref target_ref
pair<u256, unsigned> const& offsets = sourceType.storageOffsetsOfMember(member.name); pair<u256, unsigned> const& offsets = sourceType.storageOffsetsOfMember(member.name);
m_context << offsets.first << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
m_context << u256(offsets.second); m_context << u256(offsets.second);
// stack: source_ref target_ref source_member_ref source_member_off // stack: source_ref target_ref source_member_ref source_member_off
StorageItem(m_context, *sourceMemberType).retrieveValue(_location, true); StorageItem(m_context, *sourceMemberType).retrieveValue(_location, true);
@ -296,13 +296,13 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
// stack layout: source_ref target_ref // stack layout: source_ref target_ref
TypePointer sourceMemberType = sourceType.memberType(member.name); TypePointer sourceMemberType = sourceType.memberType(member.name);
m_context << sourceType.memoryOffsetOfMember(member.name); m_context << sourceType.memoryOffsetOfMember(member.name);
m_context << solidity::Instruction::DUP3 << solidity::Instruction::ADD; m_context << Instruction::DUP3 << Instruction::ADD;
MemoryItem(m_context, *sourceMemberType).retrieveValue(_location, true); MemoryItem(m_context, *sourceMemberType).retrieveValue(_location, true);
// stack layout: source_ref target_ref source_value... // stack layout: source_ref target_ref source_value...
} }
unsigned stackSize = sourceMemberType->sizeOnStack(); unsigned stackSize = sourceMemberType->sizeOnStack();
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name); pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name);
m_context << solidity::dupInstruction(1 + stackSize) << offsets.first << solidity::Instruction::ADD; m_context << dupInstruction(1 + stackSize) << offsets.first << Instruction::ADD;
m_context << u256(offsets.second); m_context << u256(offsets.second);
// stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off // stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off
StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true); StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true);
@ -312,7 +312,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
if (_move) if (_move)
utils.popStackSlots(2); utils.popStackSlots(2);
else else
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::POP; m_context << Instruction::SWAP1 << Instruction::POP;
} }
else else
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
@ -344,12 +344,12 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
continue; continue;
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name); pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name);
m_context m_context
<< offsets.first << solidity::Instruction::DUP3 << solidity::Instruction::ADD << offsets.first << Instruction::DUP3 << Instruction::ADD
<< u256(offsets.second); << u256(offsets.second);
StorageItem(m_context, *memberType).setToZero(); StorageItem(m_context, *memberType).setToZero();
} }
if (_removeReference) if (_removeReference)
m_context << solidity::Instruction::POP << solidity::Instruction::POP; m_context << Instruction::POP << Instruction::POP;
} }
else else
{ {
@ -360,23 +360,23 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
{ {
// offset should be zero // offset should be zero
m_context m_context
<< solidity::Instruction::POP << u256(0) << Instruction::POP << u256(0)
<< solidity::Instruction::SWAP1 << solidity::Instruction::SSTORE; << Instruction::SWAP1 << Instruction::SSTORE;
} }
else else
{ {
m_context << u256(0x100) << solidity::Instruction::EXP; m_context << u256(0x100) << Instruction::EXP;
// stack: storage_ref multiplier // stack: storage_ref multiplier
// fetch old value // fetch old value
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SLOAD; m_context << Instruction::DUP2 << Instruction::SLOAD;
// stack: storege_ref multiplier old_full_value // stack: storege_ref multiplier old_full_value
// clear bytes in old value // clear bytes in old value
m_context m_context
<< solidity::Instruction::SWAP1 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::SWAP1 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1)
<< solidity::Instruction::MUL; << Instruction::MUL;
m_context << solidity::Instruction::NOT << solidity::Instruction::AND; m_context << Instruction::NOT << Instruction::AND;
// stack: storage_ref cleared_value // stack: storage_ref cleared_value
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::SSTORE; m_context << Instruction::SWAP1 << Instruction::SSTORE;
} }
} }
} }
@ -393,48 +393,48 @@ void StorageByteArrayElement::retrieveValue(SourceLocation const&, bool _remove)
{ {
// stack: ref byte_number // stack: ref byte_number
if (_remove) if (_remove)
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::SLOAD m_context << Instruction::SWAP1 << Instruction::SLOAD
<< solidity::Instruction::SWAP1 << solidity::Instruction::BYTE; << Instruction::SWAP1 << Instruction::BYTE;
else else
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SLOAD m_context << Instruction::DUP2 << Instruction::SLOAD
<< solidity::Instruction::DUP2 << solidity::Instruction::BYTE; << Instruction::DUP2 << Instruction::BYTE;
m_context << (u256(1) << (256 - 8)) << solidity::Instruction::MUL; m_context << (u256(1) << (256 - 8)) << Instruction::MUL;
} }
void StorageByteArrayElement::storeValue(Type const&, SourceLocation const&, bool _move) const void StorageByteArrayElement::storeValue(Type const&, SourceLocation const&, bool _move) const
{ {
// stack: value ref byte_number // stack: value ref byte_number
m_context << u256(31) << solidity::Instruction::SUB << u256(0x100) << solidity::Instruction::EXP; m_context << u256(31) << Instruction::SUB << u256(0x100) << Instruction::EXP;
// stack: value ref (1<<(8*(31-byte_number))) // stack: value ref (1<<(8*(31-byte_number)))
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SLOAD; m_context << Instruction::DUP2 << Instruction::SLOAD;
// stack: value ref (1<<(8*(31-byte_number))) old_full_value // stack: value ref (1<<(8*(31-byte_number))) old_full_value
// clear byte in old value // clear byte in old value
m_context << solidity::Instruction::DUP2 << u256(0xff) << solidity::Instruction::MUL m_context << Instruction::DUP2 << u256(0xff) << Instruction::MUL
<< solidity::Instruction::NOT << solidity::Instruction::AND; << Instruction::NOT << Instruction::AND;
// stack: value ref (1<<(32-byte_number)) old_full_value_with_cleared_byte // stack: value ref (1<<(32-byte_number)) old_full_value_with_cleared_byte
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
m_context << (u256(1) << (256 - 8)) << solidity::Instruction::DUP5 << solidity::Instruction::DIV m_context << (u256(1) << (256 - 8)) << Instruction::DUP5 << Instruction::DIV
<< solidity::Instruction::MUL << solidity::Instruction::OR; << Instruction::MUL << Instruction::OR;
// stack: value ref new_full_value // stack: value ref new_full_value
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::SSTORE; m_context << Instruction::SWAP1 << Instruction::SSTORE;
if (_move) if (_move)
m_context << solidity::Instruction::POP; m_context << Instruction::POP;
} }
void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeReference) const void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeReference) const
{ {
// stack: ref byte_number // stack: ref byte_number
if (!_removeReference) if (!_removeReference)
m_context << solidity::Instruction::DUP2 << solidity::Instruction::DUP2; m_context << Instruction::DUP2 << Instruction::DUP2;
m_context << u256(31) << solidity::Instruction::SUB << u256(0x100) << solidity::Instruction::EXP; m_context << u256(31) << Instruction::SUB << u256(0x100) << Instruction::EXP;
// stack: ref (1<<(8*(31-byte_number))) // stack: ref (1<<(8*(31-byte_number)))
m_context << solidity::Instruction::DUP2 << solidity::Instruction::SLOAD; m_context << Instruction::DUP2 << Instruction::SLOAD;
// stack: ref (1<<(8*(31-byte_number))) old_full_value // stack: ref (1<<(8*(31-byte_number))) old_full_value
// clear byte in old value // clear byte in old value
m_context << solidity::Instruction::SWAP1 << u256(0xff) << solidity::Instruction::MUL; m_context << Instruction::SWAP1 << u256(0xff) << Instruction::MUL;
m_context << solidity::Instruction::NOT << solidity::Instruction::AND; m_context << Instruction::NOT << Instruction::AND;
// stack: ref old_full_value_with_cleared_byte // stack: ref old_full_value_with_cleared_byte
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::SSTORE; m_context << Instruction::SWAP1 << Instruction::SSTORE;
} }
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, const ArrayType& _arrayType): StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, const ArrayType& _arrayType):
@ -448,22 +448,22 @@ void StorageArrayLength::retrieveValue(SourceLocation const&, bool _remove) cons
{ {
ArrayUtils(m_context).retrieveLength(m_arrayType); ArrayUtils(m_context).retrieveLength(m_arrayType);
if (_remove) if (_remove)
m_context << solidity::Instruction::SWAP1 << solidity::Instruction::POP; m_context << Instruction::SWAP1 << Instruction::POP;
} }
void StorageArrayLength::storeValue(Type const&, SourceLocation const&, bool _move) const void StorageArrayLength::storeValue(Type const&, SourceLocation const&, bool _move) const
{ {
if (_move) if (_move)
m_context << solidity::Instruction::SWAP1; m_context << Instruction::SWAP1;
else else
m_context << solidity::Instruction::DUP2; m_context << Instruction::DUP2;
ArrayUtils(m_context).resizeDynamicArray(m_arrayType); ArrayUtils(m_context).resizeDynamicArray(m_arrayType);
} }
void StorageArrayLength::setToZero(SourceLocation const&, bool _removeReference) const void StorageArrayLength::setToZero(SourceLocation const&, bool _removeReference) const
{ {
if (!_removeReference) if (!_removeReference)
m_context << solidity::Instruction::DUP1; m_context << Instruction::DUP1;
ArrayUtils(m_context).clearDynamicArray(m_arrayType); ArrayUtils(m_context).clearDynamicArray(m_arrayType);
} }

View File

@ -137,8 +137,8 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
using Id = ExpressionClasses::Id; using Id = ExpressionClasses::Id;
using Ids = vector<Id>; using Ids = vector<Id>;
Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::sha3(_signature))))); Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::sha3(_signature)))));
Id calldata = classes.find(solidity::Instruction::CALLDATALOAD, Ids{classes.find(u256(0))}); Id calldata = classes.find(Instruction::CALLDATALOAD, Ids{classes.find(u256(0))});
classes.forceEqual(hashValue, solidity::Instruction::DIV, Ids{ classes.forceEqual(hashValue, Instruction::DIV, Ids{
calldata, calldata,
classes.find(u256(1) << (8 * 28)) classes.find(u256(1) << (8 * 28))
}); });
@ -165,7 +165,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
AssemblyItem invalidTag(PushTag, u256(-0x10)); AssemblyItem invalidTag(PushTag, u256(-0x10));
state->feedItem(invalidTag, true); state->feedItem(invalidTag, true);
if (parametersSize > 0) if (parametersSize > 0)
state->feedItem(solidity::swapInstruction(parametersSize)); state->feedItem(swapInstruction(parametersSize));
return PathGasMeter(_items).estimateMax(_offset, state); return PathGasMeter(_items).estimateMax(_offset, state);
} }

View File

@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(literal_true)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH1), 0x1}); bytes expectation({byte(Instruction::PUSH1), 0x1});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(literal_false)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH1), 0x0}); bytes expectation({byte(Instruction::PUSH1), 0x0});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(int_literal)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, bytes expectation({byte(Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90,
0x12, 0x34, 0x56, 0x78, 0x90}); 0x12, 0x34, 0x56, 0x78, 0x90});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination)
})"; })";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH1), 0x1}); bytes expectation({byte(Instruction::PUSH1), 0x1});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination)
})"; })";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00}); bytes expectation({byte(Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(int_with_finney_ether_subdenomination)
})"; })";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00}); bytes expectation({byte(Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -257,7 +257,7 @@ BOOST_AUTO_TEST_CASE(int_with_ether_ether_subdenomination)
})"; })";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00}); bytes expectation({byte(Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -268,12 +268,12 @@ BOOST_AUTO_TEST_CASE(comparison)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH1), 0x1, bytes expectation({byte(Instruction::PUSH1), 0x1,
byte(solidity::Instruction::PUSH2), 0x11, 0xaa, byte(Instruction::PUSH2), 0x11, 0xaa,
byte(solidity::Instruction::PUSH2), 0x10, 0xaa, byte(Instruction::PUSH2), 0x10, 0xaa,
byte(solidity::Instruction::LT), byte(Instruction::LT),
byte(solidity::Instruction::EQ), byte(Instruction::EQ),
byte(solidity::Instruction::ISZERO)}); byte(Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -284,22 +284,22 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(solidity::Instruction::PUSH1), 0x12, // 8 + 10 bytes expectation({byte(Instruction::PUSH1), 0x12, // 8 + 10
byte(solidity::Instruction::PUSH1), 0x4, byte(Instruction::PUSH1), 0x4,
byte(solidity::Instruction::GT), byte(Instruction::GT),
byte(solidity::Instruction::ISZERO), // after this we have 4 <= 8 + 10 byte(Instruction::ISZERO), // after this we have 4 <= 8 + 10
byte(solidity::Instruction::DUP1), byte(Instruction::DUP1),
byte(solidity::Instruction::PUSH1), 0x11, byte(Instruction::PUSH1), 0x11,
byte(solidity::Instruction::JUMPI), // short-circuit if it is true byte(Instruction::JUMPI), // short-circuit if it is true
byte(solidity::Instruction::POP), byte(Instruction::POP),
byte(solidity::Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
byte(solidity::Instruction::PUSH1), 0x9, byte(Instruction::PUSH1), 0x9,
byte(solidity::Instruction::EQ), byte(Instruction::EQ),
byte(solidity::Instruction::ISZERO), // after this we have 9 != 2 byte(Instruction::ISZERO), // after this we have 9 != 2
byte(solidity::Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(solidity::Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,
byte(solidity::Instruction::EQ), byte(Instruction::EQ),
byte(solidity::Instruction::ISZERO)}); byte(Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -309,23 +309,23 @@ BOOST_AUTO_TEST_CASE(arithmetics)
" function f(uint y) { var x = ((((((((y ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }" " function f(uint y) { var x = ((((((((y ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}}); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}});
bytes expectation({byte(solidity::Instruction::PUSH1), 0x1, bytes expectation({byte(Instruction::PUSH1), 0x1,
byte(solidity::Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
byte(solidity::Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0x3,
byte(solidity::Instruction::PUSH1), 0x4, byte(Instruction::PUSH1), 0x4,
byte(solidity::Instruction::PUSH1), 0x5, byte(Instruction::PUSH1), 0x5,
byte(solidity::Instruction::PUSH1), 0x6, byte(Instruction::PUSH1), 0x6,
byte(solidity::Instruction::PUSH1), 0x7, byte(Instruction::PUSH1), 0x7,
byte(solidity::Instruction::PUSH1), 0x8, byte(Instruction::PUSH1), 0x8,
byte(solidity::Instruction::DUP10), byte(Instruction::DUP10),
byte(solidity::Instruction::XOR), byte(Instruction::XOR),
byte(solidity::Instruction::AND), byte(Instruction::AND),
byte(solidity::Instruction::OR), byte(Instruction::OR),
byte(solidity::Instruction::SUB), byte(Instruction::SUB),
byte(solidity::Instruction::ADD), byte(Instruction::ADD),
byte(solidity::Instruction::MOD), byte(Instruction::MOD),
byte(solidity::Instruction::DIV), byte(Instruction::DIV),
byte(solidity::Instruction::MUL)}); byte(Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -336,13 +336,13 @@ BOOST_AUTO_TEST_CASE(unary_operators)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}}); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}});
bytes expectation({byte(solidity::Instruction::PUSH1), 0x2, bytes expectation({byte(Instruction::PUSH1), 0x2,
byte(solidity::Instruction::DUP3), byte(Instruction::DUP3),
byte(solidity::Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(solidity::Instruction::SUB), byte(Instruction::SUB),
byte(solidity::Instruction::NOT), byte(Instruction::NOT),
byte(solidity::Instruction::EQ), byte(Instruction::EQ),
byte(solidity::Instruction::ISZERO)}); byte(Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -354,44 +354,44 @@ BOOST_AUTO_TEST_CASE(unary_inc_dec)
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}}); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}});
// Stack: a, x // Stack: a, x
bytes expectation({byte(solidity::Instruction::DUP2), bytes expectation({byte(Instruction::DUP2),
byte(solidity::Instruction::DUP1), byte(Instruction::DUP1),
byte(solidity::Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,
byte(solidity::Instruction::ADD), byte(Instruction::ADD),
// Stack here: a x a (a+1) // Stack here: a x a (a+1)
byte(solidity::Instruction::SWAP3), byte(Instruction::SWAP3),
byte(solidity::Instruction::POP), // first ++ byte(Instruction::POP), // first ++
// Stack here: (a+1) x a // Stack here: (a+1) x a
byte(solidity::Instruction::DUP3), byte(Instruction::DUP3),
byte(solidity::Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,
byte(solidity::Instruction::ADD), byte(Instruction::ADD),
// Stack here: (a+1) x a (a+2) // Stack here: (a+1) x a (a+2)
byte(solidity::Instruction::SWAP3), byte(Instruction::SWAP3),
byte(solidity::Instruction::POP), byte(Instruction::POP),
// Stack here: (a+2) x a // Stack here: (a+2) x a
byte(solidity::Instruction::DUP3), // second ++ byte(Instruction::DUP3), // second ++
byte(solidity::Instruction::XOR), byte(Instruction::XOR),
// Stack here: (a+2) x a^(a+2) // Stack here: (a+2) x a^(a+2)
byte(solidity::Instruction::DUP3), byte(Instruction::DUP3),
byte(solidity::Instruction::DUP1), byte(Instruction::DUP1),
byte(solidity::Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,
byte(solidity::Instruction::SWAP1), byte(Instruction::SWAP1),
byte(solidity::Instruction::SUB), byte(Instruction::SUB),
// Stack here: (a+2) x a^(a+2) (a+2) (a+1) // Stack here: (a+2) x a^(a+2) (a+2) (a+1)
byte(solidity::Instruction::SWAP4), byte(Instruction::SWAP4),
byte(solidity::Instruction::POP), // first -- byte(Instruction::POP), // first --
byte(solidity::Instruction::XOR), byte(Instruction::XOR),
// Stack here: (a+1) x a^(a+2)^(a+2) // Stack here: (a+1) x a^(a+2)^(a+2)
byte(solidity::Instruction::DUP3), byte(Instruction::DUP3),
byte(solidity::Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,
byte(solidity::Instruction::SWAP1), byte(Instruction::SWAP1),
byte(solidity::Instruction::SUB), byte(Instruction::SUB),
// Stack here: (a+1) x a^(a+2)^(a+2) a // Stack here: (a+1) x a^(a+2)^(a+2) a
byte(solidity::Instruction::SWAP3), byte(Instruction::SWAP3),
byte(solidity::Instruction::POP), // second ++ byte(Instruction::POP), // second ++
// Stack here: a x a^(a+2)^(a+2) // Stack here: a x a^(a+2)^(a+2)
byte(solidity::Instruction::DUP3), // will change byte(Instruction::DUP3), // will change
byte(solidity::Instruction::XOR)}); byte(Instruction::XOR)});
// Stack here: a x a^(a+2)^(a+2)^a // Stack here: a x a^(a+2)^(a+2)^a
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -404,16 +404,16 @@ BOOST_AUTO_TEST_CASE(assignment)
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}}); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b // Stack: a, b
bytes expectation({byte(solidity::Instruction::PUSH1), 0x2, bytes expectation({byte(Instruction::PUSH1), 0x2,
byte(solidity::Instruction::DUP2), byte(Instruction::DUP2),
byte(solidity::Instruction::DUP4), byte(Instruction::DUP4),
byte(solidity::Instruction::ADD), byte(Instruction::ADD),
// Stack here: a b 2 a+b // Stack here: a b 2 a+b
byte(solidity::Instruction::SWAP3), byte(Instruction::SWAP3),
byte(solidity::Instruction::POP), byte(Instruction::POP),
byte(solidity::Instruction::DUP3), byte(Instruction::DUP3),
// Stack here: a+b b 2 a+b // Stack here: a+b b 2 a+b
byte(solidity::Instruction::MUL)}); byte(Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -427,26 +427,26 @@ BOOST_AUTO_TEST_CASE(function_call)
{{"test", "f", "a"}, {"test", "f", "b"}}); {{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b // Stack: a, b
bytes expectation({byte(solidity::Instruction::PUSH1), 0x02, bytes expectation({byte(Instruction::PUSH1), 0x02,
byte(solidity::Instruction::PUSH1), 0x0c, byte(Instruction::PUSH1), 0x0c,
byte(solidity::Instruction::PUSH1), 0x01, byte(Instruction::PUSH1), 0x01,
byte(solidity::Instruction::DUP5), byte(Instruction::DUP5),
byte(solidity::Instruction::ADD), byte(Instruction::ADD),
// Stack here: a b 2 <ret label> (a+1) // Stack here: a b 2 <ret label> (a+1)
byte(solidity::Instruction::DUP4), byte(Instruction::DUP4),
byte(solidity::Instruction::PUSH1), 0x13, byte(Instruction::PUSH1), 0x13,
byte(solidity::Instruction::JUMP), byte(Instruction::JUMP),
byte(solidity::Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
// Stack here: a b 2 g(a+1, b) // Stack here: a b 2 g(a+1, b)
byte(solidity::Instruction::MUL), byte(Instruction::MUL),
// Stack here: a b g(a+1, b)*2 // Stack here: a b g(a+1, b)*2
byte(solidity::Instruction::DUP3), byte(Instruction::DUP3),
byte(solidity::Instruction::ADD), byte(Instruction::ADD),
// Stack here: a b a+g(a+1, b)*2 // Stack here: a b a+g(a+1, b)*2
byte(solidity::Instruction::SWAP2), byte(Instruction::SWAP2),
byte(solidity::Instruction::POP), byte(Instruction::POP),
byte(solidity::Instruction::DUP2), byte(Instruction::DUP2),
byte(solidity::Instruction::JUMPDEST)}); byte(Instruction::JUMPDEST)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -457,7 +457,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_8bits)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(solidity::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80)); bytes expectation(bytes({byte(Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -468,7 +468,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_16bits)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(solidity::Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43}); bytes expectation(bytes({byte(Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -481,7 +481,7 @@ BOOST_AUTO_TEST_CASE(intermediately_overflowing_literals)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(solidity::Instruction::PUSH1), 0xbf})); bytes expectation(bytes({byte(Instruction::PUSH1), 0xbf}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -495,8 +495,8 @@ BOOST_AUTO_TEST_CASE(blockhash)
bytes code = compileFirstExpression(sourceCode, {}, {}, bytes code = compileFirstExpression(sourceCode, {}, {},
{make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block))}); {make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block))});
bytes expectation({byte(solidity::Instruction::PUSH1), 0x03, bytes expectation({byte(Instruction::PUSH1), 0x03,
byte(solidity::Instruction::BLOCKHASH)}); byte(Instruction::BLOCKHASH)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }