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)
|
||||
{
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user