diff options
author | Christian <c@ethdev.com> | 2014-12-09 05:18:19 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2014-12-09 05:26:22 +0800 |
commit | 35d5b28faeee5e19d0dbbeb3c75454249d636abd (patch) | |
tree | 227b04a23f5d66e442fc824e4cfcbba802989ccd /ExpressionCompiler.cpp | |
parent | b7d856ed5fee1f0f918e30218e3a95fd8fc20dd3 (diff) | |
download | dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.tar.gz dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.tar.zst dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.zip |
Variable-size stack elements for expression compiler.
Diffstat (limited to 'ExpressionCompiler.cpp')
-rw-r--r-- | ExpressionCompiler.cpp | 68 |
1 files changed, 53 insertions, 15 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 352b0e6d..5deb5063 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -26,6 +26,7 @@ #include <libsolidity/AST.h> #include <libsolidity/ExpressionCompiler.h> #include <libsolidity/CompilerContext.h> +#include <libsolidity/CompilerUtils.h> using namespace std; @@ -174,9 +175,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) // explicit type conversion contract -> address, nothing to do. } else - { appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); - } } else { @@ -203,13 +202,14 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) m_context.appendJump(); m_context << returnLabel; + unsigned returnParametersSize = CompilerUtils::getSizeOnStack(function.getReturnParameterTypes()); // callee adds return parameters, but removes arguments and return label - m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1); + m_context.adjustStackOffset(returnParametersSize - CompilerUtils::getSizeOnStack(arguments) - 1); // @todo for now, the return value of a function is its first return value, so remove // all others for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) - m_context << eth::Instruction::POP; + CompilerUtils(m_context).popStackElement(*function.getReturnParameterTypes()[i]); break; } case Location::EXTERNAL: @@ -356,7 +356,7 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) { StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType()); m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD; - m_currentLValue = LValue(m_context, LValue::STORAGE); + m_currentLValue = LValue(m_context, LValue::STORAGE, *_memberAccess.getType()); m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); break; } @@ -376,7 +376,7 @@ bool ExpressionCompiler::visit(IndexAccess& _indexAccess) m_context << u256(32) << eth::Instruction::MSTORE << u256(0) << eth::Instruction::MSTORE; m_context << u256(64) << u256(0) << eth::Instruction::SHA3; - m_currentLValue = LValue(m_context, LValue::STORAGE); + m_currentLValue = LValue(m_context, LValue::STORAGE, *_indexAccess.getType()); m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); return false; @@ -565,6 +565,13 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; } +ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, const Type& _dataType, + unsigned _baseStackOffset): + m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset), + m_stackSize(_dataType.getSizeOnStack()) +{ +} + void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bool _remove) const { switch (m_type) @@ -575,7 +582,8 @@ 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.")); - *m_context << eth::dupInstruction(stackPos + 1); + for (unsigned i = 0; i < m_stackSize; ++i) + *m_context << eth::dupInstruction(stackPos + 1); break; } case STORAGE: @@ -583,7 +591,17 @@ 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; - *m_context << eth::Instruction::SLOAD; + if (m_stackSize == 1) + *m_context << eth::Instruction::SLOAD; + else + for (unsigned i = 0; i < m_stackSize; ++i) + { + *m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1; + if (i + 1 < m_stackSize) + *m_context << u256(1) << eth::Instruction::ADD; + else + *m_context << eth::Instruction::POP; + } break; case MEMORY: if (!_expression.getType()->isValueType()) @@ -604,12 +622,13 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool { case STACK: { - unsigned stackPos = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); - if (stackPos > 16) + unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_stackSize + 1; + if (stackDiff > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); - else if (stackPos > 0) - *m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; + else if (stackDiff > 0) + for (unsigned i = 0; i < m_stackSize; ++i) + *m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; if (!_move) retrieveValue(_expression); break; @@ -617,9 +636,27 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool case LValue::STORAGE: if (!_expression.getType()->isValueType()) break; // no distinction between value and reference for non-value types - if (!_move) - *m_context << eth::Instruction::DUP2 << eth::Instruction::SWAP1; - *m_context << eth::Instruction::SSTORE; + // stack layout: value value ... value ref + if (!_move) // copy values + { + if (m_stackSize + 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; + } + 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 (i + 1 >= m_stackSize) + *m_context << eth::Instruction::SSTORE; + else + // v v ... v v r+x + *m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 + << eth::Instruction::SSTORE + << u256(1) << eth::Instruction::SWAP1 << eth::Instruction::SUB; + } break; case LValue::MEMORY: if (!_expression.getType()->isValueType()) @@ -645,6 +682,7 @@ 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; |