+#pragma GCC diagnostic pop
+
+class WebPage: public QWebEnginePage
+{
+ Q_OBJECT
+public:
+ WebPage(QObject* _parent): QWebEnginePage(_parent) { }
+signals:
+ void consoleMessage(QString const& _msg);
+
+protected:
+ void javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel _level, const QString& _message, int _lineNumber, const QString& _sourceID) override;
+};
diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake
index 6f2d1ad6c..d781ad2b3 100755
--- a/cmake/EthCompilerSettings.cmake
+++ b/cmake/EthCompilerSettings.cmake
@@ -7,9 +7,17 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE")
set(ETH_SHARED 1)
+ if (PROFILING)
+ set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")
+ add_definitions(-DETH_PROFILING_GPERF)
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lprofiler")
+# set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -lprofiler")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lprofiler")
+ endif ()
+
execute_process(
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
@@ -25,6 +33,10 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG")
set(ETH_SHARED 1)
+ if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX")
+ endif()
+
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# enable parallel compilation
@@ -34,12 +46,14 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# disable decorated name length exceeded, name was truncated (4503)
# disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests)
# declare Windows XP requirement
- add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501)
+ # undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions
+ add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX)
# disable empty object file warning
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# warning LNK4099: pdb was not found with lib
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075")
+ # stack size 16MB
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
# windows likes static
set(ETH_STATIC 1)
@@ -47,3 +61,14 @@ else ()
message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.")
endif ()
+if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
+ option(USE_LD_GOLD "Use GNU gold linker" ON)
+ if (USE_LD_GOLD)
+ execute_process(COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
+ if ("${LD_VERSION}" MATCHES "GNU gold")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
+ endif ()
+ endif ()
+endif ()
+
diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake
index 645942998..61c87efd2 100644
--- a/cmake/EthDependencies.cmake
+++ b/cmake/EthDependencies.cmake
@@ -30,6 +30,9 @@ if (APPLE)
set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/qt5")
endif()
+find_program(CTEST_COMMAND ctest)
+message(STATUS "ctest path: ${CTEST_COMMAND}")
+
# Dependencies must have a version number, to ensure reproducible build. The version provided here is the one that is in the extdep repository. If you use system libraries, version numbers may be different.
find_package (CryptoPP 5.6.2 EXACT REQUIRED)
@@ -45,16 +48,10 @@ find_package (Jsoncpp 0.60 REQUIRED)
message(" - Jsoncpp header: ${JSONCPP_INCLUDE_DIRS}")
message(" - Jsoncpp lib : ${JSONCPP_LIBRARIES}")
-# TODO the JsonRpcCpp package does not yet check for correct version number
-# json-rpc-cpp support is currently not mandatory
-# TODO make headless client optional
# TODO get rid of -DETH_JSONRPC
+# TODO add EXACT once we commit ourselves to cmake 3.x
if (JSONRPC)
-
- find_package (JsonRpcCpp 0.3.2)
- if (NOT JSON_RPC_CPP_FOUND)
- message (FATAL_ERROR "JSONRPC 0.3.2. not found")
- endif()
+ find_package (json_rpc_cpp 0.4 REQUIRED)
message (" - json-rpc-cpp header: ${JSON_RPC_CPP_INCLUDE_DIRS}")
message (" - json-rpc-cpp lib : ${JSON_RPC_CPP_LIBRARIES}")
add_definitions(-DETH_JSONRPC)
@@ -104,7 +101,7 @@ find_program(ETH_JSON_RPC_STUB jsonrpcstub)
message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}")
# do not compile GUI
-if (NOT HEADLESS)
+if (GUI)
# we need json rpc to build alethzero
if (NOT JSON_RPC_CPP_FOUND)
@@ -114,14 +111,17 @@ if (NOT HEADLESS)
# find all of the Qt packages
# remember to use 'Qt' instead of 'QT', cause unix is case sensitive
# TODO make headless client optional
- find_package (Qt5Core REQUIRED)
- find_package (Qt5Gui REQUIRED)
- find_package (Qt5Quick REQUIRED)
- find_package (Qt5Qml REQUIRED)
- find_package (Qt5Network REQUIRED)
- find_package (Qt5Widgets REQUIRED)
- find_package (Qt5WebEngine REQUIRED)
- find_package (Qt5WebEngineWidgets REQUIRED)
+
+ set (ETH_QT_VERSION 5.4)
+
+ find_package (Qt5Core ${ETH_QT_VERSION} REQUIRED)
+ find_package (Qt5Gui ${ETH_QT_VERSION} REQUIRED)
+ find_package (Qt5Quick ${ETH_QT_VERSION} REQUIRED)
+ find_package (Qt5Qml ${ETH_QT_VERSION} REQUIRED)
+ find_package (Qt5Network ${ETH_QT_VERSION} REQUIRED)
+ find_package (Qt5Widgets ${ETH_QT_VERSION} REQUIRED)
+ find_package (Qt5WebEngine ${ETH_QT_VERSION} REQUIRED)
+ find_package (Qt5WebEngineWidgets ${ETH_QT_VERSION} REQUIRED)
# we need to find path to macdeployqt on mac
if (APPLE)
@@ -134,16 +134,26 @@ if (NOT HEADLESS)
message(" - windeployqt path: ${WINDEPLOYQT_APP}")
endif()
-# TODO check node && npm version
- find_program(ETH_NODE node)
- string(REGEX REPLACE "node" "" ETH_NODE_DIRECTORY ${ETH_NODE})
- message(" - nodejs location : ${ETH_NODE}")
+ if (USENPM)
+
+ # TODO check node && npm version
+ find_program(ETH_NODE node)
+ string(REGEX REPLACE "node" "" ETH_NODE_DIRECTORY ${ETH_NODE})
+ message(" - nodejs location : ${ETH_NODE}")
- find_program(ETH_NPM npm)
- string(REGEX REPLACE "npm" "" ETH_NPM_DIRECTORY ${ETH_NPM})
- message(" - npm location : ${ETH_NPM}")
+ find_program(ETH_NPM npm)
+ string(REGEX REPLACE "npm" "" ETH_NPM_DIRECTORY ${ETH_NPM})
+ message(" - npm location : ${ETH_NPM}")
+
+ if (NOT ETH_NODE)
+ message(FATAL_ERROR "node not found!")
+ endif()
+ if (NOT ETH_NPM)
+ message(FATAL_ERROR "npm not found!")
+ endif()
+ endif()
-endif() #HEADLESS
+endif() #GUI
# use multithreaded boost libraries, with -mt suffix
set(Boost_USE_MULTITHREADED ON)
diff --git a/cmake/EthUtils.cmake b/cmake/EthUtils.cmake
index c6fd43ed4..69690156a 100644
--- a/cmake/EthUtils.cmake
+++ b/cmake/EthUtils.cmake
@@ -22,3 +22,43 @@ macro(replace_if_different SOURCE DST)
endif()
endmacro()
+macro(eth_add_test NAME)
+
+ # parse arguments here
+ set(commands)
+ set(current_command "")
+ foreach (arg ${ARGN})
+ if (arg STREQUAL "ARGS")
+ if (current_command)
+ list(APPEND commands ${current_command})
+ endif()
+ set(current_command "")
+ else ()
+ set(current_command "${current_command} ${arg}")
+ endif()
+ endforeach(arg)
+ list(APPEND commands ${current_command})
+
+ message(STATUS "test: ${NAME} | ${commands}")
+
+ # create tests
+ set(index 0)
+ list(LENGTH commands count)
+ while (index LESS count)
+ list(GET commands ${index} test_arguments)
+
+ set(run_test "--run_test=${NAME}")
+ add_test(NAME "${NAME}.${index}" COMMAND testeth ${run_test} ${test_arguments})
+
+ math(EXPR index "${index} + 1")
+ endwhile(index LESS count)
+
+ # add target to run them
+ add_custom_target("test.${NAME}"
+ DEPENDS testeth
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -DETH_TEST_NAME="${NAME}" -DCTEST_COMMAND="${CTEST_COMMAND}" -P "${ETH_SCRIPTS_DIR}/runtest.cmake"
+ )
+
+endmacro()
+
diff --git a/cmake/FindJsonRpcCpp.cmake b/cmake/Findjson_rpc_cpp.cmake
similarity index 65%
rename from cmake/FindJsonRpcCpp.cmake
rename to cmake/Findjson_rpc_cpp.cmake
index 39fd3b39c..9b64cda2b 100644
--- a/cmake/FindJsonRpcCpp.cmake
+++ b/cmake/Findjson_rpc_cpp.cmake
@@ -10,6 +10,11 @@
# JSON_RPC_CPP_SERVER_LIBRARIES, the libraries needed to use json-rpc-cpp-server
# JSON_RPC_CPP_CLIENT_LIBRARIES, the libraries needed to use json-rpc-cpp-client
# JSON_RCP_CPP_FOUND, If false, do not try to use json-rpc-cpp.
+# JSON_RPC_CPP_VERSION, version of library
+# JSON_RPC_CPP_VERSION_MAJOR
+# JSON_RPC_CPP_VERSION_MINOR
+# JSON_RPC_CPP_VERSION_PATCH
+
# only look in default directories
find_path(
@@ -90,10 +95,28 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
endif()
+if (JSON_RPC_CPP_INCLUDE_DIR)
+ set (JSON_RPC_CPP_VERSION_HEADER "${JSON_RPC_CPP_INCLUDE_DIR}/jsonrpccpp/version.h")
+ if (EXISTS ${JSON_RPC_CPP_VERSION_HEADER})
+ file (STRINGS ${JSON_RPC_CPP_VERSION_HEADER} JSON_RPC_CPP_VERSION_MAJOR REGEX "^#define JSONRPC_CPP_MAJOR_VERSION[ \t]+[0-9]+$")
+ file (STRINGS ${JSON_RPC_CPP_VERSION_HEADER} JSON_RPC_CPP_VERSION_MINOR REGEX "^#define JSONRPC_CPP_MINOR_VERSION[ \t]+[0-9]+$")
+ file (STRINGS ${JSON_RPC_CPP_VERSION_HEADER} JSON_RPC_CPP_VERSION_PATCH REGEX "^#define JSONRPC_CPP_PATCH_VERSION[ \t]+[0-9]+$")
+ string (REGEX REPLACE "^#define JSONRPC_CPP_MAJOR_VERSION[ \t]+([0-9]+)" "\\1" JSON_RPC_CPP_VERSION_MAJOR ${JSON_RPC_CPP_VERSION_MAJOR})
+ string (REGEX REPLACE "^#define JSONRPC_CPP_MINOR_VERSION[ \t]+([0-9]+)" "\\1" JSON_RPC_CPP_VERSION_MINOR ${JSON_RPC_CPP_VERSION_MINOR})
+ string (REGEX REPLACE "^#define JSONRPC_CPP_PATCH_VERSION[ \t]+([0-9]+)" "\\1" JSON_RPC_CPP_VERSION_PATCH ${JSON_RPC_CPP_VERSION_PATCH})
+ set (JSON_RPC_CPP_VERSION ${JSON_RPC_CPP_VERSION_MAJOR}.${JSON_RPC_CPP_VERSION_MINOR}.${JSON_RPC_CPP_VERSION_PATCH})
+ endif()
+endif()
+
# handle the QUIETLY and REQUIRED arguments and set JSON_RPC_CPP_FOUND to TRUE
# if all listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(json_rpc_cpp DEFAULT_MSG
- JSON_RPC_CPP_COMMON_LIBRARY JSON_RPC_CPP_SERVER_LIBRARY JSON_RPC_CPP_CLIENT_LIBRARY JSON_RPC_CPP_INCLUDE_DIR)
-mark_as_advanced (JSON_RPC_CPP_COMMON_LIBRARY JSON_RPC_CPP_SERVER_LIBRARY JSON_RPC_CPP_CLIENT_LIBRARY JSON_RPC_CPP_INCLUDE_DIR)
+
+find_package_handle_standard_args(
+ json_rpc_cpp
+ REQUIRED_VARS JSON_RPC_CPP_INCLUDE_DIR JSON_RPC_CPP_COMMON_LIBRARY JSON_RPC_CPP_SERVER_LIBRARY JSON_RPC_CPP_CLIENT_LIBRARY
+ VERSION_VAR JSON_RPC_CPP_VERSION
+)
+
+mark_as_advanced (JSON_RPC_CPP_INCLUDE_DIR JSON_RPC_CPP_COMMON_LIBRARY JSON_RPC_CPP_SERVER_LIBRARY JSON_RPC_CPP_CLIENT_LIBRARY)
diff --git a/cmake/scripts/runtest.cmake b/cmake/scripts/runtest.cmake
new file mode 100644
index 000000000..15f7409ef
--- /dev/null
+++ b/cmake/scripts/runtest.cmake
@@ -0,0 +1,15 @@
+# Should be used to run ctest
+#
+# example usage:
+# cmake -DETH_TEST_NAME=TestInterfaceStub -DCTEST_COMMAND=/path/to/ctest -P scripts/runtest.cmake
+
+if (NOT CTEST_COMMAND)
+ message(FATAL_ERROR "ctest could not be found!")
+endif()
+
+# verbosity is off, cause BOOST_MESSAGE is not thread safe and output is a trash
+# see https://codecrafter.wordpress.com/2012/11/01/c-unit-test-framework-adapter-part-3/
+#
+# output might not be usefull cause of thread safety issue
+execute_process(COMMAND ${CTEST_COMMAND} --force-new-ctest-process -C Debug --output-on-failure -j 4 -R "${ETH_TEST_NAME}[.].*")
+
diff --git a/eth/main.cpp b/eth/main.cpp
index 3b97c561d..9ec6dec98 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -77,7 +77,6 @@ void interactiveHelp()
<< " setetherprice Resets the ether price." << endl
<< " setpriority
Resets the transaction priority." << endl
<< " minestart Starts mining." << endl
- << " minestart Starts mining." << endl
<< " minestop Stops mining." << endl
<< " mineforce Forces mining, even when there are no transactions." << endl
<< " address Gives the current address." << endl
@@ -88,12 +87,14 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl
+#if ETH_FATDB
<< " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl
- << " setsecret Set the secret to the hex secret key." < Set the coinbase (mining payout) address." < Export the config (.RLP) to the path provided." < Import the config (.RLP) from the path provided." < Set the secret to the hex secret key." << endl
+ << " setaddress Set the coinbase (mining payout) address." << endl
+ << " exportconfig Export the config (.RLP) to the path provided." << endl
+ << " importconfig Import the config (.RLP) from the path provided." << endl
<< " inspect Dumps a contract to /.evm." << endl
<< " dumptrace Dumps a transaction trace" << endl << "to . should be one of pretty, standard, standard+." << endl
<< " dumpreceipt Dumps a transation receipt." << endl
@@ -103,7 +104,7 @@ void interactiveHelp()
void help()
{
cout
- << "Usage eth [OPTIONS] " << endl
+ << "Usage eth [OPTIONS]" << endl
<< "Options:" << endl
<< " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
@@ -116,20 +117,22 @@ void help()
<< " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << 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: " << SensibleHttpPort << ")." << endl
#endif
- << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl
- << " -L,--local-networking Use peers whose addresses are local." << endl
+ << " -K,--kill First kill the blockchain." << endl
+ << " --listen-ip Listen on the given port for incoming connections (default: 30303)." << endl
+ << " -l,--listen Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl
+ << " -u,--public-ip Force public ip to given (default: auto)." << endl
<< " -m,--mining Enable mining, optionally for a specified number of blocks (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
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
+ << " -R,--rebuild First rebuild the blockchain from the existing database." << endl
<< " -r,--remote Connect to remote host (default: none)." << endl
<< " -s,--secret Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
- << " -u,--public-ip Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
@@ -159,14 +162,14 @@ string credits(bool _interactive = false)
void version()
{
cout << "eth version " << dev::Version << endl;
- cout << "Network protocol version: " << dev::eth::c_protocolVersion << endl;
+ cout << "eth 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("ccdeac59d35627b7de09332e819d5159e7bb7250");
-string pretty(h160 _a, dev::eth::State _st)
+string pretty(h160 _a, dev::eth::State const& _st)
{
string ns;
h256 n;
@@ -197,7 +200,9 @@ enum class NodeMode
int main(int argc, char** argv)
{
+ string listenIP;
unsigned short listenPort = 30303;
+ string publicIP;
string remoteHost;
unsigned short remotePort = 30303;
string dbPath;
@@ -209,11 +214,10 @@ int main(int argc, char** argv)
#if ETH_JSONRPC
int jsonrpc = -1;
#endif
- string publicIP;
bool bootstrap = false;
bool upnp = true;
- bool useLocal = false;
bool forceMining = false;
+ WithExisting killChain = WithExisting::Trust;
bool jit = false;
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
@@ -247,7 +251,9 @@ int main(int argc, char** argv)
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
- if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
+ if (arg == "--listen-ip" && i + 1 < argc)
+ listenIP = argv[++i];
+ else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
listenPort = (short)atoi(argv[++i]);
else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
publicIP = argv[++i];
@@ -268,15 +274,16 @@ int main(int argc, char** argv)
return -1;
}
}
- else if (arg == "-L" || arg == "--local-networking")
- useLocal = true;
+ else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill")
+ killChain = WithExisting::Kill;
+ else if (arg == "-B" || arg == "--rebuild")
+ killChain = WithExisting::Verify;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
- {
try
{
- coinbase = h160(fromHex(argv[++i], ThrowType::Throw));
+ coinbase = h160(fromHex(argv[++i], WhenError::Throw));
}
catch (BadHexCharacter& _e)
{
@@ -289,7 +296,6 @@ int main(int argc, char** argv)
cwarn << "coinbase rejected";
break;
}
- }
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc)
us = KeyPair(h256(fromHex(argv[++i])));
else if (arg == "--structured-logging-format" && i + 1 < argc)
@@ -300,20 +306,24 @@ int main(int argc, char** argv)
dbPath = argv[++i];
else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
{
- try {
+ try
+ {
blockFees = stof(argv[++i]);
}
- catch (...) {
+ catch (...)
+ {
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
}
else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc)
{
- try {
+ try
+ {
etherPrice = stof(argv[++i]);
}
- catch (...) {
+ catch (...)
+ {
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
@@ -364,7 +374,7 @@ int main(int argc, char** argv)
interactive = true;
#if ETH_JSONRPC
else if ((arg == "-j" || arg == "--json-rpc"))
- jsonrpc = jsonrpc == -1 ? 8080 : jsonrpc;
+ jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc)
jsonrpc = atoi(argv[++i]);
#endif
@@ -401,7 +411,10 @@ int main(int argc, char** argv)
else if (arg == "-V" || arg == "--version")
version();
else
- remoteHost = argv[i];
+ {
+ cerr << "Invalid argument: " << arg << endl;
+ exit(-1);
+ }
}
if (!clientName.empty())
@@ -411,13 +424,13 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
- NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
+ auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3(
clientImplString,
dbPath,
- false,
+ killChain,
mode == NodeMode::Full ? set{"eth", "shh"} : set(),
netPrefs,
&nodesState,
@@ -434,20 +447,21 @@ int main(int argc, char** argv)
c->setAddress(coinbase);
}
- cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
+ cout << "Transaction Signer: " << us.address() << endl;
+ cout << "Mining Benefactor: " << coinbase << endl;
web3.startNetwork();
if (bootstrap)
- web3.connect(Host::pocHost());
+ web3.addNode(p2p::NodeId(), Host::pocHost());
if (remoteHost.size())
- web3.connect(remoteHost, remotePort);
+ web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC
shared_ptr jsonrpcServer;
unique_ptr jsonrpcConnector;
if (jsonrpc > -1)
{
- jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc));
+ jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
@@ -500,7 +514,7 @@ int main(int argc, char** argv)
string addr;
unsigned port;
iss >> addr >> port;
- web3.connect(addr, (short)port);
+ web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort));
}
else if (cmd == "netstop")
{
@@ -572,8 +586,8 @@ int main(int argc, char** argv)
else if (cmd == "jsonstart")
{
if (jsonrpc < 0)
- jsonrpc = 8080;
- jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc));
+ jsonrpc = SensibleHttpPort;
+ jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
@@ -659,7 +673,7 @@ int main(int argc, char** argv)
{
Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(hexAddr));
- c->transact(secret, amount, dest, data, gas, gasPrice);
+ c->submitTransaction(secret, amount, dest, data, gas, gasPrice);
}
catch (BadHexCharacter& _e)
{
@@ -673,14 +687,15 @@ int main(int argc, char** argv)
}
}
else
- cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
+ cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
}
+#if ETH_FATDB
else if (c && cmd == "listcontracts")
{
auto acs =c->addresses();
string ss;
for (auto const& i: acs)
- if ( c->codeAt(i, 0).size())
+ if ( c->codeAt(i, PendingBlock).size())
{
ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl;
@@ -691,12 +706,13 @@ int main(int argc, char** argv)
auto acs =c->addresses();
string ss;
for (auto const& i: acs)
- if ( c->codeAt(i, 0).empty())
+ if ( c->codeAt(i, PendingBlock).empty())
{
ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl;
}
}
+#endif
else if (c && cmd == "send")
{
if (iss.peek() != -1)
@@ -720,8 +736,8 @@ int main(int argc, char** argv)
u256 minGas = (u256)Client::txGas(bytes(), 0);
try
{
- Address dest = h160(fromHex(hexAddr, ThrowType::Throw));
- c->transact(us.secret(), amount, dest, bytes(), minGas);
+ Address dest = h160(fromHex(hexAddr, WhenError::Throw));
+ c->submitTransaction(us.secret(), amount, dest, bytes(), minGas);
}
catch (BadHexCharacter& _e)
{
@@ -764,7 +780,7 @@ int main(int argc, char** argv)
stringstream ssc;
try
{
- init = fromHex(sinit, ThrowType::Throw);
+ init = fromHex(sinit, WhenError::Throw);
}
catch (BadHexCharacter& _e)
{
@@ -790,7 +806,7 @@ int main(int argc, char** argv)
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else
- c->transact(us.secret(), endowment, init, gas, gasPrice);
+ c->submitTransaction(us.secret(), endowment, init, gas, gasPrice);
}
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
@@ -822,11 +838,8 @@ int main(int argc, char** argv)
Executive e(state, c->blockChain(), 0);
Transaction t = state.pending()[index];
state = state.fromPending(index);
- bytes r = t.rlp();
try
{
- e.setup(&r);
-
OnOpFunc oof;
if (format == "pretty")
oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
@@ -859,7 +872,9 @@ int main(int argc, char** argv)
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
- e.go(oof);
+ e.initialize(t);
+ if (!e.execute())
+ e.go(oof);
e.finalize();
}
catch(Exception const& _e)
@@ -883,10 +898,10 @@ int main(int argc, char** argv)
try
{
- auto storage =c->storageAt(h, 0);
+ auto storage =c->storageAt(h, PendingBlock);
for (auto const& i: storage)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
- s << endl << disassemble( c->codeAt(h, 0)) << endl;
+ s << endl << disassemble( c->codeAt(h, PendingBlock)) << endl;
string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs;
@@ -925,7 +940,7 @@ int main(int argc, char** argv)
{
try
{
- coinbase = h160(fromHex(hexAddr, ThrowType::Throw));
+ coinbase = h160(fromHex(hexAddr, WhenError::Throw));
}
catch (BadHexCharacter& _e)
{
diff --git a/ethrpctest/CMakeLists.txt b/ethrpctest/CMakeLists.txt
new file mode 100644
index 000000000..5d3fef542
--- /dev/null
+++ b/ethrpctest/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_policy(SET CMP0015 NEW)
+set(CMAKE_AUTOMOC OFF)
+
+aux_source_directory(. SRC_LIST)
+
+include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
+include_directories(BEFORE ..)
+include_directories(${Boost_INCLUDE_DIRS})
+include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
+
+set(EXECUTABLE ethrpctest)
+
+file(GLOB HEADERS "*.h")
+
+add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
+
+add_dependencies(${EXECUTABLE} BuildInfo.h)
+
+target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
+
+if (READLINE_FOUND)
+ target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
+endif()
+
+target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
+target_link_libraries(${EXECUTABLE} ${Boost_PROGRAM_OPTIONS_LIBRARIES})
+target_link_libraries(${EXECUTABLE} testutils)
+target_link_libraries(${EXECUTABLE} web3jsonrpc)
+
+if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
+ 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 )
+
diff --git a/ethrpctest/CommandLineInterface.cpp b/ethrpctest/CommandLineInterface.cpp
new file mode 100644
index 000000000..c4b3d8f27
--- /dev/null
+++ b/ethrpctest/CommandLineInterface.cpp
@@ -0,0 +1,129 @@
+/*
+ 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 CommandLineInterface.cpp
+ * @author Marek Kotewicz
+ * @date 2015
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "CommandLineInterface.h"
+#include "BuildInfo.h"
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+using namespace dev::test;
+namespace po = boost::program_options;
+
+bool CommandLineInterface::parseArguments(int argc, char** argv)
+{
+ // Declare the supported options.
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "Show help message and exit")
+ ("json", po::value>()->required(), "input file")
+ ("test", po::value>()->required(), "test case name");
+
+ // All positional options should be interpreted as input files
+ po::positional_options_description p;
+
+ // parse the compiler arguments
+ try
+ {
+ po::store(po::command_line_parser(argc, argv).options(desc).positional(p).allow_unregistered().run(), m_args);
+
+ if (m_args.count("help"))
+ {
+ cout << desc;
+ return false;
+ }
+
+ po::notify(m_args);
+ }
+ catch (po::error const& _exception)
+ {
+ cout << _exception.what() << endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool CommandLineInterface::processInput()
+{
+ string infile = m_args["json"].as>()[0];
+
+ auto path = boost::filesystem::path(infile);
+ if (!boost::filesystem::exists(path))
+ {
+ cout << "Non existant input file \"" << infile << "\"" << endl;
+ return false;
+ }
+
+ string test = m_args["test"].as>()[0];
+ Json::Value j = dev::test::loadJsonFromFile(path.string());
+
+ if (j[test].empty())
+ {
+ cout << "Non existant test case \"" << infile << "\"" << endl;
+ return false;
+ }
+
+ if (!j[test].isObject())
+ {
+ cout << "Incorrect JSON file \"" << infile << "\"" << endl;
+ return false;
+ }
+
+ m_json = j[test];
+
+ return true;
+}
+
+bool g_exit = false;
+
+void sighandler(int)
+{
+ g_exit = true;
+}
+
+void CommandLineInterface::actOnInput()
+{
+ BlockChainLoader bcl(m_json);
+ FixedClient client(bcl.bc(), bcl.state());
+ unique_ptr jsonrpcServer;
+ auto server = new jsonrpc::HttpServer(8080, "", "", 2);
+ jsonrpcServer.reset(new FixedWebThreeServer(*server, {}, &client));
+ jsonrpcServer->StartListening();
+
+ signal(SIGABRT, &sighandler);
+ signal(SIGTERM, &sighandler);
+ signal(SIGINT, &sighandler);
+
+ while (!g_exit)
+ this_thread::sleep_for(chrono::milliseconds(1000));
+}
diff --git a/ethrpctest/CommandLineInterface.h b/ethrpctest/CommandLineInterface.h
new file mode 100644
index 000000000..b57e1df5e
--- /dev/null
+++ b/ethrpctest/CommandLineInterface.h
@@ -0,0 +1,46 @@
+/*
+ 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 .
+*/
+/** CommandLineInterface.h
+ * @author Marek Kotewicz
+ * @date 2015
+ */
+#pragma once
+
+#include
+#include
+
+class CommandLineInterface
+{
+public:
+ CommandLineInterface() {}
+
+ /// Parse command line arguments and return false if we should not continue
+ bool parseArguments(int argc, char** argv);
+ /// Parse input file and check if test exists
+ bool processInput();
+ /// Start FixedJsonRpcServer
+ void actOnInput();
+
+private:
+
+ /// Compiler arguments variable map
+ boost::program_options::variables_map m_args;
+
+ /// loaded json test case
+ Json::Value m_json;
+};
+
diff --git a/ethrpctest/main.cpp b/ethrpctest/main.cpp
new file mode 100644
index 000000000..3d710dd5b
--- /dev/null
+++ b/ethrpctest/main.cpp
@@ -0,0 +1,34 @@
+/*
+ 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 .
+*/
+/** main.cpp
+ * @author Marek Kotewicz
+ * @date 2015
+ */
+
+#include "CommandLineInterface.h"
+
+int main(int argc, char** argv)
+{
+ CommandLineInterface cli;
+ if (!cli.parseArguments(argc, argv))
+ return 1;
+ if (!cli.processInput())
+ return 1;
+ cli.actOnInput();
+
+ return 0;
+}
diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt
index 14fca2cde..5ab394a80 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 -Wno-unknown-pragmas")
+ set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas")
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
@@ -22,7 +22,7 @@ if(LLVM_DIR OR APPLE) # local LLVM build
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)
+ llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter ipo)
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")
diff --git a/evmjit/libevmjit-cpp/CMakeLists.txt b/evmjit/libevmjit-cpp/CMakeLists.txt
index 53448332b..add132f2a 100644
--- a/evmjit/libevmjit-cpp/CMakeLists.txt
+++ b/evmjit/libevmjit-cpp/CMakeLists.txt
@@ -4,8 +4,9 @@ set(TARGET_NAME evmjit-cpp)
find_package(Boost REQUIRED)
set(SOURCES
- Env.cpp
+ Env.cpp
JitVM.cpp JitVM.h
+ Utils.h
)
source_group("" FILES ${SOURCES})
diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp
index 874993c84..b89aca726 100644
--- a/evmjit/libevmjit-cpp/Env.cpp
+++ b/evmjit/libevmjit-cpp/Env.cpp
@@ -52,7 +52,6 @@ extern "C"
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);
@@ -62,23 +61,37 @@ extern "C"
*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)
+ EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, int64_t _callGas, 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)
+ auto receiveAddress = right160(*_receiveAddress);
+ auto codeAddress = right160(*_codeAddress);
+ const auto isCall = receiveAddress == codeAddress; // OPT: The same address pointer can be used if not CODECALL
+
+ *io_gas -= _callGas;
+ if (*io_gas < 0)
+ return false;
+
+ if (isCall && !_env->exists(receiveAddress))
+ *io_gas -= static_cast(c_callNewAccountGas); // no underflow, *io_gas non-negative before
+
+ if (value > 0) // value transfer
{
- _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;
+ /*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible");
+ *io_gas -= static_cast(c_callValueTransferGas); // no underflow
+ _callGas += static_cast(c_callStipend); // overflow possibility, but in the same time *io_gas < 0
}
- return false;
+ if (*io_gas < 0)
+ return false;
+
+ auto ret = false;
+ auto callGas = u256{_callGas};
+ if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
+ ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress);
+
+ *io_gas += static_cast(callGas); // it is never more than initial _callGas
+ return ret;
}
EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash)
diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp
index e28fcd39f..84cc41dd1 100644
--- a/evmjit/libevmjit-cpp/JitVM.cpp
+++ b/evmjit/libevmjit-cpp/JitVM.cpp
@@ -69,8 +69,8 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
BOOST_THROW_EXCEPTION(BadJumpDestination());
case ReturnCode::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas());
- case ReturnCode::StackTooSmall:
- BOOST_THROW_EXCEPTION(StackTooSmall());
+ case ReturnCode::StackUnderflow:
+ BOOST_THROW_EXCEPTION(StackUnderflow());
case ReturnCode::BadInstruction:
BOOST_THROW_EXCEPTION(BadInstruction());
case ReturnCode::LinkerWorkaround: // never happens
diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp
index ddf06b463..e88fda432 100644
--- a/evmjit/libevmjit/Arith256.cpp
+++ b/evmjit/libevmjit/Arith256.cpp
@@ -9,6 +9,7 @@
#include "Type.h"
#include "Endianness.h"
+#include "Utils.h"
namespace dev
{
@@ -38,6 +39,8 @@ llvm::Function* Arith256::getMulFunc()
{
llvm::Type* argTypes[] = {Type::Word, Type::Word};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule());
+ func->setDoesNotThrow();
+ func->setDoesNotAccessMemory();
auto x = &func->getArgumentList().front();
x->setName("x");
@@ -50,12 +53,16 @@ llvm::Function* Arith256::getMulFunc()
auto i64 = Type::Size;
auto i128 = m_builder.getIntNTy(128);
auto i256 = Type::Word;
+ auto c64 = Constant::get(64);
+ auto c128 = Constant::get(128);
+ auto c192 = Constant::get(192);
+
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 x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, c64), i64);
+ auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, c64), i64);
+ auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, c128), i128);
+ auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, c128), 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));
@@ -67,13 +74,13 @@ llvm::Function* Arith256::getMulFunc()
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)));
+ p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), c64));
+ p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), c128));
+ p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), c64));
+ p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), c128));
+ p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), c192));
+ p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), c128));
+ p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), c192));
m_builder.CreateRet(p);
}
return func;
@@ -87,6 +94,8 @@ 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, "mul512", getModule());
+ func->setDoesNotThrow();
+ func->setDoesNotAccessMemory();
auto x = &func->getArgumentList().front();
x->setName("x");
@@ -130,6 +139,8 @@ llvm::Function* Arith256::getDivFunc(llvm::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());
+ func->setDoesNotThrow();
+ func->setDoesNotAccessMemory();
auto zero = llvm::ConstantInt::get(_type, 0);
auto one = llvm::ConstantInt::get(_type, 1);
@@ -221,6 +232,8 @@ llvm::Function* Arith256::getExpFunc()
{
llvm::Type* argTypes[] = {Type::Word, Type::Word};
m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule());
+ m_exp->setDoesNotThrow();
+ m_exp->setDoesNotAccessMemory();
auto base = &m_exp->getArgumentList().front();
base->setName("base");
@@ -289,6 +302,8 @@ llvm::Function* Arith256::getAddModFunc()
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());
+ m_addmod->setDoesNotThrow();
+ m_addmod->setDoesNotAccessMemory();
auto x = &m_addmod->getArgumentList().front();
x->setName("x");
@@ -318,6 +333,8 @@ llvm::Function* Arith256::getMulModFunc()
{
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());
+ m_mulmod->setDoesNotThrow();
+ m_mulmod->setDoesNotAccessMemory();
auto i512Ty = m_builder.getIntNTy(512);
auto x = &m_mulmod->getArgumentList().front();
@@ -343,18 +360,51 @@ llvm::Function* Arith256::getMulModFunc()
llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2)
{
+ if (auto c1 = llvm::dyn_cast(_arg1))
+ {
+ if (auto c2 = llvm::dyn_cast(_arg2))
+ return Constant::get(c1->getValue() * c2->getValue());
+ }
+
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");
+ // FIXME: Disabled because of llvm::APInt::urem bug
+// if (auto c1 = llvm::dyn_cast(_arg1))
+// {
+// if (auto c2 = llvm::dyn_cast(_arg2))
+// {
+// if (!c2->getValue())
+// return std::make_pair(Constant::get(0), Constant::get(0));
+// auto div = Constant::get(c1->getValue().udiv(c2->getValue()));
+// auto mod = Constant::get(c1->getValue().urem(c2->getValue()));
+// return std::make_pair(div, mod);
+// }
+// }
+
+ auto r = createCall(getDivFunc(Type::Word), {_arg1, _arg2});
+ auto div = m_builder.CreateExtractValue(r, 0, "div");
+ auto mod = m_builder.CreateExtractValue(r, 1, "mod");
return std::make_pair(div, mod);
}
std::pair Arith256::sdiv(llvm::Value* _x, llvm::Value* _y)
{
+ // FIXME: Disabled because of llvm::APInt::urem bug
+// if (auto c1 = llvm::dyn_cast(_x))
+// {
+// if (auto c2 = llvm::dyn_cast(_y))
+// {
+// if (!c2->getValue())
+// return std::make_pair(Constant::get(0), Constant::get(0));
+// auto div = Constant::get(c1->getValue().sdiv(c2->getValue()));
+// auto mod = Constant::get(c1->getValue().srem(c2->getValue()));
+// return std::make_pair(div, mod);
+// }
+// }
+
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);
@@ -378,16 +428,73 @@ std::pair Arith256::sdiv(llvm::Value* _x, llvm::Valu
llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2)
{
+ // while (e != 0) {
+ // if (e % 2 == 1)
+ // r *= b;
+ // b *= b;
+ // e /= 2;
+ // }
+
+ if (auto c1 = llvm::dyn_cast(_arg1))
+ {
+ if (auto c2 = llvm::dyn_cast(_arg2))
+ {
+ auto b = c1->getValue();
+ auto e = c2->getValue();
+ auto r = llvm::APInt{256, 1};
+ while (e != 0)
+ {
+ if (e[0])
+ r *= b;
+ b *= b;
+ e = e.lshr(1);
+ }
+ return Constant::get(r);
+ }
+ }
+
return createCall(getExpFunc(), {_arg1, _arg2});
}
llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
+ // FIXME: Disabled because of llvm::APInt::urem bug
+// if (auto c1 = llvm::dyn_cast(_arg1))
+// {
+// if (auto c2 = llvm::dyn_cast(_arg2))
+// {
+// if (auto c3 = llvm::dyn_cast(_arg3))
+// {
+// if (!c3->getValue())
+// return Constant::get(0);
+// auto s = c1->getValue().zext(256+64) + c2->getValue().zext(256+64);
+// auto r = s.urem(c3->getValue().zext(256+64)).trunc(256);
+// return Constant::get(r);
+// }
+// }
+// }
+
return createCall(getAddModFunc(), {_arg1, _arg2, _arg3});
}
llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
+ // FIXME: Disabled because of llvm::APInt::urem bug
+// if (auto c1 = llvm::dyn_cast(_arg1))
+// {
+// if (auto c2 = llvm::dyn_cast(_arg2))
+// {
+// if (auto c3 = llvm::dyn_cast(_arg3))
+// {
+// if (!c3->getValue())
+// return Constant::get(0);
+// auto p = c1->getValue().zext(512) * c2->getValue().zext(512);
+// auto r = p.urem(c3->getValue().zext(512)).trunc(256);
+// return Constant::get(r);
+// }
+// }
+// }
+
return createCall(getMulModFunc(), {_arg1, _arg2, _arg3});
}
@@ -400,7 +507,7 @@ 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
+ DLOG(JIT) << "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/Array.cpp b/evmjit/libevmjit/Array.cpp
new file mode 100644
index 000000000..3266038db
--- /dev/null
+++ b/evmjit/libevmjit/Array.cpp
@@ -0,0 +1,320 @@
+#include "Array.h"
+
+#include "preprocessor/llvm_includes_start.h"
+#include
+#include
+#include "preprocessor/llvm_includes_end.h"
+
+#include "RuntimeManager.h"
+#include "Runtime.h"
+#include "Utils.h"
+
+#include // DEBUG only
+
+namespace dev
+{
+namespace eth
+{
+namespace jit
+{
+
+static const auto c_reallocStep = 1;
+static const auto c_reallocMultipier = 2;
+
+llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args, llvm::Twine const& _name)
+{
+ if (!m_func)
+ m_func = m_creator();
+
+ return _builder.CreateCall(m_func, {_args.begin(), _args.size()}, _name);
+}
+
+llvm::Function* Array::createArrayPushFunc()
+{
+ llvm::Type* argTypes[] = {m_array->getType(), Type::Word};
+ auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule());
+ func->setDoesNotThrow();
+ func->setDoesNotCapture(1);
+
+ auto arrayPtr = &func->getArgumentList().front();
+ arrayPtr->setName("arrayPtr");
+ auto value = arrayPtr->getNextNode();
+ value->setName("value");
+
+ InsertPointGuard guard{m_builder};
+ auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func);
+ auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func);
+ auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func);
+
+ m_builder.SetInsertPoint(entryBB);
+ auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
+ auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr");
+ auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr");
+ auto data = m_builder.CreateLoad(dataPtr, "data");
+ auto size = m_builder.CreateLoad(sizePtr, "size");
+ auto cap = m_builder.CreateLoad(capPtr, "cap");
+ auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq");
+ m_builder.CreateCondBr(reallocReq, reallocBB, pushBB);
+
+ m_builder.SetInsertPoint(reallocBB);
+ auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap");
+ //newCap = m_builder.CreateNUWMul(newCap, m_builder.getInt64(c_reallocMultipier));
+ auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32
+ auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes");
+ auto newBytes = m_reallocFunc.call(m_builder, {bytes, reallocSize}, "newBytes");
+ auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData");
+ m_builder.CreateStore(newData, dataPtr);
+ m_builder.CreateStore(newCap, capPtr);
+ m_builder.CreateBr(pushBB);
+
+ m_builder.SetInsertPoint(pushBB);
+ auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi");
+ dataPhi->addIncoming(data, entryBB);
+ dataPhi->addIncoming(newData, reallocBB);
+ auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr");
+ m_builder.CreateStore(value, newElemPtr);
+ auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize");
+ m_builder.CreateStore(newSize, sizePtr);
+ m_builder.CreateRetVoid();
+
+ return func;
+}
+
+llvm::Function* Array::createArraySetFunc()
+{
+ llvm::Type* argTypes[] = {m_array->getType(), Type::Size, Type::Word};
+ auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.set", getModule());
+ func->setDoesNotThrow();
+ func->setDoesNotCapture(1);
+
+ auto arrayPtr = &func->getArgumentList().front();
+ arrayPtr->setName("arrayPtr");
+ auto index = arrayPtr->getNextNode();
+ index->setName("index");
+ auto value = index->getNextNode();
+ value->setName("value");
+
+ InsertPointGuard guard{m_builder};
+ m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
+ auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
+ auto data = m_builder.CreateLoad(dataPtr, "data");
+ auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
+ m_builder.CreateStore(value, valuePtr);
+ m_builder.CreateRetVoid();
+ return func;
+}
+
+llvm::Function* Array::createArrayGetFunc()
+{
+ llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
+ auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "array.get", getModule());
+ func->setDoesNotThrow();
+ func->setDoesNotCapture(1);
+
+ auto arrayPtr = &func->getArgumentList().front();
+ arrayPtr->setName("arrayPtr");
+ auto index = arrayPtr->getNextNode();
+ index->setName("index");
+
+ InsertPointGuard guard{m_builder};
+ m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
+ auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
+ auto data = m_builder.CreateLoad(dataPtr, "data");
+ auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
+ auto value = m_builder.CreateLoad(valuePtr, "value");
+ m_builder.CreateRet(value);
+ return func;
+}
+
+llvm::Function* Array::createGetPtrFunc()
+{
+ llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
+ auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::PrivateLinkage, "array.getPtr", getModule());
+ func->setDoesNotThrow();
+ func->setDoesNotCapture(1);
+
+ auto arrayPtr = &func->getArgumentList().front();
+ arrayPtr->setName("arrayPtr");
+ auto index = arrayPtr->getNextNode();
+ index->setName("index");
+
+ InsertPointGuard guard{m_builder};
+ m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
+ auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");
+ auto data = m_builder.CreateLoad(dataPtr, "data");
+ auto bytePtr = m_builder.CreateGEP(data, index, "bytePtr");
+ auto wordPtr = m_builder.CreateBitCast(bytePtr, Type::WordPtr, "wordPtr");
+ m_builder.CreateRet(wordPtr);
+ return func;
+}
+
+llvm::Function* Array::createFreeFunc()
+{
+ auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule());
+ func->setDoesNotThrow();
+ func->setDoesNotCapture(1);
+
+ auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "ext_free", getModule());
+ freeFunc->setDoesNotThrow();
+ freeFunc->setDoesNotCapture(1);
+
+ auto arrayPtr = &func->getArgumentList().front();
+ arrayPtr->setName("arrayPtr");
+
+ InsertPointGuard guard{m_builder};
+ m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
+ auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
+ auto data = m_builder.CreateLoad(dataPtr, "data");
+ auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem");
+ m_builder.CreateCall(freeFunc, mem);
+ m_builder.CreateRetVoid();
+ return func;
+}
+
+llvm::Function* Array::getReallocFunc()
+{
+ if (auto func = getModule()->getFunction("ext_realloc"))
+ return func;
+
+ llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size};
+ auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule());
+ reallocFunc->setDoesNotThrow();
+ reallocFunc->setDoesNotAlias(0);
+ reallocFunc->setDoesNotCapture(1);
+ return reallocFunc;
+}
+
+llvm::Function* Array::createExtendFunc()
+{
+ llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
+ auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.extend", getModule());
+ func->setDoesNotThrow();
+ func->setDoesNotCapture(1);
+
+ auto arrayPtr = &func->getArgumentList().front();
+ arrayPtr->setName("arrayPtr");
+ auto newSize = arrayPtr->getNextNode();
+ newSize->setName("newSize");
+
+ InsertPointGuard guard{m_builder};
+ m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
+ auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array
+ auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr");
+ auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr");
+ auto data = m_builder.CreateLoad(dataPtr, "data");
+ auto size = m_builder.CreateLoad(sizePtr, "size");
+ auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize");
+ auto newData = m_reallocFunc.call(m_builder, {data, newSize}, "newData"); // TODO: Check realloc result for null
+ auto extPtr = m_builder.CreateGEP(newData, size, "extPtr");
+ m_builder.CreateMemSet(extPtr, m_builder.getInt8(0), extSize, 16);
+ m_builder.CreateStore(newData, dataPtr);
+ m_builder.CreateStore(newSize, sizePtr);
+ m_builder.CreateStore(newSize, capPtr);
+ m_builder.CreateRetVoid();
+ return func;
+}
+
+llvm::Type* Array::getType()
+{
+ llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size};
+ static auto arrayTy = llvm::StructType::create(elementTys, "Array");
+ return arrayTy;
+}
+
+Array::Array(llvm::IRBuilder<>& _builder, char const* _name) :
+ CompilerHelper(_builder),
+ m_pushFunc([this](){ return createArrayPushFunc(); }),
+ m_setFunc([this](){ return createArraySetFunc(); }),
+ m_getFunc([this](){ return createArrayGetFunc(); }),
+ m_freeFunc([this](){ return createFreeFunc(); })
+{
+ m_array = m_builder.CreateAlloca(getType(), nullptr, _name);
+ m_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array);
+}
+
+Array::Array(llvm::IRBuilder<>& _builder, llvm::Value* _array) :
+ CompilerHelper(_builder),
+ m_array(_array),
+ m_pushFunc([this](){ return createArrayPushFunc(); }),
+ m_setFunc([this](){ return createArraySetFunc(); }),
+ m_getFunc([this](){ return createArrayGetFunc(); }),
+ m_freeFunc([this](){ return createFreeFunc(); })
+{
+ m_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array);
+}
+
+
+void Array::pop(llvm::Value* _count)
+{
+ auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr");
+ auto size = m_builder.CreateLoad(sizePtr, "size");
+ auto newSize = m_builder.CreateNUWSub(size, _count, "newSize");
+ m_builder.CreateStore(newSize, sizePtr);
+}
+
+llvm::Value* Array::size(llvm::Value* _array)
+{
+ auto sizePtr = m_builder.CreateStructGEP(_array ? _array : m_array, 1, "sizePtr");
+ return m_builder.CreateLoad(sizePtr, "array.size");
+}
+
+void Array::extend(llvm::Value* _arrayPtr, llvm::Value* _size)
+{
+ assert(_arrayPtr->getType() == m_array->getType());
+ assert(_size->getType() == Type::Size);
+ m_extendFunc.call(m_builder, {_arrayPtr, _size});
+}
+
+}
+}
+}
+
+namespace
+{
+ struct AllocatedMemoryWatchdog
+ {
+ std::set allocatedMemory;
+
+ ~AllocatedMemoryWatchdog()
+ {
+ if (!allocatedMemory.empty())
+ {
+ DLOG(mem) << allocatedMemory.size() << " MEM LEAKS!\n";
+ for (auto&& leak : allocatedMemory)
+ DLOG(mem) << "\t" << leak << "\n";
+ }
+ }
+ };
+
+ AllocatedMemoryWatchdog watchdog;
+}
+
+extern "C"
+{
+ using namespace dev::eth::jit;
+
+ EXPORT void* ext_realloc(void* _data, size_t _size) noexcept
+ {
+ //std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl;
+ auto newData = std::realloc(_data, _size);
+ if (_data != newData)
+ {
+ DLOG(mem) << "REALLOC: " << newData << " <- " << _data << " [" << _size << "]\n";
+ watchdog.allocatedMemory.erase(_data);
+ watchdog.allocatedMemory.insert(newData);
+ }
+ return newData;
+ }
+
+ EXPORT void ext_free(void* _data) noexcept
+ {
+ std::free(_data);
+ if (_data)
+ {
+ DLOG(mem) << "FREE : " << _data << "\n";
+ watchdog.allocatedMemory.erase(_data);
+ }
+ }
+
+} // extern "C"
+
diff --git a/evmjit/libevmjit/Array.h b/evmjit/libevmjit/Array.h
new file mode 100644
index 000000000..41842f0c9
--- /dev/null
+++ b/evmjit/libevmjit/Array.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include
+
+#include "CompilerHelper.h"
+
+namespace dev
+{
+namespace eth
+{
+namespace jit
+{
+
+class LazyFunction
+{
+public:
+ using Creator = std::function;
+
+ LazyFunction(Creator _creator) :
+ m_creator(_creator)
+ {}
+
+ llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args, llvm::Twine const& _name = "");
+
+private:
+ llvm::Function* m_func = nullptr;
+ Creator m_creator;
+};
+
+class Array : public CompilerHelper
+{
+public:
+ Array(llvm::IRBuilder<>& _builder, char const* _name);
+ Array(llvm::IRBuilder<>& _builder, llvm::Value* _array);
+
+ void push(llvm::Value* _value) { m_pushFunc.call(m_builder, {m_array, _value}); }
+ void set(llvm::Value* _index, llvm::Value* _value) { m_setFunc.call(m_builder, {m_array, _index, _value}); }
+ llvm::Value* get(llvm::Value* _index) { return m_getFunc.call(m_builder, {m_array, _index}); }
+ void pop(llvm::Value* _count);
+ llvm::Value* size(llvm::Value* _array = nullptr);
+ void free() { m_freeFunc.call(m_builder, {m_array}); }
+
+ void extend(llvm::Value* _arrayPtr, llvm::Value* _size);
+ llvm::Value* getPtr(llvm::Value* _arrayPtr, llvm::Value* _index) { return m_getPtrFunc.call(m_builder, {_arrayPtr, _index}); }
+
+ llvm::Value* getPointerTo() const { return m_array; }
+
+ static llvm::Type* getType();
+
+private:
+ llvm::Value* m_array = nullptr;
+
+ llvm::Function* createArrayPushFunc();
+ llvm::Function* createArraySetFunc();
+ llvm::Function* createArrayGetFunc();
+ llvm::Function* createGetPtrFunc();
+ llvm::Function* createFreeFunc();
+ llvm::Function* createExtendFunc();
+ llvm::Function* getReallocFunc();
+
+ LazyFunction m_pushFunc = {[this](){ return createArrayPushFunc(); }}; // TODO: If works on MSVC, remove form initialization list
+ LazyFunction m_setFunc;
+ LazyFunction m_getPtrFunc = {[this](){ return createGetPtrFunc(); }};
+ LazyFunction m_getFunc;
+ LazyFunction m_freeFunc;
+ LazyFunction m_extendFunc = {[this](){ return createExtendFunc(); }};
+ LazyFunction m_reallocFunc = {[this](){ return getReallocFunc(); }};
+};
+
+}
+}
+}
+
+
diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp
index c9e71be9a..a41743d0b 100644
--- a/evmjit/libevmjit/BasicBlock.cpp
+++ b/evmjit/libevmjit/BasicBlock.cpp
@@ -11,6 +11,7 @@
#include "preprocessor/llvm_includes_end.h"
#include "Type.h"
+#include "Utils.h"
namespace dev
{
@@ -48,6 +49,7 @@ void BasicBlock::LocalStack::push(llvm::Value* _value)
assert(_value->getType() == Type::Word);
m_bblock.m_currentStack.push_back(_value);
m_bblock.m_tosOffset += 1;
+ m_maxSize = std::max(m_maxSize, m_bblock.m_currentStack.size());
}
llvm::Value* BasicBlock::LocalStack::pop()
@@ -136,32 +138,34 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack)
{
auto blockTerminator = m_llvmBB->getTerminator();
assert(blockTerminator != nullptr);
- m_builder.SetInsertPoint(blockTerminator);
+ if (blockTerminator->getOpcode() != llvm::Instruction::Ret)
+ {
+ // Not needed in case of ret instruction. Ret also invalidates the stack.
+ m_builder.SetInsertPoint(blockTerminator);
- auto currIter = m_currentStack.begin();
- auto endIter = m_currentStack.end();
+ 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);
- }
+ // 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));
- }
+ if (m_tosOffset < 0)
+ _evmStack.pop(static_cast(-m_tosOffset));
- // Push new values
- for (; currIter < endIter; ++currIter)
- {
- assert(*currIter != nullptr);
- _evmStack.push(*currIter);
+ // Push new values
+ for (; currIter < endIter; ++currIter)
+ {
+ assert(*currIter != nullptr);
+ _evmStack.push(*currIter);
+ }
}
// Emit get() for all (used) values from the initial stack
@@ -233,7 +237,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB
for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt)
{
auto predInfoEntry = cfg.find(*predIt);
- if (predInfoEntry != cfg.end())
+ if (predInfoEntry != cfg.end()) // FIXME: It is wrong - will skip entry block
info.predecessors.push_back(&predInfoEntry->second);
}
}
@@ -242,13 +246,12 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB
bool valuesChanged = true;
while (valuesChanged)
{
- if (getenv("EVMCC_DEBUG_BLOCKS"))
+ for (auto& pair : cfg)
{
- for (auto& pair : cfg)
- std::cerr << pair.second.bblock.llvm()->getName().str()
- << ": in " << pair.second.inputItems
- << ", out " << pair.second.outputItems
- << "\n";
+ DLOG(bb) << pair.second.bblock.llvm()->getName().str()
+ << ": in " << pair.second.inputItems
+ << ", out " << pair.second.outputItems
+ << "\n";
}
valuesChanged = false;
@@ -256,6 +259,9 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB
{
auto& info = pair.second;
+ if (&info.bblock == basicBlocks.front())
+ info.inputItems = 0; // we cannot use phi nodes for first block as it is a successor of entry block
+
if (info.predecessors.empty())
info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false
@@ -340,6 +346,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput)
{
if (val == nullptr)
out << " ?";
+ else if (llvm::isa(val))
+ out << " " << val->getName();
else if (llvm::isa(val))
out << *val;
else
@@ -361,6 +369,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput)
{
if (*val == nullptr)
out << " ?";
+ else if (llvm::isa(*val))
+ out << " " << (*val)->getName();
else if (llvm::isa(*val))
out << **val;
else
diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h
index 7469b7b69..5e19235a7 100644
--- a/evmjit/libevmjit/BasicBlock.h
+++ b/evmjit/libevmjit/BasicBlock.h
@@ -33,6 +33,9 @@ public:
/// @param _index Index of value to be swaped. Must be > 0.
void swap(size_t _index);
+ size_t getMaxSize() const { return m_maxSize; }
+ int getDiff() const { return m_bblock.m_tosOffset; }
+
private:
LocalStack(BasicBlock& _owner);
LocalStack(LocalStack const&) = delete;
@@ -49,6 +52,7 @@ public:
private:
BasicBlock& m_bblock;
+ size_t m_maxSize = 0; ///< Max size reached by the stack.
};
explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
diff --git a/evmjit/libevmjit/BuildInfo.h.in b/evmjit/libevmjit/BuildInfo.h.in
index 204b4d89b..4b72144ed 100644
--- a/evmjit/libevmjit/BuildInfo.h.in
+++ b/evmjit/libevmjit/BuildInfo.h.in
@@ -8,3 +8,4 @@
#define LLVM_VERSION "${LLVM_PACKAGE_VERSION}"
#define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}"
+#define LLVM_DEBUG ${LLVM_DEBUG}
diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt
index 943c64e42..7f4e763d7 100644
--- a/evmjit/libevmjit/CMakeLists.txt
+++ b/evmjit/libevmjit/CMakeLists.txt
@@ -1,9 +1,29 @@
set(TARGET_NAME evmjit)
-file(GLOB SOURCES "*.cpp")
-file(GLOB HEADERS "*.h")
-set(INTERFACE_HEADERS interface.h)
-source_group("" FILES ${HEADERS})
+set(SOURCES
+ Arith256.cpp Arith256.h
+ Array.cpp Array.h
+ BasicBlock.cpp BasicBlock.h
+ Cache.cpp Cache.h
+ Common.h
+ Compiler.cpp Compiler.h
+ CompilerHelper.cpp CompilerHelper.h
+ Endianness.cpp Endianness.h
+ ExecStats.cpp ExecStats.h
+ ExecutionEngine.cpp ExecutionEngine.h
+ Ext.cpp Ext.h
+ GasMeter.cpp GasMeter.h
+ Instruction.cpp Instruction.h
+ interface.cpp interface.h
+ Memory.cpp Memory.h
+ Optimizer.cpp Optimizer.h
+ Runtime.cpp Runtime.h
+ RuntimeData.h
+ RuntimeManager.cpp RuntimeManager.h
+ Stack.cpp Stack.h
+ Type.cpp Type.h
+ Utils.cpp Utils.h
+)
source_group("" FILES ${SOURCES})
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
@@ -48,11 +68,13 @@ else()
set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR})
endif()
+
+string(COMPARE EQUAL "${LLVM_ENABLE_ASSERTIONS}" "ON" LLVM_DEBUG)
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)
+add_library(${TARGET_NAME} SHARED ${SOURCES} gen/BuildInfo.gen.h)
set_target_properties(${TARGET_NAME} PROPERTIES
VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION}
FOLDER "libs")
@@ -62,7 +84,4 @@ 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
index fe226eefb..47a6386e9 100644
--- a/evmjit/libevmjit/Cache.cpp
+++ b/evmjit/libevmjit/Cache.cpp
@@ -1,12 +1,10 @@
#include "Cache.h"
-#include
-#include
-
#include "preprocessor/llvm_includes_start.h"
#include
#include
#include