diff options
author | liana <liana@ethdev.com> | 2015-01-14 20:52:03 +0800 |
---|---|---|
committer | liana <liana@ethdev.com> | 2015-01-15 18:59:58 +0800 |
commit | 00b0b0933de8f745451652e8838f0c09a741228e (patch) | |
tree | 793020607eeba7ede1ed0356a215385dd5bf13e0 /ExpressionCompiler.cpp | |
parent | 6e16107870494878635da347146b076a7d75dea0 (diff) | |
download | dexon-solidity-00b0b0933de8f745451652e8838f0c09a741228e.tar.gz dexon-solidity-00b0b0933de8f745451652e8838f0c09a741228e.tar.zst dexon-solidity-00b0b0933de8f745451652e8838f0c09a741228e.zip |
- added functionality to set values to 0 when deleting structure(not for mapping)
- added unit test
Made some changes after Christian`s review on pull request
- remove/edit comments
- BoolType and ContractType return VoidType after delete
- fixed constructor_arguments test
- fixed set to 0 when deleting variable from stack
- changed test case to test that
Diffstat (limited to 'ExpressionCompiler.cpp')
-rw-r--r-- | ExpressionCompiler.cpp | 89 |
1 files changed, 66 insertions, 23 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 1c02f4f3..c8b7f350 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -94,13 +94,8 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) m_context << eth::Instruction::NOT; break; case Token::DELETE: // delete - // @todo semantics change for complex types solAssert(m_currentLValue.isValid(), "LValue not retrieved."); - - m_context << u256(0); - if (m_currentLValue.storesReferenceOnStack()) - m_context << eth::Instruction::SWAP1; - m_currentLValue.storeValue(_unaryOperation); + m_currentLValue.setToZero(_unaryOperation); m_currentLValue.reset(); break; case Token::INC: // ++ (pre- or postfix) @@ -696,9 +691,14 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, unsigned _baseStackOffset): - m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset), - m_stackSize(_dataType.getSizeOnStack()) + m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset) { + //@todo change the type cast for arrays + solAssert(_dataType.getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " +_dataType.toString() + " should fit in unsigned"); + if (m_type == STORAGE) + m_size = unsigned(_dataType.getStorageSize()); + else + m_size = unsigned(_dataType.getSizeOnStack()); } void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bool _remove) const @@ -711,7 +711,7 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); - for (unsigned i = 0; i < m_stackSize; ++i) + for (unsigned i = 0; i < m_size; ++i) *m_context << eth::dupInstruction(stackPos + 1); break; } @@ -720,14 +720,14 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo break; // no distinction between value and reference for non-value types if (!_remove) *m_context << eth::Instruction::DUP1; - if (m_stackSize == 1) + if (m_size == 1) *m_context << eth::Instruction::SLOAD; else - for (unsigned i = 0; i < m_stackSize; ++i) + for (unsigned i = 0; i < m_size; ++i) { *m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1; - if (i + 1 < m_stackSize) - *m_context << u256(1) << eth::Instruction::ADD; + if (i + 1 < m_size) + *m_context << u256(1) << eth::Instruction::ADD; else *m_context << eth::Instruction::POP; } @@ -751,12 +751,12 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool { case STACK: { - unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_stackSize + 1; + unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1; if (stackDiff > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); else if (stackDiff > 0) - for (unsigned i = 0; i < m_stackSize; ++i) + for (unsigned i = 0; i < m_size; ++i) *m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; if (!_move) retrieveValue(_expression); @@ -768,17 +768,17 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool // stack layout: value value ... value ref if (!_move) // copy values { - if (m_stackSize + 1 > 16) + if (m_size + 1 > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); - for (unsigned i = 0; i < m_stackSize; ++i) - *m_context << eth::dupInstruction(m_stackSize + 1) << eth::Instruction::SWAP1; + for (unsigned i = 0; i < m_size; ++i) + *m_context << eth::dupInstruction(m_size + 1) << eth::Instruction::SWAP1; } - if (m_stackSize > 0) // store high index value first - *m_context << u256(m_stackSize - 1) << eth::Instruction::ADD; - for (unsigned i = 0; i < m_stackSize; ++i) + if (m_size > 0) // store high index value first + *m_context << u256(m_size - 1) << eth::Instruction::ADD; + for (unsigned i = 0; i < m_size; ++i) { - if (i + 1 >= m_stackSize) + if (i + 1 >= m_size) *m_context << eth::Instruction::SSTORE; else // v v ... v v r+x @@ -800,6 +800,47 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool } } +void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const +{ + switch (m_type) + { + case STACK: + { + unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); + if (stackDiff > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + else if (stackDiff > 0) + for (unsigned i = 0; i < m_size; ++i) + *m_context << u256(0) << eth::swapInstruction(m_size - i) << eth::Instruction::POP; + break; + } + case LValue::STORAGE: + if (m_size == 0) + *m_context << eth::Instruction::POP; + for (unsigned i = 0; i < m_size; ++i) + { + if (i + 1 >= m_size) + *m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; + else + *m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE + << u256(1) << eth::Instruction::ADD; + } + break; + case LValue::MEMORY: + if (!_expression.getType()->isValueType()) + break; // no distinction between value and reference for non-value types + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Location type not yet implemented.")); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Unsupported location type.")); + break; + } + +} + void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression const& _expression) { if (!_expression.lvalueRequested()) @@ -811,15 +852,17 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration) { - m_stackSize = _identifier.getType()->getSizeOnStack(); if (m_context->isLocalVariable(&_declaration)) { m_type = STACK; + m_size = _identifier.getType()->getSizeOnStack(); m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } else if (m_context->isStateVariable(&_declaration)) { m_type = STORAGE; + solAssert(_identifier.getType()->getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " + _identifier.getType()->toString() + " should fit in unsigned"); + m_size = unsigned(_identifier.getType()->getStorageSize()); *m_context << m_context->getStorageLocationOfVariable(_declaration); } else |