diff options
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.cpp | 70 |
1 files changed, 30 insertions, 40 deletions
diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index c6142011..c1efc72c 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -140,28 +140,11 @@ public: if (m_scope.lookup(_identifier.name, Scope::NonconstVisitor( [=](Scope::Variable& _var) { - if (!_var.active) - { - m_state.addError( - Error::Type::TypeError, - "Variable used before it was declared", - _identifier.location - ); - m_state.assembly.append(u256(0)); - return; - } - int heightDiff = m_state.assembly.deposit() - _var.stackHeight; - if (heightDiff <= 0 || heightDiff > 16) - { - m_state.addError( - Error::Type::TypeError, - "Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")", - _identifier.location - ); - m_state.assembly.append(u256(0)); - } - else + if (int heightDiff = variableHeightDiff(_var, _identifier.location, false)) m_state.assembly.append(solidity::dupInstruction(heightDiff)); + else + // Store something to balance the stack + m_state.assembly.append(u256(0)); }, [=](Scope::Label& _label) { @@ -266,25 +249,8 @@ private: if (m_scope.lookup(_variableName.name, Scope::Visitor( [=](Scope::Variable const& _var) { - if (!_var.active) - { - m_state.addError( - Error::Type::TypeError, - "Variable used before it was declared", - _location - ); - m_state.assembly.append(u256(0)); - return; - } - int heightDiff = m_state.assembly.deposit() - _var.stackHeight - 1; - if (heightDiff <= 0 || heightDiff > 16) - m_state.addError( - Error::Type::TypeError, - "Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")", - _location - ); - else - m_state.assembly.append(solidity::swapInstruction(heightDiff)); + if (int heightDiff = variableHeightDiff(_var, _location, true)) + m_state.assembly.append(solidity::swapInstruction(heightDiff - 1)); m_state.assembly.append(solidity::Instruction::POP); }, [=](Scope::Label const&) @@ -304,6 +270,30 @@ private: ); } + /// Determines the stack height difference to the given variables. Automatically generates + /// errors if it is not yet in scope or the height difference is too large. Returns 0 on + /// errors and the (positive) stack height difference otherwise. + int variableHeightDiff(Scope::Variable const& _var, SourceLocation const& _location, bool _forSwap) + { + if (!_var.active) + { + m_state.addError( Error::Type::TypeError, "Variable used before it was declared", _location); + return 0; + } + int heightDiff = m_state.assembly.deposit() - _var.stackHeight; + if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16)) + { + m_state.addError( + Error::Type::TypeError, + "Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")", + _location + ); + return 0; + } + else + return heightDiff; + } + void expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location) { if (m_state.assembly.deposit() != _oldHeight + 1) |