From 38cb123a82dfa0d77c7eb629dfb9307463548a12 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 23 Feb 2015 16:31:36 +0100 Subject: [PATCH 01/13] 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. --- Compiler.cpp | 20 ++++++++++++++------ CompilerContext.cpp | 28 ++++++++++++++++++++++++++++ CompilerContext.h | 26 +++++++++++++++++++++----- ExpressionCompiler.cpp | 6 ++++++ 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/Compiler.cpp b/Compiler.cpp index e691394cb..7b79959c9 100644 --- a/Compiler.cpp +++ b/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; diff --git a/CompilerContext.cpp b/CompilerContext.cpp index 8d32a1a53..c599be5ef 100644 --- a/CompilerContext.cpp +++ b/CompilerContext.cpp @@ -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; +} + } } diff --git a/CompilerContext.h b/CompilerContext.h index da2e7f4fe..c07d9fb2f 100644 --- a/CompilerContext.h +++ b/CompilerContext.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include #include #include @@ -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 m_magicGlobals; @@ -129,6 +143,8 @@ private: std::set m_functionsWithCode; /// List of current inheritance hierarchy from derived to base. std::vector m_inheritanceHierarchy; + /// Stack of current visited AST nodes, used for location attachment + std::stack m_visitedNodes; }; } diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 183864ec7..9f8c8bbbe 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -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(); From 1891020ffb7d91b7eca4f69cc65e3722d6920361 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 23 Feb 2015 17:14:59 +0100 Subject: [PATCH 02/13] Moving Source Location libdevcore - Big plus is we now remove the useless header libsolibity/BaseTypes.h --- AST.h | 94 ++++++++++++++++++------------------ ASTPrinter.cpp | 2 +- BaseTypes.h | 60 ----------------------- Exceptions.h | 4 +- ExpressionCompiler.cpp | 12 ++--- ExpressionCompiler.h | 10 ++-- Parser.cpp | 6 +-- Scanner.h | 10 ++-- SourceReferenceFormatter.cpp | 4 +- SourceReferenceFormatter.h | 4 +- 10 files changed, 73 insertions(+), 133 deletions(-) delete mode 100644 BaseTypes.h diff --git a/AST.h b/AST.h index 60648cdc2..27dc008a8 100644 --- a/AST.h +++ b/AST.h @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -51,7 +51,7 @@ class ASTConstVisitor; class ASTNode: private boost::noncopyable { public: - explicit ASTNode(Location const& _location): m_location(_location) {} + explicit ASTNode(SourceLocation const& _location): m_location(_location) {} virtual ~ASTNode() {} @@ -71,7 +71,7 @@ public: } /// Returns the source code location of this node. - Location const& getLocation() const { return m_location; } + SourceLocation const& getLocation() const { return m_location; } /// Creates a @ref TypeError exception and decorates it with the location of the node and /// the given description @@ -85,7 +85,7 @@ public: ///@} private: - Location m_location; + SourceLocation m_location; }; /** @@ -94,7 +94,7 @@ private: class SourceUnit: public ASTNode { public: - SourceUnit(Location const& _location, std::vector> const& _nodes): + SourceUnit(SourceLocation const& _location, std::vector> const& _nodes): ASTNode(_location), m_nodes(_nodes) {} virtual void accept(ASTVisitor& _visitor) override; @@ -114,7 +114,7 @@ private: class ImportDirective: public ASTNode { public: - ImportDirective(Location const& _location, ASTPointer const& _identifier): + ImportDirective(SourceLocation const& _location, ASTPointer const& _identifier): ASTNode(_location), m_identifier(_identifier) {} virtual void accept(ASTVisitor& _visitor) override; @@ -135,7 +135,7 @@ public: /// Visibility ordered from restricted to unrestricted. enum class Visibility { Default, Private, Internal, Public, External }; - Declaration(Location const& _location, ASTPointer const& _name, + Declaration(SourceLocation const& _location, ASTPointer const& _name, Visibility _visibility = Visibility::Default): ASTNode(_location), m_name(_name), m_visibility(_visibility), m_scope(nullptr) {} @@ -205,7 +205,7 @@ protected: class ContractDefinition: public Declaration, public Documented { public: - ContractDefinition(Location const& _location, + ContractDefinition(SourceLocation const& _location, ASTPointer const& _name, ASTPointer const& _documentation, std::vector> const& _baseContracts, @@ -278,7 +278,7 @@ private: class InheritanceSpecifier: public ASTNode { public: - InheritanceSpecifier(Location const& _location, ASTPointer const& _baseName, + InheritanceSpecifier(SourceLocation const& _location, ASTPointer const& _baseName, std::vector> _arguments): ASTNode(_location), m_baseName(_baseName), m_arguments(_arguments) {} @@ -298,7 +298,7 @@ private: class StructDefinition: public Declaration { public: - StructDefinition(Location const& _location, + StructDefinition(SourceLocation const& _location, ASTPointer const& _name, std::vector> const& _members): Declaration(_location, _name), m_members(_members) {} @@ -323,7 +323,7 @@ private: class EnumDefinition: public Declaration { public: - EnumDefinition(Location const& _location, + EnumDefinition(SourceLocation const& _location, ASTPointer const& _name, std::vector> const& _members): Declaration(_location, _name), m_members(_members) {} @@ -344,7 +344,7 @@ private: class EnumValue: public Declaration { public: - EnumValue(Location const& _location, + EnumValue(SourceLocation const& _location, ASTPointer const& _name): Declaration(_location, _name) {} @@ -361,7 +361,7 @@ class EnumValue: public Declaration class ParameterList: public ASTNode { public: - ParameterList(Location const& _location, + ParameterList(SourceLocation const& _location, std::vector> const& _parameters): ASTNode(_location), m_parameters(_parameters) {} virtual void accept(ASTVisitor& _visitor) override; @@ -376,7 +376,7 @@ private: class FunctionDefinition: public Declaration, public VariableScope, public Documented { public: - FunctionDefinition(Location const& _location, ASTPointer const& _name, + FunctionDefinition(SourceLocation const& _location, ASTPointer const& _name, Declaration::Visibility _visibility, bool _isConstructor, ASTPointer const& _documentation, ASTPointer const& _parameters, @@ -431,7 +431,7 @@ private: class VariableDeclaration: public Declaration { public: - VariableDeclaration(Location const& _location, ASTPointer const& _type, + VariableDeclaration(SourceLocation const& _location, ASTPointer const& _type, ASTPointer const& _name, ASTPointer _value, Visibility _visibility, bool _isStateVar = false, bool _isIndexed = false): @@ -476,7 +476,7 @@ private: class ModifierDefinition: public Declaration, public VariableScope, public Documented { public: - ModifierDefinition(Location const& _location, + ModifierDefinition(SourceLocation const& _location, ASTPointer const& _name, ASTPointer const& _documentation, ASTPointer const& _parameters, @@ -506,7 +506,7 @@ private: class ModifierInvocation: public ASTNode { public: - ModifierInvocation(Location const& _location, ASTPointer const& _name, + ModifierInvocation(SourceLocation const& _location, ASTPointer const& _name, std::vector> _arguments): ASTNode(_location), m_modifierName(_name), m_arguments(_arguments) {} @@ -529,7 +529,7 @@ private: class EventDefinition: public Declaration, public VariableScope, public Documented { public: - EventDefinition(Location const& _location, + EventDefinition(SourceLocation const& _location, ASTPointer const& _name, ASTPointer const& _documentation, ASTPointer const& _parameters): @@ -560,7 +560,7 @@ class MagicVariableDeclaration: public Declaration { public: MagicVariableDeclaration(ASTString const& _name, std::shared_ptr const& _type): - Declaration(Location(), std::make_shared(_name)), m_type(_type) {} + Declaration(SourceLocation(), std::make_shared(_name)), m_type(_type) {} virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST.")); } virtual void accept(ASTConstVisitor&) const override { BOOST_THROW_EXCEPTION(InternalCompilerError() @@ -581,7 +581,7 @@ private: class TypeName: public ASTNode { public: - explicit TypeName(Location const& _location): ASTNode(_location) {} + explicit TypeName(SourceLocation const& _location): ASTNode(_location) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -598,7 +598,7 @@ public: class ElementaryTypeName: public TypeName { public: - explicit ElementaryTypeName(Location const& _location, Token::Value _type): + explicit ElementaryTypeName(SourceLocation const& _location, Token::Value _type): TypeName(_location), m_type(_type) { solAssert(Token::isElementaryTypeName(_type), ""); @@ -619,7 +619,7 @@ private: class UserDefinedTypeName: public TypeName { public: - UserDefinedTypeName(Location const& _location, ASTPointer const& _name): + UserDefinedTypeName(SourceLocation const& _location, ASTPointer const& _name): TypeName(_location), m_name(_name), m_referencedDeclaration(nullptr) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -641,7 +641,7 @@ private: class Mapping: public TypeName { public: - Mapping(Location const& _location, ASTPointer const& _keyType, + Mapping(SourceLocation const& _location, ASTPointer const& _keyType, ASTPointer const& _valueType): TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {} virtual void accept(ASTVisitor& _visitor) override; @@ -689,7 +689,7 @@ private: class Statement: public ASTNode { public: - explicit Statement(Location const& _location): ASTNode(_location) {} + explicit Statement(SourceLocation const& _location): ASTNode(_location) {} /// Check all type requirements, throws exception if some requirement is not met. /// This includes checking that operators are applicable to their arguments but also that @@ -703,7 +703,7 @@ public: class Block: public Statement { public: - Block(Location const& _location, std::vector> const& _statements): + Block(SourceLocation const& _location, std::vector> const& _statements): Statement(_location), m_statements(_statements) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -721,7 +721,7 @@ private: class PlaceholderStatement: public Statement { public: - PlaceholderStatement(Location const& _location): Statement(_location) {} + PlaceholderStatement(SourceLocation const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -736,7 +736,7 @@ public: class IfStatement: public Statement { public: - IfStatement(Location const& _location, ASTPointer const& _condition, + IfStatement(SourceLocation const& _location, ASTPointer const& _condition, ASTPointer const& _trueBody, ASTPointer const& _falseBody): Statement(_location), m_condition(_condition), m_trueBody(_trueBody), m_falseBody(_falseBody) {} @@ -761,13 +761,13 @@ private: class BreakableStatement: public Statement { public: - BreakableStatement(Location const& _location): Statement(_location) {} + BreakableStatement(SourceLocation const& _location): Statement(_location) {} }; class WhileStatement: public BreakableStatement { public: - WhileStatement(Location const& _location, ASTPointer const& _condition, + WhileStatement(SourceLocation const& _location, ASTPointer const& _condition, ASTPointer const& _body): BreakableStatement(_location), m_condition(_condition), m_body(_body) {} virtual void accept(ASTVisitor& _visitor) override; @@ -788,7 +788,7 @@ private: class ForStatement: public BreakableStatement { public: - ForStatement(Location const& _location, + ForStatement(SourceLocation const& _location, ASTPointer const& _initExpression, ASTPointer const& _conditionExpression, ASTPointer const& _loopExpression, @@ -821,7 +821,7 @@ private: class Continue: public Statement { public: - Continue(Location const& _location): Statement(_location) {} + Continue(SourceLocation const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override {} @@ -830,7 +830,7 @@ public: class Break: public Statement { public: - Break(Location const& _location): Statement(_location) {} + Break(SourceLocation const& _location): Statement(_location) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override {} @@ -839,7 +839,7 @@ public: class Return: public Statement { public: - Return(Location const& _location, ASTPointer _expression): + Return(SourceLocation const& _location, ASTPointer _expression): Statement(_location), m_expression(_expression), m_returnParameters(nullptr) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -864,7 +864,7 @@ private: class VariableDeclarationStatement: public Statement { public: - VariableDeclarationStatement(Location const& _location, ASTPointer _variable): + VariableDeclarationStatement(SourceLocation const& _location, ASTPointer _variable): Statement(_location), m_variable(_variable) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -883,7 +883,7 @@ private: class ExpressionStatement: public Statement { public: - ExpressionStatement(Location const& _location, ASTPointer _expression): + ExpressionStatement(SourceLocation const& _location, ASTPointer _expression): Statement(_location), m_expression(_expression) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -908,7 +908,7 @@ private: class Expression: public ASTNode { public: - Expression(Location const& _location): ASTNode(_location) {} + Expression(SourceLocation const& _location): ASTNode(_location) {} virtual void checkTypeRequirements() = 0; std::shared_ptr const& getType() const { return m_type; } @@ -939,7 +939,7 @@ protected: class Assignment: public Expression { public: - Assignment(Location const& _location, ASTPointer const& _leftHandSide, + Assignment(SourceLocation const& _location, ASTPointer const& _leftHandSide, Token::Value _assignmentOperator, ASTPointer const& _rightHandSide): Expression(_location), m_leftHandSide(_leftHandSide), m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide) @@ -967,7 +967,7 @@ private: class UnaryOperation: public Expression { public: - UnaryOperation(Location const& _location, Token::Value _operator, + UnaryOperation(SourceLocation const& _location, Token::Value _operator, ASTPointer const& _subExpression, bool _isPrefix): Expression(_location), m_operator(_operator), m_subExpression(_subExpression), m_isPrefix(_isPrefix) @@ -995,7 +995,7 @@ private: class BinaryOperation: public Expression { public: - BinaryOperation(Location const& _location, ASTPointer const& _left, + BinaryOperation(SourceLocation const& _location, ASTPointer const& _left, Token::Value _operator, ASTPointer const& _right): Expression(_location), m_left(_left), m_operator(_operator), m_right(_right) { @@ -1026,7 +1026,7 @@ private: class FunctionCall: public Expression { public: - FunctionCall(Location const& _location, ASTPointer const& _expression, + FunctionCall(SourceLocation const& _location, ASTPointer const& _expression, std::vector> const& _arguments, std::vector> const& _names): Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {} virtual void accept(ASTVisitor& _visitor) override; @@ -1053,7 +1053,7 @@ private: class NewExpression: public Expression { public: - NewExpression(Location const& _location, ASTPointer const& _contractName): + NewExpression(SourceLocation const& _location, ASTPointer const& _contractName): Expression(_location), m_contractName(_contractName) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -1074,7 +1074,7 @@ private: class MemberAccess: public Expression { public: - MemberAccess(Location const& _location, ASTPointer _expression, + MemberAccess(SourceLocation const& _location, ASTPointer _expression, ASTPointer const& _memberName): Expression(_location), m_expression(_expression), m_memberName(_memberName) {} virtual void accept(ASTVisitor& _visitor) override; @@ -1094,7 +1094,7 @@ private: class IndexAccess: public Expression { public: - IndexAccess(Location const& _location, ASTPointer const& _base, + IndexAccess(SourceLocation const& _location, ASTPointer const& _base, ASTPointer const& _index): Expression(_location), m_base(_base), m_index(_index) {} virtual void accept(ASTVisitor& _visitor) override; @@ -1116,7 +1116,7 @@ private: class PrimaryExpression: public Expression { public: - PrimaryExpression(Location const& _location): Expression(_location) {} + PrimaryExpression(SourceLocation const& _location): Expression(_location) {} }; /** @@ -1125,7 +1125,7 @@ public: class Identifier: public PrimaryExpression { public: - Identifier(Location const& _location, ASTPointer const& _name): + Identifier(SourceLocation const& _location, ASTPointer const& _name): PrimaryExpression(_location), m_name(_name) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -1160,7 +1160,7 @@ private: class ElementaryTypeNameExpression: public PrimaryExpression { public: - ElementaryTypeNameExpression(Location const& _location, Token::Value _typeToken): + ElementaryTypeNameExpression(SourceLocation const& _location, Token::Value _typeToken): PrimaryExpression(_location), m_typeToken(_typeToken) { solAssert(Token::isElementaryTypeName(_typeToken), ""); @@ -1189,7 +1189,7 @@ public: Finney = Token::SubFinney, Ether = Token::SubEther }; - Literal(Location const& _location, Token::Value _token, + Literal(SourceLocation const& _location, Token::Value _token, ASTPointer const& _value, SubDenomination _sub = SubDenomination::None): PrimaryExpression(_location), m_token(_token), m_value(_value), m_subDenomination(_sub) {} diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp index 5bcc46df7..d0b27b317 100644 --- a/ASTPrinter.cpp +++ b/ASTPrinter.cpp @@ -555,7 +555,7 @@ void ASTPrinter::printSourcePart(ASTNode const& _node) { if (!m_source.empty()) { - Location const& location(_node.getLocation()); + SourceLocation const& location(_node.getLocation()); *m_ostream << getIndentation() << " Source: " << escaped(m_source.substr(location.start, location.end - location.start), false) << endl; } diff --git a/BaseTypes.h b/BaseTypes.h deleted file mode 100644 index 057289ef3..000000000 --- a/BaseTypes.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** - * @author Christian - * @date 2014 - * Some elementary types for the parser. - */ - -#pragma once - -#include -#include -#include - -namespace dev -{ -namespace solidity -{ - -/** - * Representation of an interval of source positions. - * The interval includes start and excludes end. - */ -struct Location -{ - Location(int _start, int _end, std::shared_ptr _sourceName): - start(_start), end(_end), sourceName(_sourceName) { } - Location(): start(-1), end(-1) { } - - bool isEmpty() const { return start == -1 && end == -1; } - - int start; - int end; - std::shared_ptr sourceName; -}; - -/// Stream output for Location (used e.g. in boost exceptions). -inline std::ostream& operator<<(std::ostream& _out, Location const& _location) -{ - if (_location.isEmpty()) - return _out << "NO_LOCATION_SPECIFIED"; - return _out << *_location.sourceName << "[" << _location.start << "," << _location.end << ")"; -} - -} -} diff --git a/Exceptions.h b/Exceptions.h index 0b25abee1..48dfc52e5 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -24,7 +24,7 @@ #include #include -#include +#include namespace dev { @@ -38,7 +38,7 @@ struct CompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {}; struct DocstringParsingError: virtual Exception {}; -using errinfo_sourceLocation = boost::error_info; +using errinfo_sourceLocation = boost::error_info; } } diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 9f8c8bbbe..5a78aaadb 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -1035,7 +1035,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& << structType->getStorageOffsetOfMember(names[i]) << eth::Instruction::ADD; m_currentLValue = LValue(m_context, LValue::LValueType::Storage, types[i]); - m_currentLValue.retrieveValue(Location(), true); + m_currentLValue.retrieveValue(SourceLocation(), true); solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented."); m_context << eth::Instruction::SWAP1; retSizeOnStack += types[i]->getSizeOnStack(); @@ -1047,7 +1047,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& // simple value solAssert(accessorType.getReturnParameterTypes().size() == 1, ""); m_currentLValue = LValue(m_context, LValue::LValueType::Storage, returnType); - m_currentLValue.retrieveValue(Location(), true); + m_currentLValue.retrieveValue(SourceLocation(), true); retSizeOnStack = returnType->getSizeOnStack(); } solAssert(retSizeOnStack <= 15, "Stack too deep."); @@ -1068,7 +1068,7 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType m_size = unsigned(m_dataType->getSizeOnStack()); } -void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration, Location const& _location) +void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration, SourceLocation const& _location) { if (m_context->isLocalVariable(&_declaration)) { @@ -1091,7 +1091,7 @@ void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration << errinfo_comment("Identifier type not supported or identifier not found.")); } -void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const +void ExpressionCompiler::LValue::retrieveValue(SourceLocation const& _location, bool _remove) const { switch (m_type) { @@ -1140,7 +1140,7 @@ void ExpressionCompiler::LValue::retrieveValueFromStorage(bool _remove) const } } -void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location const& _location, bool _move) const +void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const { switch (m_type) { @@ -1243,7 +1243,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co } } -void ExpressionCompiler::LValue::setToZero(Location const& _location) const +void ExpressionCompiler::LValue::setToZero(SourceLocation const& _location) const { switch (m_type) { diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 31bcc924a..bae5afb40 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include namespace dev { @@ -133,7 +133,7 @@ private: /// Set type according to the declaration and retrieve the reference. /// @a _location is the current location - void fromDeclaration(Declaration const& _declaration, Location const& _location); + void fromDeclaration(Declaration const& _declaration, SourceLocation const& _location); void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } @@ -148,15 +148,15 @@ private: /// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true, /// also removes the reference from the stack (note that is does not reset the type to @a NONE). /// @a _location source location of the current expression, used for error reporting. - void retrieveValue(Location const& _location, bool _remove = false) const; + void retrieveValue(SourceLocation const& _location, bool _remove = false) const; /// Moves a value from the stack to the lvalue. Removes the value if @a _move is true. /// @a _location is the source location of the expression that caused this operation. /// Stack pre: value [lvalue_ref] /// Stack post if !_move: value_of(lvalue_ref) - void storeValue(Type const& _sourceType, Location const& _location = Location(), bool _move = false) const; + void storeValue(Type const& _sourceType, SourceLocation const& _location = SourceLocation(), bool _move = false) const; /// Stores zero in the lvalue. /// @a _location is the source location of the requested operation - void setToZero(Location const& _location = Location()) const; + void setToZero(SourceLocation const& _location = SourceLocation()) const; /// Convenience function to convert the stored reference to a value and reset type to NONE if /// the reference was not requested by @a _expression. void retrieveValueIfLValueNotRequested(Expression const& _expression); diff --git a/Parser.cpp b/Parser.cpp index 1fc5ec98f..ea56d68f3 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include @@ -60,7 +60,7 @@ public: private: Parser const& m_parser; - Location m_location; + SourceLocation m_location; }; ASTPointer Parser::parse(shared_ptr const& _scanner) @@ -983,7 +983,7 @@ ASTPointer Parser::createEmptyParameterList() ParserError Parser::createParserError(string const& _description) const { - return ParserError() << errinfo_sourceLocation(Location(getPosition(), getPosition(), getSourceName())) + return ParserError() << errinfo_sourceLocation(SourceLocation(getPosition(), getPosition(), getSourceName())) << errinfo_comment(_description); } diff --git a/Scanner.h b/Scanner.h index d93b79df0..61fb89035 100644 --- a/Scanner.h +++ b/Scanner.h @@ -55,7 +55,7 @@ #include #include #include -#include +#include #include namespace dev @@ -120,14 +120,14 @@ public: return m_currentToken.token; } - Location getCurrentLocation() const { return m_currentToken.location; } + SourceLocation getCurrentLocation() const { return m_currentToken.location; } std::string const& getCurrentLiteral() const { return m_currentToken.literal; } ///@} ///@{ ///@name Information about the current comment token - Location getCurrentCommentLocation() const { return m_skippedComment.location; } + SourceLocation getCurrentCommentLocation() const { return m_skippedComment.location; } std::string const& getCurrentCommentLiteral() const { return m_skippedComment.literal; } /// Called by the parser during FunctionDefinition parsing to clear the current comment void clearCurrentCommentLiteral() { m_skippedComment.literal.clear(); } @@ -139,7 +139,7 @@ public: /// Returns the next token without advancing input. Token::Value peekNextToken() const { return m_nextToken.token; } - Location peekLocation() const { return m_nextToken.location; } + SourceLocation peekLocation() const { return m_nextToken.location; } std::string const& peekLiteral() const { return m_nextToken.literal; } ///@} @@ -158,7 +158,7 @@ private: struct TokenDesc { Token::Value token; - Location location; + SourceLocation location; std::string literal; }; diff --git a/SourceReferenceFormatter.cpp b/SourceReferenceFormatter.cpp index c61f9b685..489a676ed 100644 --- a/SourceReferenceFormatter.cpp +++ b/SourceReferenceFormatter.cpp @@ -33,7 +33,7 @@ namespace solidity { void SourceReferenceFormatter::printSourceLocation(ostream& _stream, - Location const& _location, + SourceLocation const& _location, Scanner const& _scanner) { int startLine; @@ -63,7 +63,7 @@ void SourceReferenceFormatter::printExceptionInformation(ostream& _stream, string const& _name, CompilerStack const& _compiler) { - Location const* location = boost::get_error_info(_exception); + SourceLocation const* location = boost::get_error_info(_exception); Scanner const* scanner; if (location) diff --git a/SourceReferenceFormatter.h b/SourceReferenceFormatter.h index 98f1c745d..337e60659 100644 --- a/SourceReferenceFormatter.h +++ b/SourceReferenceFormatter.h @@ -23,7 +23,7 @@ #pragma once #include -#include +#include namespace dev { @@ -39,7 +39,7 @@ class CompilerStack; // forward struct SourceReferenceFormatter { public: - static void printSourceLocation(std::ostream& _stream, Location const& _location, Scanner const& _scanner); + static void printSourceLocation(std::ostream& _stream, SourceLocation const& _location, Scanner const& _scanner); static void printExceptionInformation(std::ostream& _stream, Exception const& _exception, std::string const& _name, CompilerStack const& _compiler); }; From 3e5c9a74b277aadf619aed9a41cc6936d64297b1 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 24 Feb 2015 12:08:51 +0100 Subject: [PATCH 03/13] Reset CompilerContext's visited nodes at compile start --- Compiler.cpp | 1 + CompilerContext.cpp | 7 +++++++ CompilerContext.h | 2 ++ 3 files changed, 10 insertions(+) diff --git a/Compiler.cpp b/Compiler.cpp index 7b79959c9..e4a5c4f0d 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -74,6 +74,7 @@ void Compiler::initializeContext(ContractDefinition const& _contract, m_context.setCompiledContracts(_contracts); m_context.setInheritanceHierarchy(_contract.getLinearizedBaseContracts()); registerStateVariables(_contract); + m_context.resetVisitedNodes(&_contract); } void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) diff --git a/CompilerContext.cpp b/CompilerContext.cpp index c599be5ef..67a367240 100644 --- a/CompilerContext.cpp +++ b/CompilerContext.cpp @@ -166,6 +166,13 @@ u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declarati return it->second; } +void CompilerContext::resetVisitedNodes(ASTNode const* _node) +{ + stack newStack; + newStack.push(_node); + std::swap(m_visitedNodes, newStack); +} + CompilerContext& CompilerContext::operator<<(eth::AssemblyItem _item) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); diff --git a/CompilerContext.h b/CompilerContext.h index c07d9fb2f..6ee52a5b0 100644 --- a/CompilerContext.h +++ b/CompilerContext.h @@ -100,6 +100,8 @@ 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); } + /// Resets the stack of visited nodes with a new stack having only @c _node + void resetVisitedNodes(ASTNode const* _node); /// Pops the stack of visited nodes void popVisitedNodes() { m_visitedNodes.pop();} /// Pushes an ASTNode to the stack of visited nodes From 12c32392abc4af2f7da0793e178705c55c742e79 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 24 Feb 2015 17:08:27 +0100 Subject: [PATCH 04/13] Simple Assembly Locations test - Also adding some helper functions to SourceLocation --- Compiler.h | 2 ++ CompilerContext.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Compiler.h b/Compiler.h index 28ab34adb..a35a18e1d 100644 --- a/Compiler.h +++ b/Compiler.h @@ -41,6 +41,8 @@ public: bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } + CompilerContext const& getContext() const { return m_context; } + CompilerContext const& getRuntimeContext() const { return m_runtimeContext; } private: /// Registers the non-function objects inside the contract with the context. diff --git a/CompilerContext.cpp b/CompilerContext.cpp index 67a367240..5fd91e435 100644 --- a/CompilerContext.cpp +++ b/CompilerContext.cpp @@ -176,28 +176,28 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node) CompilerContext& CompilerContext::operator<<(eth::AssemblyItem _item) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); - m_asm.append(_item); + m_asm.append(_item, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(eth::Instruction _instruction) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); - m_asm.append(_instruction); + m_asm.append(_instruction, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(u256 const& _value) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); - m_asm.append(_value); + m_asm.append(_value, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(bytes const& _data) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); - m_asm.append(_data); + m_asm.append(_data, m_visitedNodes.top()->getLocation()); return *this; } From fb328b778cdd0c6022ce072689cb3d8b333232f8 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 24 Feb 2015 17:31:06 +0100 Subject: [PATCH 05/13] Changes after rebase on top of Array Parsing --- AST.h | 2 +- Compiler.cpp | 2 +- Parser.cpp | 10 +++++----- Parser.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/AST.h b/AST.h index 27dc008a8..e2f464ac1 100644 --- a/AST.h +++ b/AST.h @@ -662,7 +662,7 @@ private: class ArrayTypeName: public TypeName { public: - ArrayTypeName(Location const& _location, ASTPointer const& _baseType, + ArrayTypeName(SourceLocation const& _location, ASTPointer const& _baseType, ASTPointer const& _length): TypeName(_location), m_baseType(_baseType), m_length(_length) {} virtual void accept(ASTVisitor& _visitor) override; diff --git a/Compiler.cpp b/Compiler.cpp index e4a5c4f0d..9cef1f2ac 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -473,7 +473,7 @@ bool Compiler::visit(Return const& _return) bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement) { StackHeightChecker checker(m_context); - CompilerContext::LocationSetter locationSetter(m_context, &_variableDefinition); + CompilerContext::LocationSetter locationSetter(m_context, &_variableDeclarationStatement); if (Expression const* expression = _variableDeclarationStatement.getExpression()) { compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType()); diff --git a/Parser.cpp b/Parser.cpp index ea56d68f3..4edcab12f 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -45,7 +45,7 @@ public: m_parser(_parser), m_location(_childNode->getLocation()) {} void markEndPosition() { m_location.end = m_parser.getEndPosition(); } - void setLocation(Location const& _location) { m_location = _location; } + void setLocation(SourceLocation const& _location) { m_location = _location; } void setLocationEmpty() { m_location.end = m_location.start; } /// Set the end position to the one of the given node. void setEndPositionFromNode(ASTPointer const& _node) { m_location.end = _node->getLocation().end; } @@ -646,9 +646,9 @@ ASTPointer Parser::parseSimpleStatement() primary = ASTNodeFactory(*this).createNode(m_scanner->getCurrentToken()); m_scanner->next(); } - vector, Location>> indices; + vector, SourceLocation>> indices; solAssert(m_scanner->getCurrentToken() == Token::LBrack, ""); - Location indexLocation = primary->getLocation(); + SourceLocation indexLocation = primary->getLocation(); do { expectToken(Token::LBrack); @@ -913,7 +913,7 @@ Parser::LookAheadInfo Parser::peekStatementType() const } ASTPointer Parser::typeNameIndexAccessStructure( - ASTPointer const& _primary, vector, Location>> const& _indices) + ASTPointer const& _primary, vector, SourceLocation>> const& _indices) { ASTNodeFactory nodeFactory(*this, _primary); ASTPointer type; @@ -932,7 +932,7 @@ ASTPointer Parser::typeNameIndexAccessStructure( } ASTPointer Parser::expressionFromIndexAccessStructure( - ASTPointer const& _primary, vector, Location>> const& _indices) + ASTPointer const& _primary, vector, SourceLocation>> const& _indices) { ASTNodeFactory nodeFactory(*this, _primary); ASTPointer expression(_primary); diff --git a/Parser.h b/Parser.h index 9e4c7bb24..87eb2f8ff 100644 --- a/Parser.h +++ b/Parser.h @@ -114,11 +114,11 @@ private: /// Returns a typename parsed in look-ahead fashion from something like "a[8][2**70]". ASTPointer typeNameIndexAccessStructure( ASTPointer const& _primary, - std::vector, Location>> const& _indices); + std::vector, SourceLocation>> const& _indices); /// Returns an expression parsed in look-ahead fashion from something like "a[8][2**70]". ASTPointer expressionFromIndexAccessStructure( ASTPointer const& _primary, - std::vector, Location>> const& _indices); + std::vector, SourceLocation>> const& _indices); /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); Token::Value expectAssignmentOperator(); From 54121a0d787df1b730fa523b21040c312dda4bf6 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 25 Feb 2015 09:53:28 +0100 Subject: [PATCH 06/13] Styling changes for SourceLocation and friends --- Compiler.h | 1 + CompilerContext.cpp | 8 ++++---- CompilerContext.h | 2 +- ExpressionCompiler.cpp | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Compiler.h b/Compiler.h index a35a18e1d..67f3a18eb 100644 --- a/Compiler.h +++ b/Compiler.h @@ -41,6 +41,7 @@ public: bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } + /// Getters for compiler contexts. Only for testing purposes. CompilerContext const& getContext() const { return m_context; } CompilerContext const& getRuntimeContext() const { return m_runtimeContext; } diff --git a/CompilerContext.cpp b/CompilerContext.cpp index 5fd91e435..8bb6cb005 100644 --- a/CompilerContext.cpp +++ b/CompilerContext.cpp @@ -175,28 +175,28 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node) CompilerContext& CompilerContext::operator<<(eth::AssemblyItem _item) { - solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); + solAssert(!m_visitedNodes.empty(), "No node on the visited stack"); m_asm.append(_item, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(eth::Instruction _instruction) { - solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); + solAssert(!m_visitedNodes.empty(), "No node on the visited stack"); m_asm.append(_instruction, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(u256 const& _value) { - solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); + solAssert(!m_visitedNodes.empty(), "No node on the visited stack"); m_asm.append(_value, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(bytes const& _data) { - solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); + solAssert(!m_visitedNodes.empty(), "No node on the visited stack"); m_asm.append(_data, m_visitedNodes.top()->getLocation()); return *this; } diff --git a/CompilerContext.h b/CompilerContext.h index 6ee52a5b0..6e1dbfbce 100644 --- a/CompilerContext.h +++ b/CompilerContext.h @@ -103,7 +103,7 @@ public: /// Resets the stack of visited nodes with a new stack having only @c _node void resetVisitedNodes(ASTNode const* _node); /// Pops the stack of visited nodes - void popVisitedNodes() { m_visitedNodes.pop();} + void popVisitedNodes() { m_visitedNodes.pop(); } /// Pushes an ASTNode to the stack of visited nodes void pushVisitedNodes(ASTNode const* _node) { m_visitedNodes.push(_node); } diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 5a78aaadb..90a3f3ac0 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -165,7 +165,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) { - CompilerContext::LocationSetter locationSetter(m_context, &_binaryOperation); + CompilerContext::LocationSetter locationSetter(m_context, &_binaryOperation); Expression const& leftExpression = _binaryOperation.getLeftExpression(); Expression const& rightExpression = _binaryOperation.getRightExpression(); Type const& commonType = _binaryOperation.getCommonType(); From 71b0d8107aae500a5301e675aef3515539efe02f Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 25 Feb 2015 10:40:14 +0100 Subject: [PATCH 07/13] LocationSetter in some extra places during Compiling - Also adjusted the test, and fixed its error reporting --- Compiler.cpp | 4 +++- CompilerContext.cpp | 4 ++-- CompilerContext.h | 2 +- ExpressionCompiler.cpp | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Compiler.cpp b/Compiler.cpp index 9cef1f2ac..23591d1a5 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -129,6 +129,7 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor, vector> const& _arguments) { + CompilerContext::LocationSetter locationSetter(m_context, &_constructor); FunctionType constructorType(_constructor); eth::AssemblyItem returnLabel = m_context.pushNewTag(); for (unsigned i = 0; i < _arguments.size(); ++i) @@ -139,6 +140,7 @@ void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor, void Compiler::appendConstructorCall(FunctionDefinition const& _constructor) { + CompilerContext::LocationSetter locationSetter(m_context, &_constructor); eth::AssemblyItem returnTag = m_context.pushNewTag(); // copy constructor arguments from code to memory and then to stack, they are supplied after the actual program unsigned argumentSize = 0; @@ -513,8 +515,8 @@ void Compiler::appendModifierOrFunctionCode() else { ASTPointer const& modifierInvocation = m_currentFunction->getModifiers()[m_modifierDepth]; - ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName()); + CompilerContext::LocationSetter locationSetter(m_context, &modifier); solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), ""); for (unsigned i = 0; i < modifier.getParameters().size(); ++i) { diff --git a/CompilerContext.cpp b/CompilerContext.cpp index 8bb6cb005..18be337fa 100644 --- a/CompilerContext.cpp +++ b/CompilerContext.cpp @@ -65,8 +65,8 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration, void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration) { + LocationSetter locationSetter(*this, &_declaration); addVariable(_declaration); - int const size = _declaration.getType()->getSizeOnStack(); for (int i = 0; i < size; ++i) *this << u256(0); @@ -173,7 +173,7 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node) std::swap(m_visitedNodes, newStack); } -CompilerContext& CompilerContext::operator<<(eth::AssemblyItem _item) +CompilerContext& CompilerContext::operator<<(eth::AssemblyItem const& _item) { solAssert(!m_visitedNodes.empty(), "No node on the visited stack"); m_asm.append(_item, m_visitedNodes.top()->getLocation()); diff --git a/CompilerContext.h b/CompilerContext.h index 6e1dbfbce..94d6443e9 100644 --- a/CompilerContext.h +++ b/CompilerContext.h @@ -108,7 +108,7 @@ public: 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 _item); + CompilerContext& operator<<(eth::AssemblyItem const& _item); CompilerContext& operator<<(eth::Instruction _instruction); CompilerContext& operator<<(u256 const& _value); CompilerContext& operator<<(bytes const& _data); diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 90a3f3ac0..94c71fc03 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -68,6 +68,7 @@ void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _con void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { + CompilerContext::LocationSetter locationSetter(m_context, &_varDecl); LValue var = LValue(m_context); var.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); var.storeValue(*_varDecl.getType(), _varDecl.getLocation()); @@ -999,6 +1000,7 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { + CompilerContext::LocationSetter locationSetter(m_context, &_varDecl); FunctionType accessorType(_varDecl); unsigned length = 0; From ece19cb91336bbd7c37c49c9079b64419c3f6cd0 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 25 Feb 2015 12:02:58 +0100 Subject: [PATCH 08/13] Tighter coupling for Assembly items retrieval - Exposing only assembly items, not the entire compiler context --- Compiler.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Compiler.h b/Compiler.h index 67f3a18eb..3ad2d8c61 100644 --- a/Compiler.h +++ b/Compiler.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace dev { namespace solidity { @@ -41,9 +42,11 @@ public: bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } - /// Getters for compiler contexts. Only for testing purposes. - CompilerContext const& getContext() const { return m_context; } - CompilerContext const& getRuntimeContext() const { return m_runtimeContext; } + + /// @returns Assembly items of the normal compiler context + eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); } + /// @returns Assembly items of the runtime compiler context + eth::AssemblyItems const& getRuntimeAssemblyItems() const { return m_runtimeContext.getAssembly().getItems(); } private: /// Registers the non-function objects inside the contract with the context. From 7f3a544d2a089e38a21b1ce566060edb8fe9c2b2 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 25 Feb 2015 12:19:02 +0100 Subject: [PATCH 09/13] Move SourceLocation to evmcore --- AST.h | 2 +- Exceptions.h | 2 +- ExpressionCompiler.h | 2 +- Parser.cpp | 2 +- Scanner.h | 2 +- SourceReferenceFormatter.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/AST.h b/AST.h index e2f464ac1..dea0fba63 100644 --- a/AST.h +++ b/AST.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Exceptions.h b/Exceptions.h index 48dfc52e5..0d07c7064 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -24,7 +24,7 @@ #include #include -#include +#include namespace dev { diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index bae5afb40..2eb8ca20c 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include namespace dev { diff --git a/Parser.cpp b/Parser.cpp index 4edcab12f..3c88efc7c 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/Scanner.h b/Scanner.h index 61fb89035..b57b8a189 100644 --- a/Scanner.h +++ b/Scanner.h @@ -55,7 +55,7 @@ #include #include #include -#include +#include #include namespace dev diff --git a/SourceReferenceFormatter.h b/SourceReferenceFormatter.h index 337e60659..304e6a273 100644 --- a/SourceReferenceFormatter.h +++ b/SourceReferenceFormatter.h @@ -23,7 +23,7 @@ #pragma once #include -#include +#include namespace dev { From cc31a7ab321a974cd81de2b539ec2bf7db2b2358 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 25 Feb 2015 15:14:22 +0100 Subject: [PATCH 10/13] LValue refactoring. --- Compiler.cpp | 13 +- ExpressionCompiler.cpp | 646 +++++++++++++---------------------------- ExpressionCompiler.h | 108 ++----- LValue.cpp | 220 ++++++++++++++ LValue.h | 112 +++++++ 5 files changed, 560 insertions(+), 539 deletions(-) create mode 100644 LValue.cpp create mode 100644 LValue.h diff --git a/Compiler.cpp b/Compiler.cpp index 23591d1a5..2f75d2ea4 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -250,7 +250,7 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) for (TypePointer const& type: _typeParameters) { CompilerUtils(m_context).copyToStackTop(stackDepth, *type); - ExpressionCompiler::appendTypeConversion(m_context, *type, *type, true); + ExpressionCompiler(m_context, m_optimize).appendTypeConversion(*type, *type, true); bool const c_padToWords = true; dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, *type, c_padToWords); stackDepth -= type->getSizeOnStack(); @@ -270,7 +270,7 @@ void Compiler::initializeStateVariables(ContractDefinition const& _contract) { for (ASTPointer const& variable: _contract.getStateVariables()) if (variable->getValue()) - ExpressionCompiler::appendStateVariableInitialization(m_context, *variable); + ExpressionCompiler(m_context, m_optimize).appendStateVariableInitialization(*variable); } bool Compiler::visit(VariableDeclaration const& _variableDeclaration) @@ -283,7 +283,7 @@ bool Compiler::visit(VariableDeclaration const& _variableDeclaration) m_continueTags.clear(); m_context << m_context.getFunctionEntryLabel(_variableDeclaration); - ExpressionCompiler::appendStateVariableAccessor(m_context, _variableDeclaration); + ExpressionCompiler(m_context, m_optimize).appendStateVariableAccessor(_variableDeclaration); return false; } @@ -475,7 +475,7 @@ bool Compiler::visit(Return const& _return) bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement) { StackHeightChecker checker(m_context); - CompilerContext::LocationSetter locationSetter(m_context, &_variableDeclarationStatement); + CompilerContext::LocationSetter locationSetter(m_context, &_variableDeclarationStatement); if (Expression const* expression = _variableDeclarationStatement.getExpression()) { compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType()); @@ -541,9 +541,10 @@ void Compiler::appendModifierOrFunctionCode() void Compiler::compileExpression(Expression const& _expression, TypePointer const& _targetType) { - ExpressionCompiler::compileExpression(m_context, _expression, m_optimize); + ExpressionCompiler expressionCompiler(m_context, m_optimize); + expressionCompiler.compile(_expression); if (_targetType) - ExpressionCompiler::appendTypeConversion(m_context, *_expression.getType(), *_targetType); + expressionCompiler.appendTypeConversion(*_expression.getType(), *_targetType); } } diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 94c71fc03..6b9b51679 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -29,6 +29,7 @@ #include #include #include +#include using namespace std; @@ -37,41 +38,167 @@ namespace dev namespace solidity { -void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression const& _expression, bool _optimize) +void ExpressionCompiler::compile(Expression const& _expression) { - ExpressionCompiler compiler(_context, _optimize); - _expression.accept(compiler); -} - -void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, - Type const& _targetType, bool _cleanupNeeded) -{ - ExpressionCompiler compiler(_context); - compiler.appendTypeConversion(_typeOnStack, _targetType, _cleanupNeeded); -} - -void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize) -{ - ExpressionCompiler compiler(_context, _optimize); - compiler.appendStateVariableAccessor(_varDecl); -} - -void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize) -{ - compileExpression(_context, *(_varDecl.getValue()), _optimize); - if (_varDecl.getValue()->getType()) - appendTypeConversion(_context, *(_varDecl.getValue())->getType(), *(_varDecl.getValue())->getType()); - - ExpressionCompiler compiler(_context, _optimize); - compiler.appendStateVariableInitialization(_varDecl); + _expression.accept(*this); } void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { + if (!_varDecl.getValue()) + return; + solAssert(!!_varDecl.getValue()->getType(), "Type information not available."); CompilerContext::LocationSetter locationSetter(m_context, &_varDecl); - LValue var = LValue(m_context); - var.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); - var.storeValue(*_varDecl.getType(), _varDecl.getLocation()); + _varDecl.getValue()->accept(*this); + appendTypeConversion(*_varDecl.getValue()->getType(), *_varDecl.getType(), true); + + StorageItem(m_context, _varDecl).storeValue(*_varDecl.getType(), _varDecl.getLocation(), true); +} + +void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) +{ + CompilerContext::LocationSetter locationSetter(m_context, &_varDecl); + FunctionType accessorType(_varDecl); + + unsigned length = 0; + TypePointers const& paramTypes = accessorType.getParameterTypes(); + // move arguments to memory + for (TypePointer const& paramType: boost::adaptors::reverse(paramTypes)) + length += CompilerUtils(m_context).storeInMemory(length, *paramType, true); + + // retrieve the position of the variable + m_context << m_context.getStorageLocationOfVariable(_varDecl); + TypePointer returnType = _varDecl.getType(); + + for (TypePointer const& paramType: paramTypes) + { + // move offset to memory + CompilerUtils(m_context).storeInMemory(length); + unsigned argLen = CompilerUtils::getPaddedSize(paramType->getCalldataEncodedSize()); + length -= argLen; + m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3; + + returnType = dynamic_cast(*returnType).getValueType(); + } + + unsigned retSizeOnStack = 0; + solAssert(accessorType.getReturnParameterTypes().size() >= 1, ""); + if (StructType const* structType = dynamic_cast(returnType.get())) + { + auto const& names = accessorType.getReturnParameterNames(); + auto const& types = accessorType.getReturnParameterTypes(); + // struct + for (size_t i = 0; i < names.size(); ++i) + { + m_context << eth::Instruction::DUP1 + << structType->getStorageOffsetOfMember(names[i]) + << eth::Instruction::ADD; + StorageItem(m_context, types[i]).retrieveValue(SourceLocation(), true); + solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented."); + m_context << eth::Instruction::SWAP1; + retSizeOnStack += types[i]->getSizeOnStack(); + } + m_context << eth::Instruction::POP; + } + else + { + // simple value + solAssert(accessorType.getReturnParameterTypes().size() == 1, ""); + StorageItem(m_context, returnType).retrieveValue(SourceLocation(), true); + retSizeOnStack = returnType->getSizeOnStack(); + } + solAssert(retSizeOnStack <= 15, "Stack too deep."); + m_context << eth::dupInstruction(retSizeOnStack + 1) << eth::Instruction::JUMP; +} + +void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) +{ + // For a type extension, we need to remove all higher-order bits that we might have ignored in + // previous operations. + // @todo: store in the AST whether the operand might have "dirty" higher order bits + + if (_typeOnStack == _targetType && !_cleanupNeeded) + return; + Type::Category stackTypeCategory = _typeOnStack.getCategory(); + Type::Category targetTypeCategory = _targetType.getCategory(); + + if (stackTypeCategory == Type::Category::String) + { + StaticStringType const& typeOnStack = dynamic_cast(_typeOnStack); + if (targetTypeCategory == Type::Category::Integer) + { + // conversion from string to hash. no need to clean the high bit + // only to shift right because of opposite alignment + IntegerType const& targetIntegerType = dynamic_cast(_targetType); + solAssert(targetIntegerType.isHash(), "Only conversion between String and Hash is allowed."); + solAssert(targetIntegerType.getNumBits() == typeOnStack.getNumBytes() * 8, "The size should be the same."); + m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV; + } + else + { + // clear lower-order bytes for conversion to shorter strings - we always clean + solAssert(targetTypeCategory == Type::Category::String, "Invalid type conversion requested."); + StaticStringType const& targetType = dynamic_cast(_targetType); + if (targetType.getNumBytes() < typeOnStack.getNumBytes()) + { + if (targetType.getNumBytes() == 0) + m_context << eth::Instruction::DUP1 << eth::Instruction::XOR; + else + m_context << (u256(1) << (256 - targetType.getNumBytes() * 8)) + << eth::Instruction::DUP1 << eth::Instruction::SWAP2 + << eth::Instruction::DIV << eth::Instruction::MUL; + } + } + } + else if (stackTypeCategory == Type::Category::Enum) + solAssert(targetTypeCategory == Type::Category::Integer || + targetTypeCategory == Type::Category::Enum, ""); + else if (stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::Contract || + stackTypeCategory == Type::Category::IntegerConstant) + { + if (targetTypeCategory == Type::Category::String && stackTypeCategory == Type::Category::Integer) + { + // conversion from hash to string. no need to clean the high bit + // only to shift left because of opposite alignment + StaticStringType const& targetStringType = dynamic_cast(_targetType); + IntegerType const& typeOnStack = dynamic_cast(_typeOnStack); + solAssert(typeOnStack.isHash(), "Only conversion between String and Hash is allowed."); + solAssert(typeOnStack.getNumBits() == targetStringType.getNumBytes() * 8, "The size should be the same."); + m_context << (u256(1) << (256 - typeOnStack.getNumBits())) << eth::Instruction::MUL; + } + else if (targetTypeCategory == Type::Category::Enum) + // just clean + appendTypeConversion(_typeOnStack, *_typeOnStack.getRealType(), true); + else + { + solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, ""); + IntegerType addressType(0, IntegerType::Modifier::Address); + IntegerType const& targetType = targetTypeCategory == Type::Category::Integer + ? dynamic_cast(_targetType) : addressType; + if (stackTypeCategory == Type::Category::IntegerConstant) + { + IntegerConstantType const& constType = dynamic_cast(_typeOnStack); + // We know that the stack is clean, we only have to clean for a narrowing conversion + // where cleanup is forced. + if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded) + appendHighBitsCleanup(targetType); + } + else + { + IntegerType const& typeOnStack = stackTypeCategory == Type::Category::Integer + ? dynamic_cast(_typeOnStack) : addressType; + // Widening: clean up according to source type width + // Non-widening and force: clean up according to target type bits + if (targetType.getNumBits() > typeOnStack.getNumBits()) + appendHighBitsCleanup(typeOnStack); + else if (_cleanupNeeded) + appendHighBitsCleanup(targetType); + } + } + } + else if (_typeOnStack != _targetType) + // All other types should not be convertible to non-equal types. + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); } bool ExpressionCompiler::visit(Assignment const& _assignment) @@ -81,20 +208,20 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) if (_assignment.getType()->isValueType()) appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType()); _assignment.getLeftHandSide().accept(*this); - solAssert(m_currentLValue.isValid(), "LValue not retrieved."); + solAssert(!!m_currentLValue, "LValue not retrieved."); Token::Value op = _assignment.getAssignmentOperator(); if (op != Token::Assign) // compound assignment { solAssert(_assignment.getType()->isValueType(), "Compound operators not implemented for non-value types."); - if (m_currentLValue.storesReferenceOnStack()) + if (m_currentLValue->storesReferenceOnStack()) m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2; - m_currentLValue.retrieveValue(_assignment.getLocation(), true); + m_currentLValue->retrieveValue(_assignment.getLocation(), true); appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType()); - if (m_currentLValue.storesReferenceOnStack()) + if (m_currentLValue->storesReferenceOnStack()) m_context << eth::Instruction::SWAP1; } - m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); + m_currentLValue->storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); m_currentLValue.reset(); return false; } @@ -123,17 +250,17 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) m_context << eth::Instruction::NOT; break; case Token::Delete: // delete - solAssert(m_currentLValue.isValid(), "LValue not retrieved."); - m_currentLValue.setToZero(_unaryOperation.getLocation()); + solAssert(!!m_currentLValue, "LValue not retrieved."); + m_currentLValue->setToZero(_unaryOperation.getLocation()); m_currentLValue.reset(); break; case Token::Inc: // ++ (pre- or postfix) case Token::Dec: // -- (pre- or postfix) - solAssert(m_currentLValue.isValid(), "LValue not retrieved."); - m_currentLValue.retrieveValue(_unaryOperation.getLocation()); + solAssert(!!m_currentLValue, "LValue not retrieved."); + m_currentLValue->retrieveValue(_unaryOperation.getLocation()); if (!_unaryOperation.isPrefixOperation()) { - if (m_currentLValue.storesReferenceOnStack()) + if (m_currentLValue->storesReferenceOnStack()) m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2; else m_context << eth::Instruction::DUP1; @@ -145,10 +272,11 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap // Stack for prefix: [ref] (*ref)+-1 // Stack for postfix: *ref [ref] (*ref)+-1 - if (m_currentLValue.storesReferenceOnStack()) + if (m_currentLValue->storesReferenceOnStack()) m_context << eth::Instruction::SWAP1; - m_currentLValue.storeValue(*_unaryOperation.getType(), _unaryOperation.getLocation(), - !_unaryOperation.isPrefixOperation()); + m_currentLValue->storeValue( + *_unaryOperation.getType(), _unaryOperation.getLocation(), + !_unaryOperation.isPrefixOperation()); m_currentLValue.reset(); break; case Token::Add: // + @@ -179,7 +307,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) else { bool cleanupNeeded = commonType.getCategory() == Type::Category::Integer && - (Token::isCompareOp(c_op) || c_op == Token::Div || c_op == Token::Mod); + (Token::isCompareOp(c_op) || c_op == Token::Div || c_op == Token::Mod); // for commutative operators, push the literal as late as possible to allow improved optimization auto isLiteral = [](Expression const& _e) @@ -505,8 +633,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) { StructType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD; - m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _memberAccess.getType()); - m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); + setLValueToStorageItem(_memberAccess); break; } case Type::Category::Enum: @@ -552,8 +679,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; break; case ArrayType::Location::Storage: - m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _memberAccess.getType()); - m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); + setLValueToStorageItem(_memberAccess); break; default: solAssert(false, "Unsupported array location."); @@ -583,8 +709,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) m_context << eth::Instruction::SWAP1; appendTypeMoveToMemory(IntegerType(256)); m_context << u256(0) << eth::Instruction::SHA3; - m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType()); - m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); + setLValueToStorageItem( _indexAccess); } else if (baseType.getCategory() == Type::Category::Array) { @@ -616,8 +741,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) CompilerUtils(m_context).computeHashStatic(); } m_context << eth::Instruction::ADD; - m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType()); - m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); + setLValueToStorageItem(_indexAccess); } else solAssert(false, "Index access only allowed for mappings or arrays."); @@ -638,10 +762,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) else if (FunctionDefinition const* functionDef = dynamic_cast(declaration)) m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag(); else if (dynamic_cast(declaration)) - { - m_currentLValue.fromDeclaration(*declaration, _identifier.getLocation()); - m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); - } + setLValueFromDeclaration(*declaration, _identifier); else if (dynamic_cast(declaration)) { // no-op @@ -798,96 +919,6 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) } } -void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) -{ - // For a type extension, we need to remove all higher-order bits that we might have ignored in - // previous operations. - // @todo: store in the AST whether the operand might have "dirty" higher order bits - - if (_typeOnStack == _targetType && !_cleanupNeeded) - return; - Type::Category stackTypeCategory = _typeOnStack.getCategory(); - Type::Category targetTypeCategory = _targetType.getCategory(); - - if (stackTypeCategory == Type::Category::String) - { - StaticStringType const& typeOnStack = dynamic_cast(_typeOnStack); - if (targetTypeCategory == Type::Category::Integer) - { - // conversion from string to hash. no need to clean the high bit - // only to shift right because of opposite alignment - IntegerType const& targetIntegerType = dynamic_cast(_targetType); - solAssert(targetIntegerType.isHash(), "Only conversion between String and Hash is allowed."); - solAssert(targetIntegerType.getNumBits() == typeOnStack.getNumBytes() * 8, "The size should be the same."); - m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV; - } - else - { - // clear lower-order bytes for conversion to shorter strings - we always clean - solAssert(targetTypeCategory == Type::Category::String, "Invalid type conversion requested."); - StaticStringType const& targetType = dynamic_cast(_targetType); - if (targetType.getNumBytes() < typeOnStack.getNumBytes()) - { - if (targetType.getNumBytes() == 0) - m_context << eth::Instruction::DUP1 << eth::Instruction::XOR; - else - m_context << (u256(1) << (256 - targetType.getNumBytes() * 8)) - << eth::Instruction::DUP1 << eth::Instruction::SWAP2 - << eth::Instruction::DIV << eth::Instruction::MUL; - } - } - } - else if (stackTypeCategory == Type::Category::Enum) - solAssert(targetTypeCategory == Type::Category::Integer || - targetTypeCategory == Type::Category::Enum, ""); - else if (stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::Contract || - stackTypeCategory == Type::Category::IntegerConstant) - { - if (targetTypeCategory == Type::Category::String && stackTypeCategory == Type::Category::Integer) - { - // conversion from hash to string. no need to clean the high bit - // only to shift left because of opposite alignment - StaticStringType const& targetStringType = dynamic_cast(_targetType); - IntegerType const& typeOnStack = dynamic_cast(_typeOnStack); - solAssert(typeOnStack.isHash(), "Only conversion between String and Hash is allowed."); - solAssert(typeOnStack.getNumBits() == targetStringType.getNumBytes() * 8, "The size should be the same."); - m_context << (u256(1) << (256 - typeOnStack.getNumBits())) << eth::Instruction::MUL; - } - else if (targetTypeCategory == Type::Category::Enum) - // just clean - appendTypeConversion(_typeOnStack, *_typeOnStack.getRealType(), true); - else - { - solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, ""); - IntegerType addressType(0, IntegerType::Modifier::Address); - IntegerType const& targetType = targetTypeCategory == Type::Category::Integer - ? dynamic_cast(_targetType) : addressType; - if (stackTypeCategory == Type::Category::IntegerConstant) - { - IntegerConstantType const& constType = dynamic_cast(_typeOnStack); - // We know that the stack is clean, we only have to clean for a narrowing conversion - // where cleanup is forced. - if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded) - appendHighBitsCleanup(targetType); - } - else - { - IntegerType const& typeOnStack = stackTypeCategory == Type::Category::Integer - ? dynamic_cast(_typeOnStack) : addressType; - // Widening: clean up according to source type width - // Non-widening and force: clean up according to target type bits - if (targetType.getNumBits() > typeOnStack.getNumBits()) - appendHighBitsCleanup(typeOnStack); - else if (_cleanupNeeded) - appendHighBitsCleanup(targetType); - } - } - } - else if (_typeOnStack != _targetType) - // All other types should not be convertible to non-equal types. - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); -} - void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) { if (_typeOnStack.getNumBits() == 256) @@ -998,319 +1029,32 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, appendTypeMoveToMemory(_expectedType); } -void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) +void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) { - CompilerContext::LocationSetter locationSetter(m_context, &_varDecl); - FunctionType accessorType(_varDecl); - - unsigned length = 0; - TypePointers const& paramTypes = accessorType.getParameterTypes(); - // move arguments to memory - for (TypePointer const& paramType: boost::adaptors::reverse(paramTypes)) - length += CompilerUtils(m_context).storeInMemory(length, *paramType, true); - - // retrieve the position of the variable - m_context << m_context.getStorageLocationOfVariable(_varDecl); - TypePointer returnType = _varDecl.getType(); - - for (TypePointer const& paramType: paramTypes) - { - // move offset to memory - CompilerUtils(m_context).storeInMemory(length); - unsigned argLen = CompilerUtils::getPaddedSize(paramType->getCalldataEncodedSize()); - length -= argLen; - m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3; - - returnType = dynamic_cast(*returnType).getValueType(); - } - - unsigned retSizeOnStack = 0; - solAssert(accessorType.getReturnParameterTypes().size() >= 1, ""); - if (StructType const* structType = dynamic_cast(returnType.get())) - { - auto const& names = accessorType.getReturnParameterNames(); - auto const& types = accessorType.getReturnParameterTypes(); - // struct - for (size_t i = 0; i < names.size(); ++i) - { - m_context << eth::Instruction::DUP1 - << structType->getStorageOffsetOfMember(names[i]) - << eth::Instruction::ADD; - m_currentLValue = LValue(m_context, LValue::LValueType::Storage, types[i]); - m_currentLValue.retrieveValue(SourceLocation(), true); - solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented."); - m_context << eth::Instruction::SWAP1; - retSizeOnStack += types[i]->getSizeOnStack(); - } - m_context << eth::Instruction::POP; - } + solAssert(!m_currentLValue, "Current LValue not reset when trying to set to new one."); + std::unique_ptr lvalue; + if (m_context.isLocalVariable(&_declaration)) + lvalue.reset(new StackVariable(m_context, _declaration)); + else if (m_context.isStateVariable(&_declaration)) + lvalue.reset(new StorageItem(m_context, _declaration)); else - { - // simple value - solAssert(accessorType.getReturnParameterTypes().size() == 1, ""); - m_currentLValue = LValue(m_context, LValue::LValueType::Storage, returnType); - m_currentLValue.retrieveValue(SourceLocation(), true); - retSizeOnStack = returnType->getSizeOnStack(); - } - solAssert(retSizeOnStack <= 15, "Stack too deep."); - m_context << eth::dupInstruction(retSizeOnStack + 1) << eth::Instruction::JUMP; -} - -ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, - TypePointer const& _dataType, unsigned _baseStackOffset): - m_context(&_compilerContext), m_type(_type), m_dataType(_dataType), - m_baseStackOffset(_baseStackOffset) -{ - //@todo change the type cast for arrays - solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), - "The storage size of " + m_dataType->toString() + " should fit in unsigned"); - if (m_type == LValueType::Storage) - m_size = unsigned(m_dataType->getStorageSize()); + BOOST_THROW_EXCEPTION(InternalCompilerError() + << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Identifier type not supported or identifier not found.")); + if (_expression.lvalueRequested()) + m_currentLValue = move(lvalue); else - m_size = unsigned(m_dataType->getSizeOnStack()); + lvalue->retrieveValue(_expression.getLocation(), true); } -void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration, SourceLocation const& _location) +void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) { - if (m_context->isLocalVariable(&_declaration)) - { - m_type = LValueType::Stack; - m_dataType = _declaration.getType(); - m_size = m_dataType->getSizeOnStack(); - m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); - } - else if (m_context->isStateVariable(&_declaration)) - { - *m_context << m_context->getStorageLocationOfVariable(_declaration); - m_type = LValueType::Storage; - m_dataType = _declaration.getType(); - solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), - "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); - } + solAssert(!m_currentLValue, "Current LValue not reset when trying to set to new one."); + std::unique_ptr lvalue(new StorageItem(m_context, _expression.getType())); + if (_expression.lvalueRequested()) + m_currentLValue = move(lvalue); else - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Identifier type not supported or identifier not found.")); -} - -void ExpressionCompiler::LValue::retrieveValue(SourceLocation const& _location, bool _remove) const -{ - switch (m_type) - { - case LValueType::Stack: - { - unsigned stackPos = m_context->baseToCurrentStackOffset(m_baseStackOffset); - if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Stack too deep.")); - for (unsigned i = 0; i < m_size; ++i) - *m_context << eth::dupInstruction(stackPos + 1); - break; - } - case LValueType::Storage: - retrieveValueFromStorage(_remove); - break; - case LValueType::Memory: - if (!m_dataType->isValueType()) - break; // no distinction between value and reference for non-value types - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Location type not yet implemented.")); - break; - default: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Unsupported location type.")); - break; - } -} - -void ExpressionCompiler::LValue::retrieveValueFromStorage(bool _remove) const -{ - if (!m_dataType->isValueType()) - return; // no distinction between value and reference for non-value types - if (!_remove) - *m_context << eth::Instruction::DUP1; - if (m_size == 1) - *m_context << eth::Instruction::SLOAD; - else - for (unsigned i = 0; i < m_size; ++i) - { - *m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1; - if (i + 1 < m_size) - *m_context << u256(1) << eth::Instruction::ADD; - else - *m_context << eth::Instruction::POP; - } -} - -void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const -{ - switch (m_type) - { - case LValueType::Stack: - { - unsigned stackDiff = m_context->baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; - if (stackDiff > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Stack too deep.")); - else if (stackDiff > 0) - for (unsigned i = 0; i < m_size; ++i) - *m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; - if (!_move) - retrieveValue(_location); - break; - } - case LValueType::Storage: - // stack layout: value value ... value target_ref - if (m_dataType->isValueType()) - { - if (!_move) // copy values - { - if (m_size + 1 > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Stack too deep.")); - for (unsigned i = 0; i < m_size; ++i) - *m_context << eth::dupInstruction(m_size + 1) << eth::Instruction::SWAP1; - } - if (m_size > 0) // store high index value first - *m_context << u256(m_size - 1) << eth::Instruction::ADD; - for (unsigned i = 0; i < m_size; ++i) - { - if (i + 1 >= m_size) - *m_context << eth::Instruction::SSTORE; - else - // stack here: value value ... value value (target_ref+offset) - *m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 - << eth::Instruction::SSTORE - << u256(1) << eth::Instruction::SWAP1 << eth::Instruction::SUB; - } - } - else - { - solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "Wrong type conversation for assignment."); - if (m_dataType->getCategory() == Type::Category::Array) - { - CompilerUtils(*m_context).copyByteArrayToStorage( - dynamic_cast(*m_dataType), - dynamic_cast(_sourceType)); - if (_move) - *m_context << eth::Instruction::POP; - } - else if (m_dataType->getCategory() == Type::Category::Struct) - { - // stack layout: source_ref target_ref - auto const& structType = dynamic_cast(*m_dataType); - solAssert(structType == _sourceType, "Struct assignment with conversion."); - for (auto const& member: structType.getMembers()) - { - // assign each member that is not a mapping - TypePointer const& memberType = member.second; - if (memberType->getCategory() == Type::Category::Mapping) - continue; - *m_context << structType.getStorageOffsetOfMember(member.first) - << eth::Instruction::DUP3 << eth::Instruction::DUP2 - << eth::Instruction::ADD; - // stack: source_ref target_ref member_offset source_member_ref - LValue rightHandSide(*m_context, LValueType::Storage, memberType); - rightHandSide.retrieveValue(_location, true); - // stack: source_ref target_ref member_offset source_value... - *m_context << eth::dupInstruction(2 + memberType->getSizeOnStack()) - << eth::dupInstruction(2 + memberType->getSizeOnStack()) - << eth::Instruction::ADD; - // stack: source_ref target_ref member_offset source_value... target_member_ref - LValue memberLValue(*m_context, LValueType::Storage, memberType); - memberLValue.storeValue(*memberType, _location, true); - *m_context << eth::Instruction::POP; - } - if (_move) - *m_context << eth::Instruction::POP; - else - *m_context << eth::Instruction::SWAP1; - *m_context << eth::Instruction::POP; - } - else - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Invalid non-value type for assignment.")); - } - break; - case LValueType::Memory: - if (!m_dataType->isValueType()) - break; // no distinction between value and reference for non-value types - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Location type not yet implemented.")); - break; - default: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Unsupported location type.")); - break; - } -} - -void ExpressionCompiler::LValue::setToZero(SourceLocation const& _location) const -{ - switch (m_type) - { - case LValueType::Stack: - { - unsigned stackDiff = m_context->baseToCurrentStackOffset(m_baseStackOffset); - if (stackDiff > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Stack too deep.")); - solAssert(stackDiff >= m_size - 1, ""); - for (unsigned i = 0; i < m_size; ++i) - *m_context << u256(0) << eth::swapInstruction(stackDiff + 1 - i) - << eth::Instruction::POP; - break; - } - case LValueType::Storage: - if (m_dataType->getCategory() == Type::Category::Array) - CompilerUtils(*m_context).clearByteArray(dynamic_cast(*m_dataType)); - else if (m_dataType->getCategory() == Type::Category::Struct) - { - // stack layout: ref - auto const& structType = dynamic_cast(*m_dataType); - for (auto const& member: structType.getMembers()) - { - // zero each member that is not a mapping - TypePointer const& memberType = member.second; - if (memberType->getCategory() == Type::Category::Mapping) - continue; - *m_context << structType.getStorageOffsetOfMember(member.first) - << eth::Instruction::DUP2 << eth::Instruction::ADD; - LValue memberValue(*m_context, LValueType::Storage, memberType); - memberValue.setToZero(); - } - *m_context << eth::Instruction::POP; - } - else - { - if (m_size == 0) - *m_context << eth::Instruction::POP; - for (unsigned i = 0; i < m_size; ++i) - if (i + 1 >= m_size) - *m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; - else - *m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE - << u256(1) << eth::Instruction::ADD; - } - break; - case LValueType::Memory: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Location type not yet implemented.")); - break; - default: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) - << errinfo_comment("Unsupported location type.")); - break; - } -} - -void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression const& _expression) -{ - if (!_expression.lvalueRequested()) - { - retrieveValue(_expression.getLocation(), true); - reset(); - } + lvalue->retrieveValue(_expression.getLocation(), true); } } diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 2eb8ca20c..edb63ad9f 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace dev { namespace eth @@ -50,22 +51,28 @@ class StaticStringType; class ExpressionCompiler: private ASTConstVisitor { public: - /// Compile the given @a _expression into the @a _context. - static void compileExpression(CompilerContext& _context, Expression const& _expression, bool _optimize = false); - - /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. - static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, - Type const& _targetType, bool _cleanupNeeded = false); /// Appends code for a State Variable accessor function static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); - /// Appends code for a State Variable Initialization function - static void appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): + m_optimize(_optimize), m_context(_compilerContext) {} + + /// Compile the given @a _expression and leave its value on the stack. + void compile(Expression const& _expression); + + /// Appends code to set a state variable to its initial value/expression. + void appendStateVariableInitialization(VariableDeclaration const& _varDecl); + + /// Appends code for a State Variable accessor function + void appendStateVariableAccessor(VariableDeclaration const& _varDecl); + + /// Appends an implicit or explicit type conversion. For now this comprises only erasing + /// higher-order bits (@see appendHighBitCleanup) when widening integer. + /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be + /// necessary. + void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false); private: - explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): - m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} - virtual bool visit(Assignment const& _assignment) override; virtual bool visit(UnaryOperation const& _unaryOperation) override; virtual bool visit(BinaryOperation const& _binaryOperation) override; @@ -87,11 +94,6 @@ private: void appendShiftOperatorCode(Token::Value _operator); /// @} - /// Appends an implicit or explicit type conversion. For now this comprises only erasing - /// higher-order bits (@see appendHighBitCleanup) when widening integer. - /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be - /// necessary. - void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false); //// Appends code that cleans higher-order bits for integer types. void appendHighBitsCleanup(IntegerType const& _typeOnStack); @@ -111,75 +113,17 @@ private: /// expected to be on the stack and is updated by this call. void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression); - /// Appends code for a State Variable accessor function - void appendStateVariableAccessor(VariableDeclaration const& _varDecl); - - /// Appends code for a State Variable initialization - void appendStateVariableInitialization(VariableDeclaration const& _varDecl); - - /** - * Helper class to store and retrieve lvalues to and from various locations. - * All types except STACK store a reference in a slot on the stack, STACK just - * stores the base stack offset of the variable in @a m_baseStackOffset. - */ - class LValue - { - public: - enum class LValueType { None, Stack, Memory, Storage }; - - explicit LValue(CompilerContext& _compilerContext): m_context(&_compilerContext) { reset(); } - LValue(CompilerContext& _compilerContext, LValueType _type, - std::shared_ptr const& _dataType, unsigned _baseStackOffset = 0); - - /// Set type according to the declaration and retrieve the reference. - /// @a _location is the current location - void fromDeclaration(Declaration const& _declaration, SourceLocation const& _location); - - void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } - - bool isValid() const { return m_type != LValueType::None; } - bool isInOnStack() const { return m_type == LValueType::Stack; } - bool isInMemory() const { return m_type == LValueType::Memory; } - bool isInStorage() const { return m_type == LValueType::Storage; } - - /// @returns true if this lvalue reference type occupies a slot on the stack. - bool storesReferenceOnStack() const { return m_type == LValueType::Storage || m_type == LValueType::Memory; } - - /// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true, - /// also removes the reference from the stack (note that is does not reset the type to @a NONE). - /// @a _location source location of the current expression, used for error reporting. - void retrieveValue(SourceLocation const& _location, bool _remove = false) const; - /// Moves a value from the stack to the lvalue. Removes the value if @a _move is true. - /// @a _location is the source location of the expression that caused this operation. - /// Stack pre: value [lvalue_ref] - /// Stack post if !_move: value_of(lvalue_ref) - void storeValue(Type const& _sourceType, SourceLocation const& _location = SourceLocation(), bool _move = false) const; - /// Stores zero in the lvalue. - /// @a _location is the source location of the requested operation - void setToZero(SourceLocation const& _location = SourceLocation()) const; - /// Convenience function to convert the stored reference to a value and reset type to NONE if - /// the reference was not requested by @a _expression. - void retrieveValueIfLValueNotRequested(Expression const& _expression); - - private: - /// Convenience function to retrieve Value from Storage. Specific version of @ref retrieveValue - void retrieveValueFromStorage(bool _remove = false) const; - /// Copies from a byte array to a byte array in storage, both references on the stack. - void copyByteArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const; - - CompilerContext* m_context; - LValueType m_type = LValueType::None; - std::shared_ptr m_dataType; - /// If m_type is STACK, this is base stack offset (@see - /// CompilerContext::getBaseStackOffsetOfVariable) of a local variable. - unsigned m_baseStackOffset = 0; - /// Size of the value of this lvalue on the stack or the storage. - unsigned m_size = 0; - }; + /// Sets the current LValue to a new one (of the appropriate type) from the given declaration. + /// Also retrieves the value if it was not requested by @a _expression. + void setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression); + /// Sets the current LValue to a StorageItem holding the type of @a _expression. The reference is assumed + /// to be on the stack. + /// Also retrieves the value if it was not requested by @a _expression. + void setLValueToStorageItem(Expression const& _expression); bool m_optimize; CompilerContext& m_context; - LValue m_currentLValue; + std::unique_ptr m_currentLValue; }; diff --git a/LValue.cpp b/LValue.cpp new file mode 100644 index 000000000..8b9bd53b6 --- /dev/null +++ b/LValue.cpp @@ -0,0 +1,220 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2015 + * LValues for use in the expresison compiler. + */ + +#include +#include +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace solidity; + + +StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration): + LValue(_compilerContext, _declaration.getType()), + m_baseStackOffset(m_context.getBaseStackOffsetOfVariable(_declaration)), + m_size(m_dataType->getSizeOnStack()) +{ +} + +void StackVariable::retrieveValue(SourceLocation const& _location, bool _remove) const +{ + unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); + if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + for (unsigned i = 0; i < m_size; ++i) + m_context << eth::dupInstruction(stackPos + 1); +} + +void StackVariable::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const +{ + unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; + if (stackDiff > 16) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + else if (stackDiff > 0) + for (unsigned i = 0; i < m_size; ++i) + m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; + if (!_move) + retrieveValue(_location); +} + +void StackVariable::setToZero(SourceLocation const& _location) const +{ + unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset); + if (stackDiff > 16) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + solAssert(stackDiff >= m_size - 1, ""); + for (unsigned i = 0; i < m_size; ++i) + m_context << u256(0) << eth::swapInstruction(stackDiff + 1 - i) + << eth::Instruction::POP; +} + + +StorageItem::StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration): + StorageItem(_compilerContext, _declaration.getType()) +{ + m_context << m_context.getStorageLocationOfVariable(_declaration); +} + +StorageItem::StorageItem(CompilerContext& _compilerContext, TypePointer const& _type): + LValue(_compilerContext, _type) +{ + if (m_dataType->isValueType()) + { + solAssert(m_dataType->getStorageSize() == m_dataType->getSizeOnStack(), ""); + solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), + "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); + m_size = unsigned(m_dataType->getStorageSize()); + } + else + m_size = 0; // unused +} + +void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const +{ + if (!m_dataType->isValueType()) + return; // no distinction between value and reference for non-value types + if (!_remove) + m_context << eth::Instruction::DUP1; + if (m_size == 1) + m_context << eth::Instruction::SLOAD; + else + for (unsigned i = 0; i < m_size; ++i) + { + m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1; + if (i + 1 < m_size) + m_context << u256(1) << eth::Instruction::ADD; + else + m_context << eth::Instruction::POP; + } +} + +void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const +{ + // stack layout: value value ... value target_ref + if (m_dataType->isValueType()) + { + if (!_move) // copy values + { + if (m_size + 1 > 16) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + for (unsigned i = 0; i < m_size; ++i) + m_context << eth::dupInstruction(m_size + 1) << eth::Instruction::SWAP1; + } + if (m_size > 1) // store high index value first + m_context << u256(m_size - 1) << eth::Instruction::ADD; + for (unsigned i = 0; i < m_size; ++i) + { + if (i + 1 >= m_size) + m_context << eth::Instruction::SSTORE; + else + // stack here: value value ... value value (target_ref+offset) + m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 + << eth::Instruction::SSTORE + << u256(1) << eth::Instruction::SWAP1 << eth::Instruction::SUB; + } + } + else + { + solAssert(_sourceType.getCategory() == m_dataType->getCategory(), + "Wrong type conversation for assignment."); + if (m_dataType->getCategory() == Type::Category::Array) + { + CompilerUtils(m_context).copyByteArrayToStorage( + dynamic_cast(*m_dataType), + dynamic_cast(_sourceType)); + if (_move) + m_context << eth::Instruction::POP; + } + else if (m_dataType->getCategory() == Type::Category::Struct) + { + // stack layout: source_ref target_ref + auto const& structType = dynamic_cast(*m_dataType); + solAssert(structType == _sourceType, "Struct assignment with conversion."); + for (auto const& member: structType.getMembers()) + { + // assign each member that is not a mapping + TypePointer const& memberType = member.second; + if (memberType->getCategory() == Type::Category::Mapping) + continue; + m_context << structType.getStorageOffsetOfMember(member.first) + << eth::Instruction::DUP3 << eth::Instruction::DUP2 << eth::Instruction::ADD; + // stack: source_ref target_ref member_offset source_member_ref + StorageItem(m_context, memberType).retrieveValue(_location, true); + // stack: source_ref target_ref member_offset source_value... + m_context << eth::dupInstruction(2 + memberType->getSizeOnStack()) + << eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::Instruction::ADD; + // stack: source_ref target_ref member_offset source_value... target_member_ref + StorageItem(m_context, memberType).storeValue(*memberType, _location, true); + m_context << eth::Instruction::POP; + } + if (_move) + m_context << eth::Instruction::POP; + else + m_context << eth::Instruction::SWAP1; + m_context << eth::Instruction::POP; + } + else + BOOST_THROW_EXCEPTION(InternalCompilerError() + << errinfo_sourceLocation(_location) << errinfo_comment("Invalid non-value type for assignment.")); + } +} + + +void StorageItem::setToZero(SourceLocation const& _location) const +{ + if (m_dataType->getCategory() == Type::Category::Array) + CompilerUtils(m_context).clearByteArray(dynamic_cast(*m_dataType)); + else if (m_dataType->getCategory() == Type::Category::Struct) + { + // stack layout: ref + auto const& structType = dynamic_cast(*m_dataType); + for (auto const& member: structType.getMembers()) + { + // zero each member that is not a mapping + TypePointer const& memberType = member.second; + if (memberType->getCategory() == Type::Category::Mapping) + continue; + m_context << structType.getStorageOffsetOfMember(member.first) + << eth::Instruction::DUP2 << eth::Instruction::ADD; + StorageItem(m_context, memberType).setToZero(); + } + m_context << eth::Instruction::POP; + } + else + { + if (m_size == 0) + m_context << eth::Instruction::POP; + for (unsigned i = 0; i < m_size; ++i) + if (i + 1 >= m_size) + m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; + else + m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE + << u256(1) << eth::Instruction::ADD; + } +} diff --git a/LValue.h b/LValue.h new file mode 100644 index 000000000..35ddc4515 --- /dev/null +++ b/LValue.h @@ -0,0 +1,112 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2015 + * LValues for use in the expresison compiler. + */ + +#pragma once + +#include +#include + +namespace dev +{ +namespace solidity +{ + +class Declaration; +class Type; +class CompilerContext; + +/** + * Abstract class used to retrieve, delete and store data in lvalues/variables. + */ +class LValue +{ +protected: + LValue(CompilerContext& _compilerContext, std::shared_ptr const& _dataType): + m_context(_compilerContext), m_dataType(_dataType) {} + +public: + /// @returns true if this lvalue reference type occupies a slot on the stack. + virtual bool storesReferenceOnStack() const = 0; + /// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true, + /// also removes the reference from the stack. + /// @a _location source location of the current expression, used for error reporting. + virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const = 0; + /// Moves a value from the stack to the lvalue. Removes the value if @a _move is true. + /// @a _location is the source location of the expression that caused this operation. + /// Stack pre: value [lvalue_ref] + /// Stack post if !_move: value_of(lvalue_ref) + virtual void storeValue(Type const& _sourceType, + SourceLocation const& _location = SourceLocation(), bool _move = false) const = 0; + /// Stores zero in the lvalue. + /// @a _location is the source location of the requested operation + virtual void setToZero(SourceLocation const& _location = SourceLocation()) const = 0; + +protected: + CompilerContext& m_context; + std::shared_ptr m_dataType; +}; + +/** + * Local variable that is completely stored on the stack. + */ +class StackVariable: public LValue +{ +public: + explicit StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration); + + virtual bool storesReferenceOnStack() const { return false; } + virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; + virtual void storeValue(Type const& _sourceType, + SourceLocation const& _location = SourceLocation(), bool _move = false) const override; + virtual void setToZero(SourceLocation const& _location = SourceLocation()) const override; + +private: + /// Base stack offset (@see CompilerContext::getBaseStackOffsetOfVariable) of the local variable. + unsigned m_baseStackOffset; + /// Number of stack elements occupied by the value (not the reference). + unsigned m_size; +}; + +/** + * Reference to some item in storage. The (starting) position of the item is stored on the stack. + */ +class StorageItem: public LValue +{ +public: + /// Constructs the LValue and pushes the location of @a _declaration onto the stack. + explicit StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration); + /// Constructs the LValue and assumes that the storage reference is already on the stack. + explicit StorageItem(CompilerContext& _compilerContext, std::shared_ptr const& _type); + virtual bool storesReferenceOnStack() const { return true; } + virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; + virtual void storeValue(Type const& _sourceType, + SourceLocation const& _location = SourceLocation(), bool _move = false) const override; + virtual void setToZero(SourceLocation const& _location = SourceLocation()) const override; + +private: + /// Number of stack elements occupied by the value (not the reference). + /// Only used for value types. + unsigned m_size; +}; + +} +} From 29c614ebaf551006bc6c028592917e8f0dd5cf96 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 25 Feb 2015 15:55:42 +0100 Subject: [PATCH 11/13] Removed code duplication. --- ExpressionCompiler.cpp | 17 +++-------------- ExpressionCompiler.h | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 6b9b51679..67686df14 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -1031,30 +1031,19 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) { - solAssert(!m_currentLValue, "Current LValue not reset when trying to set to new one."); - std::unique_ptr lvalue; if (m_context.isLocalVariable(&_declaration)) - lvalue.reset(new StackVariable(m_context, _declaration)); + setLValue(_expression, _declaration); else if (m_context.isStateVariable(&_declaration)) - lvalue.reset(new StorageItem(m_context, _declaration)); + setLValue(_expression, _declaration); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Identifier type not supported or identifier not found.")); - if (_expression.lvalueRequested()) - m_currentLValue = move(lvalue); - else - lvalue->retrieveValue(_expression.getLocation(), true); } void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) { - solAssert(!m_currentLValue, "Current LValue not reset when trying to set to new one."); - std::unique_ptr lvalue(new StorageItem(m_context, _expression.getType())); - if (_expression.lvalueRequested()) - m_currentLValue = move(lvalue); - else - lvalue->retrieveValue(_expression.getLocation(), true); + setLValue(_expression, _expression.getType()); } } diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index edb63ad9f..c3ecabbd6 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -120,12 +120,27 @@ private: /// to be on the stack. /// Also retrieves the value if it was not requested by @a _expression. void setLValueToStorageItem(Expression const& _expression); + /// Sets the current LValue to a new LValue constructed from the arguments. + /// Also retrieves the value if it was not requested by @a _expression. + template + void setLValue(Expression const& _expression, _Arguments const&... _arguments); bool m_optimize; CompilerContext& m_context; std::unique_ptr m_currentLValue; }; +template +void ExpressionCompiler::setLValue(Expression const& _expression, _Arguments const&... _arguments) +{ + solAssert(!m_currentLValue, "Current LValue not reset when trying to set to new one."); + std::unique_ptr<_LValueType> lvalue(new _LValueType(m_context, _arguments...)); + if (_expression.lvalueRequested()) + m_currentLValue = move(lvalue); + else + lvalue->retrieveValue(_expression.getLocation(), true); + +} } } From 66b6860eb88c027244abd75393f59b6b68268f6e Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 25 Feb 2015 16:00:23 +0100 Subject: [PATCH 12/13] Stylistic changes. --- ExpressionCompiler.cpp | 5 +++-- ExpressionCompiler.h | 3 ++- LValue.h | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 67686df14..430e46b06 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -153,8 +153,9 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con else if (stackTypeCategory == Type::Category::Enum) solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Enum, ""); - else if (stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::Contract || - stackTypeCategory == Type::Category::IntegerConstant) + else if (stackTypeCategory == Type::Category::Integer || + stackTypeCategory == Type::Category::Contract || + stackTypeCategory == Type::Category::IntegerConstant) { if (targetTypeCategory == Type::Category::String && stackTypeCategory == Type::Category::Integer) { diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index c3ecabbd6..9cab757ea 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -133,7 +134,7 @@ private: template void ExpressionCompiler::setLValue(Expression const& _expression, _Arguments const&... _arguments) { - solAssert(!m_currentLValue, "Current LValue not reset when trying to set to new one."); + solAssert(!m_currentLValue, "Current LValue not reset before trying to set new one."); std::unique_ptr<_LValueType> lvalue(new _LValueType(m_context, _arguments...)); if (_expression.lvalueRequested()) m_currentLValue = move(lvalue); diff --git a/LValue.h b/LValue.h index 35ddc4515..bfa681a48 100644 --- a/LValue.h +++ b/LValue.h @@ -53,7 +53,7 @@ public: /// Moves a value from the stack to the lvalue. Removes the value if @a _move is true. /// @a _location is the source location of the expression that caused this operation. /// Stack pre: value [lvalue_ref] - /// Stack post if !_move: value_of(lvalue_ref) + /// Stack post: if !_move: value_of(lvalue_ref) virtual void storeValue(Type const& _sourceType, SourceLocation const& _location = SourceLocation(), bool _move = false) const = 0; /// Stores zero in the lvalue. From a5b4f18dd7291e403237061d5f9660db0299601d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 26 Feb 2015 13:19:34 +0100 Subject: [PATCH 13/13] Fix warnings. --- LValue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/LValue.cpp b/LValue.cpp index 8b9bd53b6..db59c41af 100644 --- a/LValue.cpp +++ b/LValue.cpp @@ -40,6 +40,7 @@ StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration cons void StackVariable::retrieveValue(SourceLocation const& _location, bool _remove) const { + (void)_remove; unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory BOOST_THROW_EXCEPTION(CompilerError() @@ -50,6 +51,7 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool _remove) void StackVariable::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const { + (void)_sourceType; unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; if (stackDiff > 16) BOOST_THROW_EXCEPTION(CompilerError() @@ -188,6 +190,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc void StorageItem::setToZero(SourceLocation const& _location) const { + (void)_location; if (m_dataType->getCategory() == Type::Category::Array) CompilerUtils(m_context).clearByteArray(dynamic_cast(*m_dataType)); else if (m_dataType->getCategory() == Type::Category::Struct)