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 | |
parent | b7d856ed5fee1f0f918e30218e3a95fd8fc20dd3 (diff) | |
download | dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.tar dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.tar.gz dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.tar.bz2 dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.tar.lz dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.tar.xz dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.tar.zst dexon-solidity-35d5b28faeee5e19d0dbbeb3c75454249d636abd.zip |
Variable-size stack elements for expression compiler.
-rw-r--r-- | Compiler.cpp | 12 | ||||
-rw-r--r-- | CompilerUtils.cpp | 11 | ||||
-rw-r--r-- | CompilerUtils.h | 14 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 68 | ||||
-rw-r--r-- | ExpressionCompiler.h | 5 |
5 files changed, 84 insertions, 26 deletions
diff --git a/Compiler.cpp b/Compiler.cpp index e7263da6..73b3e324 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -213,15 +213,9 @@ bool Compiler::visit(FunctionDefinition& _function) // Note that the fact that the return arguments are of increasing index is vital for this // algorithm to work. - unsigned argumentsSize = 0; - for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters()) - argumentsSize += variable->getType()->getSizeOnStack(); - unsigned returnValuesSize = 0; - for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters()) - returnValuesSize += variable->getType()->getSizeOnStack(); - unsigned localVariablesSize = 0; - for (VariableDeclaration const* localVariable: _function.getLocalVariables()) - localVariablesSize += localVariable->getType()->getSizeOnStack(); + unsigned const argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters()); + unsigned const returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters()); + unsigned const localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables()); vector<int> stackLayout; stackLayout.push_back(returnValuesSize); // target of return address diff --git a/CompilerUtils.cpp b/CompilerUtils.cpp index b3d982c9..cbd92d2b 100644 --- a/CompilerUtils.cpp +++ b/CompilerUtils.cpp @@ -35,6 +35,9 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) { unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable)); unsigned const size = _variable.getType()->getSizeOnStack(); + if (stackPosition - size + 1 > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_variable.getLocation()) + << errinfo_comment("Stack too deep.")); for (unsigned i = 0; i < size; ++i) m_context << eth::swapInstruction(stackPosition - size + 1) << eth::Instruction::POP; } @@ -46,5 +49,13 @@ void CompilerUtils::popStackElement(Type const& _type) m_context << eth::Instruction::POP; } +unsigned CompilerUtils::getSizeOnStack(vector<shared_ptr<Type const>> const& _variableTypes) +{ + unsigned size = 0; + for (shared_ptr<Type const> const& type: _variableTypes) + size += type->getSizeOnStack(); + return size; +} + } } diff --git a/CompilerUtils.h b/CompilerUtils.h index 3b6f13e9..2aac7e4e 100644 --- a/CompilerUtils.h +++ b/CompilerUtils.h @@ -39,9 +39,23 @@ public: void moveToStackVariable(VariableDeclaration const& _variable); /// Removes the current value from the top of the stack. void popStackElement(Type const& _type); + + template <class T> + static unsigned getSizeOnStack(std::vector<T> const& _variables); + static unsigned getSizeOnStack(std::vector<std::shared_ptr<Type const>> const& _variableTypes); + private: CompilerContext& m_context; }; +template <class T> +unsigned CompilerUtils::getSizeOnStack(std::vector<T> const& _variables) +{ + unsigned size = 0; + for (T const& variable: _variables) + size += variable->getType()->getSizeOnStack(); + return size; +} + } } 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; diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index fbecbdc8..966be30e 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -93,8 +93,7 @@ private: enum LValueType { NONE, STACK, MEMORY, STORAGE }; explicit LValue(CompilerContext& _compilerContext): m_context(&_compilerContext) { reset(); } - LValue(CompilerContext& _compilerContext, LValueType _type, unsigned _baseStackOffset = 0): - m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset) {} + LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, unsigned _baseStackOffset = 0); /// Set type according to the declaration and retrieve the reference. /// @a _expression is the current expression @@ -129,6 +128,8 @@ private: /// If m_type is STACK, this is base stack offset (@see /// CompilerContext::getBaseStackOffsetOfVariable) of a local variable. unsigned m_baseStackOffset; + /// Size of the value of this lvalue on the stack. + unsigned m_stackSize; }; CompilerContext& m_context; |