From 11d34902bd7a33eca88324074bcb51a89c73a5ee Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Dec 2014 21:45:16 +0000 Subject: [PATCH 001/118] Fixed uncles allowed. --- evmjit | 2 +- libethereum/State.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evmjit b/evmjit index 1b490244b..66d5a2b5c 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 1b490244bf4864b96448d56a7cd20f3d5b0a0b9b +Subproject commit 66d5a2b5cdf1361dcf0205b191dd12be090ed224 diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e02b06bcd..f4114a148 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -563,7 +563,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) if (_bc) { BlockInfo uncleParent(_bc->block(uncle.parentHash)); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6) + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) BOOST_THROW_EXCEPTION(UncleTooOld()); uncle.verifyParent(uncleParent); } From 78cbce595d5711c85561fbcf1bf56995d7fd4bc1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 12:01:35 +0000 Subject: [PATCH 002/118] Possible fix for #660. --- libethcore/Exceptions.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index c6f35763e..9bafb04d8 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -26,7 +26,11 @@ using namespace std; using namespace dev; using namespace dev::eth; -#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str(); +#if _MSC_VER +#define thread_local __declspec( thread ) +#endif + +#define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } From 5ad8633c12995d1cf77af39775167c55ed888389 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 12:06:38 +0000 Subject: [PATCH 003/118] Add mergeMaster script. --- mergeMaster.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 mergeMaster.sh diff --git a/mergeMaster.sh b/mergeMaster.sh new file mode 100755 index 000000000..a55502799 --- /dev/null +++ b/mergeMaster.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +git checkout master && git merge --no-ff $1+ && git push && git tag -f $1 && git push --tags -f + From 7775503c168bf9ac2f76e9133a3ce45398004b93 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 12:20:07 +0000 Subject: [PATCH 004/118] Warnings fixes. --- libdevcrypto/CryptoPP.cpp | 3 +++ libsolidity/SourceReferenceFormatter.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 766ca485d..225f36dec 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -198,6 +198,9 @@ bool Secp256k1::verifySecret(Secret const& _s, Public& _p) void Secp256k1::agree(Secret const& _s, Public const& _r, h256& o_s) { + (void)_s; + (void)_r; + (void)o_s; ECDH::Domain d(m_oid); assert(d.AgreedValueLength() == sizeof(o_s)); byte remote[65] = {0x04}; diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/SourceReferenceFormatter.h index 8e3f126f0..98f1c745d 100644 --- a/libsolidity/SourceReferenceFormatter.h +++ b/libsolidity/SourceReferenceFormatter.h @@ -28,7 +28,7 @@ namespace dev { -class Exception; // forward +struct Exception; // forward namespace solidity { From 92b76d49458fe654731d7162e05ff292cd9ea360 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 13 Jan 2015 13:36:21 +0100 Subject: [PATCH 005/118] new vps address --- extdep/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extdep/CMakeLists.txt b/extdep/CMakeLists.txt index 19cd00f7b..fdee34602 100644 --- a/extdep/CMakeLists.txt +++ b/extdep/CMakeLists.txt @@ -7,7 +7,7 @@ include(eth_download.cmake) # all dependencies will be installed into this directory, separated by platform string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name) set(ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/install/${_system_name}") -set(ETH_DEPENDENCY_SERVER "http://poc-7.ethdev.com/precompiled/${_system_name}") +set(ETH_DEPENDENCY_SERVER "http://build.ethdev.com/builds/${_system_name}-precompiled") file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/lib) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/include) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/bin) From ed775c31c75fce8d72c67d6f97fb6a37a36f11bb Mon Sep 17 00:00:00 2001 From: caktux Date: Mon, 19 Jan 2015 21:23:16 -0500 Subject: [PATCH 006/118] apply 565e3f1 and 8a3eac3 --- libdevcore/Exceptions.h | 2 +- libethcore/Exceptions.cpp | 11 +- neth/main.cpp | 272 +++++++++++++++++++++----------------- 3 files changed, 162 insertions(+), 123 deletions(-) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 5d03c195f..840fe3031 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -30,7 +30,7 @@ namespace dev { // base class for all exceptions -struct Exception: virtual std::exception, virtual boost::exception {}; +struct Exception: virtual std::exception, virtual boost::exception { mutable std::string m_message; }; struct BadHexCharacter: virtual Exception {}; struct RLPException: virtual Exception {}; diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index 9bafb04d8..7dfc28334 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -26,11 +26,14 @@ using namespace std; using namespace dev; using namespace dev::eth; -#if _MSC_VER -#define thread_local __declspec( thread ) -#endif - +#if ALL_COMPILERS_ARE_CPP11 #define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); +#elsif USE_BOOST_TLS +static boost::thread_specific_ptr g_exceptionMessage; +#define ETH_RETURN_STRING(S) if (!g_exceptionMessage.get()); g_exceptionMessage.reset(new string); *g_exceptionMessage.get() = S; return g_exceptionMessage.get()->c_str(); +#else +#define ETH_RETURN_STRING(S) m_message = S; return m_message.c_str(); +#endif const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } diff --git a/neth/main.cpp b/neth/main.cpp index 8552177ce..06be53393 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -63,54 +64,54 @@ void help() { cout << "Usage neth [OPTIONS] " << endl - << "Options:" << endl - << " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl - << " -c,--client-name Add a name to your client's version string (default: blank)." << endl - << " -d,--db-path Load database from path (default: ~/.ethereum " << endl - << " /Etherum or Library/Application Support/Ethereum)." << endl - << " -h,--help Show this help message and exit." << endl + << "Options:" << endl + << " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl + << " -c,--client-name Add a name to your client's version string (default: blank)." << endl + << " -d,--db-path Load database from path (default: ~/.ethereum " << endl + << " /Etherum or Library/Application Support/Ethereum)." << endl + << " -h,--help Show this help message and exit." << endl #if ETH_JSONRPC - << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl - << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl + << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl + << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl #endif - << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl - << " -m,--mining Enable mining (default: off)" << endl - << " -n,--upnp Use upnp for NAT (default: on)." << endl - << " -o,--mode Start a full node or a peer node (Default: full)." << endl - << " -p,--port Connect to remote port (default: 30303)." << endl - << " -r,--remote Connect to remote host (default: none)." << endl - << " -s,--secret Set the secret key for use with send command (default: auto)." << endl - << " -u,--public-ip Force public ip to given (default; auto)." << endl - << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl - << " -x,--peers Attempt to connect to given number of peers (default: 5)." << endl - << " -V,--version Show the version and exit." << endl; - exit(0); + << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl + << " -m,--mining Enable mining (default: off)" << endl + << " -n,--upnp Use upnp for NAT (default: on)." << endl + << " -o,--mode Start a full node or a peer node (Default: full)." << endl + << " -p,--port Connect to remote port (default: 30303)." << endl + << " -r,--remote Connect to remote host (default: none)." << endl + << " -s,--secret Set the secret key for use with send command (default: auto)." << endl + << " -u,--public-ip Force public ip to given (default; auto)." << endl + << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl + << " -x,--peers Attempt to connect to given number of peers (default: 5)." << endl + << " -V,--version Show the version and exit." << endl; + exit(0); } void interactiveHelp() { cout - << "Commands:" << endl - << " netstart Starts the network sybsystem on a specific port." << endl - << " netstop Stops the network subsystem." << endl + << "Commands:" << endl + << " netstart Starts the network sybsystem on a specific port." << endl + << " netstop Stops the network subsystem." << endl #if ETH_JSONRPC - << " jsonstart Starts the JSON-RPC server." << endl - << " jsonstop Stops the JSON-RPC server." << endl + << " jsonstart Starts the JSON-RPC server." << endl + << " jsonstop Stops the JSON-RPC server." << endl #endif - << " connect Connects to a specific peer." << endl - << " minestart Starts mining." << endl - << " minestop Stops mining." << endl - << " address Gives the current address." << endl - << " secret Gives the current secret" << endl - << " block Gives the current block height." << endl - << " balance Gives the current balance." << endl - << " peers List the peers that are connected" << endl - << " transact Execute a given transaction." << endl - << " send Execute a given transaction with current secret." << endl - << " contract Create a new contract with current secret." << endl - << " inspect Dumps a contract to /.evm." << endl - << " reset Resets ncurses windows" << endl - << " exit Exits the application." << endl; + << " connect Connects to a specific peer." << endl + << " minestart Starts mining." << endl + << " minestop Stops mining." << endl + << " address Gives the current address." << endl + << " secret Gives the current secret" << endl + << " block Gives the current block height." << endl + << " balance Gives the current balance." << endl + << " peers List the peers that are connected" << endl + << " transact Execute a given transaction." << endl + << " send Execute a given transaction with current secret." << endl + << " contract Create a new contract with current secret." << endl + << " inspect Dumps a contract to /.evm." << endl + << " reset Resets ncurses windows" << endl + << " exit Exits the application." << endl; } string credits() @@ -121,17 +122,8 @@ string credits() << " Code by Gav Wood & , (c) 2013, 2014." << endl << " Based on a design by Vitalik Buterin." << endl << endl; - string vs = toString(dev::Version); - vs = vs.substr(vs.find_first_of('.') + 1)[0]; - int pocnumber = stoi(vs); - string m_servers; - if (pocnumber == 5) - m_servers = "54.72.69.180"; - else - m_servers = "54.76.56.74"; - ccout << "Type 'netstart 30303' to start networking" << endl; - ccout << "Type 'connect " << m_servers << " 30303' to connect" << endl; + ccout << "Type 'connect " << Host::pocHost() << " 30303' to connect" << endl; ccout << "Type 'exit' to quit" << endl << endl; return ccout.str(); } @@ -139,12 +131,13 @@ string credits() void version() { cout << "neth version " << dev::Version << endl; + cout << "Network protocol version: " << dev::eth::c_protocolVersion << endl; + cout << "Client database version: " << dev::eth::c_databaseVersion << endl; cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; exit(0); } Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); - string pretty(h160 _a, dev::eth::State _st) { string ns; @@ -161,6 +154,13 @@ string pretty(h160 _a, dev::eth::State _st) return ns; } +bool g_exit = false; + +void sighandler(int) +{ + g_exit = true; +} + namespace nc { @@ -298,13 +298,17 @@ int main(int argc, char** argv) string remoteHost; unsigned short remotePort = 30303; string dbPath; - bool mining = false; + unsigned mining = ~(unsigned)0; + NodeMode mode = NodeMode::Full; unsigned peers = 5; #if ETH_JSONRPC int jsonrpc = 8080; #endif string publicIP; + bool bootstrap = false; bool upnp = true; + bool useLocal = false; + bool forceMining = false; string clientName; // Init defaults @@ -365,14 +369,21 @@ int main(int argc, char** argv) { string m = argv[++i]; if (isTrue(m)) - mining = true; + mining = ~(unsigned)0; else if (isFalse(m)) - mining = false; + mining = 0; + else if (int i = stoi(m)) + mining = i; else { - cerr << "Unknown mining option: " << m << endl; + cerr << "Unknown -m/--mining option: " << m << endl; + return -1; } } + else if (arg == "-b" || arg == "--bootstrap") + bootstrap = true; + else if (arg == "-f" || arg == "--force-mining") + forceMining = true; #if ETH_JSONRPC else if ((arg == "-j" || arg == "--json-rpc")) jsonrpc = jsonrpc ? jsonrpc : 8080; @@ -394,12 +405,50 @@ int main(int argc, char** argv) if (!clientName.empty()) clientName += "/"; - WebThreeDirect web3("NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), dbPath); - Client& c = *web3.ethereum(); + cout << credits(); + + NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); + dev::WebThreeDirect web3( + "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), + dbPath, + false, + mode == NodeMode::Full ? set{"eth", "shh"} : set(), + netPrefs + ); + web3.setIdealPeerCount(peers); + eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr; + + if (c) + { + c->setForceMining(forceMining); + c->setAddress(coinbase); + } - c.setForceMining(true); + auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp"); + web3.restoreNodes(&nodesState); - cout << credits(); + web3.startNetwork(); + + if (bootstrap) + web3.connect(Host::pocHost()); + if (remoteHost.size()) + web3.connect(remoteHost, remotePort); + +#if ETH_JSONRPC + shared_ptr jsonrpcServer; + unique_ptr jsonrpcConnector; + if (jsonrpc > -1) + { + jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc)); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); + jsonrpcServer->setIdentities({us}); + jsonrpcServer->StartListening(); + } +#endif + + signal(SIGABRT, &sighandler); + signal(SIGTERM, &sighandler); + signal(SIGINT, &sighandler); std::ostringstream ccout; @@ -461,28 +510,6 @@ int main(int argc, char** argv) wmove(mainwin, 1, 4); - if (!remoteHost.empty()) - { - web3.setIdealPeerCount(peers); - web3.setNetworkPreferences(NetworkPreferences(listenPort, publicIP, upnp)); - web3.startNetwork(); - web3.connect(remoteHost, remotePort); - } - if (mining) - c.startMining(); - -#if ETH_JSONRPC - shared_ptr jsonrpcServer; - unique_ptr jsonrpcConnector; - if (jsonrpc > -1) - { - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); - jsonrpcServer->setIdentities({us}); - jsonrpcServer->StartListening(); - } -#endif - while (true) { wclrtobot(consolewin); @@ -532,13 +559,25 @@ int main(int argc, char** argv) { web3.stopNetwork(); } - else if (cmd == "minestart") + else if (c && cmd == "minestart") + { + c->startMining(); + } + else if (c && cmd == "minestop") { - c.startMining(); + c->stopMining(); } - else if (cmd == "minestop") + else if (c && cmd == "mineforce") { - c.stopMining(); + string enable; + iss >> enable; + c->setForceMining(isTrue(enable)); + } + else if (cmd == "verbosity") + { + if (iss.peek() != -1) + iss >> g_logVerbosity; + cout << "Verbosity: " << g_logVerbosity << endl; } #if ETH_JSONRPC else if (cmd == "jsonport") @@ -575,7 +614,7 @@ int main(int argc, char** argv) } else if (cmd == "block") { - unsigned n = c.blockChain().details().number; + unsigned n = c->blockChain().details().number; ccout << "Current block # "; ccout << toString(n) << endl; } @@ -588,13 +627,13 @@ int main(int argc, char** argv) } else if (cmd == "balance") { - u256 balance = c.balanceAt(us.address()); + u256 balance = c->balanceAt(us.address()); ccout << "Current balance:" << endl; ccout << toString(balance) << endl; } else if (cmd == "transact") { - auto const& bc = c.blockChain(); + auto const& bc = c->blockChain(); auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); @@ -663,7 +702,7 @@ int main(int argc, char** argv) { Secret secret = h256(fromHex(sechex)); Address dest = h160(fromHex(fields[0])); - c.transact(secret, amount, dest, data, gas, gasPrice); + c->transact(secret, amount, dest, data, gas, gasPrice); } } } @@ -696,19 +735,19 @@ int main(int argc, char** argv) } else { - auto const& bc = c.blockChain(); + auto const& bc = c->blockChain(); auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); u256 minGas = (u256)Client::txGas(bytes(), 0); Address dest = h160(fromHex(fields[0])); - c.transact(us.secret(), amount, dest, bytes(), minGas); + c->transact(us.secret(), amount, dest, bytes(), minGas); } } } else if (cmd == "contract") { - auto const& bc = c.blockChain(); + auto const& bc = c->blockChain(); auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); @@ -768,7 +807,7 @@ int main(int argc, char** argv) cwarn << "Minimum gas amount is" << minGas; else { - c.transact(us.secret(), endowment, init, gas); + c->transact(us.secret(), endowment, init, gas); } } } @@ -786,10 +825,10 @@ int main(int argc, char** argv) try { - auto storage = c.storageAt(address); + auto storage = c->storageAt(address); for (auto const& i: storage) s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl; - s << endl << disassemble(c.codeAt(address)) << endl; + s << endl << disassemble(c->codeAt(address)) << endl; string outFile = getDataDir() + "/" + rechex + ".evm"; ofstream ofs; @@ -824,7 +863,7 @@ int main(int argc, char** argv) // Lock to prevent corrupt block-chain errors - auto const& bc = c.blockChain(); + auto const& bc = c->blockChain(); ccout << "Genesis hash: " << bc.genesisHash() << endl; // Blocks @@ -838,11 +877,11 @@ int main(int argc, char** argv) auto b = bc.block(h); for (auto const& i: RLP(b)[1]) { - Transaction t(i[0].data()); + Transaction t(i.data()); auto s = t.receiveAddress() ? boost::format(" %1% %2%> %3%: %4% [%5%]") % toString(t.safeSender()) % - (c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % + (c->codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % toString(t.receiveAddress()) % toString(formatBalance(t.value())) % toString((unsigned)t.nonce()) : @@ -862,12 +901,12 @@ int main(int argc, char** argv) // Pending y = 1; - for (Transaction const& t: c.pending()) + for (Transaction const& t: c->pending()) { auto s = t.receiveAddress() ? boost::format("%1% %2%> %3%: %4% [%5%]") % toString(t.safeSender()) % - (c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % + (c->codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % toString(t.receiveAddress()) % toString(formatBalance(t.value())) % toString((unsigned)t.nonce()) : @@ -877,7 +916,7 @@ int main(int argc, char** argv) toString(formatBalance(t.value())) % toString((unsigned)t.nonce()); mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth); - if (y > height * 1 / 5 - 4) + if (y > height * 1 / 5 - 2) break; } @@ -885,27 +924,27 @@ int main(int argc, char** argv) // Contracts and addresses y = 1; int cc = 1; - auto acs = c.addresses(); + auto acs = c->addresses(); for (auto const& i: acs) - if (c.codeAt(i, 0).size()) + if (c->codeAt(i, 0).size()) { auto s = boost::format("%1%%2% : %3% [%4%]") % toString(i) % - pretty(i, c.postState()) % - toString(formatBalance(c.balanceAt(i))) % - toString((unsigned)c.countAt(i, 0)); + pretty(i, c->postState()) % + toString(formatBalance(c->balanceAt(i))) % + toString((unsigned)c->countAt(i, 0)); mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth); if (cc > qheight - 2) break; } for (auto const& i: acs) - if (c.codeAt(i, 0).empty()) + if (c->codeAt(i, 0).empty()) { auto s = boost::format("%1%%2% : %3% [%4%]") % toString(i) % - pretty(i, c.postState()) % - toString(formatBalance(c.balanceAt(i))) % - toString((unsigned)c.countAt(i, 0)); + pretty(i, c->postState()) % + toString(formatBalance(c->balanceAt(i))) % + toString((unsigned)c->countAt(i, 0)); mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4); if (y > height * 3 / 5 - 4) break; @@ -935,21 +974,18 @@ int main(int argc, char** argv) // Balance stringstream ssb; - u256 balance = c.balanceAt(us.address()); - Address coinsAddr = right160(c.stateAt(c_config, 1)); - Address gavCoin = right160(c.stateAt(coinsAddr, c.stateAt(coinsAddr, 1))); - u256 totalGavCoinBalance = c.stateAt(gavCoin, (u160)us.address()); - ssb << "Balance: " << formatBalance(balance) << " | " << totalGavCoinBalance << " GAV"; + u256 balance = c->balanceAt(us.address()); + ssb << "Balance: " << formatBalance(balance); mvwprintw(consolewin, 0, x, ssb.str().c_str()); // Block mvwprintw(blockswin, 0, x, "Block # "); - unsigned n = c.blockChain().details().number; + unsigned n = c->blockChain().details().number; mvwprintw(blockswin, 0, 10, toString(n).c_str()); // Pending string pc; - pc = "Pending: " + toString(c.pending().size()); + pc = "Pending: " + toString(c->pending().size()); mvwprintw(pendingwin, 0, x, pc.c_str()); // Contracts @@ -962,10 +998,10 @@ int main(int argc, char** argv) mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str()); // Mining flag - if (c.isMining()) + if (c->isMining()) { mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON"); - dev::eth::MineProgress p = c.miningProgress(); + dev::eth::MineProgress p = c->miningProgress(); auto speed = boost::format("%2% kH/s @ %1%s") % (p.ms / 1000) % (p.ms ? p.hashes / p.ms : 0); mvwprintw(consolewin, qheight - 2, width / 4 - speed.str().length() - 2, speed.str().c_str()); } From 3f6c914c5971f4e7d1bdcfd7b50d731cd55c3adc Mon Sep 17 00:00:00 2001 From: caktux Date: Mon, 19 Jan 2015 23:08:24 -0500 Subject: [PATCH 007/118] fix warning and #823 --- neth/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neth/main.cpp b/neth/main.cpp index 06be53393..96fc52de5 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -433,6 +433,8 @@ int main(int argc, char** argv) web3.connect(Host::pocHost()); if (remoteHost.size()) web3.connect(remoteHost, remotePort); + if (mining) + c->startMining(); #if ETH_JSONRPC shared_ptr jsonrpcServer; From 808b646de39c6774da3e254f0a28e1144a231db1 Mon Sep 17 00:00:00 2001 From: caktux Date: Thu, 22 Jan 2015 23:39:20 -0500 Subject: [PATCH 008/118] build status table by OS and branch --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index cfa223a56..7b9a78e6c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,11 @@ ## Ethereum C++ Client. -[![Build -Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build -Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop - By Gav Wood, 2014. -[![Build -+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build -+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop + | Linux | OSX | Windows +----------|---------|-----|-------- +develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) +master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) [![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) From 998b0f7043d4d712fa4cadd6f088363502f34c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 15:23:49 +0100 Subject: [PATCH 009/118] Create README.md --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..30ed2f489 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# The Ethereum EVM JIT + +EVM JIT is a library for just-in-time compilation of Ethereum EVM code. +It can be used to substitute classic interpreter-like EVM Virtual Machine in Ethereum client. + +## Build + +### Linux / Ubuntu + +1. Install llvm-3.5-dev package + 1. For Ubuntu 14.04 using LLVM deb packages source: http://llvm.org/apt + 2. For Ubuntu 14.10 using Ubuntu packages +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake .. && make` +3. Install library + 1. `sudo make install` + 2. `sudo ldconfig` + +### OSX + +1. Install llvm35 + 1. `brew install llvm35 --disable-shared --HEAD` +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake -DLLVM_DIR=/usr/local/lib/llvm-3.5/share/llvm/cmake .. && make` +3. Install library + 1. `make install` (with admin rights?) + +### Windows + +Ask me. + + From 8cb2a56764220439033c62875b69c5d657cb395e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 15:35:34 +0100 Subject: [PATCH 010/118] Create LICENSE.md --- LICENSE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..630157f98 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paweł Bylica + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 1b449d357e36c73bcde5394282c343a92ef5024c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 16:20:22 +0100 Subject: [PATCH 011/118] Fallback to interpreter VM in case of JIT requirements unmet --- libevmjit-cpp/JitVM.cpp | 28 ++++++++++++++++------------ libevmjit-cpp/JitVM.h | 4 +--- libevmjit/Common.h | 24 ++++++++++++++---------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 613b5031c..e3bb09099 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -1,6 +1,7 @@ #include "JitVM.h" #include +#include #include #include "Utils.h" @@ -9,22 +10,25 @@ namespace dev namespace eth { -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; - if (m_gas > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); // Do not accept requests with gas > 2^63 (int64 max) // TODO: Return "not accepted" exception to allow interpreted handle that - - if (_ext.gasPrice > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.number > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.timestamp > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); + auto rejected = false; + rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) + rejected |= _ext.gasPrice > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + if (rejected) + { + UNTESTED; + std::cerr << "Rejected\n"; + VMFactory::setKind(VMKind::Interpreter); + m_fallbackVM = VMFactory::create(m_gas); + VMFactory::setKind(VMKind::JIT); + return m_fallbackVM->go(_ext, _onOp, _step); + } m_data.gas = static_cast(m_gas); m_data.gasPrice = static_cast(_ext.gasPrice); diff --git a/libevmjit-cpp/JitVM.h b/libevmjit-cpp/JitVM.h index 90855127e..58caa3648 100644 --- a/libevmjit-cpp/JitVM.h +++ b/libevmjit-cpp/JitVM.h @@ -12,15 +12,13 @@ class JitVM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - enum Kind: bool { Interpreter, JIT }; - static std::unique_ptr create(Kind, u256 _gas = 0); - private: friend class VMFactory; explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} jit::RuntimeData m_data; jit::ExecutionEngine m_engine; + std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT }; diff --git a/libevmjit/Common.h b/libevmjit/Common.h index 7383b9f93..e485148fb 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -25,20 +25,24 @@ struct NoteChannel {}; // FIXME: Use some log library? enum class ReturnCode { - Stop = 0, - Return = 1, + // Success codes + Stop = 0, + Return = 1, Suicide = 2, - OutOfGas = -1, - BadJumpDestination = -2, - StackTooSmall = -3, - BadInstruction = -4, + // Standard error codes + OutOfGas = -1, + StackTooSmall = -2, + BadJumpDestination = -3, + BadInstruction = -4, + Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected - LLVMConfigError = -5, - LLVMCompileError = -6, - LLVMLinkError = -7, + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, - UnexpectedException = -8, + UnexpectedException = -111, }; /// Representation of 256-bit value binary compatible with LLVM i256 From de649202a096a63fc8927540b703fdb18231cc11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 16:20:22 +0100 Subject: [PATCH 012/118] Fallback to interpreter VM in case of JIT requirements unmet --- evmjit/libevmjit-cpp/JitVM.cpp | 28 ++++++++++++++++------------ evmjit/libevmjit-cpp/JitVM.h | 4 +--- evmjit/libevmjit/Common.h | 24 ++++++++++++++---------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 613b5031c..e3bb09099 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -1,6 +1,7 @@ #include "JitVM.h" #include +#include #include #include "Utils.h" @@ -9,22 +10,25 @@ namespace dev namespace eth { -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; - if (m_gas > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); // Do not accept requests with gas > 2^63 (int64 max) // TODO: Return "not accepted" exception to allow interpreted handle that - - if (_ext.gasPrice > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.number > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.timestamp > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); + auto rejected = false; + rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) + rejected |= _ext.gasPrice > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + if (rejected) + { + UNTESTED; + std::cerr << "Rejected\n"; + VMFactory::setKind(VMKind::Interpreter); + m_fallbackVM = VMFactory::create(m_gas); + VMFactory::setKind(VMKind::JIT); + return m_fallbackVM->go(_ext, _onOp, _step); + } m_data.gas = static_cast(m_gas); m_data.gasPrice = static_cast(_ext.gasPrice); diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index 90855127e..58caa3648 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -12,15 +12,13 @@ class JitVM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - enum Kind: bool { Interpreter, JIT }; - static std::unique_ptr create(Kind, u256 _gas = 0); - private: friend class VMFactory; explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} jit::RuntimeData m_data; jit::ExecutionEngine m_engine; + std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT }; diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index 7383b9f93..e485148fb 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -25,20 +25,24 @@ struct NoteChannel {}; // FIXME: Use some log library? enum class ReturnCode { - Stop = 0, - Return = 1, + // Success codes + Stop = 0, + Return = 1, Suicide = 2, - OutOfGas = -1, - BadJumpDestination = -2, - StackTooSmall = -3, - BadInstruction = -4, + // Standard error codes + OutOfGas = -1, + StackTooSmall = -2, + BadJumpDestination = -3, + BadInstruction = -4, + Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected - LLVMConfigError = -5, - LLVMCompileError = -6, - LLVMLinkError = -7, + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, - UnexpectedException = -8, + UnexpectedException = -111, }; /// Representation of 256-bit value binary compatible with LLVM i256 From 5e29eef349b39c9cf95ada5c22d1e31094480e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 17:34:31 +0100 Subject: [PATCH 013/118] Replacing code references (usually vector&) with code_iterator pair. Code is now extracted from RuntimeData what removes copy in C interface. --- libevmjit-cpp/JitVM.cpp | 2 +- libevmjit/BasicBlock.cpp | 2 +- libevmjit/BasicBlock.h | 10 +++++----- libevmjit/Common.h | 1 + libevmjit/Compiler.cpp | 27 ++++++++++++++------------- libevmjit/Compiler.h | 8 +++++--- libevmjit/ExecutionEngine.cpp | 15 +++++++++------ libevmjit/ExecutionEngine.h | 2 +- libevmjit/Instruction.cpp | 4 ++-- libevmjit/Instruction.h | 4 ++-- libevmjit/interface.cpp | 11 +++++------ 11 files changed, 46 insertions(+), 40 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index e3bb09099..f92b114df 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -47,7 +47,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) m_data.codeSize = _ext.code.size(); auto env = reinterpret_cast(&_ext); - auto exitCode = m_engine.run(_ext.code, &m_data, env); + auto exitCode = m_engine.run(&m_data, env); switch (exitCode) { case ReturnCode::Suicide: diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 5868c0f43..c3668c61e 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -20,7 +20,7 @@ namespace jit const char* BasicBlock::NamePrefix = "Instr."; -BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : m_begin(_begin), m_end(_end), // TODO: Add begin index to name diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index cda4f89bd..26d6914d2 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -53,7 +53,7 @@ public: /// Basic block name prefix. The rest is instruction index. static const char* NamePrefix; - explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; @@ -61,8 +61,8 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - bytes::const_iterator begin() { return m_begin; } - bytes::const_iterator end() { return m_end; } + code_iterator begin() { return m_begin; } + code_iterator end() { return m_end; } bool isJumpDest() const { return m_isJumpDest; } @@ -84,8 +84,8 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - bytes::const_iterator const m_begin; - bytes::const_iterator const m_end; + code_iterator const m_begin = {}; + code_iterator const m_end = {}; llvm::BasicBlock* const m_llvmBB; diff --git a/libevmjit/Common.h b/libevmjit/Common.h index e485148fb..9c9dfd8a2 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -20,6 +20,7 @@ namespace jit using byte = uint8_t; using bytes = std::vector; using bytes_ref = std::tuple; +using code_iterator = byte const*; struct NoteChannel {}; // FIXME: Use some log library? diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1ce63d8ec..b6c3f10c0 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -39,10 +39,10 @@ Compiler::Compiler(Options const& _options): Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytes const& _bytecode) +void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd) { /// Helper function that skips push data and finds next iterator (can be the end) - auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end) + auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end) { static const auto push1 = static_cast(Instruction::PUSH1); static const auto push32 = static_cast(Instruction::PUSH32); @@ -52,11 +52,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) return _curr + offset; }; - auto begin = _bytecode.begin(); + auto begin = _codeBegin; // begin of current block bool nextJumpDest = false; - for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) + for (auto curr = begin, next = begin; curr != _codeEnd; curr = next) { - next = skipPushDataAndGetNext(curr, _bytecode.end()); + next = skipPushDataAndGetNext(curr, _codeEnd); bool isEnd = false; switch (Instruction(*curr)) @@ -77,13 +77,13 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) break; } - assert(next <= _bytecode.end()); - if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) + assert(next <= _codeEnd); + if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) isEnd = true; if (isEnd) { - auto beginIdx = begin - _bytecode.begin(); + auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; @@ -124,7 +124,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock() return m_badJumpBlock->llvm(); } -std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) +std::unique_ptr Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) { auto compilationStartTime = std::chrono::high_resolution_clock::now(); auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); @@ -138,7 +138,8 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - createBasicBlocks(_bytecode); + m_codeBegin = _begin; + createBasicBlocks(_begin, _end); // Init runtime structures. RuntimeManager runtimeManager(m_builder); @@ -156,7 +157,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: @@ -223,7 +224,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str } -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager, Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) { if (!_nextBasicBlock) // this is the last block in the code @@ -622,7 +623,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::PC: { - auto value = Constant::get(it - _bytecode.begin()); + auto value = Constant::get(it - m_codeBegin); stack.push(value); break; } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 720a48cf9..3c9bb9c68 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -33,13 +33,13 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); + std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); private: - void createBasicBlocks(bytes const& _bytecode); + void createBasicBlocks(code_iterator _begin, code_iterator _end); - void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); llvm::BasicBlock* getJumpTableBlock(); @@ -76,6 +76,8 @@ private: /// Main program function llvm::Function* m_mainFunc = nullptr; + + code_iterator m_codeBegin = {}; }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index ee92a6ba9..e23a625e3 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -52,15 +52,15 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } -std::string codeHash(bytes const& _code) +std::string codeHash(code_iterator _begin, code_iterator _end) { uint32_t hash = 0; - for (auto b : _code) + std::for_each(_begin, _end, [&hash](decltype(*_begin) b) { hash += b; hash += (hash << 10); hash ^= (hash >> 6); - } + }); hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); @@ -69,13 +69,16 @@ std::string codeHash(bytes const& _code) } -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) +ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); - auto mainFuncName = codeHash(_code); + auto codeBegin = _data->code; + auto codeEnd = codeBegin + _data->codeSize; + assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? + auto mainFuncName = codeHash(codeBegin, codeEnd); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls @@ -89,7 +92,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en if (objectCache) module = Cache::getObject(mainFuncName); if (!module) - module = Compiler({}).compile(_code, mainFuncName); + module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); if (debugDumpModule) module->dump(); if (!ee) diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index e8d1e1c05..c95bbfb62 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -16,7 +16,7 @@ public: ExecutionEngine(ExecutionEngine const&) = delete; void operator=(ExecutionEngine) = delete; - EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + EXPORT ReturnCode run(RuntimeData* _data, Env* _env); /// Reference to returned data (RETURN opcode used) bytes_ref returnData; diff --git a/libevmjit/Instruction.cpp b/libevmjit/Instruction.cpp index fdc40d043..909121607 100644 --- a/libevmjit/Instruction.cpp +++ b/libevmjit/Instruction.cpp @@ -9,7 +9,7 @@ namespace eth namespace jit { -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); @@ -26,7 +26,7 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en return value; } -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +void skipPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 158490dee..6785213d6 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -161,11 +161,11 @@ enum class Instruction: uint8_t /// Reads PUSH data from pointed fragment of bytecode and constructs number out of it /// Reading out of bytecode means reading 0 /// @param _curr is updated and points the last real byte read -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end); /// Skips PUSH data in pointed fragment of bytecode. /// @param _curr is updated and points the last real byte skipped -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +void skipPushData(code_iterator& _curr, code_iterator _end); #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index 6b0992dd4..645f3d150 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -12,6 +12,7 @@ using namespace dev::eth::jit; EXPORT void* evmjit_create() noexcept { + // TODO: Make sure ExecutionEngine constructor does not throw return new(std::nothrow) ExecutionEngine; } @@ -22,14 +23,12 @@ EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept { + if (!_engine || !_data) + return static_cast(ReturnCode::UnexpectedException); + try { - auto codePtr = _data->code; - auto codeSize = _data->codeSize; - bytes bytecode; - bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - - auto returnCode = _engine->run(bytecode, _data, _env); + auto returnCode = _engine->run(_data, _env); return static_cast(returnCode); } catch(...) From 932ce6650ca47868f8a5266ab02981897808a5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 17:34:31 +0100 Subject: [PATCH 014/118] Replacing code references (usually vector&) with code_iterator pair. Code is now extracted from RuntimeData what removes copy in C interface. --- evmjit/libevmjit-cpp/JitVM.cpp | 2 +- evmjit/libevmjit/BasicBlock.cpp | 2 +- evmjit/libevmjit/BasicBlock.h | 10 +++++----- evmjit/libevmjit/Common.h | 1 + evmjit/libevmjit/Compiler.cpp | 27 ++++++++++++++------------- evmjit/libevmjit/Compiler.h | 8 +++++--- evmjit/libevmjit/ExecutionEngine.cpp | 15 +++++++++------ evmjit/libevmjit/ExecutionEngine.h | 2 +- evmjit/libevmjit/Instruction.cpp | 4 ++-- evmjit/libevmjit/Instruction.h | 4 ++-- evmjit/libevmjit/interface.cpp | 11 +++++------ 11 files changed, 46 insertions(+), 40 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index e3bb09099..f92b114df 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -47,7 +47,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) m_data.codeSize = _ext.code.size(); auto env = reinterpret_cast(&_ext); - auto exitCode = m_engine.run(_ext.code, &m_data, env); + auto exitCode = m_engine.run(&m_data, env); switch (exitCode) { case ReturnCode::Suicide: diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index 5868c0f43..c3668c61e 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -20,7 +20,7 @@ namespace jit const char* BasicBlock::NamePrefix = "Instr."; -BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : m_begin(_begin), m_end(_end), // TODO: Add begin index to name diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index cda4f89bd..26d6914d2 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -53,7 +53,7 @@ public: /// Basic block name prefix. The rest is instruction index. static const char* NamePrefix; - explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; @@ -61,8 +61,8 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - bytes::const_iterator begin() { return m_begin; } - bytes::const_iterator end() { return m_end; } + code_iterator begin() { return m_begin; } + code_iterator end() { return m_end; } bool isJumpDest() const { return m_isJumpDest; } @@ -84,8 +84,8 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - bytes::const_iterator const m_begin; - bytes::const_iterator const m_end; + code_iterator const m_begin = {}; + code_iterator const m_end = {}; llvm::BasicBlock* const m_llvmBB; diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index e485148fb..9c9dfd8a2 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -20,6 +20,7 @@ namespace jit using byte = uint8_t; using bytes = std::vector; using bytes_ref = std::tuple; +using code_iterator = byte const*; struct NoteChannel {}; // FIXME: Use some log library? diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 1ce63d8ec..b6c3f10c0 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -39,10 +39,10 @@ Compiler::Compiler(Options const& _options): Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytes const& _bytecode) +void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd) { /// Helper function that skips push data and finds next iterator (can be the end) - auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end) + auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end) { static const auto push1 = static_cast(Instruction::PUSH1); static const auto push32 = static_cast(Instruction::PUSH32); @@ -52,11 +52,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) return _curr + offset; }; - auto begin = _bytecode.begin(); + auto begin = _codeBegin; // begin of current block bool nextJumpDest = false; - for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) + for (auto curr = begin, next = begin; curr != _codeEnd; curr = next) { - next = skipPushDataAndGetNext(curr, _bytecode.end()); + next = skipPushDataAndGetNext(curr, _codeEnd); bool isEnd = false; switch (Instruction(*curr)) @@ -77,13 +77,13 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) break; } - assert(next <= _bytecode.end()); - if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) + assert(next <= _codeEnd); + if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) isEnd = true; if (isEnd) { - auto beginIdx = begin - _bytecode.begin(); + auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; @@ -124,7 +124,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock() return m_badJumpBlock->llvm(); } -std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) +std::unique_ptr Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) { auto compilationStartTime = std::chrono::high_resolution_clock::now(); auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); @@ -138,7 +138,8 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - createBasicBlocks(_bytecode); + m_codeBegin = _begin; + createBasicBlocks(_begin, _end); // Init runtime structures. RuntimeManager runtimeManager(m_builder); @@ -156,7 +157,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: @@ -223,7 +224,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str } -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager, Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) { if (!_nextBasicBlock) // this is the last block in the code @@ -622,7 +623,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::PC: { - auto value = Constant::get(it - _bytecode.begin()); + auto value = Constant::get(it - m_codeBegin); stack.push(value); break; } diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index 720a48cf9..3c9bb9c68 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -33,13 +33,13 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); + std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); private: - void createBasicBlocks(bytes const& _bytecode); + void createBasicBlocks(code_iterator _begin, code_iterator _end); - void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); llvm::BasicBlock* getJumpTableBlock(); @@ -76,6 +76,8 @@ private: /// Main program function llvm::Function* m_mainFunc = nullptr; + + code_iterator m_codeBegin = {}; }; } diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index ee92a6ba9..e23a625e3 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -52,15 +52,15 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } -std::string codeHash(bytes const& _code) +std::string codeHash(code_iterator _begin, code_iterator _end) { uint32_t hash = 0; - for (auto b : _code) + std::for_each(_begin, _end, [&hash](decltype(*_begin) b) { hash += b; hash += (hash << 10); hash ^= (hash >> 6); - } + }); hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); @@ -69,13 +69,16 @@ std::string codeHash(bytes const& _code) } -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) +ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); - auto mainFuncName = codeHash(_code); + auto codeBegin = _data->code; + auto codeEnd = codeBegin + _data->codeSize; + assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? + auto mainFuncName = codeHash(codeBegin, codeEnd); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls @@ -89,7 +92,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en if (objectCache) module = Cache::getObject(mainFuncName); if (!module) - module = Compiler({}).compile(_code, mainFuncName); + module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); if (debugDumpModule) module->dump(); if (!ee) diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index e8d1e1c05..c95bbfb62 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -16,7 +16,7 @@ public: ExecutionEngine(ExecutionEngine const&) = delete; void operator=(ExecutionEngine) = delete; - EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + EXPORT ReturnCode run(RuntimeData* _data, Env* _env); /// Reference to returned data (RETURN opcode used) bytes_ref returnData; diff --git a/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp index fdc40d043..909121607 100644 --- a/evmjit/libevmjit/Instruction.cpp +++ b/evmjit/libevmjit/Instruction.cpp @@ -9,7 +9,7 @@ namespace eth namespace jit { -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); @@ -26,7 +26,7 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en return value; } -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +void skipPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h index 158490dee..6785213d6 100644 --- a/evmjit/libevmjit/Instruction.h +++ b/evmjit/libevmjit/Instruction.h @@ -161,11 +161,11 @@ enum class Instruction: uint8_t /// Reads PUSH data from pointed fragment of bytecode and constructs number out of it /// Reading out of bytecode means reading 0 /// @param _curr is updated and points the last real byte read -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end); /// Skips PUSH data in pointed fragment of bytecode. /// @param _curr is updated and points the last real byte skipped -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +void skipPushData(code_iterator& _curr, code_iterator _end); #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ diff --git a/evmjit/libevmjit/interface.cpp b/evmjit/libevmjit/interface.cpp index 6b0992dd4..645f3d150 100644 --- a/evmjit/libevmjit/interface.cpp +++ b/evmjit/libevmjit/interface.cpp @@ -12,6 +12,7 @@ using namespace dev::eth::jit; EXPORT void* evmjit_create() noexcept { + // TODO: Make sure ExecutionEngine constructor does not throw return new(std::nothrow) ExecutionEngine; } @@ -22,14 +23,12 @@ EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept { + if (!_engine || !_data) + return static_cast(ReturnCode::UnexpectedException); + try { - auto codePtr = _data->code; - auto codeSize = _data->codeSize; - bytes bytecode; - bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - - auto returnCode = _engine->run(bytecode, _data, _env); + auto returnCode = _engine->run(_data, _env); return static_cast(returnCode); } catch(...) From 64532b6b0ab097e53331e48e6f1fb5335243724d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 18:02:55 +0100 Subject: [PATCH 015/118] Environment options for EVM JIT updated: - EVMJIT_CACHE=0 disables disk cache, default 1 - EVMJIT_DUMP=1 dumps LLVM module to error output, default 0 --- libevmjit/ExecutionEngine.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index e23a625e3..653e0d9d0 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,6 +1,7 @@ #include "ExecutionEngine.h" #include +#include // env options #include #include @@ -19,13 +20,6 @@ #include "Compiler.h" #include "Cache.h" -#if defined(NDEBUG) -#define DEBUG_ENV_OPTION(name) false -#else -#include -#define DEBUG_ENV_OPTION(name) (std::getenv(#name) != nullptr) -#endif - namespace dev { namespace eth @@ -67,13 +61,21 @@ std::string codeHash(code_iterator _begin, code_iterator _end) return std::to_string(hash); } +bool getEnvOption(char const* _name, bool _default) +{ + auto var = std::getenv(_name); + if (!var) + return _default; + return std::strtol(var, nullptr, 10) != 0; +} + } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); - static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); + static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); + static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; From c49f78ca4f73999ca828e73933acffdac144acde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 18:02:55 +0100 Subject: [PATCH 016/118] Environment options for EVM JIT updated: - EVMJIT_CACHE=0 disables disk cache, default 1 - EVMJIT_DUMP=1 dumps LLVM module to error output, default 0 --- evmjit/libevmjit/ExecutionEngine.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index e23a625e3..653e0d9d0 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -1,6 +1,7 @@ #include "ExecutionEngine.h" #include +#include // env options #include #include @@ -19,13 +20,6 @@ #include "Compiler.h" #include "Cache.h" -#if defined(NDEBUG) -#define DEBUG_ENV_OPTION(name) false -#else -#include -#define DEBUG_ENV_OPTION(name) (std::getenv(#name) != nullptr) -#endif - namespace dev { namespace eth @@ -67,13 +61,21 @@ std::string codeHash(code_iterator _begin, code_iterator _end) return std::to_string(hash); } +bool getEnvOption(char const* _name, bool _default) +{ + auto var = std::getenv(_name); + if (!var) + return _default; + return std::strtol(var, nullptr, 10) != 0; +} + } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); - static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); + static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); + static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; From c914c877e30de0c00b80f2513f589b9778621c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 19:36:41 +0100 Subject: [PATCH 017/118] Add code hash to RuntimeData. JIT is using it as an code identifier (do not need to invent any internal hashing) --- libevmjit-cpp/JitVM.cpp | 2 ++ libevmjit/ExecutionEngine.cpp | 27 +++++++++++++++------------ libevmjit/RuntimeData.h | 1 + 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index f92b114df..08113122b 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -2,6 +2,7 @@ #include "JitVM.h" #include #include +#include #include #include "Utils.h" @@ -45,6 +46,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) m_data.timestamp = static_cast(_ext.currentBlock.timestamp); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); + m_data.codeHash = eth2llvm(sha3(_ext.code)); auto env = reinterpret_cast(&_ext); auto exitCode = m_engine.run(&m_data, env); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 653e0d9d0..69cf28afd 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -20,6 +20,8 @@ #include "Compiler.h" #include "Cache.h" +#include + namespace dev { namespace eth @@ -46,19 +48,20 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } -std::string codeHash(code_iterator _begin, code_iterator _end) +std::string codeHash(i256 const& _hash) { - uint32_t hash = 0; - std::for_each(_begin, _end, [&hash](decltype(*_begin) b) + static const auto size = sizeof(_hash); + static const auto hexChars = "0123456789abcdef"; + std::string str; + str.resize(size * 2); + auto outIt = str.rbegin(); // reverse for BE + auto& arr = *(std::array*)&_hash; + for (auto b : arr) { - hash += b; - hash += (hash << 10); - hash ^= (hash >> 6); - }); - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return std::to_string(hash); + *(outIt++) = hexChars[b & 0xf]; + *(outIt++) = hexChars[b >> 4]; + } + return str; } bool getEnvOption(char const* _name, bool _default) @@ -80,7 +83,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? - auto mainFuncName = codeHash(codeBegin, codeEnd); + auto mainFuncName = codeHash(_data->codeHash); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index 58d68db8a..ff6e82fe8 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -50,6 +50,7 @@ struct RuntimeData int64_t timestamp = 0; byte const* code = nullptr; uint64_t codeSize = 0; + i256 codeHash; }; /// VM Environment (ExtVM) opaque type From b999cc28c41990ebcbf4602c146454656adfe6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 19:36:41 +0100 Subject: [PATCH 018/118] Add code hash to RuntimeData. JIT is using it as an code identifier (do not need to invent any internal hashing) --- evmjit/libevmjit-cpp/JitVM.cpp | 2 ++ evmjit/libevmjit/ExecutionEngine.cpp | 27 +++++++++++++++------------ evmjit/libevmjit/RuntimeData.h | 1 + 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index f92b114df..08113122b 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -2,6 +2,7 @@ #include "JitVM.h" #include #include +#include #include #include "Utils.h" @@ -45,6 +46,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) m_data.timestamp = static_cast(_ext.currentBlock.timestamp); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); + m_data.codeHash = eth2llvm(sha3(_ext.code)); auto env = reinterpret_cast(&_ext); auto exitCode = m_engine.run(&m_data, env); diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 653e0d9d0..69cf28afd 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -20,6 +20,8 @@ #include "Compiler.h" #include "Cache.h" +#include + namespace dev { namespace eth @@ -46,19 +48,20 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } -std::string codeHash(code_iterator _begin, code_iterator _end) +std::string codeHash(i256 const& _hash) { - uint32_t hash = 0; - std::for_each(_begin, _end, [&hash](decltype(*_begin) b) + static const auto size = sizeof(_hash); + static const auto hexChars = "0123456789abcdef"; + std::string str; + str.resize(size * 2); + auto outIt = str.rbegin(); // reverse for BE + auto& arr = *(std::array*)&_hash; + for (auto b : arr) { - hash += b; - hash += (hash << 10); - hash ^= (hash >> 6); - }); - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return std::to_string(hash); + *(outIt++) = hexChars[b & 0xf]; + *(outIt++) = hexChars[b >> 4]; + } + return str; } bool getEnvOption(char const* _name, bool _default) @@ -80,7 +83,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? - auto mainFuncName = codeHash(codeBegin, codeEnd); + auto mainFuncName = codeHash(_data->codeHash); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h index 58d68db8a..ff6e82fe8 100644 --- a/evmjit/libevmjit/RuntimeData.h +++ b/evmjit/libevmjit/RuntimeData.h @@ -50,6 +50,7 @@ struct RuntimeData int64_t timestamp = 0; byte const* code = nullptr; uint64_t codeSize = 0; + i256 codeHash; }; /// VM Environment (ExtVM) opaque type From bdba3104d6776ed4550eeae62aab2d68d4840cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 10:58:34 +0100 Subject: [PATCH 019/118] Improve versioning --- libevmjit/CMakeLists.txt | 47 ++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 545e55344..f062c65e6 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -11,19 +11,48 @@ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) endif() -find_package(Git) -if(GIT_FOUND) - execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always - OUTPUT_VARIABLE EVMJIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + +set(EVMJIT_VERSION "0.0.0") +set(EVMJIT_VERSION_MAJOR 0) +set(EVMJIT_VERSION_MINOR 0) +set(EVMJIT_VERSION_PATCH 0) +set(EVMJIT_VERSION_FULL "v0.0.0-nogit") + +find_package(Git) +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always --match v* + OUTPUT_VARIABLE EVMJIT_VERSION_FULL OUTPUT_STRIP_TRAILING_WHITESPACE) endif() -if(NOT EVMJIT_VERSION) - set(EVMJIT_VERSION "unknown") + +if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") + string(SUBSTRING ${EVMJIT_VERSION_FULL} 1 -1 EVMJIT_VERSION_FULL) # skip "v" + string(REPLACE "-" ";" VERSION_COMPONENTS ${EVMJIT_VERSION_FULL}) + list(LENGTH VERSION_COMPONENTS NUM_VERSION_COMPONENTS) + list(GET VERSION_COMPONENTS 0 EVMJIT_VERSION) + string(REPLACE "." ";" VERSION_NUMBERS ${EVMJIT_VERSION}) + list(LENGTH VERSION_NUMBERS NUM_VERSION_NUMBERS) + list(GET VERSION_NUMBERS 0 EVMJIT_VERSION_MAJOR) + list(GET VERSION_NUMBERS 1 EVMJIT_VERSION_MINOR) + if(${NUM_VERSION_NUMBERS} GREATER 2) + list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional + endif() + if(${NUM_VERSION_COMPONENTS} GREATER 0) + list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) + endif() +endif() + +if(${EVMJIT_VERSION_MAJOR} EQUAL 0) + set(EVMJIT_SOVERSION "0.${EVMJIT_VERSION_MINOR}") +else() + set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR}) endif() -message("EVM JIT version: ${EVMJIT_VERSION}") +message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH}-${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) -set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} FOLDER "libs") +set_target_properties(${TARGET_NAME} PROPERTIES + VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} + FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) @@ -32,4 +61,4 @@ target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) -#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) +#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) \ No newline at end of file From e8e9490b566563d0991ddf7f14cd2e0958ee5ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 11:20:56 +0100 Subject: [PATCH 020/118] Disable RTTI for evmjit library --- CMakeLists.txt | 6 +++--- libevmjit-cpp/CMakeLists.txt | 5 +++++ libevmjit/CMakeLists.txt | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a449f9a60..05a918ad0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,12 @@ project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra") endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") # Do not allow unresovled symbols in shared library (default on linux) set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") endif() diff --git a/libevmjit-cpp/CMakeLists.txt b/libevmjit-cpp/CMakeLists.txt index 58375e4ee..53448332b 100644 --- a/libevmjit-cpp/CMakeLists.txt +++ b/libevmjit-cpp/CMakeLists.txt @@ -9,6 +9,11 @@ set(SOURCES ) source_group("" FILES ${SOURCES}) +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive +endif() + add_library(${TARGET_NAME} ${SOURCES}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index f062c65e6..f88a5468b 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -6,9 +6,9 @@ set(INTERFACE_HEADERS interface.h) source_group("" FILES ${HEADERS}) source_group("" FILES ${SOURCES}) -if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # Disable rtti for Cache as LLVM has no rtti - set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") endif() From 27ca018c35c9c80b0dc593852989777c315e900f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 14:13:04 +0100 Subject: [PATCH 021/118] Add first instruction index to BasicBlock --- CMakeLists.txt | 1 + libevmjit/BasicBlock.cpp | 9 +++++---- libevmjit/BasicBlock.h | 17 ++++++++--------- libevmjit/Compiler.cpp | 5 ++--- libevmjit/Compiler.h | 2 -- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05a918ad0..ce05c422d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8.12) project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(CMAKE_AUTOMOC OFF) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index c3668c61e..d907aada1 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -18,13 +18,14 @@ namespace eth namespace jit { -const char* BasicBlock::NamePrefix = "Instr."; +static const char* jumpDestName = "JmpDst."; +static const char* basicBlockName = "Instr."; -BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : + m_firstInstrIdx{_firstInstrIdx}, m_begin(_begin), m_end(_end), - // TODO: Add begin index to name - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), m_stack(*this), m_builder(_builder), m_isJumpDest(isJumpDest) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 26d6914d2..1be742f9f 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -11,7 +11,7 @@ namespace eth namespace jit { -using ProgramCounter = uint64_t; // TODO: Rename +using instr_idx = uint64_t; class BasicBlock { @@ -50,10 +50,7 @@ public: BasicBlock& m_bblock; }; - /// Basic block name prefix. The rest is instruction index. - static const char* NamePrefix; - - explicit BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; @@ -61,8 +58,9 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - code_iterator begin() { return m_begin; } - code_iterator end() { return m_end; } + instr_idx firstInstrIdx() const { return m_firstInstrIdx; } + code_iterator begin() const { return m_begin; } + code_iterator end() const { return m_end; } bool isJumpDest() const { return m_isJumpDest; } @@ -84,8 +82,9 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - code_iterator const m_begin = {}; - code_iterator const m_end = {}; + instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block + code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block + code_iterator const m_end = {}; ///< Iterator pointing code end of the block llvm::BasicBlock* const m_llvmBB; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index b6c3f10c0..eddd16492 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -85,7 +85,7 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn { auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), - std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); + std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; begin = next; } @@ -138,7 +138,6 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - m_codeBegin = _begin; createBasicBlocks(_begin, _end); // Init runtime structures. @@ -623,7 +622,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::PC: { - auto value = Constant::get(it - m_codeBegin); + auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx()); stack.push(value); break; } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 3c9bb9c68..89b2f1a8e 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -76,8 +76,6 @@ private: /// Main program function llvm::Function* m_mainFunc = nullptr; - - code_iterator m_codeBegin = {}; }; } From 01dffe28f32756aca7e2be0389ff5552bf8c0105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 14:13:04 +0100 Subject: [PATCH 022/118] Add first instruction index to BasicBlock --- evmjit/CMakeLists.txt | 1 + evmjit/libevmjit/BasicBlock.cpp | 9 +++++---- evmjit/libevmjit/BasicBlock.h | 17 ++++++++--------- evmjit/libevmjit/Compiler.cpp | 5 ++--- evmjit/libevmjit/Compiler.h | 2 -- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index 05a918ad0..ce05c422d 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8.12) project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(CMAKE_AUTOMOC OFF) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index c3668c61e..d907aada1 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -18,13 +18,14 @@ namespace eth namespace jit { -const char* BasicBlock::NamePrefix = "Instr."; +static const char* jumpDestName = "JmpDst."; +static const char* basicBlockName = "Instr."; -BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : + m_firstInstrIdx{_firstInstrIdx}, m_begin(_begin), m_end(_end), - // TODO: Add begin index to name - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), m_stack(*this), m_builder(_builder), m_isJumpDest(isJumpDest) diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 26d6914d2..1be742f9f 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -11,7 +11,7 @@ namespace eth namespace jit { -using ProgramCounter = uint64_t; // TODO: Rename +using instr_idx = uint64_t; class BasicBlock { @@ -50,10 +50,7 @@ public: BasicBlock& m_bblock; }; - /// Basic block name prefix. The rest is instruction index. - static const char* NamePrefix; - - explicit BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; @@ -61,8 +58,9 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - code_iterator begin() { return m_begin; } - code_iterator end() { return m_end; } + instr_idx firstInstrIdx() const { return m_firstInstrIdx; } + code_iterator begin() const { return m_begin; } + code_iterator end() const { return m_end; } bool isJumpDest() const { return m_isJumpDest; } @@ -84,8 +82,9 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - code_iterator const m_begin = {}; - code_iterator const m_end = {}; + instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block + code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block + code_iterator const m_end = {}; ///< Iterator pointing code end of the block llvm::BasicBlock* const m_llvmBB; diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index b6c3f10c0..eddd16492 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -85,7 +85,7 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn { auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), - std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); + std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; begin = next; } @@ -138,7 +138,6 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - m_codeBegin = _begin; createBasicBlocks(_begin, _end); // Init runtime structures. @@ -623,7 +622,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::PC: { - auto value = Constant::get(it - m_codeBegin); + auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx()); stack.push(value); break; } diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index 3c9bb9c68..89b2f1a8e 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -76,8 +76,6 @@ private: /// Main program function llvm::Function* m_mainFunc = nullptr; - - code_iterator m_codeBegin = {}; }; } From 561028862681b3ccb73249305c93536198b00018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 14:30:25 +0100 Subject: [PATCH 023/118] Improve allocas order and namings --- libevmjit/Ext.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index a37a6fe99..965ef2e06 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -60,14 +60,16 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) llvm::Value* Ext::getArgAlloca() { - auto& a = m_argAllocas[m_argCounter++]; + auto& a = m_argAllocas[m_argCounter]; if (!a) { - // FIXME: Improve order and names InsertPointGuard g{getBuilder()}; - getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); - a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); + auto allocaIt = getMainFunction()->front().begin(); + std::advance(allocaIt, m_argCounter); // Skip already created allocas + getBuilder().SetInsertPoint(allocaIt); + a = getBuilder().CreateAlloca(Type::Word, nullptr, {"a.", std::to_string(m_argCounter)}); } + ++m_argCounter; return a; } From 019aa6dd638e68c3259aaebda297eb564ec8a1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 14:30:25 +0100 Subject: [PATCH 024/118] Improve allocas order and namings --- evmjit/libevmjit/Ext.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index a37a6fe99..965ef2e06 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -60,14 +60,16 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) llvm::Value* Ext::getArgAlloca() { - auto& a = m_argAllocas[m_argCounter++]; + auto& a = m_argAllocas[m_argCounter]; if (!a) { - // FIXME: Improve order and names InsertPointGuard g{getBuilder()}; - getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); - a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); + auto allocaIt = getMainFunction()->front().begin(); + std::advance(allocaIt, m_argCounter); // Skip already created allocas + getBuilder().SetInsertPoint(allocaIt); + a = getBuilder().CreateAlloca(Type::Word, nullptr, {"a.", std::to_string(m_argCounter)}); } + ++m_argCounter; return a; } From c633e62102ccb1bedbb5c79c341201627950c2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 14:31:53 +0100 Subject: [PATCH 025/118] Gas counting changes: allow memory words counter not greater than gas max (int64 max) --- libevmjit-cpp/JitVM.cpp | 1 + libevmjit/GasMeter.cpp | 11 +++++++++-- libevmjit/Type.cpp | 5 +++++ libevmjit/Type.h | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 08113122b..ab1a4cf2b 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -16,6 +16,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) using namespace jit; auto rejected = false; + // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 4aa6a738d..d54eea754 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -94,12 +94,13 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - m_builder.SetInsertPoint(checkBB); auto arg = m_gasCheckFunc->arg_begin(); arg->setName("rt"); ++arg; arg->setName("cost"); auto cost = arg; + + m_builder.SetInsertPoint(checkBB); auto gas = m_runtimeManager.getGas(); auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); @@ -208,8 +209,14 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { + assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - count(_additionalMemoryInWords); + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); + auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); + additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); + auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); + count(additionalMemoryInWords256); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 22ccea12e..169691904 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -17,6 +17,7 @@ llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Gas; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -24,6 +25,7 @@ llvm::IntegerType* Type::MainReturn; llvm::PointerType* Type::EnvPtr; llvm::PointerType* Type::RuntimeDataPtr; llvm::PointerType* Type::RuntimePtr; +llvm::ConstantInt* Constant::gasMax; void Type::init(llvm::LLVMContext& _context) { @@ -35,6 +37,7 @@ void Type::init(llvm::LLVMContext& _context) // TODO: Size should be architecture-dependent Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); + Gas = Size; Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); @@ -43,6 +46,8 @@ void Type::init(llvm::LLVMContext& _context) EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + + Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits::max()); } } diff --git a/libevmjit/Type.h b/libevmjit/Type.h index d4804ee59..cfac1e2c6 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -23,6 +23,7 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; + static llvm::IntegerType* Gas; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; @@ -41,6 +42,8 @@ struct Type struct Constant { + static llvm::ConstantInt* gasMax; + /// Returns word-size constant static llvm::ConstantInt* get(int64_t _n); static llvm::ConstantInt* get(llvm::APInt const& _n); From 3290856061b9478f084f02f10f08b35d04adb407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 14:31:53 +0100 Subject: [PATCH 026/118] Gas counting changes: allow memory words counter not greater than gas max (int64 max) --- evmjit/libevmjit-cpp/JitVM.cpp | 1 + evmjit/libevmjit/GasMeter.cpp | 11 +++++++++-- evmjit/libevmjit/Type.cpp | 5 +++++ evmjit/libevmjit/Type.h | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 08113122b..ab1a4cf2b 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -16,6 +16,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) using namespace jit; auto rejected = false; + // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 4aa6a738d..d54eea754 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -94,12 +94,13 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - m_builder.SetInsertPoint(checkBB); auto arg = m_gasCheckFunc->arg_begin(); arg->setName("rt"); ++arg; arg->setName("cost"); auto cost = arg; + + m_builder.SetInsertPoint(checkBB); auto gas = m_runtimeManager.getGas(); auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); @@ -208,8 +209,14 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { + assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - count(_additionalMemoryInWords); + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); + auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); + additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); + auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); + count(additionalMemoryInWords256); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 22ccea12e..169691904 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -17,6 +17,7 @@ llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Gas; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -24,6 +25,7 @@ llvm::IntegerType* Type::MainReturn; llvm::PointerType* Type::EnvPtr; llvm::PointerType* Type::RuntimeDataPtr; llvm::PointerType* Type::RuntimePtr; +llvm::ConstantInt* Constant::gasMax; void Type::init(llvm::LLVMContext& _context) { @@ -35,6 +37,7 @@ void Type::init(llvm::LLVMContext& _context) // TODO: Size should be architecture-dependent Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); + Gas = Size; Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); @@ -43,6 +46,8 @@ void Type::init(llvm::LLVMContext& _context) EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + + Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits::max()); } } diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index d4804ee59..cfac1e2c6 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -23,6 +23,7 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; + static llvm::IntegerType* Gas; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; @@ -41,6 +42,8 @@ struct Type struct Constant { + static llvm::ConstantInt* gasMax; + /// Returns word-size constant static llvm::ConstantInt* get(int64_t _n); static llvm::ConstantInt* get(llvm::APInt const& _n); From 407cae129f38abcdd1fbdfca366267cc59374c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:08:57 +0100 Subject: [PATCH 027/118] Count gas using int64 --- libevmjit/BasicBlock.cpp | 1 + libevmjit/Compiler.cpp | 3 +- libevmjit/Ext.cpp | 6 +- libevmjit/GasMeter.cpp | 103 ++++++++++++++++++----------------- libevmjit/GasMeter.h | 2 +- libevmjit/RuntimeManager.cpp | 10 ++-- 6 files changed, 66 insertions(+), 59 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index d907aada1..c71bae94f 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -44,6 +44,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : void BasicBlock::LocalStack::push(llvm::Value* _value) { + assert(_value->getType() == Type::Word); m_bblock.m_currentStack.push_back(_value); m_bblock.m_tosOffset += 1; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index eddd16492..b6206b8d8 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -630,7 +630,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::GAS: { _gasMeter.commitCostBlock(); - stack.push(_runtimeManager.getGas()); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); break; } @@ -770,6 +770,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti receiveAddress = _runtimeManager.get(RuntimeData::Address); _gasMeter.count(gas); + // TODO: pass gas to call as int64 auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); _gasMeter.giveBack(gas); stack.push(ret); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 965ef2e06..28e10366c 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -128,12 +128,14 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas = byPtr(_gas); + auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); + auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - _gas = m_builder.CreateLoad(gas); // Return gas + gas256 = m_builder.CreateLoad(gas); // Return gas + _gas = m_builder.CreateTrunc(gas256, Type::Gas); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index d54eea754..8ac575338 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -19,29 +19,29 @@ namespace jit namespace // Helper functions { -uint64_t const c_stepGas = 1; -uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 10; -uint64_t const c_sha3WordGas = 10; -uint64_t const c_sloadGas = 20; -uint64_t const c_sstoreSetGas = 300; -uint64_t const c_sstoreResetGas = 100; -uint64_t const c_sstoreRefundGas = 100; -uint64_t const c_createGas = 100; -uint64_t const c_createDataGas = 5; -uint64_t const c_callGas = 20; -uint64_t const c_expGas = 1; -uint64_t const c_expByteGas = 1; -uint64_t const c_memoryGas = 1; -uint64_t const c_txDataZeroGas = 1; -uint64_t const c_txDataNonZeroGas = 5; -uint64_t const c_txGas = 500; -uint64_t const c_logGas = 32; -uint64_t const c_logDataGas = 1; -uint64_t const c_logTopicGas = 32; -uint64_t const c_copyGas = 1; - -uint64_t getStepCost(Instruction inst) +int64_t const c_stepGas = 1; +int64_t const c_balanceGas = 20; +int64_t const c_sha3Gas = 10; +int64_t const c_sha3WordGas = 10; +int64_t const c_sloadGas = 20; +int64_t const c_sstoreSetGas = 300; +int64_t const c_sstoreResetGas = 100; +int64_t const c_sstoreRefundGas = 100; +int64_t const c_createGas = 100; +int64_t const c_createDataGas = 5; +int64_t const c_callGas = 20; +int64_t const c_expGas = 1; +int64_t const c_expByteGas = 1; +int64_t const c_memoryGas = 1; +int64_t const c_txDataZeroGas = 1; +int64_t const c_txDataNonZeroGas = 5; +int64_t const c_txGas = 500; +int64_t const c_logGas = 32; +int64_t const c_logDataGas = 1; +int64_t const c_logTopicGas = 32; +int64_t const c_copyGas = 1; + +int64_t getStepCost(Instruction inst) { switch (inst) { @@ -72,7 +72,7 @@ uint64_t getStepCost(Instruction inst) case Instruction::LOG3: case Instruction::LOG4: { - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } } @@ -86,7 +86,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas}; m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); @@ -94,15 +94,15 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - auto arg = m_gasCheckFunc->arg_begin(); - arg->setName("rt"); - ++arg; - arg->setName("cost"); - auto cost = arg; + auto rt = &m_gasCheckFunc->getArgumentList().front(); + rt->setName("rt"); + auto cost = rt->getNextNode(); + cost->setName("cost"); m_builder.SetInsertPoint(checkBB); auto gas = m_runtimeManager.getGas(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); + auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); @@ -110,7 +110,6 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); - gas = m_builder.CreateSub(gas, cost); m_runtimeManager.setGas(gas); m_builder.CreateRetVoid(); } @@ -120,7 +119,7 @@ void GasMeter::count(Instruction _inst) if (!m_checkCall) { // Create gas check call with mocked block cost at begining of current cost-block - m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); } m_blockCost += getStepCost(_inst); @@ -128,6 +127,15 @@ void GasMeter::count(Instruction _inst) void GasMeter::count(llvm::Value* _cost) { + if (_cost->getType() == Type::Word) + { + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh"); + auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas); + _cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost"); + } + + assert(_cost->getType() == Type::Gas); createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); } @@ -137,12 +145,13 @@ void GasMeter::countExp(llvm::Value* _exponent) // lz - leading zeros // cost = ((256 - lz) + 7) / 8 - // OPT: All calculations can be done on 32/64 bits + // OPT: Can gas update be done in exp algorithm? auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto sigBits = m_builder.CreateSub(Constant::get(256), lz); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); + auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); count(sigBytes); } @@ -155,8 +164,8 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); - auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); - cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); + auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost"); + cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost"); count(cost); } @@ -179,13 +188,13 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); - auto cost = getBuilder().CreateZExt(cost64, Type::Word); - count(cost); + count(cost64); } void GasMeter::giveBack(llvm::Value* _gas) { - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); + assert(_gas->getType() == Type::Word); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); } void GasMeter::commitCostBlock() @@ -200,7 +209,7 @@ void GasMeter::commitCostBlock() return; } - m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call + m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; } @@ -209,14 +218,8 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { - assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); - auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); - auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); - additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); - auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); - count(additionalMemoryInWords256); + count(_additionalMemoryInWords); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 56da6eb9f..27f55253f 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -50,7 +50,7 @@ public: private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow - uint64_t m_blockCost = 0; + int64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; llvm::Function* m_gasCheckFunc = nullptr; diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 408f2dee3..1441f475a 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -216,15 +216,15 @@ llvm::Value* RuntimeManager::getJmpBuf() llvm::Value* RuntimeManager::getGas() { - auto value = get(RuntimeData::Gas); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; } void RuntimeManager::setGas(llvm::Value* _gas) { - auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); - set(RuntimeData::Gas, newGas); + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); } } From b4749247833375646afb578f9172539bf78f5392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:08:57 +0100 Subject: [PATCH 028/118] Count gas using int64 --- evmjit/libevmjit/BasicBlock.cpp | 1 + evmjit/libevmjit/Compiler.cpp | 3 +- evmjit/libevmjit/Ext.cpp | 6 +- evmjit/libevmjit/GasMeter.cpp | 103 ++++++++++++++-------------- evmjit/libevmjit/GasMeter.h | 2 +- evmjit/libevmjit/RuntimeManager.cpp | 10 +-- 6 files changed, 66 insertions(+), 59 deletions(-) diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index d907aada1..c71bae94f 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -44,6 +44,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : void BasicBlock::LocalStack::push(llvm::Value* _value) { + assert(_value->getType() == Type::Word); m_bblock.m_currentStack.push_back(_value); m_bblock.m_tosOffset += 1; } diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index eddd16492..b6206b8d8 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -630,7 +630,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::GAS: { _gasMeter.commitCostBlock(); - stack.push(_runtimeManager.getGas()); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); break; } @@ -770,6 +770,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti receiveAddress = _runtimeManager.get(RuntimeData::Address); _gasMeter.count(gas); + // TODO: pass gas to call as int64 auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); _gasMeter.giveBack(gas); stack.push(ret); diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index 965ef2e06..28e10366c 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -128,12 +128,14 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas = byPtr(_gas); + auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); + auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - _gas = m_builder.CreateLoad(gas); // Return gas + gas256 = m_builder.CreateLoad(gas); // Return gas + _gas = m_builder.CreateTrunc(gas256, Type::Gas); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index d54eea754..8ac575338 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -19,29 +19,29 @@ namespace jit namespace // Helper functions { -uint64_t const c_stepGas = 1; -uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 10; -uint64_t const c_sha3WordGas = 10; -uint64_t const c_sloadGas = 20; -uint64_t const c_sstoreSetGas = 300; -uint64_t const c_sstoreResetGas = 100; -uint64_t const c_sstoreRefundGas = 100; -uint64_t const c_createGas = 100; -uint64_t const c_createDataGas = 5; -uint64_t const c_callGas = 20; -uint64_t const c_expGas = 1; -uint64_t const c_expByteGas = 1; -uint64_t const c_memoryGas = 1; -uint64_t const c_txDataZeroGas = 1; -uint64_t const c_txDataNonZeroGas = 5; -uint64_t const c_txGas = 500; -uint64_t const c_logGas = 32; -uint64_t const c_logDataGas = 1; -uint64_t const c_logTopicGas = 32; -uint64_t const c_copyGas = 1; - -uint64_t getStepCost(Instruction inst) +int64_t const c_stepGas = 1; +int64_t const c_balanceGas = 20; +int64_t const c_sha3Gas = 10; +int64_t const c_sha3WordGas = 10; +int64_t const c_sloadGas = 20; +int64_t const c_sstoreSetGas = 300; +int64_t const c_sstoreResetGas = 100; +int64_t const c_sstoreRefundGas = 100; +int64_t const c_createGas = 100; +int64_t const c_createDataGas = 5; +int64_t const c_callGas = 20; +int64_t const c_expGas = 1; +int64_t const c_expByteGas = 1; +int64_t const c_memoryGas = 1; +int64_t const c_txDataZeroGas = 1; +int64_t const c_txDataNonZeroGas = 5; +int64_t const c_txGas = 500; +int64_t const c_logGas = 32; +int64_t const c_logDataGas = 1; +int64_t const c_logTopicGas = 32; +int64_t const c_copyGas = 1; + +int64_t getStepCost(Instruction inst) { switch (inst) { @@ -72,7 +72,7 @@ uint64_t getStepCost(Instruction inst) case Instruction::LOG3: case Instruction::LOG4: { - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } } @@ -86,7 +86,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas}; m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); @@ -94,15 +94,15 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - auto arg = m_gasCheckFunc->arg_begin(); - arg->setName("rt"); - ++arg; - arg->setName("cost"); - auto cost = arg; + auto rt = &m_gasCheckFunc->getArgumentList().front(); + rt->setName("rt"); + auto cost = rt->getNextNode(); + cost->setName("cost"); m_builder.SetInsertPoint(checkBB); auto gas = m_runtimeManager.getGas(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); + auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); @@ -110,7 +110,6 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); - gas = m_builder.CreateSub(gas, cost); m_runtimeManager.setGas(gas); m_builder.CreateRetVoid(); } @@ -120,7 +119,7 @@ void GasMeter::count(Instruction _inst) if (!m_checkCall) { // Create gas check call with mocked block cost at begining of current cost-block - m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); } m_blockCost += getStepCost(_inst); @@ -128,6 +127,15 @@ void GasMeter::count(Instruction _inst) void GasMeter::count(llvm::Value* _cost) { + if (_cost->getType() == Type::Word) + { + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh"); + auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas); + _cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost"); + } + + assert(_cost->getType() == Type::Gas); createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); } @@ -137,12 +145,13 @@ void GasMeter::countExp(llvm::Value* _exponent) // lz - leading zeros // cost = ((256 - lz) + 7) / 8 - // OPT: All calculations can be done on 32/64 bits + // OPT: Can gas update be done in exp algorithm? auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto sigBits = m_builder.CreateSub(Constant::get(256), lz); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); + auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); count(sigBytes); } @@ -155,8 +164,8 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); - auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); - cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); + auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost"); + cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost"); count(cost); } @@ -179,13 +188,13 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); - auto cost = getBuilder().CreateZExt(cost64, Type::Word); - count(cost); + count(cost64); } void GasMeter::giveBack(llvm::Value* _gas) { - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); + assert(_gas->getType() == Type::Word); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); } void GasMeter::commitCostBlock() @@ -200,7 +209,7 @@ void GasMeter::commitCostBlock() return; } - m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call + m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; } @@ -209,14 +218,8 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { - assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); - auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); - auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); - additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); - auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); - count(additionalMemoryInWords256); + count(_additionalMemoryInWords); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h index 56da6eb9f..27f55253f 100644 --- a/evmjit/libevmjit/GasMeter.h +++ b/evmjit/libevmjit/GasMeter.h @@ -50,7 +50,7 @@ public: private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow - uint64_t m_blockCost = 0; + int64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; llvm::Function* m_gasCheckFunc = nullptr; diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 408f2dee3..1441f475a 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -216,15 +216,15 @@ llvm::Value* RuntimeManager::getJmpBuf() llvm::Value* RuntimeManager::getGas() { - auto value = get(RuntimeData::Gas); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; } void RuntimeManager::setGas(llvm::Value* _gas) { - auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); - set(RuntimeData::Gas, newGas); + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); } } From 494e96a89c2af3752942e4879d818a649ae1a776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:32:55 +0100 Subject: [PATCH 029/118] Pass gas counter to env_create as int64* --- libevmjit-cpp/Env.cpp | 9 ++++----- libevmjit/Compiler.cpp | 5 +---- libevmjit/Ext.cpp | 10 +++------- libevmjit/Ext.h | 2 +- libevmjit/RuntimeManager.cpp | 5 +++++ libevmjit/RuntimeManager.h | 3 ++- libevmjit/Type.cpp | 2 ++ libevmjit/Type.h | 1 + 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index f89897792..e279e1a56 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -46,16 +46,15 @@ extern "C" *o_hash = _env->blockhash(llvm2eth(*_number)); } - EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { auto endowment = llvm2eth(*_endowment); if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) { _env->subBalance(endowment); - auto gas = llvm2eth(*io_gas); - OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + *io_gas = static_cast(gas); *o_address = address; } else diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index b6206b8d8..c41fcb0bb 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -740,10 +740,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti _memory.require(initOff, initSize); _gasMeter.commitCostBlock(); - - auto gas = _runtimeManager.getGas(); - auto address = _ext.create(gas, endowment, initOff, initSize); - _runtimeManager.setGas(gas); + auto address = _ext.create(endowment, initOff, initSize); stack.push(address); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 28e10366c..dcc761062 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -41,7 +41,7 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, @@ -126,16 +126,12 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) return Endianness::toNative(getBuilder(), hash); } -llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); - auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - gas256 = m_builder.CreateLoad(gas); // Return gas - _gas = m_builder.CreateTrunc(gas256, Type::Gas); + createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(_endowment), begin, size, ret}); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 2601d32ab..b4ca30783 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -50,7 +50,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* blockhash(llvm::Value* _number); diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 1441f475a..6d6cc09a0 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -221,6 +221,11 @@ llvm::Value* RuntimeManager::getGas() return gas; } +llvm::Value* RuntimeManager::getGasPtr() +{ + return getPtr(RuntimeData::Gas); +} + void RuntimeManager::setGas(llvm::Value* _gas) { assert(_gas->getType() == Type::Gas); diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index b5f3ca657..e483f67cd 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -23,7 +23,8 @@ public: llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); - llvm::Value* getGas(); // TODO: Remove + llvm::Value* getGas(); + llvm::Value* getGasPtr(); llvm::Value* getCallData(); llvm::Value* getCode(); llvm::Value* getCodeSize(); diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 169691904..2bbb3fa6f 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -18,6 +18,7 @@ llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; llvm::IntegerType* Type::Gas; +llvm::PointerType* Type::GasPtr; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -38,6 +39,7 @@ void Type::init(llvm::LLVMContext& _context) Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); Gas = Size; + GasPtr = Gas->getPointerTo(); Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); diff --git a/libevmjit/Type.h b/libevmjit/Type.h index cfac1e2c6..e7757abbf 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -24,6 +24,7 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; static llvm::IntegerType* Gas; + static llvm::PointerType* GasPtr; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; From ce8642787115011ae36c08d77d2413fed3db062d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:32:55 +0100 Subject: [PATCH 030/118] Pass gas counter to env_create as int64* --- evmjit/libevmjit-cpp/Env.cpp | 9 ++++----- evmjit/libevmjit/Compiler.cpp | 5 +---- evmjit/libevmjit/Ext.cpp | 10 +++------- evmjit/libevmjit/Ext.h | 2 +- evmjit/libevmjit/RuntimeManager.cpp | 5 +++++ evmjit/libevmjit/RuntimeManager.h | 3 ++- evmjit/libevmjit/Type.cpp | 2 ++ evmjit/libevmjit/Type.h | 1 + 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index f89897792..e279e1a56 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -46,16 +46,15 @@ extern "C" *o_hash = _env->blockhash(llvm2eth(*_number)); } - EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { auto endowment = llvm2eth(*_endowment); if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) { _env->subBalance(endowment); - auto gas = llvm2eth(*io_gas); - OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + *io_gas = static_cast(gas); *o_address = address; } else diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index b6206b8d8..c41fcb0bb 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -740,10 +740,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti _memory.require(initOff, initSize); _gasMeter.commitCostBlock(); - - auto gas = _runtimeManager.getGas(); - auto address = _ext.create(gas, endowment, initOff, initSize); - _runtimeManager.setGas(gas); + auto address = _ext.create(endowment, initOff, initSize); stack.push(address); break; } diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index 28e10366c..dcc761062 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -41,7 +41,7 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, @@ -126,16 +126,12 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) return Endianness::toNative(getBuilder(), hash); } -llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); - auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - gas256 = m_builder.CreateLoad(gas); // Return gas - _gas = m_builder.CreateTrunc(gas256, Type::Gas); + createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(_endowment), begin, size, ret}); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index 2601d32ab..b4ca30783 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -50,7 +50,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* blockhash(llvm::Value* _number); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 1441f475a..6d6cc09a0 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -221,6 +221,11 @@ llvm::Value* RuntimeManager::getGas() return gas; } +llvm::Value* RuntimeManager::getGasPtr() +{ + return getPtr(RuntimeData::Gas); +} + void RuntimeManager::setGas(llvm::Value* _gas) { assert(_gas->getType() == Type::Gas); diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index b5f3ca657..e483f67cd 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -23,7 +23,8 @@ public: llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); - llvm::Value* getGas(); // TODO: Remove + llvm::Value* getGas(); + llvm::Value* getGasPtr(); llvm::Value* getCallData(); llvm::Value* getCode(); llvm::Value* getCodeSize(); diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 169691904..2bbb3fa6f 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -18,6 +18,7 @@ llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; llvm::IntegerType* Type::Gas; +llvm::PointerType* Type::GasPtr; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -38,6 +39,7 @@ void Type::init(llvm::LLVMContext& _context) Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); Gas = Size; + GasPtr = Gas->getPointerTo(); Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index cfac1e2c6..e7757abbf 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -24,6 +24,7 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; static llvm::IntegerType* Gas; + static llvm::PointerType* GasPtr; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; From 3cbe1186cc3f5c6d2a2a12b7a9e13699f772dc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:57:26 +0100 Subject: [PATCH 031/118] Pass gas counter to env_call as int64* --- libevmjit-cpp/Env.cpp | 9 ++++----- libevmjit/Compiler.cpp | 13 ++++++++----- libevmjit/Ext.cpp | 8 +++----- libevmjit/Ext.h | 2 +- libevmjit/GasMeter.cpp | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index e279e1a56..cdca56b99 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -61,7 +61,7 @@ extern "C" *o_address = {}; } - EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { auto value = llvm2eth(*_value); if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) @@ -70,11 +70,10 @@ extern "C" auto receiveAddress = right160(*_receiveAddress); auto inRef = bytesConstRef{_inBeg, _inSize}; auto outRef = bytesConstRef{_outBeg, _outSize}; - OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); - auto gas = llvm2eth(*io_gas); - auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); + *io_gas = static_cast(gas); return ret; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index c41fcb0bb..b19a1479e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -748,7 +748,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::CALL: case Instruction::CALLCODE: { - auto gas = stack.pop(); + auto callGas256 = stack.pop(); auto codeAddress = stack.pop(); auto value = stack.pop(); auto inOff = stack.pop(); @@ -766,10 +766,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - _gasMeter.count(gas); - // TODO: pass gas to call as int64 - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); + auto gas = _runtimeManager.getGas(); + _gasMeter.count(callGas256); + auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas); + auto gasLeft = m_builder.CreateNSWSub(gas, callGas); + _runtimeManager.setGas(callGas); + auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gasLeft); stack.push(ret); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index dcc761062..0a465bb80 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -42,7 +42,7 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, - FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, @@ -137,17 +137,15 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V return address; } -llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) { - auto gas = byPtr(_gas); auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); auto inBeg = m_memoryMan.getBytePtr(_inOff); auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); auto outBeg = m_memoryMan.getBytePtr(_outOff); auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); - auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); - _gas = m_builder.CreateLoad(gas); // Return gas + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); return m_builder.CreateZExt(ret, Type::Word, "ret"); } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index b4ca30783..8ad69ea6e 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -51,7 +51,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); - llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* blockhash(llvm::Value* _number); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 8ac575338..9c02bce8e 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -193,8 +193,8 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) void GasMeter::giveBack(llvm::Value* _gas) { - assert(_gas->getType() == Type::Word); - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); + assert(_gas->getType() == Type::Gas); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); } void GasMeter::commitCostBlock() From ee036d3c97b9f772769e12985eee46d3b008e3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:57:26 +0100 Subject: [PATCH 032/118] Pass gas counter to env_call as int64* --- evmjit/libevmjit-cpp/Env.cpp | 9 ++++----- evmjit/libevmjit/Compiler.cpp | 13 ++++++++----- evmjit/libevmjit/Ext.cpp | 8 +++----- evmjit/libevmjit/Ext.h | 2 +- evmjit/libevmjit/GasMeter.cpp | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index e279e1a56..cdca56b99 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -61,7 +61,7 @@ extern "C" *o_address = {}; } - EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { auto value = llvm2eth(*_value); if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) @@ -70,11 +70,10 @@ extern "C" auto receiveAddress = right160(*_receiveAddress); auto inRef = bytesConstRef{_inBeg, _inSize}; auto outRef = bytesConstRef{_outBeg, _outSize}; - OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); - auto gas = llvm2eth(*io_gas); - auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); + *io_gas = static_cast(gas); return ret; } diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index c41fcb0bb..b19a1479e 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -748,7 +748,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::CALL: case Instruction::CALLCODE: { - auto gas = stack.pop(); + auto callGas256 = stack.pop(); auto codeAddress = stack.pop(); auto value = stack.pop(); auto inOff = stack.pop(); @@ -766,10 +766,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - _gasMeter.count(gas); - // TODO: pass gas to call as int64 - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); + auto gas = _runtimeManager.getGas(); + _gasMeter.count(callGas256); + auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas); + auto gasLeft = m_builder.CreateNSWSub(gas, callGas); + _runtimeManager.setGas(callGas); + auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gasLeft); stack.push(ret); break; } diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index dcc761062..0a465bb80 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -42,7 +42,7 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, - FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, @@ -137,17 +137,15 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V return address; } -llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) { - auto gas = byPtr(_gas); auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); auto inBeg = m_memoryMan.getBytePtr(_inOff); auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); auto outBeg = m_memoryMan.getBytePtr(_outOff); auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); - auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); - _gas = m_builder.CreateLoad(gas); // Return gas + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); return m_builder.CreateZExt(ret, Type::Word, "ret"); } diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index b4ca30783..8ad69ea6e 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -51,7 +51,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); - llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* blockhash(llvm::Value* _number); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 8ac575338..9c02bce8e 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -193,8 +193,8 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) void GasMeter::giveBack(llvm::Value* _gas) { - assert(_gas->getType() == Type::Word); - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); + assert(_gas->getType() == Type::Gas); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); } void GasMeter::commitCostBlock() From 73bf7087e7e976174701ec29beafbb42065b22a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 18:23:23 +0100 Subject: [PATCH 033/118] Do not check memory requirements when size is 0 --- libevmjit/Memory.cpp | 483 ++++++++++++++++++++++--------------------- 1 file changed, 244 insertions(+), 239 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c6f8a9ec0..1e9646f68 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,239 +1,244 @@ -#include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Type.h" -#include "Runtime.h" -#include "GasMeter.h" -#include "Endianness.h" -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): - RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed - m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} - -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) -{ - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - // BB "Pre": Ignore checks with size 0 - m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); - return func; -} - -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) -{ - auto isWord = _valueType == Type::Word; - - llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; - auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); - auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto index = rt->getNextNode(); - index->setName("index"); - - auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - this->require(index, Constant::get(valueSize)); - auto ptr = getBytePtr(index); - if (isWord) - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - if (_isStore) - { - llvm::Value* value = index->getNextNode(); - value->setName("value"); - if (isWord) - value = Endianness::toBE(m_builder, value); - m_builder.CreateStore(value, ptr); - m_builder.CreateRetVoid(); - } - else - { - llvm::Value* ret = m_builder.CreateLoad(ptr); - ret = Endianness::toNative(m_builder, ret); - m_builder.CreateRet(ret); - } - - return func; -} - - -llvm::Value* Memory::loadWord(llvm::Value* _addr) -{ - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); -} - -llvm::Value* Memory::getData() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - return m_builder.CreateLoad(dataPtr, "data"); -} - -llvm::Value* Memory::getSize() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - return m_builder.CreateLoad(sizePtr, "size"); -} - -llvm::Value* Memory::getBytePtr(llvm::Value* _index) -{ - auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 - return m_builder.CreateGEP(getData(), idx, "ptr"); -} - -void Memory::require(llvm::Value* _offset, llvm::Value* _size) -{ - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); -} - -void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, - llvm::Value* _destMemIdx, llvm::Value* _reqBytes) -{ - require(_destMemIdx, _reqBytes); - - // Additional copy cost - // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); - m_gasMeter.countCopy(copyWords); - - // Algorithm: - // isOutsideData = idx256 >= size256 - // idx64 = trunc idx256 - // size64 = trunc size256 - // dataLeftSize = size64 - idx64 // safe if not isOutsideData - // reqBytes64 = trunc _reqBytes // require() handles large values - // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min - // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) - - auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); - - auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); - auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 - auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); - m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); -} - -} -} -} - - -extern "C" -{ - using namespace dev::eth::jit; - - EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR - { - auto size = _size->a; // Trunc to 64-bit - auto& memory = _rt->getMemory(); - memory.resize(size); - return memory.data(); - } -} +#include "Memory.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Type.h" +#include "Runtime.h" +#include "GasMeter.h" +#include "Endianness.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed + m_gasMeter(_gasMeter) +{ + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); + + m_require = createRequireFunc(_gasMeter); + m_loadWord = createFunc(false, Type::Word, _gasMeter); + m_storeWord = createFunc(true, Type::Word, _gasMeter); + m_storeByte = createFunc(true, Type::Byte, _gasMeter); +} + +llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +{ + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + _gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + return func; +} + +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +{ + auto isWord = _valueType == Type::Word; + + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + this->require(index, Constant::get(valueSize)); + auto ptr = getBytePtr(index); + if (isWord) + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + if (_isStore) + { + llvm::Value* value = index->getNextNode(); + value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + } + else + { + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); + m_builder.CreateRet(ret); + } + + return func; +} + + +llvm::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); +} + +llvm::Value* Memory::getData() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); +} + +llvm::Value* Memory::getSize() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); +} + +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 + return m_builder.CreateGEP(getData(), idx, "ptr"); +} + +void Memory::require(llvm::Value* _offset, llvm::Value* _size) +{ + if (auto constant = llvm::dyn_cast(_size)) + { + if (!constant->getValue()) + return; + } + createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); +} + +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + require(_destMemIdx, _reqBytes); + + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + m_gasMeter.countCopy(copyWords); + + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); + auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 + auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); +} + +} +} +} + + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } +} From 4c8ae3e707c8d32f65fc20505ef457133229eb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 18:23:23 +0100 Subject: [PATCH 034/118] Do not check memory requirements when size is 0 --- evmjit/libevmjit/Memory.cpp | 483 ++++++++++++++++++------------------ 1 file changed, 244 insertions(+), 239 deletions(-) diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index c6f8a9ec0..1e9646f68 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -1,239 +1,244 @@ -#include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Type.h" -#include "Runtime.h" -#include "GasMeter.h" -#include "Endianness.h" -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): - RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed - m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} - -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) -{ - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - // BB "Pre": Ignore checks with size 0 - m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); - return func; -} - -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) -{ - auto isWord = _valueType == Type::Word; - - llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; - auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); - auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto index = rt->getNextNode(); - index->setName("index"); - - auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - this->require(index, Constant::get(valueSize)); - auto ptr = getBytePtr(index); - if (isWord) - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - if (_isStore) - { - llvm::Value* value = index->getNextNode(); - value->setName("value"); - if (isWord) - value = Endianness::toBE(m_builder, value); - m_builder.CreateStore(value, ptr); - m_builder.CreateRetVoid(); - } - else - { - llvm::Value* ret = m_builder.CreateLoad(ptr); - ret = Endianness::toNative(m_builder, ret); - m_builder.CreateRet(ret); - } - - return func; -} - - -llvm::Value* Memory::loadWord(llvm::Value* _addr) -{ - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); -} - -llvm::Value* Memory::getData() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - return m_builder.CreateLoad(dataPtr, "data"); -} - -llvm::Value* Memory::getSize() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - return m_builder.CreateLoad(sizePtr, "size"); -} - -llvm::Value* Memory::getBytePtr(llvm::Value* _index) -{ - auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 - return m_builder.CreateGEP(getData(), idx, "ptr"); -} - -void Memory::require(llvm::Value* _offset, llvm::Value* _size) -{ - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); -} - -void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, - llvm::Value* _destMemIdx, llvm::Value* _reqBytes) -{ - require(_destMemIdx, _reqBytes); - - // Additional copy cost - // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); - m_gasMeter.countCopy(copyWords); - - // Algorithm: - // isOutsideData = idx256 >= size256 - // idx64 = trunc idx256 - // size64 = trunc size256 - // dataLeftSize = size64 - idx64 // safe if not isOutsideData - // reqBytes64 = trunc _reqBytes // require() handles large values - // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min - // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) - - auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); - - auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); - auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 - auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); - m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); -} - -} -} -} - - -extern "C" -{ - using namespace dev::eth::jit; - - EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR - { - auto size = _size->a; // Trunc to 64-bit - auto& memory = _rt->getMemory(); - memory.resize(size); - return memory.data(); - } -} +#include "Memory.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Type.h" +#include "Runtime.h" +#include "GasMeter.h" +#include "Endianness.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed + m_gasMeter(_gasMeter) +{ + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); + + m_require = createRequireFunc(_gasMeter); + m_loadWord = createFunc(false, Type::Word, _gasMeter); + m_storeWord = createFunc(true, Type::Word, _gasMeter); + m_storeByte = createFunc(true, Type::Byte, _gasMeter); +} + +llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +{ + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + _gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + return func; +} + +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +{ + auto isWord = _valueType == Type::Word; + + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + this->require(index, Constant::get(valueSize)); + auto ptr = getBytePtr(index); + if (isWord) + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + if (_isStore) + { + llvm::Value* value = index->getNextNode(); + value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + } + else + { + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); + m_builder.CreateRet(ret); + } + + return func; +} + + +llvm::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); +} + +llvm::Value* Memory::getData() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); +} + +llvm::Value* Memory::getSize() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); +} + +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 + return m_builder.CreateGEP(getData(), idx, "ptr"); +} + +void Memory::require(llvm::Value* _offset, llvm::Value* _size) +{ + if (auto constant = llvm::dyn_cast(_size)) + { + if (!constant->getValue()) + return; + } + createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); +} + +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + require(_destMemIdx, _reqBytes); + + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + m_gasMeter.countCopy(copyWords); + + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); + auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 + auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); +} + +} +} +} + + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } +} From 3505e832ee35066275e3fe6cd50ca2383696d8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 19:01:12 +0100 Subject: [PATCH 035/118] Some tweaks in gas counting --- libevmjit/GasMeter.cpp | 5 ++--- libevmjit/Memory.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 9c02bce8e..eb06795f0 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -183,10 +183,9 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) assert(m_blockCost > 0); // SHA3 instruction is already counted // TODO: This round ups to 32 happens in many places - // FIXME: 64-bit arith used, but not verified static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); - auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); - auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas); + auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); count(cost64); } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 1e9646f68..c212b2d1a 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -197,7 +197,8 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* // Additional copy cost // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas); + auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32)); m_gasMeter.countCopy(copyWords); // Algorithm: @@ -210,14 +211,12 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size); auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes); + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner); auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 From 7cbb44faa11259827c18a5a849cc90927b042e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 19:01:12 +0100 Subject: [PATCH 036/118] Some tweaks in gas counting --- evmjit/libevmjit/GasMeter.cpp | 5 ++--- evmjit/libevmjit/Memory.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 9c02bce8e..eb06795f0 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -183,10 +183,9 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) assert(m_blockCost > 0); // SHA3 instruction is already counted // TODO: This round ups to 32 happens in many places - // FIXME: 64-bit arith used, but not verified static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); - auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); - auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas); + auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); count(cost64); } diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index 1e9646f68..c212b2d1a 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -197,7 +197,8 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* // Additional copy cost // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas); + auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32)); m_gasMeter.countCopy(copyWords); // Algorithm: @@ -210,14 +211,12 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size); auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes); + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner); auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 From f281e5ea262636477d9640ab54497d0360bf5102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 13:45:18 +0100 Subject: [PATCH 037/118] Workaround for linker removing JIT callback functions --- libevmjit-cpp/JitVM.cpp | 16 +++++----------- libevmjit/Common.h | 2 ++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index ab1a4cf2b..53282e3ae 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -11,6 +11,8 @@ namespace dev namespace eth { +extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below + bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; @@ -65,6 +67,9 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) BOOST_THROW_EXCEPTION(StackTooSmall()); case ReturnCode::BadInstruction: BOOST_THROW_EXCEPTION(BadInstruction()); + case ReturnCode::LinkerWorkaround: // never happens + env_sload(); // but forces linker to include env_* JIT callback functions + break; default: break; } @@ -75,14 +80,3 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) } } - -namespace -{ - // MSVS linker ignores export symbols in Env.cpp if nothing points at least one of them - extern "C" void env_sload(); - void linkerWorkaround() - { - env_sload(); - (void)&linkerWorkaround; // suppress unused function warning from GCC - } -} diff --git a/libevmjit/Common.h b/libevmjit/Common.h index 9c9dfd8a2..20d9bdab3 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -44,6 +44,8 @@ enum class ReturnCode LLVMLinkError = -103, UnexpectedException = -111, + + LinkerWorkaround = -299, }; /// Representation of 256-bit value binary compatible with LLVM i256 From 62587cfd73c66a411ef97601f0e4a17bd288dd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 13:45:18 +0100 Subject: [PATCH 038/118] Workaround for linker removing JIT callback functions --- evmjit/libevmjit-cpp/JitVM.cpp | 16 +++++----------- evmjit/libevmjit/Common.h | 2 ++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index ab1a4cf2b..53282e3ae 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -11,6 +11,8 @@ namespace dev namespace eth { +extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below + bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; @@ -65,6 +67,9 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) BOOST_THROW_EXCEPTION(StackTooSmall()); case ReturnCode::BadInstruction: BOOST_THROW_EXCEPTION(BadInstruction()); + case ReturnCode::LinkerWorkaround: // never happens + env_sload(); // but forces linker to include env_* JIT callback functions + break; default: break; } @@ -75,14 +80,3 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) } } - -namespace -{ - // MSVS linker ignores export symbols in Env.cpp if nothing points at least one of them - extern "C" void env_sload(); - void linkerWorkaround() - { - env_sload(); - (void)&linkerWorkaround; // suppress unused function warning from GCC - } -} diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index 9c9dfd8a2..20d9bdab3 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -44,6 +44,8 @@ enum class ReturnCode LLVMLinkError = -103, UnexpectedException = -111, + + LinkerWorkaround = -299, }; /// Representation of 256-bit value binary compatible with LLVM i256 From 4391c9b27bf6a3ae61eadb797d14dfef096dc764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 15:18:09 +0100 Subject: [PATCH 039/118] Update README.md - add information about options --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 30ed2f489..a480e83dc 100644 --- a/README.md +++ b/README.md @@ -30,5 +30,14 @@ It can be used to substitute classic interpreter-like EVM Virtual Machine in Eth ### Windows Ask me. + +## Options + +Options to evmjit library can be passed by environmental variables, e.g. `EVMJIT_CACHE=0 testeth --jit`. + +Option | Default value | Description +------------- | ------------- | ---------------------------------------------- +EVMJIT_CACHE | 1 | Enables on disk cache for compiled EVM objects +EVMJIT_DUMP | 0 | Dumps generated LLVM module to standard output From 625095473a6ea45dc45e244056affff4c9a3eb34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 17:00:58 +0100 Subject: [PATCH 040/118] Remove dead jump table block --- libevmjit/Compiler.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1ce63d8ec..ad8a14fc7 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -91,6 +91,7 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) } } + // TODO: Create Stop basic block on demand m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } @@ -863,6 +864,18 @@ void Compiler::removeDeadBlocks() } } while (sthErased); + + if (m_jumpTableBlock && llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } + + if (m_badJumpBlock && llvm::pred_begin(m_badJumpBlock->llvm()) == llvm::pred_end(m_badJumpBlock->llvm())) + { + m_badJumpBlock->llvm()->eraseFromParent(); + m_badJumpBlock.reset(); + } } void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) From 970939ddb79b3896e1130791bd059af24e20b2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 18:21:04 +0100 Subject: [PATCH 041/118] Fix after-merge problems --- libevmjit/ExecutionEngine.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 904531a9e..69cf28afd 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -72,13 +72,6 @@ bool getEnvOption(char const* _name, bool _default) return std::strtol(var, nullptr, 10) != 0; } -bool getEnvOption(char const* _name, bool _default) -{ - auto var = std::getenv(_name); - if (!var) - return _default; - return std::strtol(var, nullptr, 10) != 0; - } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) From bb9df15d75281e9240b8ab5f21286948c00958d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 19:32:27 +0100 Subject: [PATCH 042/118] Generate BuildInfo header and display some information about evmjit library on demand --- libevmjit/BuildInfo.h.in | 10 ++++++++++ libevmjit/CMakeLists.txt | 5 ++++- libevmjit/ExecutionEngine.cpp | 13 +++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 libevmjit/BuildInfo.h.in diff --git a/libevmjit/BuildInfo.h.in b/libevmjit/BuildInfo.h.in new file mode 100644 index 000000000..204b4d89b --- /dev/null +++ b/libevmjit/BuildInfo.h.in @@ -0,0 +1,10 @@ + +#define EVMJIT_VERSION "${EVMJIT_VERSION}" +#define EVMJIT_VERSION_MAJOR ${EVMJIT_VERSION_MAJOR} +#define EVMJIT_VERSION_MINOR ${EVMJIT_VERSION_MINOR} +#define EVMJIT_VERSION_PATCH ${EVMJIT_VERSION_PATCH} +#define EVMJIT_VERSION_PRERELEASE "${EVMJIT_VERSION_PRERELEASE}" +#define EVMJIT_VERSION_FULL "${EVMJIT_VERSION_FULL}" + +#define LLVM_VERSION "${LLVM_PACKAGE_VERSION}" +#define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}" diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index f88a5468b..330eaf3c8 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -47,14 +47,17 @@ else() set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR}) endif() +configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h) + message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH}-${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") -add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) +add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h) set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 69cf28afd..1402faacc 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Compiler.h" #include "Cache.h" +#include "BuildInfo.gen.h" #include @@ -72,6 +73,16 @@ bool getEnvOption(char const* _name, bool _default) return std::strtol(var, nullptr, 10) != 0; } +bool showInfo() +{ + auto show = getEnvOption("EVMJIT_INFO", false); + if (show) + { + std::cout << "The Ethereum EVM JIT " EVMJIT_VERSION_FULL " LLVM " LLVM_VERSION << std::endl; + } + return show; +} + } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -79,6 +90,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static auto infoShown = showInfo(); + (void) infoShown; auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; From 82972e47dfc3843d00cffe36bca2b3854cfbafd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 11:45:13 +0100 Subject: [PATCH 043/118] Start of stats collector --- evmjit/libevmjit/ExecStats.cpp | 22 ++++++++++ evmjit/libevmjit/ExecStats.h | 32 +++++++++++++++ evmjit/libevmjit/ExecutionEngine.cpp | 61 ++++++++++++++++++++++++++-- evmjit/libevmjit/ExecutionEngine.h | 8 ++++ 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 evmjit/libevmjit/ExecStats.cpp create mode 100644 evmjit/libevmjit/ExecStats.h diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..e3f5293f8 --- /dev/null +++ b/evmjit/libevmjit/ExecStats.cpp @@ -0,0 +1,22 @@ +#include "ExecStats.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::execStarted() +{ + m_tp = std::chrono::high_resolution_clock::now(); +} + +void ExecStats::execEnded() +{ + execTime = std::chrono::high_resolution_clock::now() - m_tp; +} + +} +} +} diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h new file mode 100644 index 000000000..3ee730836 --- /dev/null +++ b/evmjit/libevmjit/ExecStats.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats +{ +public: + std::string id; + std::chrono::high_resolution_clock::duration compileTime; + std::chrono::high_resolution_clock::duration codegenTime; + std::chrono::high_resolution_clock::duration cacheLoadTime; + std::chrono::high_resolution_clock::duration execTime; + + void execStarted(); + void execEnded(); + +private: + std::chrono::high_resolution_clock::time_point m_tp; + +}; + +} +} +} diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 1402faacc..6c1bc5c3b 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -83,6 +83,50 @@ bool showInfo() return show; } +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector() + { + if (stats.empty()) + return; + + using d = decltype(ExecStats{}.execTime); + d total = d::zero(); + d max = d::zero(); + d min = d::max(); + + for (auto&& s : stats) + { + auto t = s->execTime; + total += t; + if (t < min) + min = t; + if (t > max) + max = t; + } + + using u = std::chrono::microseconds; + auto nTotal = std::chrono::duration_cast(total).count(); + auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); + auto nMax = std::chrono::duration_cast(max).count(); + auto nMin = std::chrono::duration_cast(min).count(); + + std::cout << "Total exec time: " << nTotal << " us" << std::endl + << "Averge exec time: " << nAverage << " us" << std::endl + << "Min exec time: " << nMin << " us" << std::endl + << "Max exec time: " << nMax << " us" << std::endl; + } +}; + +} + +void ExecutionEngine::collectStats() +{ + if (!m_stats) + m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -90,9 +134,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); static auto infoShown = showInfo(); (void) infoShown; + static StatsCollector statsCollector; + + if (statsCollectingEnabled) + collectStats(); + auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? @@ -153,17 +203,22 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } assert(entryFuncPtr); - auto executionStartTime = std::chrono::high_resolution_clock::now(); + if (m_stats) + m_stats->execStarted(); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + + if (m_stats) + m_stats->execEnded(); + if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; + if (statsCollectingEnabled) + statsCollector.stats.push_back(std::move(m_stats)); return returnCode; } diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index c95bbfb62..e12f86af4 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -1,6 +1,8 @@ #pragma once +#include #include "RuntimeData.h" +#include "ExecStats.h" namespace dev { @@ -18,6 +20,10 @@ public: EXPORT ReturnCode run(RuntimeData* _data, Env* _env); + void collectStats(); + + std::unique_ptr getStats(); + /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -25,6 +31,8 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; + + std::unique_ptr m_stats; }; } From d27352b8e1ea9507341c496ece2f31f5c8c14e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 11:45:13 +0100 Subject: [PATCH 044/118] Start of stats collector --- libevmjit/ExecStats.cpp | 22 +++++++++++++ libevmjit/ExecStats.h | 32 ++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 61 +++++++++++++++++++++++++++++++++-- libevmjit/ExecutionEngine.h | 8 +++++ 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 libevmjit/ExecStats.cpp create mode 100644 libevmjit/ExecStats.h diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..e3f5293f8 --- /dev/null +++ b/libevmjit/ExecStats.cpp @@ -0,0 +1,22 @@ +#include "ExecStats.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::execStarted() +{ + m_tp = std::chrono::high_resolution_clock::now(); +} + +void ExecStats::execEnded() +{ + execTime = std::chrono::high_resolution_clock::now() - m_tp; +} + +} +} +} diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h new file mode 100644 index 000000000..3ee730836 --- /dev/null +++ b/libevmjit/ExecStats.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats +{ +public: + std::string id; + std::chrono::high_resolution_clock::duration compileTime; + std::chrono::high_resolution_clock::duration codegenTime; + std::chrono::high_resolution_clock::duration cacheLoadTime; + std::chrono::high_resolution_clock::duration execTime; + + void execStarted(); + void execEnded(); + +private: + std::chrono::high_resolution_clock::time_point m_tp; + +}; + +} +} +} diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 1402faacc..6c1bc5c3b 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -83,6 +83,50 @@ bool showInfo() return show; } +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector() + { + if (stats.empty()) + return; + + using d = decltype(ExecStats{}.execTime); + d total = d::zero(); + d max = d::zero(); + d min = d::max(); + + for (auto&& s : stats) + { + auto t = s->execTime; + total += t; + if (t < min) + min = t; + if (t > max) + max = t; + } + + using u = std::chrono::microseconds; + auto nTotal = std::chrono::duration_cast(total).count(); + auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); + auto nMax = std::chrono::duration_cast(max).count(); + auto nMin = std::chrono::duration_cast(min).count(); + + std::cout << "Total exec time: " << nTotal << " us" << std::endl + << "Averge exec time: " << nAverage << " us" << std::endl + << "Min exec time: " << nMin << " us" << std::endl + << "Max exec time: " << nMax << " us" << std::endl; + } +}; + +} + +void ExecutionEngine::collectStats() +{ + if (!m_stats) + m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -90,9 +134,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); static auto infoShown = showInfo(); (void) infoShown; + static StatsCollector statsCollector; + + if (statsCollectingEnabled) + collectStats(); + auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? @@ -153,17 +203,22 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } assert(entryFuncPtr); - auto executionStartTime = std::chrono::high_resolution_clock::now(); + if (m_stats) + m_stats->execStarted(); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + + if (m_stats) + m_stats->execEnded(); + if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; + if (statsCollectingEnabled) + statsCollector.stats.push_back(std::move(m_stats)); return returnCode; } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index c95bbfb62..e12f86af4 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,6 +1,8 @@ #pragma once +#include #include "RuntimeData.h" +#include "ExecStats.h" namespace dev { @@ -18,6 +20,10 @@ public: EXPORT ReturnCode run(RuntimeData* _data, Env* _env); + void collectStats(); + + std::unique_ptr getStats(); + /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -25,6 +31,8 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; + + std::unique_ptr m_stats; }; } From b22f672f0bfd8c1dcb1face3e3b551fe80027db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 13:09:55 +0100 Subject: [PATCH 045/118] Move mul function to LLVM --- evmjit/libevmjit/Arith256.cpp | 94 ++++++++++++++++++++--------------- evmjit/libevmjit/Arith256.h | 11 +--- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 2ec227dcc..0345a4854 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -5,6 +5,7 @@ #include #include + #include namespace dev @@ -16,20 +17,7 @@ namespace jit Arith256::Arith256(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) -{ - using namespace llvm; - - m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); - - using Linkage = GlobalValue::LinkageTypes; - - llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; - - m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); -} +{} void Arith256::debug(llvm::Value* _value, char _c) { @@ -41,6 +29,54 @@ void Arith256::debug(llvm::Value* _value, char _c) createCall(m_debug, {_value, m_builder.getInt8(_c)}); } +llvm::Function* Arith256::getMulFunc() +{ + auto& func = m_mul; + if (!func) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i64 = Type::Size; + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo"); + auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64); + auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128); + + auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128)); + auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128)); + auto t3 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), y_hi); + auto t4 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_lo, i128)); + auto t5 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_mi, i128)); + auto t6 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), y_hi); + auto t7 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_lo, i128)); + auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128)); + + auto p = m_builder.CreateZExt(t1, i256); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); + m_builder.CreateRet(p); + } + return m_mul; +} + llvm::Function* Arith256::getDivFunc(llvm::Type* _type) { auto& func = _type == Type::Word ? m_div : m_div512; @@ -135,7 +171,7 @@ llvm::Function* Arith256::getExpFunc() if (!m_exp) { llvm::Type* argTypes[] = {Type::Word, Type::Word}; - m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "arith.exp", getModule()); + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule()); auto base = &m_exp->getArgumentList().front(); base->setName("base"); @@ -159,9 +195,6 @@ llvm::Function* Arith256::getExpFunc() auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word, nullptr, "a1"); - auto a2 = m_builder.CreateAlloca(Type::Word, nullptr, "a2"); - auto a3 = m_builder.CreateAlloca(Type::Word, nullptr, "a3"); m_builder.CreateBr(headerBB); m_builder.SetInsertPoint(headerBB); @@ -176,20 +209,14 @@ llvm::Function* Arith256::getExpFunc() m_builder.CreateCondBr(eOdd, updateBB, continueBB); m_builder.SetInsertPoint(updateBB); - m_builder.CreateStore(r, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto r0 = m_builder.CreateLoad(a3, "r0"); + auto r0 = createCall(getMulFunc(), {r, b}); m_builder.CreateBr(continueBB); m_builder.SetInsertPoint(continueBB); auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1"); r1->addIncoming(r, bodyBB); r1->addIncoming(r0, updateBB); - m_builder.CreateStore(b, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto b1 = m_builder.CreateLoad(a3, "b1"); + auto b1 = createCall(getMulFunc(), {b, b}); auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); m_builder.CreateBr(headerBB); @@ -273,17 +300,9 @@ llvm::Function* Arith256::getMulModFunc() return m_mulmod; } -llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); - return m_builder.CreateLoad(m_result); -} - llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_mul, _arg1, _arg2); + return createCall(getMulFunc(), {_arg1, _arg2}); } std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) @@ -496,11 +515,6 @@ extern "C" std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) - { - *o_result = mul(*_arg1, *_arg2); - } - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) { *o_result = mul512(*_arg1, *_arg2); diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h index 5852137f8..f8f1c9eb2 100644 --- a/evmjit/libevmjit/Arith256.h +++ b/evmjit/libevmjit/Arith256.h @@ -24,26 +24,19 @@ public: void debug(llvm::Value* _value, char _c); private: + llvm::Function* getMulFunc(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); - llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); - - llvm::Function* m_mul; - + llvm::Function* m_mul = nullptr; llvm::Function* m_div = nullptr; llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; llvm::Function* m_addmod = nullptr; llvm::Function* m_mulmod = nullptr; llvm::Function* m_debug = nullptr; - - llvm::Value* m_arg1; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_result; }; From d58f35343bb16630d751188778e19d8c5dd09877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 13:09:55 +0100 Subject: [PATCH 046/118] Move mul function to LLVM --- libevmjit/Arith256.cpp | 94 ++++++++++++++++++++++++------------------ libevmjit/Arith256.h | 11 +---- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 2ec227dcc..0345a4854 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -5,6 +5,7 @@ #include #include + #include namespace dev @@ -16,20 +17,7 @@ namespace jit Arith256::Arith256(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) -{ - using namespace llvm; - - m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); - - using Linkage = GlobalValue::LinkageTypes; - - llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; - - m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); -} +{} void Arith256::debug(llvm::Value* _value, char _c) { @@ -41,6 +29,54 @@ void Arith256::debug(llvm::Value* _value, char _c) createCall(m_debug, {_value, m_builder.getInt8(_c)}); } +llvm::Function* Arith256::getMulFunc() +{ + auto& func = m_mul; + if (!func) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i64 = Type::Size; + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo"); + auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64); + auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128); + + auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128)); + auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128)); + auto t3 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), y_hi); + auto t4 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_lo, i128)); + auto t5 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_mi, i128)); + auto t6 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), y_hi); + auto t7 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_lo, i128)); + auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128)); + + auto p = m_builder.CreateZExt(t1, i256); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); + m_builder.CreateRet(p); + } + return m_mul; +} + llvm::Function* Arith256::getDivFunc(llvm::Type* _type) { auto& func = _type == Type::Word ? m_div : m_div512; @@ -135,7 +171,7 @@ llvm::Function* Arith256::getExpFunc() if (!m_exp) { llvm::Type* argTypes[] = {Type::Word, Type::Word}; - m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "arith.exp", getModule()); + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule()); auto base = &m_exp->getArgumentList().front(); base->setName("base"); @@ -159,9 +195,6 @@ llvm::Function* Arith256::getExpFunc() auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word, nullptr, "a1"); - auto a2 = m_builder.CreateAlloca(Type::Word, nullptr, "a2"); - auto a3 = m_builder.CreateAlloca(Type::Word, nullptr, "a3"); m_builder.CreateBr(headerBB); m_builder.SetInsertPoint(headerBB); @@ -176,20 +209,14 @@ llvm::Function* Arith256::getExpFunc() m_builder.CreateCondBr(eOdd, updateBB, continueBB); m_builder.SetInsertPoint(updateBB); - m_builder.CreateStore(r, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto r0 = m_builder.CreateLoad(a3, "r0"); + auto r0 = createCall(getMulFunc(), {r, b}); m_builder.CreateBr(continueBB); m_builder.SetInsertPoint(continueBB); auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1"); r1->addIncoming(r, bodyBB); r1->addIncoming(r0, updateBB); - m_builder.CreateStore(b, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto b1 = m_builder.CreateLoad(a3, "b1"); + auto b1 = createCall(getMulFunc(), {b, b}); auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); m_builder.CreateBr(headerBB); @@ -273,17 +300,9 @@ llvm::Function* Arith256::getMulModFunc() return m_mulmod; } -llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); - return m_builder.CreateLoad(m_result); -} - llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_mul, _arg1, _arg2); + return createCall(getMulFunc(), {_arg1, _arg2}); } std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) @@ -496,11 +515,6 @@ extern "C" std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) - { - *o_result = mul(*_arg1, *_arg2); - } - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) { *o_result = mul512(*_arg1, *_arg2); diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 5852137f8..f8f1c9eb2 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -24,26 +24,19 @@ public: void debug(llvm::Value* _value, char _c); private: + llvm::Function* getMulFunc(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); - llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); - - llvm::Function* m_mul; - + llvm::Function* m_mul = nullptr; llvm::Function* m_div = nullptr; llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; llvm::Function* m_addmod = nullptr; llvm::Function* m_mulmod = nullptr; llvm::Function* m_debug = nullptr; - - llvm::Value* m_arg1; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_result; }; From 553c47ebcf34b031f2a60c6501b015e418b6231e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 14:16:17 +0100 Subject: [PATCH 047/118] Move mul512 function to LLVM --- evmjit/libevmjit/Arith256.cpp | 209 +++++++--------------------------- evmjit/libevmjit/Arith256.h | 2 + 2 files changed, 42 insertions(+), 169 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 0345a4854..a77050adc 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -74,7 +74,45 @@ llvm::Function* Arith256::getMulFunc() p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); m_builder.CreateRet(p); } - return m_mul; + return func; +} + +llvm::Function* Arith256::getMul512Func() +{ + auto& func = m_mul512; + if (!func) + { + auto i512 = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + + auto t1 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); + auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_hi, i256)}); + + auto p = m_builder.CreateZExt(t1, i512); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i512), m_builder.getIntN(512, 256))); + m_builder.CreateRet(p); + } + return func; } llvm::Function* Arith256::getDivFunc(llvm::Type* _type) @@ -271,9 +309,6 @@ llvm::Function* Arith256::getMulModFunc() m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); auto i512Ty = m_builder.getIntNTy(512); - llvm::Type* mul512ArgTypes[] = {Type::WordPtr, Type::WordPtr, i512Ty->getPointerTo()}; - auto mul512 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, mul512ArgTypes, false), llvm::Function::ExternalLinkage, "arith_mul512", getModule()); - auto x = &m_mulmod->getArgumentList().front(); x->setName("x"); auto y = x->getNextNode(); @@ -285,13 +320,7 @@ llvm::Function* Arith256::getMulModFunc() auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word); - auto a2 = m_builder.CreateAlloca(Type::Word); - auto a3 = m_builder.CreateAlloca(i512Ty); - m_builder.CreateStore(x, a1); - m_builder.CreateStore(y, a2); - createCall(mul512, {a1, a2, a3}); - auto p = m_builder.CreateLoad(a3, "p"); + auto p = createCall(getMul512Func(), {x, y}); auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); @@ -350,157 +379,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } -namespace -{ -#ifdef __SIZEOF_INT128__ - using uint128 = __uint128_t; -#else - struct uint128 - { - uint64_t lo = 0; - uint64_t hi = 0; - - uint128(uint64_t lo) : lo(lo) {} - - uint128 operator+(uint128 a) - { - uint128 r = 0; - bool overflow = lo > std::numeric_limits::max() - a.lo; - r.lo = lo + a.lo; - r.hi = hi + a.hi + overflow; - return r; - } - - uint128 operator>>(int s) - { - assert(s == 64); - return hi; - } - - uint128 operator<<(int s) - { - assert(s == 64); - uint128 r = 0; - r.hi = lo; - return r; - } - - explicit operator uint64_t() { return lo; } - - static uint128 mul(uint64_t a, uint64_t b) - { - auto x_lo = 0xFFFFFFFF & a; - auto y_lo = 0xFFFFFFFF & b; - auto x_hi = a >> 32; - auto y_hi = b >> 32; - - auto t1 = x_lo * y_lo; - auto t2 = x_lo * y_hi; - auto t3 = x_hi * y_lo; - auto t4 = x_hi * y_hi; - - auto lo = (uint32_t)t1; - auto mid = (uint64_t)(t1 >> 32) + (uint32_t)t2 + (uint32_t)t3; - auto hi = (uint64_t)(t2 >> 32) + (t3 >> 32) + t4 + (mid >> 32); - - uint128 r = 0; - r.lo = (uint64_t)lo + (mid << 32); - r.hi = hi; - return r; - } - - uint128 operator*(uint128 a) - { - auto t1 = mul(lo, a.lo); - auto t2 = mul(lo, a.hi); - auto t3 = mul(hi, a.lo); - return t1 + (t2 << 64) + (t3 << 64); - } - }; -#endif - - struct uint256 - { - uint64_t lo = 0; - uint64_t mid = 0; - uint128 hi = 0; - - uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {} - uint256(uint128 n) - { - lo = (uint64_t) n; - mid = (uint64_t) (n >> 64); - } - - explicit operator uint128() - { - uint128 r = lo; - r |= ((uint128) mid) << 64; - return r; - } - - uint256 operator+(uint256 a) - { - auto _lo = (uint128) lo + a.lo; - auto _mid = (uint128) mid + a.mid + (_lo >> 64); - auto _hi = hi + a.hi + (_mid >> 64); - return {(uint64_t)_lo, (uint64_t)_mid, _hi}; - } - - uint256 lo2hi() - { - hi = (uint128)*this; - lo = 0; - mid = 0; - return *this; - } - }; - - struct uint512 - { - uint128 lo; - uint128 mid; - uint256 hi; - }; - - uint256 mul(uint256 x, uint256 y) - { - auto t1 = (uint128) x.lo * y.lo; - auto t2 = (uint128) x.lo * y.mid; - auto t3 = (uint128) x.lo * y.hi; - auto t4 = (uint128) x.mid * y.lo; - auto t5 = (uint128) x.mid * y.mid; - auto t6 = (uint128) x.mid * y.hi; - auto t7 = x.hi * y.lo; - auto t8 = x.hi * y.mid; - - auto lo = (uint64_t) t1; - auto m1 = (t1 >> 64) + (uint64_t) t2; - auto m2 = (uint64_t) m1; - auto mid = (uint128) m2 + (uint64_t) t4; - auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7 - + (t8 << 64) + (m1 >> 64) + (mid >> 64); - - return {lo, (uint64_t)mid, hi}; - } - - uint512 mul512(uint256 x, uint256 y) - { - auto x_lo = (uint128) x; - auto y_lo = (uint128) y; - - auto t1 = mul(x_lo, y_lo); - auto t2 = mul(x_lo, y.hi); - auto t3 = mul(x.hi, y_lo); - auto t4 = mul(x.hi, y.hi); - - auto lo = (uint128) t1; - auto mid = (uint256) t1.hi + (uint128) t2 + (uint128) t3; - auto hi = (uint256)t2.hi + t3.hi + t4 + mid.hi; - - return {lo, (uint128)mid, hi}; - } -} } } @@ -508,15 +386,8 @@ namespace extern "C" { - using namespace dev::eth::jit; - EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) - { - *o_result = mul512(*_arg1, *_arg2); - } } diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h index f8f1c9eb2..2513ca568 100644 --- a/evmjit/libevmjit/Arith256.h +++ b/evmjit/libevmjit/Arith256.h @@ -25,12 +25,14 @@ public: private: llvm::Function* getMulFunc(); + llvm::Function* getMul512Func(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); llvm::Function* m_mul = nullptr; + llvm::Function* m_mul512 = nullptr; llvm::Function* m_div = nullptr; llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; From 96c89cbedc7fb4b93e3b60a1032d11b09c46edc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 14:16:17 +0100 Subject: [PATCH 048/118] Move mul512 function to LLVM --- libevmjit/Arith256.cpp | 209 ++++++++--------------------------------- libevmjit/Arith256.h | 2 + 2 files changed, 42 insertions(+), 169 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 0345a4854..a77050adc 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -74,7 +74,45 @@ llvm::Function* Arith256::getMulFunc() p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); m_builder.CreateRet(p); } - return m_mul; + return func; +} + +llvm::Function* Arith256::getMul512Func() +{ + auto& func = m_mul512; + if (!func) + { + auto i512 = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + + auto t1 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); + auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_hi, i256)}); + + auto p = m_builder.CreateZExt(t1, i512); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i512), m_builder.getIntN(512, 256))); + m_builder.CreateRet(p); + } + return func; } llvm::Function* Arith256::getDivFunc(llvm::Type* _type) @@ -271,9 +309,6 @@ llvm::Function* Arith256::getMulModFunc() m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); auto i512Ty = m_builder.getIntNTy(512); - llvm::Type* mul512ArgTypes[] = {Type::WordPtr, Type::WordPtr, i512Ty->getPointerTo()}; - auto mul512 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, mul512ArgTypes, false), llvm::Function::ExternalLinkage, "arith_mul512", getModule()); - auto x = &m_mulmod->getArgumentList().front(); x->setName("x"); auto y = x->getNextNode(); @@ -285,13 +320,7 @@ llvm::Function* Arith256::getMulModFunc() auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word); - auto a2 = m_builder.CreateAlloca(Type::Word); - auto a3 = m_builder.CreateAlloca(i512Ty); - m_builder.CreateStore(x, a1); - m_builder.CreateStore(y, a2); - createCall(mul512, {a1, a2, a3}); - auto p = m_builder.CreateLoad(a3, "p"); + auto p = createCall(getMul512Func(), {x, y}); auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); @@ -350,157 +379,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } -namespace -{ -#ifdef __SIZEOF_INT128__ - using uint128 = __uint128_t; -#else - struct uint128 - { - uint64_t lo = 0; - uint64_t hi = 0; - - uint128(uint64_t lo) : lo(lo) {} - - uint128 operator+(uint128 a) - { - uint128 r = 0; - bool overflow = lo > std::numeric_limits::max() - a.lo; - r.lo = lo + a.lo; - r.hi = hi + a.hi + overflow; - return r; - } - - uint128 operator>>(int s) - { - assert(s == 64); - return hi; - } - - uint128 operator<<(int s) - { - assert(s == 64); - uint128 r = 0; - r.hi = lo; - return r; - } - - explicit operator uint64_t() { return lo; } - - static uint128 mul(uint64_t a, uint64_t b) - { - auto x_lo = 0xFFFFFFFF & a; - auto y_lo = 0xFFFFFFFF & b; - auto x_hi = a >> 32; - auto y_hi = b >> 32; - - auto t1 = x_lo * y_lo; - auto t2 = x_lo * y_hi; - auto t3 = x_hi * y_lo; - auto t4 = x_hi * y_hi; - - auto lo = (uint32_t)t1; - auto mid = (uint64_t)(t1 >> 32) + (uint32_t)t2 + (uint32_t)t3; - auto hi = (uint64_t)(t2 >> 32) + (t3 >> 32) + t4 + (mid >> 32); - - uint128 r = 0; - r.lo = (uint64_t)lo + (mid << 32); - r.hi = hi; - return r; - } - - uint128 operator*(uint128 a) - { - auto t1 = mul(lo, a.lo); - auto t2 = mul(lo, a.hi); - auto t3 = mul(hi, a.lo); - return t1 + (t2 << 64) + (t3 << 64); - } - }; -#endif - - struct uint256 - { - uint64_t lo = 0; - uint64_t mid = 0; - uint128 hi = 0; - - uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {} - uint256(uint128 n) - { - lo = (uint64_t) n; - mid = (uint64_t) (n >> 64); - } - - explicit operator uint128() - { - uint128 r = lo; - r |= ((uint128) mid) << 64; - return r; - } - - uint256 operator+(uint256 a) - { - auto _lo = (uint128) lo + a.lo; - auto _mid = (uint128) mid + a.mid + (_lo >> 64); - auto _hi = hi + a.hi + (_mid >> 64); - return {(uint64_t)_lo, (uint64_t)_mid, _hi}; - } - - uint256 lo2hi() - { - hi = (uint128)*this; - lo = 0; - mid = 0; - return *this; - } - }; - - struct uint512 - { - uint128 lo; - uint128 mid; - uint256 hi; - }; - - uint256 mul(uint256 x, uint256 y) - { - auto t1 = (uint128) x.lo * y.lo; - auto t2 = (uint128) x.lo * y.mid; - auto t3 = (uint128) x.lo * y.hi; - auto t4 = (uint128) x.mid * y.lo; - auto t5 = (uint128) x.mid * y.mid; - auto t6 = (uint128) x.mid * y.hi; - auto t7 = x.hi * y.lo; - auto t8 = x.hi * y.mid; - - auto lo = (uint64_t) t1; - auto m1 = (t1 >> 64) + (uint64_t) t2; - auto m2 = (uint64_t) m1; - auto mid = (uint128) m2 + (uint64_t) t4; - auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7 - + (t8 << 64) + (m1 >> 64) + (mid >> 64); - - return {lo, (uint64_t)mid, hi}; - } - - uint512 mul512(uint256 x, uint256 y) - { - auto x_lo = (uint128) x; - auto y_lo = (uint128) y; - - auto t1 = mul(x_lo, y_lo); - auto t2 = mul(x_lo, y.hi); - auto t3 = mul(x.hi, y_lo); - auto t4 = mul(x.hi, y.hi); - - auto lo = (uint128) t1; - auto mid = (uint256) t1.hi + (uint128) t2 + (uint128) t3; - auto hi = (uint256)t2.hi + t3.hi + t4 + mid.hi; - - return {lo, (uint128)mid, hi}; - } -} } } @@ -508,15 +386,8 @@ namespace extern "C" { - using namespace dev::eth::jit; - EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) - { - *o_result = mul512(*_arg1, *_arg2); - } } diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index f8f1c9eb2..2513ca568 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -25,12 +25,14 @@ public: private: llvm::Function* getMulFunc(); + llvm::Function* getMul512Func(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); llvm::Function* m_mul = nullptr; + llvm::Function* m_mul512 = nullptr; llvm::Function* m_div = nullptr; llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; From 99b7607ae295f09063fc7164b66bc7c3bfa2279b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 16:47:38 +0100 Subject: [PATCH 049/118] Use code (and code size) as constants --- evmjit/libevmjit/Compiler.cpp | 2 +- evmjit/libevmjit/ExecutionEngine.cpp | 1 + evmjit/libevmjit/RuntimeManager.cpp | 13 ++++++++----- evmjit/libevmjit/RuntimeManager.h | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index b9d0143f1..02e2e920a 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -142,7 +142,7 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder); + RuntimeManager runtimeManager(m_builder, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 6c1bc5c3b..bc1202e79 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -174,6 +174,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) std::unique_ptr memoryManager(new llvm::SectionMemoryManager); builder.setMCJITMemoryManager(memoryManager.get()); builder.setOptLevel(llvm::CodeGenOpt::None); + builder.setVerifyModules(true); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 6d6cc09a0..98386e1fe 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -87,7 +87,10 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) { m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); @@ -191,14 +194,14 @@ llvm::Value* RuntimeManager::getCallData() llvm::Value* RuntimeManager::getCode() { - return get(RuntimeData::Code); + // OPT Check what is faster + //return get(RuntimeData::Code); + return m_builder.CreateGlobalStringPtr({reinterpret_cast(m_codeBegin), static_cast(m_codeEnd - m_codeBegin)}, "code"); } llvm::Value* RuntimeManager::getCodeSize() { - auto value = get(RuntimeData::CodeSize); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + return Constant::get(m_codeEnd - m_codeBegin); } llvm::Value* RuntimeManager::getCallDataSize() diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index e483f67cd..b3ce6f997 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -15,11 +15,11 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder); + RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); - llvm::Value* getEnvPtr(); // TODO: Can we make it const? + llvm::Value* getEnvPtr(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); @@ -47,6 +47,9 @@ private: llvm::Function* m_longjmp = nullptr; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; }; } From f70b7f5fd2db6f1d07780bd51fe6c785a2ed95be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 16:47:38 +0100 Subject: [PATCH 050/118] Use code (and code size) as constants --- libevmjit/Compiler.cpp | 2 +- libevmjit/ExecutionEngine.cpp | 1 + libevmjit/RuntimeManager.cpp | 13 ++++++++----- libevmjit/RuntimeManager.h | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index b9d0143f1..02e2e920a 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -142,7 +142,7 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder); + RuntimeManager runtimeManager(m_builder, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 6c1bc5c3b..bc1202e79 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -174,6 +174,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) std::unique_ptr memoryManager(new llvm::SectionMemoryManager); builder.setMCJITMemoryManager(memoryManager.get()); builder.setOptLevel(llvm::CodeGenOpt::None); + builder.setVerifyModules(true); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 6d6cc09a0..98386e1fe 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -87,7 +87,10 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) { m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); @@ -191,14 +194,14 @@ llvm::Value* RuntimeManager::getCallData() llvm::Value* RuntimeManager::getCode() { - return get(RuntimeData::Code); + // OPT Check what is faster + //return get(RuntimeData::Code); + return m_builder.CreateGlobalStringPtr({reinterpret_cast(m_codeBegin), static_cast(m_codeEnd - m_codeBegin)}, "code"); } llvm::Value* RuntimeManager::getCodeSize() { - auto value = get(RuntimeData::CodeSize); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + return Constant::get(m_codeEnd - m_codeBegin); } llvm::Value* RuntimeManager::getCallDataSize() diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index e483f67cd..b3ce6f997 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -15,11 +15,11 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder); + RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); - llvm::Value* getEnvPtr(); // TODO: Can we make it const? + llvm::Value* getEnvPtr(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); @@ -47,6 +47,9 @@ private: llvm::Function* m_longjmp = nullptr; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; }; } From 4c58e6ffa59ab2a3aaa30ff645dbfff831b9afcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 18:33:27 +0100 Subject: [PATCH 051/118] Create memory helper functions on demand --- evmjit/libevmjit/Memory.cpp | 171 ++++++++++++++++++++---------------- evmjit/libevmjit/Memory.h | 15 ++-- 2 files changed, 106 insertions(+), 80 deletions(-) diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index c212b2d1a..6a46fa8ca 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -26,78 +26,77 @@ namespace jit Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} +{} -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +llvm::Function* Memory::getRequireFunc() { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - // BB "Pre": Ignore checks with size 0 - m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); + auto& func = m_require; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder)); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + m_gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } return func; } @@ -143,21 +142,45 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet return func; } +llvm::Function* Memory::getLoadWordFunc() +{ + auto& func = m_loadWord; + if (!func) + func = createFunc(false, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreWordFunc() +{ + auto& func = m_storeWord; + if (!func) + func = createFunc(true, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreByteFunc() +{ + auto& func = m_storeByte; + if (!func) + func = createFunc(true, Type::Byte, m_gasMeter); + return func; +} + llvm::Value* Memory::loadWord(llvm::Value* _addr) { - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); + createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); } void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); } llvm::Value* Memory::getData() @@ -187,7 +210,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) if (!constant->getValue()) return; } - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h index ed9c51805..e8edce735 100644 --- a/evmjit/libevmjit/Memory.h +++ b/evmjit/libevmjit/Memory.h @@ -31,13 +31,16 @@ private: GasMeter& m_gasMeter; llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; + llvm::Function* getRequireFunc(); + llvm::Function* getLoadWordFunc(); + llvm::Function* getStoreWordFunc(); + llvm::Function* getStoreByteFunc(); + + llvm::Function* m_require = nullptr; + llvm::Function* m_loadWord = nullptr; + llvm::Function* m_storeWord = nullptr; + llvm::Function* m_storeByte = nullptr; }; } From 3fe31f0b800232a0602cc63cb02252f112a2d98e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 18:33:27 +0100 Subject: [PATCH 052/118] Create memory helper functions on demand --- libevmjit/Memory.cpp | 171 ++++++++++++++++++++++++------------------- libevmjit/Memory.h | 15 ++-- 2 files changed, 106 insertions(+), 80 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c212b2d1a..6a46fa8ca 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -26,78 +26,77 @@ namespace jit Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} +{} -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +llvm::Function* Memory::getRequireFunc() { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - // BB "Pre": Ignore checks with size 0 - m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); + auto& func = m_require; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder)); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + m_gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } return func; } @@ -143,21 +142,45 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet return func; } +llvm::Function* Memory::getLoadWordFunc() +{ + auto& func = m_loadWord; + if (!func) + func = createFunc(false, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreWordFunc() +{ + auto& func = m_storeWord; + if (!func) + func = createFunc(true, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreByteFunc() +{ + auto& func = m_storeByte; + if (!func) + func = createFunc(true, Type::Byte, m_gasMeter); + return func; +} + llvm::Value* Memory::loadWord(llvm::Value* _addr) { - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); + createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); } void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); } llvm::Value* Memory::getData() @@ -187,7 +210,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) if (!constant->getValue()) return; } - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index ed9c51805..e8edce735 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -31,13 +31,16 @@ private: GasMeter& m_gasMeter; llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; + llvm::Function* getRequireFunc(); + llvm::Function* getLoadWordFunc(); + llvm::Function* getStoreWordFunc(); + llvm::Function* getStoreByteFunc(); + + llvm::Function* m_require = nullptr; + llvm::Function* m_loadWord = nullptr; + llvm::Function* m_storeWord = nullptr; + llvm::Function* m_storeByte = nullptr; }; } From f203843114a192dee037aad2a5a614e1bb3b5b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:04:54 +0100 Subject: [PATCH 053/118] Stats for execution states times --- evmjit/libevmjit/Cache.cpp | 29 +++++++---- evmjit/libevmjit/Cache.h | 7 +-- evmjit/libevmjit/ExecStats.cpp | 77 ++++++++++++++++++++++++++-- evmjit/libevmjit/ExecStats.h | 27 +++++++--- evmjit/libevmjit/ExecutionEngine.cpp | 67 +++++------------------- evmjit/libevmjit/ExecutionEngine.h | 35 ++++++++++--- 6 files changed, 153 insertions(+), 89 deletions(-) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index 0e6fb517a..305b97d5c 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "ExecutionEngine.h" namespace dev { @@ -18,20 +19,25 @@ namespace jit //#define LOG(...) std::cerr << "CACHE " #define LOG(...) std::ostream(nullptr) -ObjectCache* Cache::getObjectCache() +namespace { - static ObjectCache objectCache; - return &objectCache; + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; } -namespace +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) { - llvm::MemoryBuffer* lastObject; + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; } std::unique_ptr Cache::getObject(std::string const& id) { - assert(!lastObject); + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); @@ -51,11 +57,11 @@ std::unique_ptr Cache::getObject(std::string const& id) #endif if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) std::cerr << r.getError().message(); // TODO: Add log - if (lastObject) // if object found create fake module + if (g_lastObject) // if object found create fake module { auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); @@ -67,6 +73,9 @@ std::unique_ptr Cache::getObject(std::string const& id) void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { + if (g_listener) + g_listener->stateChanged(ExecState::CacheWrite); + auto&& id = _module->getModuleIdentifier(); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -84,8 +93,8 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) { - auto o = lastObject; - lastObject = nullptr; + auto o = g_lastObject; + g_lastObject = nullptr; return o; } diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h index 1cad537cd..d7b32c651 100644 --- a/evmjit/libevmjit/Cache.h +++ b/evmjit/libevmjit/Cache.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include @@ -11,6 +10,7 @@ namespace eth { namespace jit { +class ExecutionEngineListener; class ObjectCache : public llvm::ObjectCache { @@ -23,16 +23,13 @@ public: /// not available. The caller owns both the MemoryBuffer returned by this /// and the memory it references. virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; - -private: - std::unordered_map> m_map; }; class Cache { public: - static ObjectCache* getObjectCache(); + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); static std::unique_ptr getObject(std::string const& id); }; diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index e3f5293f8..deb322521 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -1,4 +1,7 @@ #include "ExecStats.h" +#include +#include +#include namespace dev { @@ -7,14 +10,80 @@ namespace eth namespace jit { -void ExecStats::execStarted() +void ExecStats::stateChanged(ExecState _state) { - m_tp = std::chrono::high_resolution_clock::now(); + assert(m_state != ExecState::Finished); + auto now = clock::now(); + if (_state != ExecState::Started) + { + assert(time[(int)m_state] == ExecStats::duration::zero()); + time[(int)m_state] = now - m_tp; + } + m_state = _state; + m_tp = now; } -void ExecStats::execEnded() +namespace { - execTime = std::chrono::high_resolution_clock::now() - m_tp; +struct StatsAgg +{ + using unit = std::chrono::microseconds; + ExecStats::duration tot = ExecStats::duration::zero(); + ExecStats::duration min = ExecStats::duration::max(); + ExecStats::duration max = ExecStats::duration::zero(); + size_t count = 0; + + void update(ExecStats::duration _d) + { + ++count; + tot += _d; + min = _d < min ? _d : min; + max = _d > max ? _d : max; + } + + void output(char const* _name, std::ostream& _os) + { + auto avg = tot / count; + _os << std::setw(12) << std::left << _name + << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() + << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() + << std::setw(10) << std::right << std::chrono::duration_cast(min).count() + << std::setw(10) << std::right << std::chrono::duration_cast(max).count() + << std::endl; + } +}; + +char const* getExecStateName(ExecState _state) +{ + switch (_state) + { + case ExecState::Started: return "Start"; + case ExecState::CacheLoad: return "CacheLoad"; + case ExecState::CacheWrite: return "CacheWrite"; + case ExecState::Compilation: return "Compilation"; + case ExecState::CodeGen: return "CodeGen"; + case ExecState::Execution: return "Execution"; + case ExecState::Return: return "Return"; + case ExecState::Finished: return "Finish"; + } + return nullptr; +} +} + +StatsCollector::~StatsCollector() +{ + if (stats.empty()) + return; + + std::cout << " [us] total avg min max\n"; + for (int i = 0; i < (int)ExecState::Finished; ++i) + { + StatsAgg agg; + for (auto&& s : stats) + agg.update(s->time[i]); + + agg.output(getExecStateName(ExecState(i)), std::cout); + } } } diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h index 3ee730836..284ecad7b 100644 --- a/evmjit/libevmjit/ExecStats.h +++ b/evmjit/libevmjit/ExecStats.h @@ -2,6 +2,7 @@ #include #include +#include "ExecutionEngine.h" namespace dev { @@ -10,21 +11,31 @@ namespace eth namespace jit { -class ExecStats +class ExecStats : public ExecutionEngineListener { public: + using clock = std::chrono::high_resolution_clock; + using duration = clock::duration; + using time_point = clock::time_point; + std::string id; - std::chrono::high_resolution_clock::duration compileTime; - std::chrono::high_resolution_clock::duration codegenTime; - std::chrono::high_resolution_clock::duration cacheLoadTime; - std::chrono::high_resolution_clock::duration execTime; + duration time[(int)ExecState::Finished] = {}; - void execStarted(); - void execEnded(); + void stateChanged(ExecState _state) override; private: - std::chrono::high_resolution_clock::time_point m_tp; + ExecState m_state = {}; + time_point m_tp = {}; + +}; + + +class StatsCollector +{ +public: + std::vector> stats; + ~StatsCollector(); }; } diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index bc1202e79..dd545cd03 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Compiler.h" #include "Cache.h" +#include "ExecStats.h" #include "BuildInfo.gen.h" #include @@ -83,50 +84,6 @@ bool showInfo() return show; } -class StatsCollector -{ -public: - std::vector> stats; - - ~StatsCollector() - { - if (stats.empty()) - return; - - using d = decltype(ExecStats{}.execTime); - d total = d::zero(); - d max = d::zero(); - d min = d::max(); - - for (auto&& s : stats) - { - auto t = s->execTime; - total += t; - if (t < min) - min = t; - if (t > max) - max = t; - } - - using u = std::chrono::microseconds; - auto nTotal = std::chrono::duration_cast(total).count(); - auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); - auto nMax = std::chrono::duration_cast(max).count(); - auto nMin = std::chrono::duration_cast(min).count(); - - std::cout << "Total exec time: " << nTotal << " us" << std::endl - << "Averge exec time: " << nAverage << " us" << std::endl - << "Min exec time: " << nMin << " us" << std::endl - << "Max exec time: " << nMax << " us" << std::endl; - } -}; - -} - -void ExecutionEngine::collectStats() -{ - if (!m_stats) - m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -140,8 +97,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static StatsCollector statsCollector; - if (statsCollectingEnabled) - collectStats(); + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; @@ -155,12 +112,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } else { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; std::unique_ptr module; if (objectCache) module = Cache::getObject(mainFuncName); if (!module) + { + listener->stateChanged(ExecState::Compilation); module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + } if (debugDumpModule) module->dump(); if (!ee) @@ -190,6 +150,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (objectCache) ee->setObjectCache(objectCache); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else @@ -198,28 +159,26 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { ee->addModule(module.get()); module.release(); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } } } assert(entryFuncPtr); - if (m_stats) - m_stats->execStarted(); - + listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); - - if (m_stats) - m_stats->execEnded(); + listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } + listener->stateChanged(ExecState::Finished); if (statsCollectingEnabled) - statsCollector.stats.push_back(std::move(m_stats)); + statsCollector.stats.push_back(std::move(listener)); return returnCode; } diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index e12f86af4..101475b11 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -2,7 +2,6 @@ #include #include "RuntimeData.h" -#include "ExecStats.h" namespace dev { @@ -11,19 +10,41 @@ namespace eth namespace jit { +enum class ExecState +{ + Started, + CacheLoad, + CacheWrite, + Compilation, + CodeGen, + Execution, + Return, + Finished +}; + +class ExecutionEngineListener +{ +public: + ExecutionEngineListener() = default; + ExecutionEngineListener(ExecutionEngineListener const&) = delete; + ExecutionEngineListener& operator=(ExecutionEngineListener) = delete; + virtual ~ExecutionEngineListener() {} + + virtual void executionStarted() {} + virtual void executionEnded() {} + + virtual void stateChanged(ExecState) {} +}; + class ExecutionEngine { public: ExecutionEngine() = default; ExecutionEngine(ExecutionEngine const&) = delete; - void operator=(ExecutionEngine) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; EXPORT ReturnCode run(RuntimeData* _data, Env* _env); - void collectStats(); - - std::unique_ptr getStats(); - /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -31,8 +52,6 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; - - std::unique_ptr m_stats; }; } From 83701a2fcda281faaf3d58f39b2fcc220ca4d150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:04:54 +0100 Subject: [PATCH 054/118] Stats for execution states times --- libevmjit/Cache.cpp | 29 ++++++++----- libevmjit/Cache.h | 7 +--- libevmjit/ExecStats.cpp | 77 +++++++++++++++++++++++++++++++++-- libevmjit/ExecStats.h | 27 ++++++++---- libevmjit/ExecutionEngine.cpp | 67 ++++++------------------------ libevmjit/ExecutionEngine.h | 35 ++++++++++++---- 6 files changed, 153 insertions(+), 89 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 0e6fb517a..305b97d5c 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "ExecutionEngine.h" namespace dev { @@ -18,20 +19,25 @@ namespace jit //#define LOG(...) std::cerr << "CACHE " #define LOG(...) std::ostream(nullptr) -ObjectCache* Cache::getObjectCache() +namespace { - static ObjectCache objectCache; - return &objectCache; + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; } -namespace +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) { - llvm::MemoryBuffer* lastObject; + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; } std::unique_ptr Cache::getObject(std::string const& id) { - assert(!lastObject); + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); @@ -51,11 +57,11 @@ std::unique_ptr Cache::getObject(std::string const& id) #endif if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) std::cerr << r.getError().message(); // TODO: Add log - if (lastObject) // if object found create fake module + if (g_lastObject) // if object found create fake module { auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); @@ -67,6 +73,9 @@ std::unique_ptr Cache::getObject(std::string const& id) void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { + if (g_listener) + g_listener->stateChanged(ExecState::CacheWrite); + auto&& id = _module->getModuleIdentifier(); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -84,8 +93,8 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) { - auto o = lastObject; - lastObject = nullptr; + auto o = g_lastObject; + g_lastObject = nullptr; return o; } diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 1cad537cd..d7b32c651 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include @@ -11,6 +10,7 @@ namespace eth { namespace jit { +class ExecutionEngineListener; class ObjectCache : public llvm::ObjectCache { @@ -23,16 +23,13 @@ public: /// not available. The caller owns both the MemoryBuffer returned by this /// and the memory it references. virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; - -private: - std::unordered_map> m_map; }; class Cache { public: - static ObjectCache* getObjectCache(); + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); static std::unique_ptr getObject(std::string const& id); }; diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp index e3f5293f8..deb322521 100644 --- a/libevmjit/ExecStats.cpp +++ b/libevmjit/ExecStats.cpp @@ -1,4 +1,7 @@ #include "ExecStats.h" +#include +#include +#include namespace dev { @@ -7,14 +10,80 @@ namespace eth namespace jit { -void ExecStats::execStarted() +void ExecStats::stateChanged(ExecState _state) { - m_tp = std::chrono::high_resolution_clock::now(); + assert(m_state != ExecState::Finished); + auto now = clock::now(); + if (_state != ExecState::Started) + { + assert(time[(int)m_state] == ExecStats::duration::zero()); + time[(int)m_state] = now - m_tp; + } + m_state = _state; + m_tp = now; } -void ExecStats::execEnded() +namespace { - execTime = std::chrono::high_resolution_clock::now() - m_tp; +struct StatsAgg +{ + using unit = std::chrono::microseconds; + ExecStats::duration tot = ExecStats::duration::zero(); + ExecStats::duration min = ExecStats::duration::max(); + ExecStats::duration max = ExecStats::duration::zero(); + size_t count = 0; + + void update(ExecStats::duration _d) + { + ++count; + tot += _d; + min = _d < min ? _d : min; + max = _d > max ? _d : max; + } + + void output(char const* _name, std::ostream& _os) + { + auto avg = tot / count; + _os << std::setw(12) << std::left << _name + << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() + << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() + << std::setw(10) << std::right << std::chrono::duration_cast(min).count() + << std::setw(10) << std::right << std::chrono::duration_cast(max).count() + << std::endl; + } +}; + +char const* getExecStateName(ExecState _state) +{ + switch (_state) + { + case ExecState::Started: return "Start"; + case ExecState::CacheLoad: return "CacheLoad"; + case ExecState::CacheWrite: return "CacheWrite"; + case ExecState::Compilation: return "Compilation"; + case ExecState::CodeGen: return "CodeGen"; + case ExecState::Execution: return "Execution"; + case ExecState::Return: return "Return"; + case ExecState::Finished: return "Finish"; + } + return nullptr; +} +} + +StatsCollector::~StatsCollector() +{ + if (stats.empty()) + return; + + std::cout << " [us] total avg min max\n"; + for (int i = 0; i < (int)ExecState::Finished; ++i) + { + StatsAgg agg; + for (auto&& s : stats) + agg.update(s->time[i]); + + agg.output(getExecStateName(ExecState(i)), std::cout); + } } } diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h index 3ee730836..284ecad7b 100644 --- a/libevmjit/ExecStats.h +++ b/libevmjit/ExecStats.h @@ -2,6 +2,7 @@ #include #include +#include "ExecutionEngine.h" namespace dev { @@ -10,21 +11,31 @@ namespace eth namespace jit { -class ExecStats +class ExecStats : public ExecutionEngineListener { public: + using clock = std::chrono::high_resolution_clock; + using duration = clock::duration; + using time_point = clock::time_point; + std::string id; - std::chrono::high_resolution_clock::duration compileTime; - std::chrono::high_resolution_clock::duration codegenTime; - std::chrono::high_resolution_clock::duration cacheLoadTime; - std::chrono::high_resolution_clock::duration execTime; + duration time[(int)ExecState::Finished] = {}; - void execStarted(); - void execEnded(); + void stateChanged(ExecState _state) override; private: - std::chrono::high_resolution_clock::time_point m_tp; + ExecState m_state = {}; + time_point m_tp = {}; + +}; + + +class StatsCollector +{ +public: + std::vector> stats; + ~StatsCollector(); }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index bc1202e79..dd545cd03 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Compiler.h" #include "Cache.h" +#include "ExecStats.h" #include "BuildInfo.gen.h" #include @@ -83,50 +84,6 @@ bool showInfo() return show; } -class StatsCollector -{ -public: - std::vector> stats; - - ~StatsCollector() - { - if (stats.empty()) - return; - - using d = decltype(ExecStats{}.execTime); - d total = d::zero(); - d max = d::zero(); - d min = d::max(); - - for (auto&& s : stats) - { - auto t = s->execTime; - total += t; - if (t < min) - min = t; - if (t > max) - max = t; - } - - using u = std::chrono::microseconds; - auto nTotal = std::chrono::duration_cast(total).count(); - auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); - auto nMax = std::chrono::duration_cast(max).count(); - auto nMin = std::chrono::duration_cast(min).count(); - - std::cout << "Total exec time: " << nTotal << " us" << std::endl - << "Averge exec time: " << nAverage << " us" << std::endl - << "Min exec time: " << nMin << " us" << std::endl - << "Max exec time: " << nMax << " us" << std::endl; - } -}; - -} - -void ExecutionEngine::collectStats() -{ - if (!m_stats) - m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -140,8 +97,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static StatsCollector statsCollector; - if (statsCollectingEnabled) - collectStats(); + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; @@ -155,12 +112,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } else { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; std::unique_ptr module; if (objectCache) module = Cache::getObject(mainFuncName); if (!module) + { + listener->stateChanged(ExecState::Compilation); module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + } if (debugDumpModule) module->dump(); if (!ee) @@ -190,6 +150,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (objectCache) ee->setObjectCache(objectCache); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else @@ -198,28 +159,26 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { ee->addModule(module.get()); module.release(); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } } } assert(entryFuncPtr); - if (m_stats) - m_stats->execStarted(); - + listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); - - if (m_stats) - m_stats->execEnded(); + listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } + listener->stateChanged(ExecState::Finished); if (statsCollectingEnabled) - statsCollector.stats.push_back(std::move(m_stats)); + statsCollector.stats.push_back(std::move(listener)); return returnCode; } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index e12f86af4..101475b11 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -2,7 +2,6 @@ #include #include "RuntimeData.h" -#include "ExecStats.h" namespace dev { @@ -11,19 +10,41 @@ namespace eth namespace jit { +enum class ExecState +{ + Started, + CacheLoad, + CacheWrite, + Compilation, + CodeGen, + Execution, + Return, + Finished +}; + +class ExecutionEngineListener +{ +public: + ExecutionEngineListener() = default; + ExecutionEngineListener(ExecutionEngineListener const&) = delete; + ExecutionEngineListener& operator=(ExecutionEngineListener) = delete; + virtual ~ExecutionEngineListener() {} + + virtual void executionStarted() {} + virtual void executionEnded() {} + + virtual void stateChanged(ExecState) {} +}; + class ExecutionEngine { public: ExecutionEngine() = default; ExecutionEngine(ExecutionEngine const&) = delete; - void operator=(ExecutionEngine) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; EXPORT ReturnCode run(RuntimeData* _data, Env* _env); - void collectStats(); - - std::unique_ptr getStats(); - /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -31,8 +52,6 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; - - std::unique_ptr m_stats; }; } From 8fd2b949c147bc0a5723f60e9e164282d9a4a257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:55:46 +0100 Subject: [PATCH 055/118] Fix cache bug: code was always compiled --- libevmjit/Cache.cpp | 20 ++++++++++++++------ libevmjit/ExecutionEngine.cpp | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 305b97d5c..e6d76beba 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -16,8 +16,8 @@ namespace eth namespace jit { -//#define LOG(...) std::cerr << "CACHE " -#define LOG(...) std::ostream(nullptr) +//#define CACHE_LOG std::cerr << "CACHE " +#define CACHE_LOG std::ostream(nullptr) namespace { @@ -37,6 +37,7 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_listener) g_listener->stateChanged(ExecState::CacheLoad); + CACHE_LOG << id << ": search\n"; assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -63,10 +64,15 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_lastObject) // if object found create fake module { - auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); - auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + CACHE_LOG << id << ": found\n"; + auto&& context = llvm::getGlobalContext(); + auto module = std::unique_ptr(new llvm::Module(id, context)); + auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); + auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + return module; } + CACHE_LOG << id << ": not found\n"; return nullptr; } @@ -86,13 +92,15 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::sys::path::append(cachePath, id); + CACHE_LOG << id << ": write\n"; std::string error; llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); cacheFile << _object->getBuffer(); } -llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { + CACHE_LOG << _module->getModuleIdentifier() << ": use\n"; auto o = g_lastObject; g_lastObject = nullptr; return o; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index dd545cd03..59764eaff 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -164,7 +164,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } } } - assert(entryFuncPtr); + assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); From ddf4724ce134d8176bc1adbdf8fa02a38daaeba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:55:46 +0100 Subject: [PATCH 056/118] Fix cache bug: code was always compiled --- evmjit/libevmjit/Cache.cpp | 20 ++++++++++++++------ evmjit/libevmjit/ExecutionEngine.cpp | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index 305b97d5c..e6d76beba 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -16,8 +16,8 @@ namespace eth namespace jit { -//#define LOG(...) std::cerr << "CACHE " -#define LOG(...) std::ostream(nullptr) +//#define CACHE_LOG std::cerr << "CACHE " +#define CACHE_LOG std::ostream(nullptr) namespace { @@ -37,6 +37,7 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_listener) g_listener->stateChanged(ExecState::CacheLoad); + CACHE_LOG << id << ": search\n"; assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -63,10 +64,15 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_lastObject) // if object found create fake module { - auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); - auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + CACHE_LOG << id << ": found\n"; + auto&& context = llvm::getGlobalContext(); + auto module = std::unique_ptr(new llvm::Module(id, context)); + auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); + auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + return module; } + CACHE_LOG << id << ": not found\n"; return nullptr; } @@ -86,13 +92,15 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::sys::path::append(cachePath, id); + CACHE_LOG << id << ": write\n"; std::string error; llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); cacheFile << _object->getBuffer(); } -llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { + CACHE_LOG << _module->getModuleIdentifier() << ": use\n"; auto o = g_lastObject; g_lastObject = nullptr; return o; diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index dd545cd03..59764eaff 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -164,7 +164,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } } } - assert(entryFuncPtr); + assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); From 699ab0045cc220fb7c2603ecffddf2e316e86d55 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Fri, 6 Feb 2015 00:29:03 +0800 Subject: [PATCH 057/118] fix Mac build error for evmjit We need to include , otherwise it complains: cpp-ethereum/evmjit/libevmjit/ExecutionEngine.cpp:147:2: error: implicit instantiation of undefined template 'std::__1::basic_ostream >' clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).cou... ^ cpp-ethereum/evmjit/libevmjit/Utils.h:15:23: note: expanded from macro 'clog' #define clog(CHANNEL) std::ostream(nullptr) ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iosfwd:111:33: note: template is declared here class _LIBCPP_TYPE_VIS_ONLY basic_ostream; ^ --- libevmjit/Utils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 1e6705667..7e6133ced 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "Common.h" namespace dev From 49893ce8916cb3ea7cc216125131c868edebd0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:39:36 +0100 Subject: [PATCH 058/118] Add `unreachable` instruction to fake module generated by Cache --- libevmjit/Cache.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index e6d76beba..cad3f2094 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,8 @@ std::unique_ptr Cache::getObject(std::string const& id) auto module = std::unique_ptr(new llvm::Module(id, context)); auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); - llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); return module; } CACHE_LOG << id << ": not found\n"; From cbc1c99beb059444014670581fecc8b47a8c3630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:39:36 +0100 Subject: [PATCH 059/118] Add `unreachable` instruction to fake module generated by Cache --- evmjit/libevmjit/Cache.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index e6d76beba..cad3f2094 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,8 @@ std::unique_ptr Cache::getObject(std::string const& id) auto module = std::unique_ptr(new llvm::Module(id, context)); auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); - llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); return module; } CACHE_LOG << id << ": not found\n"; From 9640644f7237b5763f88a231027d847d88cc06cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:46:28 +0100 Subject: [PATCH 060/118] Place warning pragmas for LLVM includes in separated files --- libevmjit/ExecutionEngine.cpp | 8 ++------ libevmjit/preprocessor/llvm_includes_end.h | 3 +++ libevmjit/preprocessor/llvm_includes_start.h | 4 ++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 libevmjit/preprocessor/llvm_includes_end.h create mode 100644 libevmjit/preprocessor/llvm_includes_start.h diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 59764eaff..ef62e8441 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -2,19 +2,15 @@ #include #include // env options - +#include "preprocessor/llvm_includes_start.h" #include #include -#pragma warning(push) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include #include -#pragma warning(pop) -#pragma GCC diagnostic pop #include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Runtime.h" #include "Compiler.h" diff --git a/libevmjit/preprocessor/llvm_includes_end.h b/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..3a47dca15 --- /dev/null +++ b/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,3 @@ + +#pragma warning(pop) +#pragma GCC diagnostic pop diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..6600886f4 --- /dev/null +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,4 @@ + +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" From 33205fb9c954aa078d499c26dd3bf6a9fe287632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:46:28 +0100 Subject: [PATCH 061/118] Place warning pragmas for LLVM includes in separated files --- evmjit/libevmjit/ExecutionEngine.cpp | 8 ++------ evmjit/libevmjit/preprocessor/llvm_includes_end.h | 3 +++ evmjit/libevmjit/preprocessor/llvm_includes_start.h | 4 ++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 evmjit/libevmjit/preprocessor/llvm_includes_end.h create mode 100644 evmjit/libevmjit/preprocessor/llvm_includes_start.h diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 59764eaff..ef62e8441 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -2,19 +2,15 @@ #include #include // env options - +#include "preprocessor/llvm_includes_start.h" #include #include -#pragma warning(push) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include #include -#pragma warning(pop) -#pragma GCC diagnostic pop #include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Runtime.h" #include "Compiler.h" diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_end.h b/evmjit/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..3a47dca15 --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,3 @@ + +#pragma warning(pop) +#pragma GCC diagnostic pop diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_start.h b/evmjit/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..6600886f4 --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,4 @@ + +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" From 4bcee00be98ac55a659f3f866136e4b5ab17dc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 17:11:24 +0100 Subject: [PATCH 062/118] #include cleanups --- libevmjit/Arith256.cpp | 3 +- libevmjit/Arith256.h | 1 - libevmjit/BasicBlock.cpp | 14 +- libevmjit/BasicBlock.h | 3 +- libevmjit/Cache.cpp | 11 +- libevmjit/Cache.h | 4 +- libevmjit/Common.h | 1 - libevmjit/Compiler.cpp | 29 ++-- libevmjit/Compiler.h | 4 - libevmjit/CompilerHelper.cpp | 98 ++++++------ libevmjit/CompilerHelper.h | 153 ++++++++++--------- libevmjit/Endianness.cpp | 76 ++++----- libevmjit/Endianness.h | 49 +++--- libevmjit/ExecStats.h | 4 +- libevmjit/ExecutionEngine.cpp | 15 +- libevmjit/ExecutionEngine.h | 3 +- libevmjit/Ext.cpp | 10 +- libevmjit/Ext.h | 4 +- libevmjit/GasMeter.cpp | 12 +- libevmjit/GasMeter.h | 2 - libevmjit/Instruction.cpp | 4 +- libevmjit/Instruction.h | 1 - libevmjit/Memory.cpp | 15 +- libevmjit/Memory.h | 1 - libevmjit/Runtime.cpp | 6 +- libevmjit/Runtime.h | 4 +- libevmjit/RuntimeData.h | 4 +- libevmjit/RuntimeManager.cpp | 10 +- libevmjit/RuntimeManager.h | 1 - libevmjit/Stack.cpp | 2 - libevmjit/Stack.h | 83 +++++----- libevmjit/Type.cpp | 4 - libevmjit/Type.h | 7 +- libevmjit/Utils.cpp | 1 - libevmjit/Utils.h | 1 - libevmjit/preprocessor/llvm_includes_start.h | 1 + 36 files changed, 296 insertions(+), 345 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index a77050adc..6ae62b9d3 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -3,8 +3,9 @@ #include "Type.h" #include "Endianness.h" -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 2513ca568..4b94652d8 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index c71bae94f..112e9d652 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,15 +1,15 @@ - #include "BasicBlock.h" +#include "Type.h" -#include - +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include +#include "preprocessor/llvm_includes_end.h" -#include "Type.h" +#include namespace dev { @@ -141,7 +141,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) auto endIter = m_currentStack.end(); // Update (emit set()) changed values - for (int idx = m_currentStack.size() - 1 - m_tosOffset; + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; currIter < endIter && idx >= 0; ++currIter, --idx) { @@ -308,7 +308,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: - bblock.m_tosOffset += info.inputItems; + bblock.m_tosOffset += (int)info.inputItems; } // We must account for the items that were pushed directly to successor @@ -321,7 +321,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.m_tosOffset -= info.outputItems; + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types } } diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 1be742f9f..0f639602a 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,8 +1,7 @@ #pragma once -#include -#include #include "Common.h" #include "Stack.h" +#include namespace dev { diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index cad3f2094..64015a820 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -1,14 +1,17 @@ #include "Cache.h" -#include -#include -#include +#include "ExecutionEngine.h" + +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include #include -#include "ExecutionEngine.h" +#include "preprocessor/llvm_includes_end.h" + +#include +#include namespace dev { diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index d7b32c651..18f9237f1 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,8 +1,6 @@ #pragma once - -#include #include - +#include namespace dev { diff --git a/libevmjit/Common.h b/libevmjit/Common.h index 62731292f..cd7177e67 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -1,5 +1,4 @@ #pragma once - #include #include #include diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 02e2e920a..9ad53ce3c 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,19 +1,4 @@ - #include "Compiler.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - #include "Instruction.h" #include "Type.h" #include "Memory.h" @@ -25,6 +10,20 @@ #include "Arith256.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include +#include +#include +#include + namespace dev { namespace eth diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 89b2f1a8e..30130798c 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -1,8 +1,4 @@ - #pragma once - -#include - #include "Common.h" #include "BasicBlock.h" diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index 9cccecd79..bf2929429 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -1,51 +1,47 @@ - -#include "CompilerHelper.h" - -#include -#include - -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : - m_builder(_builder) -{} - -llvm::Module* CompilerHelper::getModule() -{ - assert(m_builder.GetInsertBlock()); - assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function - return m_builder.GetInsertBlock()->getParent()->getParent(); -} - -llvm::Function* CompilerHelper::getMainFunction() -{ - // TODO: Rename or change semantics of getMainFunction() function - assert(m_builder.GetInsertBlock()); - auto mainFunc = m_builder.GetInsertBlock()->getParent(); - assert(mainFunc); - if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module - return mainFunc; - return nullptr; -} - -llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) -{ - return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); -} - - -RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): - CompilerHelper(_runtimeManager.getBuilder()), - m_runtimeManager(_runtimeManager) -{} - -} -} -} +#include "CompilerHelper.h" +#include "RuntimeManager.h" +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : + m_builder(_builder) +{} + +llvm::Module* CompilerHelper::getModule() +{ + assert(m_builder.GetInsertBlock()); + assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function + return m_builder.GetInsertBlock()->getParent()->getParent(); +} + +llvm::Function* CompilerHelper::getMainFunction() +{ + // TODO: Rename or change semantics of getMainFunction() function + assert(m_builder.GetInsertBlock()); + auto mainFunc = m_builder.GetInsertBlock()->getParent(); + assert(mainFunc); + if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module + return mainFunc; + return nullptr; +} + +llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) +{ + return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); +} + + +RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): + CompilerHelper(_runtimeManager.getBuilder()), + m_runtimeManager(_runtimeManager) +{} + +} +} +} diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index 62733ca72..912f7e93f 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -1,78 +1,79 @@ +#pragma once -#pragma once - +#include "preprocessor/llvm_includes_start.h" #include - - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -/// Base class for compiler helpers like Memory, GasMeter, etc. -class CompilerHelper -{ -protected: - CompilerHelper(llvm::IRBuilder<>& _builder); - - CompilerHelper(const CompilerHelper&) = delete; - void operator=(CompilerHelper) = delete; - - /// Reference to the IR module being compiled - llvm::Module* getModule(); - - /// Reference to the main module function - llvm::Function* getMainFunction(); - - /// Reference to parent compiler IR builder - llvm::IRBuilder<>& m_builder; - llvm::IRBuilder<>& getBuilder() { return m_builder; } - - llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); - - friend class RuntimeHelper; -}; - - -/// Compiler helper that depends on runtime data -class RuntimeHelper : public CompilerHelper -{ -protected: - RuntimeHelper(RuntimeManager& _runtimeManager); - - RuntimeManager& getRuntimeManager() { return m_runtimeManager; } - -private: - RuntimeManager& m_runtimeManager; -}; - - -/// Saves the insert point of the IR builder and restores it when destructed -struct InsertPointGuard -{ - InsertPointGuard(llvm::IRBuilder<>& _builder) : - m_builder(_builder), - m_insertBB(m_builder.GetInsertBlock()), - m_insertPt(m_builder.GetInsertPoint()) - {} - - InsertPointGuard(const InsertPointGuard&) = delete; - void operator=(InsertPointGuard) = delete; - - ~InsertPointGuard() - { - m_builder.SetInsertPoint(m_insertBB, m_insertPt); - } - -private: - llvm::IRBuilder<>& m_builder; - llvm::BasicBlock* m_insertBB; - llvm::BasicBlock::iterator m_insertPt; -}; - -} -} -} +#include "preprocessor/llvm_includes_end.h" + + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +/// Base class for compiler helpers like Memory, GasMeter, etc. +class CompilerHelper +{ +protected: + CompilerHelper(llvm::IRBuilder<>& _builder); + + CompilerHelper(const CompilerHelper&) = delete; + CompilerHelper& operator=(CompilerHelper) = delete; + + /// Reference to the IR module being compiled + llvm::Module* getModule(); + + /// Reference to the main module function + llvm::Function* getMainFunction(); + + /// Reference to parent compiler IR builder + llvm::IRBuilder<>& m_builder; + llvm::IRBuilder<>& getBuilder() { return m_builder; } + + llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); + + friend class RuntimeHelper; +}; + + +/// Compiler helper that depends on runtime data +class RuntimeHelper : public CompilerHelper +{ +protected: + RuntimeHelper(RuntimeManager& _runtimeManager); + + RuntimeManager& getRuntimeManager() { return m_runtimeManager; } + +private: + RuntimeManager& m_runtimeManager; +}; + + +/// Saves the insert point of the IR builder and restores it when destructed +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; +}; + +} +} +} diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index db7edfdc9..f3ee4c783 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -1,38 +1,38 @@ - -#include "Endianness.h" - -#include - -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) -{ - union tester - { - unsigned int x; - unsigned char isLE; - }; - - if (tester{1}.isLE) - { - // FIXME: Disabled because of problems with BYTE - //if (auto constant = llvm::dyn_cast(_word)) - // return _builder.getInt(constant->getValue().byteSwap()); - - // OPT: Cache func declaration? - auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); - return _builder.CreateCall(bswapFunc, _word); - } - return _word; -} - -} -} -} +#include "Endianness.h" +#include "Type.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + union tester + { + unsigned int x; + unsigned char isLE; + }; + + if (tester{1}.isLE) + { + // FIXME: Disabled because of problems with BYTE + //if (auto constant = llvm::dyn_cast(_word)) + // return _builder.getInt(constant->getValue().byteSwap()); + + // OPT: Cache func declaration? + auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); + return _builder.CreateCall(bswapFunc, _word); + } + return _word; +} + +} +} +} diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h index 8a1f41085..73224fb21 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -1,24 +1,25 @@ - -#pragma once - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct Endianness -{ - static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - -private: - static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); -}; - -} -} -} +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Endianness +{ + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + +private: + static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +} diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h index 284ecad7b..17f58ccac 100644 --- a/libevmjit/ExecStats.h +++ b/libevmjit/ExecStats.h @@ -1,8 +1,6 @@ #pragma once - -#include -#include #include "ExecutionEngine.h" +#include namespace dev { diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index ef62e8441..24ed74f15 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,7 +1,10 @@ #include "ExecutionEngine.h" +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "BuildInfo.gen.h" -#include -#include // env options #include "preprocessor/llvm_includes_start.h" #include #include @@ -12,12 +15,8 @@ #include #include "preprocessor/llvm_includes_end.h" -#include "Runtime.h" -#include "Compiler.h" -#include "Cache.h" -#include "ExecStats.h" -#include "BuildInfo.gen.h" - +#include +#include // env options #include namespace dev diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 101475b11..a31b6bf1e 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,7 +1,6 @@ #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 0a465bb80..c06d01f74 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -1,15 +1,13 @@ - #include "Ext.h" - -#include -#include -#include - #include "RuntimeManager.h" #include "Memory.h" #include "Type.h" #include "Endianness.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 8ad69ea6e..669797848 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "CompilerHelper.h" +#include namespace dev { diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index eb06795f0..3f3cf2e04 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -1,14 +1,12 @@ - #include "GasMeter.h" - -#include -#include -#include - -#include "Type.h" #include "Ext.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + + namespace dev { namespace eth diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 27f55253f..4f29f5c29 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -1,6 +1,4 @@ - #pragma once - #include "CompilerHelper.h" #include "Instruction.h" diff --git a/libevmjit/Instruction.cpp b/libevmjit/Instruction.cpp index 909121607..f70b020f8 100644 --- a/libevmjit/Instruction.cpp +++ b/libevmjit/Instruction.cpp @@ -1,6 +1,8 @@ - #include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 6785213d6..db18c934a 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace llvm diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 6a46fa8ca..e29bbcaba 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,21 +1,14 @@ #include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - #include "Type.h" #include "Runtime.h" #include "GasMeter.h" #include "Endianness.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index e8edce735..90c01c1ca 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index eb70e01d1..09ad7854f 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -1,9 +1,5 @@ - #include "Runtime.h" - -#include -#include -#include +#include namespace dev { diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 20cf56984..31341d7d3 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index ff6e82fe8..50522f0bc 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -1,7 +1,5 @@ #pragma once - -#include "Utils.h" - +#include "Common.h" namespace dev { diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 98386e1fe..7b3db7477 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -1,12 +1,8 @@ - #include "RuntimeManager.h" -#include -#include -#include - -#include "RuntimeData.h" -#include "Instruction.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index b3ce6f997..92c210289 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" #include "Type.h" #include "RuntimeData.h" diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 44f1c21c1..79864f3ca 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -1,10 +1,8 @@ #include "Stack.h" #include "RuntimeManager.h" #include "Runtime.h" -#include "Type.h" #include -#include namespace dev { diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 3e8881e4f..f453d14c0 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,43 +1,40 @@ -#pragma once - -#include "CompilerHelper.h" - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -class Stack : public CompilerHelper -{ -public: - Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); - - llvm::Value* get(size_t _index); - void set(size_t _index, llvm::Value* _value); - void pop(size_t _count); - void push(llvm::Value* _value); - - static size_t maxStackSize; - -private: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#pragma once +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + RuntimeManager& m_runtimeManager; + + llvm::Function* m_push; + llvm::Function* m_pop; + llvm::Function* m_get; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 2bbb3fa6f..8e2bc13fc 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -1,8 +1,4 @@ - #include "Type.h" - -#include - #include "RuntimeManager.h" namespace dev diff --git a/libevmjit/Type.h b/libevmjit/Type.h index e7757abbf..46fd5c9b7 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -1,9 +1,10 @@ - #pragma once +#include "Common.h" +#include "preprocessor/llvm_includes_start.h" #include -#include -#include "Common.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 5f7f75bfd..bf3bf93b3 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -1,4 +1,3 @@ - #include "Utils.h" namespace dev diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 1e6705667..652c7bc35 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace dev diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h index 6600886f4..264a6e1ef 100644 --- a/libevmjit/preprocessor/llvm_includes_start.h +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -1,4 +1,5 @@ #pragma warning(push) +#pragma warning(disable: 4267 4244 4800) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" From 3365f3f4380d1c8f859cca659e44e8ab9af8017a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 17:11:24 +0100 Subject: [PATCH 063/118] #include cleanups --- evmjit/libevmjit/Arith256.cpp | 3 +- evmjit/libevmjit/Arith256.h | 1 - evmjit/libevmjit/BasicBlock.cpp | 14 +- evmjit/libevmjit/BasicBlock.h | 3 +- evmjit/libevmjit/Cache.cpp | 11 +- evmjit/libevmjit/Cache.h | 4 +- evmjit/libevmjit/Common.h | 1 - evmjit/libevmjit/Compiler.cpp | 29 ++-- evmjit/libevmjit/Compiler.h | 4 - evmjit/libevmjit/CompilerHelper.cpp | 98 ++++++----- evmjit/libevmjit/CompilerHelper.h | 153 +++++++++--------- evmjit/libevmjit/Endianness.cpp | 76 ++++----- evmjit/libevmjit/Endianness.h | 49 +++--- evmjit/libevmjit/ExecStats.h | 4 +- evmjit/libevmjit/ExecutionEngine.cpp | 15 +- evmjit/libevmjit/ExecutionEngine.h | 3 +- evmjit/libevmjit/Ext.cpp | 10 +- evmjit/libevmjit/Ext.h | 4 +- evmjit/libevmjit/GasMeter.cpp | 12 +- evmjit/libevmjit/GasMeter.h | 2 - evmjit/libevmjit/Instruction.cpp | 4 +- evmjit/libevmjit/Instruction.h | 1 - evmjit/libevmjit/Memory.cpp | 15 +- evmjit/libevmjit/Memory.h | 1 - evmjit/libevmjit/Runtime.cpp | 6 +- evmjit/libevmjit/Runtime.h | 4 +- evmjit/libevmjit/RuntimeData.h | 4 +- evmjit/libevmjit/RuntimeManager.cpp | 10 +- evmjit/libevmjit/RuntimeManager.h | 1 - evmjit/libevmjit/Stack.cpp | 2 - evmjit/libevmjit/Stack.h | 83 +++++----- evmjit/libevmjit/Type.cpp | 4 - evmjit/libevmjit/Type.h | 7 +- evmjit/libevmjit/Utils.cpp | 1 - evmjit/libevmjit/Utils.h | 1 - .../preprocessor/llvm_includes_start.h | 1 + 36 files changed, 296 insertions(+), 345 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index a77050adc..6ae62b9d3 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -3,8 +3,9 @@ #include "Type.h" #include "Endianness.h" -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h index 2513ca568..4b94652d8 100644 --- a/evmjit/libevmjit/Arith256.h +++ b/evmjit/libevmjit/Arith256.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index c71bae94f..112e9d652 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -1,15 +1,15 @@ - #include "BasicBlock.h" +#include "Type.h" -#include - +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include +#include "preprocessor/llvm_includes_end.h" -#include "Type.h" +#include namespace dev { @@ -141,7 +141,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) auto endIter = m_currentStack.end(); // Update (emit set()) changed values - for (int idx = m_currentStack.size() - 1 - m_tosOffset; + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; currIter < endIter && idx >= 0; ++currIter, --idx) { @@ -308,7 +308,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: - bblock.m_tosOffset += info.inputItems; + bblock.m_tosOffset += (int)info.inputItems; } // We must account for the items that were pushed directly to successor @@ -321,7 +321,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.m_tosOffset -= info.outputItems; + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types } } diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 1be742f9f..0f639602a 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -1,8 +1,7 @@ #pragma once -#include -#include #include "Common.h" #include "Stack.h" +#include namespace dev { diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index cad3f2094..64015a820 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -1,14 +1,17 @@ #include "Cache.h" -#include -#include -#include +#include "ExecutionEngine.h" + +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include #include -#include "ExecutionEngine.h" +#include "preprocessor/llvm_includes_end.h" + +#include +#include namespace dev { diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h index d7b32c651..18f9237f1 100644 --- a/evmjit/libevmjit/Cache.h +++ b/evmjit/libevmjit/Cache.h @@ -1,8 +1,6 @@ #pragma once - -#include #include - +#include namespace dev { diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index 62731292f..cd7177e67 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -1,5 +1,4 @@ #pragma once - #include #include #include diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 02e2e920a..9ad53ce3c 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -1,19 +1,4 @@ - #include "Compiler.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - #include "Instruction.h" #include "Type.h" #include "Memory.h" @@ -25,6 +10,20 @@ #include "Arith256.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include +#include +#include +#include + namespace dev { namespace eth diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index 89b2f1a8e..30130798c 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -1,8 +1,4 @@ - #pragma once - -#include - #include "Common.h" #include "BasicBlock.h" diff --git a/evmjit/libevmjit/CompilerHelper.cpp b/evmjit/libevmjit/CompilerHelper.cpp index 9cccecd79..bf2929429 100644 --- a/evmjit/libevmjit/CompilerHelper.cpp +++ b/evmjit/libevmjit/CompilerHelper.cpp @@ -1,51 +1,47 @@ - -#include "CompilerHelper.h" - -#include -#include - -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : - m_builder(_builder) -{} - -llvm::Module* CompilerHelper::getModule() -{ - assert(m_builder.GetInsertBlock()); - assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function - return m_builder.GetInsertBlock()->getParent()->getParent(); -} - -llvm::Function* CompilerHelper::getMainFunction() -{ - // TODO: Rename or change semantics of getMainFunction() function - assert(m_builder.GetInsertBlock()); - auto mainFunc = m_builder.GetInsertBlock()->getParent(); - assert(mainFunc); - if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module - return mainFunc; - return nullptr; -} - -llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) -{ - return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); -} - - -RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): - CompilerHelper(_runtimeManager.getBuilder()), - m_runtimeManager(_runtimeManager) -{} - -} -} -} +#include "CompilerHelper.h" +#include "RuntimeManager.h" +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : + m_builder(_builder) +{} + +llvm::Module* CompilerHelper::getModule() +{ + assert(m_builder.GetInsertBlock()); + assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function + return m_builder.GetInsertBlock()->getParent()->getParent(); +} + +llvm::Function* CompilerHelper::getMainFunction() +{ + // TODO: Rename or change semantics of getMainFunction() function + assert(m_builder.GetInsertBlock()); + auto mainFunc = m_builder.GetInsertBlock()->getParent(); + assert(mainFunc); + if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module + return mainFunc; + return nullptr; +} + +llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) +{ + return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); +} + + +RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): + CompilerHelper(_runtimeManager.getBuilder()), + m_runtimeManager(_runtimeManager) +{} + +} +} +} diff --git a/evmjit/libevmjit/CompilerHelper.h b/evmjit/libevmjit/CompilerHelper.h index 62733ca72..912f7e93f 100644 --- a/evmjit/libevmjit/CompilerHelper.h +++ b/evmjit/libevmjit/CompilerHelper.h @@ -1,78 +1,79 @@ +#pragma once -#pragma once - +#include "preprocessor/llvm_includes_start.h" #include - - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -/// Base class for compiler helpers like Memory, GasMeter, etc. -class CompilerHelper -{ -protected: - CompilerHelper(llvm::IRBuilder<>& _builder); - - CompilerHelper(const CompilerHelper&) = delete; - void operator=(CompilerHelper) = delete; - - /// Reference to the IR module being compiled - llvm::Module* getModule(); - - /// Reference to the main module function - llvm::Function* getMainFunction(); - - /// Reference to parent compiler IR builder - llvm::IRBuilder<>& m_builder; - llvm::IRBuilder<>& getBuilder() { return m_builder; } - - llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); - - friend class RuntimeHelper; -}; - - -/// Compiler helper that depends on runtime data -class RuntimeHelper : public CompilerHelper -{ -protected: - RuntimeHelper(RuntimeManager& _runtimeManager); - - RuntimeManager& getRuntimeManager() { return m_runtimeManager; } - -private: - RuntimeManager& m_runtimeManager; -}; - - -/// Saves the insert point of the IR builder and restores it when destructed -struct InsertPointGuard -{ - InsertPointGuard(llvm::IRBuilder<>& _builder) : - m_builder(_builder), - m_insertBB(m_builder.GetInsertBlock()), - m_insertPt(m_builder.GetInsertPoint()) - {} - - InsertPointGuard(const InsertPointGuard&) = delete; - void operator=(InsertPointGuard) = delete; - - ~InsertPointGuard() - { - m_builder.SetInsertPoint(m_insertBB, m_insertPt); - } - -private: - llvm::IRBuilder<>& m_builder; - llvm::BasicBlock* m_insertBB; - llvm::BasicBlock::iterator m_insertPt; -}; - -} -} -} +#include "preprocessor/llvm_includes_end.h" + + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +/// Base class for compiler helpers like Memory, GasMeter, etc. +class CompilerHelper +{ +protected: + CompilerHelper(llvm::IRBuilder<>& _builder); + + CompilerHelper(const CompilerHelper&) = delete; + CompilerHelper& operator=(CompilerHelper) = delete; + + /// Reference to the IR module being compiled + llvm::Module* getModule(); + + /// Reference to the main module function + llvm::Function* getMainFunction(); + + /// Reference to parent compiler IR builder + llvm::IRBuilder<>& m_builder; + llvm::IRBuilder<>& getBuilder() { return m_builder; } + + llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); + + friend class RuntimeHelper; +}; + + +/// Compiler helper that depends on runtime data +class RuntimeHelper : public CompilerHelper +{ +protected: + RuntimeHelper(RuntimeManager& _runtimeManager); + + RuntimeManager& getRuntimeManager() { return m_runtimeManager; } + +private: + RuntimeManager& m_runtimeManager; +}; + + +/// Saves the insert point of the IR builder and restores it when destructed +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; +}; + +} +} +} diff --git a/evmjit/libevmjit/Endianness.cpp b/evmjit/libevmjit/Endianness.cpp index db7edfdc9..f3ee4c783 100644 --- a/evmjit/libevmjit/Endianness.cpp +++ b/evmjit/libevmjit/Endianness.cpp @@ -1,38 +1,38 @@ - -#include "Endianness.h" - -#include - -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) -{ - union tester - { - unsigned int x; - unsigned char isLE; - }; - - if (tester{1}.isLE) - { - // FIXME: Disabled because of problems with BYTE - //if (auto constant = llvm::dyn_cast(_word)) - // return _builder.getInt(constant->getValue().byteSwap()); - - // OPT: Cache func declaration? - auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); - return _builder.CreateCall(bswapFunc, _word); - } - return _word; -} - -} -} -} +#include "Endianness.h" +#include "Type.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + union tester + { + unsigned int x; + unsigned char isLE; + }; + + if (tester{1}.isLE) + { + // FIXME: Disabled because of problems with BYTE + //if (auto constant = llvm::dyn_cast(_word)) + // return _builder.getInt(constant->getValue().byteSwap()); + + // OPT: Cache func declaration? + auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); + return _builder.CreateCall(bswapFunc, _word); + } + return _word; +} + +} +} +} diff --git a/evmjit/libevmjit/Endianness.h b/evmjit/libevmjit/Endianness.h index 8a1f41085..73224fb21 100644 --- a/evmjit/libevmjit/Endianness.h +++ b/evmjit/libevmjit/Endianness.h @@ -1,24 +1,25 @@ - -#pragma once - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct Endianness -{ - static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - -private: - static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); -}; - -} -} -} +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Endianness +{ + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + +private: + static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +} diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h index 284ecad7b..17f58ccac 100644 --- a/evmjit/libevmjit/ExecStats.h +++ b/evmjit/libevmjit/ExecStats.h @@ -1,8 +1,6 @@ #pragma once - -#include -#include #include "ExecutionEngine.h" +#include namespace dev { diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index ef62e8441..24ed74f15 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -1,7 +1,10 @@ #include "ExecutionEngine.h" +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "BuildInfo.gen.h" -#include -#include // env options #include "preprocessor/llvm_includes_start.h" #include #include @@ -12,12 +15,8 @@ #include #include "preprocessor/llvm_includes_end.h" -#include "Runtime.h" -#include "Compiler.h" -#include "Cache.h" -#include "ExecStats.h" -#include "BuildInfo.gen.h" - +#include +#include // env options #include namespace dev diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index 101475b11..a31b6bf1e 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -1,7 +1,6 @@ #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index 0a465bb80..c06d01f74 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -1,15 +1,13 @@ - #include "Ext.h" - -#include -#include -#include - #include "RuntimeManager.h" #include "Memory.h" #include "Type.h" #include "Endianness.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index 8ad69ea6e..669797848 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "CompilerHelper.h" +#include namespace dev { diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index eb06795f0..3f3cf2e04 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -1,14 +1,12 @@ - #include "GasMeter.h" - -#include -#include -#include - -#include "Type.h" #include "Ext.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + + namespace dev { namespace eth diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h index 27f55253f..4f29f5c29 100644 --- a/evmjit/libevmjit/GasMeter.h +++ b/evmjit/libevmjit/GasMeter.h @@ -1,6 +1,4 @@ - #pragma once - #include "CompilerHelper.h" #include "Instruction.h" diff --git a/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp index 909121607..f70b020f8 100644 --- a/evmjit/libevmjit/Instruction.cpp +++ b/evmjit/libevmjit/Instruction.cpp @@ -1,6 +1,8 @@ - #include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h index 6785213d6..db18c934a 100644 --- a/evmjit/libevmjit/Instruction.h +++ b/evmjit/libevmjit/Instruction.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace llvm diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index 6a46fa8ca..e29bbcaba 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -1,21 +1,14 @@ #include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - #include "Type.h" #include "Runtime.h" #include "GasMeter.h" #include "Endianness.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h index e8edce735..90c01c1ca 100644 --- a/evmjit/libevmjit/Memory.h +++ b/evmjit/libevmjit/Memory.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp index eb70e01d1..09ad7854f 100644 --- a/evmjit/libevmjit/Runtime.cpp +++ b/evmjit/libevmjit/Runtime.cpp @@ -1,9 +1,5 @@ - #include "Runtime.h" - -#include -#include -#include +#include namespace dev { diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index 20cf56984..31341d7d3 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h index ff6e82fe8..50522f0bc 100644 --- a/evmjit/libevmjit/RuntimeData.h +++ b/evmjit/libevmjit/RuntimeData.h @@ -1,7 +1,5 @@ #pragma once - -#include "Utils.h" - +#include "Common.h" namespace dev { diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 98386e1fe..7b3db7477 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,12 +1,8 @@ - #include "RuntimeManager.h" -#include -#include -#include - -#include "RuntimeData.h" -#include "Instruction.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index b3ce6f997..92c210289 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" #include "Type.h" #include "RuntimeData.h" diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp index 44f1c21c1..79864f3ca 100644 --- a/evmjit/libevmjit/Stack.cpp +++ b/evmjit/libevmjit/Stack.cpp @@ -1,10 +1,8 @@ #include "Stack.h" #include "RuntimeManager.h" #include "Runtime.h" -#include "Type.h" #include -#include namespace dev { diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h index 3e8881e4f..f453d14c0 100644 --- a/evmjit/libevmjit/Stack.h +++ b/evmjit/libevmjit/Stack.h @@ -1,43 +1,40 @@ -#pragma once - -#include "CompilerHelper.h" - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -class Stack : public CompilerHelper -{ -public: - Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); - - llvm::Value* get(size_t _index); - void set(size_t _index, llvm::Value* _value); - void pop(size_t _count); - void push(llvm::Value* _value); - - static size_t maxStackSize; - -private: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#pragma once +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + RuntimeManager& m_runtimeManager; + + llvm::Function* m_push; + llvm::Function* m_pop; + llvm::Function* m_get; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 2bbb3fa6f..8e2bc13fc 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -1,8 +1,4 @@ - #include "Type.h" - -#include - #include "RuntimeManager.h" namespace dev diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index e7757abbf..46fd5c9b7 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -1,9 +1,10 @@ - #pragma once +#include "Common.h" +#include "preprocessor/llvm_includes_start.h" #include -#include -#include "Common.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/evmjit/libevmjit/Utils.cpp b/evmjit/libevmjit/Utils.cpp index 5f7f75bfd..bf3bf93b3 100644 --- a/evmjit/libevmjit/Utils.cpp +++ b/evmjit/libevmjit/Utils.cpp @@ -1,4 +1,3 @@ - #include "Utils.h" namespace dev diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h index 1e6705667..652c7bc35 100644 --- a/evmjit/libevmjit/Utils.h +++ b/evmjit/libevmjit/Utils.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace dev diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_start.h b/evmjit/libevmjit/preprocessor/llvm_includes_start.h index 6600886f4..264a6e1ef 100644 --- a/evmjit/libevmjit/preprocessor/llvm_includes_start.h +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -1,4 +1,5 @@ #pragma warning(push) +#pragma warning(disable: 4267 4244 4800) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" From cf74b2a875016e317437f0ec451189d42abd3e99 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Fri, 6 Feb 2015 15:19:22 +0800 Subject: [PATCH 064/118] change typedef to using according to preferred coding style --- libevmjit/ExecutionEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 2db125c2d..aae5349d8 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -29,7 +29,7 @@ namespace jit namespace { -typedef ReturnCode(*EntryFuncPtr)(Runtime*); +using EntryFuncPtr = ReturnCode(*)(Runtime*); ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) { From 2faa67bae22990ad28afede6f650276ff26f7248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 9 Feb 2015 19:21:54 +0100 Subject: [PATCH 065/118] Dynamic stack modification: do not use longjmp in external functions --- libevmjit/Stack.cpp | 96 ++++++++++++++++++++++++++++++++++++--------- libevmjit/Stack.h | 83 ++++++++++++++++++++------------------- 2 files changed, 121 insertions(+), 58 deletions(-) diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 79864f3ca..0afefdd22 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -25,18 +25,81 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); - llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; - m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); } +llvm::Function* Stack::getPopFunc() +{ + auto& func = m_pop; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto ok = createCall(extPopFunc, {rt, index}); + m_builder.CreateCondBr(ok, returnBB, underflowBB); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Stack::getGetFunc() +{ + auto& func = m_get; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto valuePtr = createCall(extGetFunc, {rt, index}); + auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); + m_builder.CreateCondBr(ok, returnBB, underflowBB); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(valuePtr); + } + return func; +} + llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); - return m_builder.CreateLoad(m_arg); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + return m_builder.CreateLoad(valuePtr); } void Stack::set(size_t _index, llvm::Value* _value) @@ -47,7 +110,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); } void Stack::push(llvm::Value* _value) @@ -67,13 +130,14 @@ extern "C" { using namespace dev::eth::jit; - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) + EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) { auto& stack = _rt->getStack(); if (stack.size() < _count) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + return false; stack.erase(stack.end() - _count, stack.end()); + return true; } EXPORT void stack_push(Runtime* _rt, i256 const* _word) @@ -85,22 +149,18 @@ extern "C" Stack::maxStackSize = stack.size(); } - EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) + EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *o_ret = *(stack.rbegin() + _index); + return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; } EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + assert(_index < stack.size()); + if (_index >= stack.size()) + return; *(stack.rbegin() + _index) = *_word; } diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index f453d14c0..0a549597f 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,40 +1,43 @@ -#pragma once -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -class Stack : public CompilerHelper -{ -public: - Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); - - llvm::Value* get(size_t _index); - void set(size_t _index, llvm::Value* _value); - void pop(size_t _count); - void push(llvm::Value* _value); - - static size_t maxStackSize; - -private: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#pragma once +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + llvm::Function* getPopFunc(); + llvm::Function* getGetFunc(); + + RuntimeManager& m_runtimeManager; + + llvm::Function* m_pop = nullptr; + llvm::Function* m_push; + llvm::Function* m_get = nullptr; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + From 7b4892c9162be1834b279894edf08b6c850e1e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 9 Feb 2015 19:21:54 +0100 Subject: [PATCH 066/118] Dynamic stack modification: do not use longjmp in external functions --- evmjit/libevmjit/Stack.cpp | 96 +++++++++++++++++++++++++++++++------- evmjit/libevmjit/Stack.h | 83 ++++++++++++++++---------------- 2 files changed, 121 insertions(+), 58 deletions(-) diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp index 79864f3ca..0afefdd22 100644 --- a/evmjit/libevmjit/Stack.cpp +++ b/evmjit/libevmjit/Stack.cpp @@ -25,18 +25,81 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); - llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; - m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); } +llvm::Function* Stack::getPopFunc() +{ + auto& func = m_pop; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto ok = createCall(extPopFunc, {rt, index}); + m_builder.CreateCondBr(ok, returnBB, underflowBB); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Stack::getGetFunc() +{ + auto& func = m_get; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto valuePtr = createCall(extGetFunc, {rt, index}); + auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); + m_builder.CreateCondBr(ok, returnBB, underflowBB); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(valuePtr); + } + return func; +} + llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); - return m_builder.CreateLoad(m_arg); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + return m_builder.CreateLoad(valuePtr); } void Stack::set(size_t _index, llvm::Value* _value) @@ -47,7 +110,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); } void Stack::push(llvm::Value* _value) @@ -67,13 +130,14 @@ extern "C" { using namespace dev::eth::jit; - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) + EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) { auto& stack = _rt->getStack(); if (stack.size() < _count) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + return false; stack.erase(stack.end() - _count, stack.end()); + return true; } EXPORT void stack_push(Runtime* _rt, i256 const* _word) @@ -85,22 +149,18 @@ extern "C" Stack::maxStackSize = stack.size(); } - EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) + EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *o_ret = *(stack.rbegin() + _index); + return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; } EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + assert(_index < stack.size()); + if (_index >= stack.size()) + return; *(stack.rbegin() + _index) = *_word; } diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h index f453d14c0..0a549597f 100644 --- a/evmjit/libevmjit/Stack.h +++ b/evmjit/libevmjit/Stack.h @@ -1,40 +1,43 @@ -#pragma once -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -class Stack : public CompilerHelper -{ -public: - Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); - - llvm::Value* get(size_t _index); - void set(size_t _index, llvm::Value* _value); - void pop(size_t _count); - void push(llvm::Value* _value); - - static size_t maxStackSize; - -private: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#pragma once +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + llvm::Function* getPopFunc(); + llvm::Function* getGetFunc(); + + RuntimeManager& m_runtimeManager; + + llvm::Function* m_pop = nullptr; + llvm::Function* m_push; + llvm::Function* m_get = nullptr; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + From f47cd20e8e18aa146a89b2e5c43931507db17d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 00:49:17 +0100 Subject: [PATCH 067/118] Correct usage of LLVM builtin setjmp/longjmp. External setjmp was eliminated, hopefully Windows will be happier now. --- libevmjit/Compiler.cpp | 43 ++++++++++++++++++++++++----------- libevmjit/ExecStats.cpp | 3 ++- libevmjit/ExecutionEngine.cpp | 17 +------------- libevmjit/GasMeter.cpp | 2 +- libevmjit/Runtime.cpp | 3 +-- libevmjit/Runtime.h | 10 +++----- libevmjit/RuntimeManager.cpp | 20 ++++++++++------ libevmjit/RuntimeManager.h | 9 +++++--- libevmjit/Stack.cpp | 26 +++++++++++++-------- 9 files changed, 73 insertions(+), 60 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 9ad53ce3c..91831e966 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include "preprocessor/llvm_includes_end.h" @@ -89,9 +90,6 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn begin = next; } } - - // TODO: Create Stop basic block on demand - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } llvm::BasicBlock* Compiler::getJumpTableBlock() @@ -134,21 +132,40 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + // Create entry basic block + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); m_builder.SetInsertPoint(entryBlock); + auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words"); + auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress); + auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); + m_builder.CreateStore(fp, jmpBufWords); + auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); + auto sp = m_builder.CreateCall(stacksave, "sp"); + auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); + m_builder.CreateStore(sp, jmpBufSp); + auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf"); + auto r = m_builder.CreateCall(setjmp, jmpBuf); + auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); + createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder, _begin, _end); + RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); + // TODO: Create Stop basic block on demand + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); + + auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); + auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { @@ -164,6 +181,9 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera m_builder.SetInsertPoint(m_stopBB); m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + m_builder.SetInsertPoint(abortBB); + m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + removeDeadBlocks(); // Link jump table target index @@ -825,12 +845,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti break; } - default: // Invalid instruction - runtime exception - { - // TODO: Replace with return statement - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation } } diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp index deb322521..97a3445b8 100644 --- a/libevmjit/ExecStats.cpp +++ b/libevmjit/ExecStats.cpp @@ -44,7 +44,8 @@ struct StatsAgg void output(char const* _name, std::ostream& _os) { auto avg = tot / count; - _os << std::setw(12) << std::left << _name + _os << std::setfill(' ') + << std::setw(12) << std::left << _name << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() << std::setw(10) << std::right << std::chrono::duration_cast(min).count() diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 24ed74f15..8ec5cd83c 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -30,21 +30,6 @@ namespace { typedef ReturnCode(*EntryFuncPtr)(Runtime*); -ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) -{ - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - ReturnCode returnCode{}; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = _mainFunc(_runtime); - else - returnCode = static_cast(sj); - - return returnCode; -} - std::string codeHash(i256 const& _hash) { static const auto size = sizeof(_hash); @@ -162,7 +147,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); - auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + auto returnCode = entryFuncPtr(&runtime); listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 3f3cf2e04..9f73df7da 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -104,7 +104,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.raiseException(ReturnCode::OutOfGas); + m_runtimeManager.abort(); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 09ad7854f..b8466791a 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -10,8 +10,7 @@ namespace jit Runtime::Runtime(RuntimeData* _data, Env* _env) : m_data(*_data), - m_env(*_env), - m_currJmpBuf(m_jmpBuf) + m_env(*_env) {} bytes_ref Runtime::getReturnData() const diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 31341d7d3..a24d822e1 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,6 +1,5 @@ #pragma once #include "RuntimeData.h" -#include namespace dev { @@ -11,7 +10,6 @@ namespace jit using StackImpl = std::vector; using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); class Runtime { @@ -26,15 +24,13 @@ public: Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; - jmp_buf_ref getJmpBuf() { return m_jmpBuf; } private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. byte* m_memoryData = nullptr; i256 m_memorySize; - std::jmp_buf m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; }; diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 7b3db7477..0b5762fa2 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -83,12 +83,17 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd): CompilerHelper(_builder), + m_jmpBuf(_jmpBuf), m_codeBegin(_codeBegin), m_codeEnd(_codeEnd) { - m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + + // save jmpBuf to be used in helper functions + auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2); + m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt"); // Unpack data auto rtPtr = getRuntimePtr(); @@ -160,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) set(RuntimeData::SuicideDestAddress, _balanceAddress); } -void RuntimeManager::raiseException(ReturnCode _returnCode) +void RuntimeManager::abort(llvm::Value* _jmpBuf) { - m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); } llvm::Value* RuntimeManager::get(Instruction _inst) @@ -207,10 +213,10 @@ llvm::Value* RuntimeManager::getCallDataSize() return getBuilder().CreateZExt(value, Type::Word); } -llvm::Value* RuntimeManager::getJmpBuf() +llvm::Value* RuntimeManager::getJmpBufExt() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); - return getBuilder().CreateLoad(ptr, "jmpbuf"); + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); } llvm::Value* RuntimeManager::getGas() diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index 92c210289..2fdad3fb5 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -14,7 +14,7 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); @@ -28,12 +28,14 @@ public: llvm::Value* getCode(); llvm::Value* getCodeSize(); llvm::Value* getCallDataSize(); + llvm::Value* getJmpBuf() { return m_jmpBuf; } void setGas(llvm::Value* _gas); void registerReturnData(llvm::Value* _index, llvm::Value* _size); void registerSuicide(llvm::Value* _balanceAddress); - void raiseException(ReturnCode _returnCode); + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); @@ -41,9 +43,10 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); + llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 0afefdd22..b63660aa9 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -34,14 +34,17 @@ llvm::Function* Stack::getPopFunc() auto& func = m_pop; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); - auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); auto rt = &func->getArgumentList().front(); rt->setName("rt"); auto index = rt->getNextNode(); index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); InsertPointGuard guard{m_builder}; auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); @@ -50,10 +53,10 @@ llvm::Function* Stack::getPopFunc() m_builder.SetInsertPoint(entryBB); auto ok = createCall(extPopFunc, {rt, index}); - m_builder.CreateCondBr(ok, returnBB, underflowBB); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -67,14 +70,17 @@ llvm::Function* Stack::getGetFunc() auto& func = m_get; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); - auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); auto rt = &func->getArgumentList().front(); rt->setName("rt"); auto index = rt->getNextNode(); index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); InsertPointGuard guard{m_builder}; auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); @@ -84,10 +90,10 @@ llvm::Function* Stack::getGetFunc() m_builder.SetInsertPoint(entryBB); auto valuePtr = createCall(extGetFunc, {rt, index}); auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); - m_builder.CreateCondBr(ok, returnBB, underflowBB); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -98,7 +104,7 @@ llvm::Function* Stack::getGetFunc() llvm::Value* Stack::get(size_t _index) { - auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); return m_builder.CreateLoad(valuePtr); } @@ -110,7 +116,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); } void Stack::push(llvm::Value* _value) From 5f4bda5cef570026bbde249c0a4454ff6402c1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 00:49:17 +0100 Subject: [PATCH 068/118] Correct usage of LLVM builtin setjmp/longjmp. External setjmp was eliminated, hopefully Windows will be happier now. --- evmjit/libevmjit/Compiler.cpp | 43 +++++++++++++++++++--------- evmjit/libevmjit/ExecStats.cpp | 3 +- evmjit/libevmjit/ExecutionEngine.cpp | 17 +---------- evmjit/libevmjit/GasMeter.cpp | 2 +- evmjit/libevmjit/Runtime.cpp | 3 +- evmjit/libevmjit/Runtime.h | 10 ++----- evmjit/libevmjit/RuntimeManager.cpp | 20 ++++++++----- evmjit/libevmjit/RuntimeManager.h | 9 ++++-- evmjit/libevmjit/Stack.cpp | 26 ++++++++++------- 9 files changed, 73 insertions(+), 60 deletions(-) diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 9ad53ce3c..91831e966 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include "preprocessor/llvm_includes_end.h" @@ -89,9 +90,6 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn begin = next; } } - - // TODO: Create Stop basic block on demand - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } llvm::BasicBlock* Compiler::getJumpTableBlock() @@ -134,21 +132,40 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + // Create entry basic block + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); m_builder.SetInsertPoint(entryBlock); + auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words"); + auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress); + auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); + m_builder.CreateStore(fp, jmpBufWords); + auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); + auto sp = m_builder.CreateCall(stacksave, "sp"); + auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); + m_builder.CreateStore(sp, jmpBufSp); + auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf"); + auto r = m_builder.CreateCall(setjmp, jmpBuf); + auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); + createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder, _begin, _end); + RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); + // TODO: Create Stop basic block on demand + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); + + auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); + auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { @@ -164,6 +181,9 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera m_builder.SetInsertPoint(m_stopBB); m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + m_builder.SetInsertPoint(abortBB); + m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + removeDeadBlocks(); // Link jump table target index @@ -825,12 +845,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti break; } - default: // Invalid instruction - runtime exception - { - // TODO: Replace with return statement - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation } } diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index deb322521..97a3445b8 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -44,7 +44,8 @@ struct StatsAgg void output(char const* _name, std::ostream& _os) { auto avg = tot / count; - _os << std::setw(12) << std::left << _name + _os << std::setfill(' ') + << std::setw(12) << std::left << _name << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() << std::setw(10) << std::right << std::chrono::duration_cast(min).count() diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 24ed74f15..8ec5cd83c 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -30,21 +30,6 @@ namespace { typedef ReturnCode(*EntryFuncPtr)(Runtime*); -ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) -{ - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - ReturnCode returnCode{}; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = _mainFunc(_runtime); - else - returnCode = static_cast(sj); - - return returnCode; -} - std::string codeHash(i256 const& _hash) { static const auto size = sizeof(_hash); @@ -162,7 +147,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); - auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + auto returnCode = entryFuncPtr(&runtime); listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 3f3cf2e04..9f73df7da 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -104,7 +104,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.raiseException(ReturnCode::OutOfGas); + m_runtimeManager.abort(); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp index 09ad7854f..b8466791a 100644 --- a/evmjit/libevmjit/Runtime.cpp +++ b/evmjit/libevmjit/Runtime.cpp @@ -10,8 +10,7 @@ namespace jit Runtime::Runtime(RuntimeData* _data, Env* _env) : m_data(*_data), - m_env(*_env), - m_currJmpBuf(m_jmpBuf) + m_env(*_env) {} bytes_ref Runtime::getReturnData() const diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index 31341d7d3..a24d822e1 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -1,6 +1,5 @@ #pragma once #include "RuntimeData.h" -#include namespace dev { @@ -11,7 +10,6 @@ namespace jit using StackImpl = std::vector; using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); class Runtime { @@ -26,15 +24,13 @@ public: Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; - jmp_buf_ref getJmpBuf() { return m_jmpBuf; } private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. byte* m_memoryData = nullptr; i256 m_memorySize; - std::jmp_buf m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; }; diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 7b3db7477..0b5762fa2 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -83,12 +83,17 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd): CompilerHelper(_builder), + m_jmpBuf(_jmpBuf), m_codeBegin(_codeBegin), m_codeEnd(_codeEnd) { - m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + + // save jmpBuf to be used in helper functions + auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2); + m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt"); // Unpack data auto rtPtr = getRuntimePtr(); @@ -160,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) set(RuntimeData::SuicideDestAddress, _balanceAddress); } -void RuntimeManager::raiseException(ReturnCode _returnCode) +void RuntimeManager::abort(llvm::Value* _jmpBuf) { - m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); } llvm::Value* RuntimeManager::get(Instruction _inst) @@ -207,10 +213,10 @@ llvm::Value* RuntimeManager::getCallDataSize() return getBuilder().CreateZExt(value, Type::Word); } -llvm::Value* RuntimeManager::getJmpBuf() +llvm::Value* RuntimeManager::getJmpBufExt() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); - return getBuilder().CreateLoad(ptr, "jmpbuf"); + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); } llvm::Value* RuntimeManager::getGas() diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index 92c210289..2fdad3fb5 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -14,7 +14,7 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); @@ -28,12 +28,14 @@ public: llvm::Value* getCode(); llvm::Value* getCodeSize(); llvm::Value* getCallDataSize(); + llvm::Value* getJmpBuf() { return m_jmpBuf; } void setGas(llvm::Value* _gas); void registerReturnData(llvm::Value* _index, llvm::Value* _size); void registerSuicide(llvm::Value* _balanceAddress); - void raiseException(ReturnCode _returnCode); + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); @@ -41,9 +43,10 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); + llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp index 0afefdd22..b63660aa9 100644 --- a/evmjit/libevmjit/Stack.cpp +++ b/evmjit/libevmjit/Stack.cpp @@ -34,14 +34,17 @@ llvm::Function* Stack::getPopFunc() auto& func = m_pop; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); - auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); auto rt = &func->getArgumentList().front(); rt->setName("rt"); auto index = rt->getNextNode(); index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); InsertPointGuard guard{m_builder}; auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); @@ -50,10 +53,10 @@ llvm::Function* Stack::getPopFunc() m_builder.SetInsertPoint(entryBB); auto ok = createCall(extPopFunc, {rt, index}); - m_builder.CreateCondBr(ok, returnBB, underflowBB); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -67,14 +70,17 @@ llvm::Function* Stack::getGetFunc() auto& func = m_get; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); - auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); auto rt = &func->getArgumentList().front(); rt->setName("rt"); auto index = rt->getNextNode(); index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); InsertPointGuard guard{m_builder}; auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); @@ -84,10 +90,10 @@ llvm::Function* Stack::getGetFunc() m_builder.SetInsertPoint(entryBB); auto valuePtr = createCall(extGetFunc, {rt, index}); auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); - m_builder.CreateCondBr(ok, returnBB, underflowBB); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -98,7 +104,7 @@ llvm::Function* Stack::getGetFunc() llvm::Value* Stack::get(size_t _index) { - auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); return m_builder.CreateLoad(valuePtr); } @@ -110,7 +116,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); } void Stack::push(llvm::Value* _value) From 3c5c3496cf379fd4e63b006c50678e0567f594e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 10:13:47 +0100 Subject: [PATCH 069/118] Helper function name fix --- libevmjit/Arith256.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 6ae62b9d3..17a8e6138 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -85,7 +85,7 @@ llvm::Function* Arith256::getMul512Func() { auto i512 = m_builder.getIntNTy(512); llvm::Type* argTypes[] = {Type::Word, Type::Word}; - func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); auto x = &func->getArgumentList().front(); x->setName("x"); From 8b8d9d1df03e0ed3040779ecce94999b2e1e0762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 10:13:47 +0100 Subject: [PATCH 070/118] Helper function name fix --- evmjit/libevmjit/Arith256.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 6ae62b9d3..17a8e6138 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -85,7 +85,7 @@ llvm::Function* Arith256::getMul512Func() { auto i512 = m_builder.getIntNTy(512); llvm::Type* argTypes[] = {Type::Word, Type::Word}; - func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); auto x = &func->getArgumentList().front(); x->setName("x"); From 375ea71e4c4b659c3766bf83b489ab55e22fb5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 14:58:51 +0100 Subject: [PATCH 071/118] Workaround for buggy LLVM shl operator for i512 --- libevmjit/Arith256.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 17a8e6138..21a2f83cb 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -8,6 +8,7 @@ #include "preprocessor/llvm_includes_end.h" #include +#include namespace dev { @@ -27,7 +28,7 @@ void Arith256::debug(llvm::Value* _value, char _c) llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); } - createCall(m_debug, {_value, m_builder.getInt8(_c)}); + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); } llvm::Function* Arith256::getMulFunc() @@ -97,15 +98,15 @@ llvm::Function* Arith256::getMul512Func() m_builder.SetInsertPoint(bb); auto i128 = m_builder.getIntNTy(128); auto i256 = Type::Word; - auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); - auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); - auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); - auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + auto x_lo = m_builder.CreateZExt(m_builder.CreateTrunc(x, i128, "x.lo"), i256); + auto y_lo = m_builder.CreateZExt(m_builder.CreateTrunc(y, i128, "y.lo"), i256); + auto x_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256); + auto y_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256); - auto t1 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); - auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_hi, i256)}); + auto t1 = createCall(getMulFunc(), {x_lo, y_lo}); + auto t2 = createCall(getMulFunc(), {x_lo, y_hi}); + auto t3 = createCall(getMulFunc(), {x_hi, y_lo}); + auto t4 = createCall(getMulFunc(), {x_hi, y_hi}); auto p = m_builder.CreateZExt(t1, i512); p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); @@ -160,6 +161,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); auto y0 = m_builder.CreateShl(yArg, i0); + if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts + { + const auto treshold = m_builder.getIntN(512, 128); + auto highShift = m_builder.CreateICmpUGT(i0, treshold); + auto s = m_builder.CreateNUWSub(i0, treshold); + auto yhs = m_builder.CreateShl(yArg, treshold); + yhs = m_builder.CreateShl(yhs, s); + y0 = m_builder.CreateSelect(highShift, yhs, y0); + } y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result m_builder.CreateBr(loopBB); @@ -325,7 +335,8 @@ llvm::Function* Arith256::getMulModFunc() auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); - m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); } return m_mulmod; } @@ -389,6 +400,7 @@ extern "C" { EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { - std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; + std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a + << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n"; } } From 3aa2f066dd7df88a426ff41a9d9bdc06ae3af3a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 14:58:51 +0100 Subject: [PATCH 072/118] Workaround for buggy LLVM shl operator for i512 --- evmjit/libevmjit/Arith256.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 17a8e6138..21a2f83cb 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -8,6 +8,7 @@ #include "preprocessor/llvm_includes_end.h" #include +#include namespace dev { @@ -27,7 +28,7 @@ void Arith256::debug(llvm::Value* _value, char _c) llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); } - createCall(m_debug, {_value, m_builder.getInt8(_c)}); + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); } llvm::Function* Arith256::getMulFunc() @@ -97,15 +98,15 @@ llvm::Function* Arith256::getMul512Func() m_builder.SetInsertPoint(bb); auto i128 = m_builder.getIntNTy(128); auto i256 = Type::Word; - auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); - auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); - auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); - auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + auto x_lo = m_builder.CreateZExt(m_builder.CreateTrunc(x, i128, "x.lo"), i256); + auto y_lo = m_builder.CreateZExt(m_builder.CreateTrunc(y, i128, "y.lo"), i256); + auto x_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256); + auto y_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256); - auto t1 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); - auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_hi, i256)}); + auto t1 = createCall(getMulFunc(), {x_lo, y_lo}); + auto t2 = createCall(getMulFunc(), {x_lo, y_hi}); + auto t3 = createCall(getMulFunc(), {x_hi, y_lo}); + auto t4 = createCall(getMulFunc(), {x_hi, y_hi}); auto p = m_builder.CreateZExt(t1, i512); p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); @@ -160,6 +161,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); auto y0 = m_builder.CreateShl(yArg, i0); + if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts + { + const auto treshold = m_builder.getIntN(512, 128); + auto highShift = m_builder.CreateICmpUGT(i0, treshold); + auto s = m_builder.CreateNUWSub(i0, treshold); + auto yhs = m_builder.CreateShl(yArg, treshold); + yhs = m_builder.CreateShl(yhs, s); + y0 = m_builder.CreateSelect(highShift, yhs, y0); + } y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result m_builder.CreateBr(loopBB); @@ -325,7 +335,8 @@ llvm::Function* Arith256::getMulModFunc() auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); - m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); } return m_mulmod; } @@ -389,6 +400,7 @@ extern "C" { EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { - std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; + std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a + << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n"; } } From a50a891cdb1fea6cc7544eac968cdee26ef58811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 16:14:06 +0100 Subject: [PATCH 073/118] Fix wrong prerelease version component parsing --- libevmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 330eaf3c8..7d9a9c8be 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -36,7 +36,7 @@ if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") if(${NUM_VERSION_NUMBERS} GREATER 2) list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional endif() - if(${NUM_VERSION_COMPONENTS} GREATER 0) + if(${NUM_VERSION_COMPONENTS} EQUAL 1 OR ${NUM_VERSION_COMPONENTS} EQUAL 3) # git describe add 2 or 0 components list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) endif() endif() From 89db6f0696f0ed4b91ebeee4f206d6fc1ac075c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 16:14:06 +0100 Subject: [PATCH 074/118] Fix wrong prerelease version component parsing --- evmjit/libevmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index 330eaf3c8..7d9a9c8be 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -36,7 +36,7 @@ if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") if(${NUM_VERSION_NUMBERS} GREATER 2) list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional endif() - if(${NUM_VERSION_COMPONENTS} GREATER 0) + if(${NUM_VERSION_COMPONENTS} EQUAL 1 OR ${NUM_VERSION_COMPONENTS} EQUAL 3) # git describe add 2 or 0 components list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) endif() endif() From 1e79c05859f85a7b842983e50e2fc74af62906cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 18:18:39 +0100 Subject: [PATCH 075/118] Better fix for wrong prerelease version component parsing --- libevmjit/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 7d9a9c8be..943c64e42 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -36,8 +36,9 @@ if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") if(${NUM_VERSION_NUMBERS} GREATER 2) list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional endif() - if(${NUM_VERSION_COMPONENTS} EQUAL 1 OR ${NUM_VERSION_COMPONENTS} EQUAL 3) # git describe add 2 or 0 components - list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) + if(${NUM_VERSION_COMPONENTS} GREATER 1) + list(GET VERSION_COMPONENTS 1 VERSION_PRERELEASE_CANDIDATE) + string(REGEX MATCH "^[a-zA-Z]+.*" EVMJIT_VERSION_PRERELEASE ${VERSION_PRERELEASE_CANDIDATE}) # prerelease starts with letter endif() endif() @@ -49,7 +50,7 @@ endif() configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h) -message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH}-${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") +message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h) set_target_properties(${TARGET_NAME} PROPERTIES From f7fcc7c0290dc9196c13113ef43a1dc39a32df4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 11 Feb 2015 17:06:35 +0100 Subject: [PATCH 076/118] Cleanup ExecutionEngine creation --- libevmjit/Arith256.cpp | 1 - libevmjit/ExecutionEngine.cpp | 96 ++++++++++++++--------------------- libevmjit/Runtime.h | 1 - 3 files changed, 39 insertions(+), 59 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 21a2f83cb..8e1ceb748 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -1,5 +1,4 @@ #include "Arith256.h" -#include "Runtime.h" #include "Type.h" #include "Endianness.h" diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 30df7f26a..c4c03233c 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -68,81 +68,63 @@ bool showInfo() ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { - static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); static auto infoShown = showInfo(); (void) infoShown; - static StatsCollector statsCollector; - std::unique_ptr listener{new ExecStats}; listener->stateChanged(ExecState::Started); - auto codeBegin = _data->code; - auto codeEnd = codeBegin + _data->codeSize; - assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? - auto mainFuncName = codeHash(_data->codeHash); - EntryFuncPtr entryFuncPtr{}; - Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; - if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) + static std::unique_ptr ee; + if (!ee) { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + builder.setOptLevel(llvm::CodeGenOpt::None); + + auto triple = llvm::Triple(llvm::sys::getProcessTriple()); + if (triple.getOS() == llvm::Triple::OSType::Win32) + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + module->setTargetTriple(triple.str()); + + ee.reset(builder.create()); + if (!ee) + return ReturnCode::LLVMConfigError; + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + ee->setObjectCache(objectCache); } - else - { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; - std::unique_ptr module; - if (objectCache) - module = Cache::getObject(mainFuncName); + + static StatsCollector statsCollector; + + auto mainFuncName = codeHash(_data->codeHash); + Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + + auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + if (!entryFuncPtr) + { + auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; if (!module) { listener->stateChanged(ExecState::Compilation); - module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code? + module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, mainFuncName); } if (debugDumpModule) module->dump(); - if (!ee) - { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); - builder.setVerifyModules(true); - - auto triple = llvm::Triple(llvm::sys::getProcessTriple()); - if (triple.getOS() == llvm::Triple::OSType::Win32) - triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format - module->setTargetTriple(triple.str()); - - ee.reset(builder.create()); - if (!ee) - return ReturnCode::LLVMConfigError; - - module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - if (objectCache) - ee->setObjectCache(objectCache); - listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - else - { - if (!entryFuncPtr) - { - ee->addModule(module.get()); - module.release(); - listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - } + + ee->addModule(module.get()); + module.release(); + listener->stateChanged(ExecState::CodeGen); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } assert(entryFuncPtr); //TODO: Replace it with safe exception diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index a24d822e1..9ea3039a0 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -21,7 +21,6 @@ public: StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } - Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; From c95c1c81f43b42d536f15ec56ee53043e2701d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 11 Feb 2015 17:06:35 +0100 Subject: [PATCH 077/118] Cleanup ExecutionEngine creation --- evmjit/libevmjit/Arith256.cpp | 1 - evmjit/libevmjit/ExecutionEngine.cpp | 96 +++++++++++----------------- evmjit/libevmjit/Runtime.h | 1 - 3 files changed, 39 insertions(+), 59 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 21a2f83cb..8e1ceb748 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -1,5 +1,4 @@ #include "Arith256.h" -#include "Runtime.h" #include "Type.h" #include "Endianness.h" diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 30df7f26a..c4c03233c 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -68,81 +68,63 @@ bool showInfo() ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { - static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); static auto infoShown = showInfo(); (void) infoShown; - static StatsCollector statsCollector; - std::unique_ptr listener{new ExecStats}; listener->stateChanged(ExecState::Started); - auto codeBegin = _data->code; - auto codeEnd = codeBegin + _data->codeSize; - assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? - auto mainFuncName = codeHash(_data->codeHash); - EntryFuncPtr entryFuncPtr{}; - Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; - if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) + static std::unique_ptr ee; + if (!ee) { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + builder.setOptLevel(llvm::CodeGenOpt::None); + + auto triple = llvm::Triple(llvm::sys::getProcessTriple()); + if (triple.getOS() == llvm::Triple::OSType::Win32) + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + module->setTargetTriple(triple.str()); + + ee.reset(builder.create()); + if (!ee) + return ReturnCode::LLVMConfigError; + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + ee->setObjectCache(objectCache); } - else - { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; - std::unique_ptr module; - if (objectCache) - module = Cache::getObject(mainFuncName); + + static StatsCollector statsCollector; + + auto mainFuncName = codeHash(_data->codeHash); + Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + + auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + if (!entryFuncPtr) + { + auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; if (!module) { listener->stateChanged(ExecState::Compilation); - module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code? + module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, mainFuncName); } if (debugDumpModule) module->dump(); - if (!ee) - { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); - builder.setVerifyModules(true); - - auto triple = llvm::Triple(llvm::sys::getProcessTriple()); - if (triple.getOS() == llvm::Triple::OSType::Win32) - triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format - module->setTargetTriple(triple.str()); - - ee.reset(builder.create()); - if (!ee) - return ReturnCode::LLVMConfigError; - - module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - if (objectCache) - ee->setObjectCache(objectCache); - listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - else - { - if (!entryFuncPtr) - { - ee->addModule(module.get()); - module.release(); - listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - } + + ee->addModule(module.get()); + module.release(); + listener->stateChanged(ExecState::CodeGen); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } assert(entryFuncPtr); //TODO: Replace it with safe exception diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index a24d822e1..9ea3039a0 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -21,7 +21,6 @@ public: StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } - Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; From 93cb4866fd4c5869e37f345c81fe7ab2a9720029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 10:26:11 +0100 Subject: [PATCH 078/118] Includes reordering, GCC conversion warnings enabled Includes order as described in Coding Standards of cpp-ethereum project. GCC warnings about lossy conversions enabled. --- CMakeLists.txt | 2 +- libevmjit/Arith256.cpp | 9 +- libevmjit/Arith256.h | 1 + libevmjit/BasicBlock.cpp | 5 +- libevmjit/BasicBlock.h | 4 +- libevmjit/Cache.cpp | 7 +- libevmjit/Cache.h | 4 +- libevmjit/Common.h | 1 + libevmjit/Compiler.cpp | 29 ++-- libevmjit/Compiler.h | 1 + libevmjit/CompilerHelper.cpp | 98 ++++++------ libevmjit/CompilerHelper.h | 154 +++++++++---------- libevmjit/Endianness.cpp | 77 +++++----- libevmjit/Endianness.h | 50 +++--- libevmjit/ExecStats.cpp | 1 + libevmjit/ExecStats.h | 4 +- libevmjit/ExecutionEngine.cpp | 17 +- libevmjit/ExecutionEngine.h | 4 +- libevmjit/Ext.cpp | 9 +- libevmjit/Ext.h | 4 +- libevmjit/GasMeter.cpp | 8 +- libevmjit/GasMeter.h | 1 + libevmjit/Instruction.h | 1 + libevmjit/Memory.cpp | 9 +- libevmjit/Memory.h | 1 + libevmjit/Runtime.cpp | 1 + libevmjit/Runtime.h | 79 +++++----- libevmjit/RuntimeData.h | 1 + libevmjit/RuntimeManager.h | 1 + libevmjit/Stack.cpp | 7 +- libevmjit/Stack.h | 1 + libevmjit/Type.h | 3 +- libevmjit/preprocessor/llvm_includes_end.h | 8 +- libevmjit/preprocessor/llvm_includes_start.h | 13 +- 34 files changed, 329 insertions(+), 286 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce05c422d..8f3a170d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 8e1ceb748..ddf06b463 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -1,13 +1,14 @@ #include "Arith256.h" -#include "Type.h" -#include "Endianness.h" + +#include +#include #include "preprocessor/llvm_includes_start.h" #include #include "preprocessor/llvm_includes_end.h" -#include -#include +#include "Type.h" +#include "Endianness.h" namespace dev { diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 4b94652d8..2513ca568 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 112e9d652..c9e71be9a 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,5 +1,6 @@ #include "BasicBlock.h" -#include "Type.h" + +#include #include "preprocessor/llvm_includes_start.h" #include @@ -9,7 +10,7 @@ #include #include "preprocessor/llvm_includes_end.h" -#include +#include "Type.h" namespace dev { diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 0f639602a..7469b7b69 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,7 +1,9 @@ #pragma once + +#include + #include "Common.h" #include "Stack.h" -#include namespace dev { diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 64015a820..d7d6f1bbb 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -1,5 +1,7 @@ #include "Cache.h" -#include "ExecutionEngine.h" + +#include +#include #include "preprocessor/llvm_includes_start.h" #include @@ -10,8 +12,7 @@ #include #include "preprocessor/llvm_includes_end.h" -#include -#include +#include "ExecutionEngine.h" namespace dev { diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 18f9237f1..e8f01d38d 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,7 +1,9 @@ #pragma once -#include + #include +#include + namespace dev { namespace eth diff --git a/libevmjit/Common.h b/libevmjit/Common.h index cd7177e67..62731292f 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -1,4 +1,5 @@ #pragma once + #include #include #include diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 91831e966..de48e8ef9 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,14 +1,9 @@ #include "Compiler.h" -#include "Instruction.h" -#include "Type.h" -#include "Memory.h" -#include "Stack.h" -#include "Ext.h" -#include "GasMeter.h" -#include "Utils.h" -#include "Endianness.h" -#include "Arith256.h" -#include "RuntimeManager.h" + +#include +#include +#include +#include #include "preprocessor/llvm_includes_start.h" #include @@ -20,10 +15,16 @@ #include #include "preprocessor/llvm_includes_end.h" -#include -#include -#include -#include +#include "Instruction.h" +#include "Type.h" +#include "Memory.h" +#include "Stack.h" +#include "Ext.h" +#include "GasMeter.h" +#include "Utils.h" +#include "Endianness.h" +#include "Arith256.h" +#include "RuntimeManager.h" namespace dev { diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 30130798c..c9795fb99 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -1,4 +1,5 @@ #pragma once + #include "Common.h" #include "BasicBlock.h" diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index bf2929429..5c8ee8574 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -1,47 +1,51 @@ -#include "CompilerHelper.h" -#include "RuntimeManager.h" -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : - m_builder(_builder) -{} - -llvm::Module* CompilerHelper::getModule() -{ - assert(m_builder.GetInsertBlock()); - assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function - return m_builder.GetInsertBlock()->getParent()->getParent(); -} - -llvm::Function* CompilerHelper::getMainFunction() -{ - // TODO: Rename or change semantics of getMainFunction() function - assert(m_builder.GetInsertBlock()); - auto mainFunc = m_builder.GetInsertBlock()->getParent(); - assert(mainFunc); - if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module - return mainFunc; - return nullptr; -} - -llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) -{ - return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); -} - - -RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): - CompilerHelper(_runtimeManager.getBuilder()), - m_runtimeManager(_runtimeManager) -{} - -} -} -} +#include "CompilerHelper.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : + m_builder(_builder) +{} + +llvm::Module* CompilerHelper::getModule() +{ + assert(m_builder.GetInsertBlock()); + assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function + return m_builder.GetInsertBlock()->getParent()->getParent(); +} + +llvm::Function* CompilerHelper::getMainFunction() +{ + // TODO: Rename or change semantics of getMainFunction() function + assert(m_builder.GetInsertBlock()); + auto mainFunc = m_builder.GetInsertBlock()->getParent(); + assert(mainFunc); + if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module + return mainFunc; + return nullptr; +} + +llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) +{ + return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); +} + + +RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): + CompilerHelper(_runtimeManager.getBuilder()), + m_runtimeManager(_runtimeManager) +{} + +} +} +} diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index 912f7e93f..cd6d09a58 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -1,79 +1,79 @@ -#pragma once +#pragma once -#include "preprocessor/llvm_includes_start.h" +#include "preprocessor/llvm_includes_start.h" #include -#include "preprocessor/llvm_includes_end.h" - - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -/// Base class for compiler helpers like Memory, GasMeter, etc. -class CompilerHelper -{ -protected: - CompilerHelper(llvm::IRBuilder<>& _builder); - - CompilerHelper(const CompilerHelper&) = delete; - CompilerHelper& operator=(CompilerHelper) = delete; - - /// Reference to the IR module being compiled - llvm::Module* getModule(); - - /// Reference to the main module function - llvm::Function* getMainFunction(); - - /// Reference to parent compiler IR builder - llvm::IRBuilder<>& m_builder; - llvm::IRBuilder<>& getBuilder() { return m_builder; } - - llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); - - friend class RuntimeHelper; -}; - - -/// Compiler helper that depends on runtime data -class RuntimeHelper : public CompilerHelper -{ -protected: - RuntimeHelper(RuntimeManager& _runtimeManager); - - RuntimeManager& getRuntimeManager() { return m_runtimeManager; } - -private: - RuntimeManager& m_runtimeManager; -}; - - -/// Saves the insert point of the IR builder and restores it when destructed -struct InsertPointGuard -{ - InsertPointGuard(llvm::IRBuilder<>& _builder) : - m_builder(_builder), - m_insertBB(m_builder.GetInsertBlock()), - m_insertPt(m_builder.GetInsertPoint()) - {} - - InsertPointGuard(const InsertPointGuard&) = delete; - void operator=(InsertPointGuard) = delete; - - ~InsertPointGuard() - { - m_builder.SetInsertPoint(m_insertBB, m_insertPt); - } - -private: - llvm::IRBuilder<>& m_builder; - llvm::BasicBlock* m_insertBB; - llvm::BasicBlock::iterator m_insertPt; -}; - -} -} -} +#include "preprocessor/llvm_includes_end.h" + + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +/// Base class for compiler helpers like Memory, GasMeter, etc. +class CompilerHelper +{ +protected: + CompilerHelper(llvm::IRBuilder<>& _builder); + + CompilerHelper(const CompilerHelper&) = delete; + CompilerHelper& operator=(CompilerHelper) = delete; + + /// Reference to the IR module being compiled + llvm::Module* getModule(); + + /// Reference to the main module function + llvm::Function* getMainFunction(); + + /// Reference to parent compiler IR builder + llvm::IRBuilder<>& m_builder; + llvm::IRBuilder<>& getBuilder() { return m_builder; } + + llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); + + friend class RuntimeHelper; +}; + + +/// Compiler helper that depends on runtime data +class RuntimeHelper : public CompilerHelper +{ +protected: + RuntimeHelper(RuntimeManager& _runtimeManager); + + RuntimeManager& getRuntimeManager() { return m_runtimeManager; } + +private: + RuntimeManager& m_runtimeManager; +}; + + +/// Saves the insert point of the IR builder and restores it when destructed +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; +}; + +} +} +} diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index f3ee4c783..38f71560c 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -1,38 +1,39 @@ -#include "Endianness.h" -#include "Type.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) -{ - union tester - { - unsigned int x; - unsigned char isLE; - }; - - if (tester{1}.isLE) - { - // FIXME: Disabled because of problems with BYTE - //if (auto constant = llvm::dyn_cast(_word)) - // return _builder.getInt(constant->getValue().byteSwap()); - - // OPT: Cache func declaration? - auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); - return _builder.CreateCall(bswapFunc, _word); - } - return _word; -} - -} -} -} +#include "Endianness.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + union tester + { + unsigned int x; + unsigned char isLE; + }; + + if (tester{1}.isLE) + { + // FIXME: Disabled because of problems with BYTE + //if (auto constant = llvm::dyn_cast(_word)) + // return _builder.getInt(constant->getValue().byteSwap()); + + // OPT: Cache func declaration? + auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); + return _builder.CreateCall(bswapFunc, _word); + } + return _word; +} + +} +} +} diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h index 73224fb21..19fd8fc58 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -1,25 +1,25 @@ -#pragma once - -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct Endianness -{ - static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - -private: - static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); -}; - -} -} -} +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Endianness +{ + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + +private: + static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +} diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp index 97a3445b8..d8668f636 100644 --- a/libevmjit/ExecStats.cpp +++ b/libevmjit/ExecStats.cpp @@ -1,4 +1,5 @@ #include "ExecStats.h" + #include #include #include diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h index 17f58ccac..498e21341 100644 --- a/libevmjit/ExecStats.h +++ b/libevmjit/ExecStats.h @@ -1,7 +1,9 @@ #pragma once -#include "ExecutionEngine.h" + #include +#include "ExecutionEngine.h" + namespace dev { namespace eth diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index c4c03233c..ff4c64cee 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,9 +1,8 @@ #include "ExecutionEngine.h" -#include "Runtime.h" -#include "Compiler.h" -#include "Cache.h" -#include "ExecStats.h" -#include "BuildInfo.gen.h" + +#include +#include // env options +#include #include "preprocessor/llvm_includes_start.h" #include @@ -15,9 +14,11 @@ #include #include "preprocessor/llvm_includes_end.h" -#include -#include // env options -#include +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "BuildInfo.gen.h" namespace dev { diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index a31b6bf1e..4c2965e58 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,7 +1,9 @@ #pragma once -#include "RuntimeData.h" + #include +#include "RuntimeData.h" + namespace dev { namespace eth diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index c06d01f74..38deef214 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -1,13 +1,14 @@ #include "Ext.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + #include "RuntimeManager.h" #include "Memory.h" #include "Type.h" #include "Endianness.h" -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - namespace dev { namespace eth diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 669797848..1c0c0fc56 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -1,7 +1,9 @@ #pragma once -#include "CompilerHelper.h" + #include +#include "CompilerHelper.h" + namespace dev { namespace eth diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 9f73df7da..ca21714e0 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -1,11 +1,11 @@ #include "GasMeter.h" -#include "Ext.h" -#include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" +#include "Ext.h" +#include "RuntimeManager.h" namespace dev { diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 4f29f5c29..4056cd64d 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" #include "Instruction.h" diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index db18c934a..6785213d6 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -1,4 +1,5 @@ #pragma once + #include "Common.h" namespace llvm diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index e29bbcaba..647c5f26a 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,14 +1,15 @@ #include "Memory.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + #include "Type.h" #include "Runtime.h" #include "GasMeter.h" #include "Endianness.h" #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - namespace dev { namespace eth diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index 90c01c1ca..e8edce735 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index b8466791a..69937368c 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -1,4 +1,5 @@ #include "Runtime.h" + #include namespace dev diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 9ea3039a0..82be4a0c8 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,39 +1,40 @@ -#pragma once -#include "RuntimeData.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -using StackImpl = std::vector; -using MemoryImpl = bytes; - -class Runtime -{ -public: - Runtime(RuntimeData* _data, Env* _env); - - Runtime(const Runtime&) = delete; - Runtime& operator=(const Runtime&) = delete; - - StackImpl& getStack() { return m_stack; } - MemoryImpl& getMemory() { return m_memory; } - - bytes_ref getReturnData() const; - -private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. - byte* m_memoryData = nullptr; - i256 m_memorySize; - StackImpl m_stack; - MemoryImpl m_memory; -}; - -} -} -} +#pragma once + +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using StackImpl = std::vector; +using MemoryImpl = bytes; + +class Runtime +{ +public: + Runtime(RuntimeData* _data, Env* _env); + + Runtime(const Runtime&) = delete; + Runtime& operator=(const Runtime&) = delete; + + StackImpl& getStack() { return m_stack; } + MemoryImpl& getMemory() { return m_memory; } + + bytes_ref getReturnData() const; + +private: + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. + byte* m_memoryData = nullptr; + i256 m_memorySize; + StackImpl m_stack; + MemoryImpl m_memory; +}; + +} +} +} diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index 50522f0bc..cc081cc58 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -1,4 +1,5 @@ #pragma once + #include "Common.h" namespace dev diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index 2fdad3fb5..30c69ec88 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" #include "Type.h" #include "RuntimeData.h" diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index b63660aa9..81a954991 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -1,8 +1,11 @@ #include "Stack.h" -#include "RuntimeManager.h" -#include "Runtime.h" +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" +#include "Runtime.h" namespace dev { diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 0a549597f..4b6fa374f 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 46fd5c9b7..b8a4a09eb 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -1,11 +1,12 @@ #pragma once -#include "Common.h" #include "preprocessor/llvm_includes_start.h" #include #include #include "preprocessor/llvm_includes_end.h" +#include "Common.h" + namespace dev { namespace eth diff --git a/libevmjit/preprocessor/llvm_includes_end.h b/libevmjit/preprocessor/llvm_includes_end.h index 3a47dca15..023c8021e 100644 --- a/libevmjit/preprocessor/llvm_includes_end.h +++ b/libevmjit/preprocessor/llvm_includes_end.h @@ -1,3 +1,5 @@ - -#pragma warning(pop) -#pragma GCC diagnostic pop +#if defined(_MSC_VER) + #pragma warning(pop) +#else + #pragma GCC diagnostic pop +#endif diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h index 264a6e1ef..bf34ade99 100644 --- a/libevmjit/preprocessor/llvm_includes_start.h +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -1,5 +1,8 @@ - -#pragma warning(push) -#pragma warning(disable: 4267 4244 4800) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4267 4244 4800) +#else + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + #pragma GCC diagnostic ignored "-Wconversion" +#endif From 4d2dc802e8b2a69b72fd93eff21bc42651536a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 11:00:07 +0100 Subject: [PATCH 079/118] Introducing CHECK macro - an assert that always has a value --- libevmjit/Cache.cpp | 5 ++++- libevmjit/ExecutionEngine.cpp | 8 +++++--- libevmjit/Utils.h | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index d7d6f1bbb..fe226eefb 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -13,6 +13,7 @@ #include "preprocessor/llvm_includes_end.h" #include "ExecutionEngine.h" +#include "Utils.h" namespace dev { @@ -43,7 +44,9 @@ std::unique_ptr Cache::getObject(std::string const& id) g_listener->stateChanged(ExecState::CacheLoad); CACHE_LOG << id << ": search\n"; - assert(!g_lastObject); + if (!CHECK(!g_lastObject)) + g_lastObject = nullptr; + llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index ff4c64cee..1d2ff91b1 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -18,6 +18,7 @@ #include "Compiler.h" #include "Cache.h" #include "ExecStats.h" +#include "Utils.h" #include "BuildInfo.gen.h" namespace dev @@ -98,7 +99,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) module->setTargetTriple(triple.str()); ee.reset(builder.create()); - if (!ee) + if (!CHECK(ee)) return ReturnCode::LLVMConfigError; module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module ee->setObjectCache(objectCache); @@ -111,7 +112,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); if (!entryFuncPtr) - { + { auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; if (!module) { @@ -127,7 +128,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } - assert(entryFuncPtr); //TODO: Replace it with safe exception + if (!CHECK(entryFuncPtr)) + return ReturnCode::LLVMLinkError; listener->stateChanged(ExecState::Execution); auto returnCode = entryFuncPtr(&runtime); diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 7e6133ced..aad975f5b 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -16,6 +16,9 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; //#define clog(CHANNEL) std::cerr #define clog(CHANNEL) std::ostream(nullptr) +// The same as assert, but expression is always evaluated and result returned +#define CHECK(expr) (assert(expr), expr) + } } } From a61449359bbc3ecdd150fc59cdcecd1fa0355e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 11:18:29 +0100 Subject: [PATCH 080/118] Fix/disable warnings in CPP bridge --- evmjit/CMakeLists.txt | 2 +- evmjit/libevmjit-cpp/Env.cpp | 1 + evmjit/libevmjit-cpp/JitVM.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index 8f3a170d6..14fca2cde 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-unknown-pragmas") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index cdca56b99..ba1f4661e 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -1,4 +1,5 @@ +#pragma GCC diagnostic ignored "-Wconversion" #include #include #include diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 53282e3ae..55dcd94f8 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -1,4 +1,5 @@ +#pragma GCC diagnostic ignored "-Wconversion" #include "JitVM.h" #include #include From 833643ed776184fdf78c80e1103dbe76dd5779b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 11:33:15 +0100 Subject: [PATCH 081/118] Safe assert --- evmjit/libevmjit/ExecStats.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index d8668f636..18419d9e0 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -13,7 +13,9 @@ namespace jit void ExecStats::stateChanged(ExecState _state) { - assert(m_state != ExecState::Finished); + if (!CHECK(m_state != ExecState::Finished)) + return; + auto now = clock::now(); if (_state != ExecState::Started) { From f2f998f6fcb1e68d1fe04ada63c8ba3e18533da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 12:00:32 +0100 Subject: [PATCH 082/118] Build fix --- evmjit/libevmjit/ExecStats.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index 18419d9e0..684f6d39a 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -4,6 +4,8 @@ #include #include +#include "Utils.h" + namespace dev { namespace eth From 2657276cc898409f11336f2a270aee5d9426bbbb Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 20 Feb 2015 12:37:58 +0100 Subject: [PATCH 083/118] fixed web preview --- mix/qml/html/WebContainer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/qml/html/WebContainer.html b/mix/qml/html/WebContainer.html index 26cac5103..e2f97fd86 100644 --- a/mix/qml/html/WebContainer.html +++ b/mix/qml/html/WebContainer.html @@ -17,7 +17,7 @@ reloadPage = function() { updateContracts = function(contracts) { if (window.web3) { - window.web3.provider.polls = []; + window.web3.reset(); window.contracts = {}; for (var c in contracts) { var contract = window.web3.eth.contract(contracts[c].address, contracts[c].interface); From bcb888985343e0a90a1038cbb65ddb1c0951ed64 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 13:04:39 +0100 Subject: [PATCH 084/118] Protocol bump. --- libethcore/CommonEth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index e07eb04ba..2264e6ec9 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -32,7 +32,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 53; +const unsigned c_protocolVersion = 54; const unsigned c_databaseVersion = 5; vector> const& units() From 4ffa45b83fcd116f5feca4945124a1038ad8ff05 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 20 Jan 2015 11:56:06 -0800 Subject: [PATCH 085/118] Genesis info. --- libethereum/BlockChain.cpp | 3 +++ libethereum/CanonBlockChain.cpp | 25 +++++++++++----------- libethereum/GenesisInfo.cpp | 37 +++++++++++++++++++++++++++++++++ libethereum/GenesisInfo.h | 32 ++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 libethereum/GenesisInfo.cpp create mode 100644 libethereum/GenesisInfo.h diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 11ab08ce6..29095076f 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -22,6 +22,7 @@ #include "BlockChain.h" #include +#include #include #include #include @@ -29,11 +30,13 @@ #include #include #include +#include "GenesisInfo.h" #include "State.h" #include "Defaults.h" using namespace std; using namespace dev; using namespace dev::eth; +namespace js = json_spirit; #define ETH_CATCH 1 diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index fc7107154..0e468970c 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -21,6 +21,7 @@ #include "CanonBlockChain.h" +#include #include #include #include @@ -29,11 +30,13 @@ #include #include #include +#include "GenesisInfo.h" #include "State.h" #include "Defaults.h" using namespace std; using namespace dev; using namespace dev::eth; +namespace js = json_spirit; #define ETH_CATCH 1 @@ -42,18 +45,16 @@ std::map const& dev::eth::genesisState() static std::map s_ret; if (s_ret.empty()) { - // Initialise. - for (auto i: vector({ - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "e4157b34ea9615cfbde6b4fda419828124b70c78" - })) - s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation); + js::mValue val; + json_spirit::read_string(c_genesisInfo, val); + for (auto account: val.get_obj()) + if (account.second.get_obj()["code"].get_str().size()) + { + s_ret[Address(fromHex(account.first))] = Account(fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())), Account::ContractConception); + s_ret[Address(fromHex(account.first))].setCode(fromHex(account.second.get_obj()["code"].get_str())); + } + else + s_ret[Address(fromHex(account.first))] = Account(fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())), Account::NormalCreation); } return s_ret; } diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp new file mode 100644 index 000000000..5b5a4ba5d --- /dev/null +++ b/libethereum/GenesisInfo.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 GenesisInfo.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "GenesisInfo.h" + +std::string const dev::eth::c_genesisInfo = +R"ETHEREUM( +{ + "51ba59315b3a95761d0863b05ccc7a7f54703d99": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "6c386a4b26f73c802f34673f7248bb118f97424a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "e4157b34ea9615cfbde6b4fda419828124b70c78": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "000000000000000000000000000000000000002a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000", code: "60035415601c576000600060006000609660020a3360155a03f150005b610100331015602757005b60003560805260805160a060020a02330160a0523460a051540160a051553460805154016080515560006000546003600154041015607557506a027b46536c66c8e300000060005460015401115b608157600060025560a5565b600254608f574260025560a4565b62093a806002544203111560a35760016003555b5b5b" } +} +)ETHEREUM"; diff --git a/libethereum/GenesisInfo.h b/libethereum/GenesisInfo.h new file mode 100644 index 000000000..7775da9e8 --- /dev/null +++ b/libethereum/GenesisInfo.h @@ -0,0 +1,32 @@ +/* + 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 GenesisInfo.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include + +namespace dev { +namespace eth { + +extern std::string const c_genesisInfo; + +} +} From 5da18796730f3c08e246d4bd61b658fd17d4e553 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 21 Jan 2015 11:30:16 -0800 Subject: [PATCH 086/118] Better, modular Genesis info. --- libethereum/CanonBlockChain.cpp | 13 ++++++++++--- libethereum/GenesisInfo.cpp | 6 +++++- libevm/VM.cpp | 5 +++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 0e468970c..50184161e 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -48,13 +48,20 @@ std::map const& dev::eth::genesisState() js::mValue val; json_spirit::read_string(c_genesisInfo, val); for (auto account: val.get_obj()) - if (account.second.get_obj()["code"].get_str().size()) + { + u256 balance; + if (account.second.get_obj().count("balance")) + balance = fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())); + else + balance = u256(account.second.get_obj()["finney"].get_str()) * finney; + if (account.second.get_obj().count("code")) { - s_ret[Address(fromHex(account.first))] = Account(fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())), Account::ContractConception); + s_ret[Address(fromHex(account.first))] = Account(balance, Account::ContractConception); s_ret[Address(fromHex(account.first))].setCode(fromHex(account.second.get_obj()["code"].get_str())); } else - s_ret[Address(fromHex(account.first))] = Account(fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())), Account::NormalCreation); + s_ret[Address(fromHex(account.first))] = Account(balance, Account::NormalCreation); + } } return s_ret; } diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp index 5b5a4ba5d..b417837a7 100644 --- a/libethereum/GenesisInfo.cpp +++ b/libethereum/GenesisInfo.cpp @@ -32,6 +32,10 @@ R"ETHEREUM( "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "6c386a4b26f73c802f34673f7248bb118f97424a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "e4157b34ea9615cfbde6b4fda419828124b70c78": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "000000000000000000000000000000000000002a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000", code: "60035415601c576000600060006000609660020a3360155a03f150005b610100331015602757005b60003560805260805160a060020a02330160a0523460a051540160a051553460805154016080515560006000546003600154041015607557506a027b46536c66c8e300000060005460015401115b608157600060025560a5565b600254608f574260025560a4565b62093a806002544203111560a35760016003555b5b5b" } + "000000000000000000000000000000000000002a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000", "code": "60035415601c576000600060006000609660020a3360155a03f150005b610100331015602757005b60003560805260805160a060020a02330160a0523460a051540160a051553460805154016080515560006000546003600154041015607557506a027b46536c66c8e300000060005460015401115b608157600060025560a5565b600254608f574260025560a4565b62093a806002544203111560a35760016003555b5b5b" }, + "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": { "finney": "154162184" }, + "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": { "finney": "102774789" }, + "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": { "finney": "51387394" }, + "b7576e9d314df41ec5506494293afb1bd5d3f65d": { "finney": "69423399" }, } )ETHEREUM"; diff --git a/libevm/VM.cpp b/libevm/VM.cpp index d60f585a5..a922cbf14 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -34,7 +34,8 @@ void VM::reset(u256 _gas) noexcept bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { - auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; + auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; + auto gasForMem = [](bigint _size) -> bigint { bigint s = _size / 32; return (bigint)c_memoryGas * (s + s * s / 1024); }; if (m_jumpDests.empty()) for (unsigned i = 0; i < _ext.code.size(); ++i) @@ -297,7 +298,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) newTempSize = (newTempSize + 31) / 32 * 32; if (newTempSize > m_temp.size()) - runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; + runGas += gasForMem(newTempSize) - gasForMem(m_temp.size()); runGas += c_copyGas * (copySize + 31) / 32; onOperation(); From 13ee1d0f511e94e2181842fb2c725eba4d55e836 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 20 Feb 2015 14:05:44 +0100 Subject: [PATCH 087/118] use windeployqt for deployment on windows --- cmake/EthDependencies.cmake | 5 ++++ cmake/EthExecutableHelper.cmake | 46 +++++---------------------------- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index fb6b09bb8..3f6cbcd77 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -128,6 +128,11 @@ if (NOT HEADLESS) set (MACDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/macdeployqt) message(" - macdeployqt path: ${MACDEPLOYQT_APP}") endif() + # we need to find path to windeployqt on windows + if (WIN32) + set (WINDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/windeployqt) + message(" - windeployqt path: ${WINDEPLOYQT_APP}") + endif() # TODO check node && npm version find_program(ETH_NODE node) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 427e0a9c4..7d6edef34 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -63,7 +63,7 @@ macro(eth_install_executable EXECUTABLE) if (APPLE) set(eth_qml_dir "-qmldir=${ETH_INSTALL_EXECUTABLE_QMLDIR}") elseif (WIN32) - set(eth_qml_dir --qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}) + set(eth_qml_dir "--qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}") endif() message(STATUS "${EXECUTABLE} qmldir: ${eth_qml_dir}") endif() @@ -88,49 +88,17 @@ macro(eth_install_executable EXECUTABLE) set(BU_CHMOD_BUNDLE_ITEMS 1) verify_app(\"${APP_BUNDLE_PATH}\") " COMPONENT RUNTIME ) - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - - # copy all dlls to executable directory - # TODO improve that by copying only required dlls - file (GLOB DLLS ${ETH_DEPENDENCY_INSTALL_DIR}/bin/*.dll) - - foreach(DLL ${DLLS}) - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy "${DLL}" "$" - ) - endforeach() + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy_directory - "${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms" - $/platforms + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir} --verbose 100" + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) - - # ugly way, improve that + #workaround for https://bugreports.qt.io/browse/QTBUG-42083 add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy_directory - "${ETH_DEPENDENCY_INSTALL_DIR}/qml" - $ - ) - - install( FILES ${DLLS} - DESTINATION bin - COMPONENT ${EXECUTABLE} - ) - - install( DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms - DESTINATION bin - COMPONENT ${EXECUTABLE} + COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM ) - - file (GLOB QMLS ${ETH_DEPENDENCY_INSTALL_DIR}/qml/*) - foreach(QML ${QMLS}) - install( DIRECTORY ${QML} - DESTINATION bin - COMPONENT ${EXECUTABLE} - ) - endforeach() - install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin COMPONENT ${EXECUTABLE} From 6fbee922e054eadbcd5bfb91619981faadd2a748 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 14:10:03 +0100 Subject: [PATCH 088/118] Remove genesis contract. --- libethereum/GenesisInfo.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp index b417837a7..0a7572dd6 100644 --- a/libethereum/GenesisInfo.cpp +++ b/libethereum/GenesisInfo.cpp @@ -24,7 +24,7 @@ std::string const dev::eth::c_genesisInfo = R"ETHEREUM( { - "51ba59315b3a95761d0863b05ccc7a7f54703d99": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, @@ -32,7 +32,6 @@ R"ETHEREUM( "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "6c386a4b26f73c802f34673f7248bb118f97424a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "e4157b34ea9615cfbde6b4fda419828124b70c78": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "000000000000000000000000000000000000002a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000", "code": "60035415601c576000600060006000609660020a3360155a03f150005b610100331015602757005b60003560805260805160a060020a02330160a0523460a051540160a051553460805154016080515560006000546003600154041015607557506a027b46536c66c8e300000060005460015401115b608157600060025560a5565b600254608f574260025560a4565b62093a806002544203111560a35760016003555b5b5b" }, "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": { "finney": "154162184" }, "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": { "finney": "102774789" }, "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": { "finney": "51387394" }, From 4e6f4013a50121a877151d0381a761267eba549f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 15:30:40 +0100 Subject: [PATCH 089/118] Decimal wei rather than hex balance. Memory back to linear cost. --- libethereum/CanonBlockChain.cpp | 4 ++-- libethereum/GenesisInfo.cpp | 16 ++++++++-------- libevm/VM.cpp | 7 ++++++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 50184161e..b0fe90a78 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -50,8 +50,8 @@ std::map const& dev::eth::genesisState() for (auto account: val.get_obj()) { u256 balance; - if (account.second.get_obj().count("balance")) - balance = fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())); + if (account.second.get_obj().count("wei")) + balance = u256(account.second.get_obj()["wei"].get_str()); else balance = u256(account.second.get_obj()["finney"].get_str()) * finney; if (account.second.get_obj().count("code")) diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp index 0a7572dd6..b9b45d4b4 100644 --- a/libethereum/GenesisInfo.cpp +++ b/libethereum/GenesisInfo.cpp @@ -24,14 +24,14 @@ std::string const dev::eth::c_genesisInfo = R"ETHEREUM( { - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "6c386a4b26f73c802f34673f7248bb118f97424a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "e4157b34ea9615cfbde6b4fda419828124b70c78": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "e6716f9544a56c530d868e4bfbacb172315bdead": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "6c386a4b26f73c802f34673f7248bb118f97424a": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "e4157b34ea9615cfbde6b4fda419828124b70c78": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": { "finney": "154162184" }, "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": { "finney": "102774789" }, "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": { "finney": "51387394" }, diff --git a/libevm/VM.cpp b/libevm/VM.cpp index a922cbf14..a7ca91533 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -35,7 +35,12 @@ void VM::reset(u256 _gas) noexcept bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; - auto gasForMem = [](bigint _size) -> bigint { bigint s = _size / 32; return (bigint)c_memoryGas * (s + s * s / 1024); }; + auto gasForMem = [](bigint _size) -> bigint + { + bigint s = _size / 32; +// return (bigint)c_memoryGas * (s + s * s / 1024); + return (bigint)c_memoryGas * s; + }; if (m_jumpDests.empty()) for (unsigned i = 0; i < _ext.code.size(); ++i) From f71337400b88716a3daa27a2aefe7edcc42d6652 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 20 Feb 2015 15:47:07 +0100 Subject: [PATCH 090/118] removed verbosity flag --- cmake/EthExecutableHelper.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 7d6edef34..c6e0210de 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -91,7 +91,7 @@ macro(eth_install_executable EXECUTABLE) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir} --verbose 100" + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) #workaround for https://bugreports.qt.io/browse/QTBUG-42083 From 73d5ff677e8c768c282e87ffc57a60420388d7f5 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 10:51:22 +0100 Subject: [PATCH 091/118] Refactored account management out of WebThreeStubServerBase. --- libdevcrypto/Common.cpp | 2 + libdevcrypto/Common.h | 3 ++ libweb3jsonrpc/WebThreeStubServerBase.cpp | 66 ++++++++++++----------- libweb3jsonrpc/WebThreeStubServerBase.h | 33 ++++++++++-- 4 files changed, 68 insertions(+), 36 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 0a94662c8..048134de8 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -44,6 +44,8 @@ bool dev::SignatureStruct::isValid() const return true; } +Address dev::ZeroAddress = Address(); + Public dev::toPublic(Secret const& _secret) { Public p; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index e91df2526..ccbd0953b 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -62,6 +62,9 @@ struct SignatureStruct /// @NOTE This is not endian-specific; it's just a bunch of bytes. using Address = h160; +/// The zero address. +extern Address ZeroAddress; + /// A vector of Ethereum addresses. using Addresses = h160s; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 8e0b30366..185d3f6e0 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -211,22 +211,33 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message return res; } -WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): - AbstractWebThreeStubServer(_conn) -{ - setAccounts(_accounts); -} - -void WebThreeStubServerBase::setAccounts(std::vector const& _accounts) +void AccountHolder::setAccounts(std::vector const& _accounts) { m_accounts.clear(); - for (auto const& i: _accounts) + for (auto const& keyPair: _accounts) { - m_accounts.push_back(i.address()); - m_accountsLookup[i.address()] = i; + m_accounts.push_back(keyPair.address()); + m_keyPairs[keyPair.address()] = keyPair; } } +Address const& AccountHolder::getDefaultCallAccount() const +{ + if (m_accounts.empty()) + return ZeroAddress; + Address const* bestMatch = &m_accounts.front(); + for (auto const& account: m_accounts) + if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) + bestMatch = &account; + return *bestMatch; +} + +WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): + AbstractWebThreeStubServer(_conn), m_accounts(std::bind(&WebThreeStubServerBase::client, this)) +{ + m_accounts.setAccounts(_accounts); +} + void WebThreeStubServerBase::setIdentities(std::vector const& _ids) { m_ids.clear(); @@ -242,7 +253,7 @@ std::string WebThreeStubServerBase::web3_sha3(std::string const& _param1) Json::Value WebThreeStubServerBase::eth_accounts() { Json::Value ret(Json::arrayValue); - for (auto const& i: m_accounts) + for (auto const& i: m_accounts.getAllAccounts()) ret.append(toJS(i)); return ret; } @@ -326,21 +337,15 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) - { - auto b = m_accounts.front(); - for (auto const& a: m_accounts) - if (client()->balanceAt(a) > client()->balanceAt(b)) - b = a; - t.from = b; - } - if (!m_accountsLookup.count(t.from)) + if (!t.from) + t.from = m_accounts.getDefaultCallAccount(); + if (!m_accounts.isRealAccount(t.from)) return ret; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - ret = toJS(client()->call(m_accountsLookup[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->call(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice)); return ret; } @@ -684,16 +689,14 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) + if (!t.from) + t.from = m_accounts.getDefaultCallAccount(); + if (!m_accounts.isRealAccount(t.from)) { - auto b = m_accounts.front(); - for (auto const& a: m_accounts) - if (client()->balanceAt(a) > client()->balanceAt(b)) - b = a; - t.from = b; - } - if (!m_accountsLookup.count(t.from)) +// if (m_accounts.isProxyAccount(t.from)) +// m_accounts.storeTransaction(t); return ret; + } if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) @@ -702,9 +705,9 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { if (t.to) // TODO: from qethereum, insert validification hook here. - client()->transact(m_accountsLookup[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); + client()->transact(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); else - ret = toJS(client()->transact(m_accountsLookup[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->transact(m_accounts.secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); client()->flushTransactions(); } return ret; @@ -741,4 +744,3 @@ bool WebThreeStubServerBase::eth_uninstallFilter(int _id) client()->uninstallWatch(_id); return true; } - diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index ec83c9797..988f13b8f 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include #include #pragma GCC diagnostic push @@ -53,6 +54,32 @@ public: virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; }; + +/** + * Manages real accounts (where we know the secret key) and proxy accounts (where transactions + * to be sent from these accounts are forwarded to a proxy on the other side). + */ +class AccountHolder +{ +public: + explicit AccountHolder(std::function const& _client): m_client(_client) {} + + /// Sets or resets the list of real accounts. + void setAccounts(std::vector const& _accounts); + std::vector const& getRealAccounts() const { return m_accounts; } + bool isRealAccount(dev::Address const& _account) const { return m_keyPairs.count(_account) > 0; } + Secret const& secretKey(dev::Address const& _account) const { return m_keyPairs.at(_account).secret(); } + std::vector const& getAllAccounts() const { return m_accounts; /*todo */} + dev::Address const& getDefaultCallAccount() const; + +private: + std::map m_keyPairs; + std::vector m_accounts; + std::function m_client; + +}; + + /** * @brief JSON-RPC api implementation * @todo filters should work on unsigned instead of int @@ -125,7 +152,7 @@ public: virtual bool shh_post(Json::Value const& _json); virtual bool shh_uninstallFilter(int _id); - void setAccounts(std::vector const& _accounts); + void setAccounts(std::vector const& _accounts) { m_accounts.setAccounts(_accounts); } void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } @@ -138,11 +165,9 @@ protected: virtual dev::WebThreeNetworkFace* network() = 0; virtual dev::WebThreeStubDatabaseFace* db() = 0; - std::map m_accountsLookup; - std::vector m_accounts; - std::map m_ids; std::map m_shhWatches; + AccountHolder m_accounts; }; } //namespace dev From 0b014457d4b631924a0811f3104572aad3f0fc3e Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 15:13:03 +0100 Subject: [PATCH 092/118] Implemented account proxy queues. --- libweb3jsonrpc/AccountHolder.cpp | 102 ++++++++++++++++++++ libweb3jsonrpc/AccountHolder.h | 74 ++++++++++++++ libweb3jsonrpc/WebThreeStubServerBase.cpp | 91 ++++++++++------- libweb3jsonrpc/WebThreeStubServerBase.h | 37 ++----- libweb3jsonrpc/abstractwebthreestubserver.h | 18 ++++ libweb3jsonrpc/spec.json | 4 + test/AccountHolder.cpp | 74 ++++++++++++++ test/webthreestubclient.h | 30 ++++++ 8 files changed, 365 insertions(+), 65 deletions(-) create mode 100644 libweb3jsonrpc/AccountHolder.cpp create mode 100644 libweb3jsonrpc/AccountHolder.h create mode 100644 test/AccountHolder.cpp diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp new file mode 100644 index 000000000..e12380110 --- /dev/null +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -0,0 +1,102 @@ +/* + 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 AccountHolder.cpp + * @authors: + * Christian R + * Lefteris Karapetsas + * @date 2015 + */ + +#include "AccountHolder.h" +#include + + +using namespace std; +using namespace dev; +using namespace dev::eth; + +vector emptyQueue; + +void AccountHolder::setAccounts(vector const& _accounts) +{ + m_accounts.clear(); + for (auto const& keyPair: _accounts) + { + m_accounts.push_back(keyPair.address()); + m_keyPairs[keyPair.address()] = keyPair; + } +} + +vector
AccountHolder::getAllAccounts() const +{ + vector
accounts = m_accounts; + for (auto const& pair: m_proxyAccounts) + if (!isRealAccount(pair.first)) + accounts.push_back(pair.first); + return accounts; +} + +Address const& AccountHolder::getDefaultCallAccount() const +{ + if (m_accounts.empty()) + return ZeroAddress; + Address const* bestMatch = &m_accounts.front(); + for (auto const& account: m_accounts) + if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) + bestMatch = &account; + return *bestMatch; +} + +int AccountHolder::addProxyAccount(const Address& _account) +{ + int const c_id = m_transactionQueues.empty() ? 1 : m_transactionQueues.rbegin()->first + 1; + if (isProxyAccount(_account)) + return 0; + m_proxyAccounts.insert(make_pair(_account, c_id)); + m_transactionQueues[c_id].first = _account; + return c_id; +} + +bool AccountHolder::removeProxyAccount(unsigned _id) +{ + if (!m_transactionQueues.count(_id)) + return false; + m_proxyAccounts.erase(m_transactionQueues[_id].first); + m_transactionQueues.erase(_id); + return true; +} + +void AccountHolder::queueTransaction(TransactionSkeleton const& _transaction) +{ + if (!m_proxyAccounts.count(_transaction.from)) + return; + int id = m_proxyAccounts[_transaction.from]; + m_transactionQueues[id].second.push_back(_transaction); +} + +vector const& AccountHolder::getQueuedTransactions(int _id) const +{ + if (!m_transactionQueues.count(_id)) + return emptyQueue; + return m_transactionQueues.at(_id).second; +} + +void AccountHolder::clearQueue(int _id) +{ + if (m_transactionQueues.count(_id)) + m_transactionQueues.at(_id).second.clear(); +} diff --git a/libweb3jsonrpc/AccountHolder.h b/libweb3jsonrpc/AccountHolder.h new file mode 100644 index 000000000..939947ea2 --- /dev/null +++ b/libweb3jsonrpc/AccountHolder.h @@ -0,0 +1,74 @@ +/* + 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 AccountHolder.h + * @authors: + * Christian R + * Lefteris Karapetsas + * @date 2015 + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ +class Interface; +} + +/** + * Manages real accounts (where we know the secret key) and proxy accounts (where transactions + * to be sent from these accounts are forwarded to a proxy on the other side). + */ +class AccountHolder +{ +public: + explicit AccountHolder(std::function const& _client): m_client(_client) {} + + /// Sets or resets the list of real accounts. + void setAccounts(std::vector const& _accounts); + std::vector
const& getRealAccounts() const { return m_accounts; } + bool isRealAccount(Address const& _account) const { return m_keyPairs.count(_account) > 0; } + bool isProxyAccount(Address const& _account) const { return m_proxyAccounts.count(_account) > 0; } + Secret const& secretKey(Address const& _account) const { return m_keyPairs.at(_account).secret(); } + std::vector
getAllAccounts() const; + Address const& getDefaultCallAccount() const; + + int addProxyAccount(Address const& _account); + bool removeProxyAccount(unsigned _id); + void queueTransaction(eth::TransactionSkeleton const& _transaction); + + std::vector const& getQueuedTransactions(int _id) const; + void clearQueue(int _id); + +private: + using TransactionQueue = std::vector; + + std::map m_keyPairs; + std::vector
m_accounts; + std::map m_proxyAccounts; + std::map> m_transactionQueues; + std::function m_client; +}; + +} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 185d3f6e0..b5cc6e078 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -35,6 +35,7 @@ #include #endif #include "WebThreeStubServerBase.h" +#include "AccountHolder.h" using namespace std; using namespace dev; @@ -72,6 +73,18 @@ static Json::Value toJson(dev::eth::Transaction const& _t) return res; } +static Json::Value toJson(dev::eth::TransactionSkeleton const& _t) +{ + Json::Value res; + res["to"] = toJS(_t.to); + res["from"] = toJS(_t.from); + res["gas"] = (int)_t.gas; + res["gasPrice"] = toJS(_t.gasPrice); + res["value"] = toJS(_t.value); + res["data"] = jsFromBinary(_t.data); + return res; +} + static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) { Json::Value res; @@ -211,31 +224,10 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message return res; } -void AccountHolder::setAccounts(std::vector const& _accounts) -{ - m_accounts.clear(); - for (auto const& keyPair: _accounts) - { - m_accounts.push_back(keyPair.address()); - m_keyPairs[keyPair.address()] = keyPair; - } -} - -Address const& AccountHolder::getDefaultCallAccount() const -{ - if (m_accounts.empty()) - return ZeroAddress; - Address const* bestMatch = &m_accounts.front(); - for (auto const& account: m_accounts) - if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) - bestMatch = &account; - return *bestMatch; -} - WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): - AbstractWebThreeStubServer(_conn), m_accounts(std::bind(&WebThreeStubServerBase::client, this)) + AbstractWebThreeStubServer(_conn), m_accounts(make_shared(std::bind(&WebThreeStubServerBase::client, this))) { - m_accounts.setAccounts(_accounts); + m_accounts->setAccounts(_accounts); } void WebThreeStubServerBase::setIdentities(std::vector const& _ids) @@ -253,7 +245,7 @@ std::string WebThreeStubServerBase::web3_sha3(std::string const& _param1) Json::Value WebThreeStubServerBase::eth_accounts() { Json::Value ret(Json::arrayValue); - for (auto const& i: m_accounts.getAllAccounts()) + for (auto const& i: m_accounts->getAllAccounts()) ret.append(toJS(i)); return ret; } @@ -338,14 +330,14 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) std::string ret; TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts.getDefaultCallAccount(); - if (!m_accounts.isRealAccount(t.from)) + t.from = m_accounts->getDefaultCallAccount(); + if (!m_accounts->isRealAccount(t.from)) return ret; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - ret = toJS(client()->call(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->call(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice)); return ret; } @@ -469,6 +461,25 @@ bool WebThreeStubServerBase::eth_submitWork(std::string const& _nonce) return client()->submitNonce(jsToFixed<32>(_nonce)); } +int WebThreeStubServerBase::eth_register(std::string const& _address) +{ + return m_accounts->addProxyAccount(jsToAddress(_address)); +} + +bool WebThreeStubServerBase::eth_unregister(int _id) +{ + return m_accounts->removeProxyAccount(_id); +} + +Json::Value WebThreeStubServerBase::eth_queuedTransactions(int _id) +{ + Json::Value ret(Json::arrayValue); + for (TransactionSkeleton const& t: m_accounts->getQueuedTransactions(_id)) + ret.append(toJson(t)); + m_accounts->clearQueue(_id); + return ret; +} + std::string WebThreeStubServerBase::shh_newGroup(std::string const& _id, std::string const& _who) { (void)_id; @@ -690,24 +701,27 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) std::string ret; TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts.getDefaultCallAccount(); - if (!m_accounts.isRealAccount(t.from)) - { -// if (m_accounts.isProxyAccount(t.from)) -// m_accounts.storeTransaction(t); - return ret; - } + t.from = m_accounts->getDefaultCallAccount(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + if (!m_accounts->isRealAccount(t.from)) + { + if (m_accounts->isProxyAccount(t.from)) + { + // todo "authenticate for proxy" + m_accounts->queueTransaction(t); + } + return ret; + } if (authenticate(t)) { if (t.to) // TODO: from qethereum, insert validification hook here. - client()->transact(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); + client()->transact(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); else - ret = toJS(client()->transact(m_accounts.secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->transact(m_accounts->secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); client()->flushTransactions(); } return ret; @@ -744,3 +758,8 @@ bool WebThreeStubServerBase::eth_uninstallFilter(int _id) client()->uninstallWatch(_id); return true; } + +void WebThreeStubServerBase::setAccounts(const std::vector& _accounts) +{ + m_accounts->setAccounts(_accounts); +} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 988f13b8f..62260d11d 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -23,8 +23,8 @@ #pragma once +#include #include -#include #include #include #pragma GCC diagnostic push @@ -36,6 +36,7 @@ namespace dev { class WebThreeNetworkFace; +class AccountHolder; class KeyPair; namespace eth { @@ -54,32 +55,6 @@ public: virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; }; - -/** - * Manages real accounts (where we know the secret key) and proxy accounts (where transactions - * to be sent from these accounts are forwarded to a proxy on the other side). - */ -class AccountHolder -{ -public: - explicit AccountHolder(std::function const& _client): m_client(_client) {} - - /// Sets or resets the list of real accounts. - void setAccounts(std::vector const& _accounts); - std::vector const& getRealAccounts() const { return m_accounts; } - bool isRealAccount(dev::Address const& _account) const { return m_keyPairs.count(_account) > 0; } - Secret const& secretKey(dev::Address const& _account) const { return m_keyPairs.at(_account).secret(); } - std::vector const& getAllAccounts() const { return m_accounts; /*todo */} - dev::Address const& getDefaultCallAccount() const; - -private: - std::map m_keyPairs; - std::vector m_accounts; - std::function m_client; - -}; - - /** * @brief JSON-RPC api implementation * @todo filters should work on unsigned instead of int @@ -137,6 +112,10 @@ public: virtual Json::Value eth_getWork(); virtual bool eth_submitWork(std::string const& _nonce); + virtual int eth_register(std::string const& _address); + virtual bool eth_unregister(int _id); + virtual Json::Value eth_queuedTransactions(int _id); + virtual std::string db_get(std::string const& _name, std::string const& _key); virtual std::string db_getString(std::string const& _name, std::string const& _key); virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value); @@ -152,7 +131,7 @@ public: virtual bool shh_post(Json::Value const& _json); virtual bool shh_uninstallFilter(int _id); - void setAccounts(std::vector const& _accounts) { m_accounts.setAccounts(_accounts); } + void setAccounts(std::vector const& _accounts); void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } @@ -167,7 +146,7 @@ protected: std::map m_ids; std::map m_shhWatches; - AccountHolder m_accounts; + std::shared_ptr m_accounts; }; } //namespace dev diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 53d7f856d..e40c68acd 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -55,6 +55,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI); this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_register", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_registerI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_unregister", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_unregisterI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_queuedTransactions", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_queuedTransactionsI); this->bindAndAddMethod(jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI); this->bindAndAddMethod(jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI); this->bindAndAddMethod(jsonrpc::Procedure("db_putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putStringI); @@ -253,6 +256,18 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_submitWork(request[0u].asString()); } + inline virtual void eth_registerI(const Json::Value &request, Json::Value &response) + { + response = this->eth_register(request[0u].asString()); + } + inline virtual void eth_unregisterI(const Json::Value &request, Json::Value &response) + { + response = this->eth_unregister(request[0u].asInt()); + } + inline virtual void eth_queuedTransactionsI(const Json::Value &request, Json::Value &response) + { + response = this->eth_queuedTransactions(request[0u].asInt()); + } inline virtual void db_putI(const Json::Value &request, Json::Value &response) { response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString()); @@ -349,6 +364,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer. + */ +/** + * @author Christian R + * @date 2015 + * Unit tests for the account holder used by the WebThreeStubServer. + */ + +#include +#include + +namespace dev +{ +namespace test +{ + +BOOST_AUTO_TEST_SUITE(AccountHolderTest) + +BOOST_AUTO_TEST_CASE(ProxyAccountUseCase) +{ + AccountHolder h = AccountHolder(std::function()); + BOOST_CHECK(h.getAllAccounts().empty()); + BOOST_CHECK(h.getRealAccounts().empty()); + Address addr("abababababababababababababababababababab"); + Address addr2("abababababababababababababababababababab"); + int id = h.addProxyAccount(addr); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + // register it again + int secondID = h.addProxyAccount(addr); + BOOST_CHECK(h.getQueuedTransactions(secondID).empty()); + + eth::TransactionSkeleton t1; + eth::TransactionSkeleton t2; + t1.from = addr; + t1.data = fromHex("12345678"); + t2.from = addr; + t2.data = fromHex("abcdef"); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + h.queueTransaction(t1); + BOOST_CHECK_EQUAL(1, h.getQueuedTransactions(id).size()); + h.queueTransaction(t2); + BOOST_REQUIRE_EQUAL(2, h.getQueuedTransactions(id).size()); + + // second proxy should not see transactions + BOOST_CHECK(h.getQueuedTransactions(secondID).empty()); + + BOOST_CHECK(h.getQueuedTransactions(id)[0].data == t1.data); + BOOST_CHECK(h.getQueuedTransactions(id)[1].data == t2.data); + + h.clearQueue(id); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + // removing fails because it never existed + BOOST_CHECK(!h.removeProxyAccount(secondID)); + BOOST_CHECK(h.removeProxyAccount(id)); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} diff --git a/test/webthreestubclient.h b/test/webthreestubclient.h index ee175b058..70aa9db99 100644 --- a/test/webthreestubclient.h +++ b/test/webthreestubclient.h @@ -447,6 +447,36 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + int eth_register(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_register",p); + if (result.isInt()) + return result.asInt(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool eth_unregister(int param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_unregister",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value eth_queuedTransactions(int param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_queuedTransactions",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; From 78d9e1be94aa49c667ef4dc47a9e379dec9c91b0 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 15:15:30 +0100 Subject: [PATCH 093/118] Renamed method. --- libweb3jsonrpc/AccountHolder.cpp | 2 +- libweb3jsonrpc/AccountHolder.h | 2 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp index e12380110..a7bdc7a68 100644 --- a/libweb3jsonrpc/AccountHolder.cpp +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -50,7 +50,7 @@ vector
AccountHolder::getAllAccounts() const return accounts; } -Address const& AccountHolder::getDefaultCallAccount() const +Address const& AccountHolder::getDefaultTransactAccount() const { if (m_accounts.empty()) return ZeroAddress; diff --git a/libweb3jsonrpc/AccountHolder.h b/libweb3jsonrpc/AccountHolder.h index 939947ea2..52005b51f 100644 --- a/libweb3jsonrpc/AccountHolder.h +++ b/libweb3jsonrpc/AccountHolder.h @@ -52,7 +52,7 @@ public: bool isProxyAccount(Address const& _account) const { return m_proxyAccounts.count(_account) > 0; } Secret const& secretKey(Address const& _account) const { return m_keyPairs.at(_account).secret(); } std::vector
getAllAccounts() const; - Address const& getDefaultCallAccount() const; + Address const& getDefaultTransactAccount() const; int addProxyAccount(Address const& _account); bool removeProxyAccount(unsigned _id); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index b5cc6e078..d5da8a044 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -330,7 +330,7 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) std::string ret; TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts->getDefaultCallAccount(); + t.from = m_accounts->getDefaultTransactAccount(); if (!m_accounts->isRealAccount(t.from)) return ret; if (!t.gasPrice) @@ -701,7 +701,7 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) std::string ret; TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts->getDefaultCallAccount(); + t.from = m_accounts->getDefaultTransactAccount(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) From 954d818f30c8be9e111e248f77c042778ee07939 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 18:08:18 +0100 Subject: [PATCH 094/118] Session id as random number and authentication popup for proxies. --- alethzero/OurWebThreeStubServer.cpp | 25 +++++++++++++---------- alethzero/OurWebThreeStubServer.h | 8 ++++---- libweb3jsonrpc/AccountHolder.cpp | 18 ++++++++-------- libweb3jsonrpc/WebThreeStubServerBase.cpp | 13 ++++++------ libweb3jsonrpc/WebThreeStubServerBase.h | 2 +- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 2d1dd0481..5b5ce420a 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -51,22 +51,24 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string return button == QMessageBox::Ok; } -bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) const { - return showAuthenticationPopup("Contract Creation Transaction", "ÐApp is attemping to create a contract; to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); + return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) const { - return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); + return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + +", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) const { return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", "ÐApp is attempting to call into an unknown contract at address " + - m_main->pretty(_t.to).toStdString() + - ".\n\nCall involves sending " + + m_main->pretty(_t.to).toStdString() + ".\n\n" + + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + + "Call involves sending " + formatBalance(_t.value) + " to the recipient, with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + "However, this also does other stuff which we don't understand, and does so in your name.\n\n" + @@ -76,25 +78,25 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); } -bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t) +bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) { if (_t.creation) { // recipient has no code - nothing special about this transaction, show basic value transfer info - return showCreationNotice(_t); + return showCreationNotice(_t, _toProxy); } h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); if (contractCodeHash == EmptySHA3) { // recipient has no code - nothing special about this transaction, show basic value transfer info - return showSendNotice(_t); + return showSendNotice(_t, _toProxy); } string userNotice = m_main->natSpec()->getUserNotice(contractCodeHash, _t.data); if (userNotice.empty()) - return showUnknownCallNotice(_t); + return showUnknownCallNotice(_t, _toProxy); NatspecExpressionEvaluator evaluator; userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString(); @@ -104,6 +106,7 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t) "ÐApp attempting to conduct contract interaction with " + m_main->pretty(_t.to).toStdString() + ": " + userNotice + ".\n\n" + + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + (_t.value > 0 ? "In addition, ÐApp is attempting to send " + formatBalance(_t.value) + " to said recipient, with additional network fees of up to " + diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index fbdae7d03..1ab5f813c 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -35,16 +35,16 @@ public: std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); + virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); signals: void onNewId(QString _s); private: bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; - bool showCreationNotice(dev::eth::TransactionSkeleton const& _t) const; - bool showSendNotice(dev::eth::TransactionSkeleton const& _t) const; - bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t) const; + bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; + bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; + bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; dev::WebThreeDirect* m_web3; Main* m_main; diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp index a7bdc7a68..6db41cbbf 100644 --- a/libweb3jsonrpc/AccountHolder.cpp +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -22,14 +22,15 @@ */ #include "AccountHolder.h" +#include +#include #include - using namespace std; using namespace dev; using namespace dev::eth; -vector emptyQueue; +vector g_emptyQueue; void AccountHolder::setAccounts(vector const& _accounts) { @@ -63,12 +64,13 @@ Address const& AccountHolder::getDefaultTransactAccount() const int AccountHolder::addProxyAccount(const Address& _account) { - int const c_id = m_transactionQueues.empty() ? 1 : m_transactionQueues.rbegin()->first + 1; - if (isProxyAccount(_account)) + static std::mt19937 s_randomNumberGenerator(time(0)); + int id = std::uniform_int_distribution(1)(s_randomNumberGenerator); + if (isProxyAccount(_account) || id == 0 || m_transactionQueues.count(id)) return 0; - m_proxyAccounts.insert(make_pair(_account, c_id)); - m_transactionQueues[c_id].first = _account; - return c_id; + m_proxyAccounts.insert(make_pair(_account, id)); + m_transactionQueues[id].first = _account; + return id; } bool AccountHolder::removeProxyAccount(unsigned _id) @@ -91,7 +93,7 @@ void AccountHolder::queueTransaction(TransactionSkeleton const& _transaction) vector const& AccountHolder::getQueuedTransactions(int _id) const { if (!m_transactionQueues.count(_id)) - return emptyQueue; + return g_emptyQueue; return m_transactionQueues.at(_id).second; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index d5da8a044..3fa22a928 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -41,6 +41,7 @@ using namespace std; using namespace dev; using namespace dev::eth; + static Json::Value toJson(dev::eth::BlockInfo const& _bi) { Json::Value res; @@ -78,7 +79,7 @@ static Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value res; res["to"] = toJS(_t.to); res["from"] = toJS(_t.from); - res["gas"] = (int)_t.gas; + res["gas"] = toJS(_t.gas); res["gasPrice"] = toJS(_t.gasPrice); res["value"] = toJS(_t.value); res["data"] = jsFromBinary(_t.data); @@ -709,13 +710,11 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) if (!m_accounts->isRealAccount(t.from)) { if (m_accounts->isProxyAccount(t.from)) - { - // todo "authenticate for proxy" - m_accounts->queueTransaction(t); - } + if (authenticate(t, true)) + m_accounts->queueTransaction(t); return ret; } - if (authenticate(t)) + if (authenticate(t, false)) { if (t.to) // TODO: from qethereum, insert validification hook here. @@ -727,7 +726,7 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) return ret; } -bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t) +bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool) { cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; return true; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 62260d11d..ed2f09d99 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -136,7 +136,7 @@ public: std::map const& ids() const { return m_ids; } protected: - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); + virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); protected: virtual dev::eth::Interface* client() = 0; From 1c1072dff210378d97fb79bacacc338fcba505a1 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 20 Feb 2015 16:25:51 +0100 Subject: [PATCH 095/118] Thread-safe and less predictable random numbers. --- libweb3jsonrpc/AccountHolder.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp index 6db41cbbf..b88397953 100644 --- a/libweb3jsonrpc/AccountHolder.cpp +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -24,6 +24,7 @@ #include "AccountHolder.h" #include #include +#include #include using namespace std; @@ -31,6 +32,8 @@ using namespace dev; using namespace dev::eth; vector g_emptyQueue; +static std::mt19937 g_randomNumberGenerator(time(0)); +static Mutex x_rngMutex; void AccountHolder::setAccounts(vector const& _accounts) { @@ -64,8 +67,9 @@ Address const& AccountHolder::getDefaultTransactAccount() const int AccountHolder::addProxyAccount(const Address& _account) { - static std::mt19937 s_randomNumberGenerator(time(0)); - int id = std::uniform_int_distribution(1)(s_randomNumberGenerator); + Guard g(x_rngMutex); + int id = std::uniform_int_distribution(1)(g_randomNumberGenerator); + id = int(u256(FixedHash<32>(sha3(bytesConstRef((byte*)(&id), sizeof(int) / sizeof(byte)))))); if (isProxyAccount(_account) || id == 0 || m_transactionQueues.count(id)) return 0; m_proxyAccounts.insert(make_pair(_account, id)); From 40effa64466c1a1c96aeec01af1a49eceac5cfa4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 19:47:30 +0100 Subject: [PATCH 096/118] Trie fixes (long time coming). --- exp/main.cpp | 6 ++++-- libdevcrypto/TrieDB.h | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 80f4fa37d..23c907ed1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -33,11 +34,13 @@ #include #include #include +#include using namespace std; using namespace dev; using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; +namespace js = json_spirit; #if 0 int main() @@ -98,8 +101,7 @@ int main() #else int main() { - cnote << KeyPair(Secret("0000000000000000000000000000000000000000000000000000000000000000")).address(); - cnote << KeyPair(Secret("1111111111111111111111111111111111111111111111111111111111111111")).address(); + return 0; } #endif diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 3da63edf4..f5b7ff9c9 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -161,7 +161,7 @@ public: std::string at(bytesConstRef _key) const; void insert(bytesConstRef _key, bytesConstRef _value); void remove(bytesConstRef _key); - void contains(bytesConstRef _key) { return !at(_key).empty(); } + bool contains(bytesConstRef _key) { return !at(_key).empty(); } class iterator { @@ -809,7 +809,10 @@ template bytes GenericTrieDB::deleteAt(RLP const& _orig, NibbleSl // exactly our node - return null. if (k == _k && isLeaf(_orig)) + { + killNode(_orig); return RLPNull; + } // partial key is our key - move down. if (_k.contains(k)) @@ -917,7 +920,6 @@ template bytes GenericTrieDB::place(RLP const& _orig, NibbleSlice tdebug << "place " << _orig << _k; #endif - killNode(_orig); if (_orig.isEmpty()) return (RLPStream(2) << hexPrefixEncode(_k, true) << _s).out(); From 4323c987b77af21a5099ca9e2df1710c024d033f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 21:00:13 +0100 Subject: [PATCH 097/118] cppcheck fixes. --- alethzero/GraphParameters.h | 7 +++++-- alethzero/Grapher.h | 16 ++++++++-------- alethzero/MiningView.cpp | 5 ++--- alethzero/NatspecHandler.cpp | 1 - alethzero/NatspecHandler.h | 2 +- alethzero/Transact.cpp | 2 +- eth/main.cpp | 2 +- evmjit/libevmjit-cpp/Env.cpp | 2 +- libdevcore/Common.cpp | 2 +- libdevcore/Worker.h | 2 +- libdevcore/vector_ref.h | 7 ++++--- libethereum/BlockQueue.cpp | 3 +-- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 ++-- libevm/VMFace.h | 2 +- libevm/VMFactory.cpp | 2 +- libevmcore/Assembly.cpp | 6 +++--- libevmcore/Assembly.h | 2 ++ libp2p/UDP.cpp | 6 +++--- libsolidity/Token.h | 2 +- libsolidity/Types.h | 23 ++++++++++++++++------- 21 files changed, 56 insertions(+), 44 deletions(-) diff --git a/alethzero/GraphParameters.h b/alethzero/GraphParameters.h index e73061335..e1669bd21 100644 --- a/alethzero/GraphParameters.h +++ b/alethzero/GraphParameters.h @@ -37,8 +37,11 @@ static T graphParameters(T _min, T _max, unsigned _divisions, T* o_from = 0, T* T uMax = _max / _divisor; if (uMax == uMin || !_divisions) { - *o_from = 0; - *o_delta = 1; + if (o_delta && o_from) + { + *o_from = 0; + *o_delta = 1; + } return 1; } long double l10 = std::log10((uMax - uMin) / T(_divisions) * 5.5f); diff --git a/alethzero/Grapher.h b/alethzero/Grapher.h index 0f7ccd642..564fe6654 100644 --- a/alethzero/Grapher.h +++ b/alethzero/Grapher.h @@ -76,24 +76,24 @@ public: void labelYOrderedPoints(std::map const& _translatedData, int _maxCount = 20, float _minFactor = .01f) const; protected: - QPainter* p; + QPainter* p = nullptr; QRect active; std::pair xRange; std::pair yRange; - float xM; - float xC; - float yM; - float yC; + float xM = 0; + float xC = 0; + float yM = 0; + float yC = 0; - float dx; - float dy; + float dx = 0; + float dy = 0; std::function xLabel; std::function yLabel; std::function pLabel; - float fontPixelSize; + float fontPixelSize = 0; // Translate from raw indexed data into x/y graph units. Only relevant for indexed data. float xT(float _dataIndex) const { return _dataIndex * xM + xC; } diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index fa6da737b..63d1fcf99 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -48,7 +48,6 @@ string sL(float _x, float _y) { return toString(round(_x * 1000)) + "s (" + toSt MiningView::MiningView(QWidget* _p): QWidget(_p) { - } void MiningView::appendStats(list const& _i, MineProgress const& _p) @@ -86,10 +85,10 @@ void MiningView::appendStats(list const& _i, MineProgress const& _p) for (auto& i: m_resets) i -= o; - remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}); + m_resets.erase(remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}), m_resets.end()); for (auto& i: m_completes) i -= o; - remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}); + m_completes.erase(remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}), m_completes.end()); m_progress = _p; update(); diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index bfdbaa178..27cf00341 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -66,7 +66,6 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran { Json::Value natspec; Json::Value userNotice; - string retStr; m_reader.parse(json, natspec); FixedHash<4> transactionFunctionHash((bytesConstRef(&_transactionData).cropped(0, 4).toBytes())); diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 15ceb7b0b..7aeafec41 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -54,6 +54,6 @@ class NatspecHandler: public NatSpecFace private: ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; - ldb::DB* m_db; + ldb::DB* m_db = nullptr; Json::Reader m_reader; }; diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index bfeb41d9a..1b9a62a2d 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -202,7 +202,7 @@ void Transact::rejigData() for (auto& i: errors) i = "(LLL " + i + ")"; } - catch (string err) + catch (string const& err) { errors.push_back("Serpent " + err); } diff --git a/eth/main.cpp b/eth/main.cpp index f17817fbf..fbf47a69c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -749,7 +749,7 @@ int main(int argc, char** argv) else if (format == "standard+") oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { - dev::eth::VM* vm = (VM*)vvm; + dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE) for (auto const& i: ext->state().storage(ext->myAddress)) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index f89897792..228f637e8 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -70,7 +70,7 @@ extern "C" _env->subBalance(value); auto receiveAddress = right160(*_receiveAddress); auto inRef = bytesConstRef{_inBeg, _inSize}; - auto outRef = bytesConstRef{_outBeg, _outSize}; + auto outRef = bytesRef{_outBeg, _outSize}; OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); auto gas = llvm2eth(*io_gas); diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 365f65202..431a95580 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.8.1"; +char const* Version = "0.8.2"; } diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index f73a0f4aa..40bc118aa 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -64,7 +64,7 @@ protected: private: std::string m_name; - unsigned m_idleWaitMs; + unsigned m_idleWaitMs = 0; mutable Mutex x_work; ///< Lock for the network existance. std::unique_ptr m_work; ///< The network thread. diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 9039c3149..42633f6f1 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -19,7 +19,7 @@ public: vector_ref(): m_data(nullptr), m_count(0) {} vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} - vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data((_T*)_data->data()), m_count(_data->size() / sizeof(_T)) {} + vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {} vector_ref(typename std::conditional::value, std::vector::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {} #ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ @@ -29,9 +29,10 @@ public: bool contentsEqual(std::vector const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); } std::vector toVector() const { return std::vector(m_data, m_data + m_count); } - std::vector toBytes() const { return std::vector((unsigned char const*)m_data, (unsigned char const*)m_data + m_count * sizeof(_T)); } + std::vector toBytes() const { return std::vector(reinterpret_cast(m_data), reinterpret_cast(m_data) + m_count * sizeof(_T)); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); } - template operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); } + template explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); } + operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } _T* data() const { return m_data; } size_t count() const { return m_count; } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index bb5055104..01c8c796c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -59,7 +59,6 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) catch (Exception const& _e) { cwarn << "Ignoring malformed block: " << diagnostic_information(_e); - return false; return ImportResult::Malformed; } #endif @@ -128,7 +127,7 @@ void BlockQueue::drain(std::vector& o_out) void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) { list goodQueue(1, _good); - while (goodQueue.size()) + while (!goodQueue.empty()) { auto r = m_unknown.equal_range(goodQueue.front()); goodQueue.pop_front(); diff --git a/libethereum/Client.h b/libethereum/Client.h index f4ab5ce76..7cd520ab6 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -127,7 +127,7 @@ template struct ABIDeserialiser {}; template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; -template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(bytesRef((byte*)ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; template T abiOut(bytes const& _data) { diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5b9da0cdd..21fa62676 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1199,11 +1199,11 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) else if (j.second) cached.insert(j.first); } - if (delta.size()) + if (!delta.empty()) lead = (lead == " . ") ? "*.* " : "*** "; contout << " @:"; - if (delta.size()) + if (!delta.empty()) contout << "???"; else contout << r[2].toHash(); diff --git a/libevm/VMFace.h b/libevm/VMFace.h index 44ae03868..f8c20feb1 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -40,7 +40,7 @@ public: explicit VMFace(u256 _gas): m_gas(_gas) {} virtual ~VMFace() = default; VMFace(VMFace const&) = delete; - void operator=(VMFace const&) = delete; + VMFace& operator=(VMFace const&) = delete; virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } u256 gas() const noexcept { return m_gas; } diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp index b6549ba04..40f8a3500 100644 --- a/libevm/VMFactory.cpp +++ b/libevm/VMFactory.cpp @@ -39,7 +39,7 @@ void VMFactory::setKind(VMKind _kind) std::unique_ptr VMFactory::create(u256 _gas) { #if ETH_EVMJIT - return std::unique_ptr(g_kind == VMKind::JIT ? (VMFace*)new JitVM(_gas) : new VM(_gas)); + return std::unique_ptr(g_kind == VMKind::JIT ? static_cast(new JitVM(_gas)) : static_cast(new VM(_gas))); #else asserts(g_kind == VMKind::Interpreter && "JIT disabled in build configuration"); return std::unique_ptr(new VM(_gas)); diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 889865d9f..b3cb191b7 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -214,7 +214,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const BOOST_THROW_EXCEPTION(InvalidOpcode()); } - if (m_data.size() || m_subs.size()) + if (!m_data.empty() || !m_subs.empty()) { _out << _prefix << ".data:" << endl; for (auto const& i: m_data) @@ -441,7 +441,7 @@ Assembly& Assembly::optimise(bool _enable) if (i.type() == PushTag) tags.erase(i.data()); - if (tags.size()) + if (tags.empty()) { auto t = *tags.begin(); unsigned i = t.second; @@ -567,7 +567,7 @@ bytes Assembly::assemble() const toBigEndian(tagPos[i.second], r); } - if (m_data.size()) + if (!m_data.empty()) { ret.push_back(0); for (auto const& i: m_data) diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 9d9e4093c..ffe13b34d 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -72,6 +72,8 @@ inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { r class Assembly { public: + Assembly() {} + 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); } diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index e27b6e57a..5d9cdab79 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -38,9 +38,9 @@ h256 RLPXDatagramFace::sign(Secret const& _k) Signature sig = dev::sign(_k, sighash); // S(H(type||data)) data.resize(h256::size + Signature::size + rlpx.size()); - bytesConstRef rlpxHash(&data[0], h256::size); - bytesConstRef rlpxSig(&data[h256::size], Signature::size); - bytesConstRef rlpxPayload(&data[h256::size + Signature::size], rlpx.size()); + bytesRef rlpxHash(&data[0], h256::size); + bytesRef rlpxSig(&data[h256::size], Signature::size); + bytesRef rlpxPayload(&data[h256::size + Signature::size], rlpx.size()); sig.ref().copyTo(rlpxSig); rlpx.copyTo(rlpxPayload); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index e9765e5eb..4aa000475 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -372,7 +372,7 @@ public: static Value AssignmentToBinaryOp(Value op) { solAssert(isAssignmentOp(op) && op != Assign, ""); - return Token::Value(op + (BitOr - AssignBitOr)); + return Value(op + (BitOr - AssignBitOr)); } static bool isBitOp(Value op) { return (BitOr <= op && op <= SHR) || op == BitNot; } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index d529d8d08..af64f1cb5 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -430,12 +430,21 @@ public: Location _location = Location::Internal, bool _arbitraryParameters = false): FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), _location, _arbitraryParameters) {} - FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, - Location _location = Location::Internal, - bool _arbitraryParameters = false, bool _gasSet = false, bool _valueSet = false): - m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), - m_location(_location), - m_arbitraryParameters(_arbitraryParameters), m_gasSet(_gasSet), m_valueSet(_valueSet) {} + FunctionType( + TypePointers const& _parameterTypes, + TypePointers const& _returnParameterTypes, + Location _location = Location::Internal, + bool _arbitraryParameters = false, + bool _gasSet = false, + bool _valueSet = false + ): + m_parameterTypes (_parameterTypes), + m_returnParameterTypes (_returnParameterTypes), + m_location (_location), + m_arbitraryParameters (_arbitraryParameters), + m_gasSet (_gasSet), + m_valueSet (_valueSet) + {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } std::vector const& getParameterNames() const { return m_parameterNames; } @@ -490,7 +499,7 @@ private: bool const m_arbitraryParameters = false; bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack bool const m_valueSet = false; ///< true iff the value to be sent is on the stack - bool m_isConstant; + bool m_isConstant = false; mutable std::unique_ptr m_members; Declaration const* m_declaration = nullptr; }; From 03a9bc31fa2c047ec2944483dd957eadb16345db Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 21:06:13 +0100 Subject: [PATCH 098/118] Minor fix. --- libevmcore/Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index b3cb191b7..37c3ff18d 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -441,7 +441,7 @@ Assembly& Assembly::optimise(bool _enable) if (i.type() == PushTag) tags.erase(i.data()); - if (tags.empty()) + if (!tags.empty()) { auto t = *tags.begin(); unsigned i = t.second; From e185d9a117465a0b792144a99554947aede00eaa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 21:59:21 +0100 Subject: [PATCH 099/118] Add EVMJIT. --- evmjit/.gitignore | 1 + evmjit/CMakeLists.txt | 44 + evmjit/LICENSE.md | 21 + evmjit/README.md | 43 + evmjit/evmcc/CMakeLists.txt | 18 + evmjit/evmcc/evmcc.cpp | 210 ++++ evmjit/evmcc/test/arith/addmod.evm | 1 + evmjit/evmcc/test/arith/addmod.lll | 12 + evmjit/evmcc/test/arith/arith1.evm | 1 + evmjit/evmcc/test/arith/arith1.lll | 37 + evmjit/evmcc/test/arith/arith_bnot.evm | 1 + evmjit/evmcc/test/arith/arith_bnot.lll | 14 + evmjit/evmcc/test/arith/div.evm | 1 + evmjit/evmcc/test/arith/div.lll | 10 + evmjit/evmcc/test/arith/fib1.evm | 1 + evmjit/evmcc/test/arith/fib1.lll | 57 ++ evmjit/evmcc/test/arith/mul.evm | 1 + evmjit/evmcc/test/arith/mul.lll | 13 + evmjit/evmcc/test/arith/mulmod.evm | 1 + evmjit/evmcc/test/arith/mulmod.lll | 12 + evmjit/evmcc/test/except/badinst1.evm | 1 + evmjit/evmcc/test/ext/calldatacopy1.evm | 1 + evmjit/evmcc/test/ext/calldatacopy1.lll | 13 + evmjit/evmcc/test/ext/calldatacopy2.evm | 1 + evmjit/evmcc/test/ext/calldatacopy2.lll | 13 + evmjit/evmcc/test/ext/codecopy1.evm | 1 + evmjit/evmcc/test/ext/codecopy1.lll | 13 + evmjit/evmcc/test/ext/codecopy2.evm | 1 + evmjit/evmcc/test/ext/codecopy2.lll | 13 + evmjit/evmcc/test/ext/codecopy3.evm | 1 + evmjit/evmcc/test/ext/codecopy3.lll | 13 + evmjit/evmcc/test/ext/ext_test.evm | 1 + evmjit/evmcc/test/ext/ext_test.lll | 55 + evmjit/evmcc/test/ext/extcodecopy1.evm | 1 + evmjit/evmcc/test/ext/extcodecopy1.lll | 11 + evmjit/evmcc/test/ext/store_delete.evm | 1 + evmjit/evmcc/test/ext/store_delete.lll | 9 + evmjit/evmcc/test/ext/store_test.evm | 1 + evmjit/evmcc/test/ext/store_test.lll | 14 + evmjit/evmcc/test/jump/ackermann.ethel | 7 + evmjit/evmcc/test/jump/ackermann.evm | 1 + evmjit/evmcc/test/jump/badindirect1.evm | 1 + evmjit/evmcc/test/jump/badindirect1.lll | 9 + evmjit/evmcc/test/jump/badindirect2.evm | 1 + evmjit/evmcc/test/jump/badindirect2.lll | 12 + evmjit/evmcc/test/jump/badjump1.evm | 1 + evmjit/evmcc/test/jump/badjump1.lll | 6 + evmjit/evmcc/test/jump/badjump2.evm | 1 + evmjit/evmcc/test/jump/badjump2.lll | 9 + evmjit/evmcc/test/jump/call1.ethel | 5 + evmjit/evmcc/test/jump/call1.evm | 1 + evmjit/evmcc/test/jump/call2.ethel | 5 + evmjit/evmcc/test/jump/call2.evm | 1 + evmjit/evmcc/test/jump/fac.ethel | 5 + evmjit/evmcc/test/jump/fac.evm | 1 + evmjit/evmcc/test/jump/fac_tail.ethel | 5 + evmjit/evmcc/test/jump/fac_tail.evm | 1 + evmjit/evmcc/test/jump/fib1.ethel | 6 + evmjit/evmcc/test/jump/fib1.evm | 1 + evmjit/evmcc/test/jump/for1.evm | 1 + evmjit/evmcc/test/jump/for1.lll | 3 + evmjit/evmcc/test/jump/for2.evm | 1 + evmjit/evmcc/test/jump/for2.lll | 3 + evmjit/evmcc/test/jump/if1.ethel | 1 + evmjit/evmcc/test/jump/if1.evm | 1 + evmjit/evmcc/test/jump/if2.ethel | 1 + evmjit/evmcc/test/jump/if2.evm | 1 + evmjit/evmcc/test/jump/indirect1.evm | 1 + evmjit/evmcc/test/jump/indirect1.lll | 13 + evmjit/evmcc/test/jump/indirect2.evm | 1 + evmjit/evmcc/test/jump/indirect2.lll | 19 + evmjit/evmcc/test/jump/indirect3.evm | 1 + evmjit/evmcc/test/jump/indirect3.lll | 14 + evmjit/evmcc/test/jump/indirect4.evm | 1 + evmjit/evmcc/test/jump/indirect4.lll | 15 + evmjit/evmcc/test/jump/jump1.evm | 1 + evmjit/evmcc/test/jump/jump1.lll | 11 + evmjit/evmcc/test/jump/jump2.evm | 1 + evmjit/evmcc/test/jump/jump2.lll | 10 + evmjit/evmcc/test/jump/jump3.evm | 1 + evmjit/evmcc/test/jump/jump3.lll | 10 + evmjit/evmcc/test/jump/jump4.evm | 1 + evmjit/evmcc/test/jump/jump4.lll | 17 + evmjit/evmcc/test/jump/jump5.evm | 1 + evmjit/evmcc/test/jump/jump5.lll | 16 + evmjit/evmcc/test/jump/jump6.evm | 1 + evmjit/evmcc/test/jump/jump6.lll | 32 + evmjit/evmcc/test/jump/jumpi_at_the_end.evm | 1 + evmjit/evmcc/test/jump/jumpi_at_the_end.lll | 1 + evmjit/evmcc/test/jump/loop1.evm | 1 + evmjit/evmcc/test/jump/loop1.lll | 27 + evmjit/evmcc/test/jump/loop2.evm | 1 + evmjit/evmcc/test/jump/loop2.lll | 28 + evmjit/evmcc/test/jump/rec1.ethel | 4 + evmjit/evmcc/test/jump/rec1.evm | 1 + evmjit/evmcc/test/jump/when1.asm | 10 + evmjit/evmcc/test/jump/when1.evm | 1 + evmjit/evmcc/test/jump/when1.lll | 2 + evmjit/evmcc/test/kv.evm | 1 + evmjit/evmcc/test/kv.lll | 10 + evmjit/evmcc/test/mem/byte.evm | 1 + evmjit/evmcc/test/mem/byte.lll | 105 ++ evmjit/evmcc/test/mem/mem2.evm | 1 + evmjit/evmcc/test/mem/mem2.lll | 15 + evmjit/evmcc/test/mem/memtest1.evm | 1 + evmjit/evmcc/test/mem/memtest1.lll | 18 + evmjit/evmcc/test/mem/mstore1.evm | 1 + evmjit/evmcc/test/mem/mstore1.lll | 6 + evmjit/evmcc/test/ret/return1.evm | 1 + evmjit/evmcc/test/ret/return1.lll | 6 + evmjit/evmcc/test/ret/return2.evm | 1 + evmjit/evmcc/test/ret/return2.lll | 6 + evmjit/evmcc/test/ret/return_test.evm | 1 + evmjit/evmcc/test/ret/return_test.lll | 15 + evmjit/evmcc/test/stack/oos.evm | 1 + evmjit/evmcc/test/stack/oos.lll | 11 + evmjit/evmcc/test/stack/push_test.evm | 1 + evmjit/evmcc/test/stack/push_test.lll | 35 + evmjit/evmcc/test/stack/stack_test.evm | 1 + evmjit/evmcc/test/stack/stack_test.lll | 8 + evmjit/evmcc/test/stack/stackjump.evm | 1 + evmjit/evmcc/test/stack/stackjump.lll | 3 + evmjit/evmcc/test/stack/swap.evm | 1 + evmjit/evmcc/test/stack/swap.lll | 31 + evmjit/evmcc/test/stack/swapswap.evm | 1 + evmjit/evmcc/test/stack/swapswap.lll | 32 + evmjit/evmcc/test/stack/test.evm | 1 + .../test/vmtests/vmArithPerformanceTest.json | 260 +++++ .../evmcc/test/vmtests/vmPerformanceTest.json | 214 ++++ evmjit/evmcc/test/vmtests/vm_jump.json | 41 + evmjit/libevmjit-cpp/CMakeLists.txt | 24 + evmjit/libevmjit-cpp/Env.cpp | 117 +++ evmjit/libevmjit-cpp/JitVM.cpp | 83 ++ evmjit/libevmjit-cpp/JitVM.h | 26 + evmjit/libevmjit-cpp/Utils.h | 38 + evmjit/libevmjit/Arith256.cpp | 406 ++++++++ evmjit/libevmjit/Arith256.h | 47 + evmjit/libevmjit/BasicBlock.cpp | 381 +++++++ evmjit/libevmjit/BasicBlock.h | 126 +++ evmjit/libevmjit/BuildInfo.h.in | 10 + evmjit/libevmjit/CMakeLists.txt | 68 ++ evmjit/libevmjit/Cache.cpp | 120 +++ evmjit/libevmjit/Cache.h | 38 + evmjit/libevmjit/Common.h | 65 ++ evmjit/libevmjit/Compiler.cpp | 965 ++++++++++++++++++ evmjit/libevmjit/Compiler.h | 80 ++ evmjit/libevmjit/CompilerHelper.cpp | 51 + evmjit/libevmjit/CompilerHelper.h | 79 ++ evmjit/libevmjit/Endianness.cpp | 39 + evmjit/libevmjit/Endianness.h | 25 + evmjit/libevmjit/ExecStats.cpp | 97 ++ evmjit/libevmjit/ExecStats.h | 43 + evmjit/libevmjit/ExecutionEngine.cpp | 153 +++ evmjit/libevmjit/ExecutionEngine.h | 60 ++ evmjit/libevmjit/Ext.cpp | 192 ++++ evmjit/libevmjit/Ext.h | 81 ++ evmjit/libevmjit/GasMeter.cpp | 231 +++++ evmjit/libevmjit/GasMeter.h | 63 ++ evmjit/libevmjit/Instruction.cpp | 42 + evmjit/libevmjit/Instruction.h | 239 +++++ evmjit/libevmjit/Memory.cpp | 260 +++++ evmjit/libevmjit/Memory.h | 49 + evmjit/libevmjit/Runtime.cpp | 34 + evmjit/libevmjit/Runtime.h | 40 + evmjit/libevmjit/RuntimeData.h | 60 ++ evmjit/libevmjit/RuntimeManager.cpp | 242 +++++ evmjit/libevmjit/RuntimeManager.h | 60 ++ evmjit/libevmjit/Stack.cpp | 200 ++++ evmjit/libevmjit/Stack.h | 44 + evmjit/libevmjit/Type.cpp | 70 ++ evmjit/libevmjit/Type.h | 60 ++ evmjit/libevmjit/Utils.cpp | 13 + evmjit/libevmjit/Utils.h | 24 + evmjit/libevmjit/interface.cpp | 40 + evmjit/libevmjit/interface.h | 13 + .../preprocessor/llvm_includes_end.h | 5 + .../preprocessor/llvm_includes_start.h | 8 + 177 files changed, 7040 insertions(+) create mode 100644 evmjit/.gitignore create mode 100644 evmjit/CMakeLists.txt create mode 100644 evmjit/LICENSE.md create mode 100644 evmjit/README.md create mode 100644 evmjit/evmcc/CMakeLists.txt create mode 100644 evmjit/evmcc/evmcc.cpp create mode 100644 evmjit/evmcc/test/arith/addmod.evm create mode 100644 evmjit/evmcc/test/arith/addmod.lll create mode 100644 evmjit/evmcc/test/arith/arith1.evm create mode 100644 evmjit/evmcc/test/arith/arith1.lll create mode 100644 evmjit/evmcc/test/arith/arith_bnot.evm create mode 100644 evmjit/evmcc/test/arith/arith_bnot.lll create mode 100644 evmjit/evmcc/test/arith/div.evm create mode 100644 evmjit/evmcc/test/arith/div.lll create mode 100644 evmjit/evmcc/test/arith/fib1.evm create mode 100644 evmjit/evmcc/test/arith/fib1.lll create mode 100644 evmjit/evmcc/test/arith/mul.evm create mode 100644 evmjit/evmcc/test/arith/mul.lll create mode 100644 evmjit/evmcc/test/arith/mulmod.evm create mode 100644 evmjit/evmcc/test/arith/mulmod.lll create mode 100644 evmjit/evmcc/test/except/badinst1.evm create mode 100644 evmjit/evmcc/test/ext/calldatacopy1.evm create mode 100644 evmjit/evmcc/test/ext/calldatacopy1.lll create mode 100644 evmjit/evmcc/test/ext/calldatacopy2.evm create mode 100644 evmjit/evmcc/test/ext/calldatacopy2.lll create mode 100644 evmjit/evmcc/test/ext/codecopy1.evm create mode 100644 evmjit/evmcc/test/ext/codecopy1.lll create mode 100644 evmjit/evmcc/test/ext/codecopy2.evm create mode 100644 evmjit/evmcc/test/ext/codecopy2.lll create mode 100644 evmjit/evmcc/test/ext/codecopy3.evm create mode 100644 evmjit/evmcc/test/ext/codecopy3.lll create mode 100644 evmjit/evmcc/test/ext/ext_test.evm create mode 100644 evmjit/evmcc/test/ext/ext_test.lll create mode 100644 evmjit/evmcc/test/ext/extcodecopy1.evm create mode 100644 evmjit/evmcc/test/ext/extcodecopy1.lll create mode 100644 evmjit/evmcc/test/ext/store_delete.evm create mode 100644 evmjit/evmcc/test/ext/store_delete.lll create mode 100644 evmjit/evmcc/test/ext/store_test.evm create mode 100644 evmjit/evmcc/test/ext/store_test.lll create mode 100644 evmjit/evmcc/test/jump/ackermann.ethel create mode 100644 evmjit/evmcc/test/jump/ackermann.evm create mode 100644 evmjit/evmcc/test/jump/badindirect1.evm create mode 100644 evmjit/evmcc/test/jump/badindirect1.lll create mode 100644 evmjit/evmcc/test/jump/badindirect2.evm create mode 100644 evmjit/evmcc/test/jump/badindirect2.lll create mode 100644 evmjit/evmcc/test/jump/badjump1.evm create mode 100644 evmjit/evmcc/test/jump/badjump1.lll create mode 100644 evmjit/evmcc/test/jump/badjump2.evm create mode 100644 evmjit/evmcc/test/jump/badjump2.lll create mode 100644 evmjit/evmcc/test/jump/call1.ethel create mode 100644 evmjit/evmcc/test/jump/call1.evm create mode 100644 evmjit/evmcc/test/jump/call2.ethel create mode 100644 evmjit/evmcc/test/jump/call2.evm create mode 100644 evmjit/evmcc/test/jump/fac.ethel create mode 100644 evmjit/evmcc/test/jump/fac.evm create mode 100644 evmjit/evmcc/test/jump/fac_tail.ethel create mode 100644 evmjit/evmcc/test/jump/fac_tail.evm create mode 100644 evmjit/evmcc/test/jump/fib1.ethel create mode 100644 evmjit/evmcc/test/jump/fib1.evm create mode 100644 evmjit/evmcc/test/jump/for1.evm create mode 100644 evmjit/evmcc/test/jump/for1.lll create mode 100644 evmjit/evmcc/test/jump/for2.evm create mode 100644 evmjit/evmcc/test/jump/for2.lll create mode 100644 evmjit/evmcc/test/jump/if1.ethel create mode 100644 evmjit/evmcc/test/jump/if1.evm create mode 100644 evmjit/evmcc/test/jump/if2.ethel create mode 100644 evmjit/evmcc/test/jump/if2.evm create mode 100644 evmjit/evmcc/test/jump/indirect1.evm create mode 100644 evmjit/evmcc/test/jump/indirect1.lll create mode 100644 evmjit/evmcc/test/jump/indirect2.evm create mode 100644 evmjit/evmcc/test/jump/indirect2.lll create mode 100644 evmjit/evmcc/test/jump/indirect3.evm create mode 100644 evmjit/evmcc/test/jump/indirect3.lll create mode 100644 evmjit/evmcc/test/jump/indirect4.evm create mode 100644 evmjit/evmcc/test/jump/indirect4.lll create mode 100644 evmjit/evmcc/test/jump/jump1.evm create mode 100644 evmjit/evmcc/test/jump/jump1.lll create mode 100644 evmjit/evmcc/test/jump/jump2.evm create mode 100644 evmjit/evmcc/test/jump/jump2.lll create mode 100644 evmjit/evmcc/test/jump/jump3.evm create mode 100644 evmjit/evmcc/test/jump/jump3.lll create mode 100644 evmjit/evmcc/test/jump/jump4.evm create mode 100644 evmjit/evmcc/test/jump/jump4.lll create mode 100644 evmjit/evmcc/test/jump/jump5.evm create mode 100644 evmjit/evmcc/test/jump/jump5.lll create mode 100644 evmjit/evmcc/test/jump/jump6.evm create mode 100644 evmjit/evmcc/test/jump/jump6.lll create mode 100644 evmjit/evmcc/test/jump/jumpi_at_the_end.evm create mode 100644 evmjit/evmcc/test/jump/jumpi_at_the_end.lll create mode 100644 evmjit/evmcc/test/jump/loop1.evm create mode 100644 evmjit/evmcc/test/jump/loop1.lll create mode 100644 evmjit/evmcc/test/jump/loop2.evm create mode 100644 evmjit/evmcc/test/jump/loop2.lll create mode 100644 evmjit/evmcc/test/jump/rec1.ethel create mode 100644 evmjit/evmcc/test/jump/rec1.evm create mode 100644 evmjit/evmcc/test/jump/when1.asm create mode 100644 evmjit/evmcc/test/jump/when1.evm create mode 100644 evmjit/evmcc/test/jump/when1.lll create mode 100644 evmjit/evmcc/test/kv.evm create mode 100644 evmjit/evmcc/test/kv.lll create mode 100644 evmjit/evmcc/test/mem/byte.evm create mode 100644 evmjit/evmcc/test/mem/byte.lll create mode 100644 evmjit/evmcc/test/mem/mem2.evm create mode 100644 evmjit/evmcc/test/mem/mem2.lll create mode 100644 evmjit/evmcc/test/mem/memtest1.evm create mode 100644 evmjit/evmcc/test/mem/memtest1.lll create mode 100644 evmjit/evmcc/test/mem/mstore1.evm create mode 100644 evmjit/evmcc/test/mem/mstore1.lll create mode 100644 evmjit/evmcc/test/ret/return1.evm create mode 100644 evmjit/evmcc/test/ret/return1.lll create mode 100644 evmjit/evmcc/test/ret/return2.evm create mode 100644 evmjit/evmcc/test/ret/return2.lll create mode 100644 evmjit/evmcc/test/ret/return_test.evm create mode 100644 evmjit/evmcc/test/ret/return_test.lll create mode 100644 evmjit/evmcc/test/stack/oos.evm create mode 100644 evmjit/evmcc/test/stack/oos.lll create mode 100644 evmjit/evmcc/test/stack/push_test.evm create mode 100644 evmjit/evmcc/test/stack/push_test.lll create mode 100644 evmjit/evmcc/test/stack/stack_test.evm create mode 100644 evmjit/evmcc/test/stack/stack_test.lll create mode 100644 evmjit/evmcc/test/stack/stackjump.evm create mode 100644 evmjit/evmcc/test/stack/stackjump.lll create mode 100644 evmjit/evmcc/test/stack/swap.evm create mode 100644 evmjit/evmcc/test/stack/swap.lll create mode 100644 evmjit/evmcc/test/stack/swapswap.evm create mode 100644 evmjit/evmcc/test/stack/swapswap.lll create mode 100644 evmjit/evmcc/test/stack/test.evm create mode 100644 evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json create mode 100644 evmjit/evmcc/test/vmtests/vmPerformanceTest.json create mode 100644 evmjit/evmcc/test/vmtests/vm_jump.json create mode 100644 evmjit/libevmjit-cpp/CMakeLists.txt create mode 100644 evmjit/libevmjit-cpp/Env.cpp create mode 100644 evmjit/libevmjit-cpp/JitVM.cpp create mode 100644 evmjit/libevmjit-cpp/JitVM.h create mode 100644 evmjit/libevmjit-cpp/Utils.h create mode 100644 evmjit/libevmjit/Arith256.cpp create mode 100644 evmjit/libevmjit/Arith256.h create mode 100644 evmjit/libevmjit/BasicBlock.cpp create mode 100644 evmjit/libevmjit/BasicBlock.h create mode 100644 evmjit/libevmjit/BuildInfo.h.in create mode 100644 evmjit/libevmjit/CMakeLists.txt create mode 100644 evmjit/libevmjit/Cache.cpp create mode 100644 evmjit/libevmjit/Cache.h create mode 100644 evmjit/libevmjit/Common.h create mode 100644 evmjit/libevmjit/Compiler.cpp create mode 100644 evmjit/libevmjit/Compiler.h create mode 100644 evmjit/libevmjit/CompilerHelper.cpp create mode 100644 evmjit/libevmjit/CompilerHelper.h create mode 100644 evmjit/libevmjit/Endianness.cpp create mode 100644 evmjit/libevmjit/Endianness.h create mode 100644 evmjit/libevmjit/ExecStats.cpp create mode 100644 evmjit/libevmjit/ExecStats.h create mode 100644 evmjit/libevmjit/ExecutionEngine.cpp create mode 100644 evmjit/libevmjit/ExecutionEngine.h create mode 100644 evmjit/libevmjit/Ext.cpp create mode 100644 evmjit/libevmjit/Ext.h create mode 100644 evmjit/libevmjit/GasMeter.cpp create mode 100644 evmjit/libevmjit/GasMeter.h create mode 100644 evmjit/libevmjit/Instruction.cpp create mode 100644 evmjit/libevmjit/Instruction.h create mode 100644 evmjit/libevmjit/Memory.cpp create mode 100644 evmjit/libevmjit/Memory.h create mode 100644 evmjit/libevmjit/Runtime.cpp create mode 100644 evmjit/libevmjit/Runtime.h create mode 100644 evmjit/libevmjit/RuntimeData.h create mode 100644 evmjit/libevmjit/RuntimeManager.cpp create mode 100644 evmjit/libevmjit/RuntimeManager.h create mode 100644 evmjit/libevmjit/Stack.cpp create mode 100644 evmjit/libevmjit/Stack.h create mode 100644 evmjit/libevmjit/Type.cpp create mode 100644 evmjit/libevmjit/Type.h create mode 100644 evmjit/libevmjit/Utils.cpp create mode 100644 evmjit/libevmjit/Utils.h create mode 100644 evmjit/libevmjit/interface.cpp create mode 100644 evmjit/libevmjit/interface.h create mode 100644 evmjit/libevmjit/preprocessor/llvm_includes_end.h create mode 100644 evmjit/libevmjit/preprocessor/llvm_includes_start.h diff --git a/evmjit/.gitignore b/evmjit/.gitignore new file mode 100644 index 000000000..84c048a73 --- /dev/null +++ b/evmjit/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt new file mode 100644 index 000000000..14fca2cde --- /dev/null +++ b/evmjit/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(evmjit) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(CMAKE_AUTOMOC OFF) + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-unknown-pragmas") +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + # Do not allow unresovled symbols in shared library (default on linux) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") +endif() + +# LLVM +if(LLVM_DIR OR APPLE) # local LLVM build + find_package(LLVM REQUIRED CONFIG) + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + add_definitions(${LLVM_DEFINITIONS}) + # TODO: bitwriter is needed only for evmcc + llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter) +else() + # Workaround for Ubuntu broken LLVM package + message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") + execute_process(COMMAND llvm-config-3.5 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS) + message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") + set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") + add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS) + link_directories(/usr/lib/llvm-3.5/lib) +endif() + +add_subdirectory(libevmjit) + +if(EVMJIT_CPP) + add_subdirectory(libevmjit-cpp) +endif() + +if(EVMJIT_TOOLS) + add_subdirectory(evmcc) +endif() diff --git a/evmjit/LICENSE.md b/evmjit/LICENSE.md new file mode 100644 index 000000000..630157f98 --- /dev/null +++ b/evmjit/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paweł Bylica + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/evmjit/README.md b/evmjit/README.md new file mode 100644 index 000000000..a480e83dc --- /dev/null +++ b/evmjit/README.md @@ -0,0 +1,43 @@ +# The Ethereum EVM JIT + +EVM JIT is a library for just-in-time compilation of Ethereum EVM code. +It can be used to substitute classic interpreter-like EVM Virtual Machine in Ethereum client. + +## Build + +### Linux / Ubuntu + +1. Install llvm-3.5-dev package + 1. For Ubuntu 14.04 using LLVM deb packages source: http://llvm.org/apt + 2. For Ubuntu 14.10 using Ubuntu packages +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake .. && make` +3. Install library + 1. `sudo make install` + 2. `sudo ldconfig` + +### OSX + +1. Install llvm35 + 1. `brew install llvm35 --disable-shared --HEAD` +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake -DLLVM_DIR=/usr/local/lib/llvm-3.5/share/llvm/cmake .. && make` +3. Install library + 1. `make install` (with admin rights?) + +### Windows + +Ask me. + +## Options + +Options to evmjit library can be passed by environmental variables, e.g. `EVMJIT_CACHE=0 testeth --jit`. + +Option | Default value | Description +------------- | ------------- | ---------------------------------------------- +EVMJIT_CACHE | 1 | Enables on disk cache for compiled EVM objects +EVMJIT_DUMP | 0 | Dumps generated LLVM module to standard output + + diff --git a/evmjit/evmcc/CMakeLists.txt b/evmjit/evmcc/CMakeLists.txt new file mode 100644 index 000000000..4ffbf5fb5 --- /dev/null +++ b/evmjit/evmcc/CMakeLists.txt @@ -0,0 +1,18 @@ +set(TARGET_NAME evmcc) + +set(SOURCES + evmcc.cpp +) +source_group("" FILES ${SOURCES}) + +add_executable(${TARGET_NAME} ${SOURCES}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "tools") + +include_directories(../..) +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(${TARGET_NAME} ethereum) +target_link_libraries(${TARGET_NAME} ${Boost_PROGRAM_OPTIONS_LIBRARIES}) + +install(TARGETS ${TARGET_NAME} DESTINATION bin ) \ No newline at end of file diff --git a/evmjit/evmcc/evmcc.cpp b/evmjit/evmcc/evmcc.cpp new file mode 100644 index 000000000..e86f948f2 --- /dev/null +++ b/evmjit/evmcc/evmcc.cpp @@ -0,0 +1,210 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +void parseProgramOptions(int _argc, char** _argv, boost::program_options::variables_map& _varMap) +{ + namespace opt = boost::program_options; + + opt::options_description explicitOpts("Allowed options"); + explicitOpts.add_options() + ("help,h", "show usage information") + ("compile,c", "compile the code to LLVM IR") + ("interpret,i", "compile the code to LLVM IR and execute") + ("gas,g", opt::value(), "set initial gas for execution") + ("disassemble,d", "dissassemble the code") + ("dump-cfg", "dump control flow graph to graphviz file") + ("dont-optimize", "turn off optimizations") + ("optimize-stack", "optimize stack use between basic blocks (default: on)") + ("rewrite-switch", "rewrite LLVM switch to branches (default: on)") + ("output-ll", opt::value(), "dump generated LLVM IR to file") + ("output-bc", opt::value(), "dump generated LLVM bitcode to file") + ("show-logs", "output LOG statements to stderr") + ("verbose,V", "enable verbose output"); + + opt::options_description implicitOpts("Input files"); + implicitOpts.add_options() + ("input-file", opt::value(), "input file"); + + opt::options_description allOpts(""); + allOpts.add(explicitOpts).add(implicitOpts); + + opt::positional_options_description inputOpts; + inputOpts.add("input-file", 1); + + const char* errorMsg = nullptr; + try + { + auto parser = opt::command_line_parser(_argc, _argv).options(allOpts).positional(inputOpts); + opt::store(parser.run(), _varMap); + opt::notify(_varMap); + } + catch (boost::program_options::error& err) + { + errorMsg = err.what(); + } + + if (!errorMsg && _varMap.count("input-file") == 0) + errorMsg = "missing input file name"; + + if (_varMap.count("disassemble") == 0 + && _varMap.count("compile") == 0 + && _varMap.count("interpret") == 0) + { + errorMsg = "at least one of -c, -i, -d is required"; + } + + if (errorMsg || _varMap.count("help")) + { + if (errorMsg) + std::cerr << "Error: " << errorMsg << std::endl; + + std::cout << "Usage: " << _argv[0] << " input-file " << std::endl + << explicitOpts << std::endl; + std::exit(errorMsg ? 1 : 0); + } +} + +int main(int argc, char** argv) +{ + llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram X(argc, argv); + + boost::program_options::variables_map options; + parseProgramOptions(argc, argv, options); + + auto inputFile = options["input-file"].as(); + std::ifstream ifs(inputFile); + if (!ifs.is_open()) + { + std::cerr << "cannot open input file " << inputFile << std::endl; + exit(1); + } + + std::string src((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + + boost::algorithm::trim(src); + + using namespace dev; + + bytes bytecode = fromHex(src); + + if (options.count("disassemble")) + { + std::string assembly = eth::disassemble(bytecode); + std::cout << assembly << std::endl; + } + + if (options.count("compile") || options.count("interpret")) + { + size_t initialGas = 10000; + + if (options.count("gas")) + initialGas = options["gas"].as(); + + auto compilationStartTime = std::chrono::high_resolution_clock::now(); + + eth::jit::Compiler::Options compilerOptions; + compilerOptions.dumpCFG = options.count("dump-cfg") > 0; + bool optimize = options.count("dont-optimize") == 0; + compilerOptions.optimizeStack = optimize || options.count("optimize-stack") > 0; + compilerOptions.rewriteSwitchToBranches = optimize || options.count("rewrite-switch") > 0; + + auto compiler = eth::jit::Compiler(compilerOptions); + auto module = compiler.compile(bytecode, "main"); + + auto compilationEndTime = std::chrono::high_resolution_clock::now(); + + module->dump(); + + if (options.count("output-ll")) + { + auto outputFile = options["output-ll"].as(); + std::ofstream ofs(outputFile); + if (!ofs.is_open()) + { + std::cerr << "cannot open output file " << outputFile << std::endl; + exit(1); + } + llvm::raw_os_ostream ros(ofs); + module->print(ros, nullptr); + ofs.close(); + } + + if (options.count("output-bc")) + { + auto outputFile = options["output-bc"].as(); + std::ofstream ofs(outputFile); + if (!ofs.is_open()) + { + std::cerr << "cannot open output file " << outputFile << std::endl; + exit(1); + } + llvm::raw_os_ostream ros(ofs); + llvm::WriteBitcodeToFile(module.get(), ros); + ros.flush(); + ofs.close(); + } + + if (options.count("verbose")) + { + std::cerr << "*** Compilation time: " + << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count() + << std::endl; + } + + if (options.count("interpret")) + { + using namespace eth::jit; + + ExecutionEngine engine; + eth::jit::u256 gas = initialGas; + + // Create random runtime data + RuntimeData data; + data.set(RuntimeData::Gas, gas); + data.set(RuntimeData::Address, (u160)Address(1122334455667788)); + data.set(RuntimeData::Caller, (u160)Address(0xfacefacefaceface)); + data.set(RuntimeData::Origin, (u160)Address(101010101010101010)); + data.set(RuntimeData::CallValue, 0xabcd); + data.set(RuntimeData::CallDataSize, 3); + data.set(RuntimeData::GasPrice, 1003); + data.set(RuntimeData::CoinBase, (u160)Address(101010101010101015)); + data.set(RuntimeData::TimeStamp, 1005); + data.set(RuntimeData::Number, 1006); + data.set(RuntimeData::Difficulty, 16); + data.set(RuntimeData::GasLimit, 1008); + data.set(RuntimeData::CodeSize, bytecode.size()); + data.callData = (uint8_t*)"abc"; + data.code = bytecode.data(); + + // BROKEN: env_* functions must be implemented & RuntimeData struct created + // TODO: Do not compile module again + auto result = engine.run(bytecode, &data, nullptr); + return static_cast(result); + } + } + + return 0; +} diff --git a/evmjit/evmcc/test/arith/addmod.evm b/evmjit/evmcc/test/arith/addmod.evm new file mode 100644 index 000000000..4ca71e065 --- /dev/null +++ b/evmjit/evmcc/test/arith/addmod.evm @@ -0,0 +1 @@ +60646107b760271460005560006001f2 diff --git a/evmjit/evmcc/test/arith/addmod.lll b/evmjit/evmcc/test/arith/addmod.lll new file mode 100644 index 000000000..11a6b2cb9 --- /dev/null +++ b/evmjit/evmcc/test/arith/addmod.lll @@ -0,0 +1,12 @@ +;; Should return (1975 + 39) `mod` 100 = 14 = 0x0e +(asm +100 +1975 +39 +ADDMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/arith/arith1.evm b/evmjit/evmcc/test/arith/arith1.evm new file mode 100644 index 000000000..c7a029f52 --- /dev/null +++ b/evmjit/evmcc/test/arith/arith1.evm @@ -0,0 +1 @@ +60016001900160070260050160029004600490066021900560150160030260059007600303600960110860005460086000f2 diff --git a/evmjit/evmcc/test/arith/arith1.lll b/evmjit/evmcc/test/arith/arith1.lll new file mode 100644 index 000000000..4757a7420 --- /dev/null +++ b/evmjit/evmcc/test/arith/arith1.lll @@ -0,0 +1,37 @@ + +(asm +1 +1 +SWAP1 +ADD ;; 2 +7 +MUL ;; 14 +5 +ADD ;; 19 +2 +SWAP1 +DIV ;; 9 +4 +SWAP1 +MOD ;; 1 +33 +SWAP1 +SDIV;; 0 +21 +ADD ;; 21 +3 +MUL ;; 63 +5 +SWAP1 +SMOD;; 3 +3 +SUB ;; 0 +9 +17 +EXP ;; 17^9 +0 +MSTORE +8 +0 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/arith/arith_bnot.evm b/evmjit/evmcc/test/arith/arith_bnot.evm new file mode 100644 index 000000000..4cfaf8f55 --- /dev/null +++ b/evmjit/evmcc/test/arith/arith_bnot.evm @@ -0,0 +1 @@ +6201e2406000546000530960005460206000f2 diff --git a/evmjit/evmcc/test/arith/arith_bnot.lll b/evmjit/evmcc/test/arith/arith_bnot.lll new file mode 100644 index 000000000..a83b05a9a --- /dev/null +++ b/evmjit/evmcc/test/arith/arith_bnot.lll @@ -0,0 +1,14 @@ + +(asm +123456 +0 +MSTORE +0 +MLOAD +BNOT +0 +MSTORE +32 +0 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/arith/div.evm b/evmjit/evmcc/test/arith/div.evm new file mode 100644 index 000000000..b68d5d202 --- /dev/null +++ b/evmjit/evmcc/test/arith/div.evm @@ -0,0 +1 @@ +60027ffedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432100460005460206000f2 diff --git a/evmjit/evmcc/test/arith/div.lll b/evmjit/evmcc/test/arith/div.lll new file mode 100644 index 000000000..72c22bfdc --- /dev/null +++ b/evmjit/evmcc/test/arith/div.lll @@ -0,0 +1,10 @@ +(asm +0x2 +0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 +DIV +0 +MSTORE +32 +0 +RETURN +) diff --git a/evmjit/evmcc/test/arith/fib1.evm b/evmjit/evmcc/test/arith/fib1.evm new file mode 100644 index 000000000..4c141314e --- /dev/null +++ b/evmjit/evmcc/test/arith/fib1.evm @@ -0,0 +1 @@ +60016001818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101 diff --git a/evmjit/evmcc/test/arith/fib1.lll b/evmjit/evmcc/test/arith/fib1.lll new file mode 100644 index 000000000..286bed275 --- /dev/null +++ b/evmjit/evmcc/test/arith/fib1.lll @@ -0,0 +1,57 @@ +;; Fibbonacci unrolled + +(asm +1 +1 +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +) \ No newline at end of file diff --git a/evmjit/evmcc/test/arith/mul.evm b/evmjit/evmcc/test/arith/mul.evm new file mode 100644 index 000000000..7e8afd268 --- /dev/null +++ b/evmjit/evmcc/test/arith/mul.evm @@ -0,0 +1 @@ +7001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba0987654321020260005460206000f2 diff --git a/evmjit/evmcc/test/arith/mul.lll b/evmjit/evmcc/test/arith/mul.lll new file mode 100644 index 000000000..b0fa343bb --- /dev/null +++ b/evmjit/evmcc/test/arith/mul.lll @@ -0,0 +1,13 @@ +(asm +0x1234567890abcdef0fedcba0987654321 +0x1234567890abcdef0fedcba0987654321 +0x1234567890abcdef0fedcba0987654321 +MUL +MUL +0 +MSTORE +32 +0 +RETURN +;; 47d0817e4167b1eb4f9fc722b133ef9d7d9a6fb4c2c1c442d000107a5e419561 +) diff --git a/evmjit/evmcc/test/arith/mulmod.evm b/evmjit/evmcc/test/arith/mulmod.evm new file mode 100644 index 000000000..e34a06154 --- /dev/null +++ b/evmjit/evmcc/test/arith/mulmod.evm @@ -0,0 +1 @@ +6064601b60251560005560006001f2 diff --git a/evmjit/evmcc/test/arith/mulmod.lll b/evmjit/evmcc/test/arith/mulmod.lll new file mode 100644 index 000000000..5e87f0843 --- /dev/null +++ b/evmjit/evmcc/test/arith/mulmod.lll @@ -0,0 +1,12 @@ +;; Should return (27 * 37) `mod` 100 = 99 = 0x63 +(asm +100 +27 +37 +MULMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/except/badinst1.evm b/evmjit/evmcc/test/except/badinst1.evm new file mode 100644 index 000000000..69aadac5e --- /dev/null +++ b/evmjit/evmcc/test/except/badinst1.evm @@ -0,0 +1 @@ +4a diff --git a/evmjit/evmcc/test/ext/calldatacopy1.evm b/evmjit/evmcc/test/ext/calldatacopy1.evm new file mode 100644 index 000000000..f20019651 --- /dev/null +++ b/evmjit/evmcc/test/ext/calldatacopy1.evm @@ -0,0 +1 @@ +60326000600a37600053600a6014f2 diff --git a/evmjit/evmcc/test/ext/calldatacopy1.lll b/evmjit/evmcc/test/ext/calldatacopy1.lll new file mode 100644 index 000000000..3d2ae0a78 --- /dev/null +++ b/evmjit/evmcc/test/ext/calldatacopy1.lll @@ -0,0 +1,13 @@ +(asm +50 ;; byte count +0 ;; source index in calldata array +10 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/calldatacopy2.evm b/evmjit/evmcc/test/ext/calldatacopy2.evm new file mode 100644 index 000000000..e8eea8da7 --- /dev/null +++ b/evmjit/evmcc/test/ext/calldatacopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000376000536000600af2 diff --git a/evmjit/evmcc/test/ext/calldatacopy2.lll b/evmjit/evmcc/test/ext/calldatacopy2.lll new file mode 100644 index 000000000..6bbea48d8 --- /dev/null +++ b/evmjit/evmcc/test/ext/calldatacopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in calldata array +0 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/codecopy1.evm b/evmjit/evmcc/test/ext/codecopy1.evm new file mode 100644 index 000000000..d286f9232 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy1.evm @@ -0,0 +1 @@ +60146000600a39600053600a6014f2 diff --git a/evmjit/evmcc/test/ext/codecopy1.lll b/evmjit/evmcc/test/ext/codecopy1.lll new file mode 100644 index 000000000..85a02b5d7 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy1.lll @@ -0,0 +1,13 @@ +(asm +20 ;; byte count +0 ;; source index in code array +10 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/codecopy2.evm b/evmjit/evmcc/test/ext/codecopy2.evm new file mode 100644 index 000000000..71cd92525 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000396000536000600af2 diff --git a/evmjit/evmcc/test/ext/codecopy2.lll b/evmjit/evmcc/test/ext/codecopy2.lll new file mode 100644 index 000000000..dcbbcaa46 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in code array +0 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/codecopy3.evm b/evmjit/evmcc/test/ext/codecopy3.evm new file mode 100644 index 000000000..e4b6a9253 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy3.evm @@ -0,0 +1 @@ +3860006000396000536000600af2 diff --git a/evmjit/evmcc/test/ext/codecopy3.lll b/evmjit/evmcc/test/ext/codecopy3.lll new file mode 100644 index 000000000..80d9982c6 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy3.lll @@ -0,0 +1,13 @@ +(asm +CODESIZE ;; byte count +0 ;; source index in code array +0 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/ext_test.evm b/evmjit/evmcc/test/ext/ext_test.evm new file mode 100644 index 000000000..580bd9675 --- /dev/null +++ b/evmjit/evmcc/test/ext/ext_test.evm @@ -0,0 +1 @@ +5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f1600053611000545b60200260002030ff60016002f2 diff --git a/evmjit/evmcc/test/ext/ext_test.lll b/evmjit/evmcc/test/ext/ext_test.lll new file mode 100644 index 000000000..3287ae95f --- /dev/null +++ b/evmjit/evmcc/test/ext/ext_test.lll @@ -0,0 +1,55 @@ + +(asm +PC +ADDRESS +BALANCE +CALLER +ORIGIN +CALLVALUE +CALLDATASIZE +GASPRICE +PREVHASH +COINBASE +TIMESTAMP +NUMBER +DIFFICULTY +GASLIMIT +PC +CALLDATASIZE +0 +CALLDATALOAD +38 +CALLDATALOAD +19 +CALLDATALOAD +CODESIZE +0x1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff +0 +MSTORE +32 +0 +0 +CREATE +32 +0 +32 +0 +0 +ADDRESS +3000 +CALL +0 +MLOAD +4096 +MSTORE +MSIZE +32 +MUL +0 +SHA3 +ADDRESS +SUICIDE +1 +2 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/extcodecopy1.evm b/evmjit/evmcc/test/ext/extcodecopy1.evm new file mode 100644 index 000000000..6132b52d8 --- /dev/null +++ b/evmjit/evmcc/test/ext/extcodecopy1.evm @@ -0,0 +1 @@ +60c86000600a303c60005360006020f2 diff --git a/evmjit/evmcc/test/ext/extcodecopy1.lll b/evmjit/evmcc/test/ext/extcodecopy1.lll new file mode 100644 index 000000000..c37054574 --- /dev/null +++ b/evmjit/evmcc/test/ext/extcodecopy1.lll @@ -0,0 +1,11 @@ +(asm +200 ;; byte count +0 ;; source index in code array +10 ;; dest index in memory +ADDRESS +EXTCODECOPY + +0 MLOAD ;; to dump memory + +0 32 RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/store_delete.evm b/evmjit/evmcc/test/ext/store_delete.evm new file mode 100644 index 000000000..d6acae03d --- /dev/null +++ b/evmjit/evmcc/test/ext/store_delete.evm @@ -0,0 +1 @@ +6104d26063576000606357 diff --git a/evmjit/evmcc/test/ext/store_delete.lll b/evmjit/evmcc/test/ext/store_delete.lll new file mode 100644 index 000000000..3d8f0f23a --- /dev/null +++ b/evmjit/evmcc/test/ext/store_delete.lll @@ -0,0 +1,9 @@ + +(asm +1234 +99 +SSTORE +0 +99 +SSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/store_test.evm b/evmjit/evmcc/test/ext/store_test.evm new file mode 100644 index 000000000..54c9419b5 --- /dev/null +++ b/evmjit/evmcc/test/ext/store_test.evm @@ -0,0 +1 @@ +607b607c60015760005760015660005603 diff --git a/evmjit/evmcc/test/ext/store_test.lll b/evmjit/evmcc/test/ext/store_test.lll new file mode 100644 index 000000000..c40471c40 --- /dev/null +++ b/evmjit/evmcc/test/ext/store_test.lll @@ -0,0 +1,14 @@ + +(asm +123 +124 +1 +SSTORE +0 +SSTORE +1 +SLOAD +0 +SLOAD +SUB +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/ackermann.ethel b/evmjit/evmcc/test/jump/ackermann.ethel new file mode 100644 index 000000000..971fd2b8d --- /dev/null +++ b/evmjit/evmcc/test/jump/ackermann.ethel @@ -0,0 +1,7 @@ +let A m n = + if m == 0 then n+1 + else if n == 0 then A (m-1) 1 + else A (m-1) (A (m) (n-1)) + +return A 3 8 + diff --git a/evmjit/evmcc/test/jump/ackermann.evm b/evmjit/evmcc/test/jump/ackermann.evm new file mode 100644 index 000000000..964844045 --- /dev/null +++ b/evmjit/evmcc/test/jump/ackermann.evm @@ -0,0 +1 @@ +6009600360086012585d60005460206000f26000820e6047596000810e603859603460018303603084600185036012585d6012585d60445860436001830360016012585d604b5860018101905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badindirect1.evm b/evmjit/evmcc/test/jump/badindirect1.evm new file mode 100644 index 000000000..b2a8aad67 --- /dev/null +++ b/evmjit/evmcc/test/jump/badindirect1.evm @@ -0,0 +1 @@ +601b602502585d diff --git a/evmjit/evmcc/test/jump/badindirect1.lll b/evmjit/evmcc/test/jump/badindirect1.lll new file mode 100644 index 000000000..d6291be68 --- /dev/null +++ b/evmjit/evmcc/test/jump/badindirect1.lll @@ -0,0 +1,9 @@ +;; Indirect jump out of code + +(asm +27 +37 +MUL +JUMP +JUMPDEST +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badindirect2.evm b/evmjit/evmcc/test/jump/badindirect2.evm new file mode 100644 index 000000000..22217523d --- /dev/null +++ b/evmjit/evmcc/test/jump/badindirect2.evm @@ -0,0 +1 @@ +60016003600302596000600058 diff --git a/evmjit/evmcc/test/jump/badindirect2.lll b/evmjit/evmcc/test/jump/badindirect2.lll new file mode 100644 index 000000000..53a6294f7 --- /dev/null +++ b/evmjit/evmcc/test/jump/badindirect2.lll @@ -0,0 +1,12 @@ +;; Indirect jump into data + +(asm +1 ;; 0 +3 +3 +MUL ;; 6 +JUMPI ;; 7 +0 ;; 8 +0 +JUMP +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badjump1.evm b/evmjit/evmcc/test/jump/badjump1.evm new file mode 100644 index 000000000..5c11a8661 --- /dev/null +++ b/evmjit/evmcc/test/jump/badjump1.evm @@ -0,0 +1 @@ +6103e758 diff --git a/evmjit/evmcc/test/jump/badjump1.lll b/evmjit/evmcc/test/jump/badjump1.lll new file mode 100644 index 000000000..1834a62ef --- /dev/null +++ b/evmjit/evmcc/test/jump/badjump1.lll @@ -0,0 +1,6 @@ +;; Direct jump out of code. + +(asm +999 +JUMP +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badjump2.evm b/evmjit/evmcc/test/jump/badjump2.evm new file mode 100644 index 000000000..900a1c15a --- /dev/null +++ b/evmjit/evmcc/test/jump/badjump2.evm @@ -0,0 +1 @@ +6004586000600058 diff --git a/evmjit/evmcc/test/jump/badjump2.lll b/evmjit/evmcc/test/jump/badjump2.lll new file mode 100644 index 000000000..ce61276d7 --- /dev/null +++ b/evmjit/evmcc/test/jump/badjump2.lll @@ -0,0 +1,9 @@ +;; Direct jump into data + +(asm +4 ;; 0 0-3 +JUMP ;; 2 +0 ;; 3 3-4 +0 ;; 5 4-7 +JUMP ;; 6 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/call1.ethel b/evmjit/evmcc/test/jump/call1.ethel new file mode 100644 index 000000000..414ad0124 --- /dev/null +++ b/evmjit/evmcc/test/jump/call1.ethel @@ -0,0 +1,5 @@ +let f n = n + 1 + +return f 2 + + diff --git a/evmjit/evmcc/test/jump/call1.evm b/evmjit/evmcc/test/jump/call1.evm new file mode 100644 index 000000000..252aaf778 --- /dev/null +++ b/evmjit/evmcc/test/jump/call1.evm @@ -0,0 +1 @@ +600760026010585d60005460206000f28060010190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/call2.ethel b/evmjit/evmcc/test/jump/call2.ethel new file mode 100644 index 000000000..bdeb9b734 --- /dev/null +++ b/evmjit/evmcc/test/jump/call2.ethel @@ -0,0 +1,5 @@ +let f a b = a + b + +return f 2 3 + + diff --git a/evmjit/evmcc/test/jump/call2.evm b/evmjit/evmcc/test/jump/call2.evm new file mode 100644 index 000000000..6832e044d --- /dev/null +++ b/evmjit/evmcc/test/jump/call2.evm @@ -0,0 +1 @@ +6009600260036012585d60005460206000f2818101905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac.ethel b/evmjit/evmcc/test/jump/fac.ethel new file mode 100644 index 000000000..8bfe94dd6 --- /dev/null +++ b/evmjit/evmcc/test/jump/fac.ethel @@ -0,0 +1,5 @@ +let fac n = + if n == 0 then 1 + else n * fac (n-1) + +return fac 60 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac.evm b/evmjit/evmcc/test/jump/fac.evm new file mode 100644 index 000000000..04cd3e4f4 --- /dev/null +++ b/evmjit/evmcc/test/jump/fac.evm @@ -0,0 +1 @@ +6007603c6010585d60005460206000f26000810e6026596020600182036010585d8102602858600190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac_tail.ethel b/evmjit/evmcc/test/jump/fac_tail.ethel new file mode 100644 index 000000000..9ce5ecac7 --- /dev/null +++ b/evmjit/evmcc/test/jump/fac_tail.ethel @@ -0,0 +1,5 @@ +let fac a n = + if n == 0 then a + else fac (a*n) (n-1) + +return fac 1 60 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac_tail.evm b/evmjit/evmcc/test/jump/fac_tail.evm new file mode 100644 index 000000000..8384d94e4 --- /dev/null +++ b/evmjit/evmcc/test/jump/fac_tail.evm @@ -0,0 +1 @@ +60096001603c6012585d60005460206000f26000810e6029596025818302600183036012585d602a5881905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fib1.ethel b/evmjit/evmcc/test/jump/fib1.ethel new file mode 100644 index 000000000..81b869f41 --- /dev/null +++ b/evmjit/evmcc/test/jump/fib1.ethel @@ -0,0 +1,6 @@ +let fib n = + if n < 3 then 1 + else fib (n-1) + fib (n-2) + +return fib 10 + diff --git a/evmjit/evmcc/test/jump/fib1.evm b/evmjit/evmcc/test/jump/fib1.evm new file mode 100644 index 000000000..5042a192f --- /dev/null +++ b/evmjit/evmcc/test/jump/fib1.evm @@ -0,0 +1 @@ +6007600a6010585d60005460206000f26003810a602f596020600282036010585d602a600183036010585d01603158600190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/for1.evm b/evmjit/evmcc/test/jump/for1.evm new file mode 100644 index 000000000..f8e65cbf2 --- /dev/null +++ b/evmjit/evmcc/test/jump/for1.evm @@ -0,0 +1 @@ +600a60805460006080530b0f60255960a0536080530160a054600160805303608054600558 diff --git a/evmjit/evmcc/test/jump/for1.lll b/evmjit/evmcc/test/jump/for1.lll new file mode 100644 index 000000000..419fc9b54 --- /dev/null +++ b/evmjit/evmcc/test/jump/for1.lll @@ -0,0 +1,3 @@ +(for [i]:10 (> @i 0) [i](- @i 1) + [j](+ @i @j) +) diff --git a/evmjit/evmcc/test/jump/for2.evm b/evmjit/evmcc/test/jump/for2.evm new file mode 100644 index 000000000..628297778 --- /dev/null +++ b/evmjit/evmcc/test/jump/for2.evm @@ -0,0 +1 @@ +6000608054600a6080530a0f60255960a0536080530160a054600160805301608054600558 diff --git a/evmjit/evmcc/test/jump/for2.lll b/evmjit/evmcc/test/jump/for2.lll new file mode 100644 index 000000000..de17d65ac --- /dev/null +++ b/evmjit/evmcc/test/jump/for2.lll @@ -0,0 +1,3 @@ +(for [i]:0 (< @i 10) [i](+ @i 1) + [j](+ @i @j) +) diff --git a/evmjit/evmcc/test/jump/if1.ethel b/evmjit/evmcc/test/jump/if1.ethel new file mode 100644 index 000000000..85c3e126b --- /dev/null +++ b/evmjit/evmcc/test/jump/if1.ethel @@ -0,0 +1 @@ +return if 0 then 1 else 2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/if1.evm b/evmjit/evmcc/test/jump/if1.evm new file mode 100644 index 000000000..51fbe04bd --- /dev/null +++ b/evmjit/evmcc/test/jump/if1.evm @@ -0,0 +1 @@ +60006300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/if2.ethel b/evmjit/evmcc/test/jump/if2.ethel new file mode 100644 index 000000000..2a58d6365 --- /dev/null +++ b/evmjit/evmcc/test/jump/if2.ethel @@ -0,0 +1 @@ +return if 1 then 1 else 2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/if2.evm b/evmjit/evmcc/test/jump/if2.evm new file mode 100644 index 000000000..6d823b374 --- /dev/null +++ b/evmjit/evmcc/test/jump/if2.evm @@ -0,0 +1 @@ +60016300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect1.evm b/evmjit/evmcc/test/jump/indirect1.evm new file mode 100644 index 000000000..ab6928304 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect1.evm @@ -0,0 +1 @@ +600460030158005d6001600054 diff --git a/evmjit/evmcc/test/jump/indirect1.lll b/evmjit/evmcc/test/jump/indirect1.lll new file mode 100644 index 000000000..1ee7dc347 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect1.lll @@ -0,0 +1,13 @@ +;; Indirect JUMP + +(asm +4 ;; 0 +3 ;; 2 +ADD ;; 4 +JUMP ;; 5 +STOP ;; 6 +JUMPDEST ;; 7 +1 +0 +MSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect2.evm b/evmjit/evmcc/test/jump/indirect2.evm new file mode 100644 index 000000000..e9697eaa1 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect2.evm @@ -0,0 +1 @@ +600860060158005d6001600054005d600260005400 diff --git a/evmjit/evmcc/test/jump/indirect2.lll b/evmjit/evmcc/test/jump/indirect2.lll new file mode 100644 index 000000000..f2f068630 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect2.lll @@ -0,0 +1,19 @@ +;; Indirect JUMP + +(asm +8 ;; 0 +6 ;; 2 +ADD ;; 4 +JUMP ;; 5 --> 14 +STOP ;; 6 +JUMPDEST ;; 7 +1 ;; 8 +0 ;; 10 +MSTORE ;; 12 +STOP ;; 13 +JUMPDEST ;; 14 +2 +0 +MSTORE +STOP +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect3.evm b/evmjit/evmcc/test/jump/indirect3.evm new file mode 100644 index 000000000..1fb0a356c --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect3.evm @@ -0,0 +1 @@ +6001600460050159005d6001600054 diff --git a/evmjit/evmcc/test/jump/indirect3.lll b/evmjit/evmcc/test/jump/indirect3.lll new file mode 100644 index 000000000..d6a679f9a --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect3.lll @@ -0,0 +1,14 @@ +;; Indirect JUMP + +(asm +1 ;; 0 +4 ;; 2 +5 ;; 4 +ADD ;; 6 +JUMPI ;; 7 +STOP ;; 8 +JUMPDEST ;; 9 +1 +0 +MSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect4.evm b/evmjit/evmcc/test/jump/indirect4.evm new file mode 100644 index 000000000..f0e31a8f4 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect4.evm @@ -0,0 +1 @@ +60006007600501596001600054005d00 diff --git a/evmjit/evmcc/test/jump/indirect4.lll b/evmjit/evmcc/test/jump/indirect4.lll new file mode 100644 index 000000000..7fbe0b833 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect4.lll @@ -0,0 +1,15 @@ +;; Indirect JUMP + +(asm +0 ;; 0 +7 ;; 2 +5 ;; 4 +ADD ;; 6 +JUMPI ;; 7 +1 ;; 8 +0 ;; 9 +MSTORE ;; 10 +STOP ;; 11 +JUMPDEST ;; 12 +STOP +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump1.evm b/evmjit/evmcc/test/jump/jump1.evm new file mode 100644 index 000000000..0df9b4036 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump1.evm @@ -0,0 +1 @@ +600458006001600154 diff --git a/evmjit/evmcc/test/jump/jump1.lll b/evmjit/evmcc/test/jump/jump1.lll new file mode 100644 index 000000000..33119edb3 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump1.lll @@ -0,0 +1,11 @@ +;; Direct JUMP. +;; output: memory[1] == 1 + +(asm +4 ;; 0 +JUMP ;; 2 +STOP ;; 3 +1 ;; 4 +1 ;; 6 +MSTORE ;; 8 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump2.evm b/evmjit/evmcc/test/jump/jump2.evm new file mode 100644 index 000000000..35d75941d --- /dev/null +++ b/evmjit/evmcc/test/jump/jump2.evm @@ -0,0 +1 @@ +6008586001600154 diff --git a/evmjit/evmcc/test/jump/jump2.lll b/evmjit/evmcc/test/jump/jump2.lll new file mode 100644 index 000000000..a70d50ecb --- /dev/null +++ b/evmjit/evmcc/test/jump/jump2.lll @@ -0,0 +1,10 @@ +;; Direct JUMP to the end of code. +;; output: memory should have size 0. + +(asm +8 ;; 0 +JUMP ;; 2 +1 ;; 3 +1 ;; 5 +MSTORE ;; 7 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump3.evm b/evmjit/evmcc/test/jump/jump3.evm new file mode 100644 index 000000000..599d4a764 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump3.evm @@ -0,0 +1 @@ +602a586001600154 diff --git a/evmjit/evmcc/test/jump/jump3.lll b/evmjit/evmcc/test/jump/jump3.lll new file mode 100644 index 000000000..bc897e30c --- /dev/null +++ b/evmjit/evmcc/test/jump/jump3.lll @@ -0,0 +1,10 @@ +;; Direct JUMP past the end of code. +;; output: memory should have size 0. + +(asm +42 +JUMP +1 +1 +MSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump4.evm b/evmjit/evmcc/test/jump/jump4.evm new file mode 100644 index 000000000..41713f43e --- /dev/null +++ b/evmjit/evmcc/test/jump/jump4.evm @@ -0,0 +1 @@ +600b6009580000600558005d6001600154 diff --git a/evmjit/evmcc/test/jump/jump4.lll b/evmjit/evmcc/test/jump/jump4.lll new file mode 100644 index 000000000..131baee2d --- /dev/null +++ b/evmjit/evmcc/test/jump/jump4.lll @@ -0,0 +1,17 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +(asm +11 ;; 0 +9 ;; 2 +JUMP ;; 4 --> 9 +STOP ;; 5 +STOP ;; 6 +5 ;; 7 +JUMP ;; 9 --> 11 +STOP ;; 10 +JUMPDEST +1 ;; 11 +1 +MSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump5.evm b/evmjit/evmcc/test/jump/jump5.evm new file mode 100644 index 000000000..c36d9615b --- /dev/null +++ b/evmjit/evmcc/test/jump/jump5.evm @@ -0,0 +1 @@ +6005600e585d600160015400600f5800 diff --git a/evmjit/evmcc/test/jump/jump5.lll b/evmjit/evmcc/test/jump/jump5.lll new file mode 100644 index 000000000..d28b7d4ac --- /dev/null +++ b/evmjit/evmcc/test/jump/jump5.lll @@ -0,0 +1,16 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +(asm +5 ;; 0 +14 ;; 2 +JUMP ;; 4 --> 14 +JUMPDEST ;; 5 +1 ;; 6 +1 ;; 8 +MSTORE ;; 10 +STOP ;; 11 +15 ;; 12 +JUMP ;; 14 --> 5 +STOP ;; 15 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump6.evm b/evmjit/evmcc/test/jump/jump6.evm new file mode 100644 index 000000000..029db7191 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump6.evm @@ -0,0 +1 @@ +600358600f600d58006014600758005d6001600154005d600260025400 diff --git a/evmjit/evmcc/test/jump/jump6.lll b/evmjit/evmcc/test/jump/jump6.lll new file mode 100644 index 000000000..1116aa663 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump6.lll @@ -0,0 +1,32 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +;; 0, 2 --> 3 .. 7 --> 13 -*-> 15 .. 19 + +(asm +3 ;; 0 +JUMP ;; 2 + +15 ;; 3 <- start +13 ;; 5 +JUMP ;; 7 <- b +STOP ;; 8 + +20 ;; 9 +7 ;; 11 + +JUMP ;; 13 <- a +STOP ;; 14 + +JUMPDEST ;; 15 <- c +1 ;; 16 +1 ;; 18 +MSTORE ;; 19 +STOP ;; 20 + +JUMPDEST ;; 21 <- d +2 ;; 22 +2 ;; 24 +MSTORE ;; 26 +STOP ;; 27 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jumpi_at_the_end.evm b/evmjit/evmcc/test/jump/jumpi_at_the_end.evm new file mode 100644 index 000000000..2d7411761 --- /dev/null +++ b/evmjit/evmcc/test/jump/jumpi_at_the_end.evm @@ -0,0 +1 @@ +600a6000545d6000536001900380600054600659 diff --git a/evmjit/evmcc/test/jump/jumpi_at_the_end.lll b/evmjit/evmcc/test/jump/jumpi_at_the_end.lll new file mode 100644 index 000000000..263ada6a7 --- /dev/null +++ b/evmjit/evmcc/test/jump/jumpi_at_the_end.lll @@ -0,0 +1 @@ +(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/loop1.evm b/evmjit/evmcc/test/jump/loop1.evm new file mode 100644 index 000000000..7724d6308 --- /dev/null +++ b/evmjit/evmcc/test/jump/loop1.evm @@ -0,0 +1 @@ +600a600181038060025960005460015460025400 diff --git a/evmjit/evmcc/test/jump/loop1.lll b/evmjit/evmcc/test/jump/loop1.lll new file mode 100644 index 000000000..0044ec1fb --- /dev/null +++ b/evmjit/evmcc/test/jump/loop1.lll @@ -0,0 +1,27 @@ +;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits + +(asm +10 + +;; 2 +1 +DUP2 +SUB +DUP1 +2 +JUMPI + +;; stack = 1 2 3 4 5 6 7 8 9 10 +0 +MSTORE +1 +MSTORE +2 +MSTORE +;;3 +;;MSTORE + +STOP +) + + diff --git a/evmjit/evmcc/test/jump/loop2.evm b/evmjit/evmcc/test/jump/loop2.evm new file mode 100644 index 000000000..faffa4e5b --- /dev/null +++ b/evmjit/evmcc/test/jump/loop2.evm @@ -0,0 +1 @@ +600a80600190038060025960005460015460025400 diff --git a/evmjit/evmcc/test/jump/loop2.lll b/evmjit/evmcc/test/jump/loop2.lll new file mode 100644 index 000000000..9996c52ba --- /dev/null +++ b/evmjit/evmcc/test/jump/loop2.lll @@ -0,0 +1,28 @@ +;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits + +(asm +10 + +;; 2 +DUP1 +1 +SWAP1 +SUB +DUP1 +2 +JUMPI + +;; stack = 1 2 3 4 5 6 7 8 9 10 +0 +MSTORE +1 +MSTORE +2 +MSTORE +;;3 +;;MSTORE + +STOP +) + + diff --git a/evmjit/evmcc/test/jump/rec1.ethel b/evmjit/evmcc/test/jump/rec1.ethel new file mode 100644 index 000000000..f83c8e81e --- /dev/null +++ b/evmjit/evmcc/test/jump/rec1.ethel @@ -0,0 +1,4 @@ +let f n = + if n == 0 then 2 else f (n-1) + +return f 10 diff --git a/evmjit/evmcc/test/jump/rec1.evm b/evmjit/evmcc/test/jump/rec1.evm new file mode 100644 index 000000000..2ae62aff6 --- /dev/null +++ b/evmjit/evmcc/test/jump/rec1.evm @@ -0,0 +1 @@ +6007600a6010585d60005460206000f26000810e6024596020600182036010585d602658600290509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/when1.asm b/evmjit/evmcc/test/jump/when1.asm new file mode 100644 index 000000000..01d41c266 --- /dev/null +++ b/evmjit/evmcc/test/jump/when1.asm @@ -0,0 +1,10 @@ +.code: + PUSH 1 + NOT + PUSH [tag0] + JUMPI + PUSH 13 + PUSH 128 + MSTORE +tag0: + diff --git a/evmjit/evmcc/test/jump/when1.evm b/evmjit/evmcc/test/jump/when1.evm new file mode 100644 index 000000000..303b02623 --- /dev/null +++ b/evmjit/evmcc/test/jump/when1.evm @@ -0,0 +1 @@ +60010f600b59600d608054 diff --git a/evmjit/evmcc/test/jump/when1.lll b/evmjit/evmcc/test/jump/when1.lll new file mode 100644 index 000000000..990a6e64a --- /dev/null +++ b/evmjit/evmcc/test/jump/when1.lll @@ -0,0 +1,2 @@ +(when (> 1 0) [i] 13) + \ No newline at end of file diff --git a/evmjit/evmcc/test/kv.evm b/evmjit/evmcc/test/kv.evm new file mode 100644 index 000000000..55141ea59 --- /dev/null +++ b/evmjit/evmcc/test/kv.evm @@ -0,0 +1 @@ +33604557602a8060106000396000f200604556330e0f602a59366080530a0f602a59602060805301356080533557604060805301608054600958 diff --git a/evmjit/evmcc/test/kv.lll b/evmjit/evmcc/test/kv.lll new file mode 100644 index 000000000..c62d9fa70 --- /dev/null +++ b/evmjit/evmcc/test/kv.lll @@ -0,0 +1,10 @@ +{ + [[69]] (caller) + (return 0 (lll + (when (= (caller) @@69) + (for {} (< @i (calldatasize)) [i](+ @i 64) + [[ (calldataload @i) ]] (calldataload (+ @i 32)) + ) + ) + 0)) +} diff --git a/evmjit/evmcc/test/mem/byte.evm b/evmjit/evmcc/test/mem/byte.evm new file mode 100644 index 000000000..ab63431ee --- /dev/null +++ b/evmjit/evmcc/test/mem/byte.evm @@ -0,0 +1 @@ +7f112233445566778899001122334455667788990011223344556677889900aabb6000137f112233445566778899001122334455667788990011223344556677889900aabb6001137f112233445566778899001122334455667788990011223344556677889900aabb6002137f112233445566778899001122334455667788990011223344556677889900aabb6003137f112233445566778899001122334455667788990011223344556677889900aabb6004137f112233445566778899001122334455667788990011223344556677889900aabb6005137f112233445566778899001122334455667788990011223344556677889900aabb6006137f112233445566778899001122334455667788990011223344556677889900aabb6007137f112233445566778899001122334455667788990011223344556677889900aabb6008137f112233445566778899001122334455667788990011223344556677889900aabb6009137f112233445566778899001122334455667788990011223344556677889900aabb600a137f112233445566778899001122334455667788990011223344556677889900aabb600b137f112233445566778899001122334455667788990011223344556677889900aabb600c137f112233445566778899001122334455667788990011223344556677889900aabb600d137f112233445566778899001122334455667788990011223344556677889900aabb600e137f112233445566778899001122334455667788990011223344556677889900aabb600f137f112233445566778899001122334455667788990011223344556677889900aabb6010137f112233445566778899001122334455667788990011223344556677889900aabb6011137f112233445566778899001122334455667788990011223344556677889900aabb6012137f112233445566778899001122334455667788990011223344556677889900aabb6013137f112233445566778899001122334455667788990011223344556677889900aabb6014137f112233445566778899001122334455667788990011223344556677889900aabb6015137f112233445566778899001122334455667788990011223344556677889900aabb6016137f112233445566778899001122334455667788990011223344556677889900aabb6017137f112233445566778899001122334455667788990011223344556677889900aabb6018137f112233445566778899001122334455667788990011223344556677889900aabb6019137f112233445566778899001122334455667788990011223344556677889900aabb601a137f112233445566778899001122334455667788990011223344556677889900aabb601b137f112233445566778899001122334455667788990011223344556677889900aabb601c137f112233445566778899001122334455667788990011223344556677889900aabb601d137f112233445566778899001122334455667788990011223344556677889900aabb601e137f112233445566778899001122334455667788990011223344556677889900aabb601f137f112233445566778899001122334455667788990011223344556677889900aabb6020137f112233445566778899001122334455667788990011223344556677889900aabb6107de13 diff --git a/evmjit/evmcc/test/mem/byte.lll b/evmjit/evmcc/test/mem/byte.lll new file mode 100644 index 000000000..95b0f99dc --- /dev/null +++ b/evmjit/evmcc/test/mem/byte.lll @@ -0,0 +1,105 @@ + +(asm +0x112233445566778899001122334455667788990011223344556677889900aabb +0 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +1 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +2 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +3 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +4 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +5 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +6 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +7 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +8 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +9 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +10 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +11 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +12 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +13 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +14 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +15 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +16 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +17 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +18 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +19 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +20 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +21 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +22 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +23 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +24 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +25 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +26 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +27 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +28 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +29 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +30 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +31 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +32 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +2014 +BYTE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/mem/mem2.evm b/evmjit/evmcc/test/mem/mem2.evm new file mode 100644 index 000000000..49cc6e8b1 --- /dev/null +++ b/evmjit/evmcc/test/mem/mem2.evm @@ -0,0 +1 @@ +6001610d805b01556504409585d6df620493e05462061a80535b01 diff --git a/evmjit/evmcc/test/mem/mem2.lll b/evmjit/evmcc/test/mem/mem2.lll new file mode 100644 index 000000000..5345ee47c --- /dev/null +++ b/evmjit/evmcc/test/mem/mem2.lll @@ -0,0 +1,15 @@ + +(asm ;; [] +1 +3456 +MSIZE +ADD +MSTORE8 ;; [02] +4675432994527 +300000 +MSTORE +400000 +MLOAD +MSIZE +ADD +) \ No newline at end of file diff --git a/evmjit/evmcc/test/mem/memtest1.evm b/evmjit/evmcc/test/mem/memtest1.evm new file mode 100644 index 000000000..0506bf928 --- /dev/null +++ b/evmjit/evmcc/test/mem/memtest1.evm @@ -0,0 +1 @@ +6002600055600360015560005360015301600254 diff --git a/evmjit/evmcc/test/mem/memtest1.lll b/evmjit/evmcc/test/mem/memtest1.lll new file mode 100644 index 000000000..4b4389ad8 --- /dev/null +++ b/evmjit/evmcc/test/mem/memtest1.lll @@ -0,0 +1,18 @@ + +(asm ;; [] +2 +0 +MSTORE8 ;; [02] +3 +1 +MSTORE8 ;; [02 03] +0 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +1 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +ADD +2 +MSTORE ;; [2 3 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +) \ No newline at end of file diff --git a/evmjit/evmcc/test/mem/mstore1.evm b/evmjit/evmcc/test/mem/mstore1.evm new file mode 100644 index 000000000..ba6141ab1 --- /dev/null +++ b/evmjit/evmcc/test/mem/mstore1.evm @@ -0,0 +1 @@ +6001600054 diff --git a/evmjit/evmcc/test/mem/mstore1.lll b/evmjit/evmcc/test/mem/mstore1.lll new file mode 100644 index 000000000..2d2ca32b5 --- /dev/null +++ b/evmjit/evmcc/test/mem/mstore1.lll @@ -0,0 +1,6 @@ + +(asm ;; [] +1 +0 +MSTORE ;; [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ret/return1.evm b/evmjit/evmcc/test/ret/return1.evm new file mode 100644 index 000000000..8092cb007 --- /dev/null +++ b/evmjit/evmcc/test/ret/return1.evm @@ -0,0 +1 @@ +600160805460006080530b601b59600160005460206000f2602a58602760005460206000f26002608054 diff --git a/evmjit/evmcc/test/ret/return1.lll b/evmjit/evmcc/test/ret/return1.lll new file mode 100644 index 000000000..159d15ca3 --- /dev/null +++ b/evmjit/evmcc/test/ret/return1.lll @@ -0,0 +1,6 @@ +;; code should return 39 +;; i should remain 1 +{ + [i] 1 + ( if (> @i 0) { (return 39) [i] 2 } (return 1) ) +} \ No newline at end of file diff --git a/evmjit/evmcc/test/ret/return2.evm b/evmjit/evmcc/test/ret/return2.evm new file mode 100644 index 000000000..e29da7664 --- /dev/null +++ b/evmjit/evmcc/test/ret/return2.evm @@ -0,0 +1 @@ +6001620f4240f2 diff --git a/evmjit/evmcc/test/ret/return2.lll b/evmjit/evmcc/test/ret/return2.lll new file mode 100644 index 000000000..f5ee68f6e --- /dev/null +++ b/evmjit/evmcc/test/ret/return2.lll @@ -0,0 +1,6 @@ + +(asm +1 +1000000 +RETURN ;; return 1 byte from index 1M +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ret/return_test.evm b/evmjit/evmcc/test/ret/return_test.evm new file mode 100644 index 000000000..977cf7c19 --- /dev/null +++ b/evmjit/evmcc/test/ret/return_test.evm @@ -0,0 +1 @@ +60016064546002608454600360a45460606064f2 diff --git a/evmjit/evmcc/test/ret/return_test.lll b/evmjit/evmcc/test/ret/return_test.lll new file mode 100644 index 000000000..c87a2d812 --- /dev/null +++ b/evmjit/evmcc/test/ret/return_test.lll @@ -0,0 +1,15 @@ + +(asm +1 +100 +MSTORE +2 +132 +MSTORE +3 +164 +MSTORE +96 +100 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/oos.evm b/evmjit/evmcc/test/stack/oos.evm new file mode 100644 index 000000000..ea2f1c890 --- /dev/null +++ b/evmjit/evmcc/test/stack/oos.evm @@ -0,0 +1 @@ +60018194505050509150 diff --git a/evmjit/evmcc/test/stack/oos.lll b/evmjit/evmcc/test/stack/oos.lll new file mode 100644 index 000000000..5394b06ba --- /dev/null +++ b/evmjit/evmcc/test/stack/oos.lll @@ -0,0 +1,11 @@ +(asm ;; x . v y z +1 ;; 1 x . v y z +DUP2 ;; x 1 x . v y z +SWAP5 ;; y 1 x . v x z +POP ;; 1 x . v x z +POP ;; x . v x z +POP ;; . v x z +POP ;; v x z +SWAP2 ;; z x v +POP ;; x v +) diff --git a/evmjit/evmcc/test/stack/push_test.evm b/evmjit/evmcc/test/stack/push_test.evm new file mode 100644 index 000000000..d624cee1d --- /dev/null +++ b/evmjit/evmcc/test/stack/push_test.evm @@ -0,0 +1 @@ +60656107d26204a0c763026921f4640bc5588eb165372d0f1dca6e661ba1d901961c71670c55f7bc23038e3868056bc75e2d630fffff69021e19e0c9bab24000016a085d1c6e8050f0ea1c71bd6b0688be36543f3c36e638e37a6c03d41f73d55d0d482ae55555376dc76810d0fe03c91964d31c71c6f46e615dd0360c07d931663b14e38e38b16f2da3f99955a3adcf27ebb1caaaaaaa6e7014ccba6a8bb1ed35bd86bf065c71c71c2b7109491c5d4781b79c9009de6bfb8e38e38de8720414a0f6fdec81304d4c563e740bffffffffa573118427b3b4a05bc8a8a4de8459868000000000017406eb15e7331e727940d4ac54b7cdca1c71c71c71bd750567a91c9fefc96ebaa626a22f98c5e638e38e38e37a76032abd16c5b68006e15d5aa307e383f4e55555555555377701a6427bdc4f0d58eab5f48a3ec67f64e21c71c71c71c6f478080dd0a0c9b9ff2c2a0c740b06853a0a980ee38e38e38e38b17903c679cb5e8f2f9cb3b5d6652b0e7334f746faaaaaaaaaaaaa6e7a01b873815917ebb2bf3b890a1af495d6235bae3c71c71c71c71c2b7b07ae4cca96e1a55dfa49c85ad3c3e60e426b92fb8e38e38e38e38de87c036018bf074e292bcc7d6c8bea0f9699443046178bffffffffffffffa57d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000017e05b901f48a5b994d6572502bc4ea43140486666416aa1c71c71c71c71c71bd7f047889870c178fc477414ea231d70467a388fffe31b4e638e38e38e38e38e37a diff --git a/evmjit/evmcc/test/stack/push_test.lll b/evmjit/evmcc/test/stack/push_test.lll new file mode 100644 index 000000000..832daaec1 --- /dev/null +++ b/evmjit/evmcc/test/stack/push_test.lll @@ -0,0 +1,35 @@ + +(asm +101 ;; PUSH1 +2002 ;; PUSH2 +303303 ;; PUSH3 +40444404 ;; PUSH4 +50555555505 ;; PUSH5 +60666666666606 +7777777777777777 +888888888888888888 +99999999999999999999 +10000000000000000000001 +10111111111111111111111101 +2022222222222222222222222202 +303333333333333333333333333303 +4044444444444444444444444444444404 +505555555555555555555555555555555505 +60666666666666666666666666666666666606 +7077777777777777777777777777777777777707 +808888888888888888888888888888888888888808 +90999999999999999999999999999999999999999909 +100000000000000000000000000000000000000000000001 +10111111111111111111111111111111111111111111111101 +2022222222222222222222222222222222222222222222222202 +303333333333333333333333333333333333333333333333333303 +40444444444444444444444444444444444444444444444444444404 +50555555555555555555555555555555555555555555555555555555505 +6066666666666666666666666666666666666666666666666666666666606 +707777777777777777777777777777777777777777777777777777777777707 +808888888888888888888888888888888888888888888888888888888888888808 +90999999999999999999999999999999999999999999999999999999999999999909 +100000000000000000000000000000000000000000000000000000000000000000000001 +10111111111111111111111111111111111111111111111111111111111111111111111101 +2022222222222222222222222222222222222222222222222222222222222222222222222202 ;; PUSH32 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/stack_test.evm b/evmjit/evmcc/test/stack/stack_test.evm new file mode 100644 index 000000000..02417c967 --- /dev/null +++ b/evmjit/evmcc/test/stack/stack_test.evm @@ -0,0 +1 @@ +65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae81819290 diff --git a/evmjit/evmcc/test/stack/stack_test.lll b/evmjit/evmcc/test/stack/stack_test.lll new file mode 100644 index 000000000..fdf83594c --- /dev/null +++ b/evmjit/evmcc/test/stack/stack_test.lll @@ -0,0 +1,8 @@ + +(asm +123 +SSTORE +SLOAD +123 +SUB +) \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/stackjump.evm b/evmjit/evmcc/test/stack/stackjump.evm new file mode 100644 index 000000000..baddec42e --- /dev/null +++ b/evmjit/evmcc/test/stack/stackjump.evm @@ -0,0 +1 @@ +600460066009601358600a036000545b6000f260005401600958 \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/stackjump.lll b/evmjit/evmcc/test/stack/stackjump.lll new file mode 100644 index 000000000..f5da5e733 --- /dev/null +++ b/evmjit/evmcc/test/stack/stackjump.lll @@ -0,0 +1,3 @@ +(asm +0x4 0x6 0x9 0x13 JUMP 0xa SUB 0x0 MSTORE MSIZE 0x0 RETURN 0x0 MSTORE ADD 0x9 JUMP +) diff --git a/evmjit/evmcc/test/stack/swap.evm b/evmjit/evmcc/test/stack/swap.evm new file mode 100644 index 000000000..d17f0ee09 --- /dev/null +++ b/evmjit/evmcc/test/stack/swap.evm @@ -0,0 +1 @@ +600560026001600c59505000906001601559505000036000546001601ff2 diff --git a/evmjit/evmcc/test/stack/swap.lll b/evmjit/evmcc/test/stack/swap.lll new file mode 100644 index 000000000..90dee585d --- /dev/null +++ b/evmjit/evmcc/test/stack/swap.lll @@ -0,0 +1,31 @@ +(asm +5 ;; 0 +2 ;; 2 +1 ;; 4 +12 ;; 6 +JUMPI ;; 8 + +POP ;; 9 +POP ;; 10 +STOP ;; 11 + +;; stack = 2,1 +SWAP1 ;; 12 +1 ;; 13 +21 ;; 15 +JUMPI ;; 17 + +POP ;; 18 +POP ;; 19 +STOP ;; 20 + +;; stack = 1,2 +SUB ;; 21 +0 +MSTORE +1 +31 +RETURN ;; returns 03 +) + + diff --git a/evmjit/evmcc/test/stack/swapswap.evm b/evmjit/evmcc/test/stack/swapswap.evm new file mode 100644 index 000000000..fb4f1bf75 --- /dev/null +++ b/evmjit/evmcc/test/stack/swapswap.evm @@ -0,0 +1 @@ +600260056001600c5950500090906001601659505000036000546001601ff2 diff --git a/evmjit/evmcc/test/stack/swapswap.lll b/evmjit/evmcc/test/stack/swapswap.lll new file mode 100644 index 000000000..1fedf726e --- /dev/null +++ b/evmjit/evmcc/test/stack/swapswap.lll @@ -0,0 +1,32 @@ +(asm +2 ;; 0 +5 ;; 2 +1 ;; 4 +12 ;; 6 +JUMPI ;; 8 + +POP ;; 9 +POP ;; 10 +STOP ;; 11 + +;; stack = 2,1 +SWAP1 ;; 12 +SWAP1 ;; 13 +1 ;; 14 +22 ;; 16 +JUMPI ;; 18 + +POP ;; 19 +POP ;; 20 +STOP ;; 21 + +;; stack = 2,1 +SUB ;; 22 +0 +MSTORE +1 +31 +RETURN ;; returns 03 +) + + diff --git a/evmjit/evmcc/test/stack/test.evm b/evmjit/evmcc/test/stack/test.evm new file mode 100644 index 000000000..ea2f1c890 --- /dev/null +++ b/evmjit/evmcc/test/stack/test.evm @@ -0,0 +1 @@ +60018194505050509150 diff --git a/evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json b/evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json new file mode 100644 index 000000000..d9017517f --- /dev/null +++ b/evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json @@ -0,0 +1,260 @@ +{ + "arith-1" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "999538", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-2" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "995488", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-3" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "954988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-4" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "549988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { } + } + } + } + + + , + + + "arith-5" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "5499988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { } + } + } + } + +, + + "arith-6" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "data" : "0x", + "gas" : "100000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "54999988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { } + } + } + } + +} diff --git a/evmjit/evmcc/test/vmtests/vmPerformanceTest.json b/evmjit/evmcc/test/vmtests/vmPerformanceTest.json new file mode 100644 index 000000000..604e45993 --- /dev/null +++ b/evmjit/evmcc/test/vmtests/vmPerformanceTest.json @@ -0,0 +1,214 @@ +{ + "mulmodloop" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x60015b68010000000000000000908060010109600356", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "0", + "out" : "0x0", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x60015b68010000000000000000908060010109600356", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x60015b68010000000000000000908060010109600356", + "nonce" : "0", + "storage" : { } + } + } + }, + + + "for-1e06" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "data" : "0x", + "gas" : "30000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "6999982", + "out" : "0x00", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "nonce" : "0", + "storage" : { } + } + } + }, + + "fib25" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "data" : "0x", + "gas" : "40000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "5886377", + "out" : "0x00000000000000000000000000000000000000000000000000000000000cb228", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "nonce" : "0", + "storage" : { + } + } + } + }, + + "ackermann37" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "20000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "data" : "0x", + "gas" : "20000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "913456", + "out" : "0x00000000000000000000000000000000000000000000000000000000000003fd", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "nonce" : "0", + "storage" : { + } + } + } + }, + + "jumptable100" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "389596", + "out" : "0x0000000000000000000000000000000000000000000000000000000000000064", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "nonce" : "0", + "storage" : { + } + } + } + }, + +} diff --git a/evmjit/evmcc/test/vmtests/vm_jump.json b/evmjit/evmcc/test/vmtests/vm_jump.json new file mode 100644 index 000000000..6b63edeae --- /dev/null +++ b/evmjit/evmcc/test/vmtests/vm_jump.json @@ -0,0 +1,41 @@ +{ + "jumpi_at_the_end" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "data" : "0x", + "gas" : "1000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "895", + "out" : "0x0", + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "nonce" : "0", + "storage" : {} + } + }, + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "nonce" : "0", + "storage" : {} + } + } + } +} diff --git a/evmjit/libevmjit-cpp/CMakeLists.txt b/evmjit/libevmjit-cpp/CMakeLists.txt new file mode 100644 index 000000000..53448332b --- /dev/null +++ b/evmjit/libevmjit-cpp/CMakeLists.txt @@ -0,0 +1,24 @@ +set(TARGET_NAME evmjit-cpp) + +# Boost +find_package(Boost REQUIRED) + +set(SOURCES + Env.cpp + JitVM.cpp JitVM.h +) +source_group("" FILES ${SOURCES}) + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive +endif() + +add_library(${TARGET_NAME} ${SOURCES}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") + +include_directories(../..) +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(${TARGET_NAME} evmjit) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp new file mode 100644 index 000000000..11882d79d --- /dev/null +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -0,0 +1,117 @@ + +#pragma GCC diagnostic ignored "-Wconversion" +#include +#include +#include + +#include "Utils.h" + +extern "C" +{ + #ifdef _MSC_VER + #define EXPORT __declspec(dllexport) + #else + #define EXPORT + #endif + + using namespace dev; + using namespace dev::eth; + using jit::i256; + + EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) + { + auto index = llvm2eth(*_index); + auto value = _env->store(index); // Interface uses native endianness + *o_value = eth2llvm(value); + } + + EXPORT void env_sstore(ExtVMFace* _env, i256* _index, i256* _value) + { + auto index = llvm2eth(*_index); + auto value = llvm2eth(*_value); + + if (value == 0 && _env->store(index) != 0) // If delete + _env->sub.refunds += c_sstoreRefundGas; // Increase refund counter + + _env->setStore(index, value); // Interface uses native endianness + } + + EXPORT void env_balance(ExtVMFace* _env, h256* _address, i256* o_value) + { + auto u = _env->balance(right160(*_address)); + *o_value = eth2llvm(u); + } + + EXPORT void env_blockhash(ExtVMFace* _env, i256* _number, h256* o_hash) + { + *o_hash = _env->blockhash(llvm2eth(*_number)); + } + + EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + { + auto endowment = llvm2eth(*_endowment); + if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) + { + _env->subBalance(endowment); + u256 gas = *io_gas; + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + *io_gas = static_cast(gas); + *o_address = address; + } + else + *o_address = {}; + } + + EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + { + auto value = llvm2eth(*_value); + if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) + { + _env->subBalance(value); + auto receiveAddress = right160(*_receiveAddress); + auto inRef = bytesConstRef{_inBeg, _inSize}; + auto outRef = bytesRef{_outBeg, _outSize}; + auto codeAddress = right160(*_codeAddress); + u256 gas = *io_gas; + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); + *io_gas = static_cast(gas); + return ret; + } + + return false; + } + + EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) + { + auto hash = sha3({_begin, _size}); + *o_hash = hash; + } + + EXPORT byte const* env_extcode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size) + { + auto addr = right160(*_addr256); + auto& code = _env->codeAt(addr); + *o_size = code.size(); + return code.data(); + } + + EXPORT void env_log(ExtVMFace* _env, byte* _beg, uint64_t _size, h256* _topic1, h256* _topic2, h256* _topic3, h256* _topic4) + { + dev::h256s topics; + + if (_topic1) + topics.push_back(*_topic1); + + if (_topic2) + topics.push_back(*_topic2); + + if (_topic3) + topics.push_back(*_topic3); + + if (_topic4) + topics.push_back(*_topic4); + + _env->log(std::move(topics), {_beg, _size}); + } +} + diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp new file mode 100644 index 000000000..55dcd94f8 --- /dev/null +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -0,0 +1,83 @@ + +#pragma GCC diagnostic ignored "-Wconversion" +#include "JitVM.h" +#include +#include +#include +#include +#include "Utils.h" + +namespace dev +{ +namespace eth +{ + +extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below + +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) +{ + using namespace jit; + + auto rejected = false; + // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope + rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) + rejected |= _ext.gasPrice > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + + if (rejected) + { + UNTESTED; + std::cerr << "Rejected\n"; + VMFactory::setKind(VMKind::Interpreter); + m_fallbackVM = VMFactory::create(m_gas); + VMFactory::setKind(VMKind::JIT); + return m_fallbackVM->go(_ext, _onOp, _step); + } + + m_data.gas = static_cast(m_gas); + m_data.gasPrice = static_cast(_ext.gasPrice); + m_data.callData = _ext.data.data(); + m_data.callDataSize = _ext.data.size(); + m_data.address = eth2llvm(fromAddress(_ext.myAddress)); + m_data.caller = eth2llvm(fromAddress(_ext.caller)); + m_data.origin = eth2llvm(fromAddress(_ext.origin)); + m_data.callValue = eth2llvm(_ext.value); + m_data.coinBase = eth2llvm(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.difficulty = eth2llvm(_ext.currentBlock.difficulty); + m_data.gasLimit = eth2llvm(_ext.currentBlock.gasLimit); + m_data.number = static_cast(_ext.currentBlock.number); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.code = _ext.code.data(); + m_data.codeSize = _ext.code.size(); + m_data.codeHash = eth2llvm(sha3(_ext.code)); + + auto env = reinterpret_cast(&_ext); + auto exitCode = m_engine.run(&m_data, env); + switch (exitCode) + { + case ReturnCode::Suicide: + _ext.suicide(right160(llvm2eth(m_data.address))); + break; + + case ReturnCode::BadJumpDestination: + BOOST_THROW_EXCEPTION(BadJumpDestination()); + case ReturnCode::OutOfGas: + BOOST_THROW_EXCEPTION(OutOfGas()); + case ReturnCode::StackTooSmall: + BOOST_THROW_EXCEPTION(StackTooSmall()); + case ReturnCode::BadInstruction: + BOOST_THROW_EXCEPTION(BadInstruction()); + case ReturnCode::LinkerWorkaround: // never happens + env_sload(); // but forces linker to include env_* JIT callback functions + break; + default: + break; + } + + m_gas = m_data.gas; // TODO: Remove m_gas field + return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)}; +} + +} +} diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h new file mode 100644 index 000000000..58caa3648 --- /dev/null +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ + +class JitVM: public VMFace +{ + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + +private: + friend class VMFactory; + explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} + + jit::RuntimeData m_data; + jit::ExecutionEngine m_engine; + std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT +}; + + +} +} diff --git a/evmjit/libevmjit-cpp/Utils.h b/evmjit/libevmjit-cpp/Utils.h new file mode 100644 index 000000000..ac796920b --- /dev/null +++ b/evmjit/libevmjit-cpp/Utils.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace dev +{ +namespace eth +{ + +inline u256 llvm2eth(jit::i256 _i) +{ + u256 u = 0; + u |= _i.d; + u <<= 64; + u |= _i.c; + u <<= 64; + u |= _i.b; + u <<= 64; + u |= _i.a; + return u; +} + +inline jit::i256 eth2llvm(u256 _u) +{ + jit::i256 i; + u256 mask = 0xFFFFFFFFFFFFFFFF; + i.a = static_cast(_u & mask); + _u >>= 64; + i.b = static_cast(_u & mask); + _u >>= 64; + i.c = static_cast(_u & mask); + _u >>= 64; + i.d = static_cast(_u & mask); + return i; +} + +} +} diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp new file mode 100644 index 000000000..ddf06b463 --- /dev/null +++ b/evmjit/libevmjit/Arith256.cpp @@ -0,0 +1,406 @@ +#include "Arith256.h" + +#include +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" +#include "Endianness.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Arith256::Arith256(llvm::IRBuilder<>& _builder) : + CompilerHelper(_builder) +{} + +void Arith256::debug(llvm::Value* _value, char _c) +{ + if (!m_debug) + { + llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; + m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); + } + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); +} + +llvm::Function* Arith256::getMulFunc() +{ + auto& func = m_mul; + if (!func) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i64 = Type::Size; + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo"); + auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64); + auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128); + + auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128)); + auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128)); + auto t3 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), y_hi); + auto t4 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_lo, i128)); + auto t5 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_mi, i128)); + auto t6 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), y_hi); + auto t7 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_lo, i128)); + auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128)); + + auto p = m_builder.CreateZExt(t1, i256); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); + m_builder.CreateRet(p); + } + return func; +} + +llvm::Function* Arith256::getMul512Func() +{ + auto& func = m_mul512; + if (!func) + { + auto i512 = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateZExt(m_builder.CreateTrunc(x, i128, "x.lo"), i256); + auto y_lo = m_builder.CreateZExt(m_builder.CreateTrunc(y, i128, "y.lo"), i256); + auto x_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256); + auto y_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256); + + auto t1 = createCall(getMulFunc(), {x_lo, y_lo}); + auto t2 = createCall(getMulFunc(), {x_lo, y_hi}); + auto t3 = createCall(getMulFunc(), {x_hi, y_lo}); + auto t4 = createCall(getMulFunc(), {x_hi, y_hi}); + + auto p = m_builder.CreateZExt(t1, i512); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i512), m_builder.getIntN(512, 256))); + m_builder.CreateRet(p); + } + return func; +} + +llvm::Function* Arith256::getDivFunc(llvm::Type* _type) +{ + auto& func = _type == Type::Word ? m_div : m_div512; + + if (!func) + { + // Based of "Improved shift divisor algorithm" from "Software Integer Division" by Microsoft Research + // The following algorithm also handles divisor of value 0 returning 0 for both quotient and reminder + + llvm::Type* argTypes[] = {_type, _type}; + auto retType = llvm::StructType::get(m_builder.getContext(), llvm::ArrayRef{argTypes}); + auto funcName = _type == Type::Word ? "div" : "div512"; + func = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, funcName, getModule()); + + auto zero = llvm::ConstantInt::get(_type, 0); + auto one = llvm::ConstantInt::get(_type, 1); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto yArg = x->getNextNode(); + yArg->setName("y"); + + InsertPointGuard guard{m_builder}; + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func); + auto mainBB = llvm::BasicBlock::Create(m_builder.getContext(), "Main", func); + auto loopBB = llvm::BasicBlock::Create(m_builder.getContext(), "Loop", func); + auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto yNonZero = m_builder.CreateICmpNE(yArg, zero); + auto yLEx = m_builder.CreateICmpULE(yArg, x); + auto r0 = m_builder.CreateSelect(yNonZero, x, zero, "r0"); + m_builder.CreateCondBr(m_builder.CreateAnd(yLEx, yNonZero), mainBB, returnBB); + + m_builder.SetInsertPoint(mainBB); + auto ctlzIntr = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, _type); + // both y and r are non-zero + auto yLz = m_builder.CreateCall2(ctlzIntr, yArg, m_builder.getInt1(true), "y.lz"); + auto rLz = m_builder.CreateCall2(ctlzIntr, r0, m_builder.getInt1(true), "r.lz"); + auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); + auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); + auto y0 = m_builder.CreateShl(yArg, i0); + if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts + { + const auto treshold = m_builder.getIntN(512, 128); + auto highShift = m_builder.CreateICmpUGT(i0, treshold); + auto s = m_builder.CreateNUWSub(i0, treshold); + auto yhs = m_builder.CreateShl(yArg, treshold); + yhs = m_builder.CreateShl(yhs, s); + y0 = m_builder.CreateSelect(highShift, yhs, y0); + } + y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result + m_builder.CreateBr(loopBB); + + m_builder.SetInsertPoint(loopBB); + auto yPhi = m_builder.CreatePHI(_type, 2, "y.phi"); + auto rPhi = m_builder.CreatePHI(_type, 2, "r.phi"); + auto iPhi = m_builder.CreatePHI(_type, 2, "i.phi"); + auto qPhi = m_builder.CreatePHI(_type, 2, "q.phi"); + auto rUpdate = m_builder.CreateNUWSub(rPhi, yPhi); + auto qUpdate = m_builder.CreateOr(qPhi, one); // q += 1, q lowest bit is 0 + auto rGEy = m_builder.CreateICmpUGE(rPhi, yPhi); + auto r1 = m_builder.CreateSelect(rGEy, rUpdate, rPhi, "r1"); + auto q1 = m_builder.CreateSelect(rGEy, qUpdate, qPhi, "q"); + auto iZero = m_builder.CreateICmpEQ(iPhi, zero); + m_builder.CreateCondBr(iZero, returnBB, continueBB); + + m_builder.SetInsertPoint(continueBB); + auto i2 = m_builder.CreateNUWSub(iPhi, one); + auto q2 = m_builder.CreateShl(q1, one); + auto y2 = m_builder.CreateLShr(yPhi, one); + m_builder.CreateBr(loopBB); + + yPhi->addIncoming(y0, mainBB); + yPhi->addIncoming(y2, continueBB); + rPhi->addIncoming(r0, mainBB); + rPhi->addIncoming(r1, continueBB); + iPhi->addIncoming(i0, mainBB); + iPhi->addIncoming(i2, continueBB); + qPhi->addIncoming(zero, mainBB); + qPhi->addIncoming(q2, continueBB); + + m_builder.SetInsertPoint(returnBB); + auto qRet = m_builder.CreatePHI(_type, 2, "q.ret"); + qRet->addIncoming(zero, entryBB); + qRet->addIncoming(q1, loopBB); + auto rRet = m_builder.CreatePHI(_type, 2, "r.ret"); + rRet->addIncoming(r0, entryBB); + rRet->addIncoming(r1, loopBB); + auto ret = m_builder.CreateInsertValue(llvm::UndefValue::get(retType), qRet, 0, "ret0"); + ret = m_builder.CreateInsertValue(ret, rRet, 1, "ret"); + m_builder.CreateRet(ret); + } + return func; +} + +llvm::Function* Arith256::getExpFunc() +{ + if (!m_exp) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule()); + + auto base = &m_exp->getArgumentList().front(); + base->setName("base"); + auto exponent = base->getNextNode(); + exponent->setName("exponent"); + + InsertPointGuard guard{m_builder}; + + // while (e != 0) { + // if (e % 2 == 1) + // r *= b; + // b *= b; + // e /= 2; + // } + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", m_exp); + auto headerBB = llvm::BasicBlock::Create(m_builder.getContext(), "LoopHeader", m_exp); + auto bodyBB = llvm::BasicBlock::Create(m_builder.getContext(), "LoopBody", m_exp); + auto updateBB = llvm::BasicBlock::Create(m_builder.getContext(), "ResultUpdate", m_exp); + auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", m_exp); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); + + m_builder.SetInsertPoint(entryBB); + m_builder.CreateBr(headerBB); + + m_builder.SetInsertPoint(headerBB); + auto r = m_builder.CreatePHI(Type::Word, 2, "r"); + auto b = m_builder.CreatePHI(Type::Word, 2, "b"); + auto e = m_builder.CreatePHI(Type::Word, 2, "e"); + auto eNonZero = m_builder.CreateICmpNE(e, Constant::get(0), "e.nonzero"); + m_builder.CreateCondBr(eNonZero, bodyBB, returnBB); + + m_builder.SetInsertPoint(bodyBB); + auto eOdd = m_builder.CreateICmpNE(m_builder.CreateAnd(e, Constant::get(1)), Constant::get(0), "e.isodd"); + m_builder.CreateCondBr(eOdd, updateBB, continueBB); + + m_builder.SetInsertPoint(updateBB); + auto r0 = createCall(getMulFunc(), {r, b}); + m_builder.CreateBr(continueBB); + + m_builder.SetInsertPoint(continueBB); + auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1"); + r1->addIncoming(r, bodyBB); + r1->addIncoming(r0, updateBB); + auto b1 = createCall(getMulFunc(), {b, b}); + auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); + m_builder.CreateBr(headerBB); + + r->addIncoming(Constant::get(1), entryBB); + r->addIncoming(r1, continueBB); + b->addIncoming(base, entryBB); + b->addIncoming(b1, continueBB); + e->addIncoming(exponent, entryBB); + e->addIncoming(e1, continueBB); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(r); + } + return m_exp; +} + +llvm::Function* Arith256::getAddModFunc() +{ + if (!m_addmod) + { + auto i512Ty = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word}; + m_addmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "addmod", getModule()); + + auto x = &m_addmod->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + auto mod = y->getNextNode(); + mod->setName("m"); + + InsertPointGuard guard{m_builder}; + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_addmod); + m_builder.SetInsertPoint(entryBB); + auto x512 = m_builder.CreateZExt(x, i512Ty, "x512"); + auto y512 = m_builder.CreateZExt(y, i512Ty, "y512"); + auto m512 = m_builder.CreateZExt(mod, i512Ty, "m512"); + auto s = m_builder.CreateAdd(x512, y512, "s"); + auto d = createCall(getDivFunc(i512Ty), {s, m512}); + auto r = m_builder.CreateExtractValue(d, 1, "r"); + m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + } + return m_addmod; +} + +llvm::Function* Arith256::getMulModFunc() +{ + if (!m_mulmod) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word}; + m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); + + auto i512Ty = m_builder.getIntNTy(512); + auto x = &m_mulmod->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + auto mod = y->getNextNode(); + mod->setName("mod"); + + InsertPointGuard guard{m_builder}; + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); + m_builder.SetInsertPoint(entryBB); + auto p = createCall(getMul512Func(), {x, y}); + auto m = m_builder.CreateZExt(mod, i512Ty, "m"); + auto d = createCall(getDivFunc(i512Ty), {p, m}); + auto r = m_builder.CreateExtractValue(d, 1, "r"); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); + } + return m_mulmod; +} + +llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return createCall(getMulFunc(), {_arg1, _arg2}); +} + +std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) +{ + auto div = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 0, "div"); + auto mod = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 1, "mod"); + return std::make_pair(div, mod); +} + +std::pair Arith256::sdiv(llvm::Value* _x, llvm::Value* _y) +{ + auto xIsNeg = m_builder.CreateICmpSLT(_x, Constant::get(0)); + auto xNeg = m_builder.CreateSub(Constant::get(0), _x); + auto xAbs = m_builder.CreateSelect(xIsNeg, xNeg, _x); + + auto yIsNeg = m_builder.CreateICmpSLT(_y, Constant::get(0)); + auto yNeg = m_builder.CreateSub(Constant::get(0), _y); + auto yAbs = m_builder.CreateSelect(yIsNeg, yNeg, _y); + + auto res = div(xAbs, yAbs); + + // the reminder has the same sign as dividend + auto rNeg = m_builder.CreateSub(Constant::get(0), res.second); + res.second = m_builder.CreateSelect(xIsNeg, rNeg, res.second); + + auto qNeg = m_builder.CreateSub(Constant::get(0), res.first); + auto xyOpposite = m_builder.CreateXor(xIsNeg, yIsNeg); + res.first = m_builder.CreateSelect(xyOpposite, qNeg, res.first); + + return res; +} + +llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return createCall(getExpFunc(), {_arg1, _arg2}); +} + +llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + return createCall(getAddModFunc(), {_arg1, _arg2, _arg3}); +} + +llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); +} + + +} +} +} + +extern "C" +{ + EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) + { + std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a + << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n"; + } +} diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h new file mode 100644 index 000000000..2513ca568 --- /dev/null +++ b/evmjit/libevmjit/Arith256.h @@ -0,0 +1,47 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Arith256 : public CompilerHelper +{ +public: + Arith256(llvm::IRBuilder<>& _builder); + + llvm::Value* mul(llvm::Value* _arg1, llvm::Value* _arg2); + std::pair div(llvm::Value* _arg1, llvm::Value* _arg2); + std::pair sdiv(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* exp(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + llvm::Value* addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + + void debug(llvm::Value* _value, char _c); + +private: + llvm::Function* getMulFunc(); + llvm::Function* getMul512Func(); + llvm::Function* getDivFunc(llvm::Type* _type); + llvm::Function* getExpFunc(); + llvm::Function* getAddModFunc(); + llvm::Function* getMulModFunc(); + + llvm::Function* m_mul = nullptr; + llvm::Function* m_mul512 = nullptr; + llvm::Function* m_div = nullptr; + llvm::Function* m_div512 = nullptr; + llvm::Function* m_exp = nullptr; + llvm::Function* m_addmod = nullptr; + llvm::Function* m_mulmod = nullptr; + llvm::Function* m_debug = nullptr; +}; + + +} +} +} diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp new file mode 100644 index 000000000..c9e71be9a --- /dev/null +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -0,0 +1,381 @@ +#include "BasicBlock.h" + +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +static const char* jumpDestName = "JmpDst."; +static const char* basicBlockName = "Instr."; + +BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : + m_firstInstrIdx{_firstInstrIdx}, + m_begin(_begin), + m_end(_end), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), + m_stack(*this), + m_builder(_builder), + m_isJumpDest(isJumpDest) +{} + +BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), + m_stack(*this), + m_builder(_builder), + m_isJumpDest(isJumpDest) +{} + +BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : + m_bblock(_owner) +{} + +void BasicBlock::LocalStack::push(llvm::Value* _value) +{ + assert(_value->getType() == Type::Word); + m_bblock.m_currentStack.push_back(_value); + m_bblock.m_tosOffset += 1; +} + +llvm::Value* BasicBlock::LocalStack::pop() +{ + auto result = get(0); + + if (m_bblock.m_currentStack.size() > 0) + m_bblock.m_currentStack.pop_back(); + + m_bblock.m_tosOffset -= 1; + return result; +} + +/** + * Pushes a copy of _index-th element (tos is 0-th elem). + */ +void BasicBlock::LocalStack::dup(size_t _index) +{ + auto val = get(_index); + push(val); +} + +/** + * Swaps tos with _index-th element (tos is 0-th elem). + * _index must be > 0. + */ +void BasicBlock::LocalStack::swap(size_t _index) +{ + assert(_index > 0); + auto val = get(_index); + auto tos = get(0); + set(_index, tos); + set(0, val); +} + +std::vector::iterator BasicBlock::LocalStack::getItemIterator(size_t _index) +{ + auto& currentStack = m_bblock.m_currentStack; + if (_index < currentStack.size()) + return currentStack.end() - _index - 1; + + // Need to map more elements from the EVM stack + auto nNewItems = 1 + _index - currentStack.size(); + currentStack.insert(currentStack.begin(), nNewItems, nullptr); + + return currentStack.end() - _index - 1; +} + +llvm::Value* BasicBlock::LocalStack::get(size_t _index) +{ + auto& initialStack = m_bblock.m_initialStack; + auto itemIter = getItemIterator(_index); + + if (*itemIter == nullptr) + { + // Need to fetch a new item from the EVM stack + assert(static_cast(_index) >= m_bblock.m_tosOffset); + size_t initialIdx = _index - m_bblock.m_tosOffset; + if (initialIdx >= initialStack.size()) + { + auto nNewItems = 1 + initialIdx - initialStack.size(); + initialStack.insert(initialStack.end(), nNewItems, nullptr); + } + + assert(initialStack[initialIdx] == nullptr); + // Create a dummy value. + std::string name = "get_" + std::to_string(_index); + initialStack[initialIdx] = m_bblock.m_builder.CreatePHI(Type::Word, 0, std::move(name)); + *itemIter = initialStack[initialIdx]; + } + + return *itemIter; +} + +void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) +{ + auto itemIter = getItemIterator(_index); + *itemIter = _word; +} + + + + + +void BasicBlock::synchronizeLocalStack(Stack& _evmStack) +{ + auto blockTerminator = m_llvmBB->getTerminator(); + assert(blockTerminator != nullptr); + m_builder.SetInsertPoint(blockTerminator); + + auto currIter = m_currentStack.begin(); + auto endIter = m_currentStack.end(); + + // Update (emit set()) changed values + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; + currIter < endIter && idx >= 0; + ++currIter, --idx) + { + assert(static_cast(idx) < m_initialStack.size()); + if (*currIter != m_initialStack[idx]) // value needs update + _evmStack.set(static_cast(idx), *currIter); + } + + if (m_tosOffset < 0) + { + // Pop values + _evmStack.pop(static_cast(-m_tosOffset)); + } + + // Push new values + for (; currIter < endIter; ++currIter) + { + assert(*currIter != nullptr); + _evmStack.push(*currIter); + } + + // Emit get() for all (used) values from the initial stack + for (size_t idx = 0; idx < m_initialStack.size(); ++idx) + { + auto val = m_initialStack[idx]; + if (val == nullptr) + continue; + + llvm::PHINode* phi = llvm::cast(val); + // Insert call to get() just before the PHI node and replace + // the uses of PHI with the uses of this new instruction. + m_builder.SetInsertPoint(phi); + auto newVal = _evmStack.get(idx); // OPT: Value may be never user but we need to check stack heigth + // It is probably a good idea to keep heigth as a local variable accesible by LLVM directly + phi->replaceAllUsesWith(newVal); + phi->eraseFromParent(); + } + + // Reset the stack + m_initialStack.erase(m_initialStack.begin(), m_initialStack.end()); + m_currentStack.erase(m_currentStack.begin(), m_currentStack.end()); + m_tosOffset = 0; +} + +void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRBuilder<>& _builder) +{ + struct BBInfo + { + BasicBlock& bblock; + std::vector predecessors; + size_t inputItems; + size_t outputItems; + std::vector phisToRewrite; + + BBInfo(BasicBlock& _bblock) : + bblock(_bblock), + predecessors(), + inputItems(0), + outputItems(0) + { + auto& initialStack = bblock.m_initialStack; + for (auto it = initialStack.begin(); + it != initialStack.end() && *it != nullptr; + ++it, ++inputItems); + + //if (bblock.localStack().m_tosOffset > 0) + // outputItems = bblock.localStack().m_tosOffset; + auto& exitStack = bblock.m_currentStack; + for (auto it = exitStack.rbegin(); + it != exitStack.rend() && *it != nullptr; + ++it, ++outputItems); + } + }; + + std::map cfg; + + // Create nodes in cfg + for (auto bb : basicBlocks) + cfg.emplace(bb->llvm(), *bb); + + // Create edges in cfg: for each bb info fill the list + // of predecessor infos. + for (auto& pair : cfg) + { + auto bb = pair.first; + auto& info = pair.second; + + for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt) + { + auto predInfoEntry = cfg.find(*predIt); + if (predInfoEntry != cfg.end()) + info.predecessors.push_back(&predInfoEntry->second); + } + } + + // Iteratively compute inputs and outputs of each block, until reaching fixpoint. + bool valuesChanged = true; + while (valuesChanged) + { + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + for (auto& pair : cfg) + std::cerr << pair.second.bblock.llvm()->getName().str() + << ": in " << pair.second.inputItems + << ", out " << pair.second.outputItems + << "\n"; + } + + valuesChanged = false; + for (auto& pair : cfg) + { + auto& info = pair.second; + + if (info.predecessors.empty()) + info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false + + for (auto predInfo : info.predecessors) + { + if (predInfo->outputItems < info.inputItems) + { + info.inputItems = predInfo->outputItems; + valuesChanged = true; + } + else if (predInfo->outputItems > info.inputItems) + { + predInfo->outputItems = info.inputItems; + valuesChanged = true; + } + } + } + } + + // Propagate values between blocks. + for (auto& entry : cfg) + { + auto& info = entry.second; + auto& bblock = info.bblock; + + llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI()); + auto phiIter = bblock.m_initialStack.begin(); + for (size_t index = 0; index < info.inputItems; ++index, ++phiIter) + { + assert(llvm::isa(*phiIter)); + auto phi = llvm::cast(*phiIter); + + for (auto predIt : info.predecessors) + { + auto& predExitStack = predIt->bblock.m_currentStack; + auto value = *(predExitStack.end() - 1 - index); + phi->addIncoming(value, predIt->bblock.llvm()); + } + + // Move phi to the front + if (llvm::BasicBlock::iterator(phi) != bblock.llvm()->begin()) + { + phi->removeFromParent(); + _builder.SetInsertPoint(bblock.llvm(), bblock.llvm()->begin()); + _builder.Insert(phi); + } + } + + // The items pulled directly from predecessors block must be removed + // from the list of items that has to be popped from the initial stack. + auto& initialStack = bblock.m_initialStack; + initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); + // Initial stack shrinks, so the size difference grows: + bblock.m_tosOffset += (int)info.inputItems; + } + + // We must account for the items that were pushed directly to successor + // blocks and thus should not be on the list of items to be pushed onto + // to EVM stack + for (auto& entry : cfg) + { + auto& info = entry.second; + auto& bblock = info.bblock; + + auto& exitStack = bblock.m_currentStack; + exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types + } +} + +void BasicBlock::dump() +{ + dump(std::cerr, false); +} + +void BasicBlock::dump(std::ostream& _out, bool _dotOutput) +{ + llvm::raw_os_ostream out(_out); + + out << (_dotOutput ? "" : "Initial stack:\n"); + for (auto val : m_initialStack) + { + if (val == nullptr) + out << " ?"; + else if (llvm::isa(val)) + out << *val; + else + out << " " << *val; + + out << (_dotOutput ? "\\l" : "\n"); + } + + out << (_dotOutput ? "| " : "Instructions:\n"); + for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) + out << *ins << (_dotOutput ? "\\l" : "\n"); + + if (! _dotOutput) + out << "Current stack (offset = " << m_tosOffset << "):\n"; + else + out << "|"; + + for (auto val = m_currentStack.rbegin(); val != m_currentStack.rend(); ++val) + { + if (*val == nullptr) + out << " ?"; + else if (llvm::isa(*val)) + out << **val; + else + out << " " << **val; + out << (_dotOutput ? "\\l" : "\n"); + } + + if (! _dotOutput) + out << " ...\n----------------------------------------\n"; +} + + + + +} +} +} + diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h new file mode 100644 index 000000000..7469b7b69 --- /dev/null +++ b/evmjit/libevmjit/BasicBlock.h @@ -0,0 +1,126 @@ +#pragma once + +#include + +#include "Common.h" +#include "Stack.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using instr_idx = uint64_t; + +class BasicBlock +{ +public: + class LocalStack + { + public: + /// Pushes value on stack + void push(llvm::Value* _value); + + /// Pops and returns top value + llvm::Value* pop(); + + /// Duplicates _index'th value on stack + void dup(size_t _index); + + /// Swaps _index'th value on stack with a value on stack top. + /// @param _index Index of value to be swaped. Must be > 0. + void swap(size_t _index); + + private: + LocalStack(BasicBlock& _owner); + LocalStack(LocalStack const&) = delete; + void operator=(LocalStack const&) = delete; + friend BasicBlock; + + /// Gets _index'th value from top (counting from 0) + llvm::Value* get(size_t _index); + + /// Sets _index'th value from top (counting from 0) + void set(size_t _index, llvm::Value* _value); + + std::vector::iterator getItemIterator(size_t _index); + + private: + BasicBlock& m_bblock; + }; + + explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + + BasicBlock(const BasicBlock&) = delete; + BasicBlock& operator=(const BasicBlock&) = delete; + + llvm::BasicBlock* llvm() { return m_llvmBB; } + + instr_idx firstInstrIdx() const { return m_firstInstrIdx; } + code_iterator begin() const { return m_begin; } + code_iterator end() const { return m_end; } + + bool isJumpDest() const { return m_isJumpDest; } + + llvm::Value* getJumpTarget() const { return m_jumpTarget; } + void setJumpTarget(llvm::Value* _jumpTarget) { m_jumpTarget = _jumpTarget; } + + LocalStack& localStack() { return m_stack; } + + /// Optimization: propagates values between local stacks in basic blocks + /// to avoid excessive pushing/popping on the EVM stack. + static void linkLocalStacks(std::vector _basicBlocks, llvm::IRBuilder<>& _builder); + + /// Synchronize current local stack with the EVM stack. + void synchronizeLocalStack(Stack& _evmStack); + + /// Prints local stack and block instructions to stderr. + /// Useful for calling in a debugger session. + void dump(); + void dump(std::ostream& os, bool _dotOutput = false); + +private: + instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block + code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block + code_iterator const m_end = {}; ///< Iterator pointing code end of the block + + llvm::BasicBlock* const m_llvmBB; + + /// Basic black state vector (stack) - current/end values and their positions on stack + /// @internal Must be AFTER m_llvmBB + LocalStack m_stack; + + llvm::IRBuilder<>& m_builder; + + /// This stack contains LLVM values that correspond to items found at + /// the EVM stack when the current basic block starts executing. + /// Location 0 corresponds to the top of the EVM stack, location 1 is + /// the item below the top and so on. The stack grows as the code + /// accesses more items on the EVM stack but once a value is put on + /// the stack, it will never be replaced. + std::vector m_initialStack; + + /// This stack tracks the contents of the EVM stack as the basic block + /// executes. It may grow on both sides, as the code pushes items on + /// top of the stack or changes existing items. + std::vector m_currentStack; + + /// How many items higher is the current stack than the initial one. + /// May be negative. + int m_tosOffset = 0; + + /// Is the basic block a valid jump destination. + /// JUMPDEST is the first instruction of the basic block. + bool const m_isJumpDest = false; + + /// If block finishes with dynamic jump target index is stored here + llvm::Value* m_jumpTarget = nullptr; +}; + +} +} +} + diff --git a/evmjit/libevmjit/BuildInfo.h.in b/evmjit/libevmjit/BuildInfo.h.in new file mode 100644 index 000000000..204b4d89b --- /dev/null +++ b/evmjit/libevmjit/BuildInfo.h.in @@ -0,0 +1,10 @@ + +#define EVMJIT_VERSION "${EVMJIT_VERSION}" +#define EVMJIT_VERSION_MAJOR ${EVMJIT_VERSION_MAJOR} +#define EVMJIT_VERSION_MINOR ${EVMJIT_VERSION_MINOR} +#define EVMJIT_VERSION_PATCH ${EVMJIT_VERSION_PATCH} +#define EVMJIT_VERSION_PRERELEASE "${EVMJIT_VERSION_PRERELEASE}" +#define EVMJIT_VERSION_FULL "${EVMJIT_VERSION_FULL}" + +#define LLVM_VERSION "${LLVM_PACKAGE_VERSION}" +#define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}" diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt new file mode 100644 index 000000000..943c64e42 --- /dev/null +++ b/evmjit/libevmjit/CMakeLists.txt @@ -0,0 +1,68 @@ +set(TARGET_NAME evmjit) + +file(GLOB SOURCES "*.cpp") +file(GLOB HEADERS "*.h") +set(INTERFACE_HEADERS interface.h) +source_group("" FILES ${HEADERS}) +source_group("" FILES ${SOURCES}) + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +endif() + + +set(EVMJIT_VERSION "0.0.0") +set(EVMJIT_VERSION_MAJOR 0) +set(EVMJIT_VERSION_MINOR 0) +set(EVMJIT_VERSION_PATCH 0) +set(EVMJIT_VERSION_FULL "v0.0.0-nogit") + +find_package(Git) +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always --match v* + OUTPUT_VARIABLE EVMJIT_VERSION_FULL OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") + string(SUBSTRING ${EVMJIT_VERSION_FULL} 1 -1 EVMJIT_VERSION_FULL) # skip "v" + string(REPLACE "-" ";" VERSION_COMPONENTS ${EVMJIT_VERSION_FULL}) + list(LENGTH VERSION_COMPONENTS NUM_VERSION_COMPONENTS) + list(GET VERSION_COMPONENTS 0 EVMJIT_VERSION) + string(REPLACE "." ";" VERSION_NUMBERS ${EVMJIT_VERSION}) + list(LENGTH VERSION_NUMBERS NUM_VERSION_NUMBERS) + list(GET VERSION_NUMBERS 0 EVMJIT_VERSION_MAJOR) + list(GET VERSION_NUMBERS 1 EVMJIT_VERSION_MINOR) + if(${NUM_VERSION_NUMBERS} GREATER 2) + list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional + endif() + if(${NUM_VERSION_COMPONENTS} GREATER 1) + list(GET VERSION_COMPONENTS 1 VERSION_PRERELEASE_CANDIDATE) + string(REGEX MATCH "^[a-zA-Z]+.*" EVMJIT_VERSION_PRERELEASE ${VERSION_PRERELEASE_CANDIDATE}) # prerelease starts with letter + endif() +endif() + +if(${EVMJIT_VERSION_MAJOR} EQUAL 0) + set(EVMJIT_SOVERSION "0.${EVMJIT_VERSION_MINOR}") +else() + set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR}) +endif() + +configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h) + +message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") + +add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h) +set_target_properties(${TARGET_NAME} PROPERTIES + VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} + FOLDER "libs") + +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) + +target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) + +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") + +install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) +#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) \ No newline at end of file diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp new file mode 100644 index 000000000..fe226eefb --- /dev/null +++ b/evmjit/libevmjit/Cache.cpp @@ -0,0 +1,120 @@ +#include "Cache.h" + +#include +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "ExecutionEngine.h" +#include "Utils.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +//#define CACHE_LOG std::cerr << "CACHE " +#define CACHE_LOG std::ostream(nullptr) + +namespace +{ + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; +} + +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) +{ + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; +} + +std::unique_ptr Cache::getObject(std::string const& id) +{ + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + CACHE_LOG << id << ": search\n"; + if (!CHECK(!g_lastObject)) + g_lastObject = nullptr; + + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs", id); + +#if defined(__GNUC__) && !defined(NDEBUG) + llvm::sys::fs::file_status st; + auto err = llvm::sys::fs::status(cachePath.str(), st); + if (err) + return nullptr; + auto mtime = st.getLastModificationTime().toEpochTime(); + + std::tm tm; + strptime(__DATE__ __TIME__, " %b %d %Y %H:%M:%S", &tm); + auto btime = (uint64_t)std::mktime(&tm); + if (btime > mtime) + return nullptr; +#endif + + if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) + g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) + std::cerr << r.getError().message(); // TODO: Add log + + if (g_lastObject) // if object found create fake module + { + CACHE_LOG << id << ": found\n"; + auto&& context = llvm::getGlobalContext(); + auto module = std::unique_ptr(new llvm::Module(id, context)); + auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); + auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); + return module; + } + CACHE_LOG << id << ": not found\n"; + return nullptr; +} + + +void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) +{ + if (g_listener) + g_listener->stateChanged(ExecState::CacheWrite); + + auto&& id = _module->getModuleIdentifier(); + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs"); + + if (llvm::sys::fs::create_directory(cachePath.str())) + return; // TODO: Add log + + llvm::sys::path::append(cachePath, id); + + CACHE_LOG << id << ": write\n"; + std::string error; + llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); + cacheFile << _object->getBuffer(); +} + +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) +{ + CACHE_LOG << _module->getModuleIdentifier() << ": use\n"; + auto o = g_lastObject; + g_lastObject = nullptr; + return o; +} + +} +} +} diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h new file mode 100644 index 000000000..e8f01d38d --- /dev/null +++ b/evmjit/libevmjit/Cache.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class ExecutionEngineListener; + +class ObjectCache : public llvm::ObjectCache +{ +public: + /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. + virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) final override; + + /// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that + /// contains the object which corresponds with Module M, or 0 if an object is + /// not available. The caller owns both the MemoryBuffer returned by this + /// and the memory it references. + virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; +}; + + +class Cache +{ +public: + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); + static std::unique_ptr getObject(std::string const& id); +}; + +} +} +} diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h new file mode 100644 index 000000000..62731292f --- /dev/null +++ b/evmjit/libevmjit/Common.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +#ifdef _MSC_VER +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using byte = uint8_t; +using bytes = std::vector; +using bytes_ref = std::tuple; +using code_iterator = byte const*; + +struct NoteChannel {}; // FIXME: Use some log library? + +enum class ReturnCode +{ + // Success codes + Stop = 0, + Return = 1, + Suicide = 2, + + // Standard error codes + OutOfGas = -1, + StackTooSmall = -2, + BadJumpDestination = -3, + BadInstruction = -4, + Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected + + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, + + UnexpectedException = -111, + + LinkerWorkaround = -299, +}; + +/// Representation of 256-bit value binary compatible with LLVM i256 +struct i256 +{ + uint64_t a = 0; + uint64_t b = 0; + uint64_t c = 0; + uint64_t d = 0; +}; +static_assert(sizeof(i256) == 32, "Wrong i265 size"); + +#define UNTESTED assert(false) + +} +} +} diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp new file mode 100644 index 000000000..de48e8ef9 --- /dev/null +++ b/evmjit/libevmjit/Compiler.cpp @@ -0,0 +1,965 @@ +#include "Compiler.h" + +#include +#include +#include +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Instruction.h" +#include "Type.h" +#include "Memory.h" +#include "Stack.h" +#include "Ext.h" +#include "GasMeter.h" +#include "Utils.h" +#include "Endianness.h" +#include "Arith256.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Compiler::Compiler(Options const& _options): + m_options(_options), + m_builder(llvm::getGlobalContext()) +{ + Type::init(m_builder.getContext()); +} + +void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd) +{ + /// Helper function that skips push data and finds next iterator (can be the end) + auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end) + { + static const auto push1 = static_cast(Instruction::PUSH1); + static const auto push32 = static_cast(Instruction::PUSH32); + size_t offset = 1; + if (*_curr >= push1 && *_curr <= push32) + offset += std::min(*_curr - push1 + 1, (_end - _curr) - 1); + return _curr + offset; + }; + + auto begin = _codeBegin; // begin of current block + bool nextJumpDest = false; + for (auto curr = begin, next = begin; curr != _codeEnd; curr = next) + { + next = skipPushDataAndGetNext(curr, _codeEnd); + + bool isEnd = false; + switch (Instruction(*curr)) + { + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::RETURN: + case Instruction::STOP: + case Instruction::SUICIDE: + isEnd = true; + break; + + case Instruction::JUMPDEST: + nextJumpDest = true; + break; + + default: + break; + } + + assert(next <= _codeEnd); + if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) + isEnd = true; + + if (isEnd) + { + auto beginIdx = begin - _codeBegin; + m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), + std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest)); + nextJumpDest = false; + begin = next; + } + } +} + +llvm::BasicBlock* Compiler::getJumpTableBlock() +{ + if (!m_jumpTableBlock) + { + m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true)); + InsertPointGuard g{m_builder}; + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + auto dest = m_builder.CreatePHI(Type::Word, 8, "target"); + auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); + for (auto&& p : m_basicBlocks) + { + if (p.second.isJumpDest()) + switchInstr->addCase(Constant::get(p.first), p.second.llvm()); + } + } + return m_jumpTableBlock->llvm(); +} + +llvm::BasicBlock* Compiler::getBadJumpBlock() +{ + if (!m_badJumpBlock) + { + m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true)); + InsertPointGuard g{m_builder}; + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + } + return m_badJumpBlock->llvm(); +} + +std::unique_ptr Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) +{ + auto compilationStartTime = std::chrono::high_resolution_clock::now(); + auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); + + // Create main function + auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false); + m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); + m_mainFunc->getArgumentList().front().setName("rt"); + + // Create entry basic block + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); + m_builder.SetInsertPoint(entryBlock); + + auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words"); + auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress); + auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); + m_builder.CreateStore(fp, jmpBufWords); + auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); + auto sp = m_builder.CreateCall(stacksave, "sp"); + auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); + m_builder.CreateStore(sp, jmpBufSp); + auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf"); + auto r = m_builder.CreateCall(setjmp, jmpBuf); + auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); + + createBasicBlocks(_begin, _end); + + // Init runtime structures. + RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end); + GasMeter gasMeter(m_builder, runtimeManager); + Memory memory(runtimeManager, gasMeter); + Ext ext(runtimeManager, memory); + Stack stack(m_builder, runtimeManager); + Arith256 arith(m_builder); + + // TODO: Create Stop basic block on demand + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); + + auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); + auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); + + for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) + { + auto& basicBlock = basicBlockPairIt->second; + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + } + + // Code for special blocks: + // TODO: move to separate function. + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + + m_builder.SetInsertPoint(abortBB); + m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + + removeDeadBlocks(); + + // Link jump table target index + if (m_jumpTableBlock) + { + auto phi = llvm::cast(&m_jumpTableBlock->llvm()->getInstList().front()); + for (auto predIt = llvm::pred_begin(m_jumpTableBlock->llvm()); predIt != llvm::pred_end(m_jumpTableBlock->llvm()); ++predIt) + { + BasicBlock* pred = nullptr; + for (auto&& p : m_basicBlocks) + { + if (p.second.llvm() == *predIt) + { + pred = &p.second; + break; + } + } + + phi->addIncoming(pred->getJumpTarget(), pred->llvm()); + } + } + + dumpCFGifRequired("blocks-init.dot"); + + if (m_options.optimizeStack) + { + std::vector blockList; + for (auto& entry : m_basicBlocks) + blockList.push_back(&entry.second); + + if (m_jumpTableBlock) + blockList.push_back(m_jumpTableBlock.get()); + + BasicBlock::linkLocalStacks(blockList, m_builder); + + dumpCFGifRequired("blocks-opt.dot"); + } + + for (auto& entry : m_basicBlocks) + entry.second.synchronizeLocalStack(stack); + if (m_jumpTableBlock) + m_jumpTableBlock->synchronizeLocalStack(stack); + + dumpCFGifRequired("blocks-sync.dot"); + + if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) + { + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); + } + + auto compilationEndTime = std::chrono::high_resolution_clock::now(); + clog(JIT) << "JIT: " << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count(); + return module; +} + + +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager, + Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) +{ + if (!_nextBasicBlock) // this is the last block in the code + _nextBasicBlock = m_stopBB; + + m_builder.SetInsertPoint(_basicBlock.llvm()); + auto& stack = _basicBlock.localStack(); + + for (auto it = _basicBlock.begin(); it != _basicBlock.end(); ++it) + { + auto inst = Instruction(*it); + + _gasMeter.count(inst); + + switch (inst) + { + + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::MUL: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.mul(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::DIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.div(lhs, rhs); + stack.push(res.first); + break; + } + + case Instruction::SDIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.sdiv(lhs, rhs); + stack.push(res.first); + break; + } + + case Instruction::MOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.div(lhs, rhs); + stack.push(res.second); + break; + } + + case Instruction::SMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.sdiv(lhs, rhs); + stack.push(res.second); + break; + } + + case Instruction::EXP: + { + auto base = stack.pop(); + auto exponent = stack.pop(); + _gasMeter.countExp(exponent); + auto ret = _arith.exp(base, exponent); + stack.push(ret); + break; + } + + case Instruction::NOT: + { + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); + stack.push(ret); + break; + } + + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::ISZERO: + { + auto top = stack.pop(); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::Word); + stack.push(result); + break; + } + + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::BYTE: + { + const auto byteNum = stack.pop(); + auto value = stack.pop(); + + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto safeByteNum = m_builder.CreateZExt(m_builder.CreateTrunc(byteNum, m_builder.getIntNTy(5)), Type::lowPrecision); // Trim index, large values can crash + auto byte = m_builder.CreateExtractElement(bytes, safeByteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::Word); + + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); + stack.push(value); + break; + } + + case Instruction::ADDMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.addmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::MULMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.mulmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::SIGNEXTEND: + { + auto idx = stack.pop(); + auto word = stack.pop(); + + auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32"); + auto k32 = m_builder.CreateZExt(k32_, Type::lowPrecision); + auto k32x8 = m_builder.CreateMul(k32, m_builder.getInt64(8), "kx8"); + + // test for word >> (k * 8 + 7) + auto bitpos = m_builder.CreateAdd(k32x8, m_builder.getInt64(7), "bitpos"); + auto bitposEx = m_builder.CreateZExt(bitpos, Type::Word); + auto bittester = m_builder.CreateShl(Constant::get(1), bitposEx); + auto bitresult = m_builder.CreateAnd(word, bittester); + auto bittest = m_builder.CreateICmpUGT(bitresult, Constant::get(0)); + // FIXME: The following does not work - LLVM bug, report! + //auto bitval = m_builder.CreateLShr(word, bitpos, "bitval"); + //auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest"); + + auto mask_ = m_builder.CreateShl(Constant::get(1), bitposEx); + auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); + + auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::Word), "negmask"); + auto val1 = m_builder.CreateOr(word, negmask); + auto val0 = m_builder.CreateAnd(word, mask); + + auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::Word, 30)); + auto result = m_builder.CreateSelect(kInRange, + m_builder.CreateSelect(bittest, val1, val0), + word); + stack.push(result); + break; + } + + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + _memory.require(inOff, inSize); + _gasMeter.countSha3Data(inSize); + auto hash = _ext.sha3(inOff, inSize); + stack.push(hash); + break; + } + + case Instruction::POP: + { + auto val = stack.pop(); + static_cast(val); + // Generate a dummy use of val to make sure that a get(0) will be emitted at this point, + // so that StackTooSmall will be thrown + // m_builder.CreateICmpEQ(val, val, "dummy"); + break; + } + + case Instruction::ANY_PUSH: + { + auto value = readPushData(it, _basicBlock.end()); + stack.push(Constant::get(value)); + break; + } + + case Instruction::ANY_DUP: + { + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + stack.dup(index); + break; + } + + case Instruction::ANY_SWAP: + { + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } + + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = _memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = _memory.getSize(); + stack.push(word); + break; + } + + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = _ext.sload(index); + stack.push(value); + break; + } + + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + _gasMeter.countSStore(_ext, index, value); + _ext.sstore(index, value); + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + { + llvm::BasicBlock* targetBlock = nullptr; + auto target = stack.pop(); + if (auto constant = llvm::dyn_cast(target)) + { + auto&& c = constant->getValue(); + auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1; + auto it = m_basicBlocks.find(targetIdx); + targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(); + } + + // TODO: Improve; check for constants + if (inst == Instruction::JUMP) + { + if (targetBlock) + { + m_builder.CreateBr(targetBlock); + } + else + { + _basicBlock.setJumpTarget(target); + m_builder.CreateBr(getJumpTableBlock()); + } + } + else // JUMPI + { + auto val = stack.pop(); + auto zero = Constant::get(0); + auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); + + if (targetBlock) + { + m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); + } + else + { + _basicBlock.setJumpTarget(target); + m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); + } + } + break; + } + + case Instruction::JUMPDEST: + { + // Nothing to do + break; + } + + case Instruction::PC: + { + auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx()); + stack.push(value); + break; + } + + case Instruction::GAS: + { + _gasMeter.commitCostBlock(); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); + break; + } + + case Instruction::ADDRESS: + case Instruction::CALLER: + case Instruction::ORIGIN: + case Instruction::CALLVALUE: + case Instruction::GASPRICE: + case Instruction::COINBASE: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + case Instruction::NUMBER: + case Instruction::TIMESTAMP: + { + // Pushes an element of runtime data on stack + auto value = _runtimeManager.get(inst); + value = m_builder.CreateZExt(value, Type::Word); + stack.push(value); + break; + } + + case Instruction::CODESIZE: + // TODO: Use constant + stack.push(_runtimeManager.getCodeSize()); + break; + + case Instruction::CALLDATASIZE: + stack.push(_runtimeManager.getCallDataSize()); + break; + + case Instruction::BLOCKHASH: + { + auto number = stack.pop(); + auto hash = _ext.blockhash(number); + stack.push(hash); + break; + } + + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = _ext.balance(address); + stack.push(value); + break; + } + + case Instruction::EXTCODESIZE: + { + auto addr = stack.pop(); + auto codeRef = _ext.extcode(addr); + stack.push(codeRef.size); + break; + } + + case Instruction::CALLDATACOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCallData(); + auto srcSize = _runtimeManager.getCallDataSize(); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 + auto srcSize = _runtimeManager.getCodeSize(); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::EXTCODECOPY: + { + auto addr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto codeRef = _ext.extcode(addr); + + _memory.copyBytes(codeRef.ptr, codeRef.size, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = _ext.calldataload(index); + stack.push(value); + break; + } + + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + _memory.require(initOff, initSize); + + _gasMeter.commitCostBlock(); + auto address = _ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } + + case Instruction::CALL: + case Instruction::CALLCODE: + { + auto callGas256 = stack.pop(); + auto codeAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + _gasMeter.commitCostBlock(); + + // Require memory for in and out buffers + _memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one + _memory.require(inOff, inSize); + + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = _runtimeManager.get(RuntimeData::Address); + + auto gas = _runtimeManager.getGas(); + _gasMeter.count(callGas256); + auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas); + auto gasLeft = m_builder.CreateNSWSub(gas, callGas); + _runtimeManager.setGas(callGas); + auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gasLeft); + stack.push(ret); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + _memory.require(index, size); + _runtimeManager.registerReturnData(index, size); + + m_builder.CreateRet(Constant::get(ReturnCode::Return)); + break; + } + + case Instruction::SUICIDE: + { + _runtimeManager.registerSuicide(stack.pop()); + m_builder.CreateRet(Constant::get(ReturnCode::Suicide)); + break; + } + + + case Instruction::STOP: + { + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + break; + } + + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + auto beginIdx = stack.pop(); + auto numBytes = stack.pop(); + _memory.require(beginIdx, numBytes); + + // This will commit the current cost block + _gasMeter.countLogData(numBytes); + + std::array topics{{}}; + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + for (size_t i = 0; i < numTopics; ++i) + topics[i] = stack.pop(); + + _ext.log(beginIdx, numBytes, topics); + break; + } + + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation + } + } + + _gasMeter.commitCostBlock(); + + // Block may have no terminator if the next instruction is a jump destination. + if (!_basicBlock.llvm()->getTerminator()) + m_builder.CreateBr(_nextBasicBlock); +} + + + +void Compiler::removeDeadBlocks() +{ + // Remove dead basic blocks + auto sthErased = false; + do + { + sthErased = false; + for (auto it = m_basicBlocks.begin(); it != m_basicBlocks.end();) + { + auto llvmBB = it->second.llvm(); + if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) + { + llvmBB->eraseFromParent(); + m_basicBlocks.erase(it++); + sthErased = true; + } + else + ++it; + } + } + while (sthErased); + + if (m_jumpTableBlock && llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } + + if (m_badJumpBlock && llvm::pred_begin(m_badJumpBlock->llvm()) == llvm::pred_end(m_badJumpBlock->llvm())) + { + m_badJumpBlock->llvm()->eraseFromParent(); + m_badJumpBlock.reset(); + } +} + +void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) +{ + if (! m_options.dumpCFG) + return; + + // TODO: handle i/o failures + std::ofstream ofs(_dotfilePath); + dumpCFGtoStream(ofs); + ofs.close(); +} + +void Compiler::dumpCFGtoStream(std::ostream& _out) +{ + _out << "digraph BB {\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; + + std::vector blocks; + for (auto& pair : m_basicBlocks) + blocks.push_back(&pair.second); + if (m_jumpTableBlock) + blocks.push_back(m_jumpTableBlock.get()); + if (m_badJumpBlock) + blocks.push_back(m_badJumpBlock.get()); + + // std::map phiNodesPerBlock; + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + std::ostringstream oss; + bb->dump(oss, true); + + _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + } + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::pred_end(bb->llvm()); + for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) + { + _out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + << "];\n"; + } + } + + _out << "}\n"; +} + +void Compiler::dump() +{ + for (auto& entry : m_basicBlocks) + entry.second.dump(); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->dump(); +} + +} +} +} + diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h new file mode 100644 index 000000000..c9795fb99 --- /dev/null +++ b/evmjit/libevmjit/Compiler.h @@ -0,0 +1,80 @@ +#pragma once + +#include "Common.h" +#include "BasicBlock.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Compiler +{ +public: + + struct Options + { + /// Optimize stack operations between basic blocks + bool optimizeStack = true; + + /// Rewrite switch instructions to sequences of branches + bool rewriteSwitchToBranches = true; + + /// Dump CFG as a .dot file for graphviz + bool dumpCFG = false; + }; + + using ProgramCounter = uint64_t; + + Compiler(Options const& _options); + + std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); + +private: + + void createBasicBlocks(code_iterator _begin, code_iterator _end); + + void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + + llvm::BasicBlock* getJumpTableBlock(); + + llvm::BasicBlock* getBadJumpBlock(); + + void removeDeadBlocks(); + + /// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled. + void dumpCFGifRequired(std::string const& _dotfilePath); + + /// Dumps basic block graph in graphviz format to a stream. + void dumpCFGtoStream(std::ostream& _out); + + /// Dumps all basic blocks to stderr. Useful in a debugging session. + void dump(); + + /// Compiler options + Options const& m_options; + + /// Helper class for generating IR + llvm::IRBuilder<> m_builder; + + /// Maps a program counter pc to a basic block that starts at pc (if any). + std::map m_basicBlocks; + + /// Stop basic block - terminates execution with STOP code (0) + llvm::BasicBlock* m_stopBB = nullptr; + + /// Block with a jump table. + std::unique_ptr m_jumpTableBlock; + + /// Destination for invalid jumps + std::unique_ptr m_badJumpBlock; + + /// Main program function + llvm::Function* m_mainFunc = nullptr; +}; + +} +} +} diff --git a/evmjit/libevmjit/CompilerHelper.cpp b/evmjit/libevmjit/CompilerHelper.cpp new file mode 100644 index 000000000..5c8ee8574 --- /dev/null +++ b/evmjit/libevmjit/CompilerHelper.cpp @@ -0,0 +1,51 @@ +#include "CompilerHelper.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : + m_builder(_builder) +{} + +llvm::Module* CompilerHelper::getModule() +{ + assert(m_builder.GetInsertBlock()); + assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function + return m_builder.GetInsertBlock()->getParent()->getParent(); +} + +llvm::Function* CompilerHelper::getMainFunction() +{ + // TODO: Rename or change semantics of getMainFunction() function + assert(m_builder.GetInsertBlock()); + auto mainFunc = m_builder.GetInsertBlock()->getParent(); + assert(mainFunc); + if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module + return mainFunc; + return nullptr; +} + +llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) +{ + return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); +} + + +RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): + CompilerHelper(_runtimeManager.getBuilder()), + m_runtimeManager(_runtimeManager) +{} + +} +} +} diff --git a/evmjit/libevmjit/CompilerHelper.h b/evmjit/libevmjit/CompilerHelper.h new file mode 100644 index 000000000..cd6d09a58 --- /dev/null +++ b/evmjit/libevmjit/CompilerHelper.h @@ -0,0 +1,79 @@ +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +/// Base class for compiler helpers like Memory, GasMeter, etc. +class CompilerHelper +{ +protected: + CompilerHelper(llvm::IRBuilder<>& _builder); + + CompilerHelper(const CompilerHelper&) = delete; + CompilerHelper& operator=(CompilerHelper) = delete; + + /// Reference to the IR module being compiled + llvm::Module* getModule(); + + /// Reference to the main module function + llvm::Function* getMainFunction(); + + /// Reference to parent compiler IR builder + llvm::IRBuilder<>& m_builder; + llvm::IRBuilder<>& getBuilder() { return m_builder; } + + llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); + + friend class RuntimeHelper; +}; + + +/// Compiler helper that depends on runtime data +class RuntimeHelper : public CompilerHelper +{ +protected: + RuntimeHelper(RuntimeManager& _runtimeManager); + + RuntimeManager& getRuntimeManager() { return m_runtimeManager; } + +private: + RuntimeManager& m_runtimeManager; +}; + + +/// Saves the insert point of the IR builder and restores it when destructed +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; +}; + +} +} +} diff --git a/evmjit/libevmjit/Endianness.cpp b/evmjit/libevmjit/Endianness.cpp new file mode 100644 index 000000000..38f71560c --- /dev/null +++ b/evmjit/libevmjit/Endianness.cpp @@ -0,0 +1,39 @@ +#include "Endianness.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + union tester + { + unsigned int x; + unsigned char isLE; + }; + + if (tester{1}.isLE) + { + // FIXME: Disabled because of problems with BYTE + //if (auto constant = llvm::dyn_cast(_word)) + // return _builder.getInt(constant->getValue().byteSwap()); + + // OPT: Cache func declaration? + auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); + return _builder.CreateCall(bswapFunc, _word); + } + return _word; +} + +} +} +} diff --git a/evmjit/libevmjit/Endianness.h b/evmjit/libevmjit/Endianness.h new file mode 100644 index 000000000..19fd8fc58 --- /dev/null +++ b/evmjit/libevmjit/Endianness.h @@ -0,0 +1,25 @@ +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Endianness +{ + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + +private: + static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +} diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..684f6d39a --- /dev/null +++ b/evmjit/libevmjit/ExecStats.cpp @@ -0,0 +1,97 @@ +#include "ExecStats.h" + +#include +#include +#include + +#include "Utils.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::stateChanged(ExecState _state) +{ + if (!CHECK(m_state != ExecState::Finished)) + return; + + auto now = clock::now(); + if (_state != ExecState::Started) + { + assert(time[(int)m_state] == ExecStats::duration::zero()); + time[(int)m_state] = now - m_tp; + } + m_state = _state; + m_tp = now; +} + +namespace +{ +struct StatsAgg +{ + using unit = std::chrono::microseconds; + ExecStats::duration tot = ExecStats::duration::zero(); + ExecStats::duration min = ExecStats::duration::max(); + ExecStats::duration max = ExecStats::duration::zero(); + size_t count = 0; + + void update(ExecStats::duration _d) + { + ++count; + tot += _d; + min = _d < min ? _d : min; + max = _d > max ? _d : max; + } + + void output(char const* _name, std::ostream& _os) + { + auto avg = tot / count; + _os << std::setfill(' ') + << std::setw(12) << std::left << _name + << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() + << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() + << std::setw(10) << std::right << std::chrono::duration_cast(min).count() + << std::setw(10) << std::right << std::chrono::duration_cast(max).count() + << std::endl; + } +}; + +char const* getExecStateName(ExecState _state) +{ + switch (_state) + { + case ExecState::Started: return "Start"; + case ExecState::CacheLoad: return "CacheLoad"; + case ExecState::CacheWrite: return "CacheWrite"; + case ExecState::Compilation: return "Compilation"; + case ExecState::CodeGen: return "CodeGen"; + case ExecState::Execution: return "Execution"; + case ExecState::Return: return "Return"; + case ExecState::Finished: return "Finish"; + } + return nullptr; +} +} + +StatsCollector::~StatsCollector() +{ + if (stats.empty()) + return; + + std::cout << " [us] total avg min max\n"; + for (int i = 0; i < (int)ExecState::Finished; ++i) + { + StatsAgg agg; + for (auto&& s : stats) + agg.update(s->time[i]); + + agg.output(getExecStateName(ExecState(i)), std::cout); + } +} + +} +} +} diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h new file mode 100644 index 000000000..498e21341 --- /dev/null +++ b/evmjit/libevmjit/ExecStats.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include "ExecutionEngine.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats : public ExecutionEngineListener +{ +public: + using clock = std::chrono::high_resolution_clock; + using duration = clock::duration; + using time_point = clock::time_point; + + std::string id; + duration time[(int)ExecState::Finished] = {}; + + void stateChanged(ExecState _state) override; + +private: + ExecState m_state = {}; + time_point m_tp = {}; + +}; + + +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector(); +}; + +} +} +} diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp new file mode 100644 index 000000000..1d2ff91b1 --- /dev/null +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -0,0 +1,153 @@ +#include "ExecutionEngine.h" + +#include +#include // env options +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "Utils.h" +#include "BuildInfo.gen.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +namespace +{ +using EntryFuncPtr = ReturnCode(*)(Runtime*); + +std::string codeHash(i256 const& _hash) +{ + static const auto size = sizeof(_hash); + static const auto hexChars = "0123456789abcdef"; + std::string str; + str.resize(size * 2); + auto outIt = str.rbegin(); // reverse for BE + auto& arr = *(std::array*)&_hash; + for (auto b : arr) + { + *(outIt++) = hexChars[b & 0xf]; + *(outIt++) = hexChars[b >> 4]; + } + return str; +} + +bool getEnvOption(char const* _name, bool _default) +{ + auto var = std::getenv(_name); + if (!var) + return _default; + return std::strtol(var, nullptr, 10) != 0; +} + +bool showInfo() +{ + auto show = getEnvOption("EVMJIT_INFO", false); + if (show) + { + std::cout << "The Ethereum EVM JIT " EVMJIT_VERSION_FULL " LLVM " LLVM_VERSION << std::endl; + } + return show; +} + +} + +ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) +{ + static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); + static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); + static auto infoShown = showInfo(); + (void) infoShown; + + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); + + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; + + static std::unique_ptr ee; + if (!ee) + { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + builder.setOptLevel(llvm::CodeGenOpt::None); + + auto triple = llvm::Triple(llvm::sys::getProcessTriple()); + if (triple.getOS() == llvm::Triple::OSType::Win32) + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + module->setTargetTriple(triple.str()); + + ee.reset(builder.create()); + if (!CHECK(ee)) + return ReturnCode::LLVMConfigError; + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + ee->setObjectCache(objectCache); + } + + static StatsCollector statsCollector; + + auto mainFuncName = codeHash(_data->codeHash); + Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + + auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + if (!entryFuncPtr) + { + auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; + if (!module) + { + listener->stateChanged(ExecState::Compilation); + assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code? + module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, mainFuncName); + } + if (debugDumpModule) + module->dump(); + + ee->addModule(module.get()); + module.release(); + listener->stateChanged(ExecState::CodeGen); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + } + if (!CHECK(entryFuncPtr)) + return ReturnCode::LLVMLinkError; + + listener->stateChanged(ExecState::Execution); + auto returnCode = entryFuncPtr(&runtime); + listener->stateChanged(ExecState::Return); + + if (returnCode == ReturnCode::Return) + { + returnData = runtime.getReturnData(); // Save reference to return data + std::swap(m_memory, runtime.getMemory()); // Take ownership of memory + } + listener->stateChanged(ExecState::Finished); + + if (statsCollectingEnabled) + statsCollector.stats.push_back(std::move(listener)); + + return returnCode; +} + +} +} +} diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h new file mode 100644 index 000000000..4c2965e58 --- /dev/null +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +enum class ExecState +{ + Started, + CacheLoad, + CacheWrite, + Compilation, + CodeGen, + Execution, + Return, + Finished +}; + +class ExecutionEngineListener +{ +public: + ExecutionEngineListener() = default; + ExecutionEngineListener(ExecutionEngineListener const&) = delete; + ExecutionEngineListener& operator=(ExecutionEngineListener) = delete; + virtual ~ExecutionEngineListener() {} + + virtual void executionStarted() {} + virtual void executionEnded() {} + + virtual void stateChanged(ExecState) {} +}; + +class ExecutionEngine +{ +public: + ExecutionEngine() = default; + ExecutionEngine(ExecutionEngine const&) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; + + EXPORT ReturnCode run(RuntimeData* _data, Env* _env); + + /// Reference to returned data (RETURN opcode used) + bytes_ref returnData; + +private: + /// After execution, if RETURN used, memory is moved there + /// to allow client copy the returned data + bytes m_memory; +}; + +} +} +} diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp new file mode 100644 index 000000000..38deef214 --- /dev/null +++ b/evmjit/libevmjit/Ext.cpp @@ -0,0 +1,192 @@ +#include "Ext.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" +#include "Memory.h" +#include "Type.h" +#include "Endianness.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): + RuntimeHelper(_runtimeManager), + m_memoryMan(_memoryMan) +{ + m_funcs = decltype(m_funcs)(); + m_argAllocas = decltype(m_argAllocas)(); + m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); +} + + +using FuncDesc = std::tuple; + +llvm::FunctionType* getFunctionType(llvm::Type* _returnType, std::initializer_list const& _argsTypes) +{ + return llvm::FunctionType::get(_returnType, llvm::ArrayRef{_argsTypes.begin(), _argsTypes.size()}, false); +} + +std::array::value> const& getEnvFuncDescs() +{ + static std::array::value> descs{{ + FuncDesc{"env_sload", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, + FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})}, + }}; + + return descs; +} + +llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) +{ + auto&& desc = getEnvFuncDescs()[static_cast(_id)]; + return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module); +} + +llvm::Value* Ext::getArgAlloca() +{ + auto& a = m_argAllocas[m_argCounter]; + if (!a) + { + InsertPointGuard g{getBuilder()}; + auto allocaIt = getMainFunction()->front().begin(); + std::advance(allocaIt, m_argCounter); // Skip already created allocas + getBuilder().SetInsertPoint(allocaIt); + a = getBuilder().CreateAlloca(Type::Word, nullptr, {"a.", std::to_string(m_argCounter)}); + } + ++m_argCounter; + return a; +} + +llvm::Value* Ext::byPtr(llvm::Value* _value) +{ + auto a = getArgAlloca(); + getBuilder().CreateStore(_value, a); + return a; +} + +llvm::CallInst* Ext::createCall(EnvFunc _funcId, std::initializer_list const& _args) +{ + auto& func = m_funcs[static_cast(_funcId)]; + if (!func) + func = createFunc(_funcId, getModule()); + + m_argCounter = 0; + return getBuilder().CreateCall(func, {_args.begin(), _args.size()}); +} + +llvm::Value* Ext::sload(llvm::Value* _index) +{ + auto ret = getArgAlloca(); + createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), byPtr(_index), ret}); // Uses native endianness + return m_builder.CreateLoad(ret); +} + +void Ext::sstore(llvm::Value* _index, llvm::Value* _value) +{ + createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), byPtr(_index), byPtr(_value)}); // Uses native endianness +} + +llvm::Value* Ext::calldataload(llvm::Value* _index) +{ + auto ret = getArgAlloca(); + createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), byPtr(_index), ret}); + ret = m_builder.CreateLoad(ret); + return Endianness::toNative(m_builder, ret); +} + +llvm::Value* Ext::balance(llvm::Value* _address) +{ + auto address = Endianness::toBE(m_builder, _address); + auto ret = getArgAlloca(); + createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), byPtr(address), ret}); + return m_builder.CreateLoad(ret); +} + +llvm::Value* Ext::blockhash(llvm::Value* _number) +{ + auto hash = getArgAlloca(); + createCall(EnvFunc::blockhash, {getRuntimeManager().getEnvPtr(), byPtr(_number), hash}); + hash = m_builder.CreateLoad(hash); + return Endianness::toNative(getBuilder(), hash); +} + +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +{ + auto ret = getArgAlloca(); + auto begin = m_memoryMan.getBytePtr(_initOff); + auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); + createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(_endowment), begin, size, ret}); + llvm::Value* address = m_builder.CreateLoad(ret); + address = Endianness::toNative(m_builder, address); + return address; +} + +llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +{ + auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); + auto inBeg = m_memoryMan.getBytePtr(_inOff); + auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); + auto outBeg = m_memoryMan.getBytePtr(_outOff); + auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); + auto codeAddress = Endianness::toBE(m_builder, _codeAddress); + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); + return m_builder.CreateZExt(ret, Type::Word, "ret"); +} + +llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) +{ + auto begin = m_memoryMan.getBytePtr(_inOff); + auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size"); + auto ret = getArgAlloca(); + createCall(EnvFunc::sha3, {begin, size, ret}); + llvm::Value* hash = m_builder.CreateLoad(ret); + hash = Endianness::toNative(m_builder, hash); + return hash; +} + +MemoryRef Ext::extcode(llvm::Value* _addr) +{ + auto addr = Endianness::toBE(m_builder, _addr); + auto code = createCall(EnvFunc::extcode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size}); + auto codeSize = m_builder.CreateLoad(m_size); + auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); + return {code, codeSize256}; +} + +void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics) +{ + auto begin = m_memoryMan.getBytePtr(_memIdx); + auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size"); + llvm::Value* args[] = {getRuntimeManager().getEnvPtr(), begin, size, getArgAlloca(), getArgAlloca(), getArgAlloca(), getArgAlloca()}; + + auto topicArgPtr = &args[3]; + for (auto&& topic : _topics) + { + if (topic) + m_builder.CreateStore(Endianness::toBE(m_builder, topic), *topicArgPtr); + else + *topicArgPtr = llvm::ConstantPointerNull::get(Type::WordPtr); + ++topicArgPtr; + } + + createCall(EnvFunc::log, {args[0], args[1], args[2], args[3], args[4], args[5], args[6]}); // TODO: use std::initializer_list<> +} + +} +} +} diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h new file mode 100644 index 000000000..1c0c0fc56 --- /dev/null +++ b/evmjit/libevmjit/Ext.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + class Memory; + +struct MemoryRef +{ + llvm::Value* ptr; + llvm::Value* size; +}; + +template +struct sizeOf +{ + static const size_t value = static_cast(_EnumT::_size); +}; + +enum class EnvFunc +{ + sload, + sstore, + sha3, + balance, + create, + call, + log, + blockhash, + extcode, + calldataload, // Helper function, not client Env interface + + _size +}; + +class Ext : public RuntimeHelper +{ +public: + Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan); + + llvm::Value* sload(llvm::Value* _index); + void sstore(llvm::Value* _index, llvm::Value* _value); + + llvm::Value* balance(llvm::Value* _address); + llvm::Value* calldataload(llvm::Value* _index); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + llvm::Value* blockhash(llvm::Value* _number); + + llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); + MemoryRef extcode(llvm::Value* _addr); + + void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics); + +private: + Memory& m_memoryMan; + + llvm::Value* m_size; + llvm::Value* m_data = nullptr; + + std::array::value> m_funcs; + std::array m_argAllocas; + size_t m_argCounter = 0; + + llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list const& _args); + llvm::Value* getArgAlloca(); + llvm::Value* byPtr(llvm::Value* _value); +}; + + +} +} +} + diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp new file mode 100644 index 000000000..ca21714e0 --- /dev/null +++ b/evmjit/libevmjit/GasMeter.cpp @@ -0,0 +1,231 @@ +#include "GasMeter.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Ext.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +namespace // Helper functions +{ + +int64_t const c_stepGas = 1; +int64_t const c_balanceGas = 20; +int64_t const c_sha3Gas = 10; +int64_t const c_sha3WordGas = 10; +int64_t const c_sloadGas = 20; +int64_t const c_sstoreSetGas = 300; +int64_t const c_sstoreResetGas = 100; +int64_t const c_sstoreRefundGas = 100; +int64_t const c_createGas = 100; +int64_t const c_createDataGas = 5; +int64_t const c_callGas = 20; +int64_t const c_expGas = 1; +int64_t const c_expByteGas = 1; +int64_t const c_memoryGas = 1; +int64_t const c_txDataZeroGas = 1; +int64_t const c_txDataNonZeroGas = 5; +int64_t const c_txGas = 500; +int64_t const c_logGas = 32; +int64_t const c_logDataGas = 1; +int64_t const c_logTopicGas = 32; +int64_t const c_copyGas = 1; + +int64_t getStepCost(Instruction inst) +{ + switch (inst) + { + default: // Assumes instruction code is valid + return c_stepGas; + + case Instruction::STOP: + case Instruction::SUICIDE: + case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() + return 0; + + case Instruction::EXP: return c_expGas; + + case Instruction::SLOAD: return c_sloadGas; + + case Instruction::SHA3: return c_sha3Gas; + + case Instruction::BALANCE: return c_balanceGas; + + case Instruction::CALL: + case Instruction::CALLCODE: return c_callGas; + + case Instruction::CREATE: return c_createGas; + + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + return c_logGas + numTopics * c_logTopicGas; + } + } +} + +} + +GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : + CompilerHelper(_builder), + m_runtimeManager(_runtimeManager) +{ + auto module = getModule(); + + llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas}; + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); + InsertPointGuard guard(m_builder); + + auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); + auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); + auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); + + auto rt = &m_gasCheckFunc->getArgumentList().front(); + rt->setName("rt"); + auto cost = rt->getNextNode(); + cost->setName("cost"); + + m_builder.SetInsertPoint(checkBB); + auto gas = m_runtimeManager.getGas(); + gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); + auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions + m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); + + m_builder.SetInsertPoint(outOfGasBB); + m_runtimeManager.abort(); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(updateBB); + m_runtimeManager.setGas(gas); + m_builder.CreateRetVoid(); +} + +void GasMeter::count(Instruction _inst) +{ + if (!m_checkCall) + { + // Create gas check call with mocked block cost at begining of current cost-block + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); + } + + m_blockCost += getStepCost(_inst); +} + +void GasMeter::count(llvm::Value* _cost) +{ + if (_cost->getType() == Type::Word) + { + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh"); + auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas); + _cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost"); + } + + assert(_cost->getType() == Type::Gas); + createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); +} + +void GasMeter::countExp(llvm::Value* _exponent) +{ + // Additional cost is 1 per significant byte of exponent + // lz - leading zeros + // cost = ((256 - lz) + 7) / 8 + + // OPT: Can gas update be done in exp algorithm? + + auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); + auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); + auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); + count(sigBytes); +} + +void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) +{ + auto oldValue = _ext.sload(_index); + auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); + auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero"); + auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero"); + auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); + auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); + auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); + auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost"); + cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost"); + count(cost); +} + +void GasMeter::countLogData(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // LOGn instruction is already counted + static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter."); + count(_dataLength); +} + +void GasMeter::countSha3Data(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // SHA3 instruction is already counted + + // TODO: This round ups to 32 happens in many places + static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); + auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas); + auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); + count(cost64); +} + +void GasMeter::giveBack(llvm::Value* _gas) +{ + assert(_gas->getType() == Type::Gas); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); +} + +void GasMeter::commitCostBlock() +{ + // If any uncommited block + if (m_checkCall) + { + if (m_blockCost == 0) // Do not check 0 + { + m_checkCall->eraseFromParent(); // Remove the gas check call + m_checkCall = nullptr; + return; + } + + m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call + m_checkCall = nullptr; // End cost-block + m_blockCost = 0; + } + assert(m_blockCost == 0); +} + +void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) +{ + static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); + count(_additionalMemoryInWords); +} + +void GasMeter::countCopy(llvm::Value* _copyWords) +{ + static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter."); + count(_copyWords); +} + +} +} +} + diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h new file mode 100644 index 000000000..4056cd64d --- /dev/null +++ b/evmjit/libevmjit/GasMeter.h @@ -0,0 +1,63 @@ +#pragma once + +#include "CompilerHelper.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class GasMeter : public CompilerHelper // TODO: Use RuntimeHelper +{ +public: + GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager); + + /// Count step cost of instruction + void count(Instruction _inst); + + /// Count additional cost + void count(llvm::Value* _cost); + + /// Calculate & count gas cost for SSTORE instruction + void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); + + /// Calculate & count additional gas cost for EXP instruction + void countExp(llvm::Value* _exponent); + + /// Count gas cost of LOG data + void countLogData(llvm::Value* _dataLength); + + /// Count gas cost of SHA3 data + void countSha3Data(llvm::Value* _dataLength); + + /// Finalize cost-block by checking gas needed for the block before the block + void commitCostBlock(); + + /// Give back an amount of gas not used by a call + void giveBack(llvm::Value* _gas); + + /// Generate code that checks the cost of additional memory used by program + void countMemory(llvm::Value* _additionalMemoryInWords); + + /// Count addional gas cost for memory copy + void countCopy(llvm::Value* _copyWords); + +private: + /// Cumulative gas cost of a block of instructions + /// @TODO Handle overflow + int64_t m_blockCost = 0; + + llvm::CallInst* m_checkCall = nullptr; + llvm::Function* m_gasCheckFunc = nullptr; + + RuntimeManager& m_runtimeManager; +}; + +} +} +} + diff --git a/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp new file mode 100644 index 000000000..f70b020f8 --- /dev/null +++ b/evmjit/libevmjit/Instruction.cpp @@ -0,0 +1,42 @@ +#include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end) +{ + auto pushInst = *_curr; + assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); + auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1; + llvm::APInt value(256, 0); + ++_curr; // Point the data + for (decltype(numBytes) i = 0; i < numBytes; ++i) + { + byte b = (_curr != _end) ? *_curr++ : 0; + value <<= 8; + value |= b; + } + --_curr; // Point the last real byte read + return value; +} + +void skipPushData(code_iterator& _curr, code_iterator _end) +{ + auto pushInst = *_curr; + assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); + auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1; + --_end; + for (decltype(numBytes) i = 0; i < numBytes && _curr < _end; ++i, ++_curr) {} +} + +} +} +} diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h new file mode 100644 index 000000000..6785213d6 --- /dev/null +++ b/evmjit/libevmjit/Instruction.h @@ -0,0 +1,239 @@ +#pragma once + +#include "Common.h" + +namespace llvm +{ + class APInt; +} + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +/// Virtual machine bytecode instruction. +enum class Instruction: uint8_t +{ + STOP = 0x00, ///< halts execution + ADD, ///< addition operation + MUL, ///< mulitplication operation + SUB, ///< subtraction operation + DIV, ///< integer division operation + SDIV, ///< signed integer division operation + MOD, ///< modulo remainder operation + SMOD, ///< signed modulo remainder operation + ADDMOD, ///< unsigned modular addition + MULMOD, ///< unsigned modular multiplication + EXP, ///< exponential operation + SIGNEXTEND, ///< extend length of signed integer + + LT = 0x10, ///< less-than comparision + GT, ///< greater-than comparision + SLT, ///< signed less-than comparision + SGT, ///< signed greater-than comparision + EQ, ///< equality comparision + ISZERO, ///< simple not operator + AND, ///< bitwise AND operation + OR, ///< bitwise OR operation + XOR, ///< bitwise XOR operation + NOT, ///< bitwise NOT opertation + BYTE, ///< retrieve single byte from word + + SHA3 = 0x20, ///< compute SHA3-256 hash + + ADDRESS = 0x30, ///< get address of currently executing account + BALANCE, ///< get balance of the given account + ORIGIN, ///< get execution origination address + CALLER, ///< get caller address + CALLVALUE, ///< get deposited value by the instruction/transaction responsible for this execution + CALLDATALOAD, ///< get input data of current environment + CALLDATASIZE, ///< get size of input data in current environment + CALLDATACOPY, ///< copy input data in current environment to memory + CODESIZE, ///< get size of code running in current environment + CODECOPY, ///< copy code running in current environment to memory + GASPRICE, ///< get price of gas in current environment + EXTCODESIZE, ///< get external code size (from another contract) + EXTCODECOPY, ///< copy external code (from another contract) + + BLOCKHASH = 0x40, ///< get hash of most recent complete block + COINBASE, ///< get the block's coinbase address + TIMESTAMP, ///< get the block's timestamp + NUMBER, ///< get the block's number + DIFFICULTY, ///< get the block's difficulty + GASLIMIT, ///< get the block's gas limit + + POP = 0x50, ///< remove item from stack + MLOAD, ///< load word from memory + MSTORE, ///< save word to memory + MSTORE8, ///< save byte to memory + SLOAD, ///< load word from storage + SSTORE, ///< save word to storage + JUMP, ///< alter the program counter + JUMPI, ///< conditionally alter the program counter + PC, ///< get the program counter + MSIZE, ///< get the size of active memory + GAS, ///< get the amount of available gas + JUMPDEST, ///< set a potential jump destination + + PUSH1 = 0x60, ///< place 1 byte item on stack + PUSH2, ///< place 2 byte item on stack + PUSH3, ///< place 3 byte item on stack + PUSH4, ///< place 4 byte item on stack + PUSH5, ///< place 5 byte item on stack + PUSH6, ///< place 6 byte item on stack + PUSH7, ///< place 7 byte item on stack + PUSH8, ///< place 8 byte item on stack + PUSH9, ///< place 9 byte item on stack + PUSH10, ///< place 10 byte item on stack + PUSH11, ///< place 11 byte item on stack + PUSH12, ///< place 12 byte item on stack + PUSH13, ///< place 13 byte item on stack + PUSH14, ///< place 14 byte item on stack + PUSH15, ///< place 15 byte item on stack + PUSH16, ///< place 16 byte item on stack + PUSH17, ///< place 17 byte item on stack + PUSH18, ///< place 18 byte item on stack + PUSH19, ///< place 19 byte item on stack + PUSH20, ///< place 20 byte item on stack + PUSH21, ///< place 21 byte item on stack + PUSH22, ///< place 22 byte item on stack + PUSH23, ///< place 23 byte item on stack + PUSH24, ///< place 24 byte item on stack + PUSH25, ///< place 25 byte item on stack + PUSH26, ///< place 26 byte item on stack + PUSH27, ///< place 27 byte item on stack + PUSH28, ///< place 28 byte item on stack + PUSH29, ///< place 29 byte item on stack + PUSH30, ///< place 30 byte item on stack + PUSH31, ///< place 31 byte item on stack + PUSH32, ///< place 32 byte item on stack + + DUP1 = 0x80, ///< copies the highest item in the stack to the top of the stack + DUP2, ///< copies the second highest item in the stack to the top of the stack + DUP3, ///< copies the third highest item in the stack to the top of the stack + DUP4, ///< copies the 4th highest item in the stack to the top of the stack + DUP5, ///< copies the 5th highest item in the stack to the top of the stack + DUP6, ///< copies the 6th highest item in the stack to the top of the stack + DUP7, ///< copies the 7th highest item in the stack to the top of the stack + DUP8, ///< copies the 8th highest item in the stack to the top of the stack + DUP9, ///< copies the 9th highest item in the stack to the top of the stack + DUP10, ///< copies the 10th highest item in the stack to the top of the stack + DUP11, ///< copies the 11th highest item in the stack to the top of the stack + DUP12, ///< copies the 12th highest item in the stack to the top of the stack + DUP13, ///< copies the 13th highest item in the stack to the top of the stack + DUP14, ///< copies the 14th highest item in the stack to the top of the stack + DUP15, ///< copies the 15th highest item in the stack to the top of the stack + DUP16, ///< copies the 16th highest item in the stack to the top of the stack + + SWAP1 = 0x90, ///< swaps the highest and second highest value on the stack + SWAP2, ///< swaps the highest and third highest value on the stack + SWAP3, ///< swaps the highest and 4th highest value on the stack + SWAP4, ///< swaps the highest and 5th highest value on the stack + SWAP5, ///< swaps the highest and 6th highest value on the stack + SWAP6, ///< swaps the highest and 7th highest value on the stack + SWAP7, ///< swaps the highest and 8th highest value on the stack + SWAP8, ///< swaps the highest and 9th highest value on the stack + SWAP9, ///< swaps the highest and 10th highest value on the stack + SWAP10, ///< swaps the highest and 11th highest value on the stack + SWAP11, ///< swaps the highest and 12th highest value on the stack + SWAP12, ///< swaps the highest and 13th highest value on the stack + SWAP13, ///< swaps the highest and 14th highest value on the stack + SWAP14, ///< swaps the highest and 15th highest value on the stack + SWAP15, ///< swaps the highest and 16th highest value on the stack + SWAP16, ///< swaps the highest and 17th highest value on the stack + + LOG0 = 0xa0, ///< Makes a log entry; no topics. + LOG1, ///< Makes a log entry; 1 topic. + LOG2, ///< Makes a log entry; 2 topics. + LOG3, ///< Makes a log entry; 3 topics. + LOG4, ///< Makes a log entry; 4 topics. + + CREATE = 0xf0, ///< create a new account with associated code + CALL, ///< message-call into an account + CALLCODE, ///< message-call with another account's code only + RETURN, ///< halt execution returning output data + SUICIDE = 0xff ///< halt execution and register account for later deletion +}; + +/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it +/// Reading out of bytecode means reading 0 +/// @param _curr is updated and points the last real byte read +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end); + +/// Skips PUSH data in pointed fragment of bytecode. +/// @param _curr is updated and points the last real byte skipped +void skipPushData(code_iterator& _curr, code_iterator _end); + +#define ANY_PUSH PUSH1: \ + case Instruction::PUSH2: \ + case Instruction::PUSH3: \ + case Instruction::PUSH4: \ + case Instruction::PUSH5: \ + case Instruction::PUSH6: \ + case Instruction::PUSH7: \ + case Instruction::PUSH8: \ + case Instruction::PUSH9: \ + case Instruction::PUSH10: \ + case Instruction::PUSH11: \ + case Instruction::PUSH12: \ + case Instruction::PUSH13: \ + case Instruction::PUSH14: \ + case Instruction::PUSH15: \ + case Instruction::PUSH16: \ + case Instruction::PUSH17: \ + case Instruction::PUSH18: \ + case Instruction::PUSH19: \ + case Instruction::PUSH20: \ + case Instruction::PUSH21: \ + case Instruction::PUSH22: \ + case Instruction::PUSH23: \ + case Instruction::PUSH24: \ + case Instruction::PUSH25: \ + case Instruction::PUSH26: \ + case Instruction::PUSH27: \ + case Instruction::PUSH28: \ + case Instruction::PUSH29: \ + case Instruction::PUSH30: \ + case Instruction::PUSH31: \ + case Instruction::PUSH32 + +#define ANY_DUP DUP1: \ + case Instruction::DUP2: \ + case Instruction::DUP3: \ + case Instruction::DUP4: \ + case Instruction::DUP5: \ + case Instruction::DUP6: \ + case Instruction::DUP7: \ + case Instruction::DUP8: \ + case Instruction::DUP9: \ + case Instruction::DUP10: \ + case Instruction::DUP11: \ + case Instruction::DUP12: \ + case Instruction::DUP13: \ + case Instruction::DUP14: \ + case Instruction::DUP15: \ + case Instruction::DUP16 + +#define ANY_SWAP SWAP1: \ + case Instruction::SWAP2: \ + case Instruction::SWAP3: \ + case Instruction::SWAP4: \ + case Instruction::SWAP5: \ + case Instruction::SWAP6: \ + case Instruction::SWAP7: \ + case Instruction::SWAP8: \ + case Instruction::SWAP9: \ + case Instruction::SWAP10: \ + case Instruction::SWAP11: \ + case Instruction::SWAP12: \ + case Instruction::SWAP13: \ + case Instruction::SWAP14: \ + case Instruction::SWAP15: \ + case Instruction::SWAP16 + +} +} +} diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp new file mode 100644 index 000000000..647c5f26a --- /dev/null +++ b/evmjit/libevmjit/Memory.cpp @@ -0,0 +1,260 @@ +#include "Memory.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" +#include "Runtime.h" +#include "GasMeter.h" +#include "Endianness.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed + m_gasMeter(_gasMeter) +{} + +llvm::Function* Memory::getRequireFunc() +{ + auto& func = m_require; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder)); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + m_gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +{ + auto isWord = _valueType == Type::Word; + + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + this->require(index, Constant::get(valueSize)); + auto ptr = getBytePtr(index); + if (isWord) + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + if (_isStore) + { + llvm::Value* value = index->getNextNode(); + value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + } + else + { + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); + m_builder.CreateRet(ret); + } + + return func; +} + +llvm::Function* Memory::getLoadWordFunc() +{ + auto& func = m_loadWord; + if (!func) + func = createFunc(false, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreWordFunc() +{ + auto& func = m_storeWord; + if (!func) + func = createFunc(true, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreByteFunc() +{ + auto& func = m_storeByte; + if (!func) + func = createFunc(true, Type::Byte, m_gasMeter); + return func; +} + + +llvm::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); +} + +llvm::Value* Memory::getData() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); +} + +llvm::Value* Memory::getSize() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); +} + +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 + return m_builder.CreateGEP(getData(), idx, "ptr"); +} + +void Memory::require(llvm::Value* _offset, llvm::Value* _size) +{ + if (auto constant = llvm::dyn_cast(_size)) + { + if (!constant->getValue()) + return; + } + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); +} + +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + require(_destMemIdx, _reqBytes); + + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas); + auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32)); + m_gasMeter.countCopy(copyWords); + + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes); + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 + auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); +} + +} +} +} + + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } +} diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h new file mode 100644 index 000000000..e8edce735 --- /dev/null +++ b/evmjit/libevmjit/Memory.h @@ -0,0 +1,49 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class GasMeter; + +class Memory : public RuntimeHelper +{ +public: + Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter); + + llvm::Value* loadWord(llvm::Value* _addr); + void storeWord(llvm::Value* _addr, llvm::Value* _word); + void storeByte(llvm::Value* _addr, llvm::Value* _byte); + llvm::Value* getData(); + llvm::Value* getSize(); + llvm::Value* getBytePtr(llvm::Value* _index); + void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, + llvm::Value* _destMemIdx, llvm::Value* _byteCount); + + /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. + void require(llvm::Value* _offset, llvm::Value* _size); + +private: + GasMeter& m_gasMeter; + + llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); + + llvm::Function* getRequireFunc(); + llvm::Function* getLoadWordFunc(); + llvm::Function* getStoreWordFunc(); + llvm::Function* getStoreByteFunc(); + + llvm::Function* m_require = nullptr; + llvm::Function* m_loadWord = nullptr; + llvm::Function* m_storeWord = nullptr; + llvm::Function* m_storeByte = nullptr; +}; + +} +} +} + diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp new file mode 100644 index 000000000..69937368c --- /dev/null +++ b/evmjit/libevmjit/Runtime.cpp @@ -0,0 +1,34 @@ +#include "Runtime.h" + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Runtime::Runtime(RuntimeData* _data, Env* _env) : + m_data(*_data), + m_env(*_env) +{} + +bytes_ref Runtime::getReturnData() const +{ + auto data = m_data.callData; + auto size = static_cast(m_data.callDataSize); + + if (data < m_memory.data() || data >= m_memory.data() + m_memory.size() || size == 0) + { + assert(size == 0); // data can be an invalid pointer only if size is 0 + m_data.callData = nullptr; + return {}; + } + + return bytes_ref{data, size}; +} + +} +} +} diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h new file mode 100644 index 000000000..82be4a0c8 --- /dev/null +++ b/evmjit/libevmjit/Runtime.h @@ -0,0 +1,40 @@ +#pragma once + +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using StackImpl = std::vector; +using MemoryImpl = bytes; + +class Runtime +{ +public: + Runtime(RuntimeData* _data, Env* _env); + + Runtime(const Runtime&) = delete; + Runtime& operator=(const Runtime&) = delete; + + StackImpl& getStack() { return m_stack; } + MemoryImpl& getMemory() { return m_memory; } + + bytes_ref getReturnData() const; + +private: + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. + byte* m_memoryData = nullptr; + i256 m_memorySize; + StackImpl m_stack; + MemoryImpl m_memory; +}; + +} +} +} diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h new file mode 100644 index 000000000..cc081cc58 --- /dev/null +++ b/evmjit/libevmjit/RuntimeData.h @@ -0,0 +1,60 @@ +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct RuntimeData +{ + enum Index + { + Gas, + GasPrice, + CallData, + CallDataSize, + Address, + Caller, + Origin, + CallValue, + CoinBase, + Difficulty, + GasLimit, + Number, + Timestamp, + Code, + CodeSize, + + SuicideDestAddress = Address, ///< Suicide balance destination address + ReturnData = CallData, ///< Return data pointer (set only in case of RETURN) + ReturnDataSize = CallDataSize, ///< Return data size (set only in case of RETURN) + }; + + int64_t gas = 0; + int64_t gasPrice = 0; + byte const* callData = nullptr; + uint64_t callDataSize = 0; + i256 address; + i256 caller; + i256 origin; + i256 callValue; + i256 coinBase; + i256 difficulty; + i256 gasLimit; + uint64_t number = 0; + int64_t timestamp = 0; + byte const* code = nullptr; + uint64_t codeSize = 0; + i256 codeHash; +}; + +/// VM Environment (ExtVM) opaque type +struct Env; + +} +} +} diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp new file mode 100644 index 000000000..0b5762fa2 --- /dev/null +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -0,0 +1,242 @@ +#include "RuntimeManager.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::StructType* RuntimeManager::getRuntimeDataType() +{ + static llvm::StructType* type = nullptr; + if (!type) + { + llvm::Type* elems[] = + { + Type::Size, // gas + Type::Size, // gasPrice + Type::BytePtr, // callData + Type::Size, // callDataSize + Type::Word, // address + Type::Word, // caller + Type::Word, // origin + Type::Word, // callValue + Type::Word, // coinBase + Type::Word, // difficulty + Type::Word, // gasLimit + Type::Size, // blockNumber + Type::Size, // blockTimestamp + Type::BytePtr, // code + Type::Size, // codeSize + }; + type = llvm::StructType::create(elems, "RuntimeData"); + } + return type; +} + +llvm::StructType* RuntimeManager::getRuntimeType() +{ + static llvm::StructType* type = nullptr; + if (!type) + { + llvm::Type* elems[] = + { + Type::RuntimeDataPtr, // data + Type::EnvPtr, // Env* + Type::BytePtr, // jmpbuf + Type::BytePtr, // memory data + Type::Word, // memory size + }; + type = llvm::StructType::create(elems, "Runtime"); + } + return type; +} + +namespace +{ +llvm::Twine getName(RuntimeData::Index _index) +{ + switch (_index) + { + default: return "data"; + case RuntimeData::Address: return "address"; + case RuntimeData::Caller: return "caller"; + case RuntimeData::Origin: return "origin"; + case RuntimeData::CallValue: return "callvalue"; + case RuntimeData::GasPrice: return "gasprice"; + case RuntimeData::CoinBase: return "coinbase"; + case RuntimeData::Difficulty: return "difficulty"; + case RuntimeData::GasLimit: return "gaslimit"; + case RuntimeData::CallData: return "callData"; + case RuntimeData::Code: return "code"; + case RuntimeData::CodeSize: return "code"; + case RuntimeData::CallDataSize: return "callDataSize"; + case RuntimeData::Gas: return "gas"; + case RuntimeData::Number: return "number"; + case RuntimeData::Timestamp: return "timestamp"; + } +} +} + +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_jmpBuf(_jmpBuf), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) +{ + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + + // save jmpBuf to be used in helper functions + auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2); + m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt"); + + // Unpack data + auto rtPtr = getRuntimePtr(); + m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); + assert(m_dataPtr->getType() == Type::RuntimeDataPtr); + m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); + assert(m_envPtr->getType() == Type::EnvPtr); +} + +llvm::Value* RuntimeManager::getRuntimePtr() +{ + // Expect first argument of a function to be a pointer to Runtime + auto func = m_builder.GetInsertBlock()->getParent(); + auto rtPtr = &func->getArgumentList().front(); + assert(rtPtr->getType() == Type::RuntimePtr); + return rtPtr; +} + +llvm::Value* RuntimeManager::getDataPtr() +{ + if (getMainFunction()) + return m_dataPtr; + + auto rtPtr = getRuntimePtr(); + auto dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); + assert(dataPtr->getType() == getRuntimeDataType()->getPointerTo()); + return dataPtr; +} + +llvm::Value* RuntimeManager::getEnvPtr() +{ + assert(getMainFunction()); // Available only in main function + return m_envPtr; +} + +llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) +{ + auto ptr = getBuilder().CreateStructGEP(getDataPtr(), _index); + assert(getRuntimeDataType()->getElementType(_index)->getPointerTo() == ptr->getType()); + return ptr; +} + +llvm::Value* RuntimeManager::get(RuntimeData::Index _index) +{ + return getBuilder().CreateLoad(getPtr(_index), getName(_index)); +} + +void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value) +{ + auto ptr = getPtr(_index); + assert(ptr->getType() == _value->getType()->getPointerTo()); + getBuilder().CreateStore(_value, ptr); +} + +void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size) +{ + auto memPtr = getBuilder().CreateStructGEP(getRuntimePtr(), 3); + auto mem = getBuilder().CreateLoad(memPtr, "memory"); + auto idx = m_builder.CreateTrunc(_offset, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 // TODO: Report bug & fix to LLVM + auto returnDataPtr = getBuilder().CreateGEP(mem, idx); + set(RuntimeData::ReturnData, returnDataPtr); + + auto size64 = getBuilder().CreateTrunc(_size, Type::Size); + set(RuntimeData::ReturnDataSize, size64); +} + +void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) +{ + set(RuntimeData::SuicideDestAddress, _balanceAddress); +} + +void RuntimeManager::abort(llvm::Value* _jmpBuf) +{ + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); +} + +llvm::Value* RuntimeManager::get(Instruction _inst) +{ + switch (_inst) + { + default: assert(false); return nullptr; + case Instruction::ADDRESS: return get(RuntimeData::Address); + case Instruction::CALLER: return get(RuntimeData::Caller); + case Instruction::ORIGIN: return get(RuntimeData::Origin); + case Instruction::CALLVALUE: return get(RuntimeData::CallValue); + case Instruction::GASPRICE: return get(RuntimeData::GasPrice); + case Instruction::COINBASE: return get(RuntimeData::CoinBase); + case Instruction::DIFFICULTY: return get(RuntimeData::Difficulty); + case Instruction::GASLIMIT: return get(RuntimeData::GasLimit); + case Instruction::NUMBER: return get(RuntimeData::Number); + case Instruction::TIMESTAMP: return get(RuntimeData::Timestamp); + } +} + +llvm::Value* RuntimeManager::getCallData() +{ + return get(RuntimeData::CallData); +} + +llvm::Value* RuntimeManager::getCode() +{ + // OPT Check what is faster + //return get(RuntimeData::Code); + return m_builder.CreateGlobalStringPtr({reinterpret_cast(m_codeBegin), static_cast(m_codeEnd - m_codeBegin)}, "code"); +} + +llvm::Value* RuntimeManager::getCodeSize() +{ + return Constant::get(m_codeEnd - m_codeBegin); +} + +llvm::Value* RuntimeManager::getCallDataSize() +{ + auto value = get(RuntimeData::CallDataSize); + assert(value->getType() == Type::Size); + return getBuilder().CreateZExt(value, Type::Word); +} + +llvm::Value* RuntimeManager::getJmpBufExt() +{ + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); +} + +llvm::Value* RuntimeManager::getGas() +{ + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; +} + +llvm::Value* RuntimeManager::getGasPtr() +{ + return getPtr(RuntimeData::Gas); +} + +void RuntimeManager::setGas(llvm::Value* _gas) +{ + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); +} + +} +} +} diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h new file mode 100644 index 000000000..30c69ec88 --- /dev/null +++ b/evmjit/libevmjit/RuntimeManager.h @@ -0,0 +1,60 @@ +#pragma once + +#include "CompilerHelper.h" +#include "Type.h" +#include "RuntimeData.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class RuntimeManager: public CompilerHelper +{ +public: + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); + + llvm::Value* getRuntimePtr(); + llvm::Value* getDataPtr(); + llvm::Value* getEnvPtr(); + + llvm::Value* get(RuntimeData::Index _index); + llvm::Value* get(Instruction _inst); + llvm::Value* getGas(); + llvm::Value* getGasPtr(); + llvm::Value* getCallData(); + llvm::Value* getCode(); + llvm::Value* getCodeSize(); + llvm::Value* getCallDataSize(); + llvm::Value* getJmpBuf() { return m_jmpBuf; } + void setGas(llvm::Value* _gas); + + void registerReturnData(llvm::Value* _index, llvm::Value* _size); + void registerSuicide(llvm::Value* _balanceAddress); + + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } + + static llvm::StructType* getRuntimeType(); + static llvm::StructType* getRuntimeDataType(); + +private: + llvm::Value* getPtr(RuntimeData::Index _index); + void set(RuntimeData::Index _index, llvm::Value* _value); + llvm::Value* getJmpBufExt(); + + llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; + llvm::Value* m_dataPtr = nullptr; + llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; +}; + +} +} +} diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp new file mode 100644 index 000000000..81a954991 --- /dev/null +++ b/evmjit/libevmjit/Stack.cpp @@ -0,0 +1,200 @@ +#include "Stack.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" +#include "Runtime.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): + CompilerHelper(_builder), + m_runtimeManager(_runtimeManager) +{ + m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg"); + + using namespace llvm; + using Linkage = GlobalValue::LinkageTypes; + + auto module = getModule(); + + llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; + m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); + + llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; + m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); +} + +llvm::Function* Stack::getPopFunc() +{ + auto& func = m_pop; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto ok = createCall(extPopFunc, {rt, index}); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Stack::getGetFunc() +{ + auto& func = m_get; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto valuePtr = createCall(extGetFunc, {rt, index}); + auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(valuePtr); + } + return func; +} + +llvm::Value* Stack::get(size_t _index) +{ + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); + return m_builder.CreateLoad(valuePtr); +} + +void Stack::set(size_t _index, llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); + m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); +} + +void Stack::pop(size_t _count) +{ + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); +} + +void Stack::push(llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); + m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg); +} + + +size_t Stack::maxStackSize = 0; + +} +} +} + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) + { + auto& stack = _rt->getStack(); + if (stack.size() < _count) + return false; + + stack.erase(stack.end() - _count, stack.end()); + return true; + } + + EXPORT void stack_push(Runtime* _rt, i256 const* _word) + { + auto& stack = _rt->getStack(); + stack.push_back(*_word); + + if (stack.size() > Stack::maxStackSize) + Stack::maxStackSize = stack.size(); + } + + EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) + { + auto& stack = _rt->getStack(); + return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; + } + + EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) + { + auto& stack = _rt->getStack(); + assert(_index < stack.size()); + if (_index >= stack.size()) + return; + + *(stack.rbegin() + _index) = *_word; + } + + EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value) + { + // It asumes all indexes are less than 2^64 + + auto index = _index->a; + if (_index->b || _index->c || _index->d) // if bigger that 2^64 + index = std::numeric_limits::max(); // set max to fill with 0 leter + + auto data = _rtData->callData; + auto size = _rtData->callDataSize; + for (auto i = 0; i < 32; ++i) + { + if (index < size) + { + o_value[i] = data[index]; + ++index; // increment only if in range + } + else + o_value[i] = 0; + } + } + +} // extern "C" + diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h new file mode 100644 index 000000000..4b6fa374f --- /dev/null +++ b/evmjit/libevmjit/Stack.h @@ -0,0 +1,44 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + llvm::Function* getPopFunc(); + llvm::Function* getGetFunc(); + + RuntimeManager& m_runtimeManager; + + llvm::Function* m_pop = nullptr; + llvm::Function* m_push; + llvm::Function* m_get = nullptr; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp new file mode 100644 index 000000000..8e2bc13fc --- /dev/null +++ b/evmjit/libevmjit/Type.cpp @@ -0,0 +1,70 @@ +#include "Type.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::IntegerType* Type::Word; +llvm::PointerType* Type::WordPtr; +llvm::IntegerType* Type::lowPrecision; +llvm::IntegerType* Type::Bool; +llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Gas; +llvm::PointerType* Type::GasPtr; +llvm::IntegerType* Type::Byte; +llvm::PointerType* Type::BytePtr; +llvm::Type* Type::Void; +llvm::IntegerType* Type::MainReturn; +llvm::PointerType* Type::EnvPtr; +llvm::PointerType* Type::RuntimeDataPtr; +llvm::PointerType* Type::RuntimePtr; +llvm::ConstantInt* Constant::gasMax; + +void Type::init(llvm::LLVMContext& _context) +{ + if (!Word) // Do init only once + { + Word = llvm::Type::getIntNTy(_context, 256); + WordPtr = Word->getPointerTo(); + lowPrecision = llvm::Type::getInt64Ty(_context); + // TODO: Size should be architecture-dependent + Bool = llvm::Type::getInt1Ty(_context); + Size = llvm::Type::getInt64Ty(_context); + Gas = Size; + GasPtr = Gas->getPointerTo(); + Byte = llvm::Type::getInt8Ty(_context); + BytePtr = Byte->getPointerTo(); + Void = llvm::Type::getVoidTy(_context); + MainReturn = llvm::Type::getInt32Ty(_context); + + EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); + RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); + RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + + Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits::max()); + } +} + +llvm::ConstantInt* Constant::get(int64_t _n) +{ + return llvm::ConstantInt::getSigned(Type::Word, _n); +} + +llvm::ConstantInt* Constant::get(llvm::APInt const& _n) +{ + return llvm::ConstantInt::get(Type::Word->getContext(), _n); +} + +llvm::ConstantInt* Constant::get(ReturnCode _returnCode) +{ + return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); +} + +} +} +} + diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h new file mode 100644 index 000000000..b8a4a09eb --- /dev/null +++ b/evmjit/libevmjit/Type.h @@ -0,0 +1,60 @@ +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Type +{ + static llvm::IntegerType* Word; + static llvm::PointerType* WordPtr; + + /// Type for doing low precision arithmetics where 256-bit precision is not supported by native target + /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required + static llvm::IntegerType* lowPrecision; + + static llvm::IntegerType* Bool; + static llvm::IntegerType* Size; + static llvm::IntegerType* Gas; + static llvm::PointerType* GasPtr; + + static llvm::IntegerType* Byte; + static llvm::PointerType* BytePtr; + + static llvm::Type* Void; + + /// Main function return type + static llvm::IntegerType* MainReturn; + + static llvm::PointerType* EnvPtr; + static llvm::PointerType* RuntimeDataPtr; + static llvm::PointerType* RuntimePtr; + + static void init(llvm::LLVMContext& _context); +}; + +struct Constant +{ + static llvm::ConstantInt* gasMax; + + /// Returns word-size constant + static llvm::ConstantInt* get(int64_t _n); + static llvm::ConstantInt* get(llvm::APInt const& _n); + + static llvm::ConstantInt* get(ReturnCode _returnCode); +}; + +} +} +} + diff --git a/evmjit/libevmjit/Utils.cpp b/evmjit/libevmjit/Utils.cpp new file mode 100644 index 000000000..bf3bf93b3 --- /dev/null +++ b/evmjit/libevmjit/Utils.cpp @@ -0,0 +1,13 @@ +#include "Utils.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + + +} +} +} diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h new file mode 100644 index 000000000..aad975f5b --- /dev/null +++ b/evmjit/libevmjit/Utils.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; + +//#define clog(CHANNEL) std::cerr +#define clog(CHANNEL) std::ostream(nullptr) + +// The same as assert, but expression is always evaluated and result returned +#define CHECK(expr) (assert(expr), expr) + +} +} +} diff --git a/evmjit/libevmjit/interface.cpp b/evmjit/libevmjit/interface.cpp new file mode 100644 index 000000000..645f3d150 --- /dev/null +++ b/evmjit/libevmjit/interface.cpp @@ -0,0 +1,40 @@ +#include "ExecutionEngine.h" + +extern "C" +{ + +using namespace dev::eth::jit; + +#ifdef _MSC_VER +#define _ALLOW_KEYWORD_MACROS +#define noexcept throw() +#endif + +EXPORT void* evmjit_create() noexcept +{ + // TODO: Make sure ExecutionEngine constructor does not throw + return new(std::nothrow) ExecutionEngine; +} + +EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept +{ + delete _engine; +} + +EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept +{ + if (!_engine || !_data) + return static_cast(ReturnCode::UnexpectedException); + + try + { + auto returnCode = _engine->run(_data, _env); + return static_cast(returnCode); + } + catch(...) + { + return static_cast(ReturnCode::UnexpectedException); + } +} + +} diff --git a/evmjit/libevmjit/interface.h b/evmjit/libevmjit/interface.h new file mode 100644 index 000000000..4f4d56610 --- /dev/null +++ b/evmjit/libevmjit/interface.h @@ -0,0 +1,13 @@ + +#ifdef __cplusplus +extern "C" { +#endif + +void* evmjit_create(); +int evmjit_run(void* _jit, void* _data, void* _env); +void evmjit_destroy(void* _jit); + + +#ifdef __cplusplus +} +#endif diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_end.h b/evmjit/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..023c8021e --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,5 @@ +#if defined(_MSC_VER) + #pragma warning(pop) +#else + #pragma GCC diagnostic pop +#endif diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_start.h b/evmjit/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..bf34ade99 --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,8 @@ +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4267 4244 4800) +#else + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + #pragma GCC diagnostic ignored "-Wconversion" +#endif From a52fc7bdd746143c2b21201692437600a905cd9c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 22:08:30 +0100 Subject: [PATCH 100/118] Icon updates. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c4731642c..6cd9c7adf 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ By Gav Wood et al, 2013, 2014, 2015. | Linux | OSX | Windows ----------|---------|-----|-------- -develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) -master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) -evmjit | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A +develop | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) +master | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) +evmjit | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A [![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) From 87e956729cd889ece16a4a65592641a5025ebf73 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 17 Feb 2015 16:21:38 +0100 Subject: [PATCH 101/118] Inline member initialisation renamed VariableDefinition class to VariableDeclarationStatement added tests --- libsolidity/AST.cpp | 22 ++++++++---- libsolidity/AST.h | 25 +++++++------ libsolidity/ASTForward.h | 2 +- libsolidity/ASTJsonConverter.cpp | 4 +-- libsolidity/ASTJsonConverter.h | 4 +-- libsolidity/ASTPrinter.cpp | 4 +-- libsolidity/ASTPrinter.h | 4 +-- libsolidity/ASTVisitor.h | 8 ++--- libsolidity/AST_accept.h | 12 +++---- libsolidity/Compiler.cpp | 16 +++++++-- libsolidity/Compiler.h | 3 +- libsolidity/ExpressionCompiler.cpp | 30 ++++++++++++++-- libsolidity/ExpressionCompiler.h | 13 ++++++- libsolidity/NameAndTypeResolver.cpp | 6 ++-- libsolidity/NameAndTypeResolver.h | 2 +- libsolidity/Parser.cpp | 47 ++++++++++++------------ libsolidity/Parser.h | 9 ++--- libsolidity/Types.cpp | 2 +- test/SolidityEndToEndTest.cpp | 55 +++++++++++++++++++++++++++++ 19 files changed, 194 insertions(+), 74 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 761427db4..a18785ae1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -77,6 +77,9 @@ void ContractDefinition::checkTypeRequirements() for (ASTPointer const& function: getDefinedFunctions()) function->checkTypeRequirements(); + for (ASTPointer const& variable: m_stateVariables) + variable->checkTypeRequirements(); + // check for hash collisions in function signatures set> hashes; for (auto const& it: getInterfaceFunctionList()) @@ -294,6 +297,12 @@ bool VariableDeclaration::isLValue() const return !isExternalFunctionParameter(); } +void VariableDeclaration::checkTypeRequirements() +{ + if (m_value) + m_value->checkTypeRequirements(); +} + bool VariableDeclaration::isExternalFunctionParameter() const { auto const* function = dynamic_cast(getScope()); @@ -390,26 +399,26 @@ void Return::checkTypeRequirements() m_expression->expectType(*m_returnParameters->getParameters().front()->getType()); } -void VariableDefinition::checkTypeRequirements() +void VariableDeclarationStatement::checkTypeRequirements() { // Variables can be declared without type (with "var"), in which case the first assignment // sets the type. // Note that assignments before the first declaration are legal because of the special scoping // rules inherited from JavaScript. - if (m_value) + if (m_variable->getValue()) { if (m_variable->getType()) - m_value->expectType(*m_variable->getType()); + m_variable->getValue()->expectType(*m_variable->getType()); else { // no type declared and no previous assignment, infer the type - m_value->checkTypeRequirements(); - TypePointer type = m_value->getType(); + m_variable->getValue()->checkTypeRequirements(); + TypePointer type = m_variable->getValue()->getType(); if (type->getCategory() == Type::Category::IntegerConstant) { auto intType = dynamic_pointer_cast(type)->getIntegerType(); if (!intType) - BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString())); + BOOST_THROW_EXCEPTION(m_variable->getValue()->createTypeError("Invalid integer constant " + type->toString())); type = intType; } else if (type->getCategory() == Type::Category::Void) @@ -418,7 +427,6 @@ void VariableDefinition::checkTypeRequirements() } } } - void Assignment::checkTypeRequirements() { m_leftHandSide->checkTypeRequirements(); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 64dac594d..c7fd068d9 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -432,14 +432,17 @@ class VariableDeclaration: public Declaration { public: VariableDeclaration(Location const& _location, ASTPointer const& _type, - ASTPointer const& _name, Visibility _visibility, - bool _isStateVar = false, bool _isIndexed = false): - Declaration(_location, _name, _visibility), m_typeName(_type), - m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} + ASTPointer const& _name, ASTPointer _value, + Visibility _visibility, + bool _isStateVar = false, bool _isIndexed = false): + Declaration(_location, _name, _visibility), + m_typeName(_type), m_value(_value), + m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; TypeName const* getTypeName() const { return m_typeName.get(); } + ASTPointer const& getValue() const { return m_value; } /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly /// declared and there is no assignment to the variable that fixes the type. @@ -447,6 +450,9 @@ public: void setType(std::shared_ptr const& _type) { m_type = _type; } virtual bool isLValue() const override; + + /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. + void checkTypeRequirements(); bool isLocalVariable() const { return !!dynamic_cast(getScope()); } bool isExternalFunctionParameter() const; bool isStateVariable() const { return m_isStateVariable; } @@ -457,6 +463,7 @@ protected: private: ASTPointer m_typeName; ///< can be empty ("var") + ASTPointer m_value; ///< the assigned value, can be missing bool m_isStateVariable; ///< Whether or not this is a contract state variable bool m_isIndexed; ///< Whether this is an indexed variable (used by events). @@ -833,22 +840,20 @@ private: * also be "var") but the actual assignment can be missing. * Examples: var a = 2; uint256 a; */ -class VariableDefinition: public Statement +class VariableDeclarationStatement: public Statement { public: - VariableDefinition(Location const& _location, ASTPointer _variable, - ASTPointer _value): - Statement(_location), m_variable(_variable), m_value(_value) {} + VariableDeclarationStatement(Location const& _location, ASTPointer _variable): + Statement(_location), m_variable(_variable) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; VariableDeclaration const& getDeclaration() const { return *m_variable; } - Expression const* getExpression() const { return m_value.get(); } + Expression const* getExpression() const { return m_variable->getValue().get(); } private: ASTPointer m_variable; - ASTPointer m_value; ///< the assigned value, can be missing }; /** diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index 0b6817e45..3a151b63e 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -63,7 +63,7 @@ class ForStatement; class Continue; class Break; class Return; -class VariableDefinition; +class VariableDeclarationStatement; class ExpressionStatement; class Expression; class Assignment; diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index 04feafe2f..c30e4ca2b 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -198,7 +198,7 @@ bool ASTJsonConverter::visit(Return const&) return true; } -bool ASTJsonConverter::visit(VariableDefinition const&) +bool ASTJsonConverter::visit(VariableDeclarationStatement const&) { addJsonNode("VariableDefinition", {}, true); return true; @@ -394,7 +394,7 @@ void ASTJsonConverter::endVisit(Return const&) goUp(); } -void ASTJsonConverter::endVisit(VariableDefinition const&) +void ASTJsonConverter::endVisit(VariableDeclarationStatement const&) { goUp(); } diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 466801e9c..30a92e66c 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -64,7 +64,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; - bool visit(VariableDefinition const& _node) override; + bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Expression const& _node) override; bool visit(Assignment const& _node) override; @@ -98,7 +98,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; - void endVisit(VariableDefinition const&) override; + void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Expression const&) override; void endVisit(Assignment const&) override; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index d380b0029..aead6abd8 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -225,7 +225,7 @@ bool ASTPrinter::visit(Return const& _node) return goDeeper(); } -bool ASTPrinter::visit(VariableDefinition const& _node) +bool ASTPrinter::visit(VariableDeclarationStatement const& _node) { writeLine("VariableDefinition"); printSourcePart(_node); @@ -469,7 +469,7 @@ void ASTPrinter::endVisit(Return const&) m_indentation--; } -void ASTPrinter::endVisit(VariableDefinition const&) +void ASTPrinter::endVisit(VariableDeclarationStatement const&) { m_indentation--; } diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index d9072aacc..7a0ef5a65 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -68,7 +68,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; - bool visit(VariableDefinition const& _node) override; + bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Expression const& _node) override; bool visit(Assignment const& _node) override; @@ -109,7 +109,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; - void endVisit(VariableDefinition const&) override; + void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Expression const&) override; void endVisit(Assignment const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index a7fa6b1cf..2ecfbe4b1 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -69,7 +69,7 @@ public: virtual bool visit(Continue&) { return true; } virtual bool visit(Break&) { return true; } virtual bool visit(Return&) { return true; } - virtual bool visit(VariableDefinition&) { return true; } + virtual bool visit(VariableDeclarationStatement&) { return true; } virtual bool visit(ExpressionStatement&) { return true; } virtual bool visit(Expression&) { return true; } virtual bool visit(Assignment&) { return true; } @@ -112,7 +112,7 @@ public: virtual void endVisit(Continue&) { } virtual void endVisit(Break&) { } virtual void endVisit(Return&) { } - virtual void endVisit(VariableDefinition&) { } + virtual void endVisit(VariableDeclarationStatement&) { } virtual void endVisit(ExpressionStatement&) { } virtual void endVisit(Expression&) { } virtual void endVisit(Assignment&) { } @@ -159,7 +159,7 @@ public: virtual bool visit(Continue const&) { return true; } virtual bool visit(Break const&) { return true; } virtual bool visit(Return const&) { return true; } - virtual bool visit(VariableDefinition const&) { return true; } + virtual bool visit(VariableDeclarationStatement const&) { return true; } virtual bool visit(ExpressionStatement const&) { return true; } virtual bool visit(Expression const&) { return true; } virtual bool visit(Assignment const&) { return true; } @@ -202,7 +202,7 @@ public: virtual void endVisit(Continue const&) { } virtual void endVisit(Break const&) { } virtual void endVisit(Return const&) { } - virtual void endVisit(VariableDefinition const&) { } + virtual void endVisit(VariableDeclarationStatement const&) { } virtual void endVisit(ExpressionStatement const&) { } virtual void endVisit(Expression const&) { } virtual void endVisit(Assignment const&) { } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index b71e103df..217a565f0 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -475,24 +475,24 @@ void ExpressionStatement::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } -void VariableDefinition::accept(ASTVisitor& _visitor) +void VariableDeclarationStatement::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) { m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); + if (m_variable->getValue()) + m_variable->getValue()->accept(_visitor); } _visitor.endVisit(*this); } -void VariableDefinition::accept(ASTConstVisitor& _visitor) const +void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) { m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); + if (m_variable->getValue()) + m_variable->getValue()->accept(_visitor); } _visitor.endVisit(*this); } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 14acc0113..f552210f4 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -73,7 +73,7 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp for (ASTPointer const& base: contract->getBaseContracts()) { ContractDefinition const* baseContract = dynamic_cast( - base->getName()->getReferencedDeclaration()); + base->getName()->getReferencedDeclaration()); solAssert(baseContract, ""); if (baseArguments.count(baseContract) == 0) baseArguments[baseContract] = &base->getArguments(); @@ -85,12 +85,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp { ContractDefinition const* base = bases[bases.size() - i]; solAssert(base, ""); + initializeStateVariables(*base); FunctionDefinition const* baseConstructor = base->getConstructor(); if (!baseConstructor) continue; solAssert(baseArguments[base], ""); appendBaseConstructorCall(*baseConstructor, *baseArguments[base]); } + initializeStateVariables(_contract); if (_contract.getConstructor()) appendConstructorCall(*_contract.getConstructor()); @@ -247,6 +249,16 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract) m_context.addStateVariable(*variable); } +void Compiler::initializeStateVariables(ContractDefinition const& _contract) +{ + for(ASTPointer const& variable: _contract.getStateVariables()) + if (variable->getValue()) + { + compileExpression(*(variable->getValue()), (variable->getValue())->getType()); + ExpressionCompiler::appendStateVariableInitialization(m_context, *variable); + } +} + bool Compiler::visit(VariableDeclaration const& _variableDeclaration) { solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration."); @@ -429,7 +441,7 @@ bool Compiler::visit(Return const& _return) return false; } -bool Compiler::visit(VariableDefinition const& _variableDefinition) +bool Compiler::visit(VariableDeclarationStatement const& _variableDefinition) { if (Expression const* expression = _variableDefinition.getExpression()) { diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 1aeaee88f..0838512ee 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -59,6 +59,7 @@ private: void appendReturnValuePacker(TypePointers const& _typeParameters); void registerStateVariables(ContractDefinition const& _contract); + void initializeStateVariables(ContractDefinition const& _contract); virtual bool visit(VariableDeclaration const& _variableDeclaration) override; virtual bool visit(FunctionDefinition const& _function) override; @@ -68,7 +69,7 @@ private: virtual bool visit(Continue const& _continue) override; virtual bool visit(Break const& _break) override; virtual bool visit(Return const& _return) override; - virtual bool visit(VariableDefinition const& _variableDefinition) override; + virtual bool visit(VariableDeclarationStatement const& _variableDefinition) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index a8bc53e0f..74dfb2b5e 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -56,6 +56,19 @@ void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, compiler.appendStateVariableAccessor(_varDecl); } +void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize) +{ + ExpressionCompiler compiler(_context, _optimize); + compiler.appendStateVariableInitialization(_varDecl); +} + +void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) +{ + m_currentLValue.fromStateVariable(_varDecl); + m_currentLValue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); + m_currentLValue.reset(); +} + bool ExpressionCompiler::visit(Assignment const& _assignment) { _assignment.getRightHandSide().accept(*this); @@ -77,7 +90,6 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) } m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); m_currentLValue.reset(); - return false; } @@ -1018,12 +1030,24 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D m_dataType = _identifier.getType(); solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); } + m_size = unsigned(m_dataType->getStorageSize()); + } else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Identifier type not supported or identifier not found.")); } +void ExpressionCompiler::LValue::fromStateVariable(VariableDeclaration const& _declaration) +{ + solAssert(m_context->isStateVariable(&_declaration), "Not a state variable."); + *m_context << m_context->getStorageLocationOfVariable(_declaration); + m_type = LValueType::Storage; + m_dataType = _declaration.getType(); + solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), + "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); + m_size = unsigned(m_dataType->getStorageSize()); +} + void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const { switch (m_type) @@ -1117,7 +1141,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co } else { - solAssert(_sourceType.getCategory() == m_dataType->getCategory(), ""); + solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "Wrong type conversation for assignment."); if (m_dataType->getCategory() == Type::Category::ByteArray) { CompilerUtils(*m_context).copyByteArrayToStorage( diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 471d81865..3567a9148 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -59,6 +59,9 @@ public: /// Appends code for a State Variable accessor function static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + /// Appends code for a State Variable Initialization function + static void appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + private: explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} @@ -111,6 +114,9 @@ private: /// Appends code for a State Variable accessor function void appendStateVariableAccessor(VariableDeclaration const& _varDecl); + /// Appends code for a State Variable initialization + void appendStateVariableInitialization(VariableDeclaration const& _varDecl); + /** * Helper class to store and retrieve lvalues to and from various locations. * All types except STACK store a reference in a slot on the stack, STACK just @@ -126,8 +132,13 @@ private: std::shared_ptr const& _dataType, unsigned _baseStackOffset = 0); /// Set type according to the declaration and retrieve the reference. - /// @a _expression is the current expression + /// @a _identifier is the current identifier void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); + + /// Set type according to the declaration and retrieve the reference. + /// @a _declaration is the variable declaration + void fromStateVariable(VariableDeclaration const& _declaration); + void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } bool isValid() const { return m_type != LValueType::None; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index e19b0bf9e..15e1ac6f5 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -267,12 +267,12 @@ void DeclarationRegistrationHelper::endVisit(ModifierDefinition&) closeCurrentScope(); } -void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefinition) +void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement) { // Register the local variables with the function // This does not fit here perfectly, but it saves us another AST visit. - solAssert(m_currentFunction, "Variable definition without function."); - m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration()); + solAssert(m_currentFunction, "Variable declaration without function."); + m_currentFunction->addLocalVariable(_variableDeclarationStatement.getDeclaration()); } bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index d9ac98ce5..63b8ab637 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -105,7 +105,7 @@ private: void endVisit(FunctionDefinition& _function) override; bool visit(ModifierDefinition& _modifier) override; void endVisit(ModifierDefinition& _modifier) override; - void endVisit(VariableDefinition& _variableDefinition) override; + void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override; bool visit(VariableDeclaration& _declaration) override; bool visit(EventDefinition& _event) override; void endVisit(EventDefinition& _event) override; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 72334c6cc..9940fb8d9 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -148,6 +148,7 @@ ASTPointer Parser::parseContractDefinition() { VarDeclParserOptions options; options.isStateVariable = true; + options.allowInitialValue = true; stateVariables.push_back(parseVariableDeclaration(options)); expectToken(Token::Semicolon); } @@ -324,9 +325,19 @@ ASTPointer Parser::parseVariableDeclaration(VarDeclParserOp } else identifier = expectIdentifierToken(); - return nodeFactory.createNode(type, identifier, - visibility, _options.isStateVariable, - isIndexed); + ASTPointer value; + if (_options.allowInitialValue) + { + if (m_scanner->getCurrentToken() == Token::Assign) + { + m_scanner->next(); + value = parseExpression(); + nodeFactory.setEndPositionFromNode(value); + } + } + return nodeFactory.createNode(type, identifier, value, + visibility, _options.isStateVariable, + isIndexed); } ASTPointer Parser::parseModifierDefinition() @@ -519,7 +530,7 @@ ASTPointer Parser::parseStatement() } // fall-through default: - statement = parseVarDefOrExprStmt(); + statement = parseVarDeclOrExprStmt(); } expectToken(Token::Semicolon); return statement; @@ -568,7 +579,7 @@ ASTPointer Parser::parseForStatement() // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? if (m_scanner->getCurrentToken() != Token::Semicolon) - initExpression = parseVarDefOrExprStmt(); + initExpression = parseVarDeclOrExprStmt(); expectToken(Token::Semicolon); if (m_scanner->getCurrentToken() != Token::Semicolon) @@ -587,30 +598,22 @@ ASTPointer Parser::parseForStatement() body); } -ASTPointer Parser::parseVarDefOrExprStmt() +ASTPointer Parser::parseVarDeclOrExprStmt() { - if (peekVariableDefinition()) - return parseVariableDefinition(); + if (peekVariableDeclarationStatement()) + return parseVariableDeclarationStatement(); else return parseExpressionStatement(); } -ASTPointer Parser::parseVariableDefinition() +ASTPointer Parser::parseVariableDeclarationStatement() { ASTNodeFactory nodeFactory(*this); VarDeclParserOptions options; options.allowVar = true; + options.allowInitialValue = true; ASTPointer variable = parseVariableDeclaration(options); - ASTPointer value; - if (m_scanner->getCurrentToken() == Token::Assign) - { - m_scanner->next(); - value = parseExpression(); - nodeFactory.setEndPositionFromNode(value); - } - else - nodeFactory.setEndPositionFromNode(variable); - return nodeFactory.createNode(variable, value); + return nodeFactory.createNode(variable); } ASTPointer Parser::parseExpressionStatement() @@ -822,11 +825,11 @@ pair>, vector>> Parser::pars } -bool Parser::peekVariableDefinition() +bool Parser::peekVariableDeclarationStatement() { - // distinguish between variable definition (and potentially assignment) and expression statement + // distinguish between variable declaration (and potentially assignment) and expression statement // (which include assignments to other expressions and pre-declared variables) - // We have a variable definition if we get a keyword that specifies a type name, or + // We have a variable declaration if we get a keyword that specifies a type name, or // in the case of a user-defined type, we have two identifiers following each other. return (m_scanner->getCurrentToken() == Token::Mapping || m_scanner->getCurrentToken() == Token::Var || diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 1bb4ea977..4034aec85 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -51,6 +51,7 @@ private: bool isStateVariable = false; bool allowIndexed = false; bool allowEmptyName = false; + bool allowInitialValue = false; }; ///@{ @@ -76,8 +77,8 @@ private: ASTPointer parseIfStatement(); ASTPointer parseWhileStatement(); ASTPointer parseForStatement(); - ASTPointer parseVarDefOrExprStmt(); - ASTPointer parseVariableDefinition(); + ASTPointer parseVarDeclOrExprStmt(); + ASTPointer parseVariableDeclarationStatement(); ASTPointer parseExpressionStatement(); ASTPointer parseExpression(); ASTPointer parseBinaryExpression(int _minPrecedence = 4); @@ -91,8 +92,8 @@ private: ///@{ ///@name Helper functions - /// Peeks ahead in the scanner to determine if a variable definition is going to follow - bool peekVariableDefinition(); + /// Peeks ahead in the scanner to determine if a variable declaration statement is going to follow + bool peekVariableDeclarationStatement(); /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index a9c480176..55dedd921 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -653,7 +653,7 @@ MemberList const& StructType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - vector> members; + MemberList::MemberMap members; for (ASTPointer const& variable: m_struct.getMembers()) members.push_back(make_pair(variable->getName(), variable->getType())); m_members.reset(new MemberList(members)); diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 8c87db2d8..1f80b1017 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2570,6 +2570,61 @@ BOOST_AUTO_TEST_CASE(constructing_enums_from_ints) BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); } +BOOST_AUTO_TEST_CASE(inline_member_init) +{ + char const* sourceCode = R"( + contract test { + function test(){ + m_b = 6; + m_c = 8; + } + uint m_a = 5; + uint m_b; + uint m_c = 7; + function get() returns (uint a, uint b, uint c){ + a = m_a; + b = m_b; + c = m_c; + } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(5, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(inline_member_init_inheritence) +{ + char const* sourceCode = R"( + contract Base { + function Base(){} + uint m_base = 5; + function getBMember() returns (uint i) { return m_base; } + } + contract Derived is Base { + function Derived(){} + uint m_derived = 6; + function getDMember() returns (uint i) { return m_derived; } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("getBMember()") == encodeArgs(5)); + BOOST_CHECK(callContractFunction("getDMember()") == encodeArgs(6)); +} + +BOOST_AUTO_TEST_CASE(inline_member_init_inheritence_without_constructor) +{ + char const* sourceCode = R"( + contract Base { + uint m_base = 5; + function getBMember() returns (uint i) { return m_base; } + } + contract Derived is Base { + uint m_derived = 6; + function getDMember() returns (uint i) { return m_derived; } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("getBMember()") == encodeArgs(5)); + BOOST_CHECK(callContractFunction("getDMember()") == encodeArgs(6)); +} + BOOST_AUTO_TEST_CASE(external_function) { char const* sourceCode = R"( From 0a334cd7db9d84d3fb9efe9f64f1f0aac0fcbc64 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 20 Feb 2015 11:57:42 +0100 Subject: [PATCH 102/118] cosmetic changes --- libsolidity/Compiler.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 17 ++++++----------- libsolidity/ExpressionCompiler.h | 2 +- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index f552210f4..bdc29fab9 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -251,7 +251,7 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract) void Compiler::initializeStateVariables(ContractDefinition const& _contract) { - for(ASTPointer const& variable: _contract.getStateVariables()) + for (ASTPointer const& variable: _contract.getStateVariables()) if (variable->getValue()) { compileExpression(*(variable->getValue()), (variable->getValue())->getType()); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 74dfb2b5e..c2a10ab45 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -64,7 +64,7 @@ void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _con void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { - m_currentLValue.fromStateVariable(_varDecl); + m_currentLValue.fromVariableDeclaration(_varDecl); m_currentLValue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); m_currentLValue.reset(); } @@ -1024,22 +1024,17 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } else if (m_context->isStateVariable(&_declaration)) - { - *m_context << m_context->getStorageLocationOfVariable(_declaration); - m_type = LValueType::Storage; - m_dataType = _identifier.getType(); - solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), - "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); - } + //{ + fromVariableDeclaration(_declaration); + //} else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Identifier type not supported or identifier not found.")); } -void ExpressionCompiler::LValue::fromStateVariable(VariableDeclaration const& _declaration) +void ExpressionCompiler::LValue::fromVariableDeclaration(Declaration const& _declaration) { - solAssert(m_context->isStateVariable(&_declaration), "Not a state variable."); + //solAssert(m_context->isStateVariable(&_declaration), "Not a state variable."); *m_context << m_context->getStorageLocationOfVariable(_declaration); m_type = LValueType::Storage; m_dataType = _declaration.getType(); diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 3567a9148..a29abc7f1 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -137,7 +137,7 @@ private: /// Set type according to the declaration and retrieve the reference. /// @a _declaration is the variable declaration - void fromStateVariable(VariableDeclaration const& _declaration); + void fromVariableDeclaration(const Declaration &_declaration); void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } From d66c448d8215abf0b21d122074536eb9916263c2 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 20 Feb 2015 12:27:39 +0100 Subject: [PATCH 103/118] corrected accept for variableDeclaration changes after code review --- libsolidity/AST.h | 2 +- libsolidity/ASTPrinter.cpp | 2 +- libsolidity/AST_accept.h | 17 ++++++++--------- libsolidity/Compiler.cpp | 3 --- libsolidity/ExpressionCompiler.cpp | 13 +++++++------ 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index c7fd068d9..064457d3b 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -451,7 +451,7 @@ public: virtual bool isLValue() const override; - /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. + /// Calls checkTypeRequirments for all state variables. void checkTypeRequirements(); bool isLocalVariable() const { return !!dynamic_cast(getScope()); } bool isExternalFunctionParameter() const; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index aead6abd8..209bb73e6 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -227,7 +227,7 @@ bool ASTPrinter::visit(Return const& _node) bool ASTPrinter::visit(VariableDeclarationStatement const& _node) { - writeLine("VariableDefinition"); + writeLine("VariableDeclarationStatement"); printSourcePart(_node); return goDeeper(); } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 217a565f0..b1577ecd3 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -196,17 +196,24 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const void VariableDeclaration::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } _visitor.endVisit(*this); } void VariableDeclaration::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); - _visitor.endVisit(*this); + if (m_value) + m_value->accept(_visitor); + } } void ModifierDefinition::accept(ASTVisitor& _visitor) @@ -478,22 +485,14 @@ void ExpressionStatement::accept(ASTConstVisitor& _visitor) const void VariableDeclarationStatement::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) - { m_variable->accept(_visitor); - if (m_variable->getValue()) - m_variable->getValue()->accept(_visitor); - } _visitor.endVisit(*this); } void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) - { m_variable->accept(_visitor); - if (m_variable->getValue()) - m_variable->getValue()->accept(_visitor); - } _visitor.endVisit(*this); } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index bdc29fab9..23014da6c 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -253,10 +253,7 @@ void Compiler::initializeStateVariables(ContractDefinition const& _contract) { for (ASTPointer const& variable: _contract.getStateVariables()) if (variable->getValue()) - { - compileExpression(*(variable->getValue()), (variable->getValue())->getType()); ExpressionCompiler::appendStateVariableInitialization(m_context, *variable); - } } bool Compiler::visit(VariableDeclaration const& _variableDeclaration) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index c2a10ab45..653bf8298 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -58,15 +58,19 @@ void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize) { + compileExpression(_context, *(_varDecl.getValue()), _optimize); + if (_varDecl.getValue()->getType()) + appendTypeConversion(_context, *(_varDecl.getValue())->getType(), *(_varDecl.getValue())->getType()); + ExpressionCompiler compiler(_context, _optimize); compiler.appendStateVariableInitialization(_varDecl); } void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { - m_currentLValue.fromVariableDeclaration(_varDecl); - m_currentLValue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); - m_currentLValue.reset(); + LValue lvalue = LValue(m_context); + lvalue.fromVariableDeclaration(_varDecl); + lvalue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); } bool ExpressionCompiler::visit(Assignment const& _assignment) @@ -1024,9 +1028,7 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } else if (m_context->isStateVariable(&_declaration)) - //{ fromVariableDeclaration(_declaration); - //} else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Identifier type not supported or identifier not found.")); @@ -1034,7 +1036,6 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D void ExpressionCompiler::LValue::fromVariableDeclaration(Declaration const& _declaration) { - //solAssert(m_context->isStateVariable(&_declaration), "Not a state variable."); *m_context << m_context->getStorageLocationOfVariable(_declaration); m_type = LValueType::Storage; m_dataType = _declaration.getType(); From 29290402b433ddd495388d0c3878aeaaf17650b9 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 20 Feb 2015 20:09:46 +0100 Subject: [PATCH 104/118] renamed fromIdentifier to fromStateVariable --- libsolidity/ExpressionCompiler.cpp | 29 +++++++++++++---------------- libsolidity/ExpressionCompiler.h | 8 ++------ 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 653bf8298..e76a8a795 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -69,7 +69,7 @@ void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _con void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { LValue lvalue = LValue(m_context); - lvalue.fromVariableDeclaration(_varDecl); + lvalue.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); lvalue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); } @@ -588,7 +588,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag(); else if (dynamic_cast(declaration)) { - m_currentLValue.fromIdentifier(_identifier, *declaration); + m_currentLValue.fromDeclaration(*declaration, _identifier.getLocation()); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); } else if (dynamic_cast(declaration)) @@ -1018,32 +1018,29 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType m_size = unsigned(m_dataType->getSizeOnStack()); } -void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration) +void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration, Location const& _location) { if (m_context->isLocalVariable(&_declaration)) { m_type = LValueType::Stack; - m_dataType = _identifier.getType(); + m_dataType = _declaration.getType(); m_size = m_dataType->getSizeOnStack(); m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } else if (m_context->isStateVariable(&_declaration)) - fromVariableDeclaration(_declaration); + { + *m_context << m_context->getStorageLocationOfVariable(_declaration); + m_type = LValueType::Storage; + m_dataType = _declaration.getType(); + solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), + "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); + m_size = unsigned(m_dataType->getStorageSize()); + } else - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Identifier type not supported or identifier not found.")); } -void ExpressionCompiler::LValue::fromVariableDeclaration(Declaration const& _declaration) -{ - *m_context << m_context->getStorageLocationOfVariable(_declaration); - m_type = LValueType::Storage; - m_dataType = _declaration.getType(); - solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), - "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); -} - void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const { switch (m_type) diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index a29abc7f1..889c58b19 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -132,12 +132,8 @@ private: std::shared_ptr const& _dataType, unsigned _baseStackOffset = 0); /// Set type according to the declaration and retrieve the reference. - /// @a _identifier is the current identifier - void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); - - /// Set type according to the declaration and retrieve the reference. - /// @a _declaration is the variable declaration - void fromVariableDeclaration(const Declaration &_declaration); + /// @a _location is the current location + void fromDeclaration(Declaration const& _declaration, Location const& _location); void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } From 744ea7ac72b3f2d540f575141d779b5e83d6bed9 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 20 Feb 2015 23:04:32 +0100 Subject: [PATCH 105/118] renamed local vaiable in fromDeclaration added missing endvisit --- libsolidity/AST_accept.h | 1 + libsolidity/ExpressionCompiler.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index b1577ecd3..5bd6993db 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -214,6 +214,7 @@ void VariableDeclaration::accept(ASTConstVisitor& _visitor) const if (m_value) m_value->accept(_visitor); } + _visitor.endVisit(*this); } void ModifierDefinition::accept(ASTVisitor& _visitor) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index e76a8a795..461dfef14 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -68,9 +68,9 @@ void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _con void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { - LValue lvalue = LValue(m_context); - lvalue.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); - lvalue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); + LValue var = LValue(m_context); + var.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); + var.storeValue(*_varDecl.getType(), _varDecl.getLocation()); } bool ExpressionCompiler::visit(Assignment const& _assignment) From 1fce862e1bfda41055d2ce9e0cd6d2ece3e58fa9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 21 Feb 2015 00:12:20 +0100 Subject: [PATCH 106/118] Improvement to AZ - confirmation disabler. Fix network crash. --- alethzero/Main.ui | 12 ++++++++++++ alethzero/MainWin.cpp | 9 ++++++++- alethzero/MainWin.h | 1 + alethzero/OurWebThreeStubServer.cpp | 6 ++++++ eth/main.cpp | 4 +++- libjsqrc/ethereumjs/dist/ethereum.js | 2 +- libjsqrc/ethereumjs/dist/ethereum.js.map | 2 +- libjsqrc/ethereumjs/dist/ethereum.min.js | 2 +- libjsqrc/ethereumjs/lib/httpsync.js | 2 +- libp2p/Host.cpp | 3 +++ mix/qml/js/ProjectModel.js | 2 +- standard.js | 1 + 12 files changed, 39 insertions(+), 7 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b7c4f6c96..9025aa846 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -163,6 +163,7 @@ &Special + @@ -1652,6 +1653,17 @@ font-size: 14pt New &Transaction... + + + true + + + true + + + &NatSpec Enabled + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 00fb29e2d..f842937ca 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -201,6 +201,11 @@ Main::~Main() g_logPost = simpleDebugOut; } +bool Main::confirm() const +{ + return ui->natSpec->isChecked(); +} + void Main::on_newIdentity_triggered() { KeyPair kp = KeyPair::create(); @@ -651,6 +656,7 @@ void Main::writeSettings() s.setValue("localNetworking", ui->localNetworking->isChecked()); s.setValue("forceMining", ui->forceMining->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked()); + s.setValue("natSpec", ui->natSpec->isChecked()); s.setValue("showAll", ui->showAll->isChecked()); s.setValue("showAllAccounts", ui->showAllAccounts->isChecked()); s.setValue("clientName", ui->clientName->text()); @@ -662,7 +668,7 @@ void Main::writeSettings() s.setValue("jitvm", ui->jitvm->isChecked()); bytes d = m_webThree->saveNetwork(); - if (d.size()) + if (!d.empty()) m_networkConfig = QByteArray((char*)d.data(), (int)d.size()); s.setValue("peers", m_networkConfig); s.setValue("nameReg", ui->nameReg->text()); @@ -720,6 +726,7 @@ void Main::readSettings(bool _skipGeometry) ui->forceMining->setChecked(s.value("forceMining", false).toBool()); on_forceMining_triggered(); ui->paranoia->setChecked(s.value("paranoia", false).toBool()); + ui->natSpec->setChecked(s.value("natSpec", true).toBool()); ui->showAll->setChecked(s.value("showAll", false).toBool()); ui->showAllAccounts->setChecked(s.value("showAllAccounts", false).toBool()); ui->clientName->setText(s.value("clientName", "").toString()); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 6c4a97301..52b98d293 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -72,6 +72,7 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } + bool confirm() const; NatSpecFace* natSpec() { return &m_natSpecDB; } QVariant evalRaw(QString const& _js); diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 5b5ce420a..78b192515 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -46,6 +46,12 @@ string OurWebThreeStubServer::shh_newIdentity() bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const { + if (!m_main->confirm()) + { + cnote << "Skipping confirmation step for: " << _title << "\n" << _text; + return true; + } + int button; QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); return button == QMessageBox::Ok; diff --git a/eth/main.cpp b/eth/main.cpp index fbf47a69c..5051580a5 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -898,7 +898,9 @@ int main(int argc, char** argv) while (!g_exit) this_thread::sleep_for(chrono::milliseconds(1000)); - writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", web3.saveNetwork()); + auto netData = web3.saveNetwork(); + if (!netData.empty()) + writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData); return 0; } diff --git a/libjsqrc/ethereumjs/dist/ethereum.js b/libjsqrc/ethereumjs/dist/ethereum.js index 73b6e56ee..1662ddf91 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js +++ b/libjsqrc/ethereumjs/dist/ethereum.js @@ -1052,7 +1052,7 @@ if ("build" !== 'build') {/* var HttpSyncProvider = function (host) { this.handlers = []; - this.host = host || 'http://localhost:8080'; + this.host = host || 'http://127.0.0.1:8080'; }; HttpSyncProvider.prototype.send = function (payload) { diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map index 5bf0e8f1b..d9f613c6a 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js.map +++ b/libjsqrc/ethereumjs/dist/ethereum.js.map @@ -35,7 +35,7 @@ "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('./abi');\nvar utils = require('./utils');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, signature, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topic = [];\n o.topic.push(signature);\n if (indexed) {\n o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexed.splice(0, 1)[0];\n else\n value = notIndexed.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n args: {}\n };\n\n output.topics = output.topic; // fallback for go-ethereum\n if (!output.topic) {\n return result;\n }\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var signature = abi.eventSignatureFromAscii(events[i].name); \n if (signature === payload.topic[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\n/// Should be called to check if filter implementation is valid\n/// @returns true if it is, otherwise false\nvar implementationIsValid = function (i) {\n return !!i && \n typeof i.newFilter === 'function' && \n typeof i.getMessages === 'function' && \n typeof i.uninstallFilter === 'function' &&\n typeof i.startPolling === 'function' &&\n typeof i.stopPolling === 'function';\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n if (typeof options === 'string') {\n return options;\n } \n\n options = options || {};\n\n if (options.topics) {\n console.warn('\"topics\" is deprecated, is \"topic\" instead');\n }\n\n // evaluate lazy properties\n return {\n to: options.to,\n topic: options.topic,\n earliest: options.earliest,\n latest: options.latest,\n max: options.max,\n skip: options.skip,\n address: options.address\n };\n};\n\n/// Should be used when we want to watch something\n/// it's using inner polling mechanism and is notified about changes\n/// @param options are filter options\n/// @param implementation, an abstract polling implementation\n/// @param formatter (optional), callback function which formats output before 'real' callback \nvar filter = function(options, implementation, formatter) {\n if (!implementationIsValid(implementation)) {\n console.error('filter implemenation is invalid');\n return;\n }\n\n options = getOptions(options);\n var callbacks = [];\n var filterId = implementation.newFilter(options);\n var onMessages = function (messages) {\n messages.forEach(function (message) {\n message = formatter ? formatter(message) : message;\n callbacks.forEach(function (callback) {\n callback(message);\n });\n });\n };\n\n implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);\n\n var changed = function (callback) {\n callbacks.push(callback);\n };\n\n var messages = function () {\n return implementation.getMessages(filterId);\n };\n \n var uninstall = function (callback) {\n implementation.stopPolling(filterId);\n implementation.uninstallFilter(filterId);\n callbacks = [];\n };\n\n return {\n changed: changed,\n arrived: changed,\n happened: changed,\n messages: messages,\n logs: messages,\n uninstall: uninstall\n };\n};\n\nmodule.exports = filter;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file formatters.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar utils = require('./utils');\nvar c = require('./const');\n\n/// @param string string to be padded\n/// @param number of characters that result string should have\n/// @param sign, by default 0\n/// @returns right aligned string\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/// Formats input value to byte representation of int\n/// If value is negative, return it's two's complement\n/// If the value is floating point, round it down\n/// @returns right-aligned byte representation of int\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n if (value instanceof BigNumber || typeof value === 'number') {\n if (typeof value === 'number')\n value = new BigNumber(value);\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n value = value.round();\n\n if (value.lessThan(0)) \n value = new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(value).plus(1);\n value = value.toString(16);\n }\n else if (value.indexOf('0x') === 0)\n value = value.substr(2);\n else if (typeof value === 'string')\n value = formatInputInt(new BigNumber(value));\n else\n value = (+value).toString(16);\n return padLeft(value, padding);\n};\n\n/// Formats input value to byte representation of string\n/// @returns left-algined byte representation of string\nvar formatInputString = function (value) {\n return utils.fromAscii(value, c.ETH_PADDING).substr(2);\n};\n\n/// Formats input value to byte representation of bool\n/// @returns right-aligned byte representation bool\nvar formatInputBool = function (value) {\n return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n};\n\n/// Formats input value to byte representation of real\n/// Values are multiplied by 2^m and encoded as integers\n/// @returns byte representation of real\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); \n};\n\n\n/// Check if input value is negative\n/// @param value is hex format\n/// @returns true if it is negative, otherwise false\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/// Formats input right-aligned input bytes to int\n/// @returns right-aligned input bytes formatted to int\nvar formatOutputInt = function (value) {\n value = value || \"0\";\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/// Formats big right-aligned input bytes to uint\n/// @returns right-aligned input bytes formatted to uint\nvar formatOutputUInt = function (value) {\n value = value || \"0\";\n return new BigNumber(value, 16);\n};\n\n/// @returns input bytes formatted to real\nvar formatOutputReal = function (value) {\n return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns input bytes formatted to ureal\nvar formatOutputUReal = function (value) {\n return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns right-aligned input bytes formatted to hex\nvar formatOutputHash = function (value) {\n return \"0x\" + value;\n};\n\n/// @returns right-aligned input bytes formatted to bool\nvar formatOutputBool = function (value) {\n return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/// @returns left-aligned input bytes formatted to ascii string\nvar formatOutputString = function (value) {\n return utils.toAscii(value);\n};\n\n/// @returns right-aligned input bytes formatted to address\nvar formatOutputAddress = function (value) {\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputString: formatInputString,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputHash: formatOutputHash,\n formatOutputBool: formatOutputBool,\n formatOutputString: formatOutputString,\n formatOutputAddress: formatOutputAddress\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://localhost:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n\n var result = request.responseText;\n // check request.status\n if(request.status !== 200)\n return;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://127.0.0.1:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n\n var result = request.responseText;\n // check request.status\n if(request.status !== 200)\n return;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file jsonrpc.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar messageId = 1;\n\n/// Should be called to valid json create payload object\n/// @param method of jsonrpc call, required\n/// @param params, an array of method params, optional\n/// @returns valid jsonrpc payload object\nvar toPayload = function (method, params) {\n if (!method)\n console.error('jsonrpc method should be specified!');\n\n return {\n jsonrpc: '2.0',\n method: method,\n params: params || [],\n id: messageId++\n }; \n};\n\n/// Should be called to check if jsonrpc response is valid\n/// @returns true if response is valid, otherwise false \nvar isValidResponse = function (response) {\n return !!response &&\n !response.error &&\n response.jsonrpc === '2.0' &&\n typeof response.id === 'number' &&\n response.result !== undefined; // only undefined is not valid json object\n};\n\n/// Should be called to create batch payload object\n/// @param messages, an array of objects with method (required) and params (optional) fields\nvar toBatchPayload = function (messages) {\n return messages.map(function (message) {\n return toPayload(message.method, message.params);\n }); \n};\n\nmodule.exports = {\n toPayload: toPayload,\n isValidResponse: isValidResponse,\n toBatchPayload: toBatchPayload\n};\n\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qtsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nvar QtSyncProvider = function () {\n};\n\nQtSyncProvider.prototype.send = function (payload) {\n var result = navigator.qt.callMethod(JSON.stringify(payload));\n return JSON.parse(result);\n};\n\nmodule.exports = QtSyncProvider;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file requestmanager.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nvar jsonrpc = require('./jsonrpc');\nvar c = require('./const');\n\n/**\n * It's responsible for passing messages to providers\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 1 second\n */\nvar requestManager = function() {\n var polls = [];\n var provider;\n\n var send = function (data) {\n var payload = jsonrpc.toPayload(data.method, data.params);\n \n if (!provider) {\n console.error('provider is not set');\n return null;\n }\n\n var result = provider.send(payload);\n\n if (!jsonrpc.isValidResponse(result)) {\n console.log(result);\n return null;\n }\n \n return result.result;\n };\n\n var setProvider = function (p) {\n provider = p;\n };\n\n var startPolling = function (data, pollId, callback, uninstall) {\n polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});\n };\n\n var stopPolling = function (pollId) {\n for (var i = polls.length; i--;) {\n var poll = polls[i];\n if (poll.id === pollId) {\n polls.splice(i, 1);\n }\n }\n };\n\n var reset = function () {\n polls.forEach(function (poll) {\n poll.uninstall(poll.id); \n });\n polls = [];\n };\n\n var poll = function () {\n polls.forEach(function (data) {\n var result = send(data.data);\n if (!(result instanceof Array) || result.length === 0) {\n return;\n }\n data.callback(result);\n });\n setTimeout(poll, c.ETH_POLLING_TIMEOUT);\n };\n \n poll();\n\n return {\n send: send,\n setProvider: setProvider,\n startPolling: startPolling,\n stopPolling: stopPolling,\n reset: reset\n };\n};\n\nmodule.exports = requestManager;\n\n", diff --git a/libjsqrc/ethereumjs/dist/ethereum.min.js b/libjsqrc/ethereumjs/dist/ethereum.min.js index cbf98f363..92748f48a 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.min.js +++ b/libjsqrc/ethereumjs/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(n,e,r){function o(i,u){if(!e[i]){if(!n[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=e[i]={exports:{}};n[i][0].call(c.exports,function(t){var e=n[i][1][t];return o(e?e:t)},c,c.exports,t,n,e,r)}return e[i].exports}for(var a="function"==typeof require&&require,i=0;iv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(n.topics=n.topic,!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]); \ No newline at end of file +require=function t(n,e,r){function o(i,u){if(!e[i]){if(!n[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=e[i]={exports:{}};n[i][0].call(c.exports,function(t){var e=n[i][1][t];return o(e?e:t)},c,c.exports,t,n,e,r)}return e[i].exports}for(var a="function"==typeof require&&require,i=0;iv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(n.topics=n.topic,!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/lib/httpsync.js b/libjsqrc/ethereumjs/lib/httpsync.js index 90f3ee454..b90fa746e 100644 --- a/libjsqrc/ethereumjs/lib/httpsync.js +++ b/libjsqrc/ethereumjs/lib/httpsync.js @@ -27,7 +27,7 @@ if (process.env.NODE_ENV !== 'build') { var HttpSyncProvider = function (host) { this.handlers = []; - this.host = host || 'http://localhost:8080'; + this.host = host || 'http://127.0.0.1:8080'; }; HttpSyncProvider.prototype.send = function (payload) { diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f117df37a..fd5d2c4d8 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -630,6 +630,9 @@ void Host::disconnectLatePeers() bytes Host::saveNetwork() const { + if (!m_nodeTable) + return bytes(); + std::list peers; { RecursiveGuard l(x_sessions); diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 5a7bf4332..9ca9bae39 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -282,7 +282,7 @@ function deployProject(force) { var date = new Date(); var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); - var jsonRpcUrl = "http://localhost:8080"; + var jsonRpcUrl = "http://127.0.0.1:8080"; console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); deploymentStarted(); diff --git a/standard.js b/standard.js index 0f9cf6fa4..f51828cbe 100644 --- a/standard.js +++ b/standard.js @@ -10,6 +10,7 @@ var addrNameReg = initService("namereg"); var addrGavsino = initServiceVal("gavmble", "1000000000000000000"); var addrCoinReg = initService("coins"); var addrGavCoin = initService("coin"); + var addrRegistrar = initService("registrar"); var abiNameReg = [{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getName","outputs":[{"name":"o_name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":true,"inputs":[{"name":"_name","type":"string32"}],"name":"getAddress","outputs":[{"name":"o_owner","type":"address"}]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]}]; From 1f0791b4bcb100373145bb6e3d85208c00d19721 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 21 Feb 2015 00:48:31 +0100 Subject: [PATCH 107/118] Validation queuing. --- alethzero/MainWin.cpp | 1 + alethzero/OurWebThreeStubServer.cpp | 59 +++++++++++++++++------ alethzero/OurWebThreeStubServer.h | 20 ++++++-- libweb3jsonrpc/WebThreeStubServerBase.cpp | 34 ++++++------- libweb3jsonrpc/WebThreeStubServerBase.h | 2 +- 5 files changed, 75 insertions(+), 41 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index f842937ca..c40e8f6a0 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1167,6 +1167,7 @@ void Main::timerEvent(QTimerEvent*) interval = 0; refreshNetwork(); refreshWhispers(); + poll(); } else interval += 100; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 78b192515..da588ba3e 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -33,9 +33,11 @@ using namespace dev; using namespace dev::eth; OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, - vector const& _accounts, Main* main): - WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main) -{} + vector const& _accounts, Main* _main): + WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main) +{ + connect(_main, SIGNAL(poll()), this, SLOT(doValidations())); +} string OurWebThreeStubServer::shh_newIdentity() { @@ -44,7 +46,7 @@ string OurWebThreeStubServer::shh_newIdentity() return toJS(kp.pub()); } -bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const +bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) { if (!m_main->confirm()) { @@ -52,23 +54,30 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string return true; } - int button; - QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); - return button == QMessageBox::Ok; + QMessageBox userInput; + userInput.setText(QString::fromStdString(_title)); + userInput.setInformativeText(QString::fromStdString(_text)); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.button(QMessageBox::Ok)->setText("Allow"); + userInput.button(QMessageBox::Cancel)->setText("Reject"); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; + //QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); + //return button == QMessageBox::Ok; } -bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) const +bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) { - return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); + return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) const +bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) { return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + -", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); +", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) const +bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) { return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", "ÐApp is attempting to call into an unknown contract at address " + @@ -84,11 +93,29 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); } -bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) +void OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) +{ + Guard l(x_queued); + m_queued.push(make_pair(_t, _toProxy)); +} + +void OurWebThreeStubServer::doValidations() +{ + Guard l(x_queued); + while (!m_queued.empty()) + { + auto q = m_queued.front(); + m_queued.pop(); + if (validateTransaction(q.first, q.second)) + WebThreeStubServerBase::authenticate(q.first, q.second); + } +} + +bool OurWebThreeStubServer::validateTransaction(TransactionSkeleton const& _t, bool _toProxy) { if (_t.creation) { - // recipient has no code - nothing special about this transaction, show basic value transfer info + // show notice concerning the creation code. TODO: this needs entering into natspec. return showCreationNotice(_t, _toProxy); } @@ -116,8 +143,8 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _to (_t.value > 0 ? "In addition, ÐApp is attempting to send " + formatBalance(_t.value) + " to said recipient, with additional network fees of up to " + - formatBalance(_t.gas * _t.gasPrice) + " = " + - formatBalance(_t.value + _t.gas * _t.gasPrice) + "." + formatBalance(_t.gas * _t.gasPrice) + " = " + + formatBalance(_t.value + _t.gas * _t.gasPrice) + "." : "Additional network fees are at most" + formatBalance(_t.gas * _t.gasPrice) + ".") diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 1ab5f813c..95cf70438 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -19,7 +19,9 @@ * @date 2014 */ +#include #include +#include #include #include #include @@ -35,16 +37,24 @@ public: std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); signals: void onNewId(QString _s); +public slots: + void doValidations(); + private: - bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; - bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; - bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; - bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; + bool showAuthenticationPopup(std::string const& _title, std::string const& _text); + bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + + bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + + std::queue> m_queued; + dev::Mutex x_queued; dev::WebThreeDirect* m_web3; Main* m_main; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 3fa22a928..6ab701899 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -701,35 +701,31 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); + if (t.creation) + ret = right160(sha3(rlpList(t.from, client()->countAt(t.from))));; if (!t.from) t.from = m_accounts->getDefaultTransactAccount(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - if (!m_accounts->isRealAccount(t.from)) - { - if (m_accounts->isProxyAccount(t.from)) - if (authenticate(t, true)) - m_accounts->queueTransaction(t); - return ret; - } - if (authenticate(t, false)) - { - if (t.to) - // TODO: from qethereum, insert validification hook here. - client()->transact(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); - else - ret = toJS(client()->transact(m_accounts->secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); - client()->flushTransactions(); - } + + if (m_accounts->isRealAccount(t.from)) + authenticate(t, false); + else if (m_accounts->isProxyAccount(t.from)) + authenticate(t, true); + return ret; } -bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool) +void WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool _toProxy) { - cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; - return true; + if (_toProxy) + m_accounts->queueTransaction(_t); + else if (_t.to) + client()->transact(m_accounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); + else + client()->transact(m_accounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice); } Json::Value WebThreeStubServerBase::eth_transactionByHash(std::string const& _hash, int _i) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index ed2f09d99..9535c33a0 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -136,7 +136,7 @@ public: std::map const& ids() const { return m_ids; } protected: - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); protected: virtual dev::eth::Interface* client() = 0; From a0f0812fcbc56b69c4298bc4818070b8b9e63d81 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 21 Feb 2015 00:48:43 -0500 Subject: [PATCH 108/118] fix #1055 --- libp2p/Host.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f117df37a..f4882b47d 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -665,17 +665,20 @@ bytes Host::saveNetwork() const } } - auto state = m_nodeTable->snapshot(); - state.sort(); - for (auto const& s: state) + if (!!m_nodeTable) { - network.appendList(3); - if (s.endpoint.tcp.address().is_v4()) - network << s.endpoint.tcp.address().to_v4().to_bytes(); - else - network << s.endpoint.tcp.address().to_v6().to_bytes(); - network << s.endpoint.tcp.port() << s.id; - count++; + auto state = m_nodeTable->snapshot(); + state.sort(); + for (auto const& s: state) + { + network.appendList(3); + if (s.endpoint.tcp.address().is_v4()) + network << s.endpoint.tcp.address().to_v4().to_bytes(); + else + network << s.endpoint.tcp.address().to_v6().to_bytes(); + network << s.endpoint.tcp.port() << s.id; + count++; + } } RLPStream ret(3); From f971a7147da7159b3b83d237e3bb16d54d0e2e22 Mon Sep 17 00:00:00 2001 From: caktux Date: Sat, 21 Feb 2015 00:57:29 -0500 Subject: [PATCH 109/118] fix dependency server for windows --- extdep/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extdep/CMakeLists.txt b/extdep/CMakeLists.txt index 99f76800c..e9711754f 100644 --- a/extdep/CMakeLists.txt +++ b/extdep/CMakeLists.txt @@ -7,7 +7,7 @@ include(eth_download.cmake) # all dependencies will be installed into this directory, separated by platform string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name) set(ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/install/${_system_name}") -set(ETH_DEPENDENCY_SERVER "http://build.ethdev.com/builds/${_system_name}-precompiled") +set(ETH_DEPENDENCY_SERVER "https://build.ethdev.com/builds/${_system_name}-precompiled") file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/lib) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/include) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/bin) From 900f7053246d32efdddd8595645ac4325e4de68d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 20 Feb 2015 18:15:34 +0100 Subject: [PATCH 110/118] Adding Libraries as source units --- libsolidity/CompilerStack.cpp | 8 +++++--- libsolidity/CompilerStack.h | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index ca9c75bcd..a5cd91986 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -58,14 +58,15 @@ CompilerStack::CompilerStack(bool _addStandardSources): m_addStandardSources(_addStandardSources), m_parseSuccessful(false) { if (m_addStandardSources) - addSources(StandardSources); + addSources(StandardSources, true); // add them as libraries } -bool CompilerStack::addSource(string const& _name, string const& _content) +bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary) { bool existed = m_sources.count(_name) != 0; reset(true); m_sources[_name].scanner = make_shared(CharStream(expanded(_content)), _name); + m_sources[_name].isLibrary = _isLibrary; return existed; } @@ -328,7 +329,8 @@ void CompilerStack::resolveImports() }; for (auto const& sourcePair: m_sources) - toposort(&sourcePair.second); + if (!sourcePair.second.isLibrary) + toposort(&sourcePair.second); swap(m_sourceOrder, sourceOrder); } diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index cb4770cd3..c9642745a 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -64,8 +64,8 @@ public: /// Adds a source object (e.g. file) to the parser. After this, parse has to be called again. /// @returns true if a source object by the name already existed and was replaced. - void addSources(std::map const& _nameContents) { for (auto const& i: _nameContents) addSource(i.first, i.second); } - bool addSource(std::string const& _name, std::string const& _content); + void addSources(std::map const& _nameContents, bool _isLibrary = false) { for (auto const& i: _nameContents) addSource(i.first, i.second, _isLibrary); } + bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false); void setSource(std::string const& _sourceCode); /// Parses all source units that were added void parse(); @@ -125,7 +125,8 @@ private: std::shared_ptr scanner; std::shared_ptr ast; std::string interface; - void reset() { scanner.reset(); ast.reset(); interface.clear(); } + bool isLibrary; + void reset() { scanner.reset(); ast.reset(); interface.clear(); isLibrary = false;} }; struct Contract From ca8f786d563e2fc8060ccabdb75aa714f30bd5bc Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sat, 21 Feb 2015 16:25:28 +0100 Subject: [PATCH 111/118] Removing temporary contracts - They are now added as importable libraries --- libsolidity/CompilerStack.cpp | 55 ++--------------------------------- libsolidity/CompilerStack.h | 4 --- 2 files changed, 2 insertions(+), 57 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index a5cd91986..69dbced00 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -65,7 +65,7 @@ bool CompilerStack::addSource(string const& _name, string const& _content, bool { bool existed = m_sources.count(_name) != 0; reset(true); - m_sources[_name].scanner = make_shared(CharStream(expanded(_content)), _name); + m_sources[_name].scanner = make_shared(CharStream(_content), _name); m_sources[_name].isLibrary = _isLibrary; return existed; } @@ -73,7 +73,7 @@ bool CompilerStack::addSource(string const& _name, string const& _content, bool void CompilerStack::setSource(string const& _sourceCode) { reset(); - addSource("", expanded(_sourceCode)); + addSource("", _sourceCode); } void CompilerStack::parse() @@ -127,57 +127,6 @@ vector CompilerStack::getContractNames() const return contractNames; } -////// BEGIN: TEMPORARY ONLY -/// -/// NOTE: THIS INVALIDATES SOURCE POINTERS AND CAN CRASH THE COMPILER -/// -/// remove once import works properly and we have genesis contracts - -string CompilerStack::expanded(string const& _sourceCode) -{ - const map c_standardSources = map{ - { "Config", "contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}" }, - { "Coin", "contract Coin{function isApprovedFor(address _target,address _proxy)constant returns(bool _r){}function isApproved(address _proxy)constant returns(bool _r){}function sendCoinFrom(address _from,uint256 _val,address _to){}function coinBalanceOf(address _a)constant returns(uint256 _r){}function sendCoin(uint256 _val,address _to){}function coinBalance()constant returns(uint256 _r){}function approve(address _a){}}"}, - { "CoinReg", "contract CoinReg{function count()constant returns(uint256 r){}function info(uint256 i)constant returns(address addr,string3 name,uint256 denom){}function register(string3 name,uint256 denom){}function unregister(){}}" }, - { "coin", "#require CoinReg\ncontract coin {function coin(string3 name, uint denom) {CoinReg(Config().lookup(3)).register(name, denom);}}" }, - { "service", "#require Config\ncontract service{function service(uint _n){Config().register(_n, this);}}" }, - { "owned", "contract owned{function owned(){owner = msg.sender;}modifier onlyowner(){if(msg.sender==owner)_}address owner;}" }, - { "mortal", "#require owned\ncontract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }}" }, - { "NameReg", "contract NameReg{function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}}" }, - { "named", "#require Config NameReg\ncontract named {function named(string32 name) {NameReg(Config().lookup(1)).register(name);}}" }, - { "std", "#require owned mortal Config NameReg named" }, - }; - - string sub; - set got; - function localExpanded; - localExpanded = [&](string const& s) -> string - { - string ret = s; - for (size_t p = 0; p != string::npos;) - if ((p = ret.find("#require ")) != string::npos) - { - string n = ret.substr(p + 9, ret.find_first_of('\n', p + 9) - p - 9); - ret.replace(p, n.size() + 9, ""); - vector rs; - boost::split(rs, n, boost::is_any_of(" \t,"), boost::token_compress_on); - for (auto const& r: rs) - if (!got.count(r)) - { - if (c_standardSources.count(r)) - sub.append("\n" + localExpanded(c_standardSources.at(r)) + "\n"); - got.insert(r); - } - } - // TODO: remove once we have genesis contracts. - else if ((p = ret.find("Config()")) != string::npos) - ret.replace(p, 8, "Config(0xc6d9d2cd449a754c494264e1809c50e34d64562b)"); - return ret; - }; - return sub + localExpanded(_sourceCode); -} - -////// END: TEMPORARY ONLY void CompilerStack::compile(bool _optimize) { diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index c9642745a..87946a6b9 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -144,10 +144,6 @@ private: Contract(); }; - /// Expand source code with preprocessor-like includes. - /// @todo Replace with better framework. - std::string expanded(std::string const& _sourceCode); - void reset(bool _keepSources = false); void resolveImports(); From 11566fd3a03e39c3593d48c9f191de4cd95a5b43 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sat, 21 Feb 2015 18:55:55 +0100 Subject: [PATCH 112/118] Adding default value to isLibrary --- libsolidity/CompilerStack.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 87946a6b9..8f77ef68a 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -125,7 +125,7 @@ private: std::shared_ptr scanner; std::shared_ptr ast; std::string interface; - bool isLibrary; + bool isLibrary = false; void reset() { scanner.reset(); ast.reset(); interface.clear(); isLibrary = false;} }; From b6773a30841c307f0afb2f2abbba28f2f76728bf Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 22 Feb 2015 02:00:19 +0100 Subject: [PATCH 113/118] fixed microhttpd deployment --- alethzero/CMakeLists.txt | 2 +- cmake/EthExecutableHelper.cmake | 11 ++++++++++- cmake/FindMHD.cmake | 10 ++++++++-- third/CMakeLists.txt | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 008721518..9cb1a0ff7 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -58,5 +58,5 @@ if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")) endif() # eth_install_executable is defined in cmake/EthExecutableHelper.cmake -eth_install_executable(${EXECUTABLE}) +eth_install_executable(${EXECUTABLE} DLLS ${MHD_DLL_RELEASE}) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index c6e0210de..0c2f72946 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -56,7 +56,7 @@ macro(eth_install_executable EXECUTABLE) set (extra_macro_args ${ARGN}) set (options) set (one_value_args QMLDIR) - set (multi_value_args) + set (multi_value_args DLLS) cmake_parse_arguments (ETH_INSTALL_EXECUTABLE "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}") if (ETH_INSTALL_EXECUTABLE_QMLDIR) @@ -99,6 +99,15 @@ macro(eth_install_executable EXECUTABLE) COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM ) + + #copy additional dlls + foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS}) + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS -E copy ${dll} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" + ) + endforeach(dll) + install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin COMPONENT ${EXECUTABLE} diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake index 84875bc47..5cb8a98d6 100755 --- a/cmake/FindMHD.cmake +++ b/cmake/FindMHD.cmake @@ -29,13 +29,19 @@ set(MHD_LIBRARIES ${MHD_LIBRARY}) # boost is using the same "hack" as us with "optimized" and "debug" # official MHD project actually uses _d suffix if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + + #TODO: place dlls into CMAKE_CFG_INTDIR subfolders + string(REPLACE ".lib" ".dll" MHD_DLL_RELEASE ${MHD_LIBRARY}) + string(REPLACE "/lib/" "/bin/" MHD_DLL_RELEASE ${MHD_DLL_RELEASE}) + find_library( MHD_LIBRARY_DEBUG NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d DOC "mhd debug library" ) - - set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) + # always use release for now + #string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG}) + #set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) endif() diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt index bde47988b..989677626 100644 --- a/third/CMakeLists.txt +++ b/third/CMakeLists.txt @@ -51,5 +51,5 @@ target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} jsqrc) # eth_install_executable is defined in cmake/EthExecutableHelper.cmake -eth_install_executable(${EXECUTABLE}) +eth_install_executable(${EXECUTABLE} DLLS ${MHD_DLL_RELEASE}) From 7db97414cab65425e441410906a7f11f2ff4d34d Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 22 Feb 2015 10:11:21 +0100 Subject: [PATCH 114/118] copy dll for eth, check if qt is linked before running windeployqt --- cmake/EthExecutableHelper.cmake | 23 ++++++++++++++--------- eth/CMakeLists.txt | 4 ++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 0c2f72946..0c529881f 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -90,15 +90,20 @@ macro(eth_install_executable EXECUTABLE) " COMPONENT RUNTIME ) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - ) - #workaround for https://bugreports.qt.io/browse/QTBUG-42083 - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM - ) + + get_target_property(TARGET_LIBS ${EXECUTABLE} INTERFACE_LINK_LIBRARIES) + string(REGEX MATCH "Qt5::Core" HAVE_QT ${TARGET_LIBS}) + if ("${HAVE_QT}" STREQUAL "Qt5::Core") + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + ) + #workaround for https://bugreports.qt.io/browse/QTBUG-42083 + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD + COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM + ) + endif() #copy additional dlls foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS}) diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index ed65862a4..bc458a50f 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -28,5 +28,9 @@ endif() target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} secp256k1) +if (WIN32) + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") +endif() + install( TARGETS ${EXECUTABLE} DESTINATION bin ) From d417618dce14a58101a31471e025d18460b12daf Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 22 Feb 2015 18:38:32 +0100 Subject: [PATCH 115/118] Stack height checks and fix. --- libsolidity/Compiler.cpp | 40 +++++++++++++++++++++++++++++++---- libsolidity/Compiler.h | 2 +- libsolidity/CompilerContext.h | 2 +- libsolidity/Types.cpp | 11 ++++++++-- test/SolidityEndToEndTest.cpp | 1 - 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 23014da6c..e691394cb 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -34,6 +34,20 @@ using namespace std; namespace dev { namespace solidity { +/** + * Simple helper class to ensure that the stack height is the same at certain places in the code. + */ +class StackHeightChecker +{ +public: + StackHeightChecker(CompilerContext const& _context): + m_context(_context), stackHeight(m_context.getStackHeight()) {} + void check() { solAssert(m_context.getStackHeight() == stackHeight, "I sense a disturbance in the stack."); } +private: + CompilerContext const& m_context; + unsigned stackHeight; +}; + void Compiler::compileContract(ContractDefinition const& _contract, map const& _contracts) { @@ -340,6 +354,8 @@ bool Compiler::visit(FunctionDefinition const& _function) bool Compiler::visit(IfStatement const& _ifStatement) { + StackHeightChecker checker(m_context); + compileExpression(_ifStatement.getCondition()); eth::AssemblyItem trueTag = m_context.appendConditionalJump(); if (_ifStatement.getFalseStatement()) @@ -348,11 +364,15 @@ bool Compiler::visit(IfStatement const& _ifStatement) m_context << trueTag; _ifStatement.getTrueStatement().accept(*this); m_context << endTag; + + checker.check(); return false; } bool Compiler::visit(WhileStatement const& _whileStatement) { + StackHeightChecker checker(m_context); + eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); m_continueTags.push_back(loopStart); @@ -370,11 +390,15 @@ bool Compiler::visit(WhileStatement const& _whileStatement) m_continueTags.pop_back(); m_breakTags.pop_back(); + + checker.check(); return false; } bool Compiler::visit(ForStatement const& _forStatement) { + StackHeightChecker checker(m_context); + eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); m_continueTags.push_back(loopStart); @@ -404,6 +428,8 @@ bool Compiler::visit(ForStatement const& _forStatement) m_continueTags.pop_back(); m_breakTags.pop_back(); + + checker.check(); return false; } @@ -438,29 +464,35 @@ bool Compiler::visit(Return const& _return) return false; } -bool Compiler::visit(VariableDeclarationStatement const& _variableDefinition) +bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement) { - if (Expression const* expression = _variableDefinition.getExpression()) + StackHeightChecker checker(m_context); + if (Expression const* expression = _variableDeclarationStatement.getExpression()) { - compileExpression(*expression, _variableDefinition.getDeclaration().getType()); - CompilerUtils(m_context).moveToStackVariable(_variableDefinition.getDeclaration()); + compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType()); + CompilerUtils(m_context).moveToStackVariable(_variableDeclarationStatement.getDeclaration()); } + checker.check(); return false; } bool Compiler::visit(ExpressionStatement const& _expressionStatement) { + StackHeightChecker checker(m_context); Expression const& expression = _expressionStatement.getExpression(); compileExpression(expression); CompilerUtils(m_context).popStackElement(*expression.getType()); + checker.check(); return false; } bool Compiler::visit(PlaceholderStatement const&) { + StackHeightChecker checker(m_context); ++m_modifierDepth; appendModifierOrFunctionCode(); --m_modifierDepth; + checker.check(); return true; } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 0838512ee..28ab34adb 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -69,7 +69,7 @@ private: virtual bool visit(Continue const& _continue) override; virtual bool visit(Break const& _break) override; virtual bool visit(Return const& _return) override; - virtual bool visit(VariableDeclarationStatement const& _variableDefinition) override; + virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index f202d7f4e..da2e7f4fe 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -48,7 +48,7 @@ public: bytes const& getCompiledContract(ContractDefinition const& _contract) const; void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } - unsigned getStackHeight() { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } + unsigned getStackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; } bool isLocalVariable(Declaration const* _declaration) const; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 55dedd921..ce51336df 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -833,10 +833,17 @@ string FunctionType::toString() const unsigned FunctionType::getSizeOnStack() const { + Location location = m_location; + if (m_location == Location::SetGas || m_location == Location::SetValue) + { + solAssert(m_returnParameterTypes.size() == 1, ""); + location = dynamic_cast(*m_returnParameterTypes.front()).m_location; + } + unsigned size = 0; - if (m_location == Location::External) + if (location == Location::External) size = 2; - else if (m_location == Location::Internal || m_location == Location::Bare) + else if (location == Location::Internal || location == Location::Bare) size = 1; if (m_gasSet) size++; diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 1f80b1017..20bc81599 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1669,7 +1669,6 @@ BOOST_AUTO_TEST_CASE(value_insane) function test() { h = new helper(); } function sendAmount(uint amount) returns (uint256 bal) { var x1 = h.getBalance.value; - uint someStackElement = 20; var x2 = x1(amount).gas; var x3 = x2(1000).value; return x3(amount + 3)();// overwrite value From fba448415115cffd0cacfa054ba30fdd4daf8bba Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 22 Feb 2015 19:37:54 +0100 Subject: [PATCH 116/118] Replaced "inheritable" by "internal". --- libsolidity/AST.h | 6 +++--- libsolidity/Parser.cpp | 4 ++-- libsolidity/Token.h | 4 ++-- test/SolidityNameAndTypeResolution.cpp | 12 ++++++------ test/SolidityParser.cpp | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 064457d3b..138abf36e 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -133,7 +133,7 @@ class Declaration: public ASTNode { public: /// Visibility ordered from restricted to unrestricted. - enum class Visibility { Default, Private, Inheritable, Public, External }; + enum class Visibility { Default, Private, Internal, Public, External }; Declaration(Location const& _location, ASTPointer const& _name, Visibility _visibility = Visibility::Default): @@ -144,7 +144,7 @@ public: Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } bool isPublic() const { return getVisibility() >= Visibility::Public; } bool isVisibleInContract() const { return getVisibility() != Visibility::External; } - bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Inheritable; } + bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Internal; } /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. @@ -459,7 +459,7 @@ public: bool isIndexed() const { return m_isIndexed; } protected: - Visibility getDefaultVisibility() const override { return Visibility::Inheritable; } + Visibility getDefaultVisibility() const override { return Visibility::Internal; } private: ASTPointer m_typeName; ///< can be empty ("var") diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 9940fb8d9..9fe1af22e 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -187,8 +187,8 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) Declaration::Visibility visibility(Declaration::Visibility::Default); if (_token == Token::Public) visibility = Declaration::Visibility::Public; - else if (_token == Token::Inheritable) - visibility = Declaration::Visibility::Inheritable; + else if (_token == Token::Internal) + visibility = Declaration::Visibility::Internal; else if (_token == Token::Private) visibility = Declaration::Visibility::Private; else if (_token == Token::External) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 4aa000475..5e4a6317f 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -162,7 +162,7 @@ namespace solidity K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ - K(Inheritable, "inheritable", 0) \ + K(Internal, "internal", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ K(Struct, "struct", 0) \ @@ -380,7 +380,7 @@ public: static bool isCountOp(Value op) { return op == Inc || op == Dec; } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } - static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Inheritable; } + static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; } // Returns a string corresponding to the JS token string diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index da6c2a88a..df970a6ed 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -470,7 +470,7 @@ BOOST_AUTO_TEST_CASE(illegal_override_indirect) BOOST_AUTO_TEST_CASE(illegal_override_visibility) { char const* text = R"( - contract B { function f() inheritable {} } + contract B { function f() internal {} } contract C is B { function f() public {} } )"; BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); @@ -706,7 +706,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable) " uint64(2);\n" " }\n" "uint256 private foo;\n" - "uint256 inheritable bar;\n" + "uint256 internal bar;\n" "}\n"; ASTPointer source; @@ -717,7 +717,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable) function = retrieveFunctionBySignature(contract, "foo()"); BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist"); function = retrieveFunctionBySignature(contract, "bar()"); - BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an inheritable variable should not exist"); + BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist"); } BOOST_AUTO_TEST_CASE(fallback_function) @@ -832,11 +832,11 @@ BOOST_AUTO_TEST_CASE(access_to_default_function_visibility) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } -BOOST_AUTO_TEST_CASE(access_to_inheritable_function) +BOOST_AUTO_TEST_CASE(access_to_internal_function) { char const* text = R"( contract c { - function f() inheritable {} + function f() internal {} } contract d { function g() { c(0).f(); } @@ -856,7 +856,7 @@ BOOST_AUTO_TEST_CASE(access_to_default_state_variable_visibility) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } -BOOST_AUTO_TEST_CASE(access_to_inheritable_state_variable) +BOOST_AUTO_TEST_CASE(access_to_internal_state_variable) { char const* text = R"( contract c { diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index ddb582447..69bbc6e0a 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -651,13 +651,13 @@ BOOST_AUTO_TEST_CASE(visibility_specifiers) char const* text = R"( contract c { uint private a; - uint inheritable b; + uint internal b; uint public c; uint d; function f() {} function f_priv() private {} function f_public() public {} - function f_inheritable() inheritable {} + function f_internal() internal {} })"; BOOST_CHECK_NO_THROW(parseText(text)); } @@ -666,7 +666,7 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers) { char const* text = R"( contract c { - uint private inheritable a; + uint private internal a; })"; BOOST_CHECK_THROW(parseText(text), ParserError); } From 4a269eb47312e79f0eb99b6dd7a5f52be3af2444 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 23 Feb 2015 08:29:56 +0100 Subject: [PATCH 117/118] fix too-small-address-length bug in transaction --- libdevcore/RLP.h | 4 +++- libethereum/Transaction.cpp | 2 +- test/TestHelper.cpp | 4 ++-- test/transaction.cpp | 7 ++++++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index 34a0fc65f..a538fac21 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -242,7 +242,9 @@ public: AllowNonCanon = 1, ThrowOnFail = 4, FailIfTooBig = 8, + FailIfTooSmall = 16, Strict = ThrowOnFail | FailIfTooBig, + VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall, LaisezFaire = AllowNonCanon }; @@ -269,7 +271,7 @@ public: template _N toHash(int _flags = Strict) const { - if (!isData() || (length() > _N::size && (_flags & FailIfTooBig))) + if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall))) if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 345e379af..5b3557641 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -40,7 +40,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig) m_gasPrice = rlp[field = 1].toInt(); m_gas = rlp[field = 2].toInt(); m_type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; - m_receiveAddress = rlp[field = 3].toHash
(); + m_receiveAddress = rlp[field = 3].toHash
(RLP::VeryStrict); m_value = rlp[field = 4].toInt(); m_data = rlp[field = 5].toBytes(); byte v = rlp[field = 6].toInt() - 27; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index ff6939a5f..71d381030 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -475,11 +475,11 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun } catch (Exception const& _e) { - BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); + BOOST_ERROR("Failed filling test with Exception: " << diagnostic_information(_e)); } catch (std::exception const& _e) { - BOOST_ERROR("Failed test with Exception: " << _e.what()); + BOOST_ERROR("Failed filling test with Exception: " << _e.what()); } break; } diff --git a/test/transaction.cpp b/test/transaction.cpp index 7bd8ac20c..6ebe62754 100644 --- a/test/transaction.cpp +++ b/test/transaction.cpp @@ -51,7 +51,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) catch(...) { BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); - return; + continue; } BOOST_REQUIRE(o.count("transaction") > 0); @@ -108,6 +108,11 @@ BOOST_AUTO_TEST_CASE(TransactionTest) dev::test::executeTests("ttTransactionTest", "/TransactionTests", dev::test::doTransactionTests); } +BOOST_AUTO_TEST_CASE(ttWrongRLPTransaction) +{ + dev::test::executeTests("ttWrongRLPTransaction", "/TransactionTests", dev::test::doTransactionTests); +} + BOOST_AUTO_TEST_CASE(tt10mbDataField) { dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests); From a9cc2ffa87cb8b550fdc51bfaf74ead78030e016 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 23 Feb 2015 08:56:15 +0100 Subject: [PATCH 118/118] address can only be empty or 20 bytes, nothing in between --- libethereum/Transaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 5b3557641..96689326d 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -40,7 +40,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig) m_gasPrice = rlp[field = 1].toInt(); m_gas = rlp[field = 2].toInt(); m_type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; - m_receiveAddress = rlp[field = 3].toHash
(RLP::VeryStrict); + m_receiveAddress = rlp[field = 3].isEmpty() ? Address() : rlp[field = 3].toHash
(RLP::VeryStrict); m_value = rlp[field = 4].toInt(); m_data = rlp[field = 5].toBytes(); byte v = rlp[field = 6].toInt() - 27;