From d4d5f23e8f198f772d87d36b2b0a609b0584da87 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 20 Oct 2014 12:41:56 +0200 Subject: [PATCH 01/36] Expression compiler. --- libsolidity/AST.cpp | 23 ++- libsolidity/AST.h | 13 ++ libsolidity/Compiler.cpp | 408 ++++++++++++++++++++++++++++++++++++++ libsolidity/Compiler.h | 140 +++++++++++++ libsolidity/Token.h | 1 + libsolidity/Types.cpp | 85 ++++++-- libsolidity/Types.h | 31 ++- solc/main.cpp | 41 ++++ test/solidityCompiler.cpp | 229 +++++++++++++++++++++ 9 files changed, 941 insertions(+), 30 deletions(-) create mode 100644 libsolidity/Compiler.cpp create mode 100644 libsolidity/Compiler.h create mode 100644 test/solidityCompiler.cpp diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 91b4a42b1..414de9b2b 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -328,7 +328,7 @@ void Assignment::checkTypeRequirements() m_type = m_leftHandSide->getType(); if (m_assigmentOperator != Token::ASSIGN) { - // complex assignment + // compound assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); } @@ -339,7 +339,7 @@ void UnaryOperation::checkTypeRequirements() // INC, DEC, NOT, BIT_NOT, DELETE m_subExpression->checkTypeRequirements(); m_type = m_subExpression->getType(); - if (m_type->acceptsUnaryOperator(m_operator)) + if (!m_type->acceptsUnaryOperator(m_operator)) BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); } @@ -369,11 +369,11 @@ void FunctionCall::checkTypeRequirements() m_expression->checkTypeRequirements(); for (ASTPointer const& argument: m_arguments) argument->checkTypeRequirements(); - Type const& expressionType = *m_expression->getType(); - Type::Category const category = expressionType.getCategory(); - if (category == Type::Category::TYPE) + + Type const* expressionType = m_expression->getType().get(); + if (isTypeConversion()) { - TypeType const* type = dynamic_cast(&expressionType); + TypeType const* type = dynamic_cast(expressionType); BOOST_ASSERT(type); //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members @@ -384,12 +384,12 @@ void FunctionCall::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); m_type = type->getActualType(); } - else if (category == Type::Category::FUNCTION) + else { //@todo would be nice to create a struct type from the arguments // and then ask if that is implicitly convertible to the struct represented by the // function parameters - FunctionType const* function = dynamic_cast(&expressionType); + FunctionType const* function = dynamic_cast(expressionType); BOOST_ASSERT(function); FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); @@ -405,8 +405,11 @@ void FunctionCall::checkTypeRequirements() else m_type = fun.getReturnParameterList()->getParameters().front()->getType(); } - else - BOOST_THROW_EXCEPTION(createTypeError("Type does not support invocation.")); +} + +bool FunctionCall::isTypeConversion() const +{ + return m_expression->getType()->getCategory() == Type::Category::TYPE; } void MemberAccess::checkTypeRequirements() diff --git a/libsolidity/AST.h b/libsolidity/AST.h index df146ab10..a55f58c16 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -61,6 +61,12 @@ public: /// the given description TypeError createTypeError(std::string const& _description); + ///@{ + /// Equality relies on the fact that nodes cannot be copied. + bool operator==(ASTNode const& _other) const { return this == &_other; } + bool operator!=(ASTNode const& _other) const { return !operator==(_other); } + ///@} + private: Location m_location; }; @@ -386,7 +392,9 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + Expression& getLeftHandSide() const { return *m_leftHandSide; } Token::Value getAssignmentOperator() const { return m_assigmentOperator; } + Expression& getRightHandSide() const { return *m_rightHandSide; } private: ASTPointer m_leftHandSide; @@ -422,6 +430,8 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + Expression& getLeftExpression() const { return *m_left; } + Expression& getRightExpression() const { return *m_right; } Token::Value getOperator() const { return m_operator; } private: @@ -441,6 +451,9 @@ public: Expression(_location), m_expression(_expression), m_arguments(_arguments) {} virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + /// Returns true if this is not an actual function call, but an explicit type conversion + /// or constructor call. + bool isTypeConversion() const; private: ASTPointer m_expression; diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp new file mode 100644 index 000000000..319f9b1cf --- /dev/null +++ b/libsolidity/Compiler.cpp @@ -0,0 +1,408 @@ +/* + 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 + * Solidity AST to EVM bytecode compiler. + */ + +#include +#include +#include +#include + + +namespace dev { +namespace solidity { + + +void CompilerContext::setLabelPosition(uint32_t _label, uint32_t _position) +{ + BOOST_ASSERT(m_labelPositions.find(_label) == m_labelPositions.end()); + m_labelPositions[_label] = _position; +} + +uint32_t CompilerContext::getLabelPosition(uint32_t _label) const +{ + auto iter = m_labelPositions.find(_label); + BOOST_ASSERT(iter != m_labelPositions.end()); + return iter->second; +} + +void ExpressionCompiler::compile(Expression& _expression) +{ + m_assemblyItems.clear(); + _expression.accept(*this); +} + +bytes ExpressionCompiler::getAssembledBytecode() const +{ + bytes assembled; + assembled.reserve(m_assemblyItems.size()); + + // resolve label references + for (uint32_t pos = 0; pos < m_assemblyItems.size(); ++pos) + { + AssemblyItem const& item = m_assemblyItems[pos]; + if (item.getType() == AssemblyItem::Type::LABEL) + m_context.setLabelPosition(item.getLabel(), pos + 1); + } + + for (AssemblyItem const& item: m_assemblyItems) + { + if (item.getType() == AssemblyItem::Type::LABELREF) + assembled.push_back(m_context.getLabelPosition(item.getLabel())); + else + assembled.push_back(item.getData()); + } + + return assembled; +} + +AssemblyItems ExpressionCompiler::compileExpression(CompilerContext& _context, + Expression& _expression) +{ + ExpressionCompiler compiler(_context); + compiler.compile(_expression); + return compiler.getAssemblyItems(); +} + +void ExpressionCompiler::endVisit(Assignment& _assignment) +{ + Expression& rightHandSide = _assignment.getRightHandSide(); + Token::Value op = _assignment.getAssignmentOperator(); + if (op != Token::ASSIGN) + { + // compound assignment + // @todo retrieve lvalue value + rightHandSide.accept(*this); + Type const& resultType = *_assignment.getType(); + cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); + appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType); + } + else + rightHandSide.accept(*this); + // @todo store value +} + +void ExpressionCompiler::endVisit(UnaryOperation& _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 + // represents the operator + switch (_unaryOperation.getOperator()) + { + case Token::NOT: // ! + append(eth::Instruction::NOT); + break; + case Token::BIT_NOT: // ~ + // ~a modeled as "a xor (0 - 1)" for now + append(eth::Instruction::PUSH1); + append(1); + append(eth::Instruction::PUSH1); + append(0); + append(eth::Instruction::SUB); + append(eth::Instruction::XOR); + break; + case Token::DELETE: // delete + // a -> a xor a (= 0). + // @todo this should also be an assignment + // @todo semantics change for complex types + append(eth::Instruction::DUP1); + append(eth::Instruction::XOR); + break; + case Token::INC: // ++ (pre- or postfix) + // @todo this should also be an assignment + if (_unaryOperation.isPrefixOperation()) + { + append(eth::Instruction::PUSH1); + append(1); + append(eth::Instruction::ADD); + } + break; + case Token::DEC: // -- (pre- or postfix) + // @todo this should also be an assignment + if (_unaryOperation.isPrefixOperation()) + { + append(eth::Instruction::PUSH1); + append(1); + append(eth::Instruction::SWAP1); //@todo avoid this + append(eth::Instruction::SUB); + } + break; + case Token::ADD: // + + // unary add, so basically no-op + break; + case Token::SUB: // - + append(eth::Instruction::NEG); + break; + default: + BOOST_ASSERT(false); // invalid operation + } +} + +bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) +{ + Expression& leftExpression = _binaryOperation.getLeftExpression(); + Expression& rightExpression = _binaryOperation.getRightExpression(); + Type const& resultType = *_binaryOperation.getType(); + Token::Value const op = _binaryOperation.getOperator(); + + if (op == Token::AND || op == Token::OR) + { + // special case: short-circuiting + appendAndOrOperatorCode(_binaryOperation); + } + else if (Token::isCompareOp(op)) + { + leftExpression.accept(*this); + rightExpression.accept(*this); + + // the types to compare have to be the same, but the resulting type is always bool + BOOST_ASSERT(*leftExpression.getType() == *rightExpression.getType()); + appendCompareOperatorCode(op, *leftExpression.getType()); + } + else + { + leftExpression.accept(*this); + cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType); + rightExpression.accept(*this); + cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType); + appendOrdinaryBinaryOperatorCode(op, resultType); + } + + // do not visit the child nodes, we already did that explicitly + return false; +} + +void ExpressionCompiler::endVisit(FunctionCall& _functionCall) +{ + if (_functionCall.isTypeConversion()) + { + //@todo binary representation for all supported types (bool and int) is the same, so no-op + // here for now. + } + else + { + //@todo + } +} + +void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) +{ + +} + +void ExpressionCompiler::endVisit(IndexAccess& _indexAccess) +{ + +} + +void ExpressionCompiler::endVisit(Identifier& _identifier) +{ + +} + +void ExpressionCompiler::endVisit(Literal& _literal) +{ + switch (_literal.getType()->getCategory()) + { + case Type::Category::INTEGER: + case Type::Category::BOOL: + { + bytes value = _literal.getType()->literalToBigEndian(_literal); + BOOST_ASSERT(value.size() <= 32); + BOOST_ASSERT(!value.empty()); + append(static_cast(eth::Instruction::PUSH1) + static_cast(value.size() - 1)); + append(value); + break; + } + default: + BOOST_ASSERT(false); // @todo + } +} + +void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(const Type& _typeOnStack, const Type& _targetType) +{ + // If the type of one of the operands is extended, 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) + return; + if (_typeOnStack.getCategory() == Type::Category::INTEGER && + _targetType.getCategory() == Type::Category::INTEGER) + { + //@todo + } + else + { + // If we get here, there is either an implementation missing to clean higher oder bits + // for non-integer types that are explicitly convertible or we got here in error. + BOOST_ASSERT(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); + BOOST_ASSERT(false); // these types should not be convertible. + } +} + +void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) +{ + Token::Value const op = _binaryOperation.getOperator(); + BOOST_ASSERT(op == Token::OR || op == Token::AND); + + _binaryOperation.getLeftExpression().accept(*this); + append(eth::Instruction::DUP1); + if (op == Token::AND) + append(eth::Instruction::NOT); + uint32_t endLabel = appendConditionalJump(); + _binaryOperation.getRightExpression().accept(*this); + appendLabel(endLabel); +} + +void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type) +{ + if (_operator == Token::EQ || _operator == Token::NE) + { + append(eth::Instruction::EQ); + if (_operator == Token::NE) + append(eth::Instruction::NOT); + } + else + { + IntegerType const* type = dynamic_cast(&_type); + BOOST_ASSERT(type != nullptr); + bool const isSigned = type->isSigned(); + + // note that EVM opcodes compare like "stack[0] < stack[1]", + // but our left value is at stack[1], so everyhing is reversed. + switch (_operator) + { + case Token::GTE: + append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT); + append(eth::Instruction::NOT); + break; + case Token::LTE: + append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT); + append(eth::Instruction::NOT); + break; + case Token::GT: + append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT); + break; + case Token::LT: + append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT); + break; + default: + BOOST_ASSERT(false); + } + } +} + +void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type) +{ + if (Token::isArithmeticOp(_operator)) + appendArithmeticOperatorCode(_operator, _type); + else if (Token::isBitOp(_operator)) + appendBitOperatorCode(_operator); + else if (Token::isShiftOp(_operator)) + appendShiftOperatorCode(_operator); + else + BOOST_ASSERT(false); // unknown binary operator +} + +void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) +{ + IntegerType const* type = dynamic_cast(&_type); + BOOST_ASSERT(type != nullptr); + bool const isSigned = type->isSigned(); + + switch (_operator) + { + case Token::ADD: + append(eth::Instruction::ADD); + break; + case Token::SUB: + append(eth::Instruction::SWAP1); + append(eth::Instruction::SUB); + break; + case Token::MUL: + append(eth::Instruction::MUL); + break; + case Token::DIV: + append(isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); + break; + case Token::MOD: + append(isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); + break; + default: + BOOST_ASSERT(false); + } +} + +void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) +{ + switch (_operator) + { + case Token::BIT_OR: + append(eth::Instruction::OR); + break; + case Token::BIT_AND: + append(eth::Instruction::AND); + break; + case Token::BIT_XOR: + append(eth::Instruction::XOR); + break; + default: + BOOST_ASSERT(false); + } +} + +void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) +{ + switch (_operator) + { + case Token::SHL: + BOOST_ASSERT(false); //@todo + break; + case Token::SAR: + BOOST_ASSERT(false); //@todo + break; + default: + BOOST_ASSERT(false); + } +} + +uint32_t ExpressionCompiler::appendConditionalJump() +{ + uint32_t label = m_context.dispenseNewLabel(); + append(eth::Instruction::PUSH1); + appendLabelref(label); + append(eth::Instruction::JUMPI); + return label; +} + +void ExpressionCompiler::append(bytes const& _data) +{ + m_assemblyItems.reserve(m_assemblyItems.size() + _data.size()); + for (byte b: _data) + append(b); +} + + + +} +} diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h new file mode 100644 index 000000000..bddc4bef3 --- /dev/null +++ b/libsolidity/Compiler.h @@ -0,0 +1,140 @@ +/* + 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 + * Solidity AST to EVM bytecode compiler. + */ + +#include +#include +#include +#include + +namespace dev { +namespace solidity { + +/// A single item of compiled code that can be assembled to a single byte value in the final +/// bytecode. Its main purpose is to inject jump labels and label references into the opcode stream, +/// which can be resolved in the final step. +class AssemblyItem +{ +public: + enum class Type + { + CODE, //< m_data is opcode, m_label is empty. + DATA, //< m_data is actual data, m_label is empty + LABEL, //< m_data is JUMPDEST opcode, m_label is id of label + LABELREF //< m_data is empty, m_label is id of label + }; + + explicit AssemblyItem(eth::Instruction _instruction) : m_type(Type::CODE), m_data(byte(_instruction)) {} + explicit AssemblyItem(byte _data): m_type(Type::DATA), m_data(_data) {} + + /// Factory functions + static AssemblyItem labelRef(uint32_t _label) { return AssemblyItem(Type::LABELREF, 0, _label); } + static AssemblyItem label(uint32_t _label) { return AssemblyItem(Type::LABEL, byte(eth::Instruction::JUMPDEST), _label); } + + Type getType() const { return m_type; } + byte getData() const { return m_data; } + uint32_t getLabel() const { return m_label; } + +private: + AssemblyItem(Type _type, byte _data, uint32_t _label): m_type(_type), m_data(_data), m_label(_label) {} + + Type m_type; + byte m_data; //< data to be written to the bytecode stream (or filled by a label if this is a LABELREF) + uint32_t m_label; //< the id of a label either referenced or defined by this item +}; + +using AssemblyItems = std::vector; + + +/// Context to be shared by all units that compile the same contract. Its current usage only +/// concerns dispensing unique jump label IDs and storing their actual positions in the bytecode +/// stream. +class CompilerContext +{ +public: + CompilerContext(): m_nextLabel(0) {} + uint32_t dispenseNewLabel() { return m_nextLabel++; } + void setLabelPosition(uint32_t _label, uint32_t _position); + uint32_t getLabelPosition(uint32_t _label) const; + +private: + uint32_t m_nextLabel; + + std::map m_labelPositions; +}; + +/// Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream +/// of EVM instructions. It needs a compiler context that is the same for the whole compilation +/// unit. +class ExpressionCompiler: public ASTVisitor +{ +public: + ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {} + + /// Compile the given expression and (re-)populate the assembly item list. + void compile(Expression& _expression); + AssemblyItems const& getAssemblyItems() const { return m_assemblyItems; } + bytes getAssembledBytecode() const; + + /// Compile the given expression and return the assembly items right away. + static AssemblyItems compileExpression(CompilerContext& _context, Expression& _expression); + +private: + virtual void endVisit(Assignment& _assignment) override; + virtual void endVisit(UnaryOperation& _unaryOperation) override; + virtual bool visit(BinaryOperation& _binaryOperation) override; + virtual void endVisit(FunctionCall& _functionCall) override; + virtual void endVisit(MemberAccess& _memberAccess) override; + virtual void endVisit(IndexAccess& _indexAccess) override; + virtual void endVisit(Identifier& _identifier) override; + virtual void endVisit(Literal& _literal) override; + + /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. + void cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType); + + /// Append code for various operator types + /// @{ + void appendAndOrOperatorCode(BinaryOperation& _binaryOperation); + void appendCompareOperatorCode(Token::Value _operator, Type const& _type); + void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type); + + void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type); + void appendBitOperatorCode(Token::Value _operator); + void appendShiftOperatorCode(Token::Value _operator); + /// @} + + /// Appends a JUMPI instruction to a new label and returns the label + uint32_t appendConditionalJump(); + + /// Append elements to the current instruction list. + void append(eth::Instruction const& _instruction) { m_assemblyItems.push_back(AssemblyItem(_instruction)); } + void append(byte _value) { m_assemblyItems.push_back(AssemblyItem(_value)); } + void append(bytes const& _data); + void appendLabelref(byte _label) { m_assemblyItems.push_back(AssemblyItem::labelRef(_label)); } + void appendLabel(byte _label) { m_assemblyItems.push_back(AssemblyItem::label(_label)); } + + AssemblyItems m_assemblyItems; + CompilerContext& m_context; +}; + + +} +} diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 2db6e05de..7949d2c65 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -236,6 +236,7 @@ public: static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; } static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; } static bool isTruncatingBinaryOp(Value op) { return BIT_OR <= op && op <= SHR; } + static bool isArithmeticOp(Value op) { return ADD <= op && op <= MOD; } static bool isCompareOp(Value op) { return EQ <= op && op <= IN; } static bool isOrderedRelationalCompareOp(Value op) { diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 62324f8c2..f0307a7cd 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -96,7 +97,7 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const { - if (_convertTo.getCategory() != Category::INTEGER) + if (_convertTo.getCategory() != getCategory()) return false; IntegerType const& convertTo = dynamic_cast(_convertTo); if (convertTo.m_bits < m_bits) @@ -113,7 +114,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - return _convertTo.getCategory() == Category::INTEGER; + return _convertTo.getCategory() == getCategory(); } bool IntegerType::acceptsBinaryOperator(Token::Value _operator) const @@ -128,7 +129,24 @@ bool IntegerType::acceptsBinaryOperator(Token::Value _operator) const bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const { - return _operator == Token::DELETE || (!isAddress() && _operator == Token::BIT_NOT); + if (_operator == Token::DELETE) + return true; + if (isAddress()) + return false; + if (_operator == Token::BIT_NOT) + return true; + if (isHash()) + return false; + return _operator == Token::ADD || _operator == Token::SUB || + _operator == Token::INC || _operator == Token::DEC; +} + +bool IntegerType::operator==(const Type& _other) const +{ + if (_other.getCategory() != getCategory()) + return false; + IntegerType const& other = dynamic_cast(_other); + return other.m_bits == m_bits && other.m_modifier == m_modifier; } std::string IntegerType::toString() const @@ -139,11 +157,21 @@ std::string IntegerType::toString() const return prefix + dev::toString(m_bits); } +bytes IntegerType::literalToBigEndian(const Literal& _literal) const +{ + bigint value(_literal.getValue()); + if (!isSigned() && value < 0) + return bytes(); // @todo this should already be caught by "smallestTypeforLiteral" + //@todo check that the number of bits is correct + //@todo does "toCompactBigEndian" work for signed numbers? + return toCompactBigEndian(value); +} + bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const { // conversion to integer is fine, but not to address // this is an example of explicit conversions being not transitive (though implicit should be) - if (_convertTo.getCategory() == Category::INTEGER) + if (_convertTo.getCategory() == getCategory()) { IntegerType const& convertTo = dynamic_cast(_convertTo); if (!convertTo.isAddress()) @@ -152,22 +180,55 @@ bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const return isImplicitlyConvertibleTo(_convertTo); } -bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const +bytes BoolType::literalToBigEndian(const Literal& _literal) const { - if (_convertTo.getCategory() != Category::CONTRACT) + if (_literal.getToken() == Token::TRUE_LITERAL) + return bytes(1, 1); + else if (_literal.getToken() == Token::FALSE_LITERAL) + return bytes(1, 0); + else + return NullBytes; +} + +bool ContractType::operator==(const Type& _other) const +{ + if (_other.getCategory() != getCategory()) return false; - ContractType const& convertTo = dynamic_cast(_convertTo); - return &m_contract == &convertTo.m_contract; + ContractType const& other = dynamic_cast(_other); + return other.m_contract == m_contract; } -bool StructType::isImplicitlyConvertibleTo(Type const& _convertTo) const +bool StructType::operator==(const Type& _other) const { - if (_convertTo.getCategory() != Category::STRUCT) + if (_other.getCategory() != getCategory()) return false; - StructType const& convertTo = dynamic_cast(_convertTo); - return &m_struct == &convertTo.m_struct; + StructType const& other = dynamic_cast(_other); + return other.m_struct == m_struct; } +bool FunctionType::operator==(const Type& _other) const +{ + if (_other.getCategory() != getCategory()) + return false; + FunctionType const& other = dynamic_cast(_other); + return other.m_function == m_function; +} + +bool MappingType::operator==(const Type& _other) const +{ + if (_other.getCategory() != getCategory()) + return false; + MappingType const& other = dynamic_cast(_other); + return *other.m_keyType == *m_keyType && *other.m_valueType == *m_valueType; +} + +bool TypeType::operator==(const Type& _other) const +{ + if (_other.getCategory() != getCategory()) + return false; + TypeType const& other = dynamic_cast(_other); + return *getActualType() == *other.getActualType(); +} } } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 82b549433..db4b05a5a 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ public: static std::shared_ptr forLiteral(Literal const& _literal); virtual Category getCategory() const = 0; - virtual bool isImplicitlyConvertibleTo(Type const&) const { return false; } + virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const { return isImplicitlyConvertibleTo(_convertTo); @@ -60,7 +61,11 @@ public: virtual bool acceptsBinaryOperator(Token::Value) const { return false; } virtual bool acceptsUnaryOperator(Token::Value) const { return false; } + virtual bool operator==(Type const& _other) const { return getCategory() == _other.getCategory(); } + virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); } + virtual std::string toString() const = 0; + virtual bytes literalToBigEndian(Literal const&) const { return NullBytes; } }; class IntegerType: public Type @@ -81,7 +86,10 @@ public: virtual bool acceptsBinaryOperator(Token::Value _operator) const override; virtual bool acceptsUnaryOperator(Token::Value _operator) const override; + virtual bool operator==(Type const& _other) const override; + virtual std::string toString() const override; + virtual bytes literalToBigEndian(Literal const& _literal) const override; int getNumBits() const { return m_bits; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } @@ -97,10 +105,6 @@ class BoolType: public Type { public: virtual Category getCategory() const { return Category::BOOL; } - virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override - { - return _convertTo.getCategory() == Category::BOOL; - } virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool acceptsBinaryOperator(Token::Value _operator) const override { @@ -110,7 +114,9 @@ public: { return _operator == Token::NOT || _operator == Token::DELETE; } + virtual std::string toString() const override { return "bool"; } + virtual bytes literalToBigEndian(Literal const& _literal) const override; }; class ContractType: public Type @@ -118,7 +124,8 @@ class ContractType: public Type public: virtual Category getCategory() const override { return Category::CONTRACT; } ContractType(ContractDefinition const& _contract): m_contract(_contract) {} - virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const; + + virtual bool operator==(Type const& _other) const override; virtual std::string toString() const override { return "contract{...}"; } @@ -131,12 +138,12 @@ class StructType: public Type public: virtual Category getCategory() const override { return Category::STRUCT; } StructType(StructDefinition const& _struct): m_struct(_struct) {} - virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const; virtual bool acceptsUnaryOperator(Token::Value _operator) const override { return _operator == Token::DELETE; } + virtual bool operator==(Type const& _other) const override; virtual std::string toString() const override { return "struct{...}"; } @@ -154,6 +161,8 @@ public: virtual std::string toString() const override { return "function(...)returns(...)"; } + virtual bool operator==(Type const& _other) const override; + private: FunctionDefinition const& m_function; }; @@ -165,8 +174,11 @@ public: MappingType() {} virtual std::string toString() const override { return "mapping(...=>...)"; } + virtual bool operator==(Type const& _other) const override; + private: - //@todo + std::shared_ptr m_keyType; + std::shared_ptr m_valueType; }; //@todo should be changed into "empty anonymous struct" @@ -175,6 +187,7 @@ class VoidType: public Type public: virtual Category getCategory() const override { return Category::VOID; } VoidType() {} + virtual std::string toString() const override { return "void"; } }; @@ -186,6 +199,8 @@ public: std::shared_ptr const& getActualType() const { return m_actualType; } + virtual bool operator==(Type const& _other) const override; + virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } private: diff --git a/solc/main.cpp b/solc/main.cpp index ba0b6ccf7..221ab962e 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include using namespace dev; @@ -34,6 +35,35 @@ void version() exit(0); } + +/// Helper class that extracts the first expression in an AST. +class FirstExpressionExtractor: private ASTVisitor +{ +public: + FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); } + Expression* getExpression() const { return m_expression; } +private: + virtual bool visit(Expression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); } + virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); } + virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); } + virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); } + virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); } + virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); } + virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); } + virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Literal& _expression) override { return checkExpression(_expression); } + bool checkExpression(Expression& _expression) + { + if (m_expression == nullptr) + m_expression = &_expression; + return false; + } +private: + Expression* m_expression; +}; + int main(int argc, char** argv) { std::string infile; @@ -92,5 +122,16 @@ int main(int argc, char** argv) std::cout << "Syntax tree for the contract:" << std::endl; dev::solidity::ASTPrinter printer(ast, sourceCode); printer.print(std::cout); + + FirstExpressionExtractor extractor(*ast); + + CompilerContext context; + ExpressionCompiler compiler(context); + compiler.compile(*extractor.getExpression()); + bytes instructions = compiler.getAssembledBytecode(); + // debug + std::cout << "Bytecode for the first expression: " << std::endl; + std::cout << eth::disassemble(instructions) << std::endl; + return 0; } diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp new file mode 100644 index 000000000..6e12fecf8 --- /dev/null +++ b/test/solidityCompiler.cpp @@ -0,0 +1,229 @@ + +/* + 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 + * Unit tests for the name and type resolution of the solidity parser. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +namespace +{ + +/// Helper class that extracts the first expression in an AST. +class FirstExpressionExtractor: private ASTVisitor +{ +public: + FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); } + Expression* getExpression() const { return m_expression; } +private: + virtual bool visit(Expression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); } + virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); } + virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); } + virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); } + virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); } + virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); } + virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); } + virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); } + virtual bool visit(Literal& _expression) override { return checkExpression(_expression); } + bool checkExpression(Expression& _expression) + { + if (m_expression == nullptr) + m_expression = &_expression; + return false; + } +private: + Expression* m_expression; +}; + +bytes compileFirstExpression(const std::string& _sourceCode) +{ + Parser parser; + ASTPointer contract; + BOOST_REQUIRE_NO_THROW(contract = parser.parse(std::make_shared(CharStream(_sourceCode)))); + NameAndTypeResolver resolver; + BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); + FirstExpressionExtractor extractor(*contract); + BOOST_REQUIRE(extractor.getExpression() != nullptr); + + CompilerContext context; + ExpressionCompiler compiler(context); + compiler.compile(*extractor.getExpression()); + bytes instructions = compiler.getAssembledBytecode(); + // debug + //std::cout << eth::disassemble(instructions) << std::endl; + return instructions; +} + +} // end anonymous namespace + +BOOST_AUTO_TEST_SUITE(SolidityExpressionCompiler) + +BOOST_AUTO_TEST_CASE(literal_true) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = true; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0x1}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(literal_false) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = false; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0x0}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(int_literal) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = 0x12345678901234567890; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, + 0x12, 0x34, 0x56, 0x78, 0x90}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(comparison) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = (0x10aa < 0x11aa) != true; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, + byte(eth::Instruction::PUSH2), 0x11, 0xaa, + byte(eth::Instruction::GT), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::EQ), + byte(eth::Instruction::NOT)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(short_circuiting) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = (10 + 8 >= 4 || 2 != 9) != true; }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0xa, + byte(eth::Instruction::PUSH1), 0x8, + byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH1), 0x4, + byte(eth::Instruction::GT), + byte(eth::Instruction::NOT), // after this we have 10 + 8 >= 4 + byte(eth::Instruction::DUP1), + byte(eth::Instruction::PUSH1), 0x14, + byte(eth::Instruction::JUMPI), // short-circuit if it is true + byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::PUSH1), 0x9, + byte(eth::Instruction::EQ), + byte(eth::Instruction::NOT), // after this we have 2 != 9 + byte(eth::Instruction::JUMPDEST), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::EQ), + byte(eth::Instruction::NOT)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(arithmetics) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::PUSH1), 0x3, + byte(eth::Instruction::PUSH1), 0x4, + byte(eth::Instruction::PUSH1), 0x5, + byte(eth::Instruction::PUSH1), 0x6, + byte(eth::Instruction::PUSH1), 0x7, + byte(eth::Instruction::PUSH1), 0x8, + byte(eth::Instruction::PUSH1), 0x9, + byte(eth::Instruction::XOR), + byte(eth::Instruction::AND), + byte(eth::Instruction::OR), + byte(eth::Instruction::SWAP1), + byte(eth::Instruction::SUB), + byte(eth::Instruction::ADD), + byte(eth::Instruction::MOD), + byte(eth::Instruction::DIV), + byte(eth::Instruction::MUL)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(unary_operators) +{ + char const* sourceCode = "contract test {\n" + " function f() { var x = !(~+-(--(++1++)--) == 2); }" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation({byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::SWAP1), + byte(eth::Instruction::SUB), + byte(eth::Instruction::NEG), + byte(eth::Instruction::PUSH1), 0x1, + byte(eth::Instruction::PUSH1), 0x0, + byte(eth::Instruction::SUB), + byte(eth::Instruction::XOR), // bitwise not + byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::EQ), + byte(eth::Instruction::NOT)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces + From 92ee64f44323e0b90dfe4e441fef5fb4c21174c7 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 23 Oct 2014 17:06:12 +0200 Subject: [PATCH 02/36] Some documentation. --- libsolidity/ASTPrinter.h | 1 + libsolidity/ASTVisitor.h | 10 ++++++---- libsolidity/NameAndTypeResolver.cpp | 2 +- libsolidity/Scope.cpp | 4 ++-- libsolidity/Scope.h | 8 +++++--- libsolidity/Types.h | 18 ++++++++++++++++-- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index 14592e2b9..74e0837ff 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -30,6 +30,7 @@ namespace dev namespace solidity { +/// Pretty-printer for the abstract syntax tree (the "pretty" is arguable) for debugging purposes. class ASTPrinter: public ASTVisitor { public: diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index 72f287683..a667ad392 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -30,13 +30,15 @@ namespace dev namespace solidity { +/// Visitor interface for the abstract syntax tree. This class is tightly bound to the +/// implementation of @ref ASTNode::accept and its overrides. After a call to +/// @ref ASTNode::accept, the function visit for the appropriate parameter is called and then +/// (if it returns true) this continues recursively for all child nodes in document order +/// (there is an exception for contracts). After all child nodes have been visited, endVisit is +/// called for the node. class ASTVisitor { public: - /// These functions are called after a call to ASTNode::accept, - /// first visit, then (if visit returns true) recursively for all - /// child nodes in document order (exception for contracts) and then - /// endVisit. virtual bool visit(ASTNode&) { return true; } virtual bool visit(ContractDefinition&) { return true; } virtual bool visit(StructDefinition&) { return true; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index e9d90dc88..0f34eb4c5 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -130,7 +130,7 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) void DeclarationRegistrationHelper::closeCurrentScope() { BOOST_ASSERT(m_currentScope); - m_currentScope = m_currentScope->getOuterScope(); + m_currentScope = m_currentScope->getEnclosingScope(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) diff --git a/libsolidity/Scope.cpp b/libsolidity/Scope.cpp index 4fcd2f45e..540c41204 100644 --- a/libsolidity/Scope.cpp +++ b/libsolidity/Scope.cpp @@ -41,8 +41,8 @@ Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const auto result = m_declarations.find(_name); if (result != m_declarations.end()) return result->second; - if (_recursive && m_outerScope) - return m_outerScope->resolveName(_name, true); + if (_recursive && m_enclosingScope) + return m_enclosingScope->resolveName(_name, true); return nullptr; } diff --git a/libsolidity/Scope.h b/libsolidity/Scope.h index 2e36e5281..83b01f423 100644 --- a/libsolidity/Scope.h +++ b/libsolidity/Scope.h @@ -32,18 +32,20 @@ namespace dev namespace solidity { +/// Container that stores mappings betwee names and declarations. It also contains a link to the +/// enclosing scope. class Scope { public: - explicit Scope(Scope* _outerScope = nullptr): m_outerScope(_outerScope) {} + explicit Scope(Scope* _enclosingScope = nullptr): m_enclosingScope(_enclosingScope) {} /// Registers the declaration in the scope unless its name is already declared. Returns true iff /// it was not yet declared. bool registerDeclaration(Declaration& _declaration); Declaration* resolveName(ASTString const& _name, bool _recursive = false) const; - Scope* getOuterScope() const { return m_outerScope; } + Scope* getEnclosingScope() const { return m_enclosingScope; } private: - Scope* m_outerScope; + Scope* m_enclosingScope; std::map m_declarations; }; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index db4b05a5a..40bc44876 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -37,6 +37,7 @@ namespace solidity // @todo realMxN, string, mapping +/// Abstract base class that forms the root of the type hierarchy. class Type: private boost::noncopyable { public: @@ -45,11 +46,15 @@ public: INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE }; - //! factory functions that convert an AST TypeName to a Type. + ///@{ + ///@name Factory functions + /// Factory functions that convert an AST @ref TypeName to a Type. static std::shared_ptr fromElementaryTypeName(Token::Value _typeToken); static std::shared_ptr fromUserDefinedTypeName(UserDefinedTypeName const& _typeName); static std::shared_ptr fromMapping(Mapping const& _typeName); + /// @} + /// Auto-detect the proper type for a literal static std::shared_ptr forLiteral(Literal const& _literal); virtual Category getCategory() const = 0; @@ -68,6 +73,7 @@ public: virtual bytes literalToBigEndian(Literal const&) const { return NullBytes; } }; +/// Any kind of integer type including hash and address. class IntegerType: public Type { public: @@ -101,6 +107,7 @@ private: Modifier m_modifier; }; +/// The boolean type. class BoolType: public Type { public: @@ -119,6 +126,7 @@ public: virtual bytes literalToBigEndian(Literal const& _literal) const override; }; +/// The type of a contract instance, there is one distinct type for each contract definition. class ContractType: public Type { public: @@ -133,6 +141,7 @@ private: ContractDefinition const& m_contract; }; +/// The type of a struct instance, there is one distinct type per struct definition. class StructType: public Type { public: @@ -151,6 +160,7 @@ private: StructDefinition const& m_struct; }; +/// The type of a function, there is one distinct type per function definition. class FunctionType: public Type { public: @@ -167,6 +177,7 @@ private: FunctionDefinition const& m_function; }; +/// The type of a mapping, there is one distinct type per key/value type pair. class MappingType: public Type { public: @@ -181,7 +192,8 @@ private: std::shared_ptr m_valueType; }; -//@todo should be changed into "empty anonymous struct" +/// The void type, can only be implicitly used as the type that is returned by functions without +/// return parameters. class VoidType: public Type { public: @@ -191,6 +203,8 @@ public: virtual std::string toString() const override { return "void"; } }; +/// The type of a type reference. The type of "uint32" when used in "a = uint32(2)" is an example +/// of a TypeType. class TypeType: public Type { public: From 2c5b1c52623741092ebd168ccf185ffdc98c3af7 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 22 Oct 2014 20:35:35 +0200 Subject: [PATCH 03/36] Documentation for AST, Parser, Scanner and other classes. --- libsolidity/AST.h | 76 ++++++++++++++++++++++++++++++++------ libsolidity/ASTPrinter.cpp | 2 +- libsolidity/Compiler.h | 4 +- libsolidity/Parser.h | 13 ++++--- libsolidity/Scanner.h | 34 +++++++++-------- 5 files changed, 93 insertions(+), 36 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index a55f58c16..db6637aea 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -40,6 +40,10 @@ namespace solidity class ASTVisitor; + +/// The root (abstract) class of the AST inheritance tree. +/// It is possible to traverse all direct and indirect children of an AST node by calling +/// accept, providing an ASTVisitor. class ASTNode: private boost::noncopyable { public: @@ -55,6 +59,7 @@ public: element->accept(_visitor); } + /// Returns the source code location of this node. Location const& getLocation() const { return m_location; } /// Creates a @ref TypeError exception and decorates it with the location of the node and @@ -62,6 +67,7 @@ public: TypeError createTypeError(std::string const& _description); ///@{ + ///@name equality operators /// Equality relies on the fact that nodes cannot be copied. bool operator==(ASTNode const& _other) const { return this == &_other; } bool operator!=(ASTNode const& _other) const { return !operator==(_other); } @@ -71,18 +77,23 @@ private: Location m_location; }; +/// Abstract AST class for a declaration (contract, function, struct, variable). class Declaration: public ASTNode { public: Declaration(Location const& _location, ASTPointer const& _name): ASTNode(_location), m_name(_name) {} + /// Returns the declared name. const ASTString& getName() const { return *m_name; } private: ASTPointer m_name; }; +/// Definition of a contract. This is the only AST nodes where child nodes are not visited in +/// document order. It first visits all struct declarations, then all variable declarations and +/// finally all function declarations. class ContractDefinition: public Declaration { public: @@ -122,9 +133,9 @@ private: std::vector> m_members; }; -/// Used as function parameter list and return list +/// Parameter list, used as function parameter list and return list. /// None of the parameters is allowed to contain mappings (not even recursively -/// inside structs) +/// inside structs), but (@todo) this is not yet enforced. class ParameterList: public ASTNode { public: @@ -167,6 +178,8 @@ private: ASTPointer m_body; }; +/// Declaration of a variable. This can be used in various places, e.g. in function parameter +/// lists, struct definitions and even function bodys. class VariableDeclaration: public Declaration { public: @@ -186,22 +199,26 @@ public: private: ASTPointer m_typeName; ///< can be empty ("var") - std::shared_ptr m_type; + std::shared_ptr m_type; ///< derived type, initially empty }; -/// types +/// Types /// @{ +/// Abstract base class of a type name, can be any built-in or user-defined type. class TypeName: public ASTNode { public: explicit TypeName(Location const& _location): ASTNode(_location) {} virtual void accept(ASTVisitor& _visitor) override; + /// Retrieve the element of the type hierarchy this node refers to. Can return an empty shared + /// pointer until the types have been resolved using the @ref NameAndTypeResolver. virtual std::shared_ptr toType() = 0; }; -/// any pre-defined type that is not a mapping +/// Any pre-defined type name represented by a single keyword, i.e. it excludes mappings, +/// contracts, functions, etc. class ElementaryTypeName: public TypeName { public: @@ -210,12 +227,14 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual std::shared_ptr toType() override { return Type::fromElementaryTypeName(m_type); } - Token::Value getType() const { return m_type; } + Token::Value getTypeName() const { return m_type; } private: Token::Value m_type; }; +/// Name referring to a user-defined type (i.e. a struct). +/// @todo some changes are necessary if this is also used to refer to contract types later class UserDefinedTypeName: public TypeName { public: @@ -234,6 +253,7 @@ private: StructDefinition* m_referencedStruct; }; +/// A mapping type. Its source form is "mapping('keyType' => 'valueType')" class Mapping: public TypeName { public: @@ -253,6 +273,8 @@ private: /// Statements /// @{ + +/// Abstract base class for statements. class Statement: public ASTNode { public: @@ -260,16 +282,17 @@ public: virtual void accept(ASTVisitor& _visitor) override; //! Check all type requirements, throws exception if some requirement is not met. - //! For expressions, this also returns the inferred type of the expression. For other - //! statements, returns the empty pointer. + //! This includes checking that operators are applicable to their arguments but also that + //! the number of function call arguments matches the number of formal parameters and so forth. virtual void checkTypeRequirements() = 0; protected: - //! Check that the inferred type for _expression is _expectedType or at least implicitly - //! convertible to _expectedType. If not, throw exception. + //! Helper function, check that the inferred type for @a _expression is @a _expectedType or at + //! least implicitly convertible to @a _expectedType. If not, throw exception. void expectType(Expression& _expression, Type const& _expectedType); }; +/// Brace-enclosed block containing zero or more statements. class Block: public Statement { public: @@ -283,6 +306,8 @@ private: std::vector> m_statements; }; +/// If-statement with an optional "else" part. Note that "else if" is modeled by having a new +/// if-statement as the false (else) body. class IfStatement: public Statement { public: @@ -299,6 +324,8 @@ private: ASTPointer m_falseBody; //< "else" part, optional }; +/// Statement in which a break statement is legal. +/// @todo actually check this requirement. class BreakableStatement: public Statement { public: @@ -349,9 +376,13 @@ public: private: ASTPointer m_expression; //< value to return, optional - ParameterList* m_returnParameters; //< extracted from the function declaration + /// Pointer to the parameter list of the function, filled by the @ref NameAndTypeResolver. + ParameterList* m_returnParameters; }; +/// Definition of a variable as a statement inside a function. It requires a type name (which can +/// also be "var") but the actual assignment can be missing. +/// Examples: var a = 2; uint256 a; class VariableDefinition: public Statement { public: @@ -363,13 +394,16 @@ public: private: ASTPointer m_variable; - ASTPointer m_value; ///< can be missing + ASTPointer m_value; ///< the assigned value, can be missing }; +/// An expression, i.e. something that has a value (which can also be of type "void" in case +/// of function calls). class Expression: public Statement { public: Expression(Location const& _location): Statement(_location) {} + std::shared_ptr const& getType() const { return m_type; } protected: @@ -382,6 +416,8 @@ protected: /// Expressions /// @{ +/// Assignment, can also be a compound assignment. +/// Examples: (a = 7 + 8) or (a *= 2) class Assignment: public Expression { public: @@ -402,6 +438,8 @@ private: ASTPointer m_rightHandSide; }; +/// Operation involving a unary operator, pre- or postfix. +/// Examples: ++i, delete x or !true class UnaryOperation: public Expression { public: @@ -421,6 +459,8 @@ private: bool m_isPrefix; }; +/// Operation involving a binary operator. +/// Examples: 1 + 2, true && false or 1 <= 4 class BinaryOperation: public Expression { public: @@ -451,6 +491,7 @@ public: Expression(_location), m_expression(_expression), m_arguments(_arguments) {} virtual void accept(ASTVisitor& _visitor) override; virtual void checkTypeRequirements() override; + /// Returns true if this is not an actual function call, but an explicit type conversion /// or constructor call. bool isTypeConversion() const; @@ -460,6 +501,7 @@ private: std::vector> m_arguments; }; +/// Access to a member of an object. Example: x.name class MemberAccess: public Expression { public: @@ -475,6 +517,7 @@ private: ASTPointer m_memberName; }; +/// Index access to an array. Example: a[2] class IndexAccess: public Expression { public: @@ -489,12 +532,15 @@ private: ASTPointer m_index; }; +/// Primary expression, i.e. an expression that do not be divided any further like a literal or +/// a variable reference. class PrimaryExpression: public Expression { public: PrimaryExpression(Location const& _location): Expression(_location) {} }; +/// An identifier, i.e. a reference to a declaration by name like a variable or function. class Identifier: public PrimaryExpression { public: @@ -504,6 +550,7 @@ public: virtual void checkTypeRequirements() override; ASTString const& getName() const { return *m_name; } + void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } Declaration* getReferencedDeclaration() { return m_referencedDeclaration; } @@ -514,6 +561,9 @@ private: Declaration* m_referencedDeclaration; }; +/// An elementary type name expression is used in expressions like "a = uint32(2)" to change the +/// type of an expression explicitly. Here, "uint32" is the elementary type name expression and +/// "uint32(2)" is a @ref FunctionCall. class ElementaryTypeNameExpression: public PrimaryExpression { public: @@ -528,6 +578,7 @@ private: Token::Value m_typeToken; }; +/// A literal string or number. @see Type::literalToBigEndian is used to actually parse its value. class Literal: public PrimaryExpression { public: @@ -537,6 +588,7 @@ public: virtual void checkTypeRequirements() override; Token::Value getToken() const { return m_token; } + /// @returns the non-parsed value of the literal ASTString const& getValue() const { return *m_value; } private: diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 44245ed46..b933e7caa 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -87,7 +87,7 @@ bool ASTPrinter::visit(TypeName& _node) bool ASTPrinter::visit(ElementaryTypeName& _node) { - writeLine(std::string("ElementaryTypeName ") + Token::toString(_node.getType())); + writeLine(std::string("ElementaryTypeName ") + Token::toString(_node.getTypeName())); printSourcePart(_node); return goDeeper(); } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index bddc4bef3..ac5e10ec9 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -110,8 +110,8 @@ private: /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. void cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType); - /// Append code for various operator types - /// @{ + ///@{ + ///@name Append code for various operator types void appendAndOrOperatorCode(BinaryOperation& _binaryOperation); void appendCompareOperatorCode(Token::Value _operator, Type const& _type); void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type); diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 14338dc28..eabc22746 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -44,8 +44,8 @@ private: /// End position of the current token int getEndPosition() const; - /// Parsing functions for the AST nodes - /// @{ + ///@{ + ///@name Parsing functions for the AST nodes ASTPointer parseContractDefinition(); ASTPointer parseFunctionDefinition(bool _isPublic); ASTPointer parseStructDefinition(); @@ -64,16 +64,17 @@ private: ASTPointer parseLeftHandSideExpression(); ASTPointer parsePrimaryExpression(); std::vector> parseFunctionCallArguments(); - /// @} + ///@} + + ///@{ + ///@name Helper functions - /// Helper functions - /// @{ /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); Token::Value expectAssignmentOperator(); ASTPointer expectIdentifierToken(); ASTPointer getLiteralAndAdvance(); - /// @} + ///@} /// Creates a @ref ParserError exception and annotates it with the current position and the /// given @a _description. diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index adae10dca..0cf87f6ad 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -81,12 +81,13 @@ public: char advanceAndGet(); char rollback(size_t _amount); + ///@{ + ///@name Error printing helper functions /// Functions that help pretty-printing parse errors /// Do only use in error cases, they are quite expensive. - /// @{ std::string getLineAtPosition(int _position) const; std::tuple translatePositionToLineColumn(int _position) const; - /// @} + ///@} private: std::string m_source; @@ -119,29 +120,31 @@ public: /// Returns the next token and advances input. Token::Value next(); - /// Information about the current token - /// @{ + ///@{ + ///@name Information about the current token /// Returns the current token Token::Value getCurrentToken() { return m_current_token.token; } Location getCurrentLocation() const { return m_current_token.location; } const std::string& getCurrentLiteral() const { return m_current_token.literal; } - /// @} + ///@} + + ///@{ + ///@name Information about the next token - /// Information about the next token - /// @{ /// Returns the next token without advancing input. Token::Value peekNextToken() const { return m_next_token.token; } Location peekLocation() const { return m_next_token.location; } const std::string& peekLiteral() const { return m_next_token.literal; } - /// @} + ///@} - /// Functions that help pretty-printing parse errors. + ///@{ + ///@name Error printing helper functions + /// Functions that help pretty-printing parse errors /// Do only use in error cases, they are quite expensive. - /// @{ std::string getLineAtPosition(int _position) const { return m_source.getLineAtPosition(_position); } std::tuple translatePositionToLineColumn(int _position) const { return m_source.translatePositionToLineColumn(_position); } - /// @} + ///@} private: // Used for the current and look-ahead token. @@ -152,13 +155,13 @@ private: std::string literal; }; - /// Literal buffer support - /// @{ + ///@{ + ///@name Literal buffer support inline void startNewLiteral() { m_next_token.literal.clear(); } inline void addLiteralChar(char c) { m_next_token.literal.push_back(c); } inline void dropLiteral() { m_next_token.literal.clear(); } inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } - /// @} + ///@} bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); } void rollback(int _amount) { m_char = m_source.rollback(_amount); } @@ -169,9 +172,10 @@ private: bool scanHexNumber(char& o_scannedNumber, int _expectedLength); - // Scans a single JavaScript token. + /// Scans a single JavaScript token. void scanToken(); + /// Skips all whitespace and @returns true if something was skipped. bool skipWhitespace(); Token::Value skipSingleLineComment(); Token::Value skipMultiLineComment(); From 62ca0b2b43f4130fa1ad494e40899b81a5b921a5 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 18:32:15 +0200 Subject: [PATCH 04/36] Replace BOOST_ASSERT by assert. --- libsolidity/AST.cpp | 16 ++++++++-------- libsolidity/NameAndTypeResolver.cpp | 11 +++++------ libsolidity/Scanner.cpp | 16 ++++++++-------- libsolidity/Scanner.h | 2 -- libsolidity/Token.h | 19 +++++++++---------- libsolidity/Types.cpp | 7 ++++--- libsolidity/Types.h | 1 - 7 files changed, 34 insertions(+), 38 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 414de9b2b..49bb071a0 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -291,7 +291,7 @@ void Break::checkTypeRequirements() void Return::checkTypeRequirements() { - BOOST_ASSERT(m_returnParameters); + assert(m_returnParameters); if (m_returnParameters->getParameters().size() != 1) BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " "than in returns declaration.")); @@ -357,7 +357,7 @@ void BinaryOperation::checkTypeRequirements() m_type = std::make_shared(); else { - BOOST_ASSERT(Token::isBinaryOp(m_operator)); + assert(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); @@ -374,7 +374,7 @@ void FunctionCall::checkTypeRequirements() if (isTypeConversion()) { TypeType const* type = dynamic_cast(expressionType); - BOOST_ASSERT(type); + assert(type); //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) @@ -390,7 +390,7 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters FunctionType const* function = dynamic_cast(expressionType); - BOOST_ASSERT(function); + assert(function); FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) @@ -414,19 +414,19 @@ bool FunctionCall::isTypeConversion() const void MemberAccess::checkTypeRequirements() { - BOOST_ASSERT(false); // not yet implemented + assert(false); // not yet implemented // m_type = ; } void IndexAccess::checkTypeRequirements() { - BOOST_ASSERT(false); // not yet implemented + assert(false); // not yet implemented // m_type = ; } void Identifier::checkTypeRequirements() { - BOOST_ASSERT(m_referencedDeclaration); + assert(m_referencedDeclaration); //@todo these dynamic casts here are not really nice... // is i useful to have an AST visitor here? // or can this already be done in NameAndTypeResolver? @@ -467,7 +467,7 @@ void Identifier::checkTypeRequirements() m_type = std::make_shared(std::make_shared(*contractDef)); return; } - BOOST_ASSERT(false); // declaration reference of unknown/forbidden type + assert(false); // declaration reference of unknown/forbidden type } void ElementaryTypeNameExpression::checkTypeRequirements() diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 0f34eb4c5..edd946df8 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -20,11 +20,10 @@ * Parser part that determines the declarations corresponding to names and the types of expressions. */ +#include #include - #include #include -#include namespace dev { @@ -123,19 +122,19 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) std::map::iterator iter; bool newlyAdded; std::tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); - BOOST_ASSERT(newlyAdded); + assert(newlyAdded); m_currentScope = &iter->second; } void DeclarationRegistrationHelper::closeCurrentScope() { - BOOST_ASSERT(m_currentScope); + assert(m_currentScope); m_currentScope = m_currentScope->getEnclosingScope(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - BOOST_ASSERT(m_currentScope); + assert(m_currentScope); if (!m_currentScope->registerDeclaration(_declaration)) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) << errinfo_comment("Identifier already declared.")); @@ -162,7 +161,7 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) bool ReferencesResolver::visit(Return& _return) { - BOOST_ASSERT(m_returnParameters); + assert(m_returnParameters); _return.setFunctionReturnParameters(*m_returnParameters); return true; } diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 35da248a4..649054356 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -50,9 +50,9 @@ * Solidity scanner. */ +#include #include #include - #include namespace dev @@ -118,7 +118,7 @@ void Scanner::reset(CharStream const& _source) bool Scanner::scanHexNumber(char& o_scannedNumber, int _expectedLength) { - BOOST_ASSERT(_expectedLength <= 4); // prevent overflow + assert(_expectedLength <= 4); // prevent overflow char x = 0; for (int i = 0; i < _expectedLength; i++) { @@ -178,7 +178,7 @@ Token::Value Scanner::skipSingleLineComment() Token::Value Scanner::skipMultiLineComment() { - BOOST_ASSERT(m_char == '*'); + assert(m_char == '*'); advance(); while (!isSourcePastEndOfInput()) { @@ -471,7 +471,7 @@ void Scanner::scanDecimalDigits() Token::Value Scanner::scanNumber(bool _periodSeen) { - BOOST_ASSERT(IsDecimalDigit(m_char)); // the first digit of the number or the fraction + assert(IsDecimalDigit(m_char)); // the first digit of the number or the fraction enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; LiteralScope literal(this); if (_periodSeen) @@ -513,7 +513,7 @@ Token::Value Scanner::scanNumber(bool _periodSeen) // scan exponent, if any if (m_char == 'e' || m_char == 'E') { - BOOST_ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number + assert(kind != HEX); // 'e'/'E' must be scanned as part of the hex number if (kind != DECIMAL) return Token::ILLEGAL; // scan exponent addLiteralCharAndAdvance(); @@ -609,7 +609,7 @@ Token::Value Scanner::scanNumber(bool _periodSeen) static Token::Value KeywordOrIdentifierToken(std::string const& input) { - BOOST_ASSERT(!input.empty()); + assert(!input.empty()); int const kMinLength = 2; int const kMaxLength = 10; if (input.size() < kMinLength || input.size() > kMaxLength) @@ -637,7 +637,7 @@ case ch: Token::Value Scanner::scanIdentifierOrKeyword() { - BOOST_ASSERT(IsIdentifierStart(m_char)); + assert(IsIdentifierStart(m_char)); LiteralScope literal(this); addLiteralCharAndAdvance(); // Scan the rest of the identifier characters. @@ -659,7 +659,7 @@ char CharStream::advanceAndGet() char CharStream::rollback(size_t _amount) { - BOOST_ASSERT(m_pos >= _amount); + assert(m_pos >= _amount); m_pos -= _amount; return get(); } diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 0cf87f6ad..fbaba9ed6 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -52,8 +52,6 @@ #pragma once -#include - #include #include #include diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 7949d2c65..c54f387c7 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -42,8 +42,7 @@ #pragma once -#include - +#include #include #include @@ -225,7 +224,7 @@ public: // (e.g. "LT" for the token LT). static char const* getName(Value tok) { - BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned + assert(tok < NUM_TOKENS); // tok is unsigned return m_name[tok]; } @@ -252,7 +251,7 @@ public: static Value negateCompareOp(Value op) { - BOOST_ASSERT(isArithmeticCompareOp(op)); + assert(isArithmeticCompareOp(op)); switch (op) { case EQ: @@ -268,14 +267,14 @@ public: case GTE: return LT; default: - BOOST_ASSERT(false); // should not get here + assert(false); // should not get here return op; } } static Value reverseCompareOp(Value op) { - BOOST_ASSERT(isArithmeticCompareOp(op)); + assert(isArithmeticCompareOp(op)); switch (op) { case EQ: @@ -291,14 +290,14 @@ public: case GTE: return LTE; default: - BOOST_ASSERT(false); // should not get here + assert(false); // should not get here return op; } } static Value AssignmentToBinaryOp(Value op) { - BOOST_ASSERT(isAssignmentOp(op) && op != ASSIGN); + assert(isAssignmentOp(op) && op != ASSIGN); return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR)); } @@ -312,7 +311,7 @@ public: // have a (unique) string (e.g. an IDENTIFIER). static char const* toString(Value tok) { - BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. + assert(tok < NUM_TOKENS); // tok is unsigned. return m_string[tok]; } @@ -320,7 +319,7 @@ public: // operators; returns 0 otherwise. static int precedence(Value tok) { - BOOST_ASSERT(tok < NUM_TOKENS); // tok is unsigned. + assert(tok < NUM_TOKENS); // tok is unsigned. return m_precedence[tok]; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index f0307a7cd..cf901e64b 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -20,6 +20,7 @@ * Solidity data types */ +#include #include #include #include @@ -51,7 +52,7 @@ std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) else if (_typeToken == Token::BOOL) return std::make_shared(); else - BOOST_ASSERT(false); // @todo add other tyes + assert(false); // @todo add other tyes } std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) @@ -61,7 +62,7 @@ std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _ std::shared_ptr Type::fromMapping(Mapping const&) { - BOOST_ASSERT(false); //@todo not yet implemented + assert(false); //@todo not yet implemented return std::shared_ptr(); } @@ -92,7 +93,7 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): { if (isAddress()) _bits = 160; - BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0); + assert(_bits > 0 && _bits <= 256 && _bits % 8 == 0); } bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 40bc44876..4d56b5abb 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include From fd7fc4293ebe00abf8c3d9239eb6b61b9f568ef5 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 19:06:30 +0200 Subject: [PATCH 05/36] Removed std:: where it made sense. --- libsolidity/AST.cpp | 20 +++++++------ libsolidity/ASTPrinter.cpp | 30 +++++++++++--------- libsolidity/NameAndTypeResolver.cpp | 8 ++++-- libsolidity/Scanner.cpp | 29 ++++++++++--------- libsolidity/SourceReferenceFormatter.cpp | 36 +++++++++++++----------- 5 files changed, 66 insertions(+), 57 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 49bb071a0..0b635339d 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -26,6 +26,8 @@ #include #include +using namespace std; + namespace dev { namespace solidity @@ -248,7 +250,7 @@ void Literal::accept(ASTVisitor& _visitor) _visitor.endVisit(*this); } -TypeError ASTNode::createTypeError(std::string const& _description) +TypeError ASTNode::createTypeError(string const& _description) { return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); } @@ -263,7 +265,7 @@ void Statement::expectType(Expression& _expression, const Type& _expectedType) void Block::checkTypeRequirements() { - for (std::shared_ptr const& statement: m_statements) + for (shared_ptr const& statement: m_statements) statement->checkTypeRequirements(); } @@ -354,7 +356,7 @@ void BinaryOperation::checkTypeRequirements() else BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); if (Token::isCompareOp(m_operator)) - m_type = std::make_shared(); + m_type = make_shared(); else { assert(Token::isBinaryOp(m_operator)); @@ -392,7 +394,7 @@ void FunctionCall::checkTypeRequirements() FunctionType const* function = dynamic_cast(expressionType); assert(function); FunctionDefinition const& fun = function->getFunction(); - std::vector> const& parameters = fun.getParameters(); + vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); for (size_t i = 0; i < m_arguments.size(); ++i) @@ -401,7 +403,7 @@ void FunctionCall::checkTypeRequirements() // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs if (fun.getReturnParameterList()->getParameters().empty()) - m_type = std::make_shared(); + m_type = make_shared(); else m_type = fun.getReturnParameterList()->getParameters().front()->getType(); } @@ -449,7 +451,7 @@ void Identifier::checkTypeRequirements() if (structDef) { // note that we do not have a struct type here - m_type = std::make_shared(std::make_shared(*structDef)); + m_type = make_shared(make_shared(*structDef)); return; } FunctionDefinition* functionDef = dynamic_cast(m_referencedDeclaration); @@ -458,13 +460,13 @@ void Identifier::checkTypeRequirements() // a function reference is not a TypeType, because calling a TypeType converts to the type. // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type // conversion. - m_type = std::make_shared(*functionDef); + m_type = make_shared(*functionDef); return; } ContractDefinition* contractDef = dynamic_cast(m_referencedDeclaration); if (contractDef) { - m_type = std::make_shared(std::make_shared(*contractDef)); + m_type = make_shared(make_shared(*contractDef)); return; } assert(false); // declaration reference of unknown/forbidden type @@ -472,7 +474,7 @@ void Identifier::checkTypeRequirements() void ElementaryTypeNameExpression::checkTypeRequirements() { - m_type = std::make_shared(Type::fromElementaryTypeName(m_typeToken)); + m_type = make_shared(Type::fromElementaryTypeName(m_typeToken)); } void Literal::checkTypeRequirements() diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index b933e7caa..9b545ac9e 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -23,17 +23,19 @@ #include #include +using namespace std; + namespace dev { namespace solidity { -ASTPrinter::ASTPrinter(ASTPointer const& _ast, std::string const& _source): +ASTPrinter::ASTPrinter(ASTPointer const& _ast, string const& _source): m_indentation(0), m_source(_source), m_ast(_ast) { } -void ASTPrinter::print(std::ostream& _stream) +void ASTPrinter::print(ostream& _stream) { m_ostream = &_stream; m_ast->accept(*this); @@ -87,7 +89,7 @@ bool ASTPrinter::visit(TypeName& _node) bool ASTPrinter::visit(ElementaryTypeName& _node) { - writeLine(std::string("ElementaryTypeName ") + Token::toString(_node.getTypeName())); + writeLine(string("ElementaryTypeName ") + Token::toString(_node.getTypeName())); printSourcePart(_node); return goDeeper(); } @@ -179,7 +181,7 @@ bool ASTPrinter::visit(Expression& _node) bool ASTPrinter::visit(Assignment& _node) { - writeLine(std::string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); + writeLine(string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); printType(_node); printSourcePart(_node); return goDeeper(); @@ -187,7 +189,7 @@ bool ASTPrinter::visit(Assignment& _node) bool ASTPrinter::visit(UnaryOperation& _node) { - writeLine(std::string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + + writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + ") " + Token::toString(_node.getOperator())); printType(_node); printSourcePart(_node); @@ -196,7 +198,7 @@ bool ASTPrinter::visit(UnaryOperation& _node) bool ASTPrinter::visit(BinaryOperation& _node) { - writeLine(std::string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); + writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); printType(_node); printSourcePart(_node); return goDeeper(); @@ -236,7 +238,7 @@ bool ASTPrinter::visit(PrimaryExpression& _node) bool ASTPrinter::visit(Identifier& _node) { - writeLine(std::string("Identifier ") + _node.getName()); + writeLine(string("Identifier ") + _node.getName()); printType(_node); printSourcePart(_node); return goDeeper(); @@ -244,7 +246,7 @@ bool ASTPrinter::visit(Identifier& _node) bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) { - writeLine(std::string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); + writeLine(string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); printType(_node); printSourcePart(_node); return goDeeper(); @@ -255,7 +257,7 @@ bool ASTPrinter::visit(Literal& _node) char const* tokenString = Token::toString(_node.getToken()); if (!tokenString) tokenString = "[no token]"; - writeLine(std::string("Literal, token: ") + tokenString + " value: " + _node.getValue()); + writeLine(string("Literal, token: ") + tokenString + " value: " + _node.getValue()); printType(_node); printSourcePart(_node); return goDeeper(); @@ -417,7 +419,7 @@ void ASTPrinter::printSourcePart(ASTNode const& _node) { Location const& location(_node.getLocation()); *m_ostream << getIndentation() << " Source: |" - << m_source.substr(location.start, location.end - location.start) << "|" << std::endl; + << m_source.substr(location.start, location.end - location.start) << "|" << endl; } } @@ -429,14 +431,14 @@ void ASTPrinter::printType(Expression const& _expression) *m_ostream << getIndentation() << " Type unknown.\n"; } -std::string ASTPrinter::getIndentation() const +string ASTPrinter::getIndentation() const { - return std::string(m_indentation * 2, ' '); + return string(m_indentation * 2, ' '); } -void ASTPrinter::writeLine(std::string const& _line) +void ASTPrinter::writeLine(string const& _line) { - *m_ostream << getIndentation() << _line << std::endl; + *m_ostream << getIndentation() << _line << endl; } } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index edd946df8..9626ca848 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -25,6 +25,8 @@ #include #include +using namespace std; + namespace dev { namespace solidity @@ -67,7 +69,7 @@ Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name } -DeclarationRegistrationHelper::DeclarationRegistrationHelper(std::map& _scopes, +DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes, ASTNode& _astRoot): m_scopes(_scopes), m_currentScope(&m_scopes[nullptr]) { @@ -119,9 +121,9 @@ void DeclarationRegistrationHelper::endVisit(VariableDeclaration&) void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) { - std::map::iterator iter; + map::iterator iter; bool newlyAdded; - std::tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); + tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); assert(newlyAdded); m_currentScope = &iter->second; } diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 649054356..3148de52e 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -55,6 +55,8 @@ #include #include +using namespace std; + namespace dev { namespace solidity @@ -607,7 +609,7 @@ Token::Value Scanner::scanNumber(bool _periodSeen) KEYWORD("while", Token::WHILE) \ -static Token::Value KeywordOrIdentifierToken(std::string const& input) +static Token::Value KeywordOrIdentifierToken(string const& input) { assert(!input.empty()); int const kMinLength = 2; @@ -664,37 +666,36 @@ char CharStream::rollback(size_t _amount) return get(); } -std::string CharStream::getLineAtPosition(int _position) const +string CharStream::getLineAtPosition(int _position) const { // if _position points to \n, it returns the line before the \n - using size_type = std::string::size_type; - size_type searchStart = std::min(m_source.size(), _position); + using size_type = string::size_type; + size_type searchStart = min(m_source.size(), _position); if (searchStart > 0) searchStart--; size_type lineStart = m_source.rfind('\n', searchStart); - if (lineStart == std::string::npos) + if (lineStart == string::npos) lineStart = 0; else lineStart++; - return m_source.substr(lineStart, - std::min(m_source.find('\n', lineStart), - m_source.size()) - lineStart); + return m_source.substr(lineStart, min(m_source.find('\n', lineStart), + m_source.size()) - lineStart); } -std::tuple CharStream::translatePositionToLineColumn(int _position) const +tuple CharStream::translatePositionToLineColumn(int _position) const { - using size_type = std::string::size_type; - size_type searchPosition = std::min(m_source.size(), _position); - int lineNumber = std::count(m_source.begin(), m_source.begin() + searchPosition, '\n'); + using size_type = string::size_type; + size_type searchPosition = min(m_source.size(), _position); + int lineNumber = count(m_source.begin(), m_source.begin() + searchPosition, '\n'); size_type lineStart; if (searchPosition == 0) lineStart = 0; else { lineStart = m_source.rfind('\n', searchPosition - 1); - lineStart = lineStart == std::string::npos ? 0 : lineStart + 1; + lineStart = lineStart == string::npos ? 0 : lineStart + 1; } - return std::tuple(lineNumber, searchPosition - lineStart); + return tuple(lineNumber, searchPosition - lineStart); } diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index b270342c9..d3f2152a6 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -24,57 +24,59 @@ #include #include +using namespace std; + namespace dev { namespace solidity { -void SourceReferenceFormatter::printSourceLocation(std::ostream& _stream, +void SourceReferenceFormatter::printSourceLocation(ostream& _stream, Location const& _location, Scanner const& _scanner) { int startLine; int startColumn; - std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); + tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); _stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; int endLine; int endColumn; - std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); + tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); if (startLine == endLine) { - _stream << _scanner.getLineAtPosition(_location.start) << std::endl - << std::string(startColumn, ' ') << "^"; + _stream << _scanner.getLineAtPosition(_location.start) << endl + << string(startColumn, ' ') << "^"; if (endColumn > startColumn + 2) - _stream << std::string(endColumn - startColumn - 2, '-'); + _stream << string(endColumn - startColumn - 2, '-'); if (endColumn > startColumn + 1) _stream << "^"; - _stream << std::endl; + _stream << endl; } else - _stream << _scanner.getLineAtPosition(_location.start) << std::endl - << std::string(startColumn, ' ') << "^\n" + _stream << _scanner.getLineAtPosition(_location.start) << endl + << string(startColumn, ' ') << "^\n" << "Spanning multiple lines.\n"; } -void SourceReferenceFormatter::printSourcePosition(std::ostream& _stream, +void SourceReferenceFormatter::printSourcePosition(ostream& _stream, int _position, const Scanner& _scanner) { int line; int column; - std::tie(line, column) = _scanner.translatePositionToLineColumn(_position); - _stream << "at line " << (line + 1) << ", column " << (column + 1) << std::endl - << _scanner.getLineAtPosition(_position) << std::endl - << std::string(column, ' ') << "^" << std::endl; + tie(line, column) = _scanner.translatePositionToLineColumn(_position); + _stream << "at line " << (line + 1) << ", column " << (column + 1) << endl + << _scanner.getLineAtPosition(_position) << endl + << string(column, ' ') << "^" << endl; } -void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, +void SourceReferenceFormatter::printExceptionInformation(ostream& _stream, Exception const& _exception, - std::string const& _name, + string const& _name, Scanner const& _scanner) { _stream << _name; - if (std::string const* description = boost::get_error_info(_exception)) + if (string const* description = boost::get_error_info(_exception)) _stream << ": " << *description; if (int const* position = boost::get_error_info(_exception)) From a72098d54182f8cb5f9e0db975a0f778f81cef0b Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 20:01:20 +0200 Subject: [PATCH 06/36] Removed some more boost asserts. --- libsolidity/Compiler.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 319f9b1cf..acb0a5cc7 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -20,7 +20,7 @@ * Solidity AST to EVM bytecode compiler. */ -#include +#include #include #include #include @@ -32,14 +32,14 @@ namespace solidity { void CompilerContext::setLabelPosition(uint32_t _label, uint32_t _position) { - BOOST_ASSERT(m_labelPositions.find(_label) == m_labelPositions.end()); + assert(m_labelPositions.find(_label) == m_labelPositions.end()); m_labelPositions[_label] = _position; } uint32_t CompilerContext::getLabelPosition(uint32_t _label) const { auto iter = m_labelPositions.find(_label); - BOOST_ASSERT(iter != m_labelPositions.end()); + assert(iter != m_labelPositions.end()); return iter->second; } @@ -152,7 +152,7 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) append(eth::Instruction::NEG); break; default: - BOOST_ASSERT(false); // invalid operation + assert(false); // invalid operation } } @@ -174,7 +174,7 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) rightExpression.accept(*this); // the types to compare have to be the same, but the resulting type is always bool - BOOST_ASSERT(*leftExpression.getType() == *rightExpression.getType()); + assert(*leftExpression.getType() == *rightExpression.getType()); appendCompareOperatorCode(op, *leftExpression.getType()); } else @@ -226,14 +226,14 @@ void ExpressionCompiler::endVisit(Literal& _literal) case Type::Category::BOOL: { bytes value = _literal.getType()->literalToBigEndian(_literal); - BOOST_ASSERT(value.size() <= 32); - BOOST_ASSERT(!value.empty()); + assert(value.size() <= 32); + assert(!value.empty()); append(static_cast(eth::Instruction::PUSH1) + static_cast(value.size() - 1)); append(value); break; } default: - BOOST_ASSERT(false); // @todo + assert(false); // @todo } } @@ -255,15 +255,15 @@ void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(const Type& _typeOnStack, { // If we get here, there is either an implementation missing to clean higher oder bits // for non-integer types that are explicitly convertible or we got here in error. - BOOST_ASSERT(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); - BOOST_ASSERT(false); // these types should not be convertible. + assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType)); + assert(false); // these types should not be convertible. } } void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) { Token::Value const op = _binaryOperation.getOperator(); - BOOST_ASSERT(op == Token::OR || op == Token::AND); + assert(op == Token::OR || op == Token::AND); _binaryOperation.getLeftExpression().accept(*this); append(eth::Instruction::DUP1); @@ -285,7 +285,7 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type else { IntegerType const* type = dynamic_cast(&_type); - BOOST_ASSERT(type != nullptr); + assert(type); bool const isSigned = type->isSigned(); // note that EVM opcodes compare like "stack[0] < stack[1]", @@ -307,7 +307,7 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT); break; default: - BOOST_ASSERT(false); + assert(false); } } } @@ -321,13 +321,13 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator else if (Token::isShiftOp(_operator)) appendShiftOperatorCode(_operator); else - BOOST_ASSERT(false); // unknown binary operator + assert(false); // unknown binary operator } void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) { IntegerType const* type = dynamic_cast(&_type); - BOOST_ASSERT(type != nullptr); + assert(type); bool const isSigned = type->isSigned(); switch (_operator) @@ -349,7 +349,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty append(isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); break; default: - BOOST_ASSERT(false); + assert(false); } } @@ -367,7 +367,7 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) append(eth::Instruction::XOR); break; default: - BOOST_ASSERT(false); + assert(false); } } @@ -376,13 +376,13 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) switch (_operator) { case Token::SHL: - BOOST_ASSERT(false); //@todo + assert(false); //@todo break; case Token::SAR: - BOOST_ASSERT(false); //@todo + assert(false); //@todo break; default: - BOOST_ASSERT(false); + assert(false); } } From d7278b3d3402a22c148fefee7bef42b61e29eb5f Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 28 Oct 2014 09:25:01 +0100 Subject: [PATCH 07/36] Stylistic corrections. --- libsolidity/AST.h | 22 +++++++++++----------- libsolidity/Compiler.cpp | 10 +++------- libsolidity/NameAndTypeResolver.h | 16 ++++++++-------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index db6637aea..5c975ee4b 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -191,8 +191,8 @@ public: bool isTypeGivenExplicitly() const { return bool(m_typeName); } TypeName* getTypeName() const { return m_typeName.get(); } - //! Returns the declared or inferred type. Can be an empty pointer if no type was explicitly - //! declared and there is no assignment to the variable that fixes the type. + /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly + /// declared and there is no assignment to the variable that fixes the type. std::shared_ptr const& getType() const { return m_type; } void setType(std::shared_ptr const& _type) { m_type = _type; } @@ -281,14 +281,14 @@ public: explicit Statement(Location const& _location): ASTNode(_location) {} virtual void accept(ASTVisitor& _visitor) override; - //! 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 - //! the number of function call arguments matches the number of formal parameters and so forth. + /// 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 + /// the number of function call arguments matches the number of formal parameters and so forth. virtual void checkTypeRequirements() = 0; protected: - //! Helper function, check that the inferred type for @a _expression is @a _expectedType or at - //! least implicitly convertible to @a _expectedType. If not, throw exception. + /// Helper function, check that the inferred type for @a _expression is @a _expectedType or at + /// least implicitly convertible to @a _expectedType. If not, throw exception. void expectType(Expression& _expression, Type const& _expectedType); }; @@ -407,7 +407,7 @@ public: std::shared_ptr const& getType() const { return m_type; } protected: - //! Inferred type of the expression, only filled after a call to checkTypeRequirements(). + /// Inferred type of the expression, only filled after a call to checkTypeRequirements(). std::shared_ptr m_type; }; @@ -532,8 +532,8 @@ private: ASTPointer m_index; }; -/// Primary expression, i.e. an expression that do not be divided any further like a literal or -/// a variable reference. +/// Primary expression, i.e. an expression that cannot be divided any further. Examples are literals +/// or variable references. class PrimaryExpression: public Expression { public: @@ -557,7 +557,7 @@ public: private: ASTPointer m_name; - //! Declaration the name refers to. + /// Declaration the name refers to. Declaration* m_referencedDeclaration; }; diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index acb0a5cc7..ef5680138 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -25,11 +25,9 @@ #include #include - namespace dev { namespace solidity { - void CompilerContext::setLabelPosition(uint32_t _label, uint32_t _position) { assert(m_labelPositions.find(_label) == m_labelPositions.end()); @@ -63,12 +61,10 @@ bytes ExpressionCompiler::getAssembledBytecode() const } for (AssemblyItem const& item: m_assemblyItems) - { if (item.getType() == AssemblyItem::Type::LABELREF) assembled.push_back(m_context.getLabelPosition(item.getLabel())); else assembled.push_back(item.getData()); - } return assembled; } @@ -203,17 +199,17 @@ void ExpressionCompiler::endVisit(FunctionCall& _functionCall) } } -void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) +void ExpressionCompiler::endVisit(MemberAccess&) { } -void ExpressionCompiler::endVisit(IndexAccess& _indexAccess) +void ExpressionCompiler::endVisit(IndexAccess&) { } -void ExpressionCompiler::endVisit(Identifier& _identifier) +void ExpressionCompiler::endVisit(Identifier&) { } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 7abcbb0c5..055835c4f 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -33,8 +33,8 @@ namespace dev namespace solidity { -//! Resolves name references, resolves all types and checks that all operations are valid for the -//! inferred types. An exception is throw on the first error. +/// Resolves name references, resolves all types and checks that all operations are valid for the +/// inferred types. An exception is throw on the first error. class NameAndTypeResolver: private boost::noncopyable { public: @@ -46,15 +46,15 @@ public: private: void reset(); - //! Maps nodes declaring a scope to scopes, i.e. ContractDefinition, FunctionDeclaration and - //! StructDefinition (@todo not yet implemented), where nullptr denotes the global scope. + /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition, FunctionDeclaration and + /// StructDefinition (@todo not yet implemented), where nullptr denotes the global scope. std::map m_scopes; Scope* m_currentScope; }; -//! Traverses the given AST upon construction and fills _scopes with all declarations inside the -//! AST. +/// Traverses the given AST upon construction and fills _scopes with all declarations inside the +/// AST. class DeclarationRegistrationHelper: private ASTVisitor { public: @@ -78,8 +78,8 @@ private: Scope* m_currentScope; }; -//! Resolves references to declarations (of variables and types) and also establishes the link -//! between a return statement and the return parameter list. +/// Resolves references to declarations (of variables and types) and also establishes the link +/// between a return statement and the return parameter list. class ReferencesResolver: private ASTVisitor { public: From 17f54705407ab95f8a0fdae5d41684de34b34b5c Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 28 Oct 2014 16:51:26 +0100 Subject: [PATCH 08/36] Asterisk-syntax for doxygen class documentation. --- libsolidity/AST.h | 140 ++++++++++++++++++++---------- libsolidity/ASTPrinter.h | 4 +- libsolidity/Compiler.h | 24 +++-- libsolidity/NameAndTypeResolver.h | 19 ++-- libsolidity/Scope.h | 6 +- libsolidity/Types.h | 40 ++++++--- solc/main.cpp | 4 +- 7 files changed, 162 insertions(+), 75 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 5c975ee4b..e66572800 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -41,9 +41,11 @@ namespace solidity class ASTVisitor; -/// The root (abstract) class of the AST inheritance tree. -/// It is possible to traverse all direct and indirect children of an AST node by calling -/// accept, providing an ASTVisitor. +/** + * The root (abstract) class of the AST inheritance tree. + * It is possible to traverse all direct and indirect children of an AST node by calling + * accept, providing an ASTVisitor. + */ class ASTNode: private boost::noncopyable { public: @@ -77,7 +79,9 @@ private: Location m_location; }; -/// Abstract AST class for a declaration (contract, function, struct, variable). +/** + * Abstract AST class for a declaration (contract, function, struct, variable). + */ class Declaration: public ASTNode { public: @@ -91,9 +95,11 @@ private: ASTPointer m_name; }; -/// Definition of a contract. This is the only AST nodes where child nodes are not visited in -/// document order. It first visits all struct declarations, then all variable declarations and -/// finally all function declarations. +/** + * Definition of a contract. This is the only AST nodes where child nodes are not visited in + * document order. It first visits all struct declarations, then all variable declarations and + * finally all function declarations. + */ class ContractDefinition: public Declaration { public: @@ -133,9 +139,11 @@ private: std::vector> m_members; }; -/// Parameter list, used as function parameter list and return list. -/// None of the parameters is allowed to contain mappings (not even recursively -/// inside structs), but (@todo) this is not yet enforced. +/** + * Parameter list, used as function parameter list and return list. + * None of the parameters is allowed to contain mappings (not even recursively + * inside structs), but (@todo) this is not yet enforced. + */ class ParameterList: public ASTNode { public: @@ -178,8 +186,10 @@ private: ASTPointer m_body; }; -/// Declaration of a variable. This can be used in various places, e.g. in function parameter -/// lists, struct definitions and even function bodys. +/** + * Declaration of a variable. This can be used in various places, e.g. in function parameter + * lists, struct definitions and even function bodys. + */ class VariableDeclaration: public Declaration { public: @@ -205,7 +215,9 @@ private: /// Types /// @{ -/// Abstract base class of a type name, can be any built-in or user-defined type. +/** + * Abstract base class of a type name, can be any built-in or user-defined type. + */ class TypeName: public ASTNode { public: @@ -217,8 +229,10 @@ public: virtual std::shared_ptr toType() = 0; }; -/// Any pre-defined type name represented by a single keyword, i.e. it excludes mappings, -/// contracts, functions, etc. +/** + * Any pre-defined type name represented by a single keyword, i.e. it excludes mappings, + * contracts, functions, etc. + */ class ElementaryTypeName: public TypeName { public: @@ -233,8 +247,10 @@ private: Token::Value m_type; }; -/// Name referring to a user-defined type (i.e. a struct). -/// @todo some changes are necessary if this is also used to refer to contract types later +/** + * Name referring to a user-defined type (i.e. a struct). + * @todo some changes are necessary if this is also used to refer to contract types later + */ class UserDefinedTypeName: public TypeName { public: @@ -253,7 +269,9 @@ private: StructDefinition* m_referencedStruct; }; -/// A mapping type. Its source form is "mapping('keyType' => 'valueType')" +/** + * A mapping type. Its source form is "mapping('keyType' => 'valueType')" + */ class Mapping: public TypeName { public: @@ -274,7 +292,9 @@ private: /// @{ -/// Abstract base class for statements. +/** + * Abstract base class for statements. + */ class Statement: public ASTNode { public: @@ -292,7 +312,9 @@ protected: void expectType(Expression& _expression, Type const& _expectedType); }; -/// Brace-enclosed block containing zero or more statements. +/** + * Brace-enclosed block containing zero or more statements. + */ class Block: public Statement { public: @@ -306,8 +328,10 @@ private: std::vector> m_statements; }; -/// If-statement with an optional "else" part. Note that "else if" is modeled by having a new -/// if-statement as the false (else) body. +/** + * If-statement with an optional "else" part. Note that "else if" is modeled by having a new + * if-statement as the false (else) body. + */ class IfStatement: public Statement { public: @@ -324,8 +348,10 @@ private: ASTPointer m_falseBody; //< "else" part, optional }; -/// Statement in which a break statement is legal. -/// @todo actually check this requirement. +/** + * Statement in which a break statement is legal. + * @todo actually check this requirement. + */ class BreakableStatement: public Statement { public: @@ -380,9 +406,11 @@ private: ParameterList* m_returnParameters; }; -/// Definition of a variable as a statement inside a function. It requires a type name (which can -/// also be "var") but the actual assignment can be missing. -/// Examples: var a = 2; uint256 a; +/** + * Definition of a variable as a statement inside a function. It requires a type name (which can + * also be "var") but the actual assignment can be missing. + * Examples: var a = 2; uint256 a; + */ class VariableDefinition: public Statement { public: @@ -397,8 +425,10 @@ private: ASTPointer m_value; ///< the assigned value, can be missing }; -/// An expression, i.e. something that has a value (which can also be of type "void" in case -/// of function calls). +/** + * An expression, i.e. something that has a value (which can also be of type "void" in case + * of function calls). + */ class Expression: public Statement { public: @@ -416,8 +446,10 @@ protected: /// Expressions /// @{ -/// Assignment, can also be a compound assignment. -/// Examples: (a = 7 + 8) or (a *= 2) +/** + * Assignment, can also be a compound assignment. + * Examples: (a = 7 + 8) or (a *= 2) + */ class Assignment: public Expression { public: @@ -438,8 +470,10 @@ private: ASTPointer m_rightHandSide; }; -/// Operation involving a unary operator, pre- or postfix. -/// Examples: ++i, delete x or !true +/** + * Operation involving a unary operator, pre- or postfix. + * Examples: ++i, delete x or !true + */ class UnaryOperation: public Expression { public: @@ -459,8 +493,10 @@ private: bool m_isPrefix; }; -/// Operation involving a binary operator. -/// Examples: 1 + 2, true && false or 1 <= 4 +/** + * Operation involving a binary operator. + * Examples: 1 + 2, true && false or 1 <= 4 + */ class BinaryOperation: public Expression { public: @@ -482,7 +518,9 @@ private: std::shared_ptr m_commonType; }; -/// Can be ordinary function call, type cast or struct construction. +/** + * Can be ordinary function call, type cast or struct construction. + */ class FunctionCall: public Expression { public: @@ -501,7 +539,9 @@ private: std::vector> m_arguments; }; -/// Access to a member of an object. Example: x.name +/** + * Access to a member of an object. Example: x.name + */ class MemberAccess: public Expression { public: @@ -517,7 +557,9 @@ private: ASTPointer m_memberName; }; -/// Index access to an array. Example: a[2] +/** + * Index access to an array. Example: a[2] + */ class IndexAccess: public Expression { public: @@ -532,15 +574,19 @@ private: ASTPointer m_index; }; -/// Primary expression, i.e. an expression that cannot be divided any further. Examples are literals -/// or variable references. +/** + * Primary expression, i.e. an expression that cannot be divided any further. Examples are literals + * or variable references. + */ class PrimaryExpression: public Expression { public: PrimaryExpression(Location const& _location): Expression(_location) {} }; -/// An identifier, i.e. a reference to a declaration by name like a variable or function. +/** + * An identifier, i.e. a reference to a declaration by name like a variable or function. + */ class Identifier: public PrimaryExpression { public: @@ -561,9 +607,11 @@ private: Declaration* m_referencedDeclaration; }; -/// An elementary type name expression is used in expressions like "a = uint32(2)" to change the -/// type of an expression explicitly. Here, "uint32" is the elementary type name expression and -/// "uint32(2)" is a @ref FunctionCall. +/** + * An elementary type name expression is used in expressions like "a = uint32(2)" to change the + * type of an expression explicitly. Here, "uint32" is the elementary type name expression and + * "uint32(2)" is a @ref FunctionCall. + */ class ElementaryTypeNameExpression: public PrimaryExpression { public: @@ -578,7 +626,9 @@ private: Token::Value m_typeToken; }; -/// A literal string or number. @see Type::literalToBigEndian is used to actually parse its value. +/** + * A literal string or number. @see Type::literalToBigEndian is used to actually parse its value. + */ class Literal: public PrimaryExpression { public: diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index 74e0837ff..97256c056 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -30,7 +30,9 @@ namespace dev namespace solidity { -/// Pretty-printer for the abstract syntax tree (the "pretty" is arguable) for debugging purposes. +/** + * Pretty-printer for the abstract syntax tree (the "pretty" is arguable) for debugging purposes. + */ class ASTPrinter: public ASTVisitor { public: diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index ac5e10ec9..1401e12e3 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -28,9 +28,11 @@ namespace dev { namespace solidity { -/// A single item of compiled code that can be assembled to a single byte value in the final -/// bytecode. Its main purpose is to inject jump labels and label references into the opcode stream, -/// which can be resolved in the final step. +/** + * A single item of compiled code that can be assembled to a single byte value in the final + * bytecode. Its main purpose is to inject jump labels and label references into the opcode stream, + * which can be resolved in the final step. + */ class AssemblyItem { public: @@ -64,9 +66,11 @@ private: using AssemblyItems = std::vector; -/// Context to be shared by all units that compile the same contract. Its current usage only -/// concerns dispensing unique jump label IDs and storing their actual positions in the bytecode -/// stream. +/** + * Context to be shared by all units that compile the same contract. Its current usage only + * concerns dispensing unique jump label IDs and storing their actual positions in the bytecode + * stream. + */ class CompilerContext { public: @@ -81,9 +85,11 @@ private: std::map m_labelPositions; }; -/// Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream -/// of EVM instructions. It needs a compiler context that is the same for the whole compilation -/// unit. +/** + * Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream + * of EVM instructions. It needs a compiler context that is the same for the whole compilation + * unit. + */ class ExpressionCompiler: public ASTVisitor { public: diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 055835c4f..bb7fcb98f 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -33,8 +33,11 @@ namespace dev namespace solidity { -/// Resolves name references, resolves all types and checks that all operations are valid for the -/// inferred types. An exception is throw on the first error. +/** + * Resolves name references, types and checks types of all expressions. + * Specifically, it checks that all operations are valid for the inferred types. + * An exception is throw on the first error. + */ class NameAndTypeResolver: private boost::noncopyable { public: @@ -53,8 +56,10 @@ private: Scope* m_currentScope; }; -/// Traverses the given AST upon construction and fills _scopes with all declarations inside the -/// AST. +/** + * Traverses the given AST upon construction and fills _scopes with all declarations inside the + * AST. + */ class DeclarationRegistrationHelper: private ASTVisitor { public: @@ -78,8 +83,10 @@ private: Scope* m_currentScope; }; -/// Resolves references to declarations (of variables and types) and also establishes the link -/// between a return statement and the return parameter list. +/** + * Resolves references to declarations (of variables and types) and also establishes the link + * between a return statement and the return parameter list. + */ class ReferencesResolver: private ASTVisitor { public: diff --git a/libsolidity/Scope.h b/libsolidity/Scope.h index 83b01f423..637c2d5ce 100644 --- a/libsolidity/Scope.h +++ b/libsolidity/Scope.h @@ -32,8 +32,10 @@ namespace dev namespace solidity { -/// Container that stores mappings betwee names and declarations. It also contains a link to the -/// enclosing scope. +/** + * Container that stores mappings betwee names and declarations. It also contains a link to the + * enclosing scope. + */ class Scope { public: diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 4d56b5abb..c9f6da574 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -36,7 +36,9 @@ namespace solidity // @todo realMxN, string, mapping -/// Abstract base class that forms the root of the type hierarchy. +/** + * Abstract base class that forms the root of the type hierarchy. + */ class Type: private boost::noncopyable { public: @@ -72,7 +74,9 @@ public: virtual bytes literalToBigEndian(Literal const&) const { return NullBytes; } }; -/// Any kind of integer type including hash and address. +/** + * Any kind of integer type including hash and address. + */ class IntegerType: public Type { public: @@ -106,7 +110,9 @@ private: Modifier m_modifier; }; -/// The boolean type. +/** + * The boolean type. + */ class BoolType: public Type { public: @@ -125,7 +131,9 @@ public: virtual bytes literalToBigEndian(Literal const& _literal) const override; }; -/// The type of a contract instance, there is one distinct type for each contract definition. +/** + * The type of a contract instance, there is one distinct type for each contract definition. + */ class ContractType: public Type { public: @@ -140,7 +148,9 @@ private: ContractDefinition const& m_contract; }; -/// The type of a struct instance, there is one distinct type per struct definition. +/** + * The type of a struct instance, there is one distinct type per struct definition. + */ class StructType: public Type { public: @@ -159,7 +169,9 @@ private: StructDefinition const& m_struct; }; -/// The type of a function, there is one distinct type per function definition. +/** + * The type of a function, there is one distinct type per function definition. + */ class FunctionType: public Type { public: @@ -176,7 +188,9 @@ private: FunctionDefinition const& m_function; }; -/// The type of a mapping, there is one distinct type per key/value type pair. +/** + * The type of a mapping, there is one distinct type per key/value type pair. + */ class MappingType: public Type { public: @@ -191,8 +205,10 @@ private: std::shared_ptr m_valueType; }; -/// The void type, can only be implicitly used as the type that is returned by functions without -/// return parameters. +/** + * The void type, can only be implicitly used as the type that is returned by functions without + * return parameters. + */ class VoidType: public Type { public: @@ -202,8 +218,10 @@ public: virtual std::string toString() const override { return "void"; } }; -/// The type of a type reference. The type of "uint32" when used in "a = uint32(2)" is an example -/// of a TypeType. +/** + * The type of a type reference. The type of "uint32" when used in "a = uint32(2)" is an example + * of a TypeType. + */ class TypeType: public Type { public: diff --git a/solc/main.cpp b/solc/main.cpp index 221ab962e..33e8db794 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -36,7 +36,9 @@ void version() } -/// Helper class that extracts the first expression in an AST. +/** + * Helper class that extracts the first expression in an AST. + */ class FirstExpressionExtractor: private ASTVisitor { public: From 3204918cd669ceacd1d1153bc88d5e1786d4c8ee Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 28 Oct 2014 16:57:20 +0100 Subject: [PATCH 09/36] Forgot some asterisks. --- libsolidity/ASTVisitor.h | 14 ++++++++------ libsolidity/BaseTypes.h | 6 ++++-- test/solidityCompiler.cpp | 4 +++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index a667ad392..e4818ee27 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -30,12 +30,14 @@ namespace dev namespace solidity { -/// Visitor interface for the abstract syntax tree. This class is tightly bound to the -/// implementation of @ref ASTNode::accept and its overrides. After a call to -/// @ref ASTNode::accept, the function visit for the appropriate parameter is called and then -/// (if it returns true) this continues recursively for all child nodes in document order -/// (there is an exception for contracts). After all child nodes have been visited, endVisit is -/// called for the node. +/** + * Visitor interface for the abstract syntax tree. This class is tightly bound to the + * implementation of @ref ASTNode::accept and its overrides. After a call to + * @ref ASTNode::accept, the function visit for the appropriate parameter is called and then + * (if it returns true) this continues recursively for all child nodes in document order + * (there is an exception for contracts). After all child nodes have been visited, endVisit is + * called for the node. + */ class ASTVisitor { public: diff --git a/libsolidity/BaseTypes.h b/libsolidity/BaseTypes.h index cfc14c7e9..d1ffd7bbc 100644 --- a/libsolidity/BaseTypes.h +++ b/libsolidity/BaseTypes.h @@ -29,8 +29,10 @@ namespace dev namespace solidity { -/// Representation of an interval of source positions. -/// The interval includes start and excludes end. +/** + * Representation of an interval of source positions. + * The interval includes start and excludes end. + */ struct Location { Location(int _start, int _end): start(_start), end(_end) { } diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 6e12fecf8..26bfc7cb6 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -41,7 +41,9 @@ namespace test namespace { -/// Helper class that extracts the first expression in an AST. +/** + * Helper class that extracts the first expression in an AST. + */ class FirstExpressionExtractor: private ASTVisitor { public: From 0877cf6036263947a6e1f98278722807387437a5 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 28 Oct 2014 17:09:06 +0100 Subject: [PATCH 10/36] Adjustments for the NEG->BNOT change. --- libsolidity/Compiler.cpp | 13 +++++-------- test/solidityCompiler.cpp | 4 +--- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index ef5680138..43cbc462e 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -107,13 +107,7 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) append(eth::Instruction::NOT); break; case Token::BIT_NOT: // ~ - // ~a modeled as "a xor (0 - 1)" for now - append(eth::Instruction::PUSH1); - append(1); - append(eth::Instruction::PUSH1); - append(0); - append(eth::Instruction::SUB); - append(eth::Instruction::XOR); + append(eth::Instruction::BNOT); break; case Token::DELETE: // delete // a -> a xor a (= 0). @@ -145,7 +139,10 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) // unary add, so basically no-op break; case Token::SUB: // - - append(eth::Instruction::NEG); + // unary -x translates into "0-x" + append(eth::Instruction::PUSH1); + append(0); + append(eth::Instruction::SUB); break; default: assert(false); // invalid operation diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 26bfc7cb6..0d9d59c1c 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -212,11 +212,9 @@ BOOST_AUTO_TEST_CASE(unary_operators) byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::SWAP1), byte(eth::Instruction::SUB), - byte(eth::Instruction::NEG), - byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH1), 0x0, byte(eth::Instruction::SUB), - byte(eth::Instruction::XOR), // bitwise not + byte(eth::Instruction::BNOT), byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::EQ), byte(eth::Instruction::NOT)}); From d83d476002da8af2793c183d4f5851a3a1d6ea27 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 29 Oct 2014 19:28:30 +0100 Subject: [PATCH 11/36] Fixed placements of const. --- libsolidity/Compiler.cpp | 2 +- libsolidity/Types.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 43cbc462e..be1d38b9c 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -230,7 +230,7 @@ void ExpressionCompiler::endVisit(Literal& _literal) } } -void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(const Type& _typeOnStack, const Type& _targetType) +void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType) { // If the type of one of the operands is extended, we need to remove all // higher-order bits that we might have ignored in previous operations. diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 05b12df09..e6711b3cb 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -143,7 +143,7 @@ bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const _operator == Token::INC || _operator == Token::DEC; } -bool IntegerType::operator==(const Type& _other) const +bool IntegerType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) return false; @@ -159,7 +159,7 @@ std::string IntegerType::toString() const return prefix + dev::toString(m_bits); } -bytes IntegerType::literalToBigEndian(const Literal& _literal) const +bytes IntegerType::literalToBigEndian(Literal const& _literal) const { bigint value(_literal.getValue()); if (!isSigned() && value < 0) @@ -182,7 +182,7 @@ bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const return isImplicitlyConvertibleTo(_convertTo); } -bytes BoolType::literalToBigEndian(const Literal& _literal) const +bytes BoolType::literalToBigEndian(Literal const& _literal) const { if (_literal.getToken() == Token::TRUE_LITERAL) return bytes(1, 1); @@ -192,7 +192,7 @@ bytes BoolType::literalToBigEndian(const Literal& _literal) const return NullBytes; } -bool ContractType::operator==(const Type& _other) const +bool ContractType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) return false; @@ -200,7 +200,7 @@ bool ContractType::operator==(const Type& _other) const return other.m_contract == m_contract; } -bool StructType::operator==(const Type& _other) const +bool StructType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) return false; @@ -208,7 +208,7 @@ bool StructType::operator==(const Type& _other) const return other.m_struct == m_struct; } -bool FunctionType::operator==(const Type& _other) const +bool FunctionType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) return false; @@ -216,7 +216,7 @@ bool FunctionType::operator==(const Type& _other) const return other.m_function == m_function; } -bool MappingType::operator==(const Type& _other) const +bool MappingType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) return false; @@ -224,7 +224,7 @@ bool MappingType::operator==(const Type& _other) const return *other.m_keyType == *m_keyType && *other.m_valueType == *m_valueType; } -bool TypeType::operator==(const Type& _other) const +bool TypeType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) return false; From c6c7f86b8254cce1426d1ae0293d0a57dd4413ac Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 29 Oct 2014 19:41:07 +0100 Subject: [PATCH 12/36] Further const placement changes. --- libsolidity/AST.cpp | 2 +- libsolidity/AST.h | 6 +++--- libsolidity/ASTPrinter.h | 2 +- libsolidity/Scanner.h | 4 ++-- test/solidityCompiler.cpp | 2 +- test/solidityNameAndTypeResolution.cpp | 2 +- test/solidityParser.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0b635339d..5bba8dce7 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -255,7 +255,7 @@ TypeError ASTNode::createTypeError(string const& _description) return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); } -void Statement::expectType(Expression& _expression, const Type& _expectedType) +void Statement::expectType(Expression& _expression, Type const& _expectedType) { _expression.checkTypeRequirements(); if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index e66572800..e72826602 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -89,7 +89,7 @@ public: ASTNode(_location), m_name(_name) {} /// Returns the declared name. - const ASTString& getName() const { return *m_name; } + ASTString const& getName() const { return *m_name; } private: ASTPointer m_name; @@ -259,7 +259,7 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual std::shared_ptr toType() override { return Type::fromUserDefinedTypeName(*this); } - const ASTString& getName() const { return *m_name; } + ASTString const& getName() const { return *m_name; } void setReferencedStruct(StructDefinition& _referencedStruct) { m_referencedStruct = &_referencedStruct; } StructDefinition const* getReferencedStruct() const { return m_referencedStruct; } @@ -549,7 +549,7 @@ public: ASTPointer const& _memberName): Expression(_location), m_expression(_expression), m_memberName(_memberName) {} virtual void accept(ASTVisitor& _visitor) override; - const ASTString& getMemberName() const { return *m_memberName; } + ASTString const& getMemberName() const { return *m_memberName; } virtual void checkTypeRequirements() override; private: diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index 97256c056..d788ba76c 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -38,7 +38,7 @@ class ASTPrinter: public ASTVisitor public: /// Create a printer for the given abstract syntax tree. If the source is specified, /// the corresponding parts of the source are printed with each node. - ASTPrinter(ASTPointer const& _ast, const std::string& _source = std::string()); + ASTPrinter(ASTPointer const& _ast, std::string const& _source = std::string()); /// Output the string representation of the AST to _stream. void print(std::ostream& _stream); diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index fbaba9ed6..c08d3219e 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -124,7 +124,7 @@ public: /// Returns the current token Token::Value getCurrentToken() { return m_current_token.token; } Location getCurrentLocation() const { return m_current_token.location; } - const std::string& getCurrentLiteral() const { return m_current_token.literal; } + std::string const& getCurrentLiteral() const { return m_current_token.literal; } ///@} ///@{ @@ -133,7 +133,7 @@ public: /// Returns the next token without advancing input. Token::Value peekNextToken() const { return m_next_token.token; } Location peekLocation() const { return m_next_token.location; } - const std::string& peekLiteral() const { return m_next_token.literal; } + std::string const& peekLiteral() const { return m_next_token.literal; } ///@} ///@{ diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 0d9d59c1c..22828238a 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -71,7 +71,7 @@ private: Expression* m_expression; }; -bytes compileFirstExpression(const std::string& _sourceCode) +bytes compileFirstExpression(std::string const& _sourceCode) { Parser parser; ASTPointer contract; diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index 833ae6d4b..9e34e6d0e 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -38,7 +38,7 @@ namespace test namespace { -void parseTextAndResolveNames(const std::string& _source) +void parseTextAndResolveNames(std::string const& _source) { Parser parser; ASTPointer contract = parser.parse( diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 701a6e76c..4ca9370d6 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -37,7 +37,7 @@ namespace test namespace { -ASTPointer parseText(const std::string& _source) +ASTPointer parseText(std::string const& _source) { Parser parser; return parser.parse(std::make_shared(CharStream(_source))); From ec0bc599e06bd670382d682c0bd6c1897b4e69d1 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 29 Oct 2014 22:19:23 +0100 Subject: [PATCH 13/36] Update SIGNEXTEND definition and tests Conflicts: libevm/VM.h test/vmBitwiseLogicOperationTestFiller.json --- test/vmBitwiseLogicOperationTestFiller.json | 336 ++++++++++++++++++++ 1 file changed, 336 insertions(+) diff --git a/test/vmBitwiseLogicOperationTestFiller.json b/test/vmBitwiseLogicOperationTestFiller.json index ee00d9784..5f3aabfcc 100644 --- a/test/vmBitwiseLogicOperationTestFiller.json +++ b/test/vmBitwiseLogicOperationTestFiller.json @@ -1224,6 +1224,342 @@ "gasPrice" : "100000000000000", "gas" : "10000" } + }, + + "signextend_bitIsSet": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x62122ff4600016600057", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_BitIsNotSet": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x62122f6a600016600057", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_BitIsSetInHigherByte": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6212faf4600116600057", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_BitIsNotSetInHigherByte": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x62126af4600116600057", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextendInvalidByteNumber": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x62126af4605016600057", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_00": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0 0) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_BigByte_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_0_BigByte": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_BigByteBigByte": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_AlmostBiggestByte": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (SIGNEXTEND 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_bigBytePlus1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x66f000000000000161ffff16600057", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "signextend_BigBytePlus1_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60ff68f0000000000000000116600057", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } } } From 54a5c580817923d4ec84ee7eef69f91e25bbe98c Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 29 Oct 2014 22:21:26 +0100 Subject: [PATCH 14/36] style fix Conflicts: libserpent/opcodes.h --- libserpent/opcodes.h | 183 ++++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 91 deletions(-) diff --git a/libserpent/opcodes.h b/libserpent/opcodes.h index 552364731..8e811967f 100644 --- a/libserpent/opcodes.h +++ b/libserpent/opcodes.h @@ -7,78 +7,79 @@ #include class Mapping { - public: - Mapping(std::string Op, int Opcode, int In, int Out) { - op = Op; - opcode = Opcode; - in = In; - out = Out; - } - std::string op; - int opcode; - int in; - int out; +public: + Mapping(std::string Op, int Opcode, int In, int Out) { + op = Op; + opcode = Opcode; + in = In; + out = Out; + } + std::string op; + int opcode; + int in; + int out; }; Mapping mapping[] = { - Mapping("STOP", 0x00, 0, 0), - Mapping("ADD", 0x01, 2, 1), - Mapping("MUL", 0x02, 2, 1), - Mapping("SUB", 0x03, 2, 1), - Mapping("DIV", 0x04, 2, 1), - Mapping("SDIV", 0x05, 2, 1), - Mapping("MOD", 0x06, 2, 1), - Mapping("SMOD", 0x07, 2, 1), - Mapping("EXP", 0x08, 2, 1), - Mapping("NEG", 0x09, 1, 1), - Mapping("LT", 0x0a, 2, 1), - Mapping("GT", 0x0b, 2, 1), - Mapping("SLT", 0x0c, 2, 1), - Mapping("SGT", 0x0d, 2, 1), - Mapping("EQ", 0x0e, 2, 1), - Mapping("NOT", 0x0f, 1, 1), - Mapping("AND", 0x10, 2, 1), - Mapping("OR", 0x11, 2, 1), - Mapping("XOR", 0x12, 2, 1), - Mapping("BYTE", 0x13, 2, 1), - Mapping("ADDMOD", 0x14, 3, 1), - Mapping("MULMOD", 0x15, 3, 1), - Mapping("SHA3", 0x20, 2, 1), - Mapping("ADDRESS", 0x30, 0, 1), - Mapping("BALANCE", 0x31, 1, 1), - Mapping("ORIGIN", 0x32, 0, 1), - Mapping("CALLER", 0x33, 0, 1), - Mapping("CALLVALUE", 0x34, 0, 1), - Mapping("CALLDATALOAD", 0x35, 1, 1), - Mapping("CALLDATASIZE", 0x36, 0, 1), - Mapping("CALLDATACOPY", 0x37, 3, 1), - Mapping("CODESIZE", 0x38, 0, 1), - Mapping("CODECOPY", 0x39, 3, 1), - Mapping("GASPRICE", 0x3a, 0, 1), - Mapping("PREVHASH", 0x40, 0, 1), - Mapping("COINBASE", 0x41, 0, 1), - Mapping("TIMESTAMP", 0x42, 0, 1), - Mapping("NUMBER", 0x43, 0, 1), - Mapping("DIFFICULTY", 0x44, 0, 1), - Mapping("GASLIMIT", 0x45, 0, 1), - Mapping("POP", 0x50, 1, 0), - Mapping("MLOAD", 0x53, 1, 1), - Mapping("MSTORE", 0x54, 2, 0), - Mapping("MSTORE8", 0x55, 2, 0), - Mapping("SLOAD", 0x56, 1, 1), - Mapping("SSTORE", 0x57, 2, 0), - Mapping("JUMP", 0x58, 1, 0), - Mapping("JUMPI", 0x59, 2, 0), - Mapping("PC", 0x5a, 0, 1), - Mapping("MSIZE", 0x5b, 0, 1), - Mapping("GAS", 0x5c, 0, 1), - Mapping("JUMPDEST", 0x5d, 0, 0), - Mapping("CREATE", 0xf0, 3, 1), - Mapping("CALL", 0xf1, 7, 1), - Mapping("RETURN", 0xf2, 2, 0), - Mapping("CALL_CODE", 0xf3, 7, 1), - Mapping("SUICIDE", 0xff, 1, 0), - Mapping("---END---", 0x00, 0, 0), + Mapping("STOP", 0x00, 0, 0), + Mapping("ADD", 0x01, 2, 1), + Mapping("MUL", 0x02, 2, 1), + Mapping("SUB", 0x03, 2, 1), + Mapping("DIV", 0x04, 2, 1), + Mapping("SDIV", 0x05, 2, 1), + Mapping("MOD", 0x06, 2, 1), + Mapping("SMOD", 0x07, 2, 1), + Mapping("EXP", 0x08, 2, 1), + Mapping("NEG", 0x09, 1, 1), + Mapping("LT", 0x0a, 2, 1), + Mapping("GT", 0x0b, 2, 1), + Mapping("SLT", 0x0c, 2, 1), + Mapping("SGT", 0x0d, 2, 1), + Mapping("EQ", 0x0e, 2, 1), + Mapping("NOT", 0x0f, 1, 1), + Mapping("AND", 0x10, 2, 1), + Mapping("OR", 0x11, 2, 1), + Mapping("XOR", 0x12, 2, 1), + Mapping("BYTE", 0x13, 2, 1), + Mapping("ADDMOD", 0x14, 3, 1), + Mapping("MULMOD", 0x15, 3, 1), + Mapping("SIGNEXTEND", 0x16, 2, 1), + Mapping("SHA3", 0x20, 2, 1), + Mapping("ADDRESS", 0x30, 0, 1), + Mapping("BALANCE", 0x31, 1, 1), + Mapping("ORIGIN", 0x32, 0, 1), + Mapping("CALLER", 0x33, 0, 1), + Mapping("CALLVALUE", 0x34, 0, 1), + Mapping("CALLDATALOAD", 0x35, 1, 1), + Mapping("CALLDATASIZE", 0x36, 0, 1), + Mapping("CALLDATACOPY", 0x37, 3, 1), + Mapping("CODESIZE", 0x38, 0, 1), + Mapping("CODECOPY", 0x39, 3, 1), + Mapping("GASPRICE", 0x3a, 0, 1), + Mapping("PREVHASH", 0x40, 0, 1), + Mapping("COINBASE", 0x41, 0, 1), + Mapping("TIMESTAMP", 0x42, 0, 1), + Mapping("NUMBER", 0x43, 0, 1), + Mapping("DIFFICULTY", 0x44, 0, 1), + Mapping("GASLIMIT", 0x45, 0, 1), + Mapping("POP", 0x50, 1, 0), + Mapping("MLOAD", 0x53, 1, 1), + Mapping("MSTORE", 0x54, 2, 0), + Mapping("MSTORE8", 0x55, 2, 0), + Mapping("SLOAD", 0x56, 1, 1), + Mapping("SSTORE", 0x57, 2, 0), + Mapping("JUMP", 0x58, 1, 0), + Mapping("JUMPI", 0x59, 2, 0), + Mapping("PC", 0x5a, 0, 1), + Mapping("MSIZE", 0x5b, 0, 1), + Mapping("GAS", 0x5c, 0, 1), + Mapping("JUMPDEST", 0x5d, 0, 0), + Mapping("CREATE", 0xf0, 3, 1), + Mapping("CALL", 0xf1, 7, 1), + Mapping("RETURN", 0xf2, 2, 0), + Mapping("CALL_CODE", 0xf3, 7, 1), + Mapping("SUICIDE", 0xff, 1, 0), + Mapping("---END---", 0x00, 0, 0), }; std::map > opcodes; @@ -86,28 +87,28 @@ std::map reverseOpcodes; // Fetches everything EXCEPT PUSH1..32 std::pair > _opdata(std::string ops, int opi) { - if (!opcodes.size()) { - int i = 0; - while (mapping[i].op != "---END---") { - Mapping mi = mapping[i]; - opcodes[mi.op] = triple(mi.opcode, mi.in, mi.out); - i++; - } - for (i = 1; i <= 16; i++) { - opcodes["DUP"+unsignedToDecimal(i)] = triple(0x7f + i, i, i+1); - opcodes["SWAP"+unsignedToDecimal(i)] = triple(0x8f + i, i+1, i+1); - } - for (std::map >::iterator it=opcodes.begin(); - it != opcodes.end(); - it++) { - reverseOpcodes[(*it).second[0]] = (*it).first; - } - } - std::string op; - std::vector opdata; - op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : ""; - opdata = opcodes.count(ops) ? opcodes[ops] : triple(-1, -1, -1); - return std::pair >(op, opdata); + if (!opcodes.size()) { + int i = 0; + while (mapping[i].op != "---END---") { + Mapping mi = mapping[i]; + opcodes[mi.op] = triple(mi.opcode, mi.in, mi.out); + i++; + } + for (i = 1; i <= 16; i++) { + opcodes["DUP"+unsignedToDecimal(i)] = triple(0x7f + i, i, i+1); + opcodes["SWAP"+unsignedToDecimal(i)] = triple(0x8f + i, i+1, i+1); + } + for (std::map >::iterator it=opcodes.begin(); + it != opcodes.end(); + it++) { + reverseOpcodes[(*it).second[0]] = (*it).first; + } + } + std::string op; + std::vector opdata; + op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : ""; + opdata = opcodes.count(ops) ? opcodes[ops] : triple(-1, -1, -1); + return std::pair >(op, opdata); } int opcode(std::string op) { From 00b64587fd38209cc8d003ccdf7f49027705d1f3 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Tue, 28 Oct 2014 13:46:17 +0100 Subject: [PATCH 15/36] clean up PR --- test/vm.cpp | 37 ++----------------------------------- test/vm.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 76ed41a44..d69f03fda 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -130,7 +130,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, m_ms.internal.resize(m_ms.internal.size() + 1); - auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), Executive::simpleTrace(), 1); + auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), simpleTrace(), 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -421,39 +421,6 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) } } -eth::OnOpFunc FakeExtVM::simpleTrace() -{ - return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) - { - FakeExtVM const& ext = *(FakeExtVM const*)voidExt; - eth::VM& vm = *(eth::VM*)voidVM; - - std::ostringstream o; - o << std::endl << " STACK" << std::endl; - for (auto i: vm.stack()) - o << (h256)i << std::endl; - o << " MEMORY" << std::endl << memDump(vm.memory()); - o << " STORAGE" << std::endl; - - for (auto const& i: ext.state().storage(ext.myAddress)) - o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; - - for (auto const& i: std::get<2>(ext.addresses.find(ext.myAddress)->second)) - o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; - - dev::LogOutputStream(true) << o.str(); - dev::LogOutputStream(false) << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; - - if (eth::VMTraceChannel::verbosity <= g_logVerbosity) - { - std::ofstream f; - f.open("./vmtrace.log", std::ofstream::app); - f << o.str(); - f << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32"; - } - }; -} - // THIS IS BROKEN AND NEEDS TO BE REMOVED. h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { @@ -550,7 +517,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) VM vm(fev.gas); try { - output = vm.go(fev, fev.simpleTrace()).toVector(); + output = vm.go(fev, fev.simpleTrace()).toVector(); } catch (Exception const& _e) { diff --git a/test/vm.h b/test/vm.h index ddc6ddb3e..f3aae694a 100644 --- a/test/vm.h +++ b/test/vm.h @@ -81,7 +81,9 @@ public: json_spirit::mArray exportCallCreates(); void importCallCreates(json_spirit::mArray& _callcreates); + template eth::OnOpFunc simpleTrace(); + FakeState state() const { return m_s; } std::map, bytes>> addresses; @@ -95,5 +97,32 @@ private: eth::Manifest m_ms; }; +template +eth::OnOpFunc FakeExtVM::simpleTrace() +{ + return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) + { + ExtVMType const& ext = *(ExtVMType const*)voidExt; + eth::VM& vm = *(eth::VM*)voidVM; + + std::ostringstream o; + o << std::endl << " STACK" << std::endl; + for (auto i: vm.stack()) + o << (h256)i << std::endl; + o << " MEMORY" << std::endl << memDump(vm.memory()); + o << " STORAGE" << std::endl; + for (auto const& i: ext.state().storage(ext.myAddress)) + o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; + dev::LogOutputStream(true) << o.str(); + dev::LogOutputStream(false) << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; + if (eth::VMTraceChannel::verbosity <= g_logVerbosity) + { + std::ofstream f; + f.open("./vmtrace.log", std::ofstream::app); + f << o.str(); + f << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32"; + } + }; +} } } // Namespace Close From 1f5b6059afdb37add7cda97de85e5120edb3ff63 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 29 Oct 2014 21:28:31 +0100 Subject: [PATCH 16/36] Update tests to new definition --- test/vmArithmeticTestFiller.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/vmArithmeticTestFiller.json b/test/vmArithmeticTestFiller.json index 9e9538386..717257e22 100644 --- a/test/vmArithmeticTestFiller.json +++ b/test/vmArithmeticTestFiller.json @@ -1319,7 +1319,7 @@ }, - "neg0": { + "bnot0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1347,7 +1347,7 @@ } }, - "neg1": { + "bnot1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1375,7 +1375,7 @@ } }, - "neg2": { + "bnot2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1403,7 +1403,7 @@ } }, - "neg3": { + "bnot3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1431,7 +1431,7 @@ } }, - "neg4": { + "bnot4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1459,7 +1459,7 @@ } }, - "neg5": { + "bnot5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", From 4d30a898ee94d8e1c704dc85ac4bec1df0b02f41 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 29 Oct 2014 21:38:54 +0100 Subject: [PATCH 17/36] style fix --- libserpent/opcodes.h | 46 ++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/libserpent/opcodes.h b/libserpent/opcodes.h index 8e811967f..a254ea0b2 100644 --- a/libserpent/opcodes.h +++ b/libserpent/opcodes.h @@ -1,3 +1,20 @@ +/* + 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 . +*/ + #ifndef ETHSERP_OPCODES #define ETHSERP_OPCODES @@ -86,23 +103,24 @@ std::map > opcodes; std::map reverseOpcodes; // Fetches everything EXCEPT PUSH1..32 -std::pair > _opdata(std::string ops, int opi) { - if (!opcodes.size()) { +std::pair > _opdata(std::string ops, int opi) +{ + if (!opcodes.size()) + { int i = 0; - while (mapping[i].op != "---END---") { + while (mapping[i].op != "---END---") + { Mapping mi = mapping[i]; opcodes[mi.op] = triple(mi.opcode, mi.in, mi.out); i++; } - for (i = 1; i <= 16; i++) { + for (i = 1; i <= 16; i++) + { opcodes["DUP"+unsignedToDecimal(i)] = triple(0x7f + i, i, i+1); opcodes["SWAP"+unsignedToDecimal(i)] = triple(0x8f + i, i+1, i+1); } - for (std::map >::iterator it=opcodes.begin(); - it != opcodes.end(); - it++) { + for (std::map >::iterator it=opcodes.begin(); it != opcodes.end(); it++) reverseOpcodes[(*it).second[0]] = (*it).first; - } } std::string op; std::vector opdata; @@ -111,19 +129,23 @@ std::pair > _opdata(std::string ops, int opi) { return std::pair >(op, opdata); } -int opcode(std::string op) { +int opcode(std::string op) +{ return _opdata(op, -1).second[0]; } -int opinputs(std::string op) { +int opinputs(std::string op) +{ return _opdata(op, -1).second[1]; } -int opoutputs(std::string op) { +int opoutputs(std::string op) +{ return _opdata(op, -1).second[2]; } -std::string op(int opcode) { +std::string op(int opcode) +{ return _opdata("", opcode).first; } From 602c4115ffdfb784f00b1b46f80b43635b453502 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 29 Oct 2014 22:05:27 +0100 Subject: [PATCH 18/36] Clean up --- test/vm.cpp | 37 +++++++++++++++++++++++++++++++++++-- test/vm.h | 29 ----------------------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index d69f03fda..76ed41a44 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -130,7 +130,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, m_ms.internal.resize(m_ms.internal.size() + 1); - auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), simpleTrace(), 1); + auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), Executive::simpleTrace(), 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -421,6 +421,39 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) } } +eth::OnOpFunc FakeExtVM::simpleTrace() +{ + return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) + { + FakeExtVM const& ext = *(FakeExtVM const*)voidExt; + eth::VM& vm = *(eth::VM*)voidVM; + + std::ostringstream o; + o << std::endl << " STACK" << std::endl; + for (auto i: vm.stack()) + o << (h256)i << std::endl; + o << " MEMORY" << std::endl << memDump(vm.memory()); + o << " STORAGE" << std::endl; + + for (auto const& i: ext.state().storage(ext.myAddress)) + o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; + + for (auto const& i: std::get<2>(ext.addresses.find(ext.myAddress)->second)) + o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; + + dev::LogOutputStream(true) << o.str(); + dev::LogOutputStream(false) << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; + + if (eth::VMTraceChannel::verbosity <= g_logVerbosity) + { + std::ofstream f; + f.open("./vmtrace.log", std::ofstream::app); + f << o.str(); + f << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32"; + } + }; +} + // THIS IS BROKEN AND NEEDS TO BE REMOVED. h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { @@ -517,7 +550,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) VM vm(fev.gas); try { - output = vm.go(fev, fev.simpleTrace()).toVector(); + output = vm.go(fev, fev.simpleTrace()).toVector(); } catch (Exception const& _e) { diff --git a/test/vm.h b/test/vm.h index f3aae694a..ddc6ddb3e 100644 --- a/test/vm.h +++ b/test/vm.h @@ -81,9 +81,7 @@ public: json_spirit::mArray exportCallCreates(); void importCallCreates(json_spirit::mArray& _callcreates); - template eth::OnOpFunc simpleTrace(); - FakeState state() const { return m_s; } std::map, bytes>> addresses; @@ -97,32 +95,5 @@ private: eth::Manifest m_ms; }; -template -eth::OnOpFunc FakeExtVM::simpleTrace() -{ - return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) - { - ExtVMType const& ext = *(ExtVMType const*)voidExt; - eth::VM& vm = *(eth::VM*)voidVM; - - std::ostringstream o; - o << std::endl << " STACK" << std::endl; - for (auto i: vm.stack()) - o << (h256)i << std::endl; - o << " MEMORY" << std::endl << memDump(vm.memory()); - o << " STORAGE" << std::endl; - for (auto const& i: ext.state().storage(ext.myAddress)) - o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; - dev::LogOutputStream(true) << o.str(); - dev::LogOutputStream(false) << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; - if (eth::VMTraceChannel::verbosity <= g_logVerbosity) - { - std::ofstream f; - f.open("./vmtrace.log", std::ofstream::app); - f << o.str(); - f << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32"; - } - }; -} } } // Namespace Close From 3711dded2300a7e8b583354374e9712a14793424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 12:44:43 +0100 Subject: [PATCH 19/36] Update Visual Studio project file for LibEthereum --- windows/LibEthereum.vcxproj | 4 ++-- windows/LibEthereum.vcxproj.filters | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 2ece3cd28..c308f05e7 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -103,8 +103,8 @@ true + - @@ -318,8 +318,8 @@ true true + - diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index b4d898890..137440619 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -4,9 +4,6 @@ Windows - - libethereum - libethereum @@ -202,14 +199,14 @@ libdevcrypto + + libethereum + Windows - - libethereum - libethereum @@ -435,6 +432,9 @@ libdevcrypto + + libethereum + From b45701e4279fb4793772abb246d8b8a22c602867 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 31 Oct 2014 13:01:03 +0100 Subject: [PATCH 20/36] For for copying high addresses from CALLDATA/CODE/EXTCODE --- libevm/VM.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index e2f4ff5dd..59d2f12d4 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -506,7 +506,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con { unsigned mf = (unsigned)m_stack.back(); m_stack.pop_back(); - unsigned cf = (unsigned)m_stack.back(); + u256 cf = (unsigned)m_stack.back(); m_stack.pop_back(); unsigned l = (unsigned)m_stack.back(); m_stack.pop_back(); @@ -522,11 +522,11 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con { unsigned mf = (unsigned)m_stack.back(); m_stack.pop_back(); - unsigned cf = (unsigned)m_stack.back(); + u256 cf = (u256)m_stack.back(); m_stack.pop_back(); unsigned l = (unsigned)m_stack.back(); m_stack.pop_back(); - unsigned el = cf + l > _ext.code.size() ? _ext.code.size() < cf ? 0 : _ext.code.size() - cf : l; + unsigned el = cf + l > (u256)_ext.code.size() ? (u256)_ext.code.size() < cf ? 0 : _ext.code.size() - (unsigned)cf : l; memcpy(m_temp.data() + mf, _ext.code.data() + cf, el); memset(m_temp.data() + mf + el, 0, l - el); break; @@ -540,11 +540,11 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); unsigned mf = (unsigned)m_stack.back(); m_stack.pop_back(); - unsigned cf = (unsigned)m_stack.back(); + u256 cf = m_stack.back(); m_stack.pop_back(); unsigned l = (unsigned)m_stack.back(); m_stack.pop_back(); - unsigned el = cf + l > _ext.codeAt(a).size() ? _ext.codeAt(a).size() < cf ? 0 : _ext.codeAt(a).size() - cf : l; + unsigned el = cf + l > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < cf ? 0 : _ext.codeAt(a).size() - (unsigned)cf : l; memcpy(m_temp.data() + mf, _ext.codeAt(a).data() + cf, el); memset(m_temp.data() + mf + el, 0, l - el); break; From c663ff6f396484354cdec09977bacf7a3c40e517 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 31 Oct 2014 13:03:30 +0100 Subject: [PATCH 21/36] Fixed #444 --- libevm/VM.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 59d2f12d4..7cf7ce6eb 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -506,12 +506,12 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con { unsigned mf = (unsigned)m_stack.back(); m_stack.pop_back(); - u256 cf = (unsigned)m_stack.back(); + u256 cf = m_stack.back(); m_stack.pop_back(); unsigned l = (unsigned)m_stack.back(); m_stack.pop_back(); - unsigned el = cf + l > _ext.data.size() ? _ext.data.size() < cf ? 0 : _ext.data.size() - cf : l; - memcpy(m_temp.data() + mf, _ext.data.data() + cf, el); + unsigned el = cf + l > (u256)_ext.data.size() ? (u256)_ext.data.size() < cf ? 0 : _ext.data.size() - (unsigned)cf : l; + memcpy(m_temp.data() + mf, _ext.data.data() + (unsigned)cf, el); memset(m_temp.data() + mf + el, 0, l - el); break; } @@ -527,7 +527,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con unsigned l = (unsigned)m_stack.back(); m_stack.pop_back(); unsigned el = cf + l > (u256)_ext.code.size() ? (u256)_ext.code.size() < cf ? 0 : _ext.code.size() - (unsigned)cf : l; - memcpy(m_temp.data() + mf, _ext.code.data() + cf, el); + memcpy(m_temp.data() + mf, _ext.code.data() + (unsigned)cf, el); memset(m_temp.data() + mf + el, 0, l - el); break; } @@ -545,7 +545,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con unsigned l = (unsigned)m_stack.back(); m_stack.pop_back(); unsigned el = cf + l > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < cf ? 0 : _ext.codeAt(a).size() - (unsigned)cf : l; - memcpy(m_temp.data() + mf, _ext.codeAt(a).data() + cf, el); + memcpy(m_temp.data() + mf, _ext.codeAt(a).data() + (unsigned)cf, el); memset(m_temp.data() + mf + el, 0, l - el); break; } From 0c88f032049de6c80c8a85ccf0d73d902703ffc1 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 31 Oct 2014 13:29:32 +0100 Subject: [PATCH 22/36] Corrected doxygen post comments. --- libsolidity/AST.h | 4 ++-- libsolidity/Compiler.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index e72826602..4dc44e29b 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -345,7 +345,7 @@ public: private: ASTPointer m_condition; ASTPointer m_trueBody; - ASTPointer m_falseBody; //< "else" part, optional + ASTPointer m_falseBody; ///< "else" part, optional }; /** @@ -400,7 +400,7 @@ public: void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } private: - ASTPointer m_expression; //< value to return, optional + ASTPointer m_expression; ///< value to return, optional /// Pointer to the parameter list of the function, filled by the @ref NameAndTypeResolver. ParameterList* m_returnParameters; diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 1401e12e3..5817f12f1 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -38,10 +38,10 @@ class AssemblyItem public: enum class Type { - CODE, //< m_data is opcode, m_label is empty. - DATA, //< m_data is actual data, m_label is empty - LABEL, //< m_data is JUMPDEST opcode, m_label is id of label - LABELREF //< m_data is empty, m_label is id of label + CODE, ///< m_data is opcode, m_label is empty. + DATA, ///< m_data is actual data, m_label is empty + LABEL, ///< m_data is JUMPDEST opcode, m_label is id of label + LABELREF ///< m_data is empty, m_label is id of label }; explicit AssemblyItem(eth::Instruction _instruction) : m_type(Type::CODE), m_data(byte(_instruction)) {} @@ -59,8 +59,8 @@ private: AssemblyItem(Type _type, byte _data, uint32_t _label): m_type(_type), m_data(_data), m_label(_label) {} Type m_type; - byte m_data; //< data to be written to the bytecode stream (or filled by a label if this is a LABELREF) - uint32_t m_label; //< the id of a label either referenced or defined by this item + byte m_data; ///< data to be written to the bytecode stream (or filled by a label if this is a LABELREF) + uint32_t m_label; ///< the id of a label either referenced or defined by this item }; using AssemblyItems = std::vector; From 2770e6ccc7d846c771074aeff796d9675ce2f743 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 31 Oct 2014 14:32:32 +0100 Subject: [PATCH 23/36] PoC-7: Instruction set reform --- libevm/VM.h | 6 +++--- libevmface/Instruction.cpp | 8 ++++---- libevmface/Instruction.h | 17 +++++++++-------- liblll/Assembly.cpp | 2 +- liblll/CodeFragment.cpp | 14 +++++++------- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 7cf7ce6eb..4ef4e968c 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -262,8 +262,8 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::PUSH31: case Instruction::PUSH32: break; - case Instruction::BNOT: case Instruction::NOT: + case Instruction::ISZERO: case Instruction::CALLDATALOAD: case Instruction::EXTCODESIZE: case Instruction::POP: @@ -395,7 +395,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256); break; } - case Instruction::BNOT: + case Instruction::NOT: m_stack.back() = ~m_stack.back(); break; case Instruction::LT: @@ -418,7 +418,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0; m_stack.pop_back(); break; - case Instruction::NOT: + case Instruction::ISZERO: m_stack.back() = m_stack.back() ? 0 : 1; break; case Instruction::AND: diff --git a/libevmface/Instruction.cpp b/libevmface/Instruction.cpp index 2c2af8eb0..a55cc2242 100644 --- a/libevmface/Instruction.cpp +++ b/libevmface/Instruction.cpp @@ -39,13 +39,13 @@ const std::map dev::eth::c_instructions = { "MOD", Instruction::MOD }, { "SMOD", Instruction::SMOD }, { "EXP", Instruction::EXP }, - { "BNOT", Instruction::BNOT }, + { "BNOT", Instruction::NOT }, { "LT", Instruction::LT }, { "GT", Instruction::GT }, { "SLT", Instruction::SLT }, { "SGT", Instruction::SGT }, { "EQ", Instruction::EQ }, - { "NOT", Instruction::NOT }, + { "NOT", Instruction::ISZERO }, { "AND", Instruction::AND }, { "OR", Instruction::OR }, { "XOR", Instruction::XOR }, @@ -172,13 +172,13 @@ static const std::map c_instructionInfo = { Instruction::MOD, { "MOD", 0, 2, 1 } }, { Instruction::SMOD, { "SMOD", 0, 2, 1 } }, { Instruction::EXP, { "EXP", 0, 2, 1 } }, - { Instruction::BNOT, { "BNOT", 0, 1, 1 } }, + { Instruction::NOT, { "BNOT", 0, 1, 1 } }, { Instruction::LT, { "LT", 0, 2, 1 } }, { Instruction::GT, { "GT", 0, 2, 1 } }, { Instruction::SLT, { "SLT", 0, 2, 1 } }, { Instruction::SGT, { "SGT", 0, 2, 1 } }, { Instruction::EQ, { "EQ", 0, 2, 1 } }, - { Instruction::NOT, { "NOT", 0, 1, 1 } }, + { Instruction::ISZERO, { "NOT", 0, 1, 1 } }, { Instruction::AND, { "AND", 0, 2, 1 } }, { Instruction::OR, { "OR", 0, 2, 1 } }, { Instruction::XOR, { "XOR", 0, 2, 1 } }, diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index ea355fab1..965b093e5 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -43,22 +43,23 @@ enum class Instruction: uint8_t SDIV, ///< signed integer division operation MOD, ///< modulo remainder operation SMOD, ///< signed modulo remainder operation + ADDMOD, ///< unsigned modular addition + MULMOD, ///< unsigned modular multiplication EXP, ///< exponential operation - BNOT, ///< bitwise not - LT, ///< less-than comparision + SIGNEXTEND, ///< extend length of signed integer + + LT = 0x10, ///< less-than comparision GT, ///< greater-than comparision SLT, ///< signed less-than comparision SGT, ///< signed greater-than comparision EQ, ///< equality comparision - NOT, ///< simple not operator - - AND = 0x10, ///< bitwise AND operation + ISZERO, ///< simple not operator + AND, ///< bitwise AND operation OR, ///< bitwise OR operation XOR, ///< bitwise XOR operation + NOT, ///< bitwise NOT opertation BYTE, ///< retrieve single byte from word - ADDMOD, ///< unsigned modular addition - MULMOD, ///< unsigned modular multiplication - SIGNEXTEND, ///< extend length of signed integer + SHA3 = 0x20, ///< compute SHA3-256 hash ADDRESS = 0x30, ///< get address of currently executing account diff --git a/liblll/Assembly.cpp b/liblll/Assembly.cpp index 7ad84682f..25895e1b7 100644 --- a/liblll/Assembly.cpp +++ b/liblll/Assembly.cpp @@ -251,7 +251,7 @@ Assembly& Assembly::optimise(bool _enable) { { PushSub, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushSubSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } }, - { { Instruction::NOT, Instruction::NOT }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { Instruction::ISZERO, Instruction::ISZERO }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, }; for (auto const& i: c_simple) diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 56b5d440f..47df8f3b9 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -328,7 +328,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) std::map const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD }, { "&", Instruction::AND }, { "|", Instruction::OR }, { "^", Instruction::XOR } }; std::map> const c_binary = { { "<", { Instruction::LT, false } }, { "<=", { Instruction::GT, true } }, { ">", { Instruction::GT, false } }, { ">=", { Instruction::LT, true } }, { "S<", { Instruction::SLT, false } }, { "S<=", { Instruction::SGT, true } }, { "S>", { Instruction::SGT, false } }, { "S>=", { Instruction::SLT, true } }, { "=", { Instruction::EQ, false } }, { "!=", { Instruction::EQ, true } } }; - std::map const c_unary = { { "!", Instruction::NOT } }; + std::map const c_unary = { { "!", Instruction::ISZERO } }; vector code; CompilerState ns = _s; @@ -403,7 +403,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.append(code[0].m_asm, 1); m_asm.append(it->second.first); if (it->second.second) - m_asm.append(Instruction::NOT); + m_asm.append(Instruction::ISZERO); } else if (c_unary.count(us)) { @@ -437,7 +437,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.append(code[0].m_asm); if (us == "WHEN") - m_asm.append(Instruction::NOT); + m_asm.append(Instruction::ISZERO); auto end = m_asm.appendJumpI(); m_asm.onePath(); m_asm.otherPath(); @@ -452,7 +452,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) auto begin = m_asm.append(); m_asm.append(code[0].m_asm); - m_asm.append(Instruction::NOT); + m_asm.append(Instruction::ISZERO); auto end = m_asm.appendJumpI(); m_asm.append(code[1].m_asm, 0); m_asm.appendJump(begin); @@ -466,7 +466,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.append(code[0].m_asm, 0); auto begin = m_asm.append(); m_asm.append(code[1].m_asm); - m_asm.append(Instruction::NOT); + m_asm.append(Instruction::ISZERO); auto end = m_asm.appendJumpI(); m_asm.append(code[3].m_asm, 0); m_asm.append(code[2].m_asm, 0); @@ -502,7 +502,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireDeposit(2, 1); m_asm.append(code[2].m_asm, 1); m_asm.append(Instruction::LT); - m_asm.append(Instruction::NOT); + m_asm.append(Instruction::ISZERO); m_asm.append(Instruction::MUL); m_asm.append(Instruction::DUP1); } @@ -525,7 +525,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) // Check if true - predicate m_asm.append(code[i - 1].m_asm, 1); if (us == "&&") - m_asm.append(Instruction::NOT); + m_asm.append(Instruction::ISZERO); m_asm.appendJumpI(end); } m_asm.append(Instruction::POP); From eb5fdb59eafb6e538031238b077c26cb16487fe9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 31 Oct 2014 14:33:05 +0100 Subject: [PATCH 24/36] PoC-7: Instruction set reform redux. --- libevmface/Instruction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index 965b093e5..b3ed4fb74 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -84,7 +84,7 @@ enum class Instruction: uint8_t GASLIMIT, ///< get the block's gas limit POP = 0x50, ///< remove item from stack - MLOAD = 0x53, ///< load word from memory + MLOAD, ///< load word from memory MSTORE, ///< save word to memory MSTORE8, ///< save byte to memory SLOAD, ///< load word from storage From ae960c577a62171f8815955d3d4f3c3c3fe17dab Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 31 Oct 2014 14:35:13 +0100 Subject: [PATCH 25/36] Big fixes. --- libsolidity/Compiler.cpp | 4 ++-- test/solidityCompiler.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index be1d38b9c..f19dd3f7f 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -104,10 +104,10 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) switch (_unaryOperation.getOperator()) { case Token::NOT: // ! - append(eth::Instruction::NOT); + append(eth::Instruction::ISZERO); break; case Token::BIT_NOT: // ~ - append(eth::Instruction::BNOT); + append(eth::Instruction::NOT); break; case Token::DELETE: // delete // a -> a xor a (= 0). diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 22828238a..e08605110 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -214,10 +214,10 @@ BOOST_AUTO_TEST_CASE(unary_operators) byte(eth::Instruction::SUB), byte(eth::Instruction::PUSH1), 0x0, byte(eth::Instruction::SUB), - byte(eth::Instruction::BNOT), + byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::EQ), - byte(eth::Instruction::NOT)}); + byte(eth::Instruction::ISZERO)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } From 5dc0a266c4f24f1aabc1a9e4203877af02b23462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:16:34 +0100 Subject: [PATCH 26/36] Empty lines removal --- libevmjit/Compiler.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8a38e257f..121ae37d5 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -462,7 +462,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, const auto byteNum = stack.pop(); auto value = stack.pop(); - // value = Endianness::toBE(m_builder, value); auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); @@ -471,7 +470,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); stack.push(value); - break; } @@ -521,7 +519,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, m_builder.CreateSelect(bittest, val1, val0), word); stack.push(result); - break; } From b039d7ee8e98aa22e9693e52d5ad3090b25000f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:17:03 +0100 Subject: [PATCH 27/36] Use common builder in GasMeter and Memory --- libevmjit/GasMeter.cpp | 7 +++---- libevmjit/GasMeter.h | 4 ++-- libevmjit/Memory.cpp | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 5f6f81e72..a0656ace4 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -169,11 +169,10 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost) assert(m_blockCost == 0); } -void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder) +void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords) { - // Memory uses other builder, but that can be changes later - auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); - _builder.CreateCall(m_gasCheckFunc, cost); + auto cost = m_builder.CreateNUWMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); + m_builder.CreateCall(m_gasCheckFunc, cost); } } diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index dcfde92a3..3de227651 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -32,7 +32,7 @@ public: void giveBack(llvm::Value* _gas); /// Generate code that checks the cost of additional memory used by program - void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); + void checkMemory(llvm::Value* _additionalMemoryInWords); private: /// Cumulative gas cost of a block of instructions @@ -40,7 +40,7 @@ private: uint64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; - llvm::Function* m_gasCheckFunc; + llvm::Function* m_gasCheckFunc = nullptr; RuntimeManager& m_runtimeManager; }; diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 322c53ee3..beedd9cb9 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -90,7 +90,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.checkMemory(newWords, m_builder); + _gasMeter.checkMemory(newWords); // Resize m_builder.CreateStore(sizeRequired, m_size); auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData"); From 23c7da66fa406dab7df9e8a7151bc3e597cf56a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:28:27 +0100 Subject: [PATCH 28/36] Rename Type::i256 -> Type::Word --- libevmjit/Arith256.cpp | 8 ++++---- libevmjit/BasicBlock.cpp | 2 +- libevmjit/Compiler.cpp | 20 ++++++++++---------- libevmjit/Endianness.cpp | 4 ++-- libevmjit/GasMeter.cpp | 4 ++-- libevmjit/Memory.cpp | 26 +++++++++++++------------- libevmjit/Runtime.cpp | 2 +- libevmjit/Stack.cpp | 2 +- libevmjit/Type.cpp | 10 +++++----- libevmjit/Type.h | 2 +- 10 files changed, 40 insertions(+), 40 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 61b0ba35e..82e31e61d 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -18,10 +18,10 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : { using namespace llvm; - m_result = m_builder.CreateAlloca(Type::i256, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg3"); + m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); + m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); + m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); + m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); using Linkage = GlobalValue::LinkageTypes; diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index a35462cbe..0c604f1b3 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -171,7 +171,7 @@ llvm::Value* BasicBlock::LocalStack::get(size_t _index) assert(m_initialStack[initialIdx] == nullptr); // Create a dummy value. std::string name = "get_" + boost::lexical_cast(_index); - m_initialStack[initialIdx] = m_builder.CreatePHI(Type::i256, 0, name); + m_initialStack[initialIdx] = m_builder.CreatePHI(Type::Word, 0, name); *itemIter = m_initialStack[initialIdx]; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 121ae37d5..537a0082b 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -376,7 +376,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpULT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -386,7 +386,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpUGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -396,7 +396,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpSLT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -406,7 +406,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpSGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -416,7 +416,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpEQ(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -425,7 +425,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto top = stack.pop(); auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); - auto result = m_builder.CreateZExt(iszero, Type::i256); + auto result = m_builder.CreateZExt(iszero, Type::Word); stack.push(result); break; } @@ -465,7 +465,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, value = Endianness::toBE(m_builder, value); auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); - value = m_builder.CreateZExt(byte, Type::i256); + value = m_builder.CreateZExt(byte, Type::Word); auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); @@ -499,7 +499,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto word = stack.pop(); auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32"); - auto k32 = m_builder.CreateZExt(k32_, Type::i256); + auto k32 = m_builder.CreateZExt(k32_, Type::Word); auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8"); // test for word >> (k * 8 + 7) @@ -510,11 +510,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos); auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); - auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::i256), "negmask"); + auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::Word), "negmask"); auto val1 = m_builder.CreateOr(word, negmask); auto val0 = m_builder.CreateAnd(word, mask); - auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::i256, 30)); + auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::Word, 30)); auto result = m_builder.CreateSelect(kInRange, m_builder.CreateSelect(bittest, val1, val0), word); diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index f0da5f9d4..e062fb77e 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -15,8 +15,8 @@ namespace jit llvm::Value* Endianness::bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word) { // TODO: Native is Little Endian - assert(_word->getType() == Type::i256); - auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::i256); + assert(_word->getType() == Type::Word); + auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); return _builder.CreateCall(bswap, _word); } diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index a0656ace4..7a6a0ebd2 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -84,7 +84,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module); + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::Word, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); @@ -113,7 +113,7 @@ void GasMeter::count(Instruction _inst) if (!m_checkCall) { // Create gas check call with mocked block cost at begining of current cost-block - m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256)); + m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::Word)); } m_blockCost += getStepCost(_inst); diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index beedd9cb9..c06b22637 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -29,7 +29,7 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager) { auto module = getModule(); - llvm::Type* argTypes[] = {Type::i256, Type::i256}; + llvm::Type* argTypes[] = {Type::Word, Type::Word}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_dump", module); @@ -37,7 +37,7 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): m_data = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data"); m_data->setUnnamedAddr(true); // Address is not important - m_size = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); + m_size = new llvm::GlobalVariable(*module, Type::Word, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); m_size->setUnnamedAddr(true); // Address is not important llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; @@ -47,14 +47,14 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); m_require = createRequireFunc(_gasMeter, _runtimeManager); - m_loadWord = createFunc(false, Type::i256, _gasMeter); - m_storeWord = createFunc(true, Type::i256, _gasMeter); + m_loadWord = createFunc(false, Type::Word, _gasMeter); + m_storeWord = createFunc(true, Type::Word, _gasMeter); m_storeByte = createFunc(true, Type::Byte, _gasMeter); } llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager) { - llvm::Type* argTypes[] = {Type::i256, Type::i256}; + llvm::Type* argTypes[] = {Type::Word, Type::Word}; auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); auto offset = func->arg_begin(); offset->setName("offset"); @@ -67,9 +67,9 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ InsertPointGuard guard(m_builder); // Restores insert point at function exit - // BB "check" + // BB "Check" m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::i256); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); @@ -78,7 +78,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - // BB "resize" + // BB "Resize" m_builder.SetInsertPoint(resizeBB); // Check gas first uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); @@ -97,7 +97,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ m_builder.CreateStore(newData, m_data); m_builder.CreateBr(returnBB); - // BB "return" + // BB "Return" m_builder.SetInsertPoint(returnBB); m_builder.CreateRetVoid(); return func; @@ -105,11 +105,11 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) { - auto isWord = _valueType == Type::i256; + auto isWord = _valueType == Type::Word; - llvm::Type* storeArgs[] = {Type::i256, _valueType}; + llvm::Type* storeArgs[] = {Type::Word, _valueType}; auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false); + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, Type::Word, false); auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); InsertPointGuard guard(m_builder); // Restores insert point at function exit @@ -185,7 +185,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, llvm::Value* _destMemIdx, llvm::Value* _reqBytes) { - auto zero256 = llvm::ConstantInt::get(Type::i256, 0); + auto zero256 = llvm::ConstantInt::get(Type::Word, 0); require(_destMemIdx, _reqBytes); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 361089ba1..292eb02bd 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -22,7 +22,7 @@ llvm::StructType* RuntimeData::getType() { llvm::Type* elems[] = { - llvm::ArrayType::get(Type::i256, _size), + llvm::ArrayType::get(Type::Word, _size), Type::BytePtr, Type::BytePtr, Type::BytePtr diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index d6538a22d..bb157b847 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -18,7 +18,7 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): CompilerHelper(_builder), m_runtimeManager(_runtimeManager) { - m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg"); + m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg"); using namespace llvm; using Linkage = GlobalValue::LinkageTypes; diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 37757dfdf..a72ec0eda 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -12,7 +12,7 @@ namespace eth namespace jit { -llvm::IntegerType* Type::i256; +llvm::IntegerType* Type::Word; llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Size; @@ -24,8 +24,8 @@ llvm::PointerType* Type::RuntimePtr; void Type::init(llvm::LLVMContext& _context) { - i256 = llvm::Type::getIntNTy(_context, 256); - WordPtr = i256->getPointerTo(); + Word = llvm::Type::getIntNTy(_context, 256); + WordPtr = Word->getPointerTo(); lowPrecision = llvm::Type::getInt64Ty(_context); // TODO: Size should be architecture-dependent Size = llvm::Type::getInt64Ty(_context); @@ -38,14 +38,14 @@ void Type::init(llvm::LLVMContext& _context) llvm::ConstantInt* Constant::get(int64_t _n) { - return llvm::ConstantInt::getSigned(Type::i256, _n); + return llvm::ConstantInt::getSigned(Type::Word, _n); } llvm::ConstantInt* Constant::get(u256 _n) { llvm::APInt n(256, _n.str(0, std::ios_base::hex), 16); assert(n.toString(10, false) == _n.str()); - return static_cast(llvm::ConstantInt::get(Type::i256, n)); + return static_cast(llvm::ConstantInt::get(Type::Word, n)); } llvm::ConstantInt* Constant::get(ReturnCode _returnCode) diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 4658f94bb..0d8c6c530 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -14,7 +14,7 @@ namespace jit struct Type { - static llvm::IntegerType* i256; + static llvm::IntegerType* Word; static llvm::PointerType* WordPtr; /// Type for doing low precision arithmetics where 256-bit precision is not supported by native target From aa3ae144220d9255c158c5012118bac2c8c1109d Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 14:46:32 +0000 Subject: [PATCH 29/36] code cleanup & coding-standardization --- libevmjit/Compiler.cpp | 243 +++++++++++++++++++---------------------- 1 file changed, 112 insertions(+), 131 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1e394eba0..cdb9a6448 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -32,28 +32,27 @@ namespace eth namespace jit { -Compiler::Compiler(): - m_builder(llvm::getGlobalContext()), - m_jumpTableBlock(), - m_badJumpBlock() +Compiler::Compiler(Options const& _options): + m_options(_options), + m_builder(llvm::getGlobalContext()) { Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytesConstRef bytecode) +void Compiler::createBasicBlocks(bytesConstRef _bytecode) { std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end std::map directJumpTargets; std::vector indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); + boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); splitPoints.insert(0); // First basic block validJumpTargets[0] = true; - for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) + for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) { - ProgramCounter currentPC = curr - bytecode.begin(); + ProgramCounter currentPC = curr - _bytecode.begin(); validJumpTargets[currentPC] = true; auto inst = Instruction(*curr); @@ -62,19 +61,19 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) case Instruction::ANY_PUSH: { - auto val = readPushData(curr, bytecode.end()); + auto val = readPushData(curr, _bytecode.end()); auto next = curr + 1; - if (next == bytecode.end()) + if (next == _bytecode.end()) break; auto nextInst = Instruction(*next); if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) { // Create a block for the JUMP target. - ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size(); + ProgramCounter targetPC = val < _bytecode.size() ? val.convert_to() : _bytecode.size(); splitPoints.insert(targetPC); - ProgramCounter jumpPC = (next - bytecode.begin()); + ProgramCounter jumpPC = (next - _bytecode.begin()); directJumpTargets[jumpPC] = targetPC; } break; @@ -83,7 +82,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) case Instruction::JUMPDEST: { // A basic block starts at the next instruction. - if (currentPC + 1 < bytecode.size()) + if (currentPC + 1 < _bytecode.size()) { splitPoints.insert(currentPC + 1); indirectJumpTargets.push_back(currentPC + 1); @@ -98,7 +97,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) case Instruction::SUICIDE: { // Create a basic block starting at the following instruction. - if (curr + 1 < bytecode.end()) + if (curr + 1 < _bytecode.end()) { splitPoints.insert(currentPC + 1); } @@ -113,7 +112,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) // Remove split points generated from jumps out of code or into data. for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) { - if (*it > bytecode.size() || !validJumpTargets[*it]) + if (*it > _bytecode.size() || !validJumpTargets[*it]) it = splitPoints.erase(it); else ++it; @@ -123,7 +122,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) { auto beginInstIdx = *it; ++it; - auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); + auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); } @@ -133,7 +132,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { - if (it->second >= bytecode.size()) + if (it->second >= _bytecode.size()) { // Jumping out of code means STOP m_directJumpTargets[it->first] = m_stopBB; @@ -154,12 +153,10 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) } for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - { m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); - } } -std::unique_ptr Compiler::compile(bytesConstRef bytecode) +std::unique_ptr Compiler::compile(bytesConstRef _bytecode) { auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); @@ -173,7 +170,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - createBasicBlocks(bytecode); + createBasicBlocks(_bytecode); // Init runtime structures. RuntimeManager runtimeManager(m_builder); @@ -191,13 +188,11 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: // TODO: move to separate function. - // Note: Right now the codegen for special blocks depends only on createBasicBlock(), - // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). m_builder.SetInsertPoint(m_stopBB); m_builder.CreateRet(Constant::get(ReturnCode::Stop)); @@ -218,75 +213,59 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) } } else - { m_builder.CreateBr(m_badJumpBlock->llvm()); - } removeDeadBlocks(); - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-init.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter dead block elimination \n\n"; - dump(); - } + dumpCFGifRequired("blocks-init.dot"); - //if (getenv("EVMCC_OPTIMIZE_STACK")) - //{ + if (m_options.optimizeStack) + { std::vector blockList; for (auto& entry : basicBlocks) blockList.push_back(&entry.second); - if (m_jumpTableBlock != nullptr) + if (m_jumpTableBlock) blockList.push_back(m_jumpTableBlock.get()); BasicBlock::linkLocalStacks(blockList, m_builder); - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-opt.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter stack optimization \n\n"; - dump(); - } - //} + dumpCFGifRequired("blocks-opt.dot"); + } for (auto& entry : basicBlocks) entry.second.localStack().synchronize(stack); - if (m_jumpTableBlock != nullptr) + if (m_jumpTableBlock) m_jumpTableBlock->localStack().synchronize(stack); - if (getenv("EVMCC_DEBUG_BLOCKS")) + dumpCFGifRequired("blocks-sync.dot"); + + if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) { - std::ofstream ofs("blocks-sync.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter stack synchronization \n\n"; - dump(); + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); } - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - return module; } -void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Arith256& arith, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, + Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) { - m_builder.SetInsertPoint(basicBlock.llvm()); - auto& stack = basicBlock.localStack(); + if (!_nextBasicBlock) // this is the last block in the code + _nextBasicBlock = m_stopBB; + + m_builder.SetInsertPoint(_basicBlock.llvm()); + auto& stack = _basicBlock.localStack(); - for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) + for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) { - auto inst = static_cast(bytecode[currentPC]); + auto inst = static_cast(_bytecode[currentPC]); - gasMeter.count(inst); + _gasMeter.count(inst); switch (inst) { @@ -313,7 +292,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.mul(lhs, rhs); + auto res = _arith.mul(lhs, rhs); stack.push(res); break; } @@ -322,7 +301,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.div(lhs, rhs); + auto res = _arith.div(lhs, rhs); stack.push(res); break; } @@ -331,7 +310,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.sdiv(lhs, rhs); + auto res = _arith.sdiv(lhs, rhs); stack.push(res); break; } @@ -340,7 +319,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.mod(lhs, rhs); + auto res = _arith.mod(lhs, rhs); stack.push(res); break; } @@ -349,7 +328,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.smod(lhs, rhs); + auto res = _arith.smod(lhs, rhs); stack.push(res); break; } @@ -358,7 +337,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto left = stack.pop(); auto right = stack.pop(); - auto ret = ext.exp(left, right); + auto ret = _ext.exp(left, right); stack.push(ret); break; } @@ -480,7 +459,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto mod = stack.pop(); - auto res = arith.addmod(lhs, rhs, mod); + auto res = _arith.addmod(lhs, rhs, mod); stack.push(res); break; } @@ -490,7 +469,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto mod = stack.pop(); - auto res = arith.mulmod(lhs, rhs, mod); + auto res = _arith.mulmod(lhs, rhs, mod); stack.push(res); break; } @@ -529,8 +508,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto inOff = stack.pop(); auto inSize = stack.pop(); - memory.require(inOff, inSize); - auto hash = ext.sha3(inOff, inSize); + _memory.require(inOff, inSize); + auto hash = _ext.sha3(inOff, inSize); stack.push(hash); break; } @@ -543,9 +522,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_PUSH: { - auto curr = bytecode.begin() + currentPC; // TODO: replace currentPC with iterator - auto value = readPushData(curr, bytecode.end()); - currentPC = curr - bytecode.begin(); + auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator + auto value = readPushData(curr, _bytecode.end()); + currentPC = curr - _bytecode.begin(); stack.push(Constant::get(value)); break; @@ -568,7 +547,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::MLOAD: { auto addr = stack.pop(); - auto word = memory.loadWord(addr); + auto word = _memory.loadWord(addr); stack.push(word); break; } @@ -577,7 +556,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto addr = stack.pop(); auto word = stack.pop(); - memory.storeWord(addr, word); + _memory.storeWord(addr, word); break; } @@ -585,13 +564,13 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto addr = stack.pop(); auto word = stack.pop(); - memory.storeByte(addr, word); + _memory.storeByte(addr, word); break; } case Instruction::MSIZE: { - auto word = memory.getSize(); + auto word = _memory.getSize(); stack.push(word); break; } @@ -599,7 +578,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::SLOAD: { auto index = stack.pop(); - auto value = ext.store(index); + auto value = _ext.store(index); stack.push(value); break; } @@ -608,8 +587,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto index = stack.pop(); auto value = stack.pop(); - gasMeter.countSStore(ext, index, value); - ext.setStore(index, value); + _gasMeter.countSStore(_ext, index, value); + _ext.setStore(index, value); break; } @@ -621,7 +600,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) // Otherwise generate a indirect jump (a switch). llvm::BasicBlock* targetBlock = nullptr; - if (currentPC != basicBlock.begin()) + if (currentPC != _basicBlock.begin()) { auto pairIter = m_directJumpTargets.find(currentPC); if (pairIter != m_directJumpTargets.end()) @@ -647,17 +626,13 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto zero = Constant::get(0); auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - - if (!nextBasicBlock) // In case JUMPI is the last instruction - nextBasicBlock = m_stopBB; - if (targetBlock) { stack.pop(); - m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); + m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); } else - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); } break; @@ -699,7 +674,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::BALANCE: { auto address = stack.pop(); - auto value = ext.balance(address); + auto value = _ext.balance(address); stack.push(value); break; } @@ -707,7 +682,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::EXTCODESIZE: { auto addr = stack.pop(); - auto value = ext.codesizeAt(addr); + auto value = _ext.codesizeAt(addr); stack.push(value); break; } @@ -721,7 +696,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto srcPtr = _runtimeManager.getCallData(); auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; } @@ -734,7 +709,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; } @@ -745,17 +720,17 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto srcPtr = ext.codeAt(extAddr); - auto srcSize = ext.codesizeAt(extAddr); + auto srcPtr = _ext.codeAt(extAddr); + auto srcSize = _ext.codesizeAt(extAddr); - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; } case Instruction::CALLDATALOAD: { auto index = stack.pop(); - auto value = ext.calldataload(index); + auto value = _ext.calldataload(index); stack.push(value); break; } @@ -765,9 +740,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto endowment = stack.pop(); auto initOff = stack.pop(); auto initSize = stack.pop(); - memory.require(initOff, initSize); + _memory.require(initOff, initSize); - auto address = ext.create(endowment, initOff, initSize); + auto address = _ext.create(endowment, initOff, initSize); stack.push(address); break; } @@ -783,21 +758,21 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto outOff = stack.pop(); auto outSize = stack.pop(); - gasMeter.commitCostBlock(gas); + _gasMeter.commitCostBlock(gas); - // Require memory for the max of in and out buffers + // Require _memory for the max of in and out buffers auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); - memory.require(sizeReq); + _memory.require(sizeReq); auto receiveAddress = codeAddress; if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - gasMeter.giveBack(gas); + auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gas); stack.push(ret); break; } @@ -807,7 +782,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto index = stack.pop(); auto size = stack.pop(); - memory.require(index, size); + _memory.require(index, size); _runtimeManager.registerReturnData(index, size); m_builder.CreateRet(Constant::get(ReturnCode::Return)); @@ -815,13 +790,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } case Instruction::SUICIDE: - { - auto address = stack.pop(); - ext.suicide(address); - // Fall through - } case Instruction::STOP: { + if (inst == Instruction::SUICIDE) + { + auto address = stack.pop(); + _ext.suicide(address); + } + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); break; } @@ -834,15 +810,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } } - gasMeter.commitCostBlock(); + _gasMeter.commitCostBlock(); - if (!basicBlock.llvm()->getTerminator()) // If block not terminated - { - if (nextBasicBlock) - m_builder.CreateBr(nextBasicBlock); // Branch to the next block - else - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code - } + // Block may have no terminator if the next instruction is a jump destination. + if (!_basicBlock.llvm()->getTerminator()) + m_builder.CreateBr(_nextBasicBlock); } @@ -877,11 +849,22 @@ void Compiler::removeDeadBlocks() } } -void Compiler::dumpBasicBlockGraph(std::ostream& out) +void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) +{ + if (! m_options.dumpCFG) + return; + + // TODO: handle i/o failures + std::ofstream ofs(_dotfilePath); + dumpCFGtoStream(ofs); + ofs.close(); +} + +void Compiler::dumpCFGtoStream(std::ostream& _out) { - out << "digraph BB {\n" - << " node [shape=record, fontname=Courier, fontsize=10];\n" - << " entry [share=record, label=\"entry block\"];\n"; + _out << "digraph BB {\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; std::vector blocks; for (auto& pair : basicBlocks) @@ -901,7 +884,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) std::ostringstream oss; bb->dump(oss, true); - out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; } // Output edges @@ -912,15 +895,13 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) auto end = llvm::pred_end(bb->llvm()); for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) { - out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" - << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") - //<< "label = \"" - //<< phiNodesPerBlock[bb] - << "];\n"; + _out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + << "];\n"; } } - out << "}\n"; + _out << "}\n"; } void Compiler::dump() From bb4c21e5f3add80b537b222fa0ceeb2a8561d48a Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 14:47:16 +0000 Subject: [PATCH 30/36] allow --jit as non first argument --- test/vm.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 102de7c4f..3fe12dc1f 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -535,7 +535,9 @@ void doTests(json_spirit::mValue& v, bool _fillin) auto argc = boost::unit_test::framework::master_test_suite().argc; auto argv = boost::unit_test::framework::master_test_suite().argv; - auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; + auto useJit = false; + for (auto i = 0; i < argc && !useJit; ++i) + useJit |= std::string(argv[i]) == "--jit"; auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; dev::test::FakeExtVM fev; @@ -585,8 +587,8 @@ void doTests(json_spirit::mValue& v, bool _fillin) cnote << "Execution time: " << std::chrono::duration_cast(testDuration).count() << " ms"; + break; } - break; } auto gas = vm->gas(); @@ -826,7 +828,7 @@ BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) BOOST_AUTO_TEST_CASE(userDefinedFile) { - if (boost::unit_test::framework::master_test_suite().argc == 2) + if (boost::unit_test::framework::master_test_suite().argc >= 2) { string filename = boost::unit_test::framework::master_test_suite().argv[1]; int currentVerbosity = g_logVerbosity; From a19f3df3b39515bbc84599a4cfe925c254323af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:50:03 +0100 Subject: [PATCH 31/36] Coding style: use "o_" prefix for output function arguments --- libevmjit/Arith256.cpp | 28 ++++++++++++++-------------- libevmjit/Ext.cpp | 40 ++++++++++++++++++++-------------------- libevmjit/Memory.cpp | 4 +--- libevmjit/Stack.cpp | 8 ++++---- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 82e31e61d..79a8fe79c 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -103,55 +103,55 @@ extern "C" using namespace dev::eth::jit; - EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* _result) + EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg1 * arg2); + *o_result = eth2llvm(arg1 * arg2); } - EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* _result) + EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); + *o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); } - EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* _result) + EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); + *o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); } - EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* _result) + EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2))); + *o_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2))); } - EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* _result) + EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(arg2))); + *o_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(arg2))); } - EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result) + EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg3 = llvm2eth(*_arg3); - *_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3)); + *o_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3)); } - EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result) + EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg3 = llvm2eth(*_arg3); - *_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % arg3)); + *o_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % arg3)); } } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 0fe795a1f..f39ab5755 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -168,11 +168,11 @@ extern "C" using namespace dev::eth::jit; - EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value) + EXPORT void ext_store(Runtime* _rt, i256* _index, i256* o_value) { auto index = llvm2eth(*_index); auto value = _rt->getExt().store(index); // Interface uses native endianness - *_value = eth2llvm(value); + *o_value = eth2llvm(value); } EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value) @@ -187,28 +187,28 @@ extern "C" ext.setStore(index, value); // Interface uses native endianness } - EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) + EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* o_value) { auto index = static_cast(llvm2eth(*_index)); assert(index + 31 > index); // TODO: Handle large index - auto b = reinterpret_cast(_value); + auto b = reinterpret_cast(o_value); for (size_t i = index, j = 0; i <= index + 31; ++i, ++j) b[j] = i < _rt->getExt().data.size() ? _rt->getExt().data[i] : 0; // Keep Big Endian // TODO: It all can be done by adding padding to data or by using min() algorithm without branch } - EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value) + EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* o_value) { auto u = _rt->getExt().balance(right160(*_address)); - *_value = eth2llvm(u); + *o_value = eth2llvm(u); } - EXPORT void ext_suicide(Runtime* _rt, h256* _address) + EXPORT void ext_suicide(Runtime* _rt, h256 const* _address) { _rt->getExt().suicide(right160(*_address)); } - EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) + EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* o_address) { auto&& ext = _rt->getExt(); auto endowment = llvm2eth(*_endowment); @@ -222,21 +222,21 @@ extern "C" auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize); OnOpFunc onOp {}; // TODO: Handle that thing h256 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight); - *_address = address; + *o_address = address; } else - *_address = {}; + *o_address = {}; } - EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret) + EXPORT void ext_call(Runtime* _rt, i256* io_gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* o_ret) { auto&& ext = _rt->getExt(); auto value = llvm2eth(*_value); auto ret = false; - auto gas = llvm2eth(*_gas); + auto gas = llvm2eth(*io_gas); if (ext.balance(ext.myAddress) >= value) { ext.subBalance(value); @@ -252,25 +252,25 @@ extern "C" ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); } - *_gas = eth2llvm(gas); - _ret->a = ret ? 1 : 0; + *io_gas = eth2llvm(gas); + o_ret->a = ret ? 1 : 0; } - EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) + EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* o_ret) { auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); auto hash = sha3(dataRef); - *_ret = *reinterpret_cast(&hash); + *o_ret = *reinterpret_cast(&hash); } - EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* _ret) + EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* o_ret) { bigint left = llvm2eth(*_left); bigint right = llvm2eth(*_right); auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); - *_ret = eth2llvm(ret); + *o_ret = eth2llvm(ret); } EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) @@ -281,12 +281,12 @@ extern "C" return const_cast(code.data()); } - EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) + EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* o_ret) { auto&& ext = _rt->getExt(); auto addr = right160(*_addr256); auto& code = ext.codeAt(addr); - *_ret = eth2llvm(u256(code.size())); + *o_ret = eth2llvm(u256(code.size())); } } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c06b22637..c3e904ef8 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -224,7 +224,6 @@ void Memory::dump(uint64_t _begin, uint64_t _end) extern "C" { - using namespace dev::eth::jit; EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size) @@ -234,5 +233,4 @@ extern "C" memory.resize(size); return memory.data(); } - -} // extern "C" +} diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index bb157b847..494750b43 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -79,7 +79,7 @@ extern "C" stack.erase(stack.end() - _count, stack.end()); } - EXPORT void stack_push(Runtime* _rt, i256* _word) + EXPORT void stack_push(Runtime* _rt, i256 const* _word) { auto& stack = _rt->getStack(); stack.push_back(*_word); @@ -88,17 +88,17 @@ extern "C" Stack::maxStackSize = stack.size(); } - EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret) + EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) { auto& stack = _rt->getStack(); // TODO: encode _index and stack size in the return code if (stack.size() <= _index) longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - *_ret = *(stack.rbegin() + _index); + *o_ret = *(stack.rbegin() + _index); } - EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word) + EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) { auto& stack = _rt->getStack(); // TODO: encode _index and stack size in the return code From c52fd78fb66d63bb292123f7e617845201b92625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:57:54 +0100 Subject: [PATCH 32/36] Use llvm.longjmp intrinsic for longjmp [Delivers #81792986] --- libevmjit/Runtime.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 292eb02bd..96a5f75a3 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -105,7 +106,7 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui { m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; - m_longjmp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", getModule()); + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); // Export data auto mainFunc = getMainFunction(); From 44a9ea0fb850378bfd8e7d0ea843892762a410a9 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:46:05 +0000 Subject: [PATCH 33/36] code cleanup and coding-standardization --- libevmjit/Compiler.cpp | 4 +- libevmjit/Compiler.cpp.orig | 924 ++++++++++++++++++++++++++++++++++++ libevmjit/Compiler.h | 69 +-- libevmjit/VM.cpp | 3 +- 4 files changed, 970 insertions(+), 30 deletions(-) create mode 100644 libevmjit/Compiler.cpp.orig diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 6b0d5f2e1..928baee22 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -761,8 +761,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod _gasMeter.commitCostBlock(gas); // Require memory for in and out buffers - memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one - memory.require(inOff, inSize); + _memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one + _memory.require(inOff, inSize); auto receiveAddress = codeAddress; if (inst == Instruction::CALLCODE) diff --git a/libevmjit/Compiler.cpp.orig b/libevmjit/Compiler.cpp.orig new file mode 100644 index 000000000..9c6043ff2 --- /dev/null +++ b/libevmjit/Compiler.cpp.orig @@ -0,0 +1,924 @@ + +#include "Compiler.h" + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "Type.h" +#include "Memory.h" +#include "Stack.h" +#include "Ext.h" +#include "GasMeter.h" +#include "Utils.h" +#include "Endianness.h" +#include "Arith256.h" +#include "Runtime.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Compiler::Compiler(Options const& _options): + m_options(_options), + m_builder(llvm::getGlobalContext()) +{ + Type::init(m_builder.getContext()); +} + +void Compiler::createBasicBlocks(bytesConstRef _bytecode) +{ + std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end + + std::map directJumpTargets; + std::vector indirectJumpTargets; + boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); + + splitPoints.insert(0); // First basic block + validJumpTargets[0] = true; + + for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) + { + ProgramCounter currentPC = curr - _bytecode.begin(); + validJumpTargets[currentPC] = true; + + auto inst = Instruction(*curr); + switch (inst) + { + + case Instruction::ANY_PUSH: + { + auto val = readPushData(curr, _bytecode.end()); + auto next = curr + 1; + if (next == _bytecode.end()) + break; + + auto nextInst = Instruction(*next); + if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) + { + // Create a block for the JUMP target. + ProgramCounter targetPC = val < _bytecode.size() ? val.convert_to() : _bytecode.size(); + splitPoints.insert(targetPC); + + ProgramCounter jumpPC = (next - _bytecode.begin()); + directJumpTargets[jumpPC] = targetPC; + } + break; + } + + case Instruction::JUMPDEST: + { + // A basic block starts at the next instruction. + if (currentPC + 1 < _bytecode.size()) + { + splitPoints.insert(currentPC + 1); + indirectJumpTargets.push_back(currentPC + 1); + } + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::RETURN: + case Instruction::STOP: + case Instruction::SUICIDE: + { + // Create a basic block starting at the following instruction. + if (curr + 1 < _bytecode.end()) + { + splitPoints.insert(currentPC + 1); + } + break; + } + + default: + break; + } + } + + // Remove split points generated from jumps out of code or into data. + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + if (*it > _bytecode.size() || !validJumpTargets[*it]) + it = splitPoints.erase(it); + else + ++it; + } + + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + auto beginInstIdx = *it; + ++it; + auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); + basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); + } + + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); + m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); + + for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) + { + if (it->second >= _bytecode.size()) + { + // Jumping out of code means STOP + m_directJumpTargets[it->first] = m_stopBB; + continue; + } + + auto blockIter = basicBlocks.find(it->second); + if (blockIter != basicBlocks.end()) + { + m_directJumpTargets[it->first] = blockIter->second.llvm(); + } + else + { + clog(JIT) << "Bad JUMP at PC " << it->first + << ": " << it->second << " is not a valid PC"; + m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); + } + } + + for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) + m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); +} + +std::unique_ptr Compiler::compile(bytesConstRef _bytecode) +{ + auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); + + // Create main function + llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures + auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false); + m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); + m_mainFunc->arg_begin()->getNextNode()->setName("rt"); + + // Create the basic blocks. + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + m_builder.SetInsertPoint(entryBlock); + + createBasicBlocks(_bytecode); + + // Init runtime structures. + RuntimeManager runtimeManager(m_builder); + GasMeter gasMeter(m_builder, runtimeManager); + Memory memory(runtimeManager, gasMeter); + Ext ext(runtimeManager); + Stack stack(m_builder, runtimeManager); + Arith256 arith(m_builder); + + m_builder.CreateBr(basicBlocks.begin()->second); + + for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) + { + auto& basicBlock = basicBlockPairIt->second; + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + } + + // Code for special blocks: + // TODO: move to separate function. + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + if (m_indirectJumpTargets.size() > 0) + { + auto dest = m_jumpTableBlock->localStack().pop(); + auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), + m_indirectJumpTargets.size()); + for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) + { + auto& bb = *it; + auto dest = Constant::get(bb->begin()); + switchInstr->addCase(dest, bb->llvm()); + } + } + else + m_builder.CreateBr(m_badJumpBlock->llvm()); + + removeDeadBlocks(); + + dumpCFGifRequired("blocks-init.dot"); + + if (m_options.optimizeStack) + { + std::vector blockList; + for (auto& entry : basicBlocks) + blockList.push_back(&entry.second); + + if (m_jumpTableBlock) + blockList.push_back(m_jumpTableBlock.get()); + + BasicBlock::linkLocalStacks(blockList, m_builder); + + dumpCFGifRequired("blocks-opt.dot"); + } + + for (auto& entry : basicBlocks) + entry.second.localStack().synchronize(stack); + if (m_jumpTableBlock) + m_jumpTableBlock->localStack().synchronize(stack); + + dumpCFGifRequired("blocks-sync.dot"); + + if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) + { + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); + } + + return module; +} + + +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, + Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) +{ + if (!_nextBasicBlock) // this is the last block in the code + _nextBasicBlock = m_stopBB; + + m_builder.SetInsertPoint(_basicBlock.llvm()); + auto& stack = _basicBlock.localStack(); + + for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) + { + auto inst = static_cast(_bytecode[currentPC]); + + _gasMeter.count(inst); + + switch (inst) + { + + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::MUL: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.mul(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::DIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.div(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SDIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.sdiv(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::MOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.mod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.smod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::EXP: + { + auto left = stack.pop(); + auto right = stack.pop(); + auto ret = _ext.exp(left, right); + stack.push(ret); + break; + } + + case Instruction::BNOT: + { + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); + stack.push(ret); + break; + } + + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::NOT: + { + auto top = stack.pop(); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::i256); + stack.push(result); + break; + } + + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::BYTE: + { + const auto byteNum = stack.pop(); + auto value = stack.pop(); + + // + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::i256); + + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); + stack.push(value); + + break; + } + + case Instruction::ADDMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.addmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::MULMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.mulmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::SIGNEXTEND: + { + auto idx = stack.pop(); + auto word = stack.pop(); + + auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32"); + auto k32 = m_builder.CreateZExt(k32_, Type::i256); + auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8"); + + // test for word >> (k * 8 + 7) + auto bitpos = m_builder.CreateAdd(k32x8, Constant::get(7), "bitpos"); + auto bitval = m_builder.CreateLShr(word, bitpos, "bitval"); + auto bittest = m_builder.CreateTrunc(bitval, m_builder.getInt1Ty(), "bittest"); + + auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos); + auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); + + auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::i256), "negmask"); + auto val1 = m_builder.CreateOr(word, negmask); + auto val0 = m_builder.CreateAnd(word, mask); + + auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::i256, 30)); + auto result = m_builder.CreateSelect(kInRange, + m_builder.CreateSelect(bittest, val1, val0), + word); + stack.push(result); + + break; + } + + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + _memory.require(inOff, inSize); + auto hash = _ext.sha3(inOff, inSize); + stack.push(hash); + break; + } + + case Instruction::POP: + { + stack.pop(); + break; + } + + case Instruction::ANY_PUSH: + { + auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator + auto value = readPushData(curr, _bytecode.end()); + currentPC = curr - _bytecode.begin(); + + stack.push(Constant::get(value)); + break; + } + + case Instruction::ANY_DUP: + { + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + stack.dup(index); + break; + } + + case Instruction::ANY_SWAP: + { + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } + + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = _memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = _memory.getSize(); + stack.push(word); + break; + } + + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = _ext.store(index); + stack.push(value); + break; + } + + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + _gasMeter.countSStore(_ext, index, value); + _ext.setStore(index, value); + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + { + // Generate direct jump iff: + // 1. this is not the first instruction in the block + // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) + // Otherwise generate a indirect jump (a switch). + llvm::BasicBlock* targetBlock = nullptr; + if (currentPC != _basicBlock.begin()) + { + auto pairIter = m_directJumpTargets.find(currentPC); + if (pairIter != m_directJumpTargets.end()) + targetBlock = pairIter->second; + } + + if (inst == Instruction::JUMP) + { + if (targetBlock) + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + m_builder.CreateBr(targetBlock); + } + else + m_builder.CreateBr(m_jumpTableBlock->llvm()); + } + else // JUMPI + { + stack.swap(1); + auto val = stack.pop(); + auto zero = Constant::get(0); + auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); + + if (targetBlock) + { + stack.pop(); + m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); + } + else + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); + } + + break; + } + + case Instruction::JUMPDEST: + { + // Nothing to do + break; + } + + case Instruction::PC: + { + auto value = Constant::get(currentPC); + stack.push(value); + break; + } + + case Instruction::GAS: + case Instruction::ADDRESS: + case Instruction::CALLER: + case Instruction::ORIGIN: + case Instruction::CALLVALUE: + case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::GASPRICE: + case Instruction::PREVHASH: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + { + // Pushes an element of runtime data on stack + stack.push(_runtimeManager.get(inst)); + break; + } + + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = _ext.balance(address); + stack.push(value); + break; + } + + case Instruction::EXTCODESIZE: + { + auto addr = stack.pop(); + auto value = _ext.codesizeAt(addr); + stack.push(value); + break; + } + + case Instruction::CALLDATACOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCallData(); + auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 + auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::EXTCODECOPY: + { + auto extAddr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _ext.codeAt(extAddr); + auto srcSize = _ext.codesizeAt(extAddr); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = _ext.calldataload(index); + stack.push(value); + break; + } + + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + _memory.require(initOff, initSize); + + auto address = _ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } + + case Instruction::CALL: + case Instruction::CALLCODE: + { + auto gas = stack.pop(); + auto codeAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + _gasMeter.commitCostBlock(gas); + +<<<<<<< HEAD + // Require _memory for the max of in and out buffers + auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); + auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); + auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); + auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); + _memory.require(sizeReq); +======= + // Require memory for in and out buffers + memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one + memory.require(inOff, inSize); +>>>>>>> ec07859aedd18ebfd9b40cfa2a182e49c5b3f30a + + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = _runtimeManager.get(RuntimeData::Address); + + auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gas); + stack.push(ret); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + _memory.require(index, size); + _runtimeManager.registerReturnData(index, size); + + m_builder.CreateRet(Constant::get(ReturnCode::Return)); + break; + } + + case Instruction::SUICIDE: + case Instruction::STOP: + { + if (inst == Instruction::SUICIDE) + { + auto address = stack.pop(); + _ext.suicide(address); + } + + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + break; + } + + default: // Invalid instruction - runtime exception + { + _runtimeManager.raiseException(ReturnCode::BadInstruction); + } + + } + } + + _gasMeter.commitCostBlock(); + + // Block may have no terminator if the next instruction is a jump destination. + if (!_basicBlock.llvm()->getTerminator()) + m_builder.CreateBr(_nextBasicBlock); +} + + + +void Compiler::removeDeadBlocks() +{ + // Remove dead basic blocks + auto sthErased = false; + do + { + sthErased = false; + for (auto it = basicBlocks.begin(); it != basicBlocks.end();) + { + auto llvmBB = it->second.llvm(); + if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) + { + llvmBB->eraseFromParent(); + basicBlocks.erase(it++); + sthErased = true; + } + else + ++it; + } + } + while (sthErased); + + // Remove jump table block if no predecessors + if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } +} + +void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) +{ + if (! m_options.dumpCFG) + return; + + // TODO: handle i/o failures + std::ofstream ofs(_dotfilePath); + dumpCFGtoStream(ofs); + ofs.close(); +} + +void Compiler::dumpCFGtoStream(std::ostream& _out) +{ + _out << "digraph BB {\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; + + std::vector blocks; + for (auto& pair : basicBlocks) + blocks.push_back(&pair.second); + if (m_jumpTableBlock) + blocks.push_back(m_jumpTableBlock.get()); + if (m_badJumpBlock) + blocks.push_back(m_badJumpBlock.get()); + + // std::map phiNodesPerBlock; + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + std::ostringstream oss; + bb->dump(oss, true); + + _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + } + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::pred_end(bb->llvm()); + for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) + { + _out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + << "];\n"; + } + } + + _out << "}\n"; +} + +void Compiler::dump() +{ + for (auto& entry : basicBlocks) + entry.second.dump(); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->dump(); +} + +} +} +} + diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index d58745a06..12b7f6e0e 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -18,55 +18,70 @@ class Compiler { public: - using ProgramCounter = uint64_t; + struct Options + { + /// Optimize stack operations between basic blocks + bool optimizeStack; + + /// Rewrite switch instructions to sequences of branches + bool rewriteSwitchToBranches; - Compiler(); + /// Dump CFG as a .dot file for graphviz + bool dumpCFG; - std::unique_ptr compile(bytesConstRef bytecode); + Options(): + optimizeStack(true), + rewriteSwitchToBranches(true), + dumpCFG(false) + {} + }; + + using ProgramCounter = uint64_t; - void dumpBasicBlockGraph(std::ostream& out); + Compiler(Options const& _options); + std::unique_ptr compile(bytesConstRef _bytecode); private: - void createBasicBlocks(bytesConstRef bytecode); + void createBasicBlocks(bytesConstRef _bytecode); - void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class RuntimeManager& _runtimeManager, class Arith256& arith, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); void removeDeadBlocks(); - /// Dump all basic blocks to stderr. Useful in a debugging session. + /// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled. + void dumpCFGifRequired(std::string const& _dotfilePath); + + /// Dumps basic block graph in graphviz format to a stream. + void dumpCFGtoStream(std::ostream& _out); + + /// Dumps all basic blocks to stderr. Useful in a debugging session. void dump(); + /// Compiler options + Options const& m_options; + + /// Helper class for generating IR llvm::IRBuilder<> m_builder; - /** - * Maps a program counter pc to a basic block that starts at pc (if any). - */ - std::map basicBlocks; + /// Maps a program counter pc to a basic block that starts at pc (if any). + std::map basicBlocks = {}; - /** - * Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. - */ - std::map m_directJumpTargets; + /// Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. + std::map m_directJumpTargets = {}; - /** - * A list of possible blocks to which there may be indirect jumps. - */ - std::vector m_indirectJumpTargets; + /// A list of possible blocks to which there may be indirect jumps. + std::vector m_indirectJumpTargets = {}; /// Stop basic block - terminates execution with STOP code (0) llvm::BasicBlock* m_stopBB = nullptr; - /** - * Block with a jump table. - */ - std::unique_ptr m_jumpTableBlock; + /// Block with a jump table. + std::unique_ptr m_jumpTableBlock = nullptr; - /** - * Default destination for indirect jumps. - */ - std::unique_ptr m_badJumpBlock; + /// Default destination for indirect jumps. + std::unique_ptr m_badJumpBlock = nullptr; /// Main program function llvm::Function* m_mainFunc = nullptr; diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index b42b09499..f60dbe783 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -16,7 +16,8 @@ namespace jit bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { - auto module = Compiler().compile(_ext.code); + Compiler::Options defaultOptions; + auto module = Compiler(defaultOptions).compile(_ext.code); ExecutionEngine engine; auto exitCode = engine.run(std::move(module), m_gas, &_ext); From 11d78d44b13c34c8121cd5e9e48052cca24944cf Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:46:44 +0000 Subject: [PATCH 34/36] removed *.orig file --- libevmjit/Compiler.cpp.orig | 924 ------------------------------------ 1 file changed, 924 deletions(-) delete mode 100644 libevmjit/Compiler.cpp.orig diff --git a/libevmjit/Compiler.cpp.orig b/libevmjit/Compiler.cpp.orig deleted file mode 100644 index 9c6043ff2..000000000 --- a/libevmjit/Compiler.cpp.orig +++ /dev/null @@ -1,924 +0,0 @@ - -#include "Compiler.h" - -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include "Type.h" -#include "Memory.h" -#include "Stack.h" -#include "Ext.h" -#include "GasMeter.h" -#include "Utils.h" -#include "Endianness.h" -#include "Arith256.h" -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Compiler::Compiler(Options const& _options): - m_options(_options), - m_builder(llvm::getGlobalContext()) -{ - Type::init(m_builder.getContext()); -} - -void Compiler::createBasicBlocks(bytesConstRef _bytecode) -{ - std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end - - std::map directJumpTargets; - std::vector indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); - - splitPoints.insert(0); // First basic block - validJumpTargets[0] = true; - - for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) - { - ProgramCounter currentPC = curr - _bytecode.begin(); - validJumpTargets[currentPC] = true; - - auto inst = Instruction(*curr); - switch (inst) - { - - case Instruction::ANY_PUSH: - { - auto val = readPushData(curr, _bytecode.end()); - auto next = curr + 1; - if (next == _bytecode.end()) - break; - - auto nextInst = Instruction(*next); - if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) - { - // Create a block for the JUMP target. - ProgramCounter targetPC = val < _bytecode.size() ? val.convert_to() : _bytecode.size(); - splitPoints.insert(targetPC); - - ProgramCounter jumpPC = (next - _bytecode.begin()); - directJumpTargets[jumpPC] = targetPC; - } - break; - } - - case Instruction::JUMPDEST: - { - // A basic block starts at the next instruction. - if (currentPC + 1 < _bytecode.size()) - { - splitPoints.insert(currentPC + 1); - indirectJumpTargets.push_back(currentPC + 1); - } - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - case Instruction::RETURN: - case Instruction::STOP: - case Instruction::SUICIDE: - { - // Create a basic block starting at the following instruction. - if (curr + 1 < _bytecode.end()) - { - splitPoints.insert(currentPC + 1); - } - break; - } - - default: - break; - } - } - - // Remove split points generated from jumps out of code or into data. - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - if (*it > _bytecode.size() || !validJumpTargets[*it]) - it = splitPoints.erase(it); - else - ++it; - } - - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - auto beginInstIdx = *it; - ++it; - auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); - basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); - } - - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); - m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); - - for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) - { - if (it->second >= _bytecode.size()) - { - // Jumping out of code means STOP - m_directJumpTargets[it->first] = m_stopBB; - continue; - } - - auto blockIter = basicBlocks.find(it->second); - if (blockIter != basicBlocks.end()) - { - m_directJumpTargets[it->first] = blockIter->second.llvm(); - } - else - { - clog(JIT) << "Bad JUMP at PC " << it->first - << ": " << it->second << " is not a valid PC"; - m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); - } - } - - for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); -} - -std::unique_ptr Compiler::compile(bytesConstRef _bytecode) -{ - auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); - - // Create main function - llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures - auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false); - m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); - m_mainFunc->arg_begin()->getNextNode()->setName("rt"); - - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); - m_builder.SetInsertPoint(entryBlock); - - createBasicBlocks(_bytecode); - - // Init runtime structures. - RuntimeManager runtimeManager(m_builder); - GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(runtimeManager, gasMeter); - Ext ext(runtimeManager); - Stack stack(m_builder, runtimeManager); - Arith256 arith(m_builder); - - m_builder.CreateBr(basicBlocks.begin()->second); - - for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) - { - auto& basicBlock = basicBlockPairIt->second; - auto iterCopy = basicBlockPairIt; - ++iterCopy; - auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); - } - - // Code for special blocks: - // TODO: move to separate function. - m_builder.SetInsertPoint(m_stopBB); - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - - m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - - m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_indirectJumpTargets.size() > 0) - { - auto dest = m_jumpTableBlock->localStack().pop(); - auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), - m_indirectJumpTargets.size()); - for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) - { - auto& bb = *it; - auto dest = Constant::get(bb->begin()); - switchInstr->addCase(dest, bb->llvm()); - } - } - else - m_builder.CreateBr(m_badJumpBlock->llvm()); - - removeDeadBlocks(); - - dumpCFGifRequired("blocks-init.dot"); - - if (m_options.optimizeStack) - { - std::vector blockList; - for (auto& entry : basicBlocks) - blockList.push_back(&entry.second); - - if (m_jumpTableBlock) - blockList.push_back(m_jumpTableBlock.get()); - - BasicBlock::linkLocalStacks(blockList, m_builder); - - dumpCFGifRequired("blocks-opt.dot"); - } - - for (auto& entry : basicBlocks) - entry.second.localStack().synchronize(stack); - if (m_jumpTableBlock) - m_jumpTableBlock->localStack().synchronize(stack); - - dumpCFGifRequired("blocks-sync.dot"); - - if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) - { - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - } - - return module; -} - - -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, - Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) -{ - if (!_nextBasicBlock) // this is the last block in the code - _nextBasicBlock = m_stopBB; - - m_builder.SetInsertPoint(_basicBlock.llvm()); - auto& stack = _basicBlock.localStack(); - - for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) - { - auto inst = static_cast(_bytecode[currentPC]); - - _gasMeter.count(inst); - - switch (inst) - { - - case Instruction::ADD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateAdd(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::SUB: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateSub(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::MUL: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.mul(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::DIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.div(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SDIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.sdiv(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::MOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.mod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.smod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::EXP: - { - auto left = stack.pop(); - auto right = stack.pop(); - auto ret = _ext.exp(left, right); - stack.push(ret); - break; - } - - case Instruction::BNOT: - { - auto value = stack.pop(); - auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); - stack.push(ret); - break; - } - - case Instruction::LT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpULT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::GT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpUGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::SLT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSLT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::SGT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::EQ: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpEQ(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::NOT: - { - auto top = stack.pop(); - auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); - auto result = m_builder.CreateZExt(iszero, Type::i256); - stack.push(result); - break; - } - - case Instruction::AND: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateAnd(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::OR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateOr(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::XOR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateXor(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::BYTE: - { - const auto byteNum = stack.pop(); - auto value = stack.pop(); - - // - value = Endianness::toBE(m_builder, value); - auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); - auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); - value = m_builder.CreateZExt(byte, Type::i256); - - auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); - value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); - stack.push(value); - - break; - } - - case Instruction::ADDMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = _arith.addmod(lhs, rhs, mod); - stack.push(res); - break; - } - - case Instruction::MULMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = _arith.mulmod(lhs, rhs, mod); - stack.push(res); - break; - } - - case Instruction::SIGNEXTEND: - { - auto idx = stack.pop(); - auto word = stack.pop(); - - auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32"); - auto k32 = m_builder.CreateZExt(k32_, Type::i256); - auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8"); - - // test for word >> (k * 8 + 7) - auto bitpos = m_builder.CreateAdd(k32x8, Constant::get(7), "bitpos"); - auto bitval = m_builder.CreateLShr(word, bitpos, "bitval"); - auto bittest = m_builder.CreateTrunc(bitval, m_builder.getInt1Ty(), "bittest"); - - auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos); - auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); - - auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::i256), "negmask"); - auto val1 = m_builder.CreateOr(word, negmask); - auto val0 = m_builder.CreateAnd(word, mask); - - auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::i256, 30)); - auto result = m_builder.CreateSelect(kInRange, - m_builder.CreateSelect(bittest, val1, val0), - word); - stack.push(result); - - break; - } - - case Instruction::SHA3: - { - auto inOff = stack.pop(); - auto inSize = stack.pop(); - _memory.require(inOff, inSize); - auto hash = _ext.sha3(inOff, inSize); - stack.push(hash); - break; - } - - case Instruction::POP: - { - stack.pop(); - break; - } - - case Instruction::ANY_PUSH: - { - auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator - auto value = readPushData(curr, _bytecode.end()); - currentPC = curr - _bytecode.begin(); - - stack.push(Constant::get(value)); - break; - } - - case Instruction::ANY_DUP: - { - auto index = static_cast(inst) - static_cast(Instruction::DUP1); - stack.dup(index); - break; - } - - case Instruction::ANY_SWAP: - { - auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; - stack.swap(index); - break; - } - - case Instruction::MLOAD: - { - auto addr = stack.pop(); - auto word = _memory.loadWord(addr); - stack.push(word); - break; - } - - case Instruction::MSTORE: - { - auto addr = stack.pop(); - auto word = stack.pop(); - _memory.storeWord(addr, word); - break; - } - - case Instruction::MSTORE8: - { - auto addr = stack.pop(); - auto word = stack.pop(); - _memory.storeByte(addr, word); - break; - } - - case Instruction::MSIZE: - { - auto word = _memory.getSize(); - stack.push(word); - break; - } - - case Instruction::SLOAD: - { - auto index = stack.pop(); - auto value = _ext.store(index); - stack.push(value); - break; - } - - case Instruction::SSTORE: - { - auto index = stack.pop(); - auto value = stack.pop(); - _gasMeter.countSStore(_ext, index, value); - _ext.setStore(index, value); - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - { - // Generate direct jump iff: - // 1. this is not the first instruction in the block - // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) - // Otherwise generate a indirect jump (a switch). - llvm::BasicBlock* targetBlock = nullptr; - if (currentPC != _basicBlock.begin()) - { - auto pairIter = m_directJumpTargets.find(currentPC); - if (pairIter != m_directJumpTargets.end()) - targetBlock = pairIter->second; - } - - if (inst == Instruction::JUMP) - { - if (targetBlock) - { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - m_builder.CreateBr(targetBlock); - } - else - m_builder.CreateBr(m_jumpTableBlock->llvm()); - } - else // JUMPI - { - stack.swap(1); - auto val = stack.pop(); - auto zero = Constant::get(0); - auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - - if (targetBlock) - { - stack.pop(); - m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); - } - else - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); - } - - break; - } - - case Instruction::JUMPDEST: - { - // Nothing to do - break; - } - - case Instruction::PC: - { - auto value = Constant::get(currentPC); - stack.push(value); - break; - } - - case Instruction::GAS: - case Instruction::ADDRESS: - case Instruction::CALLER: - case Instruction::ORIGIN: - case Instruction::CALLVALUE: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::GASPRICE: - case Instruction::PREVHASH: - case Instruction::COINBASE: - case Instruction::TIMESTAMP: - case Instruction::NUMBER: - case Instruction::DIFFICULTY: - case Instruction::GASLIMIT: - { - // Pushes an element of runtime data on stack - stack.push(_runtimeManager.get(inst)); - break; - } - - case Instruction::BALANCE: - { - auto address = stack.pop(); - auto value = _ext.balance(address); - stack.push(value); - break; - } - - case Instruction::EXTCODESIZE: - { - auto addr = stack.pop(); - auto value = _ext.codesizeAt(addr); - stack.push(value); - break; - } - - case Instruction::CALLDATACOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _runtimeManager.getCallData(); - auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); - - _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CODECOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 - auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); - - _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::EXTCODECOPY: - { - auto extAddr = stack.pop(); - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _ext.codeAt(extAddr); - auto srcSize = _ext.codesizeAt(extAddr); - - _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CALLDATALOAD: - { - auto index = stack.pop(); - auto value = _ext.calldataload(index); - stack.push(value); - break; - } - - case Instruction::CREATE: - { - auto endowment = stack.pop(); - auto initOff = stack.pop(); - auto initSize = stack.pop(); - _memory.require(initOff, initSize); - - auto address = _ext.create(endowment, initOff, initSize); - stack.push(address); - break; - } - - case Instruction::CALL: - case Instruction::CALLCODE: - { - auto gas = stack.pop(); - auto codeAddress = stack.pop(); - auto value = stack.pop(); - auto inOff = stack.pop(); - auto inSize = stack.pop(); - auto outOff = stack.pop(); - auto outSize = stack.pop(); - - _gasMeter.commitCostBlock(gas); - -<<<<<<< HEAD - // Require _memory for the max of in and out buffers - auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); - auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); - auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); - auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); - _memory.require(sizeReq); -======= - // Require memory for in and out buffers - memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one - memory.require(inOff, inSize); ->>>>>>> ec07859aedd18ebfd9b40cfa2a182e49c5b3f30a - - auto receiveAddress = codeAddress; - if (inst == Instruction::CALLCODE) - receiveAddress = _runtimeManager.get(RuntimeData::Address); - - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); - stack.push(ret); - break; - } - - case Instruction::RETURN: - { - auto index = stack.pop(); - auto size = stack.pop(); - - _memory.require(index, size); - _runtimeManager.registerReturnData(index, size); - - m_builder.CreateRet(Constant::get(ReturnCode::Return)); - break; - } - - case Instruction::SUICIDE: - case Instruction::STOP: - { - if (inst == Instruction::SUICIDE) - { - auto address = stack.pop(); - _ext.suicide(address); - } - - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - break; - } - - default: // Invalid instruction - runtime exception - { - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - - } - } - - _gasMeter.commitCostBlock(); - - // Block may have no terminator if the next instruction is a jump destination. - if (!_basicBlock.llvm()->getTerminator()) - m_builder.CreateBr(_nextBasicBlock); -} - - - -void Compiler::removeDeadBlocks() -{ - // Remove dead basic blocks - auto sthErased = false; - do - { - sthErased = false; - for (auto it = basicBlocks.begin(); it != basicBlocks.end();) - { - auto llvmBB = it->second.llvm(); - if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) - { - llvmBB->eraseFromParent(); - basicBlocks.erase(it++); - sthErased = true; - } - else - ++it; - } - } - while (sthErased); - - // Remove jump table block if no predecessors - if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) - { - m_jumpTableBlock->llvm()->eraseFromParent(); - m_jumpTableBlock.reset(); - } -} - -void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) -{ - if (! m_options.dumpCFG) - return; - - // TODO: handle i/o failures - std::ofstream ofs(_dotfilePath); - dumpCFGtoStream(ofs); - ofs.close(); -} - -void Compiler::dumpCFGtoStream(std::ostream& _out) -{ - _out << "digraph BB {\n" - << " node [shape=record, fontname=Courier, fontsize=10];\n" - << " entry [share=record, label=\"entry block\"];\n"; - - std::vector blocks; - for (auto& pair : basicBlocks) - blocks.push_back(&pair.second); - if (m_jumpTableBlock) - blocks.push_back(m_jumpTableBlock.get()); - if (m_badJumpBlock) - blocks.push_back(m_badJumpBlock.get()); - - // std::map phiNodesPerBlock; - - // Output nodes - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - std::ostringstream oss; - bb->dump(oss, true); - - _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; - } - - // Output edges - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - auto end = llvm::pred_end(bb->llvm()); - for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) - { - _out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" - << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") - << "];\n"; - } - } - - _out << "}\n"; -} - -void Compiler::dump() -{ - for (auto& entry : basicBlocks) - entry.second.dump(); - if (m_jumpTableBlock != nullptr) - m_jumpTableBlock->dump(); -} - -} -} -} - From 683f956a2e6d08e4e99560766704acd7f118b249 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:47:36 +0000 Subject: [PATCH 35/36] added struct for compiler options --- evmcc/evmcc.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 047fdf252..191b87dcf 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -101,7 +101,10 @@ int main(int argc, char** argv) { auto compilationStartTime = std::chrono::high_resolution_clock::now(); - auto compiler = eth::jit::Compiler(); + eth::jit::Compiler::Options options; + options.dumpCFG = opt_dump_graph; + + auto compiler = eth::jit::Compiler(options); auto module = compiler.compile({bytecode.data(), bytecode.size()}); auto compilationEndTime = std::chrono::high_resolution_clock::now(); @@ -115,14 +118,6 @@ int main(int argc, char** argv) << std::endl; } - if (opt_dump_graph) - { - std::ofstream ofs("blocks.dot"); - compiler.dumpBasicBlockGraph(ofs); - ofs.close(); - std::cout << "Basic blocks graph written to block.dot\n"; - } - if (opt_interpret) { auto engine = eth::jit::ExecutionEngine(); From e756b4ae1e7921960c0b3592a878403953558e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 16:59:21 +0100 Subject: [PATCH 36/36] Rename BNOT -> NOT, NOT -> ISZERO --- libevmjit/Compiler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 39c9edc7c..51b1ee403 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -342,7 +342,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod break; } - case Instruction::BNOT: + case Instruction::NOT: { auto value = stack.pop(); auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); @@ -400,7 +400,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod break; } - case Instruction::NOT: + case Instruction::ISZERO: { auto top = stack.pop(); auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero");