Adding location information to assembly items

- In order to facilitate this addition we also now have a ScopeGuard
  object used in the Compiler to set the currently visited node.
This commit is contained in:
Lefteris Karapetsas 2015-02-23 16:31:36 +01:00
parent 820ed2dfe1
commit 38cb123a82
4 changed files with 69 additions and 11 deletions

View File

@ -273,6 +273,7 @@ void Compiler::initializeStateVariables(ContractDefinition const& _contract)
bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
{
solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
CompilerContext::LocationSetter locationSetter(m_context, &_variableDeclaration);
m_context.startFunction(_variableDeclaration);
m_breakTags.clear();
@ -286,6 +287,7 @@ bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
bool Compiler::visit(FunctionDefinition const& _function)
{
CompilerContext::LocationSetter locationSetter(m_context, &_function);
//@todo to simplify this, the calling convention could by changed such that
// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
// although note that this reduces the size of the visible stack
@ -355,7 +357,7 @@ bool Compiler::visit(FunctionDefinition const& _function)
bool Compiler::visit(IfStatement const& _ifStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_ifStatement);
compileExpression(_ifStatement.getCondition());
eth::AssemblyItem trueTag = m_context.appendConditionalJump();
if (_ifStatement.getFalseStatement())
@ -372,7 +374,7 @@ bool Compiler::visit(IfStatement const& _ifStatement)
bool Compiler::visit(WhileStatement const& _whileStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_whileStatement);
eth::AssemblyItem loopStart = m_context.newTag();
eth::AssemblyItem loopEnd = m_context.newTag();
m_continueTags.push_back(loopStart);
@ -398,7 +400,7 @@ bool Compiler::visit(WhileStatement const& _whileStatement)
bool Compiler::visit(ForStatement const& _forStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_forStatement);
eth::AssemblyItem loopStart = m_context.newTag();
eth::AssemblyItem loopEnd = m_context.newTag();
m_continueTags.push_back(loopStart);
@ -433,15 +435,17 @@ bool Compiler::visit(ForStatement const& _forStatement)
return false;
}
bool Compiler::visit(Continue const&)
bool Compiler::visit(Continue const& _continueStatement)
{
CompilerContext::LocationSetter locationSetter(m_context, &_continueStatement);
if (!m_continueTags.empty())
m_context.appendJumpTo(m_continueTags.back());
return false;
}
bool Compiler::visit(Break const&)
bool Compiler::visit(Break const& _breakStatement)
{
CompilerContext::LocationSetter locationSetter(m_context, &_breakStatement);
if (!m_breakTags.empty())
m_context.appendJumpTo(m_breakTags.back());
return false;
@ -449,6 +453,7 @@ bool Compiler::visit(Break const&)
bool Compiler::visit(Return const& _return)
{
CompilerContext::LocationSetter locationSetter(m_context, &_return);
//@todo modifications are needed to make this work with functions returning multiple values
if (Expression const* expression = _return.getExpression())
{
@ -467,6 +472,7 @@ bool Compiler::visit(Return const& _return)
bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_variableDefinition);
if (Expression const* expression = _variableDeclarationStatement.getExpression())
{
compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType());
@ -479,6 +485,7 @@ bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationSta
bool Compiler::visit(ExpressionStatement const& _expressionStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_expressionStatement);
Expression const& expression = _expressionStatement.getExpression();
compileExpression(expression);
CompilerUtils(m_context).popStackElement(*expression.getType());
@ -486,9 +493,10 @@ bool Compiler::visit(ExpressionStatement const& _expressionStatement)
return false;
}
bool Compiler::visit(PlaceholderStatement const&)
bool Compiler::visit(PlaceholderStatement const& _placeholderStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_placeholderStatement);
++m_modifierDepth;
appendModifierOrFunctionCode();
--m_modifierDepth;

View File

@ -166,5 +166,33 @@ u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declarati
return it->second;
}
CompilerContext& CompilerContext::operator<<(eth::AssemblyItem _item)
{
solAssert(m_visitedNodes.size() > 0, "No node on the visited stack");
m_asm.append(_item);
return *this;
}
CompilerContext& CompilerContext::operator<<(eth::Instruction _instruction)
{
solAssert(m_visitedNodes.size() > 0, "No node on the visited stack");
m_asm.append(_instruction);
return *this;
}
CompilerContext& CompilerContext::operator<<(u256 const& _value)
{
solAssert(m_visitedNodes.size() > 0, "No node on the visited stack");
m_asm.append(_value);
return *this;
}
CompilerContext& CompilerContext::operator<<(bytes const& _data)
{
solAssert(m_visitedNodes.size() > 0, "No node on the visited stack");
m_asm.append(_data);
return *this;
}
}
}

View File

@ -23,6 +23,7 @@
#pragma once
#include <ostream>
#include <stack>
#include <libevmcore/Instruction.h>
#include <libevmcore/Assembly.h>
#include <libsolidity/ASTForward.h>
@ -99,19 +100,32 @@ public:
void appendProgramSize() { return m_asm.appendProgramSize(); }
/// Adds data to the data section, pushes a reference to the stack
eth::AssemblyItem appendData(bytes const& _data) { return m_asm.append(_data); }
/// Pops the stack of visited nodes
void popVisitedNodes() { m_visitedNodes.pop();}
/// Pushes an ASTNode to the stack of visited nodes
void pushVisitedNodes(ASTNode const* _node) { m_visitedNodes.push(_node); }
/// 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::Instruction _instruction) { m_asm.append(_instruction); 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<<(eth::AssemblyItem _item);
CompilerContext& operator<<(eth::Instruction _instruction);
CompilerContext& operator<<(u256 const& _value);
CompilerContext& operator<<(bytes const& _data);
eth::Assembly const& getAssembly() const { return m_asm; }
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; }
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }
private:
/**
* Helper class to pop the visited nodes stack when a scope closes
*/
class LocationSetter: public ScopeGuard
{
public:
LocationSetter(CompilerContext& _compilerContext, ASTNode const* _node):
ScopeGuard(std::bind(&CompilerContext::popVisitedNodes, _compilerContext)) { _compilerContext.pushVisitedNodes(_node); }
};
eth::Assembly m_asm;
private:
/// Magic global variables like msg, tx or this, distinguished by type.
std::set<Declaration const*> m_magicGlobals;
@ -129,6 +143,8 @@ private:
std::set<Declaration const*> m_functionsWithCode;
/// List of current inheritance hierarchy from derived to base.
std::vector<ContractDefinition const*> m_inheritanceHierarchy;
/// Stack of current visited AST nodes, used for location attachment
std::stack<ASTNode const*> m_visitedNodes;
};
}

View File

@ -75,6 +75,7 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
bool ExpressionCompiler::visit(Assignment const& _assignment)
{
CompilerContext::LocationSetter locationSetter(m_context, &_assignment);
_assignment.getRightHandSide().accept(*this);
if (_assignment.getType()->isValueType())
appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType());
@ -99,6 +100,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
{
CompilerContext::LocationSetter locationSetter(m_context, &_unaryOperation);
//@todo type checking and creating code for an operator should be in the same place:
// the operator should know how to convert itself and to which types it applies, so
// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
@ -163,6 +165,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
{
CompilerContext::LocationSetter locationSetter(m_context, &_binaryOperation);
Expression const& leftExpression = _binaryOperation.getLeftExpression();
Expression const& rightExpression = _binaryOperation.getRightExpression();
Type const& commonType = _binaryOperation.getCommonType();
@ -209,6 +212,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
CompilerContext::LocationSetter locationSetter(m_context, &_functionCall);
using Location = FunctionType::Location;
if (_functionCall.isTypeConversion())
{
@ -426,6 +430,7 @@ bool ExpressionCompiler::visit(NewExpression const&)
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{
CompilerContext::LocationSetter locationSetter(m_context, &_memberAccess);
ASTString const& member = _memberAccess.getMemberName();
switch (_memberAccess.getExpression().getType()->getCategory())
{
@ -562,6 +567,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
{
CompilerContext::LocationSetter locationSetter(m_context, &_indexAccess);
_indexAccess.getBaseExpression().accept(*this);
Type const& baseType = *_indexAccess.getBaseExpression().getType();