diff options
-rw-r--r-- | Compiler.cpp | 2 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 79 | ||||
-rw-r--r-- | ExpressionCompiler.h | 4 | ||||
-rw-r--r-- | Types.cpp | 16 | ||||
-rw-r--r-- | Types.h | 19 |
5 files changed, 93 insertions, 27 deletions
diff --git a/Compiler.cpp b/Compiler.cpp index a82ecd95..988390d0 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -325,7 +325,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement) Expression& expression = _expressionStatement.getExpression(); ExpressionCompiler::compileExpression(m_context, expression); Type::Category category = expression.getType()->getCategory(); - if (category != Type::Category::VOID && category != Type::Category::MAGIC) + for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i) m_context << eth::Instruction::POP; return false; } diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 9e396874..f5ab829c 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -179,33 +179,62 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) } else { - //@todo: check for "external call" (to be stored in type) - - // Calling convention: Caller pushes return address and arguments - // Callee removes them and pushes return values FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()); - - eth::AssemblyItem returnLabel = m_context.pushNewTag(); std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments(); if (asserts(arguments.size() == function.getParameterTypes().size())) BOOST_THROW_EXCEPTION(InternalCompilerError()); - for (unsigned i = 0; i < arguments.size(); ++i) + + if (function.getLocation() == FunctionType::Location::INTERNAL) { - arguments[i]->accept(*this); - appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]); + // Calling convention: Caller pushes return address and arguments + // Callee removes them and pushes return values + + eth::AssemblyItem returnLabel = m_context.pushNewTag(); + for (unsigned i = 0; i < arguments.size(); ++i) + { + arguments[i]->accept(*this); + appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]); + } + _functionCall.getExpression().accept(*this); + + m_context.appendJump(); + m_context << returnLabel; + + // callee adds return parameters, but removes arguments and return label + m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1); + + // @todo for now, the return value of a function is its first return value, so remove + // all others + for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) + m_context << eth::Instruction::POP; + } + else if (function.getLocation() == FunctionType::Location::EXTERNAL) + { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("External function calls not implemented yet.")); + } + else + { + switch (function.getLocation()) + { + case FunctionType::Location::SEND: + m_context << u256(0) << u256(0) << u256(0) << u256(0); + arguments.front()->accept(*this); + //@todo might not be necessary + appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front()); + _functionCall.getExpression().accept(*this); + m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB + << eth::Instruction::CALL + << eth::Instruction::POP; + break; + case FunctionType::Location::SUICIDE: + arguments.front()->accept(*this); + //@todo might not be necessary + appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front()); + m_context << eth::Instruction::SUICIDE; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function not yet implemented.")); + } } - _functionCall.getExpression().accept(*this); - - m_context.appendJump(); - m_context << returnLabel; - - // callee adds return parameters, but removes arguments and return label - m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1); - - // @todo for now, the return value of a function is its first return value, so remove - // all others - for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) - m_context << eth::Instruction::POP; } return false; } @@ -216,9 +245,13 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) switch (_memberAccess.getExpression().getType()->getCategory()) { case Type::Category::INTEGER: - if (asserts(member == "balance")) + if (member == "balance") + m_context << eth::Instruction::BALANCE; + else if (member == "send") + { // no modification + } + else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); - m_context << eth::Instruction::BALANCE; break; case Type::Category::CONTRACT: // call function diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 3ed7848b..83d7cdc6 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -132,6 +132,10 @@ private: CompilerContext& m_context; LValue m_currentLValue; + /// If a "virtual" function (i.e. a bulit-in function without jump tag) is encountered, the + /// actual function is stored here. @todo prevent assignment or store it with assignment + enum class SpecialFunction { NONE, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 }; + SpecialFunction m_currentSpecialFunction; }; @@ -192,7 +192,7 @@ u256 IntegerType::literalValue(Literal const& _literal) const const MemberList IntegerType::AddressMemberList = MemberList({{"balance", make_shared<IntegerType const>(256)}, {"send", make_shared<FunctionType const>(TypePointers({make_shared<IntegerType const>(256)}), - TypePointers())}}); + TypePointers(), FunctionType::Location::SEND)}}); bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const { @@ -314,6 +314,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function) retParams.push_back(var->getType()); swap(params, m_parameterTypes); swap(retParams, m_returnParameterTypes); + m_location = Location::INTERNAL; } bool FunctionType::operator==(Type const& _other) const @@ -347,6 +348,19 @@ string FunctionType::toString() const return name + ")"; } +unsigned FunctionType::getSizeOnStack() const +{ + switch (m_location) + { + case Location::INTERNAL: + return 1; + case Location::EXTERNAL: + return 2; + default: + return 0; + } +} + bool MappingType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -115,6 +115,7 @@ public: /// Returns true if the type can be stored as a value (as opposed to a reference) on the stack, /// i.e. it behaves differently in lvalue context and in value context. virtual bool isValueType() const { return false; } + virtual unsigned getSizeOnStack() const { return 1; } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } @@ -235,6 +236,7 @@ public: virtual bool operator==(Type const& _other) const override; virtual u256 getStorageSize() const override; virtual bool canLiveOutsideStorage() const override; + virtual unsigned getSizeOnStack() const override { return 1; /*@todo*/ } virtual std::string toString() const override; virtual MemberList const& getMembers() const override; @@ -255,10 +257,17 @@ private: class FunctionType: public Type { public: + /// The meaning of the value(s) on the stack referencing the function: + /// INTERNAL: jump tag, EXTERNAL: contract address + function index, + /// OTHERS: special virtual function, nothing on the stack + enum class Location { INTERNAL, EXTERNAL, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 }; + virtual Category getCategory() const override { return Category::FUNCTION; } explicit FunctionType(FunctionDefinition const& _function); - FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes): - m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes) {} + FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, + Location _location = Location::INTERNAL): + m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), + m_location(_location) {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; } @@ -268,10 +277,14 @@ public: virtual bool canBeStored() const override { return false; } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } virtual bool canLiveOutsideStorage() const override { return false; } + virtual unsigned getSizeOnStack() const override; + + Location getLocation() const { return m_location; } private: TypePointers m_parameterTypes; TypePointers m_returnParameterTypes; + Location m_location; }; /** @@ -310,6 +323,7 @@ public: virtual bool canBeStored() const override { return false; } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } virtual bool canLiveOutsideStorage() const override { return false; } + virtual unsigned getSizeOnStack() const override { return 0; } }; /** @@ -349,6 +363,7 @@ public: virtual bool operator==(Type const& _other) const; virtual bool canBeStored() const override { return false; } virtual bool canLiveOutsideStorage() const override { return true; } + virtual unsigned getSizeOnStack() const override { return 0; } virtual MemberList const& getMembers() const override { return m_members; } virtual std::string toString() const override; |