From a4e46e665aac0aa26afa37a22eaf44941d856d9f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 26 May 2014 11:22:19 +0200 Subject: [PATCH 01/92] Major reorganisation. New libs (libethsupport, libevm, liblll). New LLLC binary. --- Assembly.cpp | 0 Assembly.h | 0 CMakeLists.txt | 70 +++++ CodeFragment.cpp | 701 ++++++++++++++++++++++++++++++++++++++++++++++ CodeFragment.h | 157 +++++++++++ Compiler.cpp | 61 ++++ Compiler.h | 35 +++ CompilerState.cpp | 37 +++ CompilerState.h | 49 ++++ Parser.cpp | 91 ++++++ Parser.h | 38 +++ 11 files changed, 1239 insertions(+) create mode 100644 Assembly.cpp create mode 100644 Assembly.h create mode 100644 CMakeLists.txt create mode 100644 CodeFragment.cpp create mode 100644 CodeFragment.h create mode 100644 Compiler.cpp create mode 100644 Compiler.h create mode 100644 CompilerState.cpp create mode 100644 CompilerState.h create mode 100644 Parser.cpp create mode 100644 Parser.h diff --git a/Assembly.cpp b/Assembly.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/Assembly.h b/Assembly.h new file mode 100644 index 000000000..e69de29bb diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..dc5fc2221 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_policy(SET CMP0015 NEW) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") + +aux_source_directory(. SRC_LIST) + +set(EXECUTABLE lll) + +if(APPLE) + # set(CMAKE_INSTALL_PREFIX ../lib) + add_library(${EXECUTABLE} SHARED ${SRC_LIST}) +else() + add_library(${EXECUTABLE} ${SRC_LIST}) +endif() +if (UNIX) + FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework locale) +endif() +file(GLOB HEADERS "*.h") + +include_directories(..) +include_directories(${MINIUPNPC_ID}) +include_directories(${LEVELDB_ID}) + +target_link_libraries(${EXECUTABLE} ethcore) +target_link_libraries(${EXECUTABLE} ethsupport) +target_link_libraries(${EXECUTABLE} secp256k1) +target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) +target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) +target_link_libraries(${EXECUTABLE} gmp) + + +if(${TARGET_PLATFORM} STREQUAL "w64") + include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) + target_link_libraries(${EXECUTABLE} cryptopp) + target_link_libraries(${EXECUTABLE} boost_system-mt-s) + target_link_libraries(${EXECUTABLE} boost_filesystem-mt-s) + target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) + target_link_libraries(${EXECUTABLE} iphlpapi) + target_link_libraries(${EXECUTABLE} ws2_32) + target_link_libraries(${EXECUTABLE} mswsock) + target_link_libraries(${EXECUTABLE} shlwapi) +elseif (APPLE) + # Latest mavericks boost libraries only come with -mt + target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) + target_link_libraries(${EXECUTABLE} boost_system-mt) + target_link_libraries(${EXECUTABLE} boost_filesystem-mt) + target_link_libraries(${EXECUTABLE} boost_thread-mt) + find_package(Threads REQUIRED) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +elseif (UNIX) + target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) + target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY}) + target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARY}) + target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) + target_link_libraries(${EXECUTABLE} ${Boost_DATE_TIME_LIBRARY}) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +else () + target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) + target_link_libraries(${EXECUTABLE} boost_system) + target_link_libraries(${EXECUTABLE} boost_filesystem) + target_link_libraries(${EXECUTABLE} boost_thread) + find_package(Threads REQUIRED) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +endif () + +message("Installation path: ${CMAKE_INSTALL_PREFIX}") + +install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/CodeFragment.cpp b/CodeFragment.cpp new file mode 100644 index 000000000..854a27c40 --- /dev/null +++ b/CodeFragment.cpp @@ -0,0 +1,701 @@ +/* + 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 . +*/ +/** @file CodeFragment.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Parser.h" +#include "CodeFragment.h" + +#include +#include +#include +#include +#include +#include "CompilerState.h" +using namespace std; +using namespace eth; +namespace qi = boost::spirit::qi; +namespace px = boost::phoenix; +namespace sp = boost::spirit; + +void eth::debugOutAST(ostream& _out, sp::utree const& _this) +{ + switch (_this.which()) + { + case sp::utree_type::list_type: + switch (_this.tag()) + { + case 0: _out << "( "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << ")"; break; + case 1: _out << "@ "; debugOutAST(_out, _this.front()); break; + case 2: _out << "@@ "; debugOutAST(_out, _this.front()); break; + case 3: _out << "[ "; debugOutAST(_out, _this.front()); _out << " ] "; debugOutAST(_out, _this.back()); break; + case 4: _out << "[[ "; debugOutAST(_out, _this.front()); _out << " ]] "; debugOutAST(_out, _this.back()); break; + case 5: _out << "{ "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << "}"; break; + default:; + } + + break; + case sp::utree_type::int_type: _out << _this.get(); break; + case sp::utree_type::string_type: _out << "\"" << _this.get, sp::utree_type::string_type>>() << "\""; break; + case sp::utree_type::symbol_type: _out << _this.get, sp::utree_type::symbol_type>>(); break; + case sp::utree_type::any_type: _out << *_this.get(); break; + default: _out << "nil"; + } +} + +CodeLocation::CodeLocation(CodeFragment* _f) +{ + m_f = _f; + m_pos = _f->m_code.size(); +} + +unsigned CodeLocation::get() const +{ + assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); + bytesConstRef r(&m_f->m_code[m_pos], 4); + cdebug << toHex(r); + return fromBigEndian(r); +} + +void CodeLocation::set(unsigned _val) +{ + assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); + assert(!get()); + bytesRef r(&m_f->m_code[m_pos], 4); + toBigEndian(_val, r); +} + +void CodeLocation::anchor() +{ + set(m_f->m_code.size()); +} + +void CodeLocation::increase(unsigned _val) +{ + assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); + bytesRef r(&m_f->m_code[m_pos], 4); + toBigEndian(get() + _val, r); +} + +void CodeFragment::appendFragment(CodeFragment const& _f) +{ + m_locs.reserve(m_locs.size() + _f.m_locs.size()); + m_code.reserve(m_code.size() + _f.m_code.size()); + + unsigned os = m_code.size(); + + for (auto i: _f.m_code) + m_code.push_back(i); + + for (auto i: _f.m_locs) + { + CodeLocation(this, i + os).increase(os); + m_locs.push_back(i + os); + } + + for (auto i: _f.m_data) + m_data.insert(make_pair(i.first, i.second + os)); + + m_deposit += _f.m_deposit; +} + +CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s) +{ + CodeFragment ret; + sp::utree o; + parseTreeLLL(_src, o); + if (!o.empty()) + ret = CodeFragment(o, _s); + _s.treesToKill.push_back(o); + return ret; +} + +void CodeFragment::consolidateData() +{ + m_code.push_back(0); + bytes ld; + for (auto const& i: m_data) + { + if (ld != i.first) + { + ld = i.first; + for (auto j: ld) + m_code.push_back(j); + } + CodeLocation(this, i.second).set(m_code.size() - ld.size()); + } + m_data.clear(); +} + +void CodeFragment::appendFragment(CodeFragment const& _f, unsigned _deposit) +{ + if ((int)_deposit > _f.m_deposit) + error(); + else + { + appendFragment(_f); + while (_deposit++ < (unsigned)_f.m_deposit) + appendInstruction(Instruction::POP); + } +} + +CodeLocation CodeFragment::appendPushLocation(unsigned _locationValue) +{ + m_code.push_back((byte)Instruction::PUSH4); + CodeLocation ret(this, m_code.size()); + m_locs.push_back(m_code.size()); + m_code.resize(m_code.size() + 4); + bytesRef r(&m_code[m_code.size() - 4], 4); + toBigEndian(_locationValue, r); + m_deposit++; + return ret; +} + +unsigned CodeFragment::appendPush(u256 _literalValue) +{ + unsigned br = max(1, bytesRequired(_literalValue)); + m_code.push_back((byte)Instruction::PUSH1 + br - 1); + m_code.resize(m_code.size() + br); + for (unsigned i = 0; i < br; ++i) + { + m_code[m_code.size() - 1 - i] = (byte)(_literalValue & 0xff); + _literalValue >>= 8; + } + m_deposit++; + return br + 1; +} + +void CodeFragment::appendInstruction(Instruction _i) +{ + m_code.push_back((byte)_i); + m_deposit += c_instructionInfo.at(_i).ret - c_instructionInfo.at(_i).args; +} + +CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) +{ +/* cdebug << "CodeFragment. Locals:"; + for (auto const& i: _s.defs) + cdebug << i.first << ":" << toHex(i.second.m_code); + cdebug << "Args:"; + for (auto const& i: _s.args) + cdebug << i.first << ":" << toHex(i.second.m_code); + cdebug << "Outers:"; + for (auto const& i: _s.outers) + cdebug << i.first << ":" << toHex(i.second.m_code); + debugOutAST(cout, _t); + cout << endl << flush; +*/ + switch (_t.which()) + { + case sp::utree_type::list_type: + constructOperation(_t, _s); + break; + case sp::utree_type::string_type: + { + auto sr = _t.get, sp::utree_type::string_type>>(); + string s(sr.begin(), sr.end()); + if (s.size() > 32) + error(); + h256 valHash; + memcpy(valHash.data(), s.data(), s.size()); + memset(valHash.data() + s.size(), 0, 32 - s.size()); + appendPush(valHash); + break; + } + case sp::utree_type::symbol_type: + { + auto sr = _t.get, sp::utree_type::symbol_type>>(); + string s(sr.begin(), sr.end()); + string us = boost::algorithm::to_upper_copy(s); + if (_allowASM) + { + if (c_instructions.count(us)) + { + auto it = c_instructions.find(us); + m_deposit = c_instructionInfo.at(it->second).ret - c_instructionInfo.at(it->second).args; + m_code.push_back((byte)it->second); + } + } + if (_s.defs.count(s)) + appendFragment(_s.defs.at(s)); + else if (_s.args.count(s)) + appendFragment(_s.args.at(s)); + else if (_s.outers.count(s)) + appendFragment(_s.outers.at(s)); + else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) + { + auto it = _s.vars.find(s); + if (it == _s.vars.end()) + { + bool ok; + tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32)); + } + appendPush(it->second); + } + else + error(); + + break; + } + case sp::utree_type::any_type: + { + bigint i = *_t.get(); + if (i < 0 || i > bigint(u256(0) - 1)) + error(); + appendPush((u256)i); + break; + } + default: break; + } +} + +void CodeFragment::appendPushDataLocation(bytes const& _data) +{ + m_code.push_back((byte)Instruction::PUSH4); + m_data.insert(make_pair(_data, m_code.size())); + m_code.resize(m_code.size() + 4); + memset(&m_code.back() - 3, 0, 4); + m_deposit++; +} + +std::string CodeFragment::asPushedString() const +{ + string ret; + if (m_code.size()) + { + unsigned bc = m_code[0] - (byte)Instruction::PUSH1 + 1; + if (m_code[0] >= (byte)Instruction::PUSH1 && m_code[0] <= (byte)Instruction::PUSH32) + { + for (unsigned s = 0; s < bc && m_code[1 + s]; ++s) + ret.push_back(m_code[1 + s]); + return ret; + } + } + error(); + return ret; +} + +void CodeFragment::optimise() +{ +// map const&)>> pattern = { { "PUSH,PUSH,ADD", [](vector const& v) { return CodeFragment(appendPush(v[0] + v[1])); } } }; +} + +void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) +{ + if (_t.empty()) + error(); + else if (_t.tag() == 0 && _t.front().which() != sp::utree_type::symbol_type) + error(); + else + { + string s; + string us; + switch (_t.tag()) + { + case 0: + { + auto sr = _t.front().get, sp::utree_type::symbol_type>>(); + s = string(sr.begin(), sr.end()); + us = boost::algorithm::to_upper_copy(s); + break; + } + case 1: + us = "MLOAD"; + break; + case 2: + us = "SLOAD"; + break; + case 3: + us = "MSTORE"; + break; + case 4: + us = "SSTORE"; + break; + case 5: + us = "SEQ"; + break; + default:; + } + + // Operations who args are not standard stack-pushers. + bool nonStandard = true; + if (us == "ASM") + { + int c = 0; + for (auto const& i: _t) + if (c++) + appendFragment(CodeFragment(i, _s, true)); + } + else if (us == "INCLUDE") + { + if (_t.size() != 2) + error(); + string n; + auto i = *++_t.begin(); + if (i.tag()) + error(); + if (i.which() == sp::utree_type::string_type) + { + auto sr = i.get, sp::utree_type::string_type>>(); + n = string(sr.begin(), sr.end()); + } + else if (i.which() == sp::utree_type::symbol_type) + { + auto sr = i.get, sp::utree_type::symbol_type>>(); + n = _s.getDef(string(sr.begin(), sr.end())).asPushedString(); + } + appendFragment(CodeFragment::compile(asString(contents(n)), _s)); + } + else if (us == "DEF") + { + string n; + unsigned ii = 0; + if (_t.size() != 3 && _t.size() != 4) + error(); + for (auto const& i: _t) + { + if (ii == 1) + { + if (i.tag()) + error(); + if (i.which() == sp::utree_type::string_type) + { + auto sr = i.get, sp::utree_type::string_type>>(); + n = string(sr.begin(), sr.end()); + } + else if (i.which() == sp::utree_type::symbol_type) + { + auto sr = i.get, sp::utree_type::symbol_type>>(); + n = _s.getDef(string(sr.begin(), sr.end())).asPushedString(); + } + } + else if (ii == 2) + if (_t.size() == 3) + _s.defs[n] = CodeFragment(i, _s); + else + for (auto const& j: i) + { + if (j.tag() || j.which() != sp::utree_type::symbol_type) + error(); + auto sr = j.get, sp::utree_type::symbol_type>>(); + _s.macros[n].args.push_back(string(sr.begin(), sr.end())); + } + else if (ii == 3) + { + _s.macros[n].code = i; + _s.macros[n].env = _s.outers; + for (auto const& i: _s.args) + _s.macros[n].env[i.first] = i.second; + for (auto const& i: _s.defs) + _s.macros[n].env[i.first] = i.second; + } + ++ii; + } + + } + else if (us == "LIT") + { + if (_t.size() < 3) + error(); + unsigned ii = 0; + CodeFragment pos; + bytes data; + for (auto const& i: _t) + { + if (ii == 1) + { + pos = CodeFragment(i, _s); + if (pos.m_deposit != 1) + error(); + } + else if (ii == 2 && !i.tag() && i.which() == sp::utree_type::string_type) + { + auto sr = i.get, sp::utree_type::string_type>>(); + data = bytes((byte const*)sr.begin(), (byte const*)sr.end()); + } + else if (ii >= 2 && !i.tag() && i.which() == sp::utree_type::any_type) + { + bigint bi = *i.get(); + if (bi < 0) + error(); + else if (bi > bigint(u256(0) - 1)) + { + if (ii == 2 && _t.size() == 3) + { + // One big int - allow it as hex. + data.resize(bytesRequired(bi)); + toBigEndian(bi, data); + } + else + error(); + } + else + { + data.resize(data.size() + 32); + *(h256*)(&data.back() - 31) = (u256)bi; + } + } + else if (ii) + error(); + ++ii; + } + appendPush(data.size()); + appendInstruction(Instruction::DUP); + appendPushDataLocation(data); + appendFragment(pos, 1); + appendInstruction(Instruction::CODECOPY); + } + else + nonStandard = false; + + if (nonStandard) + return; + + 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 } }; + + vector code; + CompilerState ns = _s; + ns.vars.clear(); + int c = _t.tag() ? 1 : 0; + for (auto const& i: _t) + if (c++) + { + if (us == "LLL" && c == 1) + code.push_back(CodeFragment(i, ns)); + else + code.push_back(CodeFragment(i, _s)); + } + auto requireSize = [&](unsigned s) { if (code.size() != s) error(); }; + auto requireMinSize = [&](unsigned s) { if (code.size() < s) error(); }; + auto requireMaxSize = [&](unsigned s) { if (code.size() > s) error(); }; + auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_deposit != s) error(); }; + + if (_s.macros.count(s) && _s.macros.at(s).args.size() == code.size()) + { + Macro const& m = _s.macros.at(s); + CompilerState cs = _s; + for (auto const& i: m.env) + cs.outers[i.first] = i.second; + for (auto const& i: cs.defs) + cs.outers[i.first] = i.second; + cs.defs.clear(); + for (unsigned i = 0; i < m.args.size(); ++i) + { + requireDeposit(i, 1); + cs.args[m.args[i]] = code[i]; + } + appendFragment(CodeFragment(m.code, cs)); + for (auto const& i: cs.defs) + _s.defs[i.first] = i.second; + for (auto const& i: cs.macros) + _s.macros.insert(i); + } + else if (c_instructions.count(us)) + { + auto it = c_instructions.find(us); + int ea = c_instructionInfo.at(it->second).args; + if (ea >= 0) + requireSize(ea); + else + requireMinSize(-ea); + + for (unsigned i = code.size(); i; --i) + appendFragment(code[i - 1], 1); + appendInstruction(it->second); + } + else if (c_arith.count(us)) + { + auto it = c_arith.find(us); + requireMinSize(1); + for (unsigned i = code.size(); i; --i) + { + requireDeposit(i - 1, 1); + appendFragment(code[i - 1], 1); + } + for (unsigned i = 1; i < code.size(); ++i) + appendInstruction(it->second); + } + else if (c_binary.count(us)) + { + auto it = c_binary.find(us); + requireSize(2); + requireDeposit(0, 1); + requireDeposit(1, 1); + appendFragment(code[1], 1); + appendFragment(code[0], 1); + appendInstruction(it->second.first); + if (it->second.second) + appendInstruction(Instruction::NOT); + } + else if (c_unary.count(us)) + { + auto it = c_unary.find(us); + requireSize(1); + requireDeposit(0, 1); + appendFragment(code[0], 1); + appendInstruction(it->second); + } + else if (us == "IF") + { + requireSize(3); + requireDeposit(0, 1); + appendFragment(code[0]); + auto pos = appendJumpI(); + onePath(); + appendFragment(code[2]); + auto end = appendJump(); + otherPath(); + pos.anchor(); + appendFragment(code[1]); + donePaths(); + end.anchor(); + } + else if (us == "WHEN" || us == "UNLESS") + { + requireSize(2); + requireDeposit(0, 1); + appendFragment(code[0]); + if (us == "WHEN") + appendInstruction(Instruction::NOT); + auto end = appendJumpI(); + onePath(); + otherPath(); + appendFragment(code[1], 0); + donePaths(); + end.anchor(); + } + else if (us == "WHILE") + { + requireSize(2); + requireDeposit(0, 1); + auto begin = CodeLocation(this); + appendFragment(code[0], 1); + appendInstruction(Instruction::NOT); + auto end = appendJumpI(); + appendFragment(code[1], 0); + appendJump(begin); + end.anchor(); + } + else if (us == "FOR") + { + requireSize(4); + requireDeposit(1, 1); + appendFragment(code[0], 0); + auto begin = CodeLocation(this); + appendFragment(code[1], 1); + appendInstruction(Instruction::NOT); + auto end = appendJumpI(); + appendFragment(code[3], 0); + appendFragment(code[2], 0); + appendJump(begin); + end.anchor(); + } + else if (us == "LLL") + { + requireMinSize(2); + requireMaxSize(3); + requireDeposit(1, 1); + + CodeLocation codeloc(this, m_code.size() + 6); + bytes const& subcode = code[0].code(); + appendPush(subcode.size()); + appendInstruction(Instruction::DUP); + if (code.size() == 3) + { + requireDeposit(2, 1); + appendFragment(code[2], 1); + appendInstruction(Instruction::LT); + appendInstruction(Instruction::NOT); + appendInstruction(Instruction::MUL); + appendInstruction(Instruction::DUP); + } + appendPushDataLocation(subcode); + appendFragment(code[1], 1); + appendInstruction(Instruction::CODECOPY); + } + else if (us == "&&" || us == "||") + { + requireMinSize(1); + for (unsigned i = 0; i < code.size(); ++i) + requireDeposit(i, 1); + + vector ends; + if (code.size() > 1) + { + appendPush(us == "||" ? 1 : 0); + for (unsigned i = 1; i < code.size(); ++i) + { + // Check if true - predicate + appendFragment(code[i - 1], 1); + if (us == "&&") + appendInstruction(Instruction::NOT); + ends.push_back(appendJumpI()); + } + appendInstruction(Instruction::POP); + } + + // Check if true - predicate + appendFragment(code.back(), 1); + + // At end now. + for (auto& i: ends) + i.anchor(); + } + else if (us == "~") + { + requireSize(1); + requireDeposit(0, 1); + appendFragment(code[0], 1); + appendPush(1); + appendPush(0); + appendInstruction(Instruction::SUB); + appendInstruction(Instruction::SUB); + } + else if (us == "SEQ") + { + unsigned ii = 0; + for (auto const& i: code) + if (++ii < code.size()) + appendFragment(i, 0); + else + appendFragment(i); + } + else if (us == "RAW") + { + for (auto const& i: code) + appendFragment(i); + while (m_deposit > 1) + appendInstruction(Instruction::POP); + } + else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) + { + auto it = _s.vars.find(s); + if (it == _s.vars.end()) + { + bool ok; + tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32)); + } + appendPush(it->second); + } + else + error(); + } +} diff --git a/CodeFragment.h b/CodeFragment.h new file mode 100644 index 000000000..82630dbe6 --- /dev/null +++ b/CodeFragment.h @@ -0,0 +1,157 @@ +/* + 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 . +*/ +/** @file CodeFragment.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include "Exceptions.h" + +namespace boost { namespace spirit { class utree; } } +namespace sp = boost::spirit; + +namespace eth +{ + +class CompilerState; +class CodeFragment; + +void debugOutAST(std::ostream& _out, sp::utree const& _this); + +class CodeLocation +{ + friend class CodeFragment; + +public: + CodeLocation(CodeFragment* _f); + CodeLocation(CodeFragment* _f, unsigned _p): m_f(_f), m_pos(_p) {} + + unsigned get() const; + void increase(unsigned _val); + void set(unsigned _val); + void set(CodeLocation _loc) { assert(_loc.m_f == m_f); set(_loc.m_pos); } + void anchor(); + + CodeLocation operator+(unsigned _i) const { return CodeLocation(m_f, m_pos + _i); } + +private: + CodeFragment* m_f; + unsigned m_pos; +}; + +class CompilerState; + +enum AssemblyItemType { Operation, Push, PushString, PushTag, Tag, PushData }; + +class AssemblyItem +{ +public: + AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} + AssemblyItem(std::string const& _push): m_type(PushString), m_pushString(_push) {} + AssemblyItem(AssemblyItemType _type, AssemblyItem const& _tag): m_type(_type), m_data(_tag.m_data) { assert(_type == PushTag); assert(_tag.m_type == Tag); } + AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} + AssemblyItem(AssemblyItemType _type, u256 _data): m_type(_type), m_data(_data) {} + + AssemblyItemType type() const { return m_type; } + u256 data() const { return m_data; } + std::string const& pushString() const { return m_pushString; } + +private: + AssemblyItemType m_type; + u256 m_data; + std::string m_pushString; +}; + +class Assembly +{ +public: + AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } + AssemblyItem newData(bytes const& _data) { auto h = sha3(_data); m_data[h] = _data; return AssemblyItem(PushData, h); } + bytes assemble() const; + void append(Assembly const& _a); + +private: + u256 m_usedTags = 0; + std::vector m_items; + std::map m_data; +}; + +class CodeFragment +{ + friend class CodeLocation; + +public: + CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM = false); + CodeFragment(bytes const& _c = bytes()): m_code(_c) {} + + static CodeFragment compile(std::string const& _src, CompilerState& _s); + + /// Consolidates data and returns code. + bytes const& code() { optimise(); consolidateData(); return m_code; } + + unsigned appendPush(u256 _l); + void appendFragment(CodeFragment const& _f); + void appendFragment(CodeFragment const& _f, unsigned _i); + void appendInstruction(Instruction _i); + + CodeLocation appendPushLocation(unsigned _l = 0); + void appendPushLocation(CodeLocation _l) { assert(_l.m_f == this); appendPushLocation(_l.m_pos); } + void appendPushDataLocation(bytes const& _data); + + CodeLocation appendJump() { auto ret = appendPushLocation(0); appendInstruction(Instruction::JUMP); return ret; } + CodeLocation appendJumpI() { auto ret = appendPushLocation(0); appendInstruction(Instruction::JUMPI); return ret; } + CodeLocation appendJump(CodeLocation _l) { auto ret = appendPushLocation(_l.m_pos); appendInstruction(Instruction::JUMP); return ret; } + CodeLocation appendJumpI(CodeLocation _l) { auto ret = appendPushLocation(_l.m_pos); appendInstruction(Instruction::JUMPI); return ret; } + + void appendFile(std::string const& _fn); + + std::string asPushedString() const; + + void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } + void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } + void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } + void ignored() { m_baseDeposit = m_deposit; } + void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } + + bool operator==(CodeFragment const& _f) const { return _f.m_code == m_code && _f.m_data == m_data; } + bool operator!=(CodeFragment const& _f) const { return !operator==(_f); } + unsigned size() const { return m_code.size(); } + + void consolidateData(); + void optimise(); + +private: + template void error() const { throw T(); } + void constructOperation(sp::utree const& _t, CompilerState& _s); + + void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) error(); } + + int m_deposit = 0; + int m_baseDeposit = 0; + int m_totalDeposit = 0; + bytes m_code; + std::vector m_locs; + std::multimap m_data; +}; + +static const CodeFragment NullCodeFragment; + +} diff --git a/Compiler.cpp b/Compiler.cpp new file mode 100644 index 000000000..afe84eb4b --- /dev/null +++ b/Compiler.cpp @@ -0,0 +1,61 @@ +/* + 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 . +*/ +/** @file Compiler.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Compiler.h" +#include "Parser.h" +#include "CompilerState.h" +#include "CodeFragment.h" + +using namespace std; +using namespace eth; + +bytes eth::compileLLL(string const& _s, vector* _errors) +{ + try + { + CompilerState cs; + bytes ret = CodeFragment::compile(_s, cs).code(); + for (auto i: cs.treesToKill) + killBigints(i); + return ret; + } + catch (Exception const& _e) + { + if (_errors) + _errors->push_back(_e.description()); + } + catch (std::exception) + { + if (_errors) + _errors->push_back("Parse error."); + } + return bytes(); +} + +string eth::parseLLL(string const& _src) +{ + sp::utree o; + parseTreeLLL(_src, o); + ostringstream ret; + debugOutAST(ret, o); + killBigints(o); + return ret.str(); +} diff --git a/Compiler.h b/Compiler.h new file mode 100644 index 000000000..e58e12bae --- /dev/null +++ b/Compiler.h @@ -0,0 +1,35 @@ +/* + 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 . +*/ +/** @file Compiler.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include + +namespace eth +{ + +std::string parseLLL(std::string const& _src); +bytes compileLLL(std::string const& _s, std::vector* _errors = nullptr); + +} + diff --git a/CompilerState.cpp b/CompilerState.cpp new file mode 100644 index 000000000..d2894475a --- /dev/null +++ b/CompilerState.cpp @@ -0,0 +1,37 @@ +/* + 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 . +*/ +/** @file CompilerState.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "CompilerState.h" + +using namespace std; +using namespace eth; + +CodeFragment const& CompilerState::getDef(std::string const& _s) +{ + if (defs.count(_s)) + return defs.at(_s); + else if (args.count(_s)) + return args.at(_s); + else if (outers.count(_s)) + return outers.at(_s); + else + return NullCodeFragment; +} diff --git a/CompilerState.h b/CompilerState.h new file mode 100644 index 000000000..d53c2bcd7 --- /dev/null +++ b/CompilerState.h @@ -0,0 +1,49 @@ +/* + 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 . +*/ +/** @file CompilerState.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include "CodeFragment.h" + +namespace eth +{ + +struct Macro +{ + std::vector args; + boost::spirit::utree code; + std::map env; +}; + +struct CompilerState +{ + CodeFragment const& getDef(std::string const& _s); + + std::map vars; + std::map defs; + std::map args; + std::map outers; + std::map macros; + std::vector treesToKill; +}; + +} diff --git a/Parser.cpp b/Parser.cpp new file mode 100644 index 000000000..2a0146a60 --- /dev/null +++ b/Parser.cpp @@ -0,0 +1,91 @@ +/* + 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 . +*/ +/** @file Parser.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Parser.h" + +#include +#include +#include +#include + +using namespace std; +using namespace eth; +namespace qi = boost::spirit::qi; +namespace px = boost::phoenix; +namespace sp = boost::spirit; + +void eth::killBigints(sp::utree const& _this) +{ + switch (_this.which()) + { + case sp::utree_type::list_type: for (auto const& i: _this) killBigints(i); break; + case sp::utree_type::any_type: delete _this.get(); break; + default:; + } +} + +void eth::parseTreeLLL(string const& _s, sp::utree& o_out) +{ + using qi::ascii::space; + typedef sp::basic_string symbol_type; + typedef string::const_iterator it; + + qi::rule element; + qi::rule str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"'; + qi::rule strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;())") + '\0'))]; + qi::rule symbol = qi::lexeme[+(~qi::char_(std::string(" @[]{}:();\"\x01-\x1f\x7f") + '\0'))]; + qi::rule intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]]; + qi::rule integer = intstr; + qi::rule multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether]; + qi::rule quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1]; + qi::rule atom = quantity[qi::_val = px::construct(px::new_(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1]; + qi::rule seq = '{' > *element > '}'; + qi::rule mload = '@' > element; + qi::rule sload = qi::lit("@@") > element; + qi::rule mstore = '[' > element > ']' > -qi::lit(":") > element; + qi::rule sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element; + qi::rule extra = sload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 2)] | mload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 1)] | sstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 4)] | mstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 3)] | seq[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 5)]; + qi::rule list = '(' > *element > ')'; + element = atom | list | extra; + + string s; + s.reserve(_s.size()); + bool incomment = false; + bool instring = false; + bool insstring = false; + for (auto i: _s) + { + if (i == ';' && !instring && !insstring) + incomment = true; + else if (i == '\n') + incomment = instring = insstring = false; + else if (i == '"' && !insstring) + instring = !instring; + else if (i == '\'') + insstring = true; + else if (i == ' ') + insstring = false; + if (!incomment) + s.push_back(i); + } + qi::phrase_parse(s.cbegin(), s.cend(), element, space, o_out); +} + diff --git a/Parser.h b/Parser.h new file mode 100644 index 000000000..3b2756576 --- /dev/null +++ b/Parser.h @@ -0,0 +1,38 @@ +/* + 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 . +*/ +/** @file Parser.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include + +namespace boost { namespace spirit { class utree; } } +namespace sp = boost::spirit; + +namespace eth +{ + +void killBigints(sp::utree const& _this); +void parseTreeLLL(std::string const& _s, sp::utree& o_out); + +} + From 48f6bad8a3f0290f0439545c799d725a2d5b2d54 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 26 May 2014 11:34:43 +0200 Subject: [PATCH 02/92] Ever more repotting. --- Assembly.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ CodeFragment.cpp | 34 ------------------------- CodeFragment.h | 60 +------------------------------------------ CodeLocation.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++ CodeLocation.h | 54 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 93 deletions(-) create mode 100644 CodeLocation.cpp create mode 100644 CodeLocation.h diff --git a/Assembly.h b/Assembly.h index e69de29bb..28d2974bb 100644 --- a/Assembly.h +++ b/Assembly.h @@ -0,0 +1,66 @@ +/* + 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 . +*/ +/** @file CodeFragment.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include "Exceptions.h" + +namespace eth +{ + +enum AssemblyItemType { Operation, Push, PushString, PushTag, Tag, PushData }; + +class AssemblyItem +{ +public: + AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} + AssemblyItem(std::string const& _push): m_type(PushString), m_pushString(_push) {} + AssemblyItem(AssemblyItemType _type, AssemblyItem const& _tag): m_type(_type), m_data(_tag.m_data) { assert(_type == PushTag); assert(_tag.m_type == Tag); } + AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} + AssemblyItem(AssemblyItemType _type, u256 _data): m_type(_type), m_data(_data) {} + + AssemblyItemType type() const { return m_type; } + u256 data() const { return m_data; } + std::string const& pushString() const { return m_pushString; } + +private: + AssemblyItemType m_type; + u256 m_data; + std::string m_pushString; +}; + +class Assembly +{ +public: + AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } + AssemblyItem newData(bytes const& _data) { auto h = sha3(_data); m_data[h] = _data; return AssemblyItem(PushData, h); } + bytes assemble() const; + void append(Assembly const& _a); + +private: + u256 m_usedTags = 0; + std::vector m_items; + std::map m_data; +}; + +} diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 854a27c40..cc76c432a 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -59,40 +59,6 @@ void eth::debugOutAST(ostream& _out, sp::utree const& _this) } } -CodeLocation::CodeLocation(CodeFragment* _f) -{ - m_f = _f; - m_pos = _f->m_code.size(); -} - -unsigned CodeLocation::get() const -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - bytesConstRef r(&m_f->m_code[m_pos], 4); - cdebug << toHex(r); - return fromBigEndian(r); -} - -void CodeLocation::set(unsigned _val) -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - assert(!get()); - bytesRef r(&m_f->m_code[m_pos], 4); - toBigEndian(_val, r); -} - -void CodeLocation::anchor() -{ - set(m_f->m_code.size()); -} - -void CodeLocation::increase(unsigned _val) -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - bytesRef r(&m_f->m_code[m_pos], 4); - toBigEndian(get() + _val, r); -} - void CodeFragment::appendFragment(CodeFragment const& _f) { m_locs.reserve(m_locs.size() + _f.m_locs.size()); diff --git a/CodeFragment.h b/CodeFragment.h index 82630dbe6..cee7da3b3 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -23,6 +23,7 @@ #include #include +#include "CodeLocation.h" #include "Exceptions.h" namespace boost { namespace spirit { class utree; } } @@ -31,69 +32,10 @@ namespace sp = boost::spirit; namespace eth { -class CompilerState; -class CodeFragment; - void debugOutAST(std::ostream& _out, sp::utree const& _this); -class CodeLocation -{ - friend class CodeFragment; - -public: - CodeLocation(CodeFragment* _f); - CodeLocation(CodeFragment* _f, unsigned _p): m_f(_f), m_pos(_p) {} - - unsigned get() const; - void increase(unsigned _val); - void set(unsigned _val); - void set(CodeLocation _loc) { assert(_loc.m_f == m_f); set(_loc.m_pos); } - void anchor(); - - CodeLocation operator+(unsigned _i) const { return CodeLocation(m_f, m_pos + _i); } - -private: - CodeFragment* m_f; - unsigned m_pos; -}; - class CompilerState; -enum AssemblyItemType { Operation, Push, PushString, PushTag, Tag, PushData }; - -class AssemblyItem -{ -public: - AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} - AssemblyItem(std::string const& _push): m_type(PushString), m_pushString(_push) {} - AssemblyItem(AssemblyItemType _type, AssemblyItem const& _tag): m_type(_type), m_data(_tag.m_data) { assert(_type == PushTag); assert(_tag.m_type == Tag); } - AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} - AssemblyItem(AssemblyItemType _type, u256 _data): m_type(_type), m_data(_data) {} - - AssemblyItemType type() const { return m_type; } - u256 data() const { return m_data; } - std::string const& pushString() const { return m_pushString; } - -private: - AssemblyItemType m_type; - u256 m_data; - std::string m_pushString; -}; - -class Assembly -{ -public: - AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } - AssemblyItem newData(bytes const& _data) { auto h = sha3(_data); m_data[h] = _data; return AssemblyItem(PushData, h); } - bytes assemble() const; - void append(Assembly const& _a); - -private: - u256 m_usedTags = 0; - std::vector m_items; - std::map m_data; -}; - class CodeFragment { friend class CodeLocation; diff --git a/CodeLocation.cpp b/CodeLocation.cpp new file mode 100644 index 000000000..2c9ca2644 --- /dev/null +++ b/CodeLocation.cpp @@ -0,0 +1,59 @@ +/* + 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 . +*/ +/** @file CodeLocation.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "CodeLocation.h" +#include "CodeFragment.h" +using namespace std; +using namespace eth; + +CodeLocation::CodeLocation(CodeFragment* _f) +{ + m_f = _f; + m_pos = _f->m_code.size(); +} + +unsigned CodeLocation::get() const +{ + assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); + bytesConstRef r(&m_f->m_code[m_pos], 4); + return fromBigEndian(r); +} + +void CodeLocation::set(unsigned _val) +{ + assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); + assert(!get()); + bytesRef r(&m_f->m_code[m_pos], 4); + toBigEndian(_val, r); +} + +void CodeLocation::anchor() +{ + set(m_f->m_code.size()); +} + +void CodeLocation::increase(unsigned _val) +{ + assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); + bytesRef r(&m_f->m_code[m_pos], 4); + toBigEndian(get() + _val, r); +} + diff --git a/CodeLocation.h b/CodeLocation.h new file mode 100644 index 000000000..c8cf5ee87 --- /dev/null +++ b/CodeLocation.h @@ -0,0 +1,54 @@ +/* + 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 . +*/ +/** @file CodeLocation.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include "Exceptions.h" + +namespace eth +{ + +class CodeFragment; + +class CodeLocation +{ + friend class CodeFragment; + +public: + CodeLocation(CodeFragment* _f); + CodeLocation(CodeFragment* _f, unsigned _p): m_f(_f), m_pos(_p) {} + + unsigned get() const; + void increase(unsigned _val); + void set(unsigned _val); + void set(CodeLocation _loc) { assert(_loc.m_f == m_f); set(_loc.m_pos); } + void anchor(); + + CodeLocation operator+(unsigned _i) const { return CodeLocation(m_f, m_pos + _i); } + +private: + CodeFragment* m_f; + unsigned m_pos; +}; + +} From e2d327308d9024cbbb80ea21c056f38591319234 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 26 May 2014 12:12:22 +0200 Subject: [PATCH 03/92] Assembler. Debug trace stuff. --- Assembly.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ Assembly.h | 13 +++++++++--- CodeFragment.cpp | 25 ----------------------- CodeFragment.h | 2 -- Parser.cpp | 25 +++++++++++++++++++++++ Parser.h | 1 + 6 files changed, 89 insertions(+), 30 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index e69de29bb..317a92fc8 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -0,0 +1,53 @@ +/* + 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 . +*/ +/** @file Assembly.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Assembly.h" + +#include + +using namespace std; +using namespace eth; + +void Assembly::append(Assembly const& _a) +{ + for (AssemblyItem i: _a.m_items) + { + if (i.type() == Tag || i.type() == PushTag) + i.m_data += m_usedTags; + m_items.push_back(i); + } + for (auto const& i: _a.m_data) + m_data.insert(i); +} + +ostream& Assembly::streamOut(ostream& _out) const +{ + for (auto const& i: m_items) + { + } + return _out; +} + +bytes Assembly::assemble() const +{ + bytes ret; + return ret; +} diff --git a/Assembly.h b/Assembly.h index 28d2974bb..cbce3ca82 100644 --- a/Assembly.h +++ b/Assembly.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include "Exceptions.h" @@ -30,23 +31,24 @@ namespace eth enum AssemblyItemType { Operation, Push, PushString, PushTag, Tag, PushData }; +class Assembly; + class AssemblyItem { + friend class Assembly; + public: AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} - AssemblyItem(std::string const& _push): m_type(PushString), m_pushString(_push) {} AssemblyItem(AssemblyItemType _type, AssemblyItem const& _tag): m_type(_type), m_data(_tag.m_data) { assert(_type == PushTag); assert(_tag.m_type == Tag); } AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(AssemblyItemType _type, u256 _data): m_type(_type), m_data(_data) {} AssemblyItemType type() const { return m_type; } u256 data() const { return m_data; } - std::string const& pushString() const { return m_pushString; } private: AssemblyItemType m_type; u256 m_data; - std::string m_pushString; }; class Assembly @@ -54,8 +56,13 @@ class Assembly public: AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { auto h = sha3(_data); m_data[h] = _data; return AssemblyItem(PushData, h); } + AssemblyItem newPushString(std::string const& _data) { auto b = asBytes(_data); auto h = sha3(b); m_data[h] = b; return AssemblyItem(PushString, h); } + + void append(AssemblyItem const& _i) { m_items.push_back(_i); } + bytes assemble() const; void append(Assembly const& _a); + std::ostream& streamOut(std::ostream& _out) const; private: u256 m_usedTags = 0; diff --git a/CodeFragment.cpp b/CodeFragment.cpp index cc76c432a..c4b7ae0bb 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -34,31 +34,6 @@ namespace qi = boost::spirit::qi; namespace px = boost::phoenix; namespace sp = boost::spirit; -void eth::debugOutAST(ostream& _out, sp::utree const& _this) -{ - switch (_this.which()) - { - case sp::utree_type::list_type: - switch (_this.tag()) - { - case 0: _out << "( "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << ")"; break; - case 1: _out << "@ "; debugOutAST(_out, _this.front()); break; - case 2: _out << "@@ "; debugOutAST(_out, _this.front()); break; - case 3: _out << "[ "; debugOutAST(_out, _this.front()); _out << " ] "; debugOutAST(_out, _this.back()); break; - case 4: _out << "[[ "; debugOutAST(_out, _this.front()); _out << " ]] "; debugOutAST(_out, _this.back()); break; - case 5: _out << "{ "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << "}"; break; - default:; - } - - break; - case sp::utree_type::int_type: _out << _this.get(); break; - case sp::utree_type::string_type: _out << "\"" << _this.get, sp::utree_type::string_type>>() << "\""; break; - case sp::utree_type::symbol_type: _out << _this.get, sp::utree_type::symbol_type>>(); break; - case sp::utree_type::any_type: _out << *_this.get(); break; - default: _out << "nil"; - } -} - void CodeFragment::appendFragment(CodeFragment const& _f) { m_locs.reserve(m_locs.size() + _f.m_locs.size()); diff --git a/CodeFragment.h b/CodeFragment.h index cee7da3b3..9f312cda9 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -32,8 +32,6 @@ namespace sp = boost::spirit; namespace eth { -void debugOutAST(std::ostream& _out, sp::utree const& _this); - class CompilerState; class CodeFragment diff --git a/Parser.cpp b/Parser.cpp index 2a0146a60..10d2188a4 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -42,6 +42,31 @@ void eth::killBigints(sp::utree const& _this) } } +void eth::debugOutAST(ostream& _out, sp::utree const& _this) +{ + switch (_this.which()) + { + case sp::utree_type::list_type: + switch (_this.tag()) + { + case 0: _out << "( "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << ")"; break; + case 1: _out << "@ "; debugOutAST(_out, _this.front()); break; + case 2: _out << "@@ "; debugOutAST(_out, _this.front()); break; + case 3: _out << "[ "; debugOutAST(_out, _this.front()); _out << " ] "; debugOutAST(_out, _this.back()); break; + case 4: _out << "[[ "; debugOutAST(_out, _this.front()); _out << " ]] "; debugOutAST(_out, _this.back()); break; + case 5: _out << "{ "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << "}"; break; + default:; + } + + break; + case sp::utree_type::int_type: _out << _this.get(); break; + case sp::utree_type::string_type: _out << "\"" << _this.get, sp::utree_type::string_type>>() << "\""; break; + case sp::utree_type::symbol_type: _out << _this.get, sp::utree_type::symbol_type>>(); break; + case sp::utree_type::any_type: _out << *_this.get(); break; + default: _out << "nil"; + } +} + void eth::parseTreeLLL(string const& _s, sp::utree& o_out) { using qi::ascii::space; diff --git a/Parser.h b/Parser.h index 3b2756576..059ffe6a2 100644 --- a/Parser.h +++ b/Parser.h @@ -33,6 +33,7 @@ namespace eth void killBigints(sp::utree const& _this); void parseTreeLLL(std::string const& _s, sp::utree& o_out); +void debugOutAST(std::ostream& _out, sp::utree const& _this); } From 8e3e592ec6a3b39835e540766774025e3f34c590 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 26 May 2014 12:26:08 +0200 Subject: [PATCH 04/92] Add missing files. --- Assembly.cpp | 16 +++++++++++++--- Assembly.h | 2 ++ Exceptions.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 Exceptions.h diff --git a/Assembly.cpp b/Assembly.cpp index 317a92fc8..a84913762 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -40,9 +40,19 @@ void Assembly::append(Assembly const& _a) ostream& Assembly::streamOut(ostream& _out) const { - for (auto const& i: m_items) - { - } + for (AssemblyItem const& i: m_items) + switch (i.m_type) + { + case Operation: + _out << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; + break; + case Push: + _out << i.m_data << endl; + break; +/* case PushString: + _out << i.m_data << endl; + break;*/ + } return _out; } diff --git a/Assembly.h b/Assembly.h index cbce3ca82..ca3beaf5b 100644 --- a/Assembly.h +++ b/Assembly.h @@ -46,6 +46,8 @@ public: AssemblyItemType type() const { return m_type; } u256 data() const { return m_data; } + std::ostream& streamOut(std::ostream& _out) const; + private: AssemblyItemType m_type; u256 m_data; diff --git a/Exceptions.h b/Exceptions.h new file mode 100644 index 000000000..79b7cd520 --- /dev/null +++ b/Exceptions.h @@ -0,0 +1,44 @@ +/* + 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 . +*/ +/** @file Exceptions.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include + +namespace eth +{ + +/// Compile a Low-level Lisp-like Language program into EVM-code. +class CompilerException: public Exception {}; +class InvalidOperation: public CompilerException {}; +class IntegerOutOfRange: public CompilerException {}; +class StringTooLong: public CompilerException {}; +class EmptyList: public CompilerException {}; +class DataNotExecutable: public CompilerException {}; +class IncorrectParameterCount: public CompilerException {}; +class InvalidDeposit: public CompilerException {}; +class InvalidName: public CompilerException {}; +class InvalidMacroArgs: public CompilerException {}; +class InvalidLiteral: public CompilerException {}; +class BareSymbol: public CompilerException {}; +class ExpectedLiteral: public CompilerException {}; + +} From 51e6c251641eef12ba93b725974faa35b514d636 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 26 May 2014 19:41:46 +0200 Subject: [PATCH 05/92] New Assembler. --- Assembly.cpp | 175 +++++++++++++++++++++++- Assembly.h | 56 +++++++- CodeFragment.cpp | 338 +++++++++++++++-------------------------------- CodeFragment.h | 51 +------ CodeLocation.cpp | 59 --------- CodeLocation.h | 54 -------- Compiler.cpp | 27 +++- Compiler.h | 3 +- 8 files changed, 358 insertions(+), 405 deletions(-) delete mode 100644 CodeLocation.cpp delete mode 100644 CodeLocation.h diff --git a/Assembly.cpp b/Assembly.cpp index a84913762..1f53cfb5f 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -26,38 +26,201 @@ using namespace std; using namespace eth; +int AssemblyItem::deposit() const +{ + switch (m_type) + { + case Operation: + return c_instructionInfo.at((Instruction)(byte)m_data).ret - c_instructionInfo.at((Instruction)(byte)m_data).args; + case Push: case PushString: case PushTag: case PushData: + return 1; + case Tag: + return 0; + } + assert(false); +} + +unsigned Assembly::bytesRequired() const +{ + for (unsigned br = 1;; ++br) + { + unsigned ret = 1; + for (auto const& i: m_data) + ret += i.second.size(); + + for (AssemblyItem const& i: m_items) + switch (i.m_type) + { + case Operation: + ret++; + break; + case PushString: + ret += 33; + break; + case Push: + ret += 1 + max(1, eth::bytesRequired(i.m_data)); + break; + case PushTag: + case PushData: + ret += 1 + br; + case Tag:; + } + if (eth::bytesRequired(ret) <= br) + return ret; + } +} + void Assembly::append(Assembly const& _a) { for (AssemblyItem i: _a.m_items) { if (i.type() == Tag || i.type() == PushTag) i.m_data += m_usedTags; - m_items.push_back(i); + append(i); } + m_usedTags += _a.m_usedTags; for (auto const& i: _a.m_data) m_data.insert(i); + for (auto const& i: _a.m_strings) + m_strings.insert(i); + + assert(!_a.m_baseDeposit); + assert(!_a.m_totalDeposit); +} + +void Assembly::append(Assembly const& _a, int _deposit) +{ + if (_deposit > _a.m_deposit) + throw InvalidDeposit(); + else + { + append(_a); + while (_deposit++ < _a.m_deposit) + append(Instruction::POP); + } } ostream& Assembly::streamOut(ostream& _out) const { + _out << ".code:" << endl; for (AssemblyItem const& i: m_items) switch (i.m_type) { case Operation: - _out << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; + _out << " " << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; break; case Push: - _out << i.m_data << endl; + _out << " PUSH " << i.m_data << endl; + break; + case PushString: + _out << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; + break; + case PushTag: + _out << " PUSH [tag" << i.m_data << "]" << endl; + break; + case Tag: + _out << "tag" << i.m_data << ": " << endl; + break; + case PushData: + _out << " PUSH [" << h256(i.m_data).abridged() << "]" << endl; break; -/* case PushString: - _out << i.m_data << endl; - break;*/ } + + if (m_data.size()) + { + _out << ".data:" << endl; + for (auto const& i: m_data) + _out << " " << i.first.abridged() << ": " << toHex(i.second) << endl; + } return _out; } +AssemblyItem const& Assembly::append(AssemblyItem const& _i) +{ + m_deposit += _i.deposit(); + m_items.push_back(_i); + return back(); +} + bytes Assembly::assemble() const { bytes ret; + + unsigned totalBytes = bytesRequired(); + ret.reserve(totalBytes); + vector tagPos(m_usedTags); + map tagRef; + multimap dataRef; + unsigned bytesPerTag = eth::bytesRequired(totalBytes); + byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; + + for (AssemblyItem const& i: m_items) + switch (i.m_type) + { + case Operation: + ret.push_back((byte)i.m_data); + break; + case PushString: + { + ret.push_back((byte)Instruction::PUSH32); + unsigned ii = 0; + for (auto j: m_strings.at((h256)i.m_data)) + if (++ii > 32) + break; + else + ret.push_back((byte)j); + while (ii++ < 32) + ret.push_back(0); + break; + } + case Push: + { + byte b = max(1, eth::bytesRequired(i.m_data)); + ret.push_back((byte)Instruction::PUSH1 - 1 + b); + ret.resize(ret.size() + b); + bytesRef byr(&ret.back() + 1 - b, b); + toBigEndian(i.m_data, byr); + break; + } + case PushTag: + { + ret.push_back(tagPush); + tagRef[ret.size()] = (unsigned)i.m_data; + ret.resize(ret.size() + bytesPerTag); + break; + } + case PushData: + { + ret.push_back(tagPush); + dataRef.insert(make_pair((h256)i.m_data, ret.size())); + ret.resize(ret.size() + bytesPerTag); + break; + } + case Tag: + tagPos[(unsigned)i.m_data] = ret.size(); + break; + } + + for (auto const& i: tagRef) + { + bytesRef r(ret.data() + i.first, bytesPerTag); + toBigEndian(tagPos[i.second], r); + } + + if (m_data.size()) + { + ret.push_back(0); + for (auto const& i: m_data) + { + auto its = dataRef.equal_range(i.first); + for (auto it = its.first; it != its.second; ++it) + { + bytesRef r(ret.data() + it->second, bytesPerTag); + toBigEndian(ret.size(), r); + } + for (auto b: i.second) + ret.push_back(b); + } + } return ret; } diff --git a/Assembly.h b/Assembly.h index ca3beaf5b..86b37622e 100644 --- a/Assembly.h +++ b/Assembly.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include #include "Exceptions.h" @@ -39,14 +40,16 @@ class AssemblyItem public: AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} - AssemblyItem(AssemblyItemType _type, AssemblyItem const& _tag): m_type(_type), m_data(_tag.m_data) { assert(_type == PushTag); assert(_tag.m_type == Tag); } AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(AssemblyItemType _type, u256 _data): m_type(_type), m_data(_data) {} + AssemblyItem tag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(Tag, m_data); } + AssemblyItem pushTag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(PushTag, m_data); } + AssemblyItemType type() const { return m_type; } u256 data() const { return m_data; } - std::ostream& streamOut(std::ostream& _out) const; + int deposit() const; private: AssemblyItemType m_type; @@ -57,19 +60,58 @@ class Assembly { public: AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } + AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { auto h = sha3(_data); m_data[h] = _data; return AssemblyItem(PushData, h); } - AssemblyItem newPushString(std::string const& _data) { auto b = asBytes(_data); auto h = sha3(b); m_data[h] = b; return AssemblyItem(PushString, h); } + AssemblyItem newPushString(std::string const& _data) { auto h = sha3(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } - void append(AssemblyItem const& _i) { m_items.push_back(_i); } - - bytes assemble() const; + AssemblyItem append() { return append(newTag()); } void append(Assembly const& _a); + void append(Assembly const& _a, int _deposit); + AssemblyItem const& append(AssemblyItem const& _i); + AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } + AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } + + AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } + AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } + AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; } + AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; } + + template Assembly& operator<<(T const& _d) { append(_d); return *this; } + + AssemblyItem const& back() { return m_items.back(); } + std::string backString() const { return m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } + + void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } + void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } + void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } + void ignored() { m_baseDeposit = m_deposit; } + void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } + + void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); } + + std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } + int deposit() const { return m_deposit; } + bytes assemble() const; std::ostream& streamOut(std::ostream& _out) const; private: - u256 m_usedTags = 0; + void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) throw InvalidDeposit(); } + unsigned bytesRequired() const; + + unsigned m_usedTags = 0; std::vector m_items; std::map m_data; + std::map m_strings; + + int m_deposit = 0; + int m_baseDeposit = 0; + int m_totalDeposit = 0; }; +inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) +{ + _a.streamOut(_out); + return _out; +} + } diff --git a/CodeFragment.cpp b/CodeFragment.cpp index c4b7ae0bb..59ff729e7 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -34,100 +34,6 @@ namespace qi = boost::spirit::qi; namespace px = boost::phoenix; namespace sp = boost::spirit; -void CodeFragment::appendFragment(CodeFragment const& _f) -{ - m_locs.reserve(m_locs.size() + _f.m_locs.size()); - m_code.reserve(m_code.size() + _f.m_code.size()); - - unsigned os = m_code.size(); - - for (auto i: _f.m_code) - m_code.push_back(i); - - for (auto i: _f.m_locs) - { - CodeLocation(this, i + os).increase(os); - m_locs.push_back(i + os); - } - - for (auto i: _f.m_data) - m_data.insert(make_pair(i.first, i.second + os)); - - m_deposit += _f.m_deposit; -} - -CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s) -{ - CodeFragment ret; - sp::utree o; - parseTreeLLL(_src, o); - if (!o.empty()) - ret = CodeFragment(o, _s); - _s.treesToKill.push_back(o); - return ret; -} - -void CodeFragment::consolidateData() -{ - m_code.push_back(0); - bytes ld; - for (auto const& i: m_data) - { - if (ld != i.first) - { - ld = i.first; - for (auto j: ld) - m_code.push_back(j); - } - CodeLocation(this, i.second).set(m_code.size() - ld.size()); - } - m_data.clear(); -} - -void CodeFragment::appendFragment(CodeFragment const& _f, unsigned _deposit) -{ - if ((int)_deposit > _f.m_deposit) - error(); - else - { - appendFragment(_f); - while (_deposit++ < (unsigned)_f.m_deposit) - appendInstruction(Instruction::POP); - } -} - -CodeLocation CodeFragment::appendPushLocation(unsigned _locationValue) -{ - m_code.push_back((byte)Instruction::PUSH4); - CodeLocation ret(this, m_code.size()); - m_locs.push_back(m_code.size()); - m_code.resize(m_code.size() + 4); - bytesRef r(&m_code[m_code.size() - 4], 4); - toBigEndian(_locationValue, r); - m_deposit++; - return ret; -} - -unsigned CodeFragment::appendPush(u256 _literalValue) -{ - unsigned br = max(1, bytesRequired(_literalValue)); - m_code.push_back((byte)Instruction::PUSH1 + br - 1); - m_code.resize(m_code.size() + br); - for (unsigned i = 0; i < br; ++i) - { - m_code[m_code.size() - 1 - i] = (byte)(_literalValue & 0xff); - _literalValue >>= 8; - } - m_deposit++; - return br + 1; -} - -void CodeFragment::appendInstruction(Instruction _i) -{ - m_code.push_back((byte)_i); - m_deposit += c_instructionInfo.at(_i).ret - c_instructionInfo.at(_i).args; -} - CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) { /* cdebug << "CodeFragment. Locals:"; @@ -151,12 +57,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS { auto sr = _t.get, sp::utree_type::string_type>>(); string s(sr.begin(), sr.end()); - if (s.size() > 32) - error(); - h256 valHash; - memcpy(valHash.data(), s.data(), s.size()); - memset(valHash.data() + s.size(), 0, 32 - s.size()); - appendPush(valHash); + m_asm.append(s); break; } case sp::utree_type::symbol_type: @@ -164,21 +65,14 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS auto sr = _t.get, sp::utree_type::symbol_type>>(); string s(sr.begin(), sr.end()); string us = boost::algorithm::to_upper_copy(s); - if (_allowASM) - { - if (c_instructions.count(us)) - { - auto it = c_instructions.find(us); - m_deposit = c_instructionInfo.at(it->second).ret - c_instructionInfo.at(it->second).args; - m_code.push_back((byte)it->second); - } - } + if (_allowASM && c_instructions.count(us)) + m_asm.append(c_instructions.at(us)); if (_s.defs.count(s)) - appendFragment(_s.defs.at(s)); + m_asm.append(_s.defs.at(s).m_asm); else if (_s.args.count(s)) - appendFragment(_s.args.at(s)); + m_asm.append(_s.args.at(s).m_asm); else if (_s.outers.count(s)) - appendFragment(_s.outers.at(s)); + m_asm.append(_s.outers.at(s).m_asm); else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) { auto it = _s.vars.find(s); @@ -187,7 +81,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS bool ok; tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32)); } - appendPush(it->second); + m_asm.append((u256)it->second); } else error(); @@ -199,44 +93,13 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS bigint i = *_t.get(); if (i < 0 || i > bigint(u256(0) - 1)) error(); - appendPush((u256)i); + m_asm.append((u256)i); break; } default: break; } } -void CodeFragment::appendPushDataLocation(bytes const& _data) -{ - m_code.push_back((byte)Instruction::PUSH4); - m_data.insert(make_pair(_data, m_code.size())); - m_code.resize(m_code.size() + 4); - memset(&m_code.back() - 3, 0, 4); - m_deposit++; -} - -std::string CodeFragment::asPushedString() const -{ - string ret; - if (m_code.size()) - { - unsigned bc = m_code[0] - (byte)Instruction::PUSH1 + 1; - if (m_code[0] >= (byte)Instruction::PUSH1 && m_code[0] <= (byte)Instruction::PUSH32) - { - for (unsigned s = 0; s < bc && m_code[1 + s]; ++s) - ret.push_back(m_code[1 + s]); - return ret; - } - } - error(); - return ret; -} - -void CodeFragment::optimise() -{ -// map const&)>> pattern = { { "PUSH,PUSH,ADD", [](vector const& v) { return CodeFragment(appendPush(v[0] + v[1])); } } }; -} - void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { if (_t.empty()) @@ -281,7 +144,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) int c = 0; for (auto const& i: _t) if (c++) - appendFragment(CodeFragment(i, _s, true)); + m_asm.append(CodeFragment(i, _s, true).m_asm); } else if (us == "INCLUDE") { @@ -299,9 +162,9 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) else if (i.which() == sp::utree_type::symbol_type) { auto sr = i.get, sp::utree_type::symbol_type>>(); - n = _s.getDef(string(sr.begin(), sr.end())).asPushedString(); + n = _s.getDef(string(sr.begin(), sr.end())).m_asm.backString(); } - appendFragment(CodeFragment::compile(asString(contents(n)), _s)); + m_asm.append(CodeFragment::compile(asString(contents(n)), _s).m_asm); } else if (us == "DEF") { @@ -323,7 +186,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) else if (i.which() == sp::utree_type::symbol_type) { auto sr = i.get, sp::utree_type::symbol_type>>(); - n = _s.getDef(string(sr.begin(), sr.end())).asPushedString(); + n = _s.getDef(string(sr.begin(), sr.end())).m_asm.backString(); } } else if (ii == 2) @@ -362,7 +225,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) if (ii == 1) { pos = CodeFragment(i, _s); - if (pos.m_deposit != 1) + if (pos.m_asm.deposit() != 1) error(); } else if (ii == 2 && !i.tag() && i.which() == sp::utree_type::string_type) @@ -396,11 +259,11 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) error(); ++ii; } - appendPush(data.size()); - appendInstruction(Instruction::DUP); - appendPushDataLocation(data); - appendFragment(pos, 1); - appendInstruction(Instruction::CODECOPY); + m_asm.append((u256)data.size()); + m_asm.append(Instruction::DUP); + m_asm.append(data); + m_asm.append(pos.m_asm, 1); + m_asm.append(Instruction::CODECOPY); } else nonStandard = false; @@ -427,7 +290,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) auto requireSize = [&](unsigned s) { if (code.size() != s) error(); }; auto requireMinSize = [&](unsigned s) { if (code.size() < s) error(); }; auto requireMaxSize = [&](unsigned s) { if (code.size() > s) error(); }; - auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_deposit != s) error(); }; + auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_asm.deposit() != s) error(); }; if (_s.macros.count(s) && _s.macros.at(s).args.size() == code.size()) { @@ -443,7 +306,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireDeposit(i, 1); cs.args[m.args[i]] = code[i]; } - appendFragment(CodeFragment(m.code, cs)); + m_asm.append(CodeFragment(m.code, cs).m_asm); for (auto const& i: cs.defs) _s.defs[i.first] = i.second; for (auto const& i: cs.macros) @@ -459,8 +322,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireMinSize(-ea); for (unsigned i = code.size(); i; --i) - appendFragment(code[i - 1], 1); - appendInstruction(it->second); + m_asm.append(code[i - 1].m_asm, 1); + m_asm.append(it->second); } else if (c_arith.count(us)) { @@ -469,10 +332,10 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) for (unsigned i = code.size(); i; --i) { requireDeposit(i - 1, 1); - appendFragment(code[i - 1], 1); + m_asm.append(code[i - 1].m_asm, 1); } for (unsigned i = 1; i < code.size(); ++i) - appendInstruction(it->second); + m_asm.append(it->second); } else if (c_binary.count(us)) { @@ -480,74 +343,75 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireSize(2); requireDeposit(0, 1); requireDeposit(1, 1); - appendFragment(code[1], 1); - appendFragment(code[0], 1); - appendInstruction(it->second.first); + m_asm.append(code[1].m_asm, 1); + m_asm.append(code[0].m_asm, 1); + m_asm.append(it->second.first); if (it->second.second) - appendInstruction(Instruction::NOT); + m_asm.append(Instruction::NOT); } else if (c_unary.count(us)) { auto it = c_unary.find(us); requireSize(1); requireDeposit(0, 1); - appendFragment(code[0], 1); - appendInstruction(it->second); + m_asm.append(code[0].m_asm, 1); + m_asm.append(it->second); } else if (us == "IF") { requireSize(3); requireDeposit(0, 1); - appendFragment(code[0]); - auto pos = appendJumpI(); - onePath(); - appendFragment(code[2]); - auto end = appendJump(); - otherPath(); - pos.anchor(); - appendFragment(code[1]); - donePaths(); - end.anchor(); + + m_asm.append(code[0].m_asm); + auto pos = m_asm.appendJumpI(); + m_asm.onePath(); + m_asm << code[2].m_asm; + auto end = m_asm.appendJump(); + m_asm.otherPath(); + m_asm << pos.tag() << code[1].m_asm << end.tag(); + m_asm.donePaths(); } else if (us == "WHEN" || us == "UNLESS") { requireSize(2); requireDeposit(0, 1); - appendFragment(code[0]); + + m_asm.append(code[0].m_asm); if (us == "WHEN") - appendInstruction(Instruction::NOT); - auto end = appendJumpI(); - onePath(); - otherPath(); - appendFragment(code[1], 0); - donePaths(); - end.anchor(); + m_asm.append(Instruction::NOT); + auto end = m_asm.appendJumpI(); + m_asm.onePath(); + m_asm.otherPath(); + m_asm << code[1].m_asm << end.tag(); + m_asm.donePaths(); } else if (us == "WHILE") { requireSize(2); requireDeposit(0, 1); - auto begin = CodeLocation(this); - appendFragment(code[0], 1); - appendInstruction(Instruction::NOT); - auto end = appendJumpI(); - appendFragment(code[1], 0); - appendJump(begin); - end.anchor(); + + auto begin = m_asm.append(); + m_asm.append(code[0].m_asm); + m_asm.append(Instruction::NOT); + auto end = m_asm.appendJumpI(); + m_asm.append(code[1].m_asm, 0); + m_asm.appendJump(begin); + m_asm << end.tag(); } else if (us == "FOR") { requireSize(4); requireDeposit(1, 1); - appendFragment(code[0], 0); - auto begin = CodeLocation(this); - appendFragment(code[1], 1); - appendInstruction(Instruction::NOT); - auto end = appendJumpI(); - appendFragment(code[3], 0); - appendFragment(code[2], 0); - appendJump(begin); - end.anchor(); + + 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); + auto end = m_asm.appendJumpI(); + m_asm.append(code[3].m_asm, 0); + m_asm.append(code[2].m_asm, 0); + m_asm.appendJump(begin); + m_asm << end.tag(); } else if (us == "LLL") { @@ -555,22 +419,22 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireMaxSize(3); requireDeposit(1, 1); - CodeLocation codeloc(this, m_code.size() + 6); bytes const& subcode = code[0].code(); - appendPush(subcode.size()); - appendInstruction(Instruction::DUP); + + m_asm.append((u256)subcode.size()); + m_asm.append(Instruction::DUP); if (code.size() == 3) { requireDeposit(2, 1); - appendFragment(code[2], 1); - appendInstruction(Instruction::LT); - appendInstruction(Instruction::NOT); - appendInstruction(Instruction::MUL); - appendInstruction(Instruction::DUP); + m_asm.append(code[2].m_asm, 1); + m_asm.append(Instruction::LT); + m_asm.append(Instruction::NOT); + m_asm.append(Instruction::MUL); + m_asm.append(Instruction::DUP); } - appendPushDataLocation(subcode); - appendFragment(code[1], 1); - appendInstruction(Instruction::CODECOPY); + m_asm.append(subcode); + m_asm.append(code[1].m_asm, 1); + m_asm.append(Instruction::CODECOPY); } else if (us == "&&" || us == "||") { @@ -578,53 +442,52 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) for (unsigned i = 0; i < code.size(); ++i) requireDeposit(i, 1); - vector ends; + auto end = m_asm.newTag(); if (code.size() > 1) { - appendPush(us == "||" ? 1 : 0); + m_asm.append((u256)(us == "||" ? 1 : 0)); for (unsigned i = 1; i < code.size(); ++i) { // Check if true - predicate - appendFragment(code[i - 1], 1); + m_asm.append(code[i - 1].m_asm, 1); if (us == "&&") - appendInstruction(Instruction::NOT); - ends.push_back(appendJumpI()); + m_asm.append(Instruction::NOT); + m_asm.appendJumpI(end); } - appendInstruction(Instruction::POP); + m_asm.append(Instruction::POP); } // Check if true - predicate - appendFragment(code.back(), 1); + m_asm.append(code.back().m_asm, 1); // At end now. - for (auto& i: ends) - i.anchor(); + m_asm.append(end); } else if (us == "~") { requireSize(1); requireDeposit(0, 1); - appendFragment(code[0], 1); - appendPush(1); - appendPush(0); - appendInstruction(Instruction::SUB); - appendInstruction(Instruction::SUB); + + m_asm.append(code[0].m_asm, 1); + m_asm.append((u256)1); + m_asm.append((u256)0); + m_asm.append(Instruction::SUB); + m_asm.append(Instruction::SUB); } else if (us == "SEQ") { unsigned ii = 0; for (auto const& i: code) if (++ii < code.size()) - appendFragment(i, 0); + m_asm.append(i.m_asm, 0); else - appendFragment(i); + m_asm.append(i.m_asm); } else if (us == "RAW") { for (auto const& i: code) - appendFragment(i); - while (m_deposit > 1) - appendInstruction(Instruction::POP); + m_asm.append(i.m_asm); + m_asm.popTo(1); } else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) { @@ -634,9 +497,20 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) bool ok; tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32)); } - appendPush(it->second); + m_asm.append((u256)it->second); } else error(); } } + +CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s) +{ + CodeFragment ret; + sp::utree o; + parseTreeLLL(_src, o); + if (!o.empty()) + ret = CodeFragment(o, _s); + _s.treesToKill.push_back(o); + return ret; +} diff --git a/CodeFragment.h b/CodeFragment.h index 9f312cda9..647604849 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -23,7 +23,7 @@ #include #include -#include "CodeLocation.h" +#include "Assembly.h" #include "Exceptions.h" namespace boost { namespace spirit { class utree; } } @@ -36,60 +36,23 @@ class CompilerState; class CodeFragment { - friend class CodeLocation; - public: + CodeFragment() {} CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM = false); - CodeFragment(bytes const& _c = bytes()): m_code(_c) {} static CodeFragment compile(std::string const& _src, CompilerState& _s); - /// Consolidates data and returns code. - bytes const& code() { optimise(); consolidateData(); return m_code; } + /// Consolidates data and compiles code. + bytes code() const { return m_asm.assemble(); } - unsigned appendPush(u256 _l); - void appendFragment(CodeFragment const& _f); - void appendFragment(CodeFragment const& _f, unsigned _i); - void appendInstruction(Instruction _i); - - CodeLocation appendPushLocation(unsigned _l = 0); - void appendPushLocation(CodeLocation _l) { assert(_l.m_f == this); appendPushLocation(_l.m_pos); } - void appendPushDataLocation(bytes const& _data); - - CodeLocation appendJump() { auto ret = appendPushLocation(0); appendInstruction(Instruction::JUMP); return ret; } - CodeLocation appendJumpI() { auto ret = appendPushLocation(0); appendInstruction(Instruction::JUMPI); return ret; } - CodeLocation appendJump(CodeLocation _l) { auto ret = appendPushLocation(_l.m_pos); appendInstruction(Instruction::JUMP); return ret; } - CodeLocation appendJumpI(CodeLocation _l) { auto ret = appendPushLocation(_l.m_pos); appendInstruction(Instruction::JUMPI); return ret; } - - void appendFile(std::string const& _fn); - - std::string asPushedString() const; - - void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } - void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } - void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } - void ignored() { m_baseDeposit = m_deposit; } - void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } - - bool operator==(CodeFragment const& _f) const { return _f.m_code == m_code && _f.m_data == m_data; } - bool operator!=(CodeFragment const& _f) const { return !operator==(_f); } - unsigned size() const { return m_code.size(); } - - void consolidateData(); - void optimise(); + /// Consolidates data and compiles code. + std::string assembly() const { return m_asm.out(); } private: template void error() const { throw T(); } void constructOperation(sp::utree const& _t, CompilerState& _s); - void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) error(); } - - int m_deposit = 0; - int m_baseDeposit = 0; - int m_totalDeposit = 0; - bytes m_code; - std::vector m_locs; - std::multimap m_data; + Assembly m_asm; }; static const CodeFragment NullCodeFragment; diff --git a/CodeLocation.cpp b/CodeLocation.cpp deleted file mode 100644 index 2c9ca2644..000000000 --- a/CodeLocation.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file CodeLocation.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "CodeLocation.h" -#include "CodeFragment.h" -using namespace std; -using namespace eth; - -CodeLocation::CodeLocation(CodeFragment* _f) -{ - m_f = _f; - m_pos = _f->m_code.size(); -} - -unsigned CodeLocation::get() const -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - bytesConstRef r(&m_f->m_code[m_pos], 4); - return fromBigEndian(r); -} - -void CodeLocation::set(unsigned _val) -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - assert(!get()); - bytesRef r(&m_f->m_code[m_pos], 4); - toBigEndian(_val, r); -} - -void CodeLocation::anchor() -{ - set(m_f->m_code.size()); -} - -void CodeLocation::increase(unsigned _val) -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - bytesRef r(&m_f->m_code[m_pos], 4); - toBigEndian(get() + _val, r); -} - diff --git a/CodeLocation.h b/CodeLocation.h deleted file mode 100644 index c8cf5ee87..000000000 --- a/CodeLocation.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file CodeLocation.h - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include -#include -#include "Exceptions.h" - -namespace eth -{ - -class CodeFragment; - -class CodeLocation -{ - friend class CodeFragment; - -public: - CodeLocation(CodeFragment* _f); - CodeLocation(CodeFragment* _f, unsigned _p): m_f(_f), m_pos(_p) {} - - unsigned get() const; - void increase(unsigned _val); - void set(unsigned _val); - void set(CodeLocation _loc) { assert(_loc.m_f == m_f); set(_loc.m_pos); } - void anchor(); - - CodeLocation operator+(unsigned _i) const { return CodeLocation(m_f, m_pos + _i); } - -private: - CodeFragment* m_f; - unsigned m_pos; -}; - -} diff --git a/Compiler.cpp b/Compiler.cpp index afe84eb4b..777bb72d1 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -27,12 +27,12 @@ using namespace std; using namespace eth; -bytes eth::compileLLL(string const& _s, vector* _errors) +bytes eth::compileLLL(string const& _src, vector* _errors) { try { CompilerState cs; - bytes ret = CodeFragment::compile(_s, cs).code(); + bytes ret = CodeFragment::compile(_src, cs).code(); for (auto i: cs.treesToKill) killBigints(i); return ret; @@ -50,6 +50,29 @@ bytes eth::compileLLL(string const& _s, vector* _errors) return bytes(); } +std::string eth::compileLLLToAsm(std::string const& _src, std::vector* _errors) +{ + try + { + CompilerState cs; + string ret = CodeFragment::compile(_src, cs).assembly(); + for (auto i: cs.treesToKill) + killBigints(i); + return ret; + } + catch (Exception const& _e) + { + if (_errors) + _errors->push_back(_e.description()); + } + catch (std::exception) + { + if (_errors) + _errors->push_back("Parse error."); + } + return string(); +} + string eth::parseLLL(string const& _src) { sp::utree o; diff --git a/Compiler.h b/Compiler.h index e58e12bae..9dd5fc291 100644 --- a/Compiler.h +++ b/Compiler.h @@ -29,7 +29,8 @@ namespace eth { std::string parseLLL(std::string const& _src); -bytes compileLLL(std::string const& _s, std::vector* _errors = nullptr); +std::string compileLLLToAsm(std::string const& _src, std::vector* _errors = nullptr); +bytes compileLLL(std::string const& _src, std::vector* _errors = nullptr); } From 8a0dcc26c45c29b86fc4c9ea5195b44c8fe4b493 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 26 May 2014 20:09:15 +0200 Subject: [PATCH 06/92] Convenience fixups. --- Assembly.cpp | 4 ++++ Assembly.h | 1 + CodeFragment.cpp | 9 ++++++--- CodeFragment.h | 4 ++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 1f53cfb5f..3614bfc48 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -142,6 +142,10 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i) return back(); } +void Assembly::optimise() +{ +} + bytes Assembly::assemble() const { bytes ret; diff --git a/Assembly.h b/Assembly.h index 86b37622e..26392d141 100644 --- a/Assembly.h +++ b/Assembly.h @@ -92,6 +92,7 @@ public: std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } int deposit() const { return m_deposit; } bytes assemble() const; + void optimise(); std::ostream& streamOut(std::ostream& _out) const; private: diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 59ff729e7..299cda5f6 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -102,7 +102,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { - if (_t.empty()) + if (_t.tag() == 0 && _t.empty()) error(); else if (_t.tag() == 0 && _t.front().which() != sp::utree_type::symbol_type) error(); @@ -361,14 +361,17 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { requireSize(3); requireDeposit(0, 1); + int minDep = min(code[1].m_asm.deposit(), code[2].m_asm.deposit()); m_asm.append(code[0].m_asm); auto pos = m_asm.appendJumpI(); m_asm.onePath(); - m_asm << code[2].m_asm; + m_asm.append(code[2].m_asm, minDep); auto end = m_asm.appendJump(); m_asm.otherPath(); - m_asm << pos.tag() << code[1].m_asm << end.tag(); + m_asm << pos.tag(); + m_asm.append(code[1].m_asm, minDep); + m_asm << end.tag(); m_asm.donePaths(); } else if (us == "WHEN" || us == "UNLESS") diff --git a/CodeFragment.h b/CodeFragment.h index 647604849..6935a111c 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -43,10 +43,10 @@ public: static CodeFragment compile(std::string const& _src, CompilerState& _s); /// Consolidates data and compiles code. - bytes code() const { return m_asm.assemble(); } + bytes code() { m_asm.optimise(); return m_asm.assemble(); } /// Consolidates data and compiles code. - std::string assembly() const { return m_asm.out(); } + std::string assembly() { m_asm.optimise(); return m_asm.out(); } private: template void error() const { throw T(); } From 52fbe7dbfd57f4e884992b6596d54aadb070bd41 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 27 May 2014 14:02:15 +0200 Subject: [PATCH 07/92] Start of pinhole optimiser. Minor fix for debugger. --- Assembly.cpp | 2 ++ Assembly.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Assembly.cpp b/Assembly.cpp index 3614bfc48..aebe71850 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -144,6 +144,8 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i) void Assembly::optimise() { + std::vector, function< vector(vector) > >> rules; +// rules.insert(make_pair({(int)Instruction::ADD, (int)Instruction::ADD, -(int)Push}, []() {})); } bytes Assembly::assemble() const diff --git a/Assembly.h b/Assembly.h index 26392d141..5194d23fa 100644 --- a/Assembly.h +++ b/Assembly.h @@ -51,11 +51,15 @@ public: int deposit() const; + bool operator==(int _mask) const { return -_mask == (int)m_type || (m_type == Operation && _mask == (int)m_data); } + private: AssemblyItemType m_type; u256 m_data; }; +inline bool operator==(int _i, AssemblyItem _ai) { return _ai.operator==(_i); } + class Assembly { public: From 7476c6884ee22194b7d363c5e5401773d04bf47d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 27 May 2014 17:46:57 +0200 Subject: [PATCH 08/92] Quick fix for eth -j; thread naming. --- Assembly.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++- Assembly.h | 13 +++--- 2 files changed, 124 insertions(+), 7 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index aebe71850..053de61a5 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -21,6 +21,7 @@ #include "Assembly.h" +#include #include using namespace std; @@ -36,6 +37,7 @@ int AssemblyItem::deposit() const return 1; case Tag: return 0; + default:; } assert(false); } @@ -64,6 +66,7 @@ unsigned Assembly::bytesRequired() const case PushData: ret += 1 + br; case Tag:; + default:; } if (eth::bytesRequired(ret) <= br) return ret; @@ -100,6 +103,36 @@ void Assembly::append(Assembly const& _a, int _deposit) } } +ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) +{ + for (AssemblyItem const& i: _i) + switch (i.type()) + { + case Operation: + _out << " " << c_instructionInfo.at((Instruction)(byte)i.data()).name; + break; + case Push: + _out << " PUSH" << i.data(); + break; + case PushString: + _out << " PUSH'[" << h256(i.data()).abridged() << "]"; + break; + case PushTag: + _out << " PUSH[tag" << i.data() << "]"; + break; + case Tag: + _out << " tag" << i.data() << ":"; + break; + case PushData: + _out << " PUSH*[" << h256(i.data()).abridged() << "]"; + break; + case UndefinedItem: + _out << " ???"; + default:; + } + return _out; +} + ostream& Assembly::streamOut(ostream& _out) const { _out << ".code:" << endl; @@ -124,6 +157,7 @@ ostream& Assembly::streamOut(ostream& _out) const case PushData: _out << " PUSH [" << h256(i.m_data).abridged() << "]" << endl; break; + default:; } if (m_data.size()) @@ -142,10 +176,89 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i) return back(); } +inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) +{ + if (_a.size() != _b.size()) + return false; + for (unsigned i = 0; i < _a.size(); ++i) + if (!_a[i].match(_b[i])) + return false; + return true; +} + void Assembly::optimise() { - std::vector, function< vector(vector) > >> rules; -// rules.insert(make_pair({(int)Instruction::ADD, (int)Instruction::ADD, -(int)Push}, []() {})); + map> c_simple = + { + { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, + { Instruction::DIV, [](u256 a, u256 b)->u256{return a / b;} }, + { Instruction::SDIV, [](u256 a, u256 b)->u256{u256 r; (s256&)r = (s256&)a / (s256&)b; return r;} }, + { Instruction::MOD, [](u256 a, u256 b)->u256{return a % b;} }, + { Instruction::SMOD, [](u256 a, u256 b)->u256{u256 r; (s256&)r = (s256&)a % (s256&)b; return r;} }, + { Instruction::EXP, [](u256 a, u256 b)->u256{return boost::multiprecision::pow(a, (unsigned)b);} }, + { Instruction::LT, [](u256 a, u256 b)->u256{return a < b ? 1 : 0;} }, + { Instruction::GT, [](u256 a, u256 b)->u256{return a > b ? 1 : 0;} }, + { Instruction::SLT, [](u256 a, u256 b)->u256{return *(s256*)&a < *(s256*)&b ? 1 : 0;} }, + { Instruction::SGT, [](u256 a, u256 b)->u256{return *(s256*)&a > *(s256*)&b ? 1 : 0;} }, + { Instruction::EQ, [](u256 a, u256 b)->u256{return a == b ? 1 : 0;} }, + }; + map> c_associative = + { + { Instruction::ADD, [](u256 a, u256 b)->u256{return a + b;} }, + { Instruction::MUL, [](u256 a, u256 b)->u256{return a * b;} }, + }; + std::vector>> rules = + { + { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { return m[0].data() ? AssemblyItems({ m[1], Instruction::JUMP }) : AssemblyItems(); } }, + }; + + for (auto const& i: c_simple) + rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); + for (auto const& i: c_associative) + { + rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); + rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } }); + rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems + { + if (m[0].m_data == m[2].m_data) + return {}; + else + return m.toVector(); + }}); + } + + unsigned total = 0; + for (unsigned count = 1; count > 0; total += count) + { + count = 0; + for (unsigned i = 0; i < m_items.size(); ++i) + { + for (auto const& r: rules) + { + auto vr = AssemblyItemsConstRef(&m_items).cropped(i, r.first.size()); + if (matches(&r.first, vr)) + { + auto rw = r.second(vr); + if (rw.size() < vr.size()) + { + cnote << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; + for (unsigned j = 0; j < vr.size(); ++j) + if (j < rw.size()) + m_items[i + j] = rw[j]; + else + m_items.erase(m_items.begin() + i + rw.size()); + cnote << AssemblyItemsConstRef(&rw); + count++; + } + } + } + } + } + + // TODO: find all unused tags, for all those that have an unconditional jump immediately before, remove code between the tag and the next used tag (removing unused tags from the todo along the way). + + cnote << total << " optimisations done."; } bytes Assembly::assemble() const @@ -205,6 +318,7 @@ bytes Assembly::assemble() const case Tag: tagPos[(unsigned)i.m_data] = ret.size(); break; + default:; } for (auto const& i: tagRef) diff --git a/Assembly.h b/Assembly.h index 5194d23fa..2efff9437 100644 --- a/Assembly.h +++ b/Assembly.h @@ -30,7 +30,7 @@ namespace eth { -enum AssemblyItemType { Operation, Push, PushString, PushTag, Tag, PushData }; +enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, Tag, PushData }; class Assembly; @@ -41,7 +41,7 @@ class AssemblyItem public: AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} - AssemblyItem(AssemblyItemType _type, u256 _data): m_type(_type), m_data(_data) {} + AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {} AssemblyItem tag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(Tag, m_data); } AssemblyItem pushTag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(PushTag, m_data); } @@ -51,14 +51,17 @@ public: int deposit() const; - bool operator==(int _mask) const { return -_mask == (int)m_type || (m_type == Operation && _mask == (int)m_data); } + bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); } private: AssemblyItemType m_type; u256 m_data; }; -inline bool operator==(int _i, AssemblyItem _ai) { return _ai.operator==(_i); } +typedef std::vector AssemblyItems; +typedef vector_ref AssemblyItemsConstRef; + +std::ostream& operator<<(std::ostream& _out, AssemblyItemsConstRef _i); class Assembly { @@ -104,7 +107,7 @@ private: unsigned bytesRequired() const; unsigned m_usedTags = 0; - std::vector m_items; + AssemblyItems m_items; std::map m_data; std::map m_strings; From 1fdb7a1536209409010c6b6a69aedfce03c8372d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 27 May 2014 18:51:10 +0200 Subject: [PATCH 09/92] Pinhole optimise working fairly well... --- Assembly.cpp | 80 ++++++++++++++++++++++++++++++++++++++------------ Assembly.h | 1 + CodeFragment.h | 7 +++-- Compiler.cpp | 14 ++++++--- Compiler.h | 4 +-- 5 files changed, 80 insertions(+), 26 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 053de61a5..1d9cb4bcb 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -186,6 +186,9 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) return true; } +struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; +#define copt eth::LogOutputStream() + void Assembly::optimise() { map> c_simple = @@ -210,7 +213,7 @@ void Assembly::optimise() std::vector>> rules = { { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { return m[0].data() ? AssemblyItems({ m[1], Instruction::JUMP }) : AssemblyItems(); } }, + { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } }, }; for (auto const& i: c_simple) @@ -219,19 +222,16 @@ void Assembly::optimise() { rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } }); - rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems - { - if (m[0].m_data == m[2].m_data) - return {}; - else - return m.toVector(); - }}); + rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {}; else return m.toVector(); }}); } + copt << *this; + unsigned total = 0; for (unsigned count = 1; count > 0; total += count) { count = 0; + map tags; for (unsigned i = 0; i < m_items.size(); ++i) { for (auto const& r: rules) @@ -242,23 +242,64 @@ void Assembly::optimise() auto rw = r.second(vr); if (rw.size() < vr.size()) { - cnote << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; + copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; for (unsigned j = 0; j < vr.size(); ++j) if (j < rw.size()) m_items[i + j] = rw[j]; else m_items.erase(m_items.begin() + i + rw.size()); - cnote << AssemblyItemsConstRef(&rw); + copt << AssemblyItemsConstRef(&rw); count++; + copt << "Now:\n" << m_items; } } } + if (m_items[i].type() == Operation && m_items[i].data() == (byte)Instruction::JUMP) + { + bool o = false; + while (m_items.size() > i + 1 && m_items[i + 1].type() != Tag) + { + m_items.erase(m_items.begin() + i + 1); + o = true; + } + if (o) + { + copt << "Jump with no tag. Now:\n" << m_items; + ++count; + } + } + } + + for (unsigned i = 0; i < m_items.size(); ++i) + if (m_items[i].type() == Tag) + tags.insert(make_pair(m_items[i].data(), i)); + + for (auto const& i: m_items) + if (i.type() == PushTag) + tags.erase(i.data()); + + if (tags.size()) + { + auto t = *tags.begin(); + unsigned i = t.second; + if (i && m_items[i - 1].type() == Operation && m_items[i - 1].data() == (byte)Instruction::JUMP) + while (i < m_items.size() && (m_items[i].type() != Tag || tags.count(m_items[i].data()))) + { + if (m_items[i].type() == Tag && tags.count(m_items[i].data())) + tags.erase(m_items[i].data()); + m_items.erase(m_items.begin() + i); + } + else + { + m_items.erase(m_items.begin() + i); + tags.erase(t.first); + } + copt << "Unused tag. Now:\n" << m_items; + ++count; } } - // TODO: find all unused tags, for all those that have an unconditional jump immediately before, remove code between the tag and the next used tag (removing unused tags from the todo along the way). - - cnote << total << " optimisations done."; + copt << total << " optimisations done."; } bytes Assembly::assemble() const @@ -333,13 +374,16 @@ bytes Assembly::assemble() const for (auto const& i: m_data) { auto its = dataRef.equal_range(i.first); - for (auto it = its.first; it != its.second; ++it) + if (its.first != its.second) { - bytesRef r(ret.data() + it->second, bytesPerTag); - toBigEndian(ret.size(), r); + for (auto it = its.first; it != its.second; ++it) + { + bytesRef r(ret.data() + it->second, bytesPerTag); + toBigEndian(ret.size(), r); + } + for (auto b: i.second) + ret.push_back(b); } - for (auto b: i.second) - ret.push_back(b); } } return ret; diff --git a/Assembly.h b/Assembly.h index 2efff9437..a3bf998d6 100644 --- a/Assembly.h +++ b/Assembly.h @@ -62,6 +62,7 @@ typedef std::vector AssemblyItems; typedef vector_ref AssemblyItemsConstRef; std::ostream& operator<<(std::ostream& _out, AssemblyItemsConstRef _i); +inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { return operator<<(_out, AssemblyItemsConstRef(&_i)); } class Assembly { diff --git a/CodeFragment.h b/CodeFragment.h index 6935a111c..2c6f2cce6 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -43,10 +43,13 @@ public: static CodeFragment compile(std::string const& _src, CompilerState& _s); /// Consolidates data and compiles code. - bytes code() { m_asm.optimise(); return m_asm.assemble(); } + bytes code() const { return m_asm.assemble(); } /// Consolidates data and compiles code. - std::string assembly() { m_asm.optimise(); return m_asm.out(); } + std::string assembly() const { return m_asm.out(); } + + /// Optimise the code. Best do this just before calling code() or assembly(). + void optimise() { m_asm.optimise(); } private: template void error() const { throw T(); } diff --git a/Compiler.cpp b/Compiler.cpp index 777bb72d1..cd326341c 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -27,12 +27,15 @@ using namespace std; using namespace eth; -bytes eth::compileLLL(string const& _src, vector* _errors) +bytes eth::compileLLL(string const& _src, bool _opt, vector* _errors) { try { CompilerState cs; - bytes ret = CodeFragment::compile(_src, cs).code(); + auto f = CodeFragment::compile(_src, cs); + if (_opt) + f.optimise(); + bytes ret = f.code(); for (auto i: cs.treesToKill) killBigints(i); return ret; @@ -50,12 +53,15 @@ bytes eth::compileLLL(string const& _src, vector* _errors) return bytes(); } -std::string eth::compileLLLToAsm(std::string const& _src, std::vector* _errors) +std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector* _errors) { try { CompilerState cs; - string ret = CodeFragment::compile(_src, cs).assembly(); + auto f = CodeFragment::compile(_src, cs); + if (_opt) + f.optimise(); + string ret = f.assembly(); for (auto i: cs.treesToKill) killBigints(i); return ret; diff --git a/Compiler.h b/Compiler.h index 9dd5fc291..395d79094 100644 --- a/Compiler.h +++ b/Compiler.h @@ -29,8 +29,8 @@ namespace eth { std::string parseLLL(std::string const& _src); -std::string compileLLLToAsm(std::string const& _src, std::vector* _errors = nullptr); -bytes compileLLL(std::string const& _src, std::vector* _errors = nullptr); +std::string compileLLLToAsm(std::string const& _src, bool _opt = true, std::vector* _errors = nullptr); +bytes compileLLL(std::string const& _src, bool _opt = true, std::vector* _errors = nullptr); } From 009b25d043adc8f165de525eecc19702d105c125 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 27 May 2014 19:11:37 +0200 Subject: [PATCH 10/92] Assembler fix. --- Assembly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assembly.h b/Assembly.h index a3bf998d6..3907f69fd 100644 --- a/Assembly.h +++ b/Assembly.h @@ -87,7 +87,7 @@ public: template Assembly& operator<<(T const& _d) { append(_d); return *this; } AssemblyItem const& back() { return m_items.back(); } - std::string backString() const { return m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } + std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } From 72265ac38ad65b0adc07e7ea7ece26baea9b356c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 29 May 2014 20:30:56 +0200 Subject: [PATCH 11/92] Fix for unless/when. --- CodeFragment.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 299cda5f6..f30fba956 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -385,7 +385,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) auto end = m_asm.appendJumpI(); m_asm.onePath(); m_asm.otherPath(); - m_asm << code[1].m_asm << end.tag(); + m_asm.append(code[1].m_asm, 0); + m_asm << end.tag(); m_asm.donePaths(); } else if (us == "WHILE") From 362cfb350e8cd2ea58615877e3f1d37b95f0d0bf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 29 May 2014 23:11:45 +0200 Subject: [PATCH 12/92] Revert "Fix for unless/when." This reverts commit b12d91e726ae5d1742e6d828c2cb5b694ffdf8a3. --- CodeFragment.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index f30fba956..299cda5f6 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -385,8 +385,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) auto end = m_asm.appendJumpI(); m_asm.onePath(); m_asm.otherPath(); - m_asm.append(code[1].m_asm, 0); - m_asm << end.tag(); + m_asm << code[1].m_asm << end.tag(); m_asm.donePaths(); } else if (us == "WHILE") From de85b070b8c65f9ea7e1dd261467d759798629f7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 29 May 2014 23:21:51 +0200 Subject: [PATCH 13/92] Fix for when/unless. --- CodeFragment.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 299cda5f6..f30fba956 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -385,7 +385,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) auto end = m_asm.appendJumpI(); m_asm.onePath(); m_asm.otherPath(); - m_asm << code[1].m_asm << end.tag(); + m_asm.append(code[1].m_asm, 0); + m_asm << end.tag(); m_asm.donePaths(); } else if (us == "WHILE") From b64a96199fb17d624974d8d5efe8e0758ef117bf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 30 May 2014 13:37:39 +0200 Subject: [PATCH 14/92] Fix for nonce incrementing. Messaging for some execution failures. State uses temporary for transaction trie. Additional optimisation. --- Assembly.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Assembly.cpp b/Assembly.cpp index 1d9cb4bcb..c0dc6fd5e 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -213,7 +213,10 @@ void Assembly::optimise() std::vector>> rules = { { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { PushTag, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { PushString, 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 {}; } }, }; for (auto const& i: c_simple) From 78c0baa026d69a6b03d0f3d9288c4da4e03f4b96 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 30 May 2014 14:47:13 +0200 Subject: [PATCH 15/92] Actually do endow ether. Standard extension. --- Compiler.cpp | 2 ++ CompilerState.cpp | 23 +++++++++++++++++++++++ CompilerState.h | 1 + 3 files changed, 26 insertions(+) diff --git a/Compiler.cpp b/Compiler.cpp index cd326341c..8400ad955 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -32,6 +32,7 @@ bytes eth::compileLLL(string const& _src, bool _opt, vector* _errors) try { CompilerState cs; + cs.populateStandard(); auto f = CodeFragment::compile(_src, cs); if (_opt) f.optimise(); @@ -58,6 +59,7 @@ std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector try { CompilerState cs; + cs.populateStandard(); auto f = CodeFragment::compile(_src, cs); if (_opt) f.optimise(); diff --git a/CompilerState.cpp b/CompilerState.cpp index d2894475a..571b9de3d 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -20,6 +20,7 @@ */ #include "CompilerState.h" +#include "CodeFragment.h" using namespace std; using namespace eth; @@ -35,3 +36,25 @@ CodeFragment const& CompilerState::getDef(std::string const& _s) else return NullCodeFragment; } + +void CompilerState::populateStandard() +{ + static const string s = "{" + "(def 'gav 0x8a40bfaa73256b60764c1bf40675a99083efb075)" + "(def 'send (to value) (call (- (gas) 21) to value 0 0 0 0))" +#if 0 + "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" + "(def 'alloc (len) (asm msize 0 1 len msize add sub mstore8))" + "(def 'msg (gaslimit to value data datasize outsize) { [32]:outsize [0]:(alloc @32) (call gaslimit to value data datasize @0 @32) @0 })" + "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" + "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" + "(def 'create (to value code) { [0]:(msize) (create to value @0 (lll code @0)) })" + "(def 'sha3 (val) { [0]:val (sha3 0 32) })" + "(def 'return (val) { [0]:val (return 0 32) })" + "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" + "(def 'permcount 0)" + "(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )" +#endif + "}"; + CodeFragment::compile(s, *this); +} diff --git a/CompilerState.h b/CompilerState.h index d53c2bcd7..7f3cef82e 100644 --- a/CompilerState.h +++ b/CompilerState.h @@ -37,6 +37,7 @@ struct Macro struct CompilerState { CodeFragment const& getDef(std::string const& _s); + void populateStandard(); std::map vars; std::map defs; From b379ce906530797f0f58569653b648ab64f2968d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 30 May 2014 14:55:07 +0200 Subject: [PATCH 16/92] Variadic macros work. --- CodeFragment.cpp | 17 ++++++++++------- CompilerState.cpp | 2 +- CompilerState.h | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index f30fba956..448d3ef2f 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -172,6 +172,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) unsigned ii = 0; if (_t.size() != 3 && _t.size() != 4) error(); + vector args; for (auto const& i: _t) { if (ii == 1) @@ -198,16 +199,18 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) if (j.tag() || j.which() != sp::utree_type::symbol_type) error(); auto sr = j.get, sp::utree_type::symbol_type>>(); - _s.macros[n].args.push_back(string(sr.begin(), sr.end())); + args.push_back(string(sr.begin(), sr.end())); } else if (ii == 3) { - _s.macros[n].code = i; - _s.macros[n].env = _s.outers; + auto k = make_pair(n, args.size()); + _s.macros[k].code = i; + _s.macros[k].env = _s.outers; + _s.macros[k].args = args; for (auto const& i: _s.args) - _s.macros[n].env[i.first] = i.second; + _s.macros[k].env[i.first] = i.second; for (auto const& i: _s.defs) - _s.macros[n].env[i.first] = i.second; + _s.macros[k].env[i.first] = i.second; } ++ii; } @@ -292,9 +295,9 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) auto requireMaxSize = [&](unsigned s) { if (code.size() > s) error(); }; auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_asm.deposit() != s) error(); }; - if (_s.macros.count(s) && _s.macros.at(s).args.size() == code.size()) + if (_s.macros.count(make_pair(s, code.size()))) { - Macro const& m = _s.macros.at(s); + Macro const& m = _s.macros.at(make_pair(s, code.size())); CompilerState cs = _s; for (auto const& i: m.env) cs.outers[i.first] = i.second; diff --git a/CompilerState.cpp b/CompilerState.cpp index 571b9de3d..e5d0b2a0a 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -42,8 +42,8 @@ void CompilerState::populateStandard() static const string s = "{" "(def 'gav 0x8a40bfaa73256b60764c1bf40675a99083efb075)" "(def 'send (to value) (call (- (gas) 21) to value 0 0 0 0))" -#if 0 "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" +#if 1 "(def 'alloc (len) (asm msize 0 1 len msize add sub mstore8))" "(def 'msg (gaslimit to value data datasize outsize) { [32]:outsize [0]:(alloc @32) (call gaslimit to value data datasize @0 @32) @0 })" "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" diff --git a/CompilerState.h b/CompilerState.h index 7f3cef82e..b7581e0bc 100644 --- a/CompilerState.h +++ b/CompilerState.h @@ -43,7 +43,7 @@ struct CompilerState std::map defs; std::map args; std::map outers; - std::map macros; + std::map, Macro> macros; std::vector treesToKill; }; From 8c25c35b375b5284505e0004ad741497c222e293 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 31 May 2014 00:49:07 +0200 Subject: [PATCH 17/92] Javascript console and env.load(), env.note, ... --- Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Parser.cpp b/Parser.cpp index 10d2188a4..de0a5428a 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -75,7 +75,7 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) qi::rule element; qi::rule str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"'; - qi::rule strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;())") + '\0'))]; + qi::rule strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;@()[]{}:") + '\0'))]; qi::rule symbol = qi::lexeme[+(~qi::char_(std::string(" @[]{}:();\"\x01-\x1f\x7f") + '\0'))]; qi::rule intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]]; qi::rule integer = intstr; From 9ebaeb53fa398a2b983bd9320cd73d3c2f0b2c62 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 31 May 2014 02:00:49 +0200 Subject: [PATCH 18/92] Minor bug fix. Fixes for a few warnings. --- Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assembly.cpp b/Assembly.cpp index c0dc6fd5e..4b7d98345 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -39,7 +39,7 @@ int AssemblyItem::deposit() const return 0; default:; } - assert(false); + return 0; } unsigned Assembly::bytesRequired() const From 7afd678509cf01187d8a706a0bbdb45df115f755 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 31 May 2014 13:01:06 +0200 Subject: [PATCH 19/92] Fix for compiler. --- CompilerState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompilerState.cpp b/CompilerState.cpp index e5d0b2a0a..2d23d14ec 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -48,7 +48,7 @@ void CompilerState::populateStandard() "(def 'msg (gaslimit to value data datasize outsize) { [32]:outsize [0]:(alloc @32) (call gaslimit to value data datasize @0 @32) @0 })" "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" - "(def 'create (to value code) { [0]:(msize) (create to value @0 (lll code @0)) })" + "(def 'create (value code) { [0]:(msize) (create value @0 (lll code @0)) })" "(def 'sha3 (val) { [0]:val (sha3 0 32) })" "(def 'return (val) { [0]:val (return 0 32) })" "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" From 99e9cb0e2e891a790553adf9309362a709e8689a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 31 May 2014 13:06:32 +0200 Subject: [PATCH 20/92] Additional variants of create and send. --- CompilerState.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CompilerState.cpp b/CompilerState.cpp index 2d23d14ec..5cf2a965d 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -43,18 +43,19 @@ void CompilerState::populateStandard() "(def 'gav 0x8a40bfaa73256b60764c1bf40675a99083efb075)" "(def 'send (to value) (call (- (gas) 21) to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" -#if 1 "(def 'alloc (len) (asm msize 0 1 len msize add sub mstore8))" "(def 'msg (gaslimit to value data datasize outsize) { [32]:outsize [0]:(alloc @32) (call gaslimit to value data datasize @0 @32) @0 })" "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" + "(def 'msg (to value data) { [0]:data (msg 0 to value 0 32) })" + "(def 'msg (to data) { [0]:data (msg 0 to 0 0 32) })" "(def 'create (value code) { [0]:(msize) (create value @0 (lll code @0)) })" + "(def 'create (code) { [0]:(msize) (create 0 @0 (lll code @0)) })" "(def 'sha3 (val) { [0]:val (sha3 0 32) })" "(def 'return (val) { [0]:val (return 0 32) })" "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" "(def 'permcount 0)" "(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )" -#endif "}"; CodeFragment::compile(s, *this); } From f64b371382e0a7f2adbe4fd3b45f61fd1ad7d759 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 31 May 2014 13:41:08 +0200 Subject: [PATCH 21/92] Fixes and language additions. --- CompilerState.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CompilerState.cpp b/CompilerState.cpp index 5cf2a965d..74e5062f7 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -41,6 +41,11 @@ void CompilerState::populateStandard() { static const string s = "{" "(def 'gav 0x8a40bfaa73256b60764c1bf40675a99083efb075)" + "(def 'namereg 0x2d0aceee7e5ab874e22ccf8d1a649f59106d74e8)" + "(def 'config 0xccdeac59d35627b7de09332e819d5159e7bb7250)" + "(def 'gavcoin 0x5620133321fcac7f15a5c570016f6cb6dc263f9d)" + "(def 'sendgavcoin (to value) { [0]:to [32]:value (call (- (gas) 21) gavcoin 0 0 64 0 0) })" + "(def 'regname (name) { [0]:name (call (- (gas) 21) namereg 0 0 32 0 0) })" "(def 'send (to value) (call (- (gas) 21) to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" "(def 'alloc (len) (asm msize 0 1 len msize add sub mstore8))" @@ -53,6 +58,7 @@ void CompilerState::populateStandard() "(def 'create (code) { [0]:(msize) (create 0 @0 (lll code @0)) })" "(def 'sha3 (val) { [0]:val (sha3 0 32) })" "(def 'return (val) { [0]:val (return 0 32) })" + "(def 'returnlll (code) (return 0 (lll code 0)) )" "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" "(def 'permcount 0)" "(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )" From bbc7bd19e529cd1a64708b45b8f8193b60d5fb59 Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Wed, 4 Jun 2014 11:34:14 +0100 Subject: [PATCH 22/92] Fixed all the windows compile errors and project reorg with the exception of the more complex problem in Parser.cpp --- CodeFragment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeFragment.h b/CodeFragment.h index 2c6f2cce6..8e3ff1d7d 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -32,7 +32,7 @@ namespace sp = boost::spirit; namespace eth { -class CompilerState; +struct CompilerState; class CodeFragment { From 5ea7efd593aa4576df6ac0c2b3c334e0f4ec6201 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 10 Jun 2014 16:49:54 +0100 Subject: [PATCH 23/92] Fix signed instructions. --- Assembly.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 4b7d98345..0de16982f 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -195,14 +195,14 @@ void Assembly::optimise() { { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, { Instruction::DIV, [](u256 a, u256 b)->u256{return a / b;} }, - { Instruction::SDIV, [](u256 a, u256 b)->u256{u256 r; (s256&)r = (s256&)a / (s256&)b; return r;} }, + { Instruction::SDIV, [](u256 a, u256 b)->u256{return s2u(u2s(a) / u2s(b));} }, { Instruction::MOD, [](u256 a, u256 b)->u256{return a % b;} }, - { Instruction::SMOD, [](u256 a, u256 b)->u256{u256 r; (s256&)r = (s256&)a % (s256&)b; return r;} }, + { Instruction::SMOD, [](u256 a, u256 b)->u256{return s2u(u2s(a) % u2s(b));} }, { Instruction::EXP, [](u256 a, u256 b)->u256{return boost::multiprecision::pow(a, (unsigned)b);} }, { Instruction::LT, [](u256 a, u256 b)->u256{return a < b ? 1 : 0;} }, { Instruction::GT, [](u256 a, u256 b)->u256{return a > b ? 1 : 0;} }, - { Instruction::SLT, [](u256 a, u256 b)->u256{return *(s256*)&a < *(s256*)&b ? 1 : 0;} }, - { Instruction::SGT, [](u256 a, u256 b)->u256{return *(s256*)&a > *(s256*)&b ? 1 : 0;} }, + { Instruction::SLT, [](u256 a, u256 b)->u256{return u2s(a) < u2s(b) ? 1 : 0;} }, + { Instruction::SGT, [](u256 a, u256 b)->u256{return u2s(a) > u2s(b) ? 1 : 0;} }, { Instruction::EQ, [](u256 a, u256 b)->u256{return a == b ? 1 : 0;} }, }; map> c_associative = From a2219639febeeac1807c670071aded337d7a4d7c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 11 Jun 2014 19:25:21 +0100 Subject: [PATCH 24/92] LLL supports get/set/ref. Logging changes. --- CodeFragment.cpp | 81 ++++++++++++++++++++++++++++++++--------------- CompilerState.cpp | 4 +++ CompilerState.h | 5 ++- 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 448d3ef2f..804504f07 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -79,9 +79,10 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS if (it == _s.vars.end()) { bool ok; - tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32)); + tie(it, ok) = _s.vars.insert(make_pair(s, make_pair(_s.stackSize, 32))); + _s.stackSize += 32; } - m_asm.append((u256)it->second); + m_asm.append((u256)it->second.first); } else error(); @@ -137,6 +138,36 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) default:; } + auto firstAsString = [&]() + { + auto i = *++_t.begin(); + if (i.tag()) + error(); + if (i.which() == sp::utree_type::string_type) + { + auto sr = i.get, sp::utree_type::string_type>>(); + return string(sr.begin(), sr.end()); + } + else if (i.which() == sp::utree_type::symbol_type) + { + auto sr = i.get, sp::utree_type::symbol_type>>(); + return _s.getDef(string(sr.begin(), sr.end())).m_asm.backString(); + } + return string(); + }; + + auto varAddress = [&](string const& n) + { + auto it = _s.vars.find(n); + if (it == _s.vars.end()) + { + bool ok; + tie(it, ok) = _s.vars.insert(make_pair(n, make_pair(_s.stackSize, 32))); + _s.stackSize += 32; + } + return it->second.first; + }; + // Operations who args are not standard stack-pushers. bool nonStandard = true; if (us == "ASM") @@ -150,22 +181,28 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { if (_t.size() != 2) error(); - string n; - auto i = *++_t.begin(); - if (i.tag()) - error(); - if (i.which() == sp::utree_type::string_type) - { - auto sr = i.get, sp::utree_type::string_type>>(); - n = string(sr.begin(), sr.end()); - } - else if (i.which() == sp::utree_type::symbol_type) - { - auto sr = i.get, sp::utree_type::symbol_type>>(); - n = _s.getDef(string(sr.begin(), sr.end())).m_asm.backString(); - } - m_asm.append(CodeFragment::compile(asString(contents(n)), _s).m_asm); + m_asm.append(CodeFragment::compile(asString(contents(firstAsString())), _s).m_asm); } + else if (us == "SET") + { + if (_t.size() != 3) + error(); + int c = 0; + for (auto const& i: _t) + if (c++ == 2) + m_asm.append(CodeFragment(i, _s, false).m_asm); + m_asm.append((u256)varAddress(firstAsString())); + m_asm.append(Instruction::MSTORE); + } + else if (us == "GET") + { + if (_t.size() != 2) + error(); + m_asm.append((u256)varAddress(firstAsString())); + m_asm.append(Instruction::MLOAD); + } + else if (us == "REF") + m_asm.append((u256)varAddress(firstAsString())); else if (us == "DEF") { string n; @@ -497,15 +534,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.popTo(1); } else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) - { - auto it = _s.vars.find(s); - if (it == _s.vars.end()) - { - bool ok; - tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32)); - } - m_asm.append((u256)it->second); - } + m_asm.append((u256)varAddress(s)); else error(); } diff --git a/CompilerState.cpp b/CompilerState.cpp index 74e5062f7..490e92672 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -25,6 +25,10 @@ using namespace std; using namespace eth; +CompilerState::CompilerState() +{ +} + CodeFragment const& CompilerState::getDef(std::string const& _s) { if (defs.count(_s)) diff --git a/CompilerState.h b/CompilerState.h index b7581e0bc..f8f7ce815 100644 --- a/CompilerState.h +++ b/CompilerState.h @@ -36,10 +36,13 @@ struct Macro struct CompilerState { + CompilerState(); + CodeFragment const& getDef(std::string const& _s); void populateStandard(); - std::map vars; + unsigned stackSize = 64; + std::map> vars; ///< maps name to stack offset & size. std::map defs; std::map args; std::map outers; From 52d7d699021182207853cc657f3633f4f960fcc3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 12 Jun 2014 18:35:39 +0100 Subject: [PATCH 25/92] Standard service JS script. Bug fix for load & LLL macros. Move to new services. --- CodeFragment.cpp | 2 +- CompilerState.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 804504f07..9284c1f31 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -343,7 +343,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) cs.defs.clear(); for (unsigned i = 0; i < m.args.size(); ++i) { - requireDeposit(i, 1); + //requireDeposit(i, 1); cs.args[m.args[i]] = code[i]; } m_asm.append(CodeFragment(m.code, cs).m_asm); diff --git a/CompilerState.cpp b/CompilerState.cpp index 490e92672..7e990413f 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -44,7 +44,7 @@ CodeFragment const& CompilerState::getDef(std::string const& _s) void CompilerState::populateStandard() { static const string s = "{" - "(def 'gav 0x8a40bfaa73256b60764c1bf40675a99083efb075)" + "(def 'gav 0x51ba59315b3a95761d0863b05ccc7a7f54703d99)" "(def 'namereg 0x2d0aceee7e5ab874e22ccf8d1a649f59106d74e8)" "(def 'config 0xccdeac59d35627b7de09332e819d5159e7bb7250)" "(def 'gavcoin 0x5620133321fcac7f15a5c570016f6cb6dc263f9d)" From 2c0c091616cb5a57626c714e8857e31cc39b5ab7 Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Wed, 18 Jun 2014 12:24:56 +0100 Subject: [PATCH 26/92] Fixed MSVC compile errors (but missing functionality in LLL parser) --- Parser.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Parser.cpp b/Parser.cpp index de0a5428a..98583f332 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -87,9 +87,16 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) qi::rule sload = qi::lit("@@") > element; qi::rule mstore = '[' > element > ']' > -qi::lit(":") > element; qi::rule sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element; - qi::rule extra = sload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 2)] | mload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 1)] | sstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 4)] | mstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 3)] | seq[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 5)]; qi::rule list = '(' > *element > ')'; + + // todo: fix compound compile errors in this line for Visual Studio 2013 +#ifndef _MSC_VER + qi::rule extra = sload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 2)] | mload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 1)] | sstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 4)] | mstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 3)] | seq[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 5)]; element = atom | list | extra; +#else + element = atom | list/* | extra*/; +#endif + string s; s.reserve(_s.size()); From eaf79f924c3757268fe6829dbeef6fdfd7960d45 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 22 Jun 2014 11:41:29 +0100 Subject: [PATCH 27/92] Better language determination. --- Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Parser.cpp b/Parser.cpp index 98583f332..13faf5839 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -118,6 +118,6 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) if (!incomment) s.push_back(i); } - qi::phrase_parse(s.cbegin(), s.cend(), element, space, o_out); + qi::phrase_parse(s.cbegin(), s.cend(), element, space, qi::skip_flag::dont_postskip, o_out); } From 18c3da3eb29fa646f34b56876012abcee65e03ca Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 22 Jun 2014 20:36:16 +0100 Subject: [PATCH 28/92] Better language detection. --- Parser.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Parser.cpp b/Parser.cpp index 13faf5839..0ae3c6fee 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -118,6 +118,9 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) if (!incomment) s.push_back(i); } - qi::phrase_parse(s.cbegin(), s.cend(), element, space, qi::skip_flag::dont_postskip, o_out); + auto ret = s.cbegin(); + qi::phrase_parse(ret, s.cend(), element, space, qi::skip_flag::dont_postskip, o_out); + if (ret != s.cend()) + throw std::exception(); } From 5e2b4bbd58f1d244d1aab985e07835071692d7a5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 27 Jun 2014 23:47:24 +0200 Subject: [PATCH 29/92] Project refactor. Introduce the Serpent library. --- Assembly.cpp | 2 +- Assembly.h | 5 +++-- CMakeLists.txt | 11 ++--------- CodeFragment.cpp | 4 ++-- CodeFragment.h | 4 ++-- Compiler.h | 2 +- Parser.h | 2 +- 7 files changed, 12 insertions(+), 18 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 0de16982f..0fa125378 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -21,7 +21,7 @@ #include "Assembly.h" -#include +#include #include using namespace std; diff --git a/Assembly.h b/Assembly.h index 3907f69fd..29f899c0e 100644 --- a/Assembly.h +++ b/Assembly.h @@ -23,8 +23,9 @@ #include #include -#include -#include +#include +#include +#include #include "Exceptions.h" namespace eth diff --git a/CMakeLists.txt b/CMakeLists.txt index dc5fc2221..4117e6edc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,17 +18,10 @@ endif() file(GLOB HEADERS "*.h") include_directories(..) -include_directories(${MINIUPNPC_ID}) -include_directories(${LEVELDB_ID}) - -target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} ethsupport) -target_link_libraries(${EXECUTABLE} secp256k1) -target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) +target_link_libraries(${EXECUTABLE} ethential) +target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} gmp) - if(${TARGET_PLATFORM} STREQUAL "w64") include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) target_link_libraries(${EXECUTABLE} cryptopp) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 9284c1f31..2ad23471d 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -24,8 +24,8 @@ #include #include -#include -#include +#include +#include #include #include "CompilerState.h" using namespace std; diff --git a/CodeFragment.h b/CodeFragment.h index 8e3ff1d7d..b9d44c030 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -21,8 +21,8 @@ #pragma once -#include -#include +#include +#include #include "Assembly.h" #include "Exceptions.h" diff --git a/Compiler.h b/Compiler.h index 395d79094..da84a2fea 100644 --- a/Compiler.h +++ b/Compiler.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace eth { diff --git a/Parser.h b/Parser.h index 059ffe6a2..5286c3e8a 100644 --- a/Parser.h +++ b/Parser.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace boost { namespace spirit { class utree; } } namespace sp = boost::spirit; From 674ff8e3cc1e95a351d14683db7b67a7822d5aa3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 28 Jun 2014 19:23:32 +0200 Subject: [PATCH 30/92] Full python serpent support. Shared libs on all platforms. --- Assembly.h | 4 ++-- CMakeLists.txt | 26 ++++++-------------------- CodeFragment.cpp | 1 - 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/Assembly.h b/Assembly.h index 29f899c0e..3e8a83260 100644 --- a/Assembly.h +++ b/Assembly.h @@ -70,8 +70,8 @@ class Assembly public: AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } - AssemblyItem newData(bytes const& _data) { auto h = sha3(_data); m_data[h] = _data; return AssemblyItem(PushData, h); } - AssemblyItem newPushString(std::string const& _data) { auto h = sha3(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } + AssemblyItem newData(bytes const& _data) { h256 h = (u256)std::hash()(asString(_data)); m_data[h] = _data; return AssemblyItem(PushData, h); } + AssemblyItem newPushString(std::string const& _data) { h256 h = (u256)std::hash()(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } AssemblyItem append() { return append(newTag()); } void append(Assembly const& _a); diff --git a/CMakeLists.txt b/CMakeLists.txt index 4117e6edc..2356b7d9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,27 +6,20 @@ aux_source_directory(. SRC_LIST) set(EXECUTABLE lll) -if(APPLE) - # set(CMAKE_INSTALL_PREFIX ../lib) - add_library(${EXECUTABLE} SHARED ${SRC_LIST}) -else() - add_library(${EXECUTABLE} ${SRC_LIST}) -endif() -if (UNIX) - FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework locale) -endif() +# set(CMAKE_INSTALL_PREFIX ../lib) +add_library(${EXECUTABLE} SHARED ${SRC_LIST}) + file(GLOB HEADERS "*.h") include_directories(..) -target_link_libraries(${EXECUTABLE} ethential) + target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} ethential) target_link_libraries(${EXECUTABLE} gmp) + if(${TARGET_PLATFORM} STREQUAL "w64") - include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) - target_link_libraries(${EXECUTABLE} cryptopp) target_link_libraries(${EXECUTABLE} boost_system-mt-s) - target_link_libraries(${EXECUTABLE} boost_filesystem-mt-s) target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) target_link_libraries(${EXECUTABLE} iphlpapi) target_link_libraries(${EXECUTABLE} ws2_32) @@ -34,23 +27,16 @@ if(${TARGET_PLATFORM} STREQUAL "w64") target_link_libraries(${EXECUTABLE} shlwapi) elseif (APPLE) # Latest mavericks boost libraries only come with -mt - target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} boost_system-mt) - target_link_libraries(${EXECUTABLE} boost_filesystem-mt) target_link_libraries(${EXECUTABLE} boost_thread-mt) find_package(Threads REQUIRED) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) elseif (UNIX) - target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARY}) target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${Boost_DATE_TIME_LIBRARY}) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) else () - target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} boost_system) - target_link_libraries(${EXECUTABLE} boost_filesystem) target_link_libraries(${EXECUTABLE} boost_thread) find_package(Threads REQUIRED) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 2ad23471d..f0aeb860c 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include "CompilerState.h" using namespace std; using namespace eth; From e65c3ff17de66cfd7d80ef78abba09c6ecf35ded Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 30 Jun 2014 11:49:52 +0200 Subject: [PATCH 31/92] Docs & consolidation of headers. --- All.h | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 All.h diff --git a/All.h b/All.h new file mode 100644 index 000000000..ec6989e66 --- /dev/null +++ b/All.h @@ -0,0 +1,7 @@ +#pragma once + +#include "Assembly.h" +#include "CodeFragment.h" +#include "Compiler.h" +#include "CompilerState.h" +#include "Parser.h" From 3174a5e0c6072004159326f000c0e1dfe6703b00 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Jul 2014 00:16:01 +0200 Subject: [PATCH 32/92] Fixed problem with alloc. --- Assembly.cpp | 5 +++++ Assembly.h | 2 ++ CodeFragment.cpp | 39 +++++++++++++++++++++++++++++++++++++-- CodeFragment.h | 7 +++++-- Compiler.cpp | 4 ++-- CompilerState.cpp | 3 +-- CompilerState.h | 1 + 7 files changed, 53 insertions(+), 8 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 0fa125378..7016b2863 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -176,6 +176,11 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i) return back(); } +void Assembly::injectStart(AssemblyItem const& _i) +{ + m_items.insert(m_items.begin(), _i); +} + inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) { if (_a.size() != _b.size()) diff --git a/Assembly.h b/Assembly.h index 3e8a83260..9cd10a820 100644 --- a/Assembly.h +++ b/Assembly.h @@ -98,6 +98,8 @@ public: void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); } + void injectStart(AssemblyItem const& _i); + std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } int deposit() const { return m_deposit; } bytes assemble() const; diff --git a/CodeFragment.cpp b/CodeFragment.cpp index f0aeb860c..70973aab4 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -19,7 +19,6 @@ * @date 2014 */ -#include "Parser.h" #include "CodeFragment.h" #include @@ -27,12 +26,30 @@ #include #include #include "CompilerState.h" +#include "Parser.h" using namespace std; using namespace eth; namespace qi = boost::spirit::qi; namespace px = boost::phoenix; namespace sp = boost::spirit; +void CodeFragment::finalise(CompilerState const& _cs) +{ + if (_cs.usedAlloc && _cs.vars.size() && !m_finalised) + { + m_finalised = true; + m_asm.injectStart(Instruction::MSTORE8); + m_asm.injectStart((u256)((_cs.vars.size() + 2) * 32) - 1); + m_asm.injectStart((u256)1); + } +} + +bytes CodeFragment::code(CompilerState const& _cs) +{ + finalise(_cs); + return m_asm.assemble(); +} + CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) { /* cdebug << "CodeFragment. Locals:"; @@ -317,6 +334,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) vector code; CompilerState ns = _s; ns.vars.clear(); + ns.usedAlloc = false; int c = _t.tag() ? 1 : 0; for (auto const& i: _t) if (c++) @@ -456,13 +474,30 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.appendJump(begin); m_asm << end.tag(); } + else if (us == "ALLOC") + { + requireSize(1); + requireDeposit(0, 1); + + m_asm.append(Instruction::MEMSIZE); + m_asm.append(u256(0)); + m_asm.append(u256(1)); + m_asm.append(code[0].m_asm, 1); + m_asm.append(Instruction::MEMSIZE); + m_asm.append(Instruction::ADD); + m_asm.append(Instruction::SUB); + m_asm.append(Instruction::MSTORE8); + + _s.usedAlloc = true; + } else if (us == "LLL") { requireMinSize(2); requireMaxSize(3); requireDeposit(1, 1); - bytes const& subcode = code[0].code(); + code[0].optimise(); + bytes subcode = code[0].code(ns); m_asm.append((u256)subcode.size()); m_asm.append(Instruction::DUP); diff --git a/CodeFragment.h b/CodeFragment.h index b9d44c030..58e409125 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -43,18 +43,21 @@ public: static CodeFragment compile(std::string const& _src, CompilerState& _s); /// Consolidates data and compiles code. - bytes code() const { return m_asm.assemble(); } + bytes code(CompilerState const& _cs); /// Consolidates data and compiles code. - std::string assembly() const { return m_asm.out(); } + std::string assembly(CompilerState const& _cs) { finalise(_cs); return m_asm.out(); } /// Optimise the code. Best do this just before calling code() or assembly(). void optimise() { m_asm.optimise(); } private: + void finalise(CompilerState const& _cs); + template void error() const { throw T(); } void constructOperation(sp::utree const& _t, CompilerState& _s); + bool m_finalised = false; Assembly m_asm; }; diff --git a/Compiler.cpp b/Compiler.cpp index 8400ad955..0faf478d6 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -36,7 +36,7 @@ bytes eth::compileLLL(string const& _src, bool _opt, vector* _errors) auto f = CodeFragment::compile(_src, cs); if (_opt) f.optimise(); - bytes ret = f.code(); + bytes ret = f.code(cs); for (auto i: cs.treesToKill) killBigints(i); return ret; @@ -63,7 +63,7 @@ std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector auto f = CodeFragment::compile(_src, cs); if (_opt) f.optimise(); - string ret = f.assembly(); + string ret = f.assembly(cs); for (auto i: cs.treesToKill) killBigints(i); return ret; diff --git a/CompilerState.cpp b/CompilerState.cpp index 7e990413f..7a6681909 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -52,8 +52,7 @@ void CompilerState::populateStandard() "(def 'regname (name) { [0]:name (call (- (gas) 21) namereg 0 0 32 0 0) })" "(def 'send (to value) (call (- (gas) 21) to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" - "(def 'alloc (len) (asm msize 0 1 len msize add sub mstore8))" - "(def 'msg (gaslimit to value data datasize outsize) { [32]:outsize [0]:(alloc @32) (call gaslimit to value data datasize @0 @32) @0 })" + "(def 'msg (gaslimit to value data datasize outsize) { (set x outsize) (set y (alloc @32)) (call gaslimit to value data datasize @0 @32) @0 })" "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" "(def 'msg (to value data) { [0]:data (msg 0 to value 0 32) })" diff --git a/CompilerState.h b/CompilerState.h index f8f7ce815..5dcde6147 100644 --- a/CompilerState.h +++ b/CompilerState.h @@ -48,6 +48,7 @@ struct CompilerState std::map outers; std::map, Macro> macros; std::vector treesToKill; + bool usedAlloc = false; }; } From a8133b6f489cd7357e64c918d096d1180962670e Mon Sep 17 00:00:00 2001 From: Vitalik Buterin Date: Tue, 1 Jul 2014 13:29:58 -0400 Subject: [PATCH 33/92] Removed libethcore dependencies --- Assembly.h | 1 - Exceptions.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/Assembly.h b/Assembly.h index 9cd10a820..4a6d02ce0 100644 --- a/Assembly.h +++ b/Assembly.h @@ -25,7 +25,6 @@ #include #include #include -#include #include "Exceptions.h" namespace eth diff --git a/Exceptions.h b/Exceptions.h index 79b7cd520..a1aee1738 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -21,8 +21,6 @@ #pragma once -#include - namespace eth { From 17010d445c28d5d67ebb124563f3b9f6991f034f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Jul 2014 10:19:04 +0200 Subject: [PATCH 34/92] Remove unneeded dependencies. --- Assembly.cpp | 1 - Assembly.h | 1 - Parser.cpp | 5 ++++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 7016b2863..f4d700f92 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -22,7 +22,6 @@ #include "Assembly.h" #include -#include using namespace std; using namespace eth; diff --git a/Assembly.h b/Assembly.h index 9cd10a820..4a6d02ce0 100644 --- a/Assembly.h +++ b/Assembly.h @@ -25,7 +25,6 @@ #include #include #include -#include #include "Exceptions.h" namespace eth diff --git a/Parser.cpp b/Parser.cpp index 0ae3c6fee..d7658f672 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -24,7 +24,6 @@ #include #include #include -#include using namespace std; using namespace eth; @@ -73,6 +72,10 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) typedef sp::basic_string symbol_type; typedef string::const_iterator it; + static const u256 ether = u256(1000000000) * 1000000000; + static const u256 finney = u256(1000000000) * 1000000; + static const u256 szabo = u256(1000000000) * 1000; + qi::rule element; qi::rule str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"'; qi::rule strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;@()[]{}:") + '\0'))]; From 67315763116cf78b8c2047ce8bd2808576d8c066 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Jul 2014 14:39:21 +0200 Subject: [PATCH 35/92] Fix some macros. --- CompilerState.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CompilerState.cpp b/CompilerState.cpp index 7a6681909..e1d710110 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -55,8 +55,8 @@ void CompilerState::populateStandard() "(def 'msg (gaslimit to value data datasize outsize) { (set x outsize) (set y (alloc @32)) (call gaslimit to value data datasize @0 @32) @0 })" "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" - "(def 'msg (to value data) { [0]:data (msg 0 to value 0 32) })" - "(def 'msg (to data) { [0]:data (msg 0 to 0 0 32) })" + "(def 'msg (to value data) { [0]:data (msg (- gas 21) to value 0 32) })" + "(def 'msg (to data) { [0]:data (msg (- gas 21) to 0 0 32) })" "(def 'create (value code) { [0]:(msize) (create value @0 (lll code @0)) })" "(def 'create (code) { [0]:(msize) (create 0 @0 (lll code @0)) })" "(def 'sha3 (val) { [0]:val (sha3 0 32) })" From f4c99cdbb9f6123b33e29cb810c8781b5a2ba125 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 3 Jul 2014 15:00:22 +0200 Subject: [PATCH 36/92] Windows build coersions. --- CMakeLists.txt | 7 +++++-- Compiler.cpp | 6 +++++- Parser.cpp | 13 ++++++++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2356b7d9d..99d6d980f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,11 @@ aux_source_directory(. SRC_LIST) set(EXECUTABLE lll) # set(CMAKE_INSTALL_PREFIX ../lib) -add_library(${EXECUTABLE} SHARED ${SRC_LIST}) +if(ETH_STATIC) + add_library(${EXECUTABLE} STATIC ${SRC_LIST}) +else() + add_library(${EXECUTABLE} SHARED ${SRC_LIST}) +endif() file(GLOB HEADERS "*.h") @@ -15,7 +19,6 @@ include_directories(..) target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} ethential) -target_link_libraries(${EXECUTABLE} gmp) if(${TARGET_PLATFORM} STREQUAL "w64") diff --git a/Compiler.cpp b/Compiler.cpp index 0faf478d6..1621acf90 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -84,7 +84,11 @@ std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector string eth::parseLLL(string const& _src) { sp::utree o; - parseTreeLLL(_src, o); + try + { + parseTreeLLL(_src, o); + } + catch (...) {} ostringstream ret; debugOutAST(ret, o); killBigints(o); diff --git a/Parser.cpp b/Parser.cpp index d7658f672..4adcdd0eb 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -21,6 +21,8 @@ #include "Parser.h" +#define BOOST_RESULT_OF_USE_DECLTYPE +#define BOOST_SPIRIT_USE_PHOENIX_V3 #include #include #include @@ -93,12 +95,13 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) qi::rule list = '(' > *element > ')'; // todo: fix compound compile errors in this line for Visual Studio 2013 -#ifndef _MSC_VER - qi::rule extra = sload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 2)] | mload[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 1)] | sstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 4)] | mstore[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 3)] | seq[qi::_val = qi::_1, bind(&sp::utree::tag, qi::_val, 5)]; +//#ifndef _MSC_VER + auto x = [](int a) { return [=](sp::utree& n, typename qi::rule::context_type& c) { (boost::fusion::at_c<0>(c.attributes) = n).tag(a); }; }; + qi::rule extra = mload[x(1)] | sload[x(2)] | mstore[x(3)] | sstore[x(4)] | seq[x(5)]; element = atom | list | extra; -#else - element = atom | list/* | extra*/; -#endif +/*#else + element = atom | list; +#endif*/ string s; From a7f469020033b8879a99e6c9dc7cc68deed14c9f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 4 Jul 2014 03:45:21 +0200 Subject: [PATCH 37/92] Latest API updates. --- Parser.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Parser.cpp b/Parser.cpp index 4adcdd0eb..53580898c 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -94,15 +94,9 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) qi::rule sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element; qi::rule list = '(' > *element > ')'; - // todo: fix compound compile errors in this line for Visual Studio 2013 -//#ifndef _MSC_VER auto x = [](int a) { return [=](sp::utree& n, typename qi::rule::context_type& c) { (boost::fusion::at_c<0>(c.attributes) = n).tag(a); }; }; - qi::rule extra = mload[x(1)] | sload[x(2)] | mstore[x(3)] | sstore[x(4)] | seq[x(5)]; + qi::rule extra = sload[x(2)] | mload[x(1)] | sstore[x(4)] | mstore[x(3)] | seq[x(5)]; element = atom | list | extra; -/*#else - element = atom | list; -#endif*/ - string s; s.reserve(_s.size()); From b5cc0ae6cdf0bef2a92845fc6f5b74ce47d6428c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 6 Jul 2014 04:23:13 +0200 Subject: [PATCH 38/92] Compiler fixes. Updates for coins. --- Assembly.cpp | 2 ++ CodeFragment.cpp | 3 +++ CompilerState.cpp | 16 +++++++++------- CompilerState.h | 2 +- Parser.cpp | 13 ++++++++----- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index f4d700f92..6f5678539 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -74,12 +74,14 @@ unsigned Assembly::bytesRequired() const void Assembly::append(Assembly const& _a) { + auto newDeposit = m_deposit + _a.deposit(); for (AssemblyItem i: _a.m_items) { if (i.type() == Tag || i.type() == PushTag) i.m_data += m_usedTags; append(i); } + m_deposit = newDeposit; m_usedTags += _a.m_usedTags; for (auto const& i: _a.m_data) m_data.insert(i); diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 70973aab4..47c83e635 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -151,6 +151,9 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) case 5: us = "SEQ"; break; + case 6: + us = "CALLDATALOAD"; + break; default:; } diff --git a/CompilerState.cpp b/CompilerState.cpp index e1d710110..380d5a66f 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -45,18 +45,20 @@ void CompilerState::populateStandard() { static const string s = "{" "(def 'gav 0x51ba59315b3a95761d0863b05ccc7a7f54703d99)" - "(def 'namereg 0x2d0aceee7e5ab874e22ccf8d1a649f59106d74e8)" - "(def 'config 0xccdeac59d35627b7de09332e819d5159e7bb7250)" + "(def 'config 0x661005d2720d855f1d9976f88bb10c1a3398c77f)" + "(def 'namereg 0x50441127ea5b9dfd835a9aba4e1dc9c1257b58ca)" "(def 'gavcoin 0x5620133321fcac7f15a5c570016f6cb6dc263f9d)" - "(def 'sendgavcoin (to value) { [0]:to [32]:value (call (- (gas) 21) gavcoin 0 0 64 0 0) })" - "(def 'regname (name) { [0]:name (call (- (gas) 21) namereg 0 0 32 0 0) })" - "(def 'send (to value) (call (- (gas) 21) to value 0 0 0 0))" + "(def 'allgas (- (gas) 21))" + "(def 'sendgavcoin (to value) { [0]'send [32]:to [64]:value (call allgas gavcoin 0 0 96 0 0) })" + "(def 'regname (name) { [0]'register [32]name (call allgas namereg 0 0 64 0 0) })" + "(def 'regcoins (name) { [0]'register [32]name (call allgas namereg 0 0 64 0 0) })" + "(def 'send (to value) (call allgas to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" "(def 'msg (gaslimit to value data datasize outsize) { (set x outsize) (set y (alloc @32)) (call gaslimit to value data datasize @0 @32) @0 })" "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" - "(def 'msg (to value data) { [0]:data (msg (- gas 21) to value 0 32) })" - "(def 'msg (to data) { [0]:data (msg (- gas 21) to 0 0 32) })" + "(def 'msg (to value data) { [0]:data (msg allgas to value 0 32) })" + "(def 'msg (to data) { [0]:data (msg allgas to 0 0 32) })" "(def 'create (value code) { [0]:(msize) (create value @0 (lll code @0)) })" "(def 'create (code) { [0]:(msize) (create 0 @0 (lll code @0)) })" "(def 'sha3 (val) { [0]:val (sha3 0 32) })" diff --git a/CompilerState.h b/CompilerState.h index 5dcde6147..a0b3bf46e 100644 --- a/CompilerState.h +++ b/CompilerState.h @@ -41,7 +41,7 @@ struct CompilerState CodeFragment const& getDef(std::string const& _s); void populateStandard(); - unsigned stackSize = 64; + unsigned stackSize = 128; std::map> vars; ///< maps name to stack offset & size. std::map defs; std::map args; diff --git a/Parser.cpp b/Parser.cpp index 53580898c..314e6cf78 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -56,6 +56,7 @@ void eth::debugOutAST(ostream& _out, sp::utree const& _this) case 3: _out << "[ "; debugOutAST(_out, _this.front()); _out << " ] "; debugOutAST(_out, _this.back()); break; case 4: _out << "[[ "; debugOutAST(_out, _this.front()); _out << " ]] "; debugOutAST(_out, _this.back()); break; case 5: _out << "{ "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << "}"; break; + case 6: _out << "$ "; debugOutAST(_out, _this.front()); break; default:; } @@ -80,8 +81,8 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) qi::rule element; qi::rule str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"'; - qi::rule strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;@()[]{}:") + '\0'))]; - qi::rule symbol = qi::lexeme[+(~qi::char_(std::string(" @[]{}:();\"\x01-\x1f\x7f") + '\0'))]; + qi::rule strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))]; + qi::rule symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))]; qi::rule intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]]; qi::rule integer = intstr; qi::rule multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether]; @@ -92,10 +93,11 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) qi::rule sload = qi::lit("@@") > element; qi::rule mstore = '[' > element > ']' > -qi::lit(":") > element; qi::rule sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element; + qi::rule calldataload = qi::lit("$") > element; qi::rule list = '(' > *element > ')'; auto x = [](int a) { return [=](sp::utree& n, typename qi::rule::context_type& c) { (boost::fusion::at_c<0>(c.attributes) = n).tag(a); }; }; - qi::rule extra = sload[x(2)] | mload[x(1)] | sstore[x(4)] | mstore[x(3)] | seq[x(5)]; + qi::rule extra = sload[x(2)] | mload[x(1)] | sstore[x(4)] | mstore[x(3)] | seq[x(5)] | calldataload[x(6)]; element = atom | list | extra; string s; @@ -120,7 +122,8 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) } auto ret = s.cbegin(); qi::phrase_parse(ret, s.cend(), element, space, qi::skip_flag::dont_postskip, o_out); - if (ret != s.cend()) - throw std::exception(); + for (auto i = ret; i != s.cend(); ++i) + if (!isspace(*i)) + throw std::exception(); } From 352e75179999d6de562b810ccffd874c0fb4bc66 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 6 Jul 2014 13:13:37 +0200 Subject: [PATCH 39/92] Build fixes. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 99d6d980f..b220d8e91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} ethential) -if(${TARGET_PLATFORM} STREQUAL "w64") +if("${TARGET_PLATFORM}" STREQUAL "w64") target_link_libraries(${EXECUTABLE} boost_system-mt-s) target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) target_link_libraries(${EXECUTABLE} iphlpapi) From e128f34b6ba7b3dd2337fde54a2cf1e16489de1e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 9 Jul 2014 16:05:07 +0100 Subject: [PATCH 40/92] MEMSIZE -> MSIZE --- CodeFragment.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 47c83e635..d19d75090 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -482,11 +482,11 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireSize(1); requireDeposit(0, 1); - m_asm.append(Instruction::MEMSIZE); + m_asm.append(Instruction::MSIZE); m_asm.append(u256(0)); m_asm.append(u256(1)); m_asm.append(code[0].m_asm, 1); - m_asm.append(Instruction::MEMSIZE); + m_asm.append(Instruction::MSIZE); m_asm.append(Instruction::ADD); m_asm.append(Instruction::SUB); m_asm.append(Instruction::MSTORE8); From f9612d61be27af23446fe1fb0cae9e2743c1e58d Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Wed, 9 Jul 2014 19:43:39 +0100 Subject: [PATCH 41/92] Fixed MSVC build errors and updated projects. --- Parser.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Parser.cpp b/Parser.cpp index 314e6cf78..1907fd17c 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -69,9 +69,24 @@ void eth::debugOutAST(ostream& _out, sp::utree const& _this) } } +namespace eth { +namespace parseTreeLLL_ { + +template +struct tagNode +{ + void operator()(sp::utree& n, qi::rule::context_type& c) const + { + (boost::fusion::at_c<0>(c.attributes) = n).tag(N); + } +}; + +}} + void eth::parseTreeLLL(string const& _s, sp::utree& o_out) { using qi::ascii::space; + using eth::parseTreeLLL_::tagNode; typedef sp::basic_string symbol_type; typedef string::const_iterator it; @@ -96,8 +111,7 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) qi::rule calldataload = qi::lit("$") > element; qi::rule list = '(' > *element > ')'; - auto x = [](int a) { return [=](sp::utree& n, typename qi::rule::context_type& c) { (boost::fusion::at_c<0>(c.attributes) = n).tag(a); }; }; - qi::rule extra = sload[x(2)] | mload[x(1)] | sstore[x(4)] | mstore[x(3)] | seq[x(5)] | calldataload[x(6)]; + qi::rule extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | seq[tagNode<5>()] | calldataload[tagNode<6>()]; element = atom | list | extra; string s; From 8dfad3e7c0ef1f0dd7527e0ed52663b52fc1e870 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 21 Jul 2014 15:14:44 +0200 Subject: [PATCH 42/92] Move JS setup code up into lib macro. Remove a few redundant messages from build. --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b220d8e91..98bebdfed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,8 +45,6 @@ else () target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) endif () -message("Installation path: ${CMAKE_INSTALL_PREFIX}") - install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) From b56713375074a1db82ad44726f43dcfc12f37141 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 23 Jul 2014 22:51:14 +0200 Subject: [PATCH 43/92] Minor updates. --- Assembly.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 6f5678539..3abdf66f7 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -116,7 +116,7 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) _out << " PUSH" << i.data(); break; case PushString: - _out << " PUSH'[" << h256(i.data()).abridged() << "]"; + _out << " PUSH'[" << hex << (unsigned)i.data() << "]"; break; case PushTag: _out << " PUSH[tag" << i.data() << "]"; @@ -125,7 +125,7 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) _out << " tag" << i.data() << ":"; break; case PushData: - _out << " PUSH*[" << h256(i.data()).abridged() << "]"; + _out << " PUSH*[" << hex << (unsigned)i.data() << "]"; break; case UndefinedItem: _out << " ???"; @@ -156,7 +156,7 @@ ostream& Assembly::streamOut(ostream& _out) const _out << "tag" << i.m_data << ": " << endl; break; case PushData: - _out << " PUSH [" << h256(i.m_data).abridged() << "]" << endl; + _out << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; break; default:; } @@ -165,7 +165,7 @@ ostream& Assembly::streamOut(ostream& _out) const { _out << ".data:" << endl; for (auto const& i: m_data) - _out << " " << i.first.abridged() << ": " << toHex(i.second) << endl; + _out << " " << hex << (unsigned)(u256)i.first << ": " << toHex(i.second) << endl; } return _out; } From 510abc0997c248a1a767ceade6749f426ae3a968 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 27 Jul 2014 11:20:43 +0200 Subject: [PATCH 44/92] Fixes and whatnot. --- CompilerState.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CompilerState.cpp b/CompilerState.cpp index 380d5a66f..01995674f 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -62,6 +62,8 @@ void CompilerState::populateStandard() "(def 'create (value code) { [0]:(msize) (create value @0 (lll code @0)) })" "(def 'create (code) { [0]:(msize) (create 0 @0 (lll code @0)) })" "(def 'sha3 (val) { [0]:val (sha3 0 32) })" + "(def 'sha3pair (a b) { [0]:a [32]:b (sha3 0 64) })" + "(def 'sha3trip (a b c) { [0]:a [32]:b [64]:c (sha3 0 96) })" "(def 'return (val) { [0]:val (return 0 32) })" "(def 'returnlll (code) (return 0 (lll code 0)) )" "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" From ed0209fefc50ab59b43b7f781410699c49445aab Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 27 Jul 2014 13:09:36 +0200 Subject: [PATCH 45/92] Updates to assembler - see the sub-codes. --- Assembly.cpp | 74 +++++++++++++++++++++++++++++++++++++++--------- Assembly.h | 12 +++++--- CodeFragment.cpp | 13 ++------- CodeFragment.h | 8 +----- Compiler.cpp | 9 ++---- 5 files changed, 73 insertions(+), 43 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 3abdf66f7..78552f3c5 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -32,7 +32,7 @@ int AssemblyItem::deposit() const { case Operation: return c_instructionInfo.at((Instruction)(byte)m_data).ret - c_instructionInfo.at((Instruction)(byte)m_data).args; - case Push: case PushString: case PushTag: case PushData: + case Push: case PushString: case PushTag: case PushData: case PushSub: case PushSubSize: return 1; case Tag: return 0; @@ -61,8 +61,12 @@ unsigned Assembly::bytesRequired() const case Push: ret += 1 + max(1, eth::bytesRequired(i.m_data)); break; + case PushSubSize: + ret += 4; // worst case: a 16MB program + break; case PushTag: case PushData: + case PushSub: ret += 1 + br; case Tag:; default:; @@ -87,6 +91,8 @@ void Assembly::append(Assembly const& _a) m_data.insert(i); for (auto const& i: _a.m_strings) m_strings.insert(i); + for (auto const& i: _a.m_subs) + m_subs.insert(i); assert(!_a.m_baseDeposit); assert(!_a.m_totalDeposit); @@ -127,6 +133,12 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) case PushData: _out << " PUSH*[" << hex << (unsigned)i.data() << "]"; break; + case PushSub: + _out << " PUSHs[" << hex << h256(i.data()).abridged() << "]"; + break; + case PushSubSize: + _out << " PUSHss[" << hex << h256(i.data()).abridged() << "]"; + break; case UndefinedItem: _out << " ???"; default:; @@ -134,38 +146,50 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) return _out; } -ostream& Assembly::streamOut(ostream& _out) const +ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const { - _out << ".code:" << endl; + _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) switch (i.m_type) { case Operation: - _out << " " << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; + _out << _prefix << " " << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; break; case Push: - _out << " PUSH " << i.m_data << endl; + _out << _prefix << " PUSH " << i.m_data << endl; break; case PushString: - _out << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; + _out << _prefix << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; break; case PushTag: - _out << " PUSH [tag" << i.m_data << "]" << endl; + _out << _prefix << " PUSH [tag" << i.m_data << "]" << endl; + break; + case PushSub: + _out << _prefix << " PUSH [$" << h256(i.m_data).abridged() << "]" << endl; + break; + case PushSubSize: + _out << _prefix << " PUSH #[$" << h256(i.m_data).abridged() << "]" << endl; break; case Tag: - _out << "tag" << i.m_data << ": " << endl; + _out << _prefix << "tag" << i.m_data << ": " << endl; break; case PushData: - _out << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; + _out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; break; default:; } - if (m_data.size()) + if (m_data.size() || m_subs.size()) { - _out << ".data:" << endl; + _out << _prefix << ".data:" << endl; for (auto const& i: m_data) - _out << " " << hex << (unsigned)(u256)i.first << ": " << toHex(i.second) << endl; + if (!m_subs.count(i.first)) + _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << toHex(i.second) << endl; + for (auto const& i: m_subs) + { + _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << endl; + i.second.streamOut(_out, _prefix + " "); + } } return _out; } @@ -195,8 +219,10 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; #define copt eth::LogOutputStream() -void Assembly::optimise() +Assembly& Assembly::optimise(bool _enable) { + if (!_enable) + return *this; map> c_simple = { { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, @@ -221,6 +247,8 @@ void Assembly::optimise() { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushTag, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushString, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { 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 {}; } }, }; @@ -309,6 +337,11 @@ void Assembly::optimise() } copt << total << " optimisations done."; + + for (auto& i: m_subs) + i.second.optimise(true); + + return *this; } bytes Assembly::assemble() const @@ -323,6 +356,9 @@ bytes Assembly::assemble() const unsigned bytesPerTag = eth::bytesRequired(totalBytes); byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; + for (auto const& i: m_subs) + m_data[i.first] = i.second.assemble(); + for (AssemblyItem const& i: m_items) switch (i.m_type) { @@ -358,13 +394,23 @@ bytes Assembly::assemble() const ret.resize(ret.size() + bytesPerTag); break; } - case PushData: + case PushData: case PushSub: { ret.push_back(tagPush); dataRef.insert(make_pair((h256)i.m_data, ret.size())); ret.resize(ret.size() + bytesPerTag); break; } + case PushSubSize: + { + auto s = m_data[i.m_data].size(); + byte b = max(1, eth::bytesRequired(s)); + ret.push_back((byte)Instruction::PUSH1 - 1 + b); + ret.resize(ret.size() + b); + bytesRef byr(&ret.back() + 1 - b, b); + toBigEndian(s, byr); + break; + } case Tag: tagPos[(unsigned)i.m_data] = ret.size(); break; diff --git a/Assembly.h b/Assembly.h index 4a6d02ce0..581e16433 100644 --- a/Assembly.h +++ b/Assembly.h @@ -30,7 +30,7 @@ namespace eth { -enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, Tag, PushData }; +enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, Tag, PushData }; class Assembly; @@ -70,7 +70,9 @@ public: AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { h256 h = (u256)std::hash()(asString(_data)); m_data[h] = _data; return AssemblyItem(PushData, h); } + AssemblyItem newSub(Assembly const& _sub) { h256 h = h256::random(s_fixedHashEngine); m_subs[h] = _sub; return AssemblyItem(PushSub, h); } AssemblyItem newPushString(std::string const& _data) { h256 h = (u256)std::hash()(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } + AssemblyItem newPushSubSize(h256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem append() { return append(newTag()); } void append(Assembly const& _a); @@ -78,6 +80,7 @@ public: AssemblyItem const& append(AssemblyItem const& _i); AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } + AssemblyItem appendSubSize(Assembly const& _asm) { auto ret = newSub(_asm); append(newPushSubSize(ret.data())); return ret; } AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } @@ -102,8 +105,8 @@ public: std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } int deposit() const { return m_deposit; } bytes assemble() const; - void optimise(); - std::ostream& streamOut(std::ostream& _out) const; + Assembly& optimise(bool _enable); + std::ostream& streamOut(std::ostream& _out, std::string const& _prefix = "") const; private: void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) throw InvalidDeposit(); } @@ -111,7 +114,8 @@ private: unsigned m_usedTags = 0; AssemblyItems m_items; - std::map m_data; + mutable std::map m_data; + std::map m_subs; std::map m_strings; int m_deposit = 0; diff --git a/CodeFragment.cpp b/CodeFragment.cpp index d19d75090..bc7fa6153 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -44,12 +44,6 @@ void CodeFragment::finalise(CompilerState const& _cs) } } -bytes CodeFragment::code(CompilerState const& _cs) -{ - finalise(_cs); - return m_asm.assemble(); -} - CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) { /* cdebug << "CodeFragment. Locals:"; @@ -499,10 +493,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireMaxSize(3); requireDeposit(1, 1); - code[0].optimise(); - bytes subcode = code[0].code(ns); - - m_asm.append((u256)subcode.size()); + auto subPush = m_asm.appendSubSize(code[0].assembly(ns)); m_asm.append(Instruction::DUP); if (code.size() == 3) { @@ -513,7 +504,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.append(Instruction::MUL); m_asm.append(Instruction::DUP); } - m_asm.append(subcode); + m_asm.append(subPush); m_asm.append(code[1].m_asm, 1); m_asm.append(Instruction::CODECOPY); } diff --git a/CodeFragment.h b/CodeFragment.h index 58e409125..98a6f15c7 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -43,13 +43,7 @@ public: static CodeFragment compile(std::string const& _src, CompilerState& _s); /// Consolidates data and compiles code. - bytes code(CompilerState const& _cs); - - /// Consolidates data and compiles code. - std::string assembly(CompilerState const& _cs) { finalise(_cs); return m_asm.out(); } - - /// Optimise the code. Best do this just before calling code() or assembly(). - void optimise() { m_asm.optimise(); } + Assembly& assembly(CompilerState const& _cs) { finalise(_cs); return m_asm; } private: void finalise(CompilerState const& _cs); diff --git a/Compiler.cpp b/Compiler.cpp index 1621acf90..ebe2638be 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -34,9 +34,7 @@ bytes eth::compileLLL(string const& _src, bool _opt, vector* _errors) CompilerState cs; cs.populateStandard(); auto f = CodeFragment::compile(_src, cs); - if (_opt) - f.optimise(); - bytes ret = f.code(cs); + bytes ret = f.assembly(cs).optimise(_opt).assemble(); for (auto i: cs.treesToKill) killBigints(i); return ret; @@ -60,10 +58,7 @@ std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector { CompilerState cs; cs.populateStandard(); - auto f = CodeFragment::compile(_src, cs); - if (_opt) - f.optimise(); - string ret = f.assembly(cs); + string ret = CodeFragment::compile(_src, cs).assembly(cs).optimise(_opt).out(); for (auto i: cs.treesToKill) killBigints(i); return ret; From 6f68842208e1025d3769cdea4829407e65b07744 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 27 Jul 2014 14:06:38 +0200 Subject: [PATCH 46/92] Avoid _asm from MSVC. --- Assembly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assembly.h b/Assembly.h index 581e16433..888b373c5 100644 --- a/Assembly.h +++ b/Assembly.h @@ -80,7 +80,7 @@ public: AssemblyItem const& append(AssemblyItem const& _i); AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } - AssemblyItem appendSubSize(Assembly const& _asm) { auto ret = newSub(_asm); append(newPushSubSize(ret.data())); return ret; } + AssemblyItem appendSubSize(Assembly const& _asmbly) { auto ret = newSub(_asmbly); append(newPushSubSize(ret.data())); return ret; } AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } From 621fbc00f47d962562fb647f4c64de5ddd55af9a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 28 Jul 2014 01:58:34 +0200 Subject: [PATCH 47/92] Rename assembly again. --- Assembly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assembly.h b/Assembly.h index 888b373c5..f0f93297f 100644 --- a/Assembly.h +++ b/Assembly.h @@ -80,7 +80,7 @@ public: AssemblyItem const& append(AssemblyItem const& _i); AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } - AssemblyItem appendSubSize(Assembly const& _asmbly) { auto ret = newSub(_asmbly); append(newPushSubSize(ret.data())); return ret; } + AssemblyItem appendSubSize(Assembly const& _a) { auto ret = newSub(_a); append(newPushSubSize(ret.data())); return ret; } AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } From b3e207090337126cd48c5c827b6e0fd5c20c6097 Mon Sep 17 00:00:00 2001 From: Giacomo Tazzari Date: Sun, 10 Aug 2014 00:42:34 +0200 Subject: [PATCH 48/92] Using boost::spirit::standard namespace instead of boost::spirit::ascii in parseTreeLLL() to prevent crashing when parsing code containing non-ascii characters --- Parser.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Parser.cpp b/Parser.cpp index 1907fd17c..edcd38f32 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -85,7 +85,8 @@ struct tagNode void eth::parseTreeLLL(string const& _s, sp::utree& o_out) { - using qi::ascii::space; + using qi::standard::space; + using qi::standard::space_type; using eth::parseTreeLLL_::tagNode; typedef sp::basic_string symbol_type; typedef string::const_iterator it; @@ -94,24 +95,24 @@ void eth::parseTreeLLL(string const& _s, sp::utree& o_out) static const u256 finney = u256(1000000000) * 1000000; static const u256 szabo = u256(1000000000) * 1000; - qi::rule element; + qi::rule element; qi::rule str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"'; qi::rule strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))]; qi::rule symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))]; qi::rule intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]]; qi::rule integer = intstr; qi::rule multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether]; - qi::rule quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1]; - qi::rule atom = quantity[qi::_val = px::construct(px::new_(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1]; - qi::rule seq = '{' > *element > '}'; - qi::rule mload = '@' > element; - qi::rule sload = qi::lit("@@") > element; - qi::rule mstore = '[' > element > ']' > -qi::lit(":") > element; - qi::rule sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element; - qi::rule calldataload = qi::lit("$") > element; - qi::rule list = '(' > *element > ')'; + qi::rule quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1]; + qi::rule atom = quantity[qi::_val = px::construct(px::new_(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1]; + qi::rule seq = '{' > *element > '}'; + qi::rule mload = '@' > element; + qi::rule sload = qi::lit("@@") > element; + qi::rule mstore = '[' > element > ']' > -qi::lit(":") > element; + qi::rule sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element; + qi::rule calldataload = qi::lit("$") > element; + qi::rule list = '(' > *element > ')'; - qi::rule extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | seq[tagNode<5>()] | calldataload[tagNode<6>()]; + qi::rule extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | seq[tagNode<5>()] | calldataload[tagNode<6>()]; element = atom | list | extra; string s; From 17cb91aa35e3048723ac449b48d26038e6956de7 Mon Sep 17 00:00:00 2001 From: Giacomo Tazzari Date: Mon, 11 Aug 2014 11:06:32 +0200 Subject: [PATCH 49/92] Fixed implementation of EXP opcode (wrong results when exponent >= 2^32) --- Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assembly.cpp b/Assembly.cpp index 78552f3c5..550f5c89e 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -230,7 +230,7 @@ Assembly& Assembly::optimise(bool _enable) { Instruction::SDIV, [](u256 a, u256 b)->u256{return s2u(u2s(a) / u2s(b));} }, { Instruction::MOD, [](u256 a, u256 b)->u256{return a % b;} }, { Instruction::SMOD, [](u256 a, u256 b)->u256{return s2u(u2s(a) % u2s(b));} }, - { Instruction::EXP, [](u256 a, u256 b)->u256{return boost::multiprecision::pow(a, (unsigned)b);} }, + { Instruction::EXP, [](u256 a, u256 b)->u256{return (u256)boost::multiprecision::powm((bigint)a, (bigint)b, bigint(2) << 256);} }, { Instruction::LT, [](u256 a, u256 b)->u256{return a < b ? 1 : 0;} }, { Instruction::GT, [](u256 a, u256 b)->u256{return a > b ? 1 : 0;} }, { Instruction::SLT, [](u256 a, u256 b)->u256{return u2s(a) < u2s(b) ? 1 : 0;} }, From 905df780a32370725ea5e28f97724a496d816d0a Mon Sep 17 00:00:00 2001 From: Giacomo Tazzari Date: Mon, 11 Aug 2014 11:20:11 +0200 Subject: [PATCH 50/92] Code indentation fix --- Assembly.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 550f5c89e..491d3812e 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -227,14 +227,14 @@ Assembly& Assembly::optimise(bool _enable) { { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, { Instruction::DIV, [](u256 a, u256 b)->u256{return a / b;} }, - { Instruction::SDIV, [](u256 a, u256 b)->u256{return s2u(u2s(a) / u2s(b));} }, + { Instruction::SDIV, [](u256 a, u256 b)->u256{return s2u(u2s(a) / u2s(b));} }, { Instruction::MOD, [](u256 a, u256 b)->u256{return a % b;} }, - { Instruction::SMOD, [](u256 a, u256 b)->u256{return s2u(u2s(a) % u2s(b));} }, + { Instruction::SMOD, [](u256 a, u256 b)->u256{return s2u(u2s(a) % u2s(b));} }, { Instruction::EXP, [](u256 a, u256 b)->u256{return (u256)boost::multiprecision::powm((bigint)a, (bigint)b, bigint(2) << 256);} }, { Instruction::LT, [](u256 a, u256 b)->u256{return a < b ? 1 : 0;} }, { Instruction::GT, [](u256 a, u256 b)->u256{return a > b ? 1 : 0;} }, - { Instruction::SLT, [](u256 a, u256 b)->u256{return u2s(a) < u2s(b) ? 1 : 0;} }, - { Instruction::SGT, [](u256 a, u256 b)->u256{return u2s(a) > u2s(b) ? 1 : 0;} }, + { Instruction::SLT, [](u256 a, u256 b)->u256{return u2s(a) < u2s(b) ? 1 : 0;} }, + { Instruction::SGT, [](u256 a, u256 b)->u256{return u2s(a) > u2s(b) ? 1 : 0;} }, { Instruction::EQ, [](u256 a, u256 b)->u256{return a == b ? 1 : 0;} }, }; map> c_associative = From e4e46b07ebcf05bebbb3b1711b843f65268d99bc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 14 Aug 2014 13:26:28 +0200 Subject: [PATCH 51/92] Fix for padding in new SHA3. --- CompilerState.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CompilerState.cpp b/CompilerState.cpp index 01995674f..222775017 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -46,12 +46,7 @@ void CompilerState::populateStandard() static const string s = "{" "(def 'gav 0x51ba59315b3a95761d0863b05ccc7a7f54703d99)" "(def 'config 0x661005d2720d855f1d9976f88bb10c1a3398c77f)" - "(def 'namereg 0x50441127ea5b9dfd835a9aba4e1dc9c1257b58ca)" - "(def 'gavcoin 0x5620133321fcac7f15a5c570016f6cb6dc263f9d)" "(def 'allgas (- (gas) 21))" - "(def 'sendgavcoin (to value) { [0]'send [32]:to [64]:value (call allgas gavcoin 0 0 96 0 0) })" - "(def 'regname (name) { [0]'register [32]name (call allgas namereg 0 0 64 0 0) })" - "(def 'regcoins (name) { [0]'register [32]name (call allgas namereg 0 0 64 0 0) })" "(def 'send (to value) (call allgas to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" "(def 'msg (gaslimit to value data datasize outsize) { (set x outsize) (set y (alloc @32)) (call gaslimit to value data datasize @0 @32) @0 })" @@ -69,6 +64,13 @@ void CompilerState::populateStandard() "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" "(def 'permcount 0)" "(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )" + "(def 'namereg (msg config 0))" + "(def 'coinreg (msg config 1))" + "(def 'gavcoin (msg config 2))" + "(def 'sendgavcoin (to value) { [32]'send [64]:to [96]:value (call allgas gavcoin 0 32 96 0 0) })" + "(def 'regname (name) { [32]'register [64]name (call allgas namereg 0 32 64 0 0) })" + "(def 'regcoin (name) { [32]name (call allgas coinreg 0 32 32 0 0) })" + "(def 'regcoin (name denom) { [32]name [64]denom (call allgas coinreg 0 32 64 0 0) })" "}"; CodeFragment::compile(s, *this); } From 5cdacb1bc1728ef0411f6d6cdb4172bc26dc5fa7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 21 Aug 2014 15:53:59 +0200 Subject: [PATCH 52/92] Unambiguous licence. --- CodeFragment.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index bc7fa6153..09f49bc73 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -313,7 +313,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) ++ii; } m_asm.append((u256)data.size()); - m_asm.append(Instruction::DUP); + m_asm.append(Instruction::DUP1); m_asm.append(data); m_asm.append(pos.m_asm, 1); m_asm.append(Instruction::CODECOPY); @@ -494,7 +494,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireDeposit(1, 1); auto subPush = m_asm.appendSubSize(code[0].assembly(ns)); - m_asm.append(Instruction::DUP); + m_asm.append(Instruction::DUP1); if (code.size() == 3) { requireDeposit(2, 1); @@ -502,7 +502,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.append(Instruction::LT); m_asm.append(Instruction::NOT); m_asm.append(Instruction::MUL); - m_asm.append(Instruction::DUP); + m_asm.append(Instruction::DUP1); } m_asm.append(subPush); m_asm.append(code[1].m_asm, 1); From 74f198c0438a2674103c8e1ce24a0feedef278dc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 21 Aug 2014 16:14:12 +0200 Subject: [PATCH 53/92] SWAP & DUP --- CodeFragment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 09f49bc73..a9128e29c 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -77,7 +77,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS string us = boost::algorithm::to_upper_copy(s); if (_allowASM && c_instructions.count(us)) m_asm.append(c_instructions.at(us)); - if (_s.defs.count(s)) + else if (_s.defs.count(s)) m_asm.append(_s.defs.at(s).m_asm); else if (_s.args.count(s)) m_asm.append(_s.args.at(s).m_asm); From 00caaf53d28976ed276d9d2fe7a54c07ba92b002 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 26 Aug 2014 22:27:45 +0200 Subject: [PATCH 54/92] Better interface for instrInfo. --- Assembly.cpp | 6 +++--- CodeFragment.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 491d3812e..f397ec37d 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -31,7 +31,7 @@ int AssemblyItem::deposit() const switch (m_type) { case Operation: - return c_instructionInfo.at((Instruction)(byte)m_data).ret - c_instructionInfo.at((Instruction)(byte)m_data).args; + return instructionInfo((Instruction)(byte)m_data).ret - instructionInfo((Instruction)(byte)m_data).args; case Push: case PushString: case PushTag: case PushData: case PushSub: case PushSubSize: return 1; case Tag: @@ -116,7 +116,7 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) switch (i.type()) { case Operation: - _out << " " << c_instructionInfo.at((Instruction)(byte)i.data()).name; + _out << " " << instructionInfo((Instruction)(byte)i.data()).name; break; case Push: _out << " PUSH" << i.data(); @@ -153,7 +153,7 @@ ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const switch (i.m_type) { case Operation: - _out << _prefix << " " << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; + _out << _prefix << " " << instructionInfo((Instruction)(byte)i.m_data).name << endl; break; case Push: _out << _prefix << " PUSH " << i.m_data << endl; diff --git a/CodeFragment.cpp b/CodeFragment.cpp index a9128e29c..07d17fbef 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -369,7 +369,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) else if (c_instructions.count(us)) { auto it = c_instructions.find(us); - int ea = c_instructionInfo.at(it->second).args; + int ea = instructionInfo(it->second).args; if (ea >= 0) requireSize(ea); else From 6ff57fe0759d13a97346cf5590f57ad729cbbae7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 5 Sep 2014 17:09:58 +0200 Subject: [PATCH 55/92] Project-wide reorganisation of namespaces. --- Assembly.cpp | 17 +++++++++-------- Assembly.h | 3 +++ CodeFragment.cpp | 3 ++- CodeFragment.h | 3 +++ Compiler.cpp | 9 +++++---- Compiler.h | 4 +++- CompilerState.cpp | 3 ++- CompilerState.h | 3 +++ Exceptions.h | 7 ++++++- Parser.cpp | 15 ++++++++------- Parser.h | 4 +++- 11 files changed, 47 insertions(+), 24 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index f397ec37d..475eaeabf 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -24,7 +24,8 @@ #include using namespace std; -using namespace eth; +using namespace dev; +using namespace dev::eth; int AssemblyItem::deposit() const { @@ -59,7 +60,7 @@ unsigned Assembly::bytesRequired() const ret += 33; break; case Push: - ret += 1 + max(1, eth::bytesRequired(i.m_data)); + ret += 1 + max(1, dev::bytesRequired(i.m_data)); break; case PushSubSize: ret += 4; // worst case: a 16MB program @@ -71,7 +72,7 @@ unsigned Assembly::bytesRequired() const case Tag:; default:; } - if (eth::bytesRequired(ret) <= br) + if (dev::bytesRequired(ret) <= br) return ret; } } @@ -110,7 +111,7 @@ void Assembly::append(Assembly const& _a, int _deposit) } } -ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) +ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) { for (AssemblyItem const& i: _i) switch (i.type()) @@ -217,7 +218,7 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) } struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; -#define copt eth::LogOutputStream() +#define copt dev::LogOutputStream() Assembly& Assembly::optimise(bool _enable) { @@ -353,7 +354,7 @@ bytes Assembly::assemble() const vector tagPos(m_usedTags); map tagRef; multimap dataRef; - unsigned bytesPerTag = eth::bytesRequired(totalBytes); + unsigned bytesPerTag = dev::bytesRequired(totalBytes); byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; for (auto const& i: m_subs) @@ -380,7 +381,7 @@ bytes Assembly::assemble() const } case Push: { - byte b = max(1, eth::bytesRequired(i.m_data)); + byte b = max(1, dev::bytesRequired(i.m_data)); ret.push_back((byte)Instruction::PUSH1 - 1 + b); ret.resize(ret.size() + b); bytesRef byr(&ret.back() + 1 - b, b); @@ -404,7 +405,7 @@ bytes Assembly::assemble() const case PushSubSize: { auto s = m_data[i.m_data].size(); - byte b = max(1, eth::bytesRequired(s)); + byte b = max(1, dev::bytesRequired(s)); ret.push_back((byte)Instruction::PUSH1 - 1 + b); ret.resize(ret.size() + b); bytesRef byr(&ret.back() + 1 - b, b); diff --git a/Assembly.h b/Assembly.h index f0f93297f..cfeb6d1fb 100644 --- a/Assembly.h +++ b/Assembly.h @@ -27,6 +27,8 @@ #include #include "Exceptions.h" +namespace dev +{ namespace eth { @@ -130,3 +132,4 @@ inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) } } +} diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 07d17fbef..ecad3d364 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -28,7 +28,8 @@ #include "CompilerState.h" #include "Parser.h" using namespace std; -using namespace eth; +using namespace dev; +using namespace dev::eth; namespace qi = boost::spirit::qi; namespace px = boost::phoenix; namespace sp = boost::spirit; diff --git a/CodeFragment.h b/CodeFragment.h index 98a6f15c7..a81d8ea22 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -29,6 +29,8 @@ namespace boost { namespace spirit { class utree; } } namespace sp = boost::spirit; +namespace dev +{ namespace eth { @@ -58,3 +60,4 @@ private: static const CodeFragment NullCodeFragment; } +} diff --git a/Compiler.cpp b/Compiler.cpp index ebe2638be..389c10be2 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -25,9 +25,10 @@ #include "CodeFragment.h" using namespace std; -using namespace eth; +using namespace dev; +using namespace dev::eth; -bytes eth::compileLLL(string const& _src, bool _opt, vector* _errors) +bytes dev::eth::compileLLL(string const& _src, bool _opt, vector* _errors) { try { @@ -52,7 +53,7 @@ bytes eth::compileLLL(string const& _src, bool _opt, vector* _errors) return bytes(); } -std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector* _errors) +std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector* _errors) { try { @@ -76,7 +77,7 @@ std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector return string(); } -string eth::parseLLL(string const& _src) +string dev::eth::parseLLL(string const& _src) { sp::utree o; try diff --git a/Compiler.h b/Compiler.h index da84a2fea..5daec0a54 100644 --- a/Compiler.h +++ b/Compiler.h @@ -25,6 +25,8 @@ #include #include +namespace dev +{ namespace eth { @@ -33,4 +35,4 @@ std::string compileLLLToAsm(std::string const& _src, bool _opt = true, std::vect bytes compileLLL(std::string const& _src, bool _opt = true, std::vector* _errors = nullptr); } - +} diff --git a/CompilerState.cpp b/CompilerState.cpp index 222775017..c3dc2dda3 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -23,7 +23,8 @@ #include "CodeFragment.h" using namespace std; -using namespace eth; +using namespace dev; +using namespace dev::eth; CompilerState::CompilerState() { diff --git a/CompilerState.h b/CompilerState.h index a0b3bf46e..bfe56f927 100644 --- a/CompilerState.h +++ b/CompilerState.h @@ -24,6 +24,8 @@ #include #include "CodeFragment.h" +namespace dev +{ namespace eth { @@ -52,3 +54,4 @@ struct CompilerState }; } +} diff --git a/Exceptions.h b/Exceptions.h index a1aee1738..1dcbbcc66 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -21,11 +21,15 @@ #pragma once +#include + +namespace dev +{ namespace eth { /// Compile a Low-level Lisp-like Language program into EVM-code. -class CompilerException: public Exception {}; +class CompilerException: public dev::Exception {}; class InvalidOperation: public CompilerException {}; class IntegerOutOfRange: public CompilerException {}; class StringTooLong: public CompilerException {}; @@ -40,3 +44,4 @@ class BareSymbol: public CompilerException {}; class ExpectedLiteral: public CompilerException {}; } +} diff --git a/Parser.cpp b/Parser.cpp index edcd38f32..52a05174b 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -28,12 +28,13 @@ #include using namespace std; -using namespace eth; +using namespace dev; +using namespace dev::eth; namespace qi = boost::spirit::qi; namespace px = boost::phoenix; namespace sp = boost::spirit; -void eth::killBigints(sp::utree const& _this) +void dev::eth::killBigints(sp::utree const& _this) { switch (_this.which()) { @@ -43,7 +44,7 @@ void eth::killBigints(sp::utree const& _this) } } -void eth::debugOutAST(ostream& _out, sp::utree const& _this) +void dev::eth::debugOutAST(ostream& _out, sp::utree const& _this) { switch (_this.which()) { @@ -69,7 +70,7 @@ void eth::debugOutAST(ostream& _out, sp::utree const& _this) } } -namespace eth { +namespace dev { namespace eth { namespace parseTreeLLL_ { template @@ -81,13 +82,13 @@ struct tagNode } }; -}} +}}} -void eth::parseTreeLLL(string const& _s, sp::utree& o_out) +void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out) { using qi::standard::space; using qi::standard::space_type; - using eth::parseTreeLLL_::tagNode; + using dev::eth::parseTreeLLL_::tagNode; typedef sp::basic_string symbol_type; typedef string::const_iterator it; diff --git a/Parser.h b/Parser.h index 5286c3e8a..f90c6b5df 100644 --- a/Parser.h +++ b/Parser.h @@ -28,6 +28,8 @@ namespace boost { namespace spirit { class utree; } } namespace sp = boost::spirit; +namespace dev +{ namespace eth { @@ -36,4 +38,4 @@ void parseTreeLLL(std::string const& _s, sp::utree& o_out); void debugOutAST(std::ostream& _out, sp::utree const& _this); } - +} From 55d0e1c34ef3c14b2c262fe7edd4fdc2f18bcfb5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 5 Sep 2014 18:24:29 +0200 Subject: [PATCH 56/92] Split ethcore off into devcrypto ready for Whisper's crypto and repot namespace. Rename ethential to devcore. --- Assembly.cpp | 2 +- Assembly.h | 2 +- CMakeLists.txt | 2 +- CodeFragment.cpp | 2 +- CodeFragment.h | 2 +- Compiler.h | 2 +- Exceptions.h | 2 +- Parser.h | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 475eaeabf..2250a71fe 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -21,7 +21,7 @@ #include "Assembly.h" -#include +#include using namespace std; using namespace dev; diff --git a/Assembly.h b/Assembly.h index cfeb6d1fb..b8152fe02 100644 --- a/Assembly.h +++ b/Assembly.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include "Exceptions.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index 98bebdfed..7746613ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ file(GLOB HEADERS "*.h") include_directories(..) target_link_libraries(${EXECUTABLE} evmface) -target_link_libraries(${EXECUTABLE} ethential) +target_link_libraries(${EXECUTABLE} devcore) if("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/CodeFragment.cpp b/CodeFragment.cpp index ecad3d364..533d00a96 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include "CompilerState.h" #include "Parser.h" diff --git a/CodeFragment.h b/CodeFragment.h index a81d8ea22..60ab7c6de 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -21,7 +21,7 @@ #pragma once -#include +#include #include #include "Assembly.h" #include "Exceptions.h" diff --git a/Compiler.h b/Compiler.h index 5daec0a54..0fadd2785 100644 --- a/Compiler.h +++ b/Compiler.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace dev { diff --git a/Exceptions.h b/Exceptions.h index 1dcbbcc66..c45215f1a 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -21,7 +21,7 @@ #pragma once -#include +#include namespace dev { diff --git a/Parser.h b/Parser.h index f90c6b5df..b21989f06 100644 --- a/Parser.h +++ b/Parser.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace boost { namespace spirit { class utree; } } namespace sp = boost::spirit; From f61c3232449d36cc44bcff70240f5292bf8f9f16 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Thu, 2 Oct 2014 14:20:33 +0200 Subject: [PATCH 57/92] Restructured exceptions. Boost::exception is now used primarily. --- Assembly.cpp | 2 +- Assembly.h | 2 +- CodeFragment.h | 2 +- Compiler.cpp | 7 +++++-- Parser.cpp | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 2250a71fe..9b6dee947 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -102,7 +102,7 @@ void Assembly::append(Assembly const& _a) void Assembly::append(Assembly const& _a, int _deposit) { if (_deposit > _a.m_deposit) - throw InvalidDeposit(); + BOOST_THROW_EXCEPTION(InvalidDeposit()); else { append(_a); diff --git a/Assembly.h b/Assembly.h index b8152fe02..b7feaf4f4 100644 --- a/Assembly.h +++ b/Assembly.h @@ -111,7 +111,7 @@ public: std::ostream& streamOut(std::ostream& _out, std::string const& _prefix = "") const; private: - void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) throw InvalidDeposit(); } + void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } unsigned bytesRequired() const; unsigned m_usedTags = 0; diff --git a/CodeFragment.h b/CodeFragment.h index 60ab7c6de..d6ca86bbe 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -50,7 +50,7 @@ public: private: void finalise(CompilerState const& _cs); - template void error() const { throw T(); } + template void error() const { BOOST_THROW_EXCEPTION(T() ); } void constructOperation(sp::utree const& _t, CompilerState& _s); bool m_finalised = false; diff --git a/Compiler.cpp b/Compiler.cpp index 389c10be2..37fb3c340 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -43,7 +43,10 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector* _error catch (Exception const& _e) { if (_errors) - _errors->push_back(_e.description()); + { + _errors->push_back("Parse error."); + _errors->push_back(diagnostic_information(_e)); + } } catch (std::exception) { @@ -67,7 +70,7 @@ std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::v catch (Exception const& _e) { if (_errors) - _errors->push_back(_e.description()); + _errors->push_back(diagnostic_information(_e)); } catch (std::exception) { diff --git a/Parser.cpp b/Parser.cpp index 52a05174b..e94e88e19 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -140,6 +140,6 @@ void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out) qi::phrase_parse(ret, s.cend(), element, space, qi::skip_flag::dont_postskip, o_out); for (auto i = ret; i != s.cend(); ++i) if (!isspace(*i)) - throw std::exception(); + BOOST_THROW_EXCEPTION(std::exception()); } From 92d9a107d711040cc34921aa6bd5f5abcf515b8c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 7 Oct 2014 18:43:01 +0200 Subject: [PATCH 58/92] PoC-7: JUMPDEST implemented. --- Assembly.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Assembly.cpp b/Assembly.cpp index 9b6dee947..11ee9122c 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -149,6 +149,17 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const { + _out << _prefix << ".pre:" << endl; + for (AssemblyItem const& i: m_items) + switch (i.m_type) + { + case PushTag: + _out << _prefix << " PUSH [tag" << i.m_data << "]" << endl; + _out << _prefix << " JUMPDEST" << endl; + break; + default:; + } + _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) switch (i.m_type) @@ -353,9 +364,11 @@ bytes Assembly::assemble() const ret.reserve(totalBytes); vector tagPos(m_usedTags); map tagRef; + map pretagRef; multimap dataRef; unsigned bytesPerTag = dev::bytesRequired(totalBytes); byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; + bytes preret; for (auto const& i: m_subs) m_data[i.first] = i.second.assemble(); @@ -393,6 +406,11 @@ bytes Assembly::assemble() const ret.push_back(tagPush); tagRef[ret.size()] = (unsigned)i.m_data; ret.resize(ret.size() + bytesPerTag); + + preret.push_back(tagPush); + pretagRef[preret.size()] = (unsigned)i.m_data; + preret.resize(preret.size() + bytesPerTag); + preret.push_back((byte)Instruction::JUMPDEST); break; } case PushData: case PushSub: @@ -424,6 +442,12 @@ bytes Assembly::assemble() const toBigEndian(tagPos[i.second], r); } + for (auto const& i: pretagRef) + { + bytesRef r(preret.data() + i.first, bytesPerTag); + toBigEndian(tagPos[i.second], r); + } + if (m_data.size()) { ret.push_back(0); @@ -442,5 +466,5 @@ bytes Assembly::assemble() const } } } - return ret; + return preret + ret; } From 8c1c9ac6646a93837c5fcd9c446097ae797c25da Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 7 Oct 2014 23:07:56 +0200 Subject: [PATCH 59/92] More attempts to fix for the ultra-pedantic clang compiler. --- CodeFragment.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 533d00a96..56b5d440f 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "CompilerState.h" #include "Parser.h" From b4865f961bfa946c38545403e515d8825ebb0399 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 8 Oct 2014 14:43:32 +0200 Subject: [PATCH 60/92] PoC-7 JUMPDEST done the intended way. Windows pedantic build fix. --- Assembly.cpp | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 11ee9122c..695c9ffab 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -129,7 +129,7 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) _out << " PUSH[tag" << i.data() << "]"; break; case Tag: - _out << " tag" << i.data() << ":"; + _out << " tag" << i.data() << ": JUMPDEST"; break; case PushData: _out << " PUSH*[" << hex << (unsigned)i.data() << "]"; @@ -149,17 +149,6 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const { - _out << _prefix << ".pre:" << endl; - for (AssemblyItem const& i: m_items) - switch (i.m_type) - { - case PushTag: - _out << _prefix << " PUSH [tag" << i.m_data << "]" << endl; - _out << _prefix << " JUMPDEST" << endl; - break; - default:; - } - _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) switch (i.m_type) @@ -183,7 +172,7 @@ ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const _out << _prefix << " PUSH #[$" << h256(i.m_data).abridged() << "]" << endl; break; case Tag: - _out << _prefix << "tag" << i.m_data << ": " << endl; + _out << _prefix << "tag" << i.m_data << ": " << endl << _prefix << " JUMPDEST" << endl; break; case PushData: _out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; @@ -364,11 +353,9 @@ bytes Assembly::assemble() const ret.reserve(totalBytes); vector tagPos(m_usedTags); map tagRef; - map pretagRef; multimap dataRef; unsigned bytesPerTag = dev::bytesRequired(totalBytes); byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; - bytes preret; for (auto const& i: m_subs) m_data[i.first] = i.second.assemble(); @@ -406,11 +393,6 @@ bytes Assembly::assemble() const ret.push_back(tagPush); tagRef[ret.size()] = (unsigned)i.m_data; ret.resize(ret.size() + bytesPerTag); - - preret.push_back(tagPush); - pretagRef[preret.size()] = (unsigned)i.m_data; - preret.resize(preret.size() + bytesPerTag); - preret.push_back((byte)Instruction::JUMPDEST); break; } case PushData: case PushSub: @@ -432,6 +414,7 @@ bytes Assembly::assemble() const } case Tag: tagPos[(unsigned)i.m_data] = ret.size(); + ret.push_back((byte)Instruction::JUMPDEST); break; default:; } @@ -442,12 +425,6 @@ bytes Assembly::assemble() const toBigEndian(tagPos[i.second], r); } - for (auto const& i: pretagRef) - { - bytesRef r(preret.data() + i.first, bytesPerTag); - toBigEndian(tagPos[i.second], r); - } - if (m_data.size()) { ret.push_back(0); @@ -466,5 +443,5 @@ bytes Assembly::assemble() const } } } - return preret + ret; + return ret; } From db9b99602e72cccdcb346fb80612a9275ec0a8f8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 8 Oct 2014 16:40:46 +0200 Subject: [PATCH 61/92] According commit for JUMPDEST. --- Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assembly.cpp b/Assembly.cpp index 695c9ffab..c26a9a98e 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -413,8 +413,8 @@ bytes Assembly::assemble() const break; } case Tag: - tagPos[(unsigned)i.m_data] = ret.size(); ret.push_back((byte)Instruction::JUMPDEST); + tagPos[(unsigned)i.m_data] = ret.size(); break; default:; } From 9c691e917fcfd291fcaa3c6aaff8c8242fc50873 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 16 Oct 2014 15:10:54 +0200 Subject: [PATCH 62/92] add headers to cmake --- CMakeLists.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7746613ec..cb50cc36e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,15 +6,13 @@ aux_source_directory(. SRC_LIST) set(EXECUTABLE lll) -# set(CMAKE_INSTALL_PREFIX ../lib) +file(GLOB HEADERS "*.h") if(ETH_STATIC) - add_library(${EXECUTABLE} STATIC ${SRC_LIST}) + add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) else() - add_library(${EXECUTABLE} SHARED ${SRC_LIST}) + add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) endif() -file(GLOB HEADERS "*.h") - include_directories(..) target_link_libraries(${EXECUTABLE} evmface) From bded2ff3726c5626ea59b2bcbdf5fcded25457c7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 20:26:34 +0100 Subject: [PATCH 63/92] Draft of new LOG/bloom/headers/block format. --- Assembly.cpp | 4 ++-- Assembly.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index c26a9a98e..5b10138d1 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -147,7 +147,7 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) return _out; } -ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const +ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const { _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) @@ -189,7 +189,7 @@ ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const for (auto const& i: m_subs) { _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << endl; - i.second.streamOut(_out, _prefix + " "); + i.second.streamRLP(_out, _prefix + " "); } } return _out; diff --git a/Assembly.h b/Assembly.h index b7feaf4f4..8ab3062dc 100644 --- a/Assembly.h +++ b/Assembly.h @@ -104,11 +104,11 @@ public: void injectStart(AssemblyItem const& _i); - std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } + std::string out() const { std::stringstream ret; streamRLP(ret); return ret.str(); } int deposit() const { return m_deposit; } bytes assemble() const; Assembly& optimise(bool _enable); - std::ostream& streamOut(std::ostream& _out, std::string const& _prefix = "") const; + std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "") const; private: void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } @@ -127,7 +127,7 @@ private: inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) { - _a.streamOut(_out); + _a.streamRLP(_out); return _out; } From f6e24989ec929eb7d22486544a0053c4e5bb2e6c Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 29 Oct 2014 00:13:26 +0100 Subject: [PATCH 64/92] Bugfix: Tag takes one byte (for JUMPDEST) --- Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assembly.cpp b/Assembly.cpp index 5b10138d1..7ad84682f 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -54,6 +54,7 @@ unsigned Assembly::bytesRequired() const switch (i.m_type) { case Operation: + case Tag: // 1 byte for the JUMPDEST ret++; break; case PushString: @@ -69,7 +70,6 @@ unsigned Assembly::bytesRequired() const case PushData: case PushSub: ret += 1 + br; - case Tag:; default:; } if (dev::bytesRequired(ret) <= br) From d038c0751dba11ce8c6d9c3ec2375190ab145b6d Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 30 Oct 2014 01:20:32 +0100 Subject: [PATCH 65/92] Contract compiler and also add ExpressionStatement to AST. ExpressionStatement functions as glue between Statements and Expressions. This way it is possible to detect when the border between statements and expressions is crossed while walking the AST. Note that ExpressionStatement is not the only border, almost every statement can contains expressions. --- Assembly.cpp | 2 +- Assembly.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Assembly.cpp b/Assembly.cpp index 5b10138d1..7ad84682f 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -54,6 +54,7 @@ unsigned Assembly::bytesRequired() const switch (i.m_type) { case Operation: + case Tag: // 1 byte for the JUMPDEST ret++; break; case PushString: @@ -69,7 +70,6 @@ unsigned Assembly::bytesRequired() const case PushData: case PushSub: ret += 1 + br; - case Tag:; default:; } if (dev::bytesRequired(ret) <= br) diff --git a/Assembly.h b/Assembly.h index 8ab3062dc..38baee0c5 100644 --- a/Assembly.h +++ b/Assembly.h @@ -105,7 +105,11 @@ public: void injectStart(AssemblyItem const& _i); std::string out() const { std::stringstream ret; streamRLP(ret); return ret.str(); } + int deposit() const { return m_deposit; } + void adjustDeposit(int _adjustment) { m_deposit += _adjustment; assert(m_deposit >= 0); } + void setDeposit(int _deposit) { m_deposit = _deposit; assert(m_deposit >= 0); } + bytes assemble() const; Assembly& optimise(bool _enable); std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "") const; From 64786387c17fec33e3e9de40387925c10a9dccfb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 31 Oct 2014 14:32:32 +0100 Subject: [PATCH 66/92] PoC-7: Instruction set reform --- Assembly.cpp | 2 +- CodeFragment.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Assembly.cpp b/Assembly.cpp index 7ad84682f..25895e1b7 100644 --- a/Assembly.cpp +++ b/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/CodeFragment.cpp b/CodeFragment.cpp index 56b5d440f..47df8f3b9 100644 --- a/CodeFragment.cpp +++ b/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 577503539e5fe6c06edc3271b0b00d51f82e29c9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 31 Oct 2014 20:29:38 +0100 Subject: [PATCH 67/92] Fix for assembler. --- Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assembly.cpp b/Assembly.cpp index 25895e1b7..d4f6c0a73 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -413,8 +413,8 @@ bytes Assembly::assemble() const break; } case Tag: - ret.push_back((byte)Instruction::JUMPDEST); tagPos[(unsigned)i.m_data] = ret.size(); + ret.push_back((byte)Instruction::JUMPDEST); break; default:; } From fd980ea543a9d666dd20289ac61cfbe40a039d5e Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 5 Nov 2014 15:21:20 +0100 Subject: [PATCH 68/92] assert and exception corrections in solidity-external files. --- Assembly.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Assembly.h b/Assembly.h index 38baee0c5..e39f1899b 100644 --- a/Assembly.h +++ b/Assembly.h @@ -45,8 +45,8 @@ public: AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {} - AssemblyItem tag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(Tag, m_data); } - AssemblyItem pushTag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(PushTag, m_data); } + AssemblyItem tag() const { if (asserts(m_type == PushTag || m_type == Tag)) BOOST_THROW_EXCEPTION(Exception()); return AssemblyItem(Tag, m_data); } + AssemblyItem pushTag() const { if (asserts(m_type == PushTag || m_type == Tag)) BOOST_THROW_EXCEPTION(Exception()); return AssemblyItem(PushTag, m_data); } AssemblyItemType type() const { return m_type; } u256 data() const { return m_data; } @@ -94,7 +94,7 @@ public: AssemblyItem const& back() { return m_items.back(); } std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } - void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } + void onePath() { if (asserts(!m_totalDeposit && !m_baseDeposit)) BOOST_THROW_EXCEPTION(InvalidDeposit()); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } void ignored() { m_baseDeposit = m_deposit; } @@ -107,8 +107,8 @@ public: std::string out() const { std::stringstream ret; streamRLP(ret); return ret.str(); } int deposit() const { return m_deposit; } - void adjustDeposit(int _adjustment) { m_deposit += _adjustment; assert(m_deposit >= 0); } - void setDeposit(int _deposit) { m_deposit = _deposit; assert(m_deposit >= 0); } + 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()); } bytes assemble() const; Assembly& optimise(bool _enable); From 476853f3feb2159fa24a85826c19e7e5190d3770 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 6 Nov 2014 14:50:18 +0100 Subject: [PATCH 69/92] Moved instructions and assembly to new libevmcore. --- All.h | 1 - Assembly.cpp | 447 ----------------------------------------------- Assembly.h | 139 --------------- CMakeLists.txt | 2 +- CodeFragment.cpp | 2 +- CodeFragment.h | 4 +- Exceptions.h | 3 - 7 files changed, 4 insertions(+), 594 deletions(-) delete mode 100644 Assembly.cpp delete mode 100644 Assembly.h diff --git a/All.h b/All.h index ec6989e66..7c4192f62 100644 --- a/All.h +++ b/All.h @@ -1,6 +1,5 @@ #pragma once -#include "Assembly.h" #include "CodeFragment.h" #include "Compiler.h" #include "CompilerState.h" diff --git a/Assembly.cpp b/Assembly.cpp deleted file mode 100644 index d4f6c0a73..000000000 --- a/Assembly.cpp +++ /dev/null @@ -1,447 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Assembly.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "Assembly.h" - -#include - -using namespace std; -using namespace dev; -using namespace dev::eth; - -int AssemblyItem::deposit() const -{ - switch (m_type) - { - case Operation: - return instructionInfo((Instruction)(byte)m_data).ret - instructionInfo((Instruction)(byte)m_data).args; - case Push: case PushString: case PushTag: case PushData: case PushSub: case PushSubSize: - return 1; - case Tag: - return 0; - default:; - } - return 0; -} - -unsigned Assembly::bytesRequired() const -{ - for (unsigned br = 1;; ++br) - { - unsigned ret = 1; - for (auto const& i: m_data) - ret += i.second.size(); - - for (AssemblyItem const& i: m_items) - switch (i.m_type) - { - case Operation: - case Tag: // 1 byte for the JUMPDEST - ret++; - break; - case PushString: - ret += 33; - break; - case Push: - ret += 1 + max(1, dev::bytesRequired(i.m_data)); - break; - case PushSubSize: - ret += 4; // worst case: a 16MB program - break; - case PushTag: - case PushData: - case PushSub: - ret += 1 + br; - default:; - } - if (dev::bytesRequired(ret) <= br) - return ret; - } -} - -void Assembly::append(Assembly const& _a) -{ - auto newDeposit = m_deposit + _a.deposit(); - for (AssemblyItem i: _a.m_items) - { - if (i.type() == Tag || i.type() == PushTag) - i.m_data += m_usedTags; - append(i); - } - m_deposit = newDeposit; - m_usedTags += _a.m_usedTags; - for (auto const& i: _a.m_data) - m_data.insert(i); - for (auto const& i: _a.m_strings) - m_strings.insert(i); - for (auto const& i: _a.m_subs) - m_subs.insert(i); - - assert(!_a.m_baseDeposit); - assert(!_a.m_totalDeposit); -} - -void Assembly::append(Assembly const& _a, int _deposit) -{ - if (_deposit > _a.m_deposit) - BOOST_THROW_EXCEPTION(InvalidDeposit()); - else - { - append(_a); - while (_deposit++ < _a.m_deposit) - append(Instruction::POP); - } -} - -ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) -{ - for (AssemblyItem const& i: _i) - switch (i.type()) - { - case Operation: - _out << " " << instructionInfo((Instruction)(byte)i.data()).name; - break; - case Push: - _out << " PUSH" << i.data(); - break; - case PushString: - _out << " PUSH'[" << hex << (unsigned)i.data() << "]"; - break; - case PushTag: - _out << " PUSH[tag" << i.data() << "]"; - break; - case Tag: - _out << " tag" << i.data() << ": JUMPDEST"; - break; - case PushData: - _out << " PUSH*[" << hex << (unsigned)i.data() << "]"; - break; - case PushSub: - _out << " PUSHs[" << hex << h256(i.data()).abridged() << "]"; - break; - case PushSubSize: - _out << " PUSHss[" << hex << h256(i.data()).abridged() << "]"; - break; - case UndefinedItem: - _out << " ???"; - default:; - } - return _out; -} - -ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const -{ - _out << _prefix << ".code:" << endl; - for (AssemblyItem const& i: m_items) - switch (i.m_type) - { - case Operation: - _out << _prefix << " " << instructionInfo((Instruction)(byte)i.m_data).name << endl; - break; - case Push: - _out << _prefix << " PUSH " << i.m_data << endl; - break; - case PushString: - _out << _prefix << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; - break; - case PushTag: - _out << _prefix << " PUSH [tag" << i.m_data << "]" << endl; - break; - case PushSub: - _out << _prefix << " PUSH [$" << h256(i.m_data).abridged() << "]" << endl; - break; - case PushSubSize: - _out << _prefix << " PUSH #[$" << h256(i.m_data).abridged() << "]" << endl; - break; - case Tag: - _out << _prefix << "tag" << i.m_data << ": " << endl << _prefix << " JUMPDEST" << endl; - break; - case PushData: - _out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; - break; - default:; - } - - if (m_data.size() || m_subs.size()) - { - _out << _prefix << ".data:" << endl; - for (auto const& i: m_data) - if (!m_subs.count(i.first)) - _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << toHex(i.second) << endl; - for (auto const& i: m_subs) - { - _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << endl; - i.second.streamRLP(_out, _prefix + " "); - } - } - return _out; -} - -AssemblyItem const& Assembly::append(AssemblyItem const& _i) -{ - m_deposit += _i.deposit(); - m_items.push_back(_i); - return back(); -} - -void Assembly::injectStart(AssemblyItem const& _i) -{ - m_items.insert(m_items.begin(), _i); -} - -inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) -{ - if (_a.size() != _b.size()) - return false; - for (unsigned i = 0; i < _a.size(); ++i) - if (!_a[i].match(_b[i])) - return false; - return true; -} - -struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; -#define copt dev::LogOutputStream() - -Assembly& Assembly::optimise(bool _enable) -{ - if (!_enable) - return *this; - map> c_simple = - { - { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, - { Instruction::DIV, [](u256 a, u256 b)->u256{return a / b;} }, - { Instruction::SDIV, [](u256 a, u256 b)->u256{return s2u(u2s(a) / u2s(b));} }, - { Instruction::MOD, [](u256 a, u256 b)->u256{return a % b;} }, - { Instruction::SMOD, [](u256 a, u256 b)->u256{return s2u(u2s(a) % u2s(b));} }, - { Instruction::EXP, [](u256 a, u256 b)->u256{return (u256)boost::multiprecision::powm((bigint)a, (bigint)b, bigint(2) << 256);} }, - { Instruction::LT, [](u256 a, u256 b)->u256{return a < b ? 1 : 0;} }, - { Instruction::GT, [](u256 a, u256 b)->u256{return a > b ? 1 : 0;} }, - { Instruction::SLT, [](u256 a, u256 b)->u256{return u2s(a) < u2s(b) ? 1 : 0;} }, - { Instruction::SGT, [](u256 a, u256 b)->u256{return u2s(a) > u2s(b) ? 1 : 0;} }, - { Instruction::EQ, [](u256 a, u256 b)->u256{return a == b ? 1 : 0;} }, - }; - map> c_associative = - { - { Instruction::ADD, [](u256 a, u256 b)->u256{return a + b;} }, - { Instruction::MUL, [](u256 a, u256 b)->u256{return a * b;} }, - }; - std::vector>> rules = - { - { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { PushTag, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { PushString, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - { { 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::ISZERO, Instruction::ISZERO }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, - }; - - for (auto const& i: c_simple) - rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); - for (auto const& i: c_associative) - { - rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); - rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } }); - rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {}; else return m.toVector(); }}); - } - - copt << *this; - - unsigned total = 0; - for (unsigned count = 1; count > 0; total += count) - { - count = 0; - map tags; - for (unsigned i = 0; i < m_items.size(); ++i) - { - for (auto const& r: rules) - { - auto vr = AssemblyItemsConstRef(&m_items).cropped(i, r.first.size()); - if (matches(&r.first, vr)) - { - auto rw = r.second(vr); - if (rw.size() < vr.size()) - { - copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; - for (unsigned j = 0; j < vr.size(); ++j) - if (j < rw.size()) - m_items[i + j] = rw[j]; - else - m_items.erase(m_items.begin() + i + rw.size()); - copt << AssemblyItemsConstRef(&rw); - count++; - copt << "Now:\n" << m_items; - } - } - } - if (m_items[i].type() == Operation && m_items[i].data() == (byte)Instruction::JUMP) - { - bool o = false; - while (m_items.size() > i + 1 && m_items[i + 1].type() != Tag) - { - m_items.erase(m_items.begin() + i + 1); - o = true; - } - if (o) - { - copt << "Jump with no tag. Now:\n" << m_items; - ++count; - } - } - } - - for (unsigned i = 0; i < m_items.size(); ++i) - if (m_items[i].type() == Tag) - tags.insert(make_pair(m_items[i].data(), i)); - - for (auto const& i: m_items) - if (i.type() == PushTag) - tags.erase(i.data()); - - if (tags.size()) - { - auto t = *tags.begin(); - unsigned i = t.second; - if (i && m_items[i - 1].type() == Operation && m_items[i - 1].data() == (byte)Instruction::JUMP) - while (i < m_items.size() && (m_items[i].type() != Tag || tags.count(m_items[i].data()))) - { - if (m_items[i].type() == Tag && tags.count(m_items[i].data())) - tags.erase(m_items[i].data()); - m_items.erase(m_items.begin() + i); - } - else - { - m_items.erase(m_items.begin() + i); - tags.erase(t.first); - } - copt << "Unused tag. Now:\n" << m_items; - ++count; - } - } - - copt << total << " optimisations done."; - - for (auto& i: m_subs) - i.second.optimise(true); - - return *this; -} - -bytes Assembly::assemble() const -{ - bytes ret; - - unsigned totalBytes = bytesRequired(); - ret.reserve(totalBytes); - vector tagPos(m_usedTags); - map tagRef; - multimap dataRef; - unsigned bytesPerTag = dev::bytesRequired(totalBytes); - byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; - - for (auto const& i: m_subs) - m_data[i.first] = i.second.assemble(); - - for (AssemblyItem const& i: m_items) - switch (i.m_type) - { - case Operation: - ret.push_back((byte)i.m_data); - break; - case PushString: - { - ret.push_back((byte)Instruction::PUSH32); - unsigned ii = 0; - for (auto j: m_strings.at((h256)i.m_data)) - if (++ii > 32) - break; - else - ret.push_back((byte)j); - while (ii++ < 32) - ret.push_back(0); - break; - } - case Push: - { - byte b = max(1, dev::bytesRequired(i.m_data)); - ret.push_back((byte)Instruction::PUSH1 - 1 + b); - ret.resize(ret.size() + b); - bytesRef byr(&ret.back() + 1 - b, b); - toBigEndian(i.m_data, byr); - break; - } - case PushTag: - { - ret.push_back(tagPush); - tagRef[ret.size()] = (unsigned)i.m_data; - ret.resize(ret.size() + bytesPerTag); - break; - } - case PushData: case PushSub: - { - ret.push_back(tagPush); - dataRef.insert(make_pair((h256)i.m_data, ret.size())); - ret.resize(ret.size() + bytesPerTag); - break; - } - case PushSubSize: - { - auto s = m_data[i.m_data].size(); - byte b = max(1, dev::bytesRequired(s)); - ret.push_back((byte)Instruction::PUSH1 - 1 + b); - ret.resize(ret.size() + b); - bytesRef byr(&ret.back() + 1 - b, b); - toBigEndian(s, byr); - break; - } - case Tag: - tagPos[(unsigned)i.m_data] = ret.size(); - ret.push_back((byte)Instruction::JUMPDEST); - break; - default:; - } - - for (auto const& i: tagRef) - { - bytesRef r(ret.data() + i.first, bytesPerTag); - toBigEndian(tagPos[i.second], r); - } - - if (m_data.size()) - { - ret.push_back(0); - for (auto const& i: m_data) - { - auto its = dataRef.equal_range(i.first); - if (its.first != its.second) - { - for (auto it = its.first; it != its.second; ++it) - { - bytesRef r(ret.data() + it->second, bytesPerTag); - toBigEndian(ret.size(), r); - } - for (auto b: i.second) - ret.push_back(b); - } - } - } - return ret; -} diff --git a/Assembly.h b/Assembly.h deleted file mode 100644 index e39f1899b..000000000 --- a/Assembly.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file CodeFragment.h - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include -#include -#include -#include -#include "Exceptions.h" - -namespace dev -{ -namespace eth -{ - -enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, Tag, PushData }; - -class Assembly; - -class AssemblyItem -{ - friend class Assembly; - -public: - 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) {} - - AssemblyItem tag() const { if (asserts(m_type == PushTag || m_type == Tag)) BOOST_THROW_EXCEPTION(Exception()); return AssemblyItem(Tag, m_data); } - AssemblyItem pushTag() const { if (asserts(m_type == PushTag || m_type == Tag)) BOOST_THROW_EXCEPTION(Exception()); return AssemblyItem(PushTag, m_data); } - - AssemblyItemType type() const { return m_type; } - u256 data() const { return m_data; } - - 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)); } - -private: - AssemblyItemType m_type; - u256 m_data; -}; - -typedef std::vector AssemblyItems; -typedef vector_ref AssemblyItemsConstRef; - -std::ostream& operator<<(std::ostream& _out, AssemblyItemsConstRef _i); -inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { return operator<<(_out, AssemblyItemsConstRef(&_i)); } - -class Assembly -{ -public: - AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } - AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } - AssemblyItem newData(bytes const& _data) { h256 h = (u256)std::hash()(asString(_data)); m_data[h] = _data; return AssemblyItem(PushData, h); } - AssemblyItem newSub(Assembly const& _sub) { h256 h = h256::random(s_fixedHashEngine); m_subs[h] = _sub; return AssemblyItem(PushSub, h); } - AssemblyItem newPushString(std::string const& _data) { h256 h = (u256)std::hash()(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } - AssemblyItem newPushSubSize(h256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } - - AssemblyItem append() { return append(newTag()); } - void append(Assembly const& _a); - void append(Assembly const& _a, int _deposit); - AssemblyItem const& append(AssemblyItem const& _i); - AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } - AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } - AssemblyItem appendSubSize(Assembly const& _a) { auto ret = newSub(_a); append(newPushSubSize(ret.data())); return ret; } - - AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } - AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } - AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; } - AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; } - - template Assembly& operator<<(T const& _d) { append(_d); return *this; } - - AssemblyItem const& back() { return m_items.back(); } - std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } - - void onePath() { if (asserts(!m_totalDeposit && !m_baseDeposit)) BOOST_THROW_EXCEPTION(InvalidDeposit()); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } - void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } - void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } - void ignored() { m_baseDeposit = m_deposit; } - void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } - - 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(); } - - 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()); } - - bytes assemble() const; - Assembly& optimise(bool _enable); - std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "") const; - -private: - void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } - unsigned bytesRequired() const; - - unsigned m_usedTags = 0; - AssemblyItems m_items; - mutable std::map m_data; - std::map m_subs; - std::map m_strings; - - int m_deposit = 0; - int m_baseDeposit = 0; - int m_totalDeposit = 0; -}; - -inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) -{ - _a.streamRLP(_out); - return _out; -} - -} -} diff --git a/CMakeLists.txt b/CMakeLists.txt index cb50cc36e..8b1581785 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ endif() include_directories(..) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 47df8f3b9..2c200caa5 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "CompilerState.h" #include "Parser.h" using namespace std; diff --git a/CodeFragment.h b/CodeFragment.h index d6ca86bbe..b24b474da 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -22,8 +22,8 @@ #pragma once #include -#include -#include "Assembly.h" +#include +#include #include "Exceptions.h" namespace boost { namespace spirit { class utree; } } diff --git a/Exceptions.h b/Exceptions.h index c45215f1a..1e9671b36 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -32,16 +32,13 @@ namespace eth class CompilerException: public dev::Exception {}; class InvalidOperation: public CompilerException {}; class IntegerOutOfRange: public CompilerException {}; -class StringTooLong: public CompilerException {}; class EmptyList: public CompilerException {}; class DataNotExecutable: public CompilerException {}; class IncorrectParameterCount: public CompilerException {}; -class InvalidDeposit: public CompilerException {}; class InvalidName: public CompilerException {}; class InvalidMacroArgs: public CompilerException {}; class InvalidLiteral: public CompilerException {}; class BareSymbol: public CompilerException {}; -class ExpectedLiteral: public CompilerException {}; } } From c60def06b504bda1cc61923c8d1951465996c7a1 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 4 Dec 2014 09:55:54 +0100 Subject: [PATCH 70/92] removed automocs --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b1581785..4e6941359 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_policy(SET CMP0015 NEW) +set(CMAKE_AUTOMOC OFF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") From 33ac800c01ca080cea4b954a0c609782c9f3bbe3 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 5 Dec 2014 16:40:41 +0100 Subject: [PATCH 71/92] lll, buildinfo.h and llc compiling on windows --- CMakeLists.txt | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e6941359..e2c000010 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(${Boost_INCLUDE_DIRS}) +include_directories(..) + set(EXECUTABLE lll) file(GLOB HEADERS "*.h") @@ -14,36 +17,9 @@ else() add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) endif() -include_directories(..) - target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) - -if("${TARGET_PLATFORM}" STREQUAL "w64") - target_link_libraries(${EXECUTABLE} boost_system-mt-s) - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) -elseif (APPLE) - # Latest mavericks boost libraries only come with -mt - target_link_libraries(${EXECUTABLE} boost_system-mt) - target_link_libraries(${EXECUTABLE} boost_thread-mt) - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -elseif (UNIX) - target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -else () - target_link_libraries(${EXECUTABLE} boost_system) - target_link_libraries(${EXECUTABLE} boost_thread) - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () - install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) From 8f3f5275c01e40bbbf0e1a5df3ec01115e757478 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 10 Dec 2014 11:39:41 +0100 Subject: [PATCH 72/92] jsonrpc option in cmakes, removed all warnings --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2c000010..908b8caf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,10 @@ cmake_policy(SET CMP0015 NEW) +# this policy was introduced in cmake 3.0 +# remove if, once 3.0 will be used on unix +if (APPLE) + # old policy do not use MACOSX_RPATH + cmake_policy(SET CMP0042 OLD) +endif() set(CMAKE_AUTOMOC OFF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") From c8ad93914148a3a0c191f22bb21e9eabf217d1ae Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 10 Dec 2014 12:49:12 +0100 Subject: [PATCH 73/92] updated cmake policies --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 908b8caf3..28e5cb758 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_policy(SET CMP0015 NEW) # this policy was introduced in cmake 3.0 # remove if, once 3.0 will be used on unix -if (APPLE) +if (${CMAKE_MAJOR_VERSION} GREATER 2) # old policy do not use MACOSX_RPATH cmake_policy(SET CMP0042 OLD) endif() From 005f551bfbf153a11af7cb3c2015ccfe6cf70e08 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 11 Dec 2014 15:06:11 +0100 Subject: [PATCH 74/92] fixed styling issues --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28e5cb758..fb79d5873 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ include_directories(..) set(EXECUTABLE lll) file(GLOB HEADERS "*.h") + if(ETH_STATIC) add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) else() From fee1a7f44cbb3a7743531b12bf1091075d435e6a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 11 Dec 2014 18:25:21 +0100 Subject: [PATCH 75/92] Fix for crazy compiler lambda behaviour. --- CompilerState.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CompilerState.cpp b/CompilerState.cpp index c3dc2dda3..63351bc4c 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -72,6 +72,11 @@ void CompilerState::populateStandard() "(def 'regname (name) { [32]'register [64]name (call allgas namereg 0 32 64 0 0) })" "(def 'regcoin (name) { [32]name (call allgas coinreg 0 32 32 0 0) })" "(def 'regcoin (name denom) { [32]name [64]denom (call allgas coinreg 0 32 64 0 0) })" + "(def 'ecrecover (r s v hash) { [0] r [32] s [64] v [96] hash (msg allgas 1 0 0 128) })" + "(def 'sha256 (data datasize) (msg allgas 2 0 data datasize))" + "(def 'ripemd160 (data datasize) (msg allgas 3 0 data datasize))" + "(def 'sha256 (val) { [0]:val (sha256 0 32) })" + "(def 'ripemd160 (val) { [0]:val (ripemd160 0 32) })" "}"; CodeFragment::compile(s, *this); } From 529847d8e1e91f3c764b5adddc5d832a2d598d0c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 21 Jan 2015 11:31:14 -0800 Subject: [PATCH 76/92] Claim ether makes wallet & trasfers. "#require" in solidity. --- CodeFragment.cpp | 1 - CodeFragment.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 2c200caa5..1e7766434 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -266,7 +266,6 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) } ++ii; } - } else if (us == "LIT") { diff --git a/CodeFragment.h b/CodeFragment.h index b24b474da..554f90b46 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -61,3 +61,4 @@ static const CodeFragment NullCodeFragment; } } + From 887627fd284440b346818d17b139d3bd876ba4e6 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Fri, 6 Feb 2015 15:19:22 +0800 Subject: [PATCH 77/92] change typedef to using according to preferred coding style --- Parser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Parser.cpp b/Parser.cpp index e94e88e19..df30f3897 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -89,8 +89,8 @@ void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out) using qi::standard::space; using qi::standard::space_type; using dev::eth::parseTreeLLL_::tagNode; - typedef sp::basic_string symbol_type; - typedef string::const_iterator it; + using symbol_type = sp::basic_string; + using it = string::const_iterator; static const u256 ether = u256(1000000000) * 1000000000; static const u256 finney = u256(1000000000) * 1000000; From 1137e84828c44120cf0300f0b434a8dd20dcc298 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 16 Feb 2015 13:48:25 +0100 Subject: [PATCH 78/92] fixed #1022 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb79d5873..3b9dc6030 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE lll) From b804ef818a07d53faa3b3cdeca6914a5871cc8a9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 21:59:21 +0100 Subject: [PATCH 79/92] Add EVMJIT. --- All.h | 6 - CMakeLists.txt | 32 --- CodeFragment.cpp | 581 ---------------------------------------------- CodeFragment.h | 64 ----- Compiler.cpp | 95 -------- Compiler.h | 38 --- CompilerState.cpp | 82 ------- CompilerState.h | 57 ----- Exceptions.h | 44 ---- Parser.cpp | 145 ------------ Parser.h | 41 ---- 11 files changed, 1185 deletions(-) delete mode 100644 All.h delete mode 100644 CMakeLists.txt delete mode 100644 CodeFragment.cpp delete mode 100644 CodeFragment.h delete mode 100644 Compiler.cpp delete mode 100644 Compiler.h delete mode 100644 CompilerState.cpp delete mode 100644 CompilerState.h delete mode 100644 Exceptions.h delete mode 100644 Parser.cpp delete mode 100644 Parser.h diff --git a/All.h b/All.h deleted file mode 100644 index 7c4192f62..000000000 --- a/All.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "CodeFragment.h" -#include "Compiler.h" -#include "CompilerState.h" -#include "Parser.h" diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 3b9dc6030..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -cmake_policy(SET CMP0015 NEW) -# this policy was introduced in cmake 3.0 -# remove if, once 3.0 will be used on unix -if (${CMAKE_MAJOR_VERSION} GREATER 2) - # old policy do not use MACOSX_RPATH - cmake_policy(SET CMP0042 OLD) -endif() -set(CMAKE_AUTOMOC OFF) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") - -aux_source_directory(. SRC_LIST) - -include_directories(BEFORE ..) -include_directories(${Boost_INCLUDE_DIRS}) - -set(EXECUTABLE lll) - -file(GLOB HEADERS "*.h") - -if(ETH_STATIC) - add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) -else() - add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) -endif() - -target_link_libraries(${EXECUTABLE} evmcore) -target_link_libraries(${EXECUTABLE} devcore) - -install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) -install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) - diff --git a/CodeFragment.cpp b/CodeFragment.cpp deleted file mode 100644 index 1e7766434..000000000 --- a/CodeFragment.cpp +++ /dev/null @@ -1,581 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file CodeFragment.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "CodeFragment.h" - -#include -#include -#include -#include -#include -#include "CompilerState.h" -#include "Parser.h" -using namespace std; -using namespace dev; -using namespace dev::eth; -namespace qi = boost::spirit::qi; -namespace px = boost::phoenix; -namespace sp = boost::spirit; - -void CodeFragment::finalise(CompilerState const& _cs) -{ - if (_cs.usedAlloc && _cs.vars.size() && !m_finalised) - { - m_finalised = true; - m_asm.injectStart(Instruction::MSTORE8); - m_asm.injectStart((u256)((_cs.vars.size() + 2) * 32) - 1); - m_asm.injectStart((u256)1); - } -} - -CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) -{ -/* cdebug << "CodeFragment. Locals:"; - for (auto const& i: _s.defs) - cdebug << i.first << ":" << toHex(i.second.m_code); - cdebug << "Args:"; - for (auto const& i: _s.args) - cdebug << i.first << ":" << toHex(i.second.m_code); - cdebug << "Outers:"; - for (auto const& i: _s.outers) - cdebug << i.first << ":" << toHex(i.second.m_code); - debugOutAST(cout, _t); - cout << endl << flush; -*/ - switch (_t.which()) - { - case sp::utree_type::list_type: - constructOperation(_t, _s); - break; - case sp::utree_type::string_type: - { - auto sr = _t.get, sp::utree_type::string_type>>(); - string s(sr.begin(), sr.end()); - m_asm.append(s); - break; - } - case sp::utree_type::symbol_type: - { - auto sr = _t.get, sp::utree_type::symbol_type>>(); - string s(sr.begin(), sr.end()); - string us = boost::algorithm::to_upper_copy(s); - if (_allowASM && c_instructions.count(us)) - m_asm.append(c_instructions.at(us)); - else if (_s.defs.count(s)) - m_asm.append(_s.defs.at(s).m_asm); - else if (_s.args.count(s)) - m_asm.append(_s.args.at(s).m_asm); - else if (_s.outers.count(s)) - m_asm.append(_s.outers.at(s).m_asm); - else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) - { - auto it = _s.vars.find(s); - if (it == _s.vars.end()) - { - bool ok; - tie(it, ok) = _s.vars.insert(make_pair(s, make_pair(_s.stackSize, 32))); - _s.stackSize += 32; - } - m_asm.append((u256)it->second.first); - } - else - error(); - - break; - } - case sp::utree_type::any_type: - { - bigint i = *_t.get(); - if (i < 0 || i > bigint(u256(0) - 1)) - error(); - m_asm.append((u256)i); - break; - } - default: break; - } -} - -void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) -{ - if (_t.tag() == 0 && _t.empty()) - error(); - else if (_t.tag() == 0 && _t.front().which() != sp::utree_type::symbol_type) - error(); - else - { - string s; - string us; - switch (_t.tag()) - { - case 0: - { - auto sr = _t.front().get, sp::utree_type::symbol_type>>(); - s = string(sr.begin(), sr.end()); - us = boost::algorithm::to_upper_copy(s); - break; - } - case 1: - us = "MLOAD"; - break; - case 2: - us = "SLOAD"; - break; - case 3: - us = "MSTORE"; - break; - case 4: - us = "SSTORE"; - break; - case 5: - us = "SEQ"; - break; - case 6: - us = "CALLDATALOAD"; - break; - default:; - } - - auto firstAsString = [&]() - { - auto i = *++_t.begin(); - if (i.tag()) - error(); - if (i.which() == sp::utree_type::string_type) - { - auto sr = i.get, sp::utree_type::string_type>>(); - return string(sr.begin(), sr.end()); - } - else if (i.which() == sp::utree_type::symbol_type) - { - auto sr = i.get, sp::utree_type::symbol_type>>(); - return _s.getDef(string(sr.begin(), sr.end())).m_asm.backString(); - } - return string(); - }; - - auto varAddress = [&](string const& n) - { - auto it = _s.vars.find(n); - if (it == _s.vars.end()) - { - bool ok; - tie(it, ok) = _s.vars.insert(make_pair(n, make_pair(_s.stackSize, 32))); - _s.stackSize += 32; - } - return it->second.first; - }; - - // Operations who args are not standard stack-pushers. - bool nonStandard = true; - if (us == "ASM") - { - int c = 0; - for (auto const& i: _t) - if (c++) - m_asm.append(CodeFragment(i, _s, true).m_asm); - } - else if (us == "INCLUDE") - { - if (_t.size() != 2) - error(); - m_asm.append(CodeFragment::compile(asString(contents(firstAsString())), _s).m_asm); - } - else if (us == "SET") - { - if (_t.size() != 3) - error(); - int c = 0; - for (auto const& i: _t) - if (c++ == 2) - m_asm.append(CodeFragment(i, _s, false).m_asm); - m_asm.append((u256)varAddress(firstAsString())); - m_asm.append(Instruction::MSTORE); - } - else if (us == "GET") - { - if (_t.size() != 2) - error(); - m_asm.append((u256)varAddress(firstAsString())); - m_asm.append(Instruction::MLOAD); - } - else if (us == "REF") - m_asm.append((u256)varAddress(firstAsString())); - else if (us == "DEF") - { - string n; - unsigned ii = 0; - if (_t.size() != 3 && _t.size() != 4) - error(); - vector args; - for (auto const& i: _t) - { - if (ii == 1) - { - if (i.tag()) - error(); - if (i.which() == sp::utree_type::string_type) - { - auto sr = i.get, sp::utree_type::string_type>>(); - n = string(sr.begin(), sr.end()); - } - else if (i.which() == sp::utree_type::symbol_type) - { - auto sr = i.get, sp::utree_type::symbol_type>>(); - n = _s.getDef(string(sr.begin(), sr.end())).m_asm.backString(); - } - } - else if (ii == 2) - if (_t.size() == 3) - _s.defs[n] = CodeFragment(i, _s); - else - for (auto const& j: i) - { - if (j.tag() || j.which() != sp::utree_type::symbol_type) - error(); - auto sr = j.get, sp::utree_type::symbol_type>>(); - args.push_back(string(sr.begin(), sr.end())); - } - else if (ii == 3) - { - auto k = make_pair(n, args.size()); - _s.macros[k].code = i; - _s.macros[k].env = _s.outers; - _s.macros[k].args = args; - for (auto const& i: _s.args) - _s.macros[k].env[i.first] = i.second; - for (auto const& i: _s.defs) - _s.macros[k].env[i.first] = i.second; - } - ++ii; - } - } - else if (us == "LIT") - { - if (_t.size() < 3) - error(); - unsigned ii = 0; - CodeFragment pos; - bytes data; - for (auto const& i: _t) - { - if (ii == 1) - { - pos = CodeFragment(i, _s); - if (pos.m_asm.deposit() != 1) - error(); - } - else if (ii == 2 && !i.tag() && i.which() == sp::utree_type::string_type) - { - auto sr = i.get, sp::utree_type::string_type>>(); - data = bytes((byte const*)sr.begin(), (byte const*)sr.end()); - } - else if (ii >= 2 && !i.tag() && i.which() == sp::utree_type::any_type) - { - bigint bi = *i.get(); - if (bi < 0) - error(); - else if (bi > bigint(u256(0) - 1)) - { - if (ii == 2 && _t.size() == 3) - { - // One big int - allow it as hex. - data.resize(bytesRequired(bi)); - toBigEndian(bi, data); - } - else - error(); - } - else - { - data.resize(data.size() + 32); - *(h256*)(&data.back() - 31) = (u256)bi; - } - } - else if (ii) - error(); - ++ii; - } - m_asm.append((u256)data.size()); - m_asm.append(Instruction::DUP1); - m_asm.append(data); - m_asm.append(pos.m_asm, 1); - m_asm.append(Instruction::CODECOPY); - } - else - nonStandard = false; - - if (nonStandard) - return; - - 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::ISZERO } }; - - vector code; - CompilerState ns = _s; - ns.vars.clear(); - ns.usedAlloc = false; - int c = _t.tag() ? 1 : 0; - for (auto const& i: _t) - if (c++) - { - if (us == "LLL" && c == 1) - code.push_back(CodeFragment(i, ns)); - else - code.push_back(CodeFragment(i, _s)); - } - auto requireSize = [&](unsigned s) { if (code.size() != s) error(); }; - auto requireMinSize = [&](unsigned s) { if (code.size() < s) error(); }; - auto requireMaxSize = [&](unsigned s) { if (code.size() > s) error(); }; - auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_asm.deposit() != s) error(); }; - - if (_s.macros.count(make_pair(s, code.size()))) - { - Macro const& m = _s.macros.at(make_pair(s, code.size())); - CompilerState cs = _s; - for (auto const& i: m.env) - cs.outers[i.first] = i.second; - for (auto const& i: cs.defs) - cs.outers[i.first] = i.second; - cs.defs.clear(); - for (unsigned i = 0; i < m.args.size(); ++i) - { - //requireDeposit(i, 1); - cs.args[m.args[i]] = code[i]; - } - m_asm.append(CodeFragment(m.code, cs).m_asm); - for (auto const& i: cs.defs) - _s.defs[i.first] = i.second; - for (auto const& i: cs.macros) - _s.macros.insert(i); - } - else if (c_instructions.count(us)) - { - auto it = c_instructions.find(us); - int ea = instructionInfo(it->second).args; - if (ea >= 0) - requireSize(ea); - else - requireMinSize(-ea); - - for (unsigned i = code.size(); i; --i) - m_asm.append(code[i - 1].m_asm, 1); - m_asm.append(it->second); - } - else if (c_arith.count(us)) - { - auto it = c_arith.find(us); - requireMinSize(1); - for (unsigned i = code.size(); i; --i) - { - requireDeposit(i - 1, 1); - m_asm.append(code[i - 1].m_asm, 1); - } - for (unsigned i = 1; i < code.size(); ++i) - m_asm.append(it->second); - } - else if (c_binary.count(us)) - { - auto it = c_binary.find(us); - requireSize(2); - requireDeposit(0, 1); - requireDeposit(1, 1); - m_asm.append(code[1].m_asm, 1); - m_asm.append(code[0].m_asm, 1); - m_asm.append(it->second.first); - if (it->second.second) - m_asm.append(Instruction::ISZERO); - } - else if (c_unary.count(us)) - { - auto it = c_unary.find(us); - requireSize(1); - requireDeposit(0, 1); - m_asm.append(code[0].m_asm, 1); - m_asm.append(it->second); - } - else if (us == "IF") - { - requireSize(3); - requireDeposit(0, 1); - int minDep = min(code[1].m_asm.deposit(), code[2].m_asm.deposit()); - - m_asm.append(code[0].m_asm); - auto pos = m_asm.appendJumpI(); - m_asm.onePath(); - m_asm.append(code[2].m_asm, minDep); - auto end = m_asm.appendJump(); - m_asm.otherPath(); - m_asm << pos.tag(); - m_asm.append(code[1].m_asm, minDep); - m_asm << end.tag(); - m_asm.donePaths(); - } - else if (us == "WHEN" || us == "UNLESS") - { - requireSize(2); - requireDeposit(0, 1); - - m_asm.append(code[0].m_asm); - if (us == "WHEN") - m_asm.append(Instruction::ISZERO); - auto end = m_asm.appendJumpI(); - m_asm.onePath(); - m_asm.otherPath(); - m_asm.append(code[1].m_asm, 0); - m_asm << end.tag(); - m_asm.donePaths(); - } - else if (us == "WHILE") - { - requireSize(2); - requireDeposit(0, 1); - - auto begin = m_asm.append(); - m_asm.append(code[0].m_asm); - m_asm.append(Instruction::ISZERO); - auto end = m_asm.appendJumpI(); - m_asm.append(code[1].m_asm, 0); - m_asm.appendJump(begin); - m_asm << end.tag(); - } - else if (us == "FOR") - { - requireSize(4); - requireDeposit(1, 1); - - m_asm.append(code[0].m_asm, 0); - auto begin = m_asm.append(); - m_asm.append(code[1].m_asm); - 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); - m_asm.appendJump(begin); - m_asm << end.tag(); - } - else if (us == "ALLOC") - { - requireSize(1); - requireDeposit(0, 1); - - m_asm.append(Instruction::MSIZE); - m_asm.append(u256(0)); - m_asm.append(u256(1)); - m_asm.append(code[0].m_asm, 1); - m_asm.append(Instruction::MSIZE); - m_asm.append(Instruction::ADD); - m_asm.append(Instruction::SUB); - m_asm.append(Instruction::MSTORE8); - - _s.usedAlloc = true; - } - else if (us == "LLL") - { - requireMinSize(2); - requireMaxSize(3); - requireDeposit(1, 1); - - auto subPush = m_asm.appendSubSize(code[0].assembly(ns)); - m_asm.append(Instruction::DUP1); - if (code.size() == 3) - { - requireDeposit(2, 1); - m_asm.append(code[2].m_asm, 1); - m_asm.append(Instruction::LT); - m_asm.append(Instruction::ISZERO); - m_asm.append(Instruction::MUL); - m_asm.append(Instruction::DUP1); - } - m_asm.append(subPush); - m_asm.append(code[1].m_asm, 1); - m_asm.append(Instruction::CODECOPY); - } - else if (us == "&&" || us == "||") - { - requireMinSize(1); - for (unsigned i = 0; i < code.size(); ++i) - requireDeposit(i, 1); - - auto end = m_asm.newTag(); - if (code.size() > 1) - { - m_asm.append((u256)(us == "||" ? 1 : 0)); - for (unsigned i = 1; i < code.size(); ++i) - { - // Check if true - predicate - m_asm.append(code[i - 1].m_asm, 1); - if (us == "&&") - m_asm.append(Instruction::ISZERO); - m_asm.appendJumpI(end); - } - m_asm.append(Instruction::POP); - } - - // Check if true - predicate - m_asm.append(code.back().m_asm, 1); - - // At end now. - m_asm.append(end); - } - else if (us == "~") - { - requireSize(1); - requireDeposit(0, 1); - - m_asm.append(code[0].m_asm, 1); - m_asm.append((u256)1); - m_asm.append((u256)0); - m_asm.append(Instruction::SUB); - m_asm.append(Instruction::SUB); - } - else if (us == "SEQ") - { - unsigned ii = 0; - for (auto const& i: code) - if (++ii < code.size()) - m_asm.append(i.m_asm, 0); - else - m_asm.append(i.m_asm); - } - else if (us == "RAW") - { - for (auto const& i: code) - m_asm.append(i.m_asm); - m_asm.popTo(1); - } - else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) - m_asm.append((u256)varAddress(s)); - else - error(); - } -} - -CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s) -{ - CodeFragment ret; - sp::utree o; - parseTreeLLL(_src, o); - if (!o.empty()) - ret = CodeFragment(o, _s); - _s.treesToKill.push_back(o); - return ret; -} diff --git a/CodeFragment.h b/CodeFragment.h deleted file mode 100644 index 554f90b46..000000000 --- a/CodeFragment.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file CodeFragment.h - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include -#include -#include -#include "Exceptions.h" - -namespace boost { namespace spirit { class utree; } } -namespace sp = boost::spirit; - -namespace dev -{ -namespace eth -{ - -struct CompilerState; - -class CodeFragment -{ -public: - CodeFragment() {} - CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM = false); - - static CodeFragment compile(std::string const& _src, CompilerState& _s); - - /// Consolidates data and compiles code. - Assembly& assembly(CompilerState const& _cs) { finalise(_cs); return m_asm; } - -private: - void finalise(CompilerState const& _cs); - - template void error() const { BOOST_THROW_EXCEPTION(T() ); } - void constructOperation(sp::utree const& _t, CompilerState& _s); - - bool m_finalised = false; - Assembly m_asm; -}; - -static const CodeFragment NullCodeFragment; - -} -} - diff --git a/Compiler.cpp b/Compiler.cpp deleted file mode 100644 index 37fb3c340..000000000 --- a/Compiler.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Compiler.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "Compiler.h" -#include "Parser.h" -#include "CompilerState.h" -#include "CodeFragment.h" - -using namespace std; -using namespace dev; -using namespace dev::eth; - -bytes dev::eth::compileLLL(string const& _src, bool _opt, vector* _errors) -{ - try - { - CompilerState cs; - cs.populateStandard(); - auto f = CodeFragment::compile(_src, cs); - bytes ret = f.assembly(cs).optimise(_opt).assemble(); - for (auto i: cs.treesToKill) - killBigints(i); - return ret; - } - catch (Exception const& _e) - { - if (_errors) - { - _errors->push_back("Parse error."); - _errors->push_back(diagnostic_information(_e)); - } - } - catch (std::exception) - { - if (_errors) - _errors->push_back("Parse error."); - } - return bytes(); -} - -std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector* _errors) -{ - try - { - CompilerState cs; - cs.populateStandard(); - string ret = CodeFragment::compile(_src, cs).assembly(cs).optimise(_opt).out(); - for (auto i: cs.treesToKill) - killBigints(i); - return ret; - } - catch (Exception const& _e) - { - if (_errors) - _errors->push_back(diagnostic_information(_e)); - } - catch (std::exception) - { - if (_errors) - _errors->push_back("Parse error."); - } - return string(); -} - -string dev::eth::parseLLL(string const& _src) -{ - sp::utree o; - try - { - parseTreeLLL(_src, o); - } - catch (...) {} - ostringstream ret; - debugOutAST(ret, o); - killBigints(o); - return ret.str(); -} diff --git a/Compiler.h b/Compiler.h deleted file mode 100644 index 0fadd2785..000000000 --- a/Compiler.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Compiler.h - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include -#include -#include - -namespace dev -{ -namespace eth -{ - -std::string parseLLL(std::string const& _src); -std::string compileLLLToAsm(std::string const& _src, bool _opt = true, std::vector* _errors = nullptr); -bytes compileLLL(std::string const& _src, bool _opt = true, std::vector* _errors = nullptr); - -} -} diff --git a/CompilerState.cpp b/CompilerState.cpp deleted file mode 100644 index 63351bc4c..000000000 --- a/CompilerState.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file CompilerState.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "CompilerState.h" -#include "CodeFragment.h" - -using namespace std; -using namespace dev; -using namespace dev::eth; - -CompilerState::CompilerState() -{ -} - -CodeFragment const& CompilerState::getDef(std::string const& _s) -{ - if (defs.count(_s)) - return defs.at(_s); - else if (args.count(_s)) - return args.at(_s); - else if (outers.count(_s)) - return outers.at(_s); - else - return NullCodeFragment; -} - -void CompilerState::populateStandard() -{ - static const string s = "{" - "(def 'gav 0x51ba59315b3a95761d0863b05ccc7a7f54703d99)" - "(def 'config 0x661005d2720d855f1d9976f88bb10c1a3398c77f)" - "(def 'allgas (- (gas) 21))" - "(def 'send (to value) (call allgas to value 0 0 0 0))" - "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" - "(def 'msg (gaslimit to value data datasize outsize) { (set x outsize) (set y (alloc @32)) (call gaslimit to value data datasize @0 @32) @0 })" - "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" - "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" - "(def 'msg (to value data) { [0]:data (msg allgas to value 0 32) })" - "(def 'msg (to data) { [0]:data (msg allgas to 0 0 32) })" - "(def 'create (value code) { [0]:(msize) (create value @0 (lll code @0)) })" - "(def 'create (code) { [0]:(msize) (create 0 @0 (lll code @0)) })" - "(def 'sha3 (val) { [0]:val (sha3 0 32) })" - "(def 'sha3pair (a b) { [0]:a [32]:b (sha3 0 64) })" - "(def 'sha3trip (a b c) { [0]:a [32]:b [64]:c (sha3 0 96) })" - "(def 'return (val) { [0]:val (return 0 32) })" - "(def 'returnlll (code) (return 0 (lll code 0)) )" - "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" - "(def 'permcount 0)" - "(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )" - "(def 'namereg (msg config 0))" - "(def 'coinreg (msg config 1))" - "(def 'gavcoin (msg config 2))" - "(def 'sendgavcoin (to value) { [32]'send [64]:to [96]:value (call allgas gavcoin 0 32 96 0 0) })" - "(def 'regname (name) { [32]'register [64]name (call allgas namereg 0 32 64 0 0) })" - "(def 'regcoin (name) { [32]name (call allgas coinreg 0 32 32 0 0) })" - "(def 'regcoin (name denom) { [32]name [64]denom (call allgas coinreg 0 32 64 0 0) })" - "(def 'ecrecover (r s v hash) { [0] r [32] s [64] v [96] hash (msg allgas 1 0 0 128) })" - "(def 'sha256 (data datasize) (msg allgas 2 0 data datasize))" - "(def 'ripemd160 (data datasize) (msg allgas 3 0 data datasize))" - "(def 'sha256 (val) { [0]:val (sha256 0 32) })" - "(def 'ripemd160 (val) { [0]:val (ripemd160 0 32) })" - "}"; - CodeFragment::compile(s, *this); -} diff --git a/CompilerState.h b/CompilerState.h deleted file mode 100644 index bfe56f927..000000000 --- a/CompilerState.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file CompilerState.h - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include -#include "CodeFragment.h" - -namespace dev -{ -namespace eth -{ - -struct Macro -{ - std::vector args; - boost::spirit::utree code; - std::map env; -}; - -struct CompilerState -{ - CompilerState(); - - CodeFragment const& getDef(std::string const& _s); - void populateStandard(); - - unsigned stackSize = 128; - std::map> vars; ///< maps name to stack offset & size. - std::map defs; - std::map args; - std::map outers; - std::map, Macro> macros; - std::vector treesToKill; - bool usedAlloc = false; -}; - -} -} diff --git a/Exceptions.h b/Exceptions.h deleted file mode 100644 index 1e9671b36..000000000 --- a/Exceptions.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Exceptions.h - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include - -namespace dev -{ -namespace eth -{ - -/// Compile a Low-level Lisp-like Language program into EVM-code. -class CompilerException: public dev::Exception {}; -class InvalidOperation: public CompilerException {}; -class IntegerOutOfRange: public CompilerException {}; -class EmptyList: public CompilerException {}; -class DataNotExecutable: public CompilerException {}; -class IncorrectParameterCount: public CompilerException {}; -class InvalidName: public CompilerException {}; -class InvalidMacroArgs: public CompilerException {}; -class InvalidLiteral: public CompilerException {}; -class BareSymbol: public CompilerException {}; - -} -} diff --git a/Parser.cpp b/Parser.cpp deleted file mode 100644 index df30f3897..000000000 --- a/Parser.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Parser.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "Parser.h" - -#define BOOST_RESULT_OF_USE_DECLTYPE -#define BOOST_SPIRIT_USE_PHOENIX_V3 -#include -#include -#include - -using namespace std; -using namespace dev; -using namespace dev::eth; -namespace qi = boost::spirit::qi; -namespace px = boost::phoenix; -namespace sp = boost::spirit; - -void dev::eth::killBigints(sp::utree const& _this) -{ - switch (_this.which()) - { - case sp::utree_type::list_type: for (auto const& i: _this) killBigints(i); break; - case sp::utree_type::any_type: delete _this.get(); break; - default:; - } -} - -void dev::eth::debugOutAST(ostream& _out, sp::utree const& _this) -{ - switch (_this.which()) - { - case sp::utree_type::list_type: - switch (_this.tag()) - { - case 0: _out << "( "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << ")"; break; - case 1: _out << "@ "; debugOutAST(_out, _this.front()); break; - case 2: _out << "@@ "; debugOutAST(_out, _this.front()); break; - case 3: _out << "[ "; debugOutAST(_out, _this.front()); _out << " ] "; debugOutAST(_out, _this.back()); break; - case 4: _out << "[[ "; debugOutAST(_out, _this.front()); _out << " ]] "; debugOutAST(_out, _this.back()); break; - case 5: _out << "{ "; for (auto const& i: _this) { debugOutAST(_out, i); _out << " "; } _out << "}"; break; - case 6: _out << "$ "; debugOutAST(_out, _this.front()); break; - default:; - } - - break; - case sp::utree_type::int_type: _out << _this.get(); break; - case sp::utree_type::string_type: _out << "\"" << _this.get, sp::utree_type::string_type>>() << "\""; break; - case sp::utree_type::symbol_type: _out << _this.get, sp::utree_type::symbol_type>>(); break; - case sp::utree_type::any_type: _out << *_this.get(); break; - default: _out << "nil"; - } -} - -namespace dev { namespace eth { -namespace parseTreeLLL_ { - -template -struct tagNode -{ - void operator()(sp::utree& n, qi::rule::context_type& c) const - { - (boost::fusion::at_c<0>(c.attributes) = n).tag(N); - } -}; - -}}} - -void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out) -{ - using qi::standard::space; - using qi::standard::space_type; - using dev::eth::parseTreeLLL_::tagNode; - using symbol_type = sp::basic_string; - using it = string::const_iterator; - - static const u256 ether = u256(1000000000) * 1000000000; - static const u256 finney = u256(1000000000) * 1000000; - static const u256 szabo = u256(1000000000) * 1000; - - qi::rule element; - qi::rule str = '"' > qi::lexeme[+(~qi::char_(std::string("\"") + '\0'))] > '"'; - qi::rule strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))]; - qi::rule symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))]; - qi::rule intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]]; - qi::rule integer = intstr; - qi::rule multiplier = qi::lit("wei")[qi::_val = 1] | qi::lit("szabo")[qi::_val = szabo] | qi::lit("finney")[qi::_val = finney] | qi::lit("ether")[qi::_val = ether]; - qi::rule quantity = integer[qi::_val = qi::_1] >> -multiplier[qi::_val *= qi::_1]; - qi::rule atom = quantity[qi::_val = px::construct(px::new_(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1]; - qi::rule seq = '{' > *element > '}'; - qi::rule mload = '@' > element; - qi::rule sload = qi::lit("@@") > element; - qi::rule mstore = '[' > element > ']' > -qi::lit(":") > element; - qi::rule sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element; - qi::rule calldataload = qi::lit("$") > element; - qi::rule list = '(' > *element > ')'; - - qi::rule extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | seq[tagNode<5>()] | calldataload[tagNode<6>()]; - element = atom | list | extra; - - string s; - s.reserve(_s.size()); - bool incomment = false; - bool instring = false; - bool insstring = false; - for (auto i: _s) - { - if (i == ';' && !instring && !insstring) - incomment = true; - else if (i == '\n') - incomment = instring = insstring = false; - else if (i == '"' && !insstring) - instring = !instring; - else if (i == '\'') - insstring = true; - else if (i == ' ') - insstring = false; - if (!incomment) - s.push_back(i); - } - auto ret = s.cbegin(); - qi::phrase_parse(ret, s.cend(), element, space, qi::skip_flag::dont_postskip, o_out); - for (auto i = ret; i != s.cend(); ++i) - if (!isspace(*i)) - BOOST_THROW_EXCEPTION(std::exception()); -} - diff --git a/Parser.h b/Parser.h deleted file mode 100644 index b21989f06..000000000 --- a/Parser.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Parser.h - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include -#include -#include - -namespace boost { namespace spirit { class utree; } } -namespace sp = boost::spirit; - -namespace dev -{ -namespace eth -{ - -void killBigints(sp::utree const& _this); -void parseTreeLLL(std::string const& _s, sp::utree& o_out); -void debugOutAST(std::ostream& _out, sp::utree const& _this); - -} -} From 62ec556a9d2b308648b089cfbad810cbb50a16b9 Mon Sep 17 00:00:00 2001 From: jhuntley Date: Fri, 16 Jan 2015 16:37:20 -0500 Subject: [PATCH 80/92] Mingw cmake updates. Make sure Boost_INCLUDE_DIRS is included for each library using boost. When installing libraries, don't forget to copy DLLs, add target 'RUNTIME DESTINATION bin'. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b9dc6030..e60522a7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,6 @@ endif() target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) -install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) From d99247cb5dd34d49e23f09cd78a9618cfafab466 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 17 Apr 2015 16:15:25 +0200 Subject: [PATCH 81/92] reordered output Conflicts: libevmcore/Assembly.cpp --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e60522a7c..b865d4afe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) From ed096881b97222357ac636b41eb21e20225beaf1 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 22 Apr 2015 11:30:33 +0200 Subject: [PATCH 82/92] Use BUILD_SHARED_LIB --- CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b865d4afe..d3f465f37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,11 +19,7 @@ set(EXECUTABLE lll) file(GLOB HEADERS "*.h") -if(ETH_STATIC) - add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) -else() - add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) -endif() +add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) From 3ec162e910c34f049332d487d9f07674a42c40aa Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 24 Apr 2015 17:35:16 +0200 Subject: [PATCH 83/92] Move assembly related files to libevmasm and Params.h/.cpp to libevmcore. --- CMakeLists.txt | 3 +-- CodeFragment.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3f465f37..66f32e4d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,7 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} evmcore) -target_link_libraries(${EXECUTABLE} devcore) +target_link_libraries(${EXECUTABLE} evmasm) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/CodeFragment.h b/CodeFragment.h index 554f90b46..03f812b60 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include "Exceptions.h" namespace boost { namespace spirit { class utree; } } From e3597bf21368af07225d7d427105f72b3b19b364 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 16 Jun 2015 14:58:03 +0200 Subject: [PATCH 84/92] Some changes in libdevcore. --- CodeFragment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index 1e7766434..b50e316d3 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -196,7 +196,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { if (_t.size() != 2) error(); - m_asm.append(CodeFragment::compile(asString(contents(firstAsString())), _s).m_asm); + m_asm.append(CodeFragment::compile(contentsString(firstAsString()), _s).m_asm); } else if (us == "SET") { From d512c8639cd8cd0e8781bf3bda7a0a1ef4fac5bf Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 5 Aug 2015 11:35:05 +0200 Subject: [PATCH 85/92] fixed cmake policy CMP0042, MACOSX RPATH --- CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66f32e4d8..21fc18f97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,4 @@ cmake_policy(SET CMP0015 NEW) -# this policy was introduced in cmake 3.0 -# remove if, once 3.0 will be used on unix -if (${CMAKE_MAJOR_VERSION} GREATER 2) - # old policy do not use MACOSX_RPATH - cmake_policy(SET CMP0042 OLD) -endif() set(CMAKE_AUTOMOC OFF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") From 876f54694aa2ec98eb17e2d0d96a59e55f0d0ad9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Aug 2015 17:57:22 +0200 Subject: [PATCH 86/92] Revert "fixed cmake policy CMP0042, MACOSX RPATH" --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21fc18f97..66f32e4d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,10 @@ cmake_policy(SET CMP0015 NEW) +# this policy was introduced in cmake 3.0 +# remove if, once 3.0 will be used on unix +if (${CMAKE_MAJOR_VERSION} GREATER 2) + # old policy do not use MACOSX_RPATH + cmake_policy(SET CMP0042 OLD) +endif() set(CMAKE_AUTOMOC OFF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") From cbe7593460312f364b3677ecff2d71ef901c4648 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 5 Aug 2015 23:48:19 +0200 Subject: [PATCH 87/92] now policy CMP0042 is set to OLD This reverts commit 61e99b1040b80685c70c57cfb23f92e898cd41fb. --- CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66f32e4d8..21fc18f97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,4 @@ cmake_policy(SET CMP0015 NEW) -# this policy was introduced in cmake 3.0 -# remove if, once 3.0 will be used on unix -if (${CMAKE_MAJOR_VERSION} GREATER 2) - # old policy do not use MACOSX_RPATH - cmake_policy(SET CMP0042 OLD) -endif() set(CMAKE_AUTOMOC OFF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") From 6945c2eb898da72e434378bfa983b2875e8d94a7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 6 Aug 2015 21:00:29 +0200 Subject: [PATCH 88/92] Warning fix. --- CodeFragment.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CodeFragment.cpp b/CodeFragment.cpp index b50e316d3..64680d5a4 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -22,7 +22,12 @@ #include "CodeFragment.h" #include +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" #include +#pragma warning(pop) +#pragma GCC diagnostic pop #include #include #include From f47ca4ad14dce9a1d7c576d410aca0750c171f11 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 27 Aug 2015 12:19:33 +0200 Subject: [PATCH 89/92] cmake refactor in progress --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21fc18f97..0b468d7a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +#include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) -include_directories(${Boost_INCLUDE_DIRS}) +#include_directories(${Boost_INCLUDE_DIRS}) set(EXECUTABLE lll) @@ -15,7 +15,8 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} evmasm) +eth_use(${EXECUTABLE} REQUIRED Eth::evmasm) +#target_link_libraries(${EXECUTABLE} evmasm) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) From f9447147466178e2ae5aa6507d91b8ff4b5d923f Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 10 Sep 2015 12:02:18 +0200 Subject: [PATCH 90/92] Transition from bytecode to more general linker objects. --- Compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Compiler.cpp b/Compiler.cpp index 37fb3c340..f15387894 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -35,7 +35,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector* _error CompilerState cs; cs.populateStandard(); auto f = CodeFragment::compile(_src, cs); - bytes ret = f.assembly(cs).optimise(_opt).assemble(); + bytes ret = f.assembly(cs).optimise(_opt).assemble().bytecode; for (auto i: cs.treesToKill) killBigints(i); return ret; From e95dd9203ac17a65bb5c08c57237717d29b7b158 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 21 Mar 2016 14:58:34 +0300 Subject: [PATCH 91/92] move liblll --- All.h => liblll/All.h | 0 CMakeLists.txt => liblll/CMakeLists.txt | 0 CodeFragment.cpp => liblll/CodeFragment.cpp | 0 CodeFragment.h => liblll/CodeFragment.h | 0 Compiler.cpp => liblll/Compiler.cpp | 0 Compiler.h => liblll/Compiler.h | 0 CompilerState.cpp => liblll/CompilerState.cpp | 0 CompilerState.h => liblll/CompilerState.h | 0 Exceptions.h => liblll/Exceptions.h | 0 Parser.cpp => liblll/Parser.cpp | 0 Parser.h => liblll/Parser.h | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename All.h => liblll/All.h (100%) rename CMakeLists.txt => liblll/CMakeLists.txt (100%) rename CodeFragment.cpp => liblll/CodeFragment.cpp (100%) rename CodeFragment.h => liblll/CodeFragment.h (100%) rename Compiler.cpp => liblll/Compiler.cpp (100%) rename Compiler.h => liblll/Compiler.h (100%) rename CompilerState.cpp => liblll/CompilerState.cpp (100%) rename CompilerState.h => liblll/CompilerState.h (100%) rename Exceptions.h => liblll/Exceptions.h (100%) rename Parser.cpp => liblll/Parser.cpp (100%) rename Parser.h => liblll/Parser.h (100%) diff --git a/All.h b/liblll/All.h similarity index 100% rename from All.h rename to liblll/All.h diff --git a/CMakeLists.txt b/liblll/CMakeLists.txt similarity index 100% rename from CMakeLists.txt rename to liblll/CMakeLists.txt diff --git a/CodeFragment.cpp b/liblll/CodeFragment.cpp similarity index 100% rename from CodeFragment.cpp rename to liblll/CodeFragment.cpp diff --git a/CodeFragment.h b/liblll/CodeFragment.h similarity index 100% rename from CodeFragment.h rename to liblll/CodeFragment.h diff --git a/Compiler.cpp b/liblll/Compiler.cpp similarity index 100% rename from Compiler.cpp rename to liblll/Compiler.cpp diff --git a/Compiler.h b/liblll/Compiler.h similarity index 100% rename from Compiler.h rename to liblll/Compiler.h diff --git a/CompilerState.cpp b/liblll/CompilerState.cpp similarity index 100% rename from CompilerState.cpp rename to liblll/CompilerState.cpp diff --git a/CompilerState.h b/liblll/CompilerState.h similarity index 100% rename from CompilerState.h rename to liblll/CompilerState.h diff --git a/Exceptions.h b/liblll/Exceptions.h similarity index 100% rename from Exceptions.h rename to liblll/Exceptions.h diff --git a/Parser.cpp b/liblll/Parser.cpp similarity index 100% rename from Parser.cpp rename to liblll/Parser.cpp diff --git a/Parser.h b/liblll/Parser.h similarity index 100% rename from Parser.h rename to liblll/Parser.h From 4675fad0db224477d9173bfee73e78036d681ff8 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 21 Mar 2016 21:36:01 +0300 Subject: [PATCH 92/92] liblllc --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a02b779e8..eb6cdee05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ configure_project(TESTS) add_subdirectory(libsolidity) add_subdirectory(solc) if (NOT EMSCRIPTEN) + add_subdirectory(liblll) add_subdirectory(test) endif()