mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
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:
parent
820ed2dfe1
commit
38cb123a82
20
Compiler.cpp
20
Compiler.cpp
@ -273,6 +273,7 @@ void Compiler::initializeStateVariables(ContractDefinition const& _contract)
|
|||||||
bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
|
bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
|
||||||
{
|
{
|
||||||
solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
|
solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_variableDeclaration);
|
||||||
|
|
||||||
m_context.startFunction(_variableDeclaration);
|
m_context.startFunction(_variableDeclaration);
|
||||||
m_breakTags.clear();
|
m_breakTags.clear();
|
||||||
@ -286,6 +287,7 @@ bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
|
|||||||
|
|
||||||
bool Compiler::visit(FunctionDefinition const& _function)
|
bool Compiler::visit(FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_function);
|
||||||
//@todo to simplify this, the calling convention could by changed such that
|
//@todo to simplify this, the calling convention could by changed such that
|
||||||
// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
|
// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
|
||||||
// although note that this reduces the size of the visible stack
|
// 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)
|
bool Compiler::visit(IfStatement const& _ifStatement)
|
||||||
{
|
{
|
||||||
StackHeightChecker checker(m_context);
|
StackHeightChecker checker(m_context);
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_ifStatement);
|
||||||
compileExpression(_ifStatement.getCondition());
|
compileExpression(_ifStatement.getCondition());
|
||||||
eth::AssemblyItem trueTag = m_context.appendConditionalJump();
|
eth::AssemblyItem trueTag = m_context.appendConditionalJump();
|
||||||
if (_ifStatement.getFalseStatement())
|
if (_ifStatement.getFalseStatement())
|
||||||
@ -372,7 +374,7 @@ bool Compiler::visit(IfStatement const& _ifStatement)
|
|||||||
bool Compiler::visit(WhileStatement const& _whileStatement)
|
bool Compiler::visit(WhileStatement const& _whileStatement)
|
||||||
{
|
{
|
||||||
StackHeightChecker checker(m_context);
|
StackHeightChecker checker(m_context);
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_whileStatement);
|
||||||
eth::AssemblyItem loopStart = m_context.newTag();
|
eth::AssemblyItem loopStart = m_context.newTag();
|
||||||
eth::AssemblyItem loopEnd = m_context.newTag();
|
eth::AssemblyItem loopEnd = m_context.newTag();
|
||||||
m_continueTags.push_back(loopStart);
|
m_continueTags.push_back(loopStart);
|
||||||
@ -398,7 +400,7 @@ bool Compiler::visit(WhileStatement const& _whileStatement)
|
|||||||
bool Compiler::visit(ForStatement const& _forStatement)
|
bool Compiler::visit(ForStatement const& _forStatement)
|
||||||
{
|
{
|
||||||
StackHeightChecker checker(m_context);
|
StackHeightChecker checker(m_context);
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_forStatement);
|
||||||
eth::AssemblyItem loopStart = m_context.newTag();
|
eth::AssemblyItem loopStart = m_context.newTag();
|
||||||
eth::AssemblyItem loopEnd = m_context.newTag();
|
eth::AssemblyItem loopEnd = m_context.newTag();
|
||||||
m_continueTags.push_back(loopStart);
|
m_continueTags.push_back(loopStart);
|
||||||
@ -433,15 +435,17 @@ bool Compiler::visit(ForStatement const& _forStatement)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Compiler::visit(Continue const&)
|
bool Compiler::visit(Continue const& _continueStatement)
|
||||||
{
|
{
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_continueStatement);
|
||||||
if (!m_continueTags.empty())
|
if (!m_continueTags.empty())
|
||||||
m_context.appendJumpTo(m_continueTags.back());
|
m_context.appendJumpTo(m_continueTags.back());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Compiler::visit(Break const&)
|
bool Compiler::visit(Break const& _breakStatement)
|
||||||
{
|
{
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_breakStatement);
|
||||||
if (!m_breakTags.empty())
|
if (!m_breakTags.empty())
|
||||||
m_context.appendJumpTo(m_breakTags.back());
|
m_context.appendJumpTo(m_breakTags.back());
|
||||||
return false;
|
return false;
|
||||||
@ -449,6 +453,7 @@ bool Compiler::visit(Break const&)
|
|||||||
|
|
||||||
bool Compiler::visit(Return const& _return)
|
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
|
//@todo modifications are needed to make this work with functions returning multiple values
|
||||||
if (Expression const* expression = _return.getExpression())
|
if (Expression const* expression = _return.getExpression())
|
||||||
{
|
{
|
||||||
@ -467,6 +472,7 @@ bool Compiler::visit(Return const& _return)
|
|||||||
bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement)
|
bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement)
|
||||||
{
|
{
|
||||||
StackHeightChecker checker(m_context);
|
StackHeightChecker checker(m_context);
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_variableDefinition);
|
||||||
if (Expression const* expression = _variableDeclarationStatement.getExpression())
|
if (Expression const* expression = _variableDeclarationStatement.getExpression())
|
||||||
{
|
{
|
||||||
compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType());
|
compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType());
|
||||||
@ -479,6 +485,7 @@ bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationSta
|
|||||||
bool Compiler::visit(ExpressionStatement const& _expressionStatement)
|
bool Compiler::visit(ExpressionStatement const& _expressionStatement)
|
||||||
{
|
{
|
||||||
StackHeightChecker checker(m_context);
|
StackHeightChecker checker(m_context);
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_expressionStatement);
|
||||||
Expression const& expression = _expressionStatement.getExpression();
|
Expression const& expression = _expressionStatement.getExpression();
|
||||||
compileExpression(expression);
|
compileExpression(expression);
|
||||||
CompilerUtils(m_context).popStackElement(*expression.getType());
|
CompilerUtils(m_context).popStackElement(*expression.getType());
|
||||||
@ -486,9 +493,10 @@ bool Compiler::visit(ExpressionStatement const& _expressionStatement)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Compiler::visit(PlaceholderStatement const&)
|
bool Compiler::visit(PlaceholderStatement const& _placeholderStatement)
|
||||||
{
|
{
|
||||||
StackHeightChecker checker(m_context);
|
StackHeightChecker checker(m_context);
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_placeholderStatement);
|
||||||
++m_modifierDepth;
|
++m_modifierDepth;
|
||||||
appendModifierOrFunctionCode();
|
appendModifierOrFunctionCode();
|
||||||
--m_modifierDepth;
|
--m_modifierDepth;
|
||||||
|
@ -166,5 +166,33 @@ u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declarati
|
|||||||
return it->second;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <stack>
|
||||||
#include <libevmcore/Instruction.h>
|
#include <libevmcore/Instruction.h>
|
||||||
#include <libevmcore/Assembly.h>
|
#include <libevmcore/Assembly.h>
|
||||||
#include <libsolidity/ASTForward.h>
|
#include <libsolidity/ASTForward.h>
|
||||||
@ -99,19 +100,32 @@ public:
|
|||||||
void appendProgramSize() { return m_asm.appendProgramSize(); }
|
void appendProgramSize() { return m_asm.appendProgramSize(); }
|
||||||
/// Adds data to the data section, pushes a reference to the stack
|
/// Adds data to the data section, pushes a reference to the stack
|
||||||
eth::AssemblyItem appendData(bytes const& _data) { return m_asm.append(_data); }
|
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.
|
/// 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::AssemblyItem _item);
|
||||||
CompilerContext& operator<<(eth::Instruction _instruction) { m_asm.append(_instruction); return *this; }
|
CompilerContext& operator<<(eth::Instruction _instruction);
|
||||||
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; }
|
CompilerContext& operator<<(u256 const& _value);
|
||||||
CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; }
|
CompilerContext& operator<<(bytes const& _data);
|
||||||
|
|
||||||
eth::Assembly const& getAssembly() const { return m_asm; }
|
eth::Assembly const& getAssembly() const { return m_asm; }
|
||||||
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; }
|
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; }
|
||||||
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }
|
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;
|
eth::Assembly m_asm;
|
||||||
|
private:
|
||||||
|
|
||||||
/// Magic global variables like msg, tx or this, distinguished by type.
|
/// Magic global variables like msg, tx or this, distinguished by type.
|
||||||
std::set<Declaration const*> m_magicGlobals;
|
std::set<Declaration const*> m_magicGlobals;
|
||||||
@ -129,6 +143,8 @@ private:
|
|||||||
std::set<Declaration const*> m_functionsWithCode;
|
std::set<Declaration const*> m_functionsWithCode;
|
||||||
/// List of current inheritance hierarchy from derived to base.
|
/// List of current inheritance hierarchy from derived to base.
|
||||||
std::vector<ContractDefinition const*> m_inheritanceHierarchy;
|
std::vector<ContractDefinition const*> m_inheritanceHierarchy;
|
||||||
|
/// Stack of current visited AST nodes, used for location attachment
|
||||||
|
std::stack<ASTNode const*> m_visitedNodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
|
|||||||
|
|
||||||
bool ExpressionCompiler::visit(Assignment const& _assignment)
|
bool ExpressionCompiler::visit(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_assignment);
|
||||||
_assignment.getRightHandSide().accept(*this);
|
_assignment.getRightHandSide().accept(*this);
|
||||||
if (_assignment.getType()->isValueType())
|
if (_assignment.getType()->isValueType())
|
||||||
appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType());
|
appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType());
|
||||||
@ -99,6 +100,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
|||||||
|
|
||||||
bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
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:
|
//@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
|
// 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
|
// 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)
|
bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
|
||||||
{
|
{
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_binaryOperation);
|
||||||
Expression const& leftExpression = _binaryOperation.getLeftExpression();
|
Expression const& leftExpression = _binaryOperation.getLeftExpression();
|
||||||
Expression const& rightExpression = _binaryOperation.getRightExpression();
|
Expression const& rightExpression = _binaryOperation.getRightExpression();
|
||||||
Type const& commonType = _binaryOperation.getCommonType();
|
Type const& commonType = _binaryOperation.getCommonType();
|
||||||
@ -209,6 +212,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
|
|||||||
|
|
||||||
bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||||
{
|
{
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_functionCall);
|
||||||
using Location = FunctionType::Location;
|
using Location = FunctionType::Location;
|
||||||
if (_functionCall.isTypeConversion())
|
if (_functionCall.isTypeConversion())
|
||||||
{
|
{
|
||||||
@ -426,6 +430,7 @@ bool ExpressionCompiler::visit(NewExpression const&)
|
|||||||
|
|
||||||
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
||||||
{
|
{
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_memberAccess);
|
||||||
ASTString const& member = _memberAccess.getMemberName();
|
ASTString const& member = _memberAccess.getMemberName();
|
||||||
switch (_memberAccess.getExpression().getType()->getCategory())
|
switch (_memberAccess.getExpression().getType()->getCategory())
|
||||||
{
|
{
|
||||||
@ -562,6 +567,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
|||||||
|
|
||||||
bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||||
{
|
{
|
||||||
|
CompilerContext::LocationSetter locationSetter(m_context, &_indexAccess);
|
||||||
_indexAccess.getBaseExpression().accept(*this);
|
_indexAccess.getBaseExpression().accept(*this);
|
||||||
|
|
||||||
Type const& baseType = *_indexAccess.getBaseExpression().getType();
|
Type const& baseType = *_indexAccess.getBaseExpression().getType();
|
||||||
|
Loading…
Reference in New Issue
Block a user