diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index be35b62c2..0a0611292 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -77,6 +77,20 @@ int AssemblyItem::deposit() const return 0; } +string AssemblyItem::getJumpTypeAsString() const +{ + switch (m_jumpType) + { + case JumpType::IntoFunction: + return "[in]"; + case JumpType::OutOfFunction: + return "[out]"; + case JumpType::Ordinary: + default: + return ""; + } +} + unsigned Assembly::bytesRequired() const { for (unsigned br = 1;; ++br) @@ -196,7 +210,7 @@ string Assembly::getLocationFromSources(StringMap const& _sourceCodes, SourceLoc return move(cut); } -ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const +ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const { _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) @@ -205,7 +219,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con switch (i.m_type) { case Operation: - _out << " " << instructionInfo((Instruction)(byte)i.m_data).name; + _out << " " << instructionInfo((Instruction)(byte)i.m_data).name << "\t" << i.getJumpTypeAsString(); break; case Push: _out << " PUSH " << i.m_data; @@ -240,7 +254,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con default: BOOST_THROW_EXCEPTION(InvalidOpcode()); } - _out << string("\t\t") << getLocationFromSources(_sourceCodes, i.getLocation()) << endl; + _out << "\t\t" << getLocationFromSources(_sourceCodes, i.getLocation()) << endl; } if (!m_data.empty() || !m_subs.empty()) @@ -252,7 +266,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con for (size_t i = 0; i < m_subs.size(); ++i) { _out << _prefix << " " << hex << i << ": " << endl; - m_subs[i].streamRLP(_out, _prefix + " ", _sourceCodes); + m_subs[i].stream(_out, _prefix + " ", _sourceCodes); } } return _out; diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index cd71db747..1cbb12e12 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -42,6 +42,8 @@ class AssemblyItem friend class Assembly; public: + enum class JumpType { Ordinary, IntoFunction, OutOfFunction }; + AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {} @@ -58,13 +60,18 @@ public: int deposit() const; bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); } - void setLocation(SourceLocation const& _location) { m_location = _location;} + void setLocation(SourceLocation const& _location) { m_location = _location; } SourceLocation const& getLocation() const { return m_location; } + void setJumpType(JumpType _jumpType) { m_jumpType = _jumpType; } + JumpType getJumpType() const { return m_jumpType; } + std::string getJumpTypeAsString() const; + private: AssemblyItemType m_type; u256 m_data; SourceLocation m_location; + JumpType m_jumpType; }; using AssemblyItems = std::vector; @@ -114,7 +121,7 @@ public: void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); } void injectStart(AssemblyItem const& _i); - std::string out() const { std::stringstream ret; streamRLP(ret); return ret.str(); } + std::string out() const { std::stringstream ret; stream(ret); return ret.str(); } int deposit() const { return m_deposit; } void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } @@ -124,7 +131,7 @@ public: bytes assemble() const; Assembly& optimise(bool _enable); - std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap()) const; + std::ostream& stream(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap()) const; protected: std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; @@ -146,7 +153,7 @@ protected: inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) { - _a.streamRLP(_out); + _a.stream(_out); return _out; } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 7ff846bdb..dc6e2c5a8 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -378,8 +378,9 @@ bool Compiler::visit(FunctionDefinition const& _function) m_context.removeVariable(*localVariable); m_context.adjustStackOffset(-(int)c_returnValuesSize); + if (!_function.isConstructor()) - m_context << eth::Instruction::JUMP; + m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); return false; } diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 1dea62e93..f2bb1de20 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -177,6 +177,13 @@ u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declarati return it->second; } +CompilerContext& CompilerContext::appendJump(eth::AssemblyItem::JumpType _jumpType) +{ + eth::AssemblyItem item(eth::Instruction::JUMP); + item.setJumpType(_jumpType); + return *this << item; +} + void CompilerContext::resetVisitedNodes(ASTNode const* _node) { stack newStack; diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 4d63d8ba0..76923a77a 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -91,7 +91,7 @@ public: /// Appends a JUMP to a new tag and @returns the tag eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); } /// Appends a JUMP to a tag already on the stack - CompilerContext& appendJump() { return *this << eth::Instruction::JUMP; } + CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary); /// Appends a JUMP to a specific tag CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } /// Appends pushing of a new tag and @returns the new tag. @@ -120,7 +120,7 @@ public: eth::Assembly const& getAssembly() const { return m_asm; } /// @arg _sourceCodes is the map of input files to source code strings - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const { m_asm.streamRLP(_stream, "", _sourceCodes); } + void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const { m_asm.stream(_stream, "", _sourceCodes); } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index b02aecf5f..129261120 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -108,7 +108,8 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& retSizeOnStack = returnType->getSizeOnStack(); } solAssert(retSizeOnStack <= 15, "Stack too deep."); - m_context << eth::dupInstruction(retSizeOnStack + 1) << eth::Instruction::JUMP; + m_context << eth::dupInstruction(retSizeOnStack + 1); + m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); } void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) @@ -405,7 +406,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } _functionCall.getExpression().accept(*this); - m_context.appendJump(); + m_context.appendJump(eth::AssemblyItem::JumpType::IntoFunction); m_context << returnLabel; unsigned returnParametersSize = CompilerUtils::getSizeOnStack(function.getReturnParameterTypes()); @@ -825,10 +826,20 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) Declaration const* declaration = _identifier.getReferencedDeclaration(); if (MagicVariableDeclaration const* magicVar = dynamic_cast(declaration)) { - if (magicVar->getType()->getCategory() == Type::Category::Contract) + switch (magicVar->getType()->getCategory()) + { + case Type::Category::Contract: // "this" or "super" if (!dynamic_cast(*magicVar->getType()).isSuper()) m_context << eth::Instruction::ADDRESS; + break; + case Type::Category::Integer: + // "now" + m_context << eth::Instruction::TIMESTAMP; + break; + default: + break; + } } else if (FunctionDefinition const* functionDef = dynamic_cast(declaration)) m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag(); diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index 60de5105f..411e99abb 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -37,6 +37,7 @@ GlobalContext::GlobalContext(): m_magicVariables(vector>{make_shared("block", make_shared(MagicType::Kind::Block)), make_shared("msg", make_shared(MagicType::Kind::Message)), make_shared("tx", make_shared(MagicType::Kind::Transaction)), + make_shared("now", make_shared(256)), make_shared("suicide", make_shared(strings{"address"}, strings{}, FunctionType::Location::Suicide)), make_shared("sha3", diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 08acb5ebd..01d8f8485 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -272,7 +272,7 @@ bool CommandLineInterface::processInput() while (!cin.eof()) { getline(cin, s); - m_sourceCodes[""].append(s); + m_sourceCodes[""].append(s + '\n'); } } else diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index ae2417052..3205c038a 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1031,6 +1031,17 @@ BOOST_AUTO_TEST_CASE(blockchain) BOOST_CHECK(callContractFunctionWithValue("someInfo()", 28) == encodeArgs(28, 0, 1)); } +BOOST_AUTO_TEST_CASE(now) +{ + char const* sourceCode = "contract test {\n" + " function someInfo() returns (bool success) {\n" + " return block.timestamp == now && now > 0;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("someInfo()") == encodeArgs(true)); +} + BOOST_AUTO_TEST_CASE(function_types) { char const* sourceCode = "contract test {\n"