Browse Source

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.
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
4c6bf04b87
  1. 3
      libevmcore/Assembly.cpp
  2. 7
      libevmcore/Assembly.h
  3. 20
      libsolidity/Compiler.cpp
  4. 28
      libsolidity/CompilerContext.cpp
  5. 26
      libsolidity/CompilerContext.h
  6. 6
      libsolidity/ExpressionCompiler.cpp

3
libevmcore/Assembly.cpp

@ -229,10 +229,11 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const
return _out; return _out;
} }
AssemblyItem const& Assembly::append(AssemblyItem const& _i) AssemblyItem const& Assembly::append(AssemblyItem const& _i, solidity::Location const& _location)
{ {
m_deposit += _i.deposit(); m_deposit += _i.deposit();
m_items.push_back(_i); m_items.push_back(_i);
m_items.back().setLocation(_location);
return back(); return back();
} }

7
libevmcore/Assembly.h

@ -25,6 +25,7 @@
#include <sstream> #include <sstream>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libevmcore/Instruction.h> #include <libevmcore/Instruction.h>
#include <libsolidity/BaseTypes.h>
#include "Exceptions.h" #include "Exceptions.h"
namespace dev namespace dev
@ -57,10 +58,12 @@ public:
int deposit() const; int deposit() const;
bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); } bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); }
void setLocation(dev::solidity::Location const& _location) { m_location = _location;}
private: private:
AssemblyItemType m_type; AssemblyItemType m_type;
u256 m_data; u256 m_data;
dev::solidity::Location m_location;
}; };
using AssemblyItems = std::vector<AssemblyItem>; using AssemblyItems = std::vector<AssemblyItem>;
@ -84,7 +87,7 @@ public:
AssemblyItem append() { return append(newTag()); } AssemblyItem append() { return append(newTag()); }
void append(Assembly const& _a); void append(Assembly const& _a);
void append(Assembly const& _a, int _deposit); void append(Assembly const& _a, int _deposit);
AssemblyItem const& append(AssemblyItem const& _i); AssemblyItem const& append(AssemblyItem const& _i, solidity::Location const& _location = solidity::Location());
AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); }
AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); }
AssemblyItem appendSubSize(Assembly const& _a) { auto ret = newSub(_a); append(newPushSubSize(ret.data())); return ret; } AssemblyItem appendSubSize(Assembly const& _a) { auto ret = newSub(_a); append(newPushSubSize(ret.data())); return ret; }
@ -99,7 +102,7 @@ public:
template <class T> Assembly& operator<<(T const& _d) { append(_d); return *this; } template <class T> Assembly& operator<<(T const& _d) { append(_d); return *this; }
AssemblyItem const& back() { return m_items.back(); } AssemblyItem const& back() const { return m_items.back(); }
std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); }
void onePath() { if (asserts(!m_totalDeposit && !m_baseDeposit)) BOOST_THROW_EXCEPTION(InvalidDeposit()); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } void onePath() { if (asserts(!m_totalDeposit && !m_baseDeposit)) BOOST_THROW_EXCEPTION(InvalidDeposit()); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; }

20
libsolidity/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;

28
libsolidity/CompilerContext.cpp

@ -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;
}
} }
} }

26
libsolidity/CompilerContext.h

@ -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;
}; };
} }

6
libsolidity/ExpressionCompiler.cpp

@ -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…
Cancel
Save