diff --git a/CMakeLists.txt b/CMakeLists.txt index 579905c93..69a6ebb7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,6 @@ set(D_TESTS ON) set(D_FATDB ON) set(D_ETHASHCL ON) set(D_ETHASHCUDA OFF) -set(D_EVMJIT ON) set(D_JSCONSOLE ON) set(D_JSONRPC ON) set(D_VMTRACE OFF) @@ -112,7 +111,6 @@ elseif (BUNDLE STREQUAL "wallet") set(D_FATDB OFF) set(D_JSONRPC OFF) set(D_JSCONSOLE OFF) - set(D_EVMJIT OFF) elseif (BUNDLE STREQUAL "miner") set(D_SERPENT OFF) set(D_USENPM OFF) @@ -124,7 +122,6 @@ elseif (BUNDLE STREQUAL "miner") set(D_FATDB OFF) set(D_JSONRPC ON) set(D_JSCONSOLE OFF) - set(D_EVMJIT OFF) elseif (BUNDLE STREQUAL "cudaminer") set(D_SERPENT OFF) set(D_USENPM OFF) @@ -137,7 +134,6 @@ elseif (BUNDLE STREQUAL "cudaminer") set(D_FATDB OFF) set(D_JSONRPC ON) set(D_JSCONSOLE OFF) - set(D_EVMJIT OFF) elseif (BUNDLE STREQUAL "release") # release builds set(D_SERPENT ${DECENT_PLATFORM}) set(D_USENPM OFF) @@ -146,7 +142,6 @@ elseif (BUNDLE STREQUAL "release") # release builds set(D_TESTS OFF) set(D_FATDB OFF) set(D_ETHASHCL ON) - set(D_EVMJIT ON) set(D_JSCONSOLE ON) set(D_JSONRPC ON) set(D_CMAKE_BUILD_TYPE "Release") @@ -174,10 +169,6 @@ function(configureProject) add_definitions(-DETH_ETHASHCUDA) endif() - if (EVMJIT) - add_definitions(-DETH_EVMJIT) - endif() - if (FATDB) add_definitions(-DETH_FATDB) endif() @@ -222,11 +213,7 @@ function(createBuildInfo) set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/unknown") endif () - if (EVMJIT) - set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/JIT") - else () - set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/int") - endif () + set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/int") if (PARANOID) set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/PARA") @@ -294,7 +281,6 @@ endmacro() # Normalise build options eth_format_option(PARANOID) eth_format_option(VMTRACE) -eth_format_option(EVMJIT) eth_format_option(FATDB) eth_format_option(JSONRPC) eth_format_option(MINER) @@ -358,7 +344,6 @@ message("-- TESTS Build tests ${TESTS}") message("-- ETHASHCL Build OpenCL components ${ETHASHCL}") message("-- ETHASHCUDA Build CUDA components ${ETHASHCUDA}") message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}") -message("-- EVMJIT Build LLVM-based JIT EVM ${EVMJIT}") message("------------------------------------------------------------------------") message("") @@ -382,23 +367,6 @@ else() set(DB_LIBRARIES ${LEVELDB_LIBRARIES}) endif() -if (EVMJIT) - if (NOT DEFINED LLVM_DIR) - if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(LLVM_DIR "${CMAKE_SOURCE_DIR}/extdep/install/windows/x64/share/llvm/cmake") - elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set(LLVM_DIR "/usr/local/opt/llvm/share/llvm/cmake") - endif() - endif() - - set(EVMJIT_CPP TRUE) # include CPP-JIT connector - add_subdirectory(evmjit) - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - set(EVMJIT_DLLS_LOCAL $) - set(EVMJIT_DLLS optimized ${EVMJIT_DLLS_LOCAL} debug ${EVMJIT_DLLS_LOCAL}) - endif() -endif() - if (TOOLS OR GUI OR TESTS) set(GENERAL 1) else () diff --git a/evmjit/.gitignore b/evmjit/.gitignore deleted file mode 100644 index 84c048a73..000000000 --- a/evmjit/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build/ diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt deleted file mode 100644 index 49bf7f73d..000000000 --- a/evmjit/CMakeLists.txt +++ /dev/null @@ -1,65 +0,0 @@ -cmake_minimum_required(VERSION 2.8.12) - -if (${CMAKE_VERSION} VERSION_GREATER 3.0) - cmake_policy(SET CMP0042 OLD) # fix MACOSX_RPATH - cmake_policy(SET CMP0048 NEW) # allow VERSION argument in project() - project(EVMJIT VERSION 0.9.0.1 LANGUAGES CXX) -else() - project(EVMJIT) - set(EVMJIT_VERSION "0.9.0.1") - set(EVMJIT_VERSION_MAJOR 0) - set(EVMJIT_VERSION_MINOR 9) - set(EVMJIT_VERSION_PATCH 0) - set(EVMJIT_VERSION_TWEAK 1) -endif() - -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-sign-conversion -Wno-unknown-pragmas ${CMAKE_CXX_FLAGS}") -endif() - -if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ${CMAKE_BUILD_TYPE} STREQUAL "DebugSan") - # Do not allow unresovled symbols in shared library (default on linux) - set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") -endif() - -# LLVM -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT LLVM_DIR) - # Workaround for Ubuntu broken LLVM package - find_program(LLVM3_7_CONFIG llvm-config-3.7) - find_program(LLVM3_8_CONFIG llvm-config-3.8) - if (LLVM3_7_CONFIG) - message(STATUS "Using llvm-3.7-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") - set(LLVM_CONFIG_EXEC llvm-config-3.7) - set(LLVM_LIB_DIR /usr/lib/llvm-3.7/lib) - elseif(LLVM3_8_CONFIG) - message(STATUS "Using llvm-3.8-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") - set(LLVM_CONFIG_EXEC llvm-config-3.8) - set(LLVM_LIB_DIR /usr/lib/llvm-3.8/lib) - else() - message(FATAL_ERROR "No LLVM package found!") - endif() - - execute_process(COMMAND ${LLVM_CONFIG_EXEC} --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS OUTPUT_STRIP_TRAILING_WHITESPACE) - message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") - set(LLVM_LIBS "-lLLVMipo -lLLVMVectorize -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info -lLLVMMCDisassembler -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMProfileData -lLLVMInstCombine -lLLVMInstrumentation -lLLVMTransformUtils -lLLVMipa -lLLVMMCJIT -lLLVMExecutionEngine -lLLVMTarget -lLLVMAnalysis -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") - set(LLVM_DEFINITIONS "-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS") - link_directories(${LLVM_LIB_DIR}) -else() - find_package(LLVM REQUIRED CONFIG) - if (${LLVM_VERSION} VERSION_LESS 3.7) - message(FATAL_ERROR "Incompatible LLVM version ${LLVM_VERSION}") - endif() - message(STATUS "Found LLVM ${LLVM_VERSION}") - message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen ipo) -endif() - -add_subdirectory(libevmjit) - -if(EVMJIT_CPP) - add_subdirectory(libevmjit-cpp) -endif() diff --git a/evmjit/LICENSE.md b/evmjit/LICENSE.md deleted file mode 100644 index 630157f98..000000000 --- a/evmjit/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index fe8bc9de6..000000000 --- a/evmjit/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# 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 variable, e.g. `EVMJIT="-help" testeth --jit`. diff --git a/evmjit/include/evmjit/JIT-c.h b/evmjit/include/evmjit/JIT-c.h deleted file mode 100644 index 4e0993ab7..000000000 --- a/evmjit/include/evmjit/JIT-c.h +++ /dev/null @@ -1,70 +0,0 @@ - -#include "stdint.h" - -#ifdef _MSC_VER -#define EXPORT __declspec(dllexport) -#define _ALLOW_KEYWORD_MACROS -#define noexcept throw() -#else -#define EXPORT -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct evmjit_i256 -{ - uint64_t words[4]; -} evmjit_i256; - -typedef struct evmjit_runtime_data -{ - int64_t gas; - int64_t gasPrice; - char const* callData; - uint64_t callDataSize; - evmjit_i256 address; - evmjit_i256 caller; - evmjit_i256 origin; - evmjit_i256 callValue; - evmjit_i256 coinBase; - evmjit_i256 difficulty; - evmjit_i256 gasLimit; - uint64_t number; - int64_t timestamp; - char const* code; - uint64_t codeSize; - evmjit_i256 codeHash; -} evmjit_runtime_data; - -typedef enum evmjit_return_code -{ - // Success codes - Stop = 0, - Return = 1, - Suicide = 2, - - // Standard error codes - OutOfGas = -1, - - // Internal error codes - LLVMError = -101, - UnexpectedException = -111 -} evmjit_return_code; - -typedef struct evmjit_context evmjit_context; - -EXPORT evmjit_context* evmjit_create(evmjit_runtime_data* _data, void* _env); - -EXPORT evmjit_return_code evmjit_exec(evmjit_context* _context); - -EXPORT void evmjit_destroy(evmjit_context* _context); - - -inline char const* evmjit_get_output(evmjit_runtime_data* _data) { return _data->callData; } -inline uint64_t evmjit_get_output_size(evmjit_runtime_data* _data) { return _data->callDataSize; } - -#ifdef __cplusplus -} -#endif diff --git a/evmjit/include/evmjit/JIT.h b/evmjit/include/evmjit/JIT.h deleted file mode 100644 index 285a33218..000000000 --- a/evmjit/include/evmjit/JIT.h +++ /dev/null @@ -1,172 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifdef _MSC_VER -#define EXPORT __declspec(dllexport) -#define _ALLOW_KEYWORD_MACROS -#define noexcept throw() -#else -#define EXPORT -#endif - -namespace dev -{ -namespace evmjit -{ - -using byte = uint8_t; -using bytes_ref = std::tuple; - -/// Representation of 256-bit hash value -struct h256 -{ - uint64_t words[4]; -}; - -inline bool operator==(h256 const& _h1, h256 const& _h2) -{ - return _h1.words[0] == _h2.words[0] && - _h1.words[1] == _h2.words[1] && - _h1.words[2] == _h2.words[2] && - _h1.words[3] == _h2.words[3]; -} - -/// Representation of 256-bit value binary compatible with LLVM i256 -struct i256 -{ - uint64_t words[4]; - - i256() = default; - i256(h256 const& _h) { std::memcpy(this, &_h, sizeof(*this)); } -}; - -// TODO: Merge with ExecutionContext -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) - }; - - static size_t const numElements = CodeSize + 1; - - 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; - h256 codeHash; -}; - -/// VM Environment (ExtVM) opaque type -struct Env; - -enum class ReturnCode -{ - // Success codes - Stop = 0, - Return = 1, - Suicide = 2, - - // Standard error codes - OutOfGas = -1, - - // Internal error codes - LLVMError = -101, - - UnexpectedException = -111, - - LinkerWorkaround = -299, -}; - -class ExecutionContext -{ -public: - ExecutionContext() = default; - ExecutionContext(RuntimeData& _data, Env* _env) { init(_data, _env); } - ExecutionContext(ExecutionContext const&) = delete; - ExecutionContext& operator=(ExecutionContext const&) = delete; - EXPORT ~ExecutionContext() noexcept; - - void init(RuntimeData& _data, Env* _env) { m_data = &_data; m_env = _env; } - - byte const* code() const { return m_data->code; } - uint64_t codeSize() const { return m_data->codeSize; } - h256 const& codeHash() const { return m_data->codeHash; } - - bytes_ref getReturnData() const; - -protected: - RuntimeData* m_data = nullptr; ///< Pointer to data. Expected by compiled contract. - Env* m_env = nullptr; ///< Pointer to environment proxy. Expected by compiled contract. - byte* m_memData = nullptr; - uint64_t m_memSize = 0; - uint64_t m_memCap = 0; - -public: - /// Reference to returned data (RETURN opcode used) - bytes_ref returnData; -}; - -class JIT -{ -public: - - /// Ask JIT if the EVM code is ready for execution. - /// Returns `true` if the EVM code has been compiled and loaded into memory. - /// In this case the code can be executed without overhead. - /// \param _codeHash The Keccak hash of the EVM code. - EXPORT static bool isCodeReady(h256 const& _codeHash); - - /// Compile the given EVM code to machine code and make available for execution. - EXPORT static void compile(byte const* _code, uint64_t _codeSize, h256 const& _codeHash); - - EXPORT static ReturnCode exec(ExecutionContext& _context); -}; - -} -} - -namespace std -{ -template<> struct hash -{ - size_t operator()(dev::evmjit::h256 const& _h) const - { - /// This implementation expects the argument to be a full 256-bit Keccak hash. - /// It does nothing more than returning a slice of the input hash. - return static_cast(_h.words[0]); - }; -}; -} diff --git a/evmjit/libevmjit-cpp/CMakeLists.txt b/evmjit/libevmjit-cpp/CMakeLists.txt deleted file mode 100644 index 142687726..000000000 --- a/evmjit/libevmjit-cpp/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -set(TARGET_NAME evmjit-cpp) - -# Boost -find_package(Boost REQUIRED) - -set(SOURCES - Env.cpp - JitVM.cpp JitVM.h - Utils.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} STATIC ${SOURCES}) -set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") - -include_directories(../..) -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 deleted file mode 100644 index 54745a8b4..000000000 --- a/evmjit/libevmjit-cpp/Env.cpp +++ /dev/null @@ -1,135 +0,0 @@ - -#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 evmjit::i256; - - EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) - { - auto index = jit2eth(*_index); - auto value = _env->store(index); // Interface uses native endianness - *o_value = eth2jit(value); - } - - EXPORT void env_sstore(ExtVMFace* _env, i256* _index, i256* _value) - { - auto index = jit2eth(*_index); - auto value = jit2eth(*_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 = eth2jit(u); - } - - EXPORT void env_blockhash(ExtVMFace* _env, i256* _number, h256* o_hash) - { - *o_hash = _env->blockHash(jit2eth(*_number)); - } - - EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) - { - auto endowment = jit2eth(*_endowment); - if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) - { - u256 gas = *io_gas; - h256 address(_env->create(endowment, gas, {_initBeg, (size_t)_initSize}, {}), h256::AlignRight); - *io_gas = static_cast(gas); - *o_address = address; - } - else - *o_address = {}; - } - - 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) - { - CallParameters params; - params.value = jit2eth(*_value); - params.senderAddress = _env->myAddress; - params.receiveAddress = right160(*_receiveAddress); - params.codeAddress = right160(*_codeAddress); - params.data = {_inBeg, (size_t)_inSize}; - params.out = {_outBeg, (size_t)_outSize}; - params.onOp = {}; - const auto isCall = params.receiveAddress == params.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(params.receiveAddress)) - *io_gas -= static_cast(c_callNewAccountGas); // no underflow, *io_gas non-negative before - - if (params.value > 0) // value transfer - { - /*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 - } - - if (*io_gas < 0) - return false; - - auto ret = false; - params.gas = u256{_callGas}; - if (_env->balance(_env->myAddress) >= params.value && _env->depth < 1024) - ret = _env->call(params); - - *io_gas += static_cast(params.gas); // it is never more than initial _callGas - return ret; - } - - EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) - { - auto hash = sha3({_begin, (size_t)_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_t)_size}); - } -} - diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp deleted file mode 100644 index 6db58b594..000000000 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ /dev/null @@ -1,77 +0,0 @@ - -#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::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) -{ - auto rejected = false; - // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope - rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) - rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.envInfo().number() > std::numeric_limits::max(); - rejected |= _ext.envInfo().timestamp() > std::numeric_limits::max(); - - if (rejected) - { - cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter"; - m_fallbackVM = VMFactory::create(VMKind::Interpreter); - return m_fallbackVM->execImpl(io_gas, _ext, _onOp); - } - - m_data.gas = static_cast(io_gas); - m_data.gasPrice = static_cast(_ext.gasPrice); - m_data.callData = _ext.data.data(); - m_data.callDataSize = _ext.data.size(); - m_data.address = eth2jit(fromAddress(_ext.myAddress)); - m_data.caller = eth2jit(fromAddress(_ext.caller)); - m_data.origin = eth2jit(fromAddress(_ext.origin)); - m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.envInfo().beneficiary())); - m_data.difficulty = eth2jit(_ext.envInfo().difficulty()); - m_data.gasLimit = eth2jit(_ext.envInfo().gasLimit()); - m_data.number = static_cast(_ext.envInfo().number()); - m_data.timestamp = static_cast(_ext.envInfo().timestamp()); - m_data.code = _ext.code.data(); - m_data.codeSize = _ext.code.size(); - m_data.codeHash = eth2jit(_ext.codeHash); - - // Pass pointer to ExtVMFace casted to evmjit::Env* opaque type. - // JIT will do nothing with the pointer, just pass it to Env callback functions implemented in Env.cpp. - m_context.init(m_data, reinterpret_cast(&_ext)); - auto exitCode = evmjit::JIT::exec(m_context); - switch (exitCode) - { - case evmjit::ReturnCode::Suicide: - _ext.suicide(right160(jit2eth(m_data.address))); - break; - - case evmjit::ReturnCode::OutOfGas: - BOOST_THROW_EXCEPTION(OutOfGas()); - case evmjit::ReturnCode::LinkerWorkaround: // never happens - env_sload(); // but forces linker to include env_* JIT callback functions - break; - default: - break; - } - - io_gas = m_data.gas; - return {std::get<0>(m_context.returnData), std::get<1>(m_context.returnData)}; -} - -} -} diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h deleted file mode 100644 index 43933ebe4..000000000 --- a/evmjit/libevmjit-cpp/JitVM.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include - -namespace dev -{ -namespace eth -{ - -class JitVM: public VMFace -{ -public: - virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final; - -private: - evmjit::RuntimeData m_data; - evmjit::ExecutionContext m_context; - 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 deleted file mode 100644 index ebb6ad97d..000000000 --- a/evmjit/libevmjit-cpp/Utils.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -namespace dev -{ -namespace eth -{ - -/// Converts EVM JIT representation of 256-bit integer to eth type dev::u256. -inline u256 jit2eth(evmjit::i256 _i) -{ - u256 u = _i.words[3]; - u <<= 64; - u |= _i.words[2]; - u <<= 64; - u |= _i.words[1]; - u <<= 64; - u |= _i.words[0]; - return u; -} - -/// Converts eth type dev::u256 to EVM JIT representation of 256-bit integer. -inline evmjit::i256 eth2jit(u256 _u) -{ - evmjit::i256 i; - i.words[0] = static_cast(_u); - _u >>= 64; - i.words[1] = static_cast(_u); - _u >>= 64; - i.words[2] = static_cast(_u); - _u >>= 64; - i.words[3] = static_cast(_u); - return i; -} - -/// Converts eth type dev::h256 to EVM JIT representation of 256-bit hash value. -inline evmjit::h256 eth2jit(h256 _u) -{ - /// Just directly copies memory - return *(evmjit::h256*)&_u; -} - -} -} diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp deleted file mode 100644 index 76c53c78d..000000000 --- a/evmjit/libevmjit/Arith256.cpp +++ /dev/null @@ -1,508 +0,0 @@ -#include "Arith256.h" - -#include -#include - -#include "preprocessor/llvm_includes_start.h" -#include -#include -#include "preprocessor/llvm_includes_end.h" - -#include "Type.h" -#include "Endianness.h" -#include "Utils.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(llvm::Module& _module) -{ - static const auto funcName = "evm.mul.i256"; - if (auto func = _module.getFunction(funcName)) - return func; - - llvm::Type* argTypes[] = {Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, funcName, &_module); - func->setDoesNotThrow(); - func->setDoesNotAccessMemory(); - - auto x = &func->getArgumentList().front(); - x->setName("x"); - auto y = x->getNextNode(); - y->setName("y"); - - auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func); - auto builder = llvm::IRBuilder<>{bb}; - auto i64 = Type::Size; - auto i128 = 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 = builder.CreateTrunc(x, i64, "x.lo"); - auto y_lo = builder.CreateTrunc(y, i64, "y.lo"); - auto x_mi = builder.CreateTrunc(builder.CreateLShr(x, c64), i64); - auto y_mi = builder.CreateTrunc(builder.CreateLShr(y, c64), i64); - auto x_hi = builder.CreateTrunc(builder.CreateLShr(x, c128), i128); - auto y_hi = builder.CreateTrunc(builder.CreateLShr(y, c128), i128); - - auto t1 = builder.CreateMul(builder.CreateZExt(x_lo, i128), builder.CreateZExt(y_lo, i128)); - auto t2 = builder.CreateMul(builder.CreateZExt(x_lo, i128), builder.CreateZExt(y_mi, i128)); - auto t3 = builder.CreateMul(builder.CreateZExt(x_lo, i128), y_hi); - auto t4 = builder.CreateMul(builder.CreateZExt(x_mi, i128), builder.CreateZExt(y_lo, i128)); - auto t5 = builder.CreateMul(builder.CreateZExt(x_mi, i128), builder.CreateZExt(y_mi, i128)); - auto t6 = builder.CreateMul(builder.CreateZExt(x_mi, i128), y_hi); - auto t7 = builder.CreateMul(x_hi, builder.CreateZExt(y_lo, i128)); - auto t8 = builder.CreateMul(x_hi, builder.CreateZExt(y_mi, i128)); - - auto p = builder.CreateZExt(t1, i256); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t2, i256), c64)); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t3, i256), c128)); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t4, i256), c64)); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t5, i256), c128)); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t6, i256), c192)); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t7, i256), c128)); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t8, i256), c192)); - builder.CreateRet(p); - return func; -} - -llvm::Function* Arith256::getMul512Func(llvm::Module& _module) -{ - static const auto funcName = "evm.mul.i512"; - if (auto func = _module.getFunction(funcName)) - return func; - - auto i512Ty = llvm::IntegerType::get(_module.getContext(), 512); - auto func = llvm::Function::Create(llvm::FunctionType::get(i512Ty, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module); - func->setDoesNotThrow(); - func->setDoesNotAccessMemory(); - - auto x = &func->getArgumentList().front(); - x->setName("x"); - auto y = x->getNextNode(); - y->setName("y"); - - auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func); - auto builder = llvm::IRBuilder<>{bb}; - - auto i128 = builder.getIntNTy(128); - auto i256 = Type::Word; - auto x_lo = builder.CreateZExt(builder.CreateTrunc(x, i128, "x.lo"), i256); - auto y_lo = builder.CreateZExt(builder.CreateTrunc(y, i128, "y.lo"), i256); - auto x_hi = builder.CreateZExt(builder.CreateTrunc(builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256); - auto y_hi = builder.CreateZExt(builder.CreateTrunc(builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256); - - auto mul256Func = getMulFunc(_module); - auto t1 = builder.CreateCall(mul256Func, {x_lo, y_lo}); - auto t2 = builder.CreateCall(mul256Func, {x_lo, y_hi}); - auto t3 = builder.CreateCall(mul256Func, {x_hi, y_lo}); - auto t4 = builder.CreateCall(mul256Func, {x_hi, y_hi}); - - auto p = builder.CreateZExt(t1, i512Ty); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t2, i512Ty), builder.getIntN(512, 128))); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t3, i512Ty), builder.getIntN(512, 128))); - p = builder.CreateAdd(p, builder.CreateShl(builder.CreateZExt(t4, i512Ty), builder.getIntN(512, 256))); - builder.CreateRet(p); - - return func; -} - -namespace -{ -llvm::Function* createUDivRemFunc(llvm::Type* _type, llvm::Module& _module, char const* _funcName) -{ - // 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 remainder - - auto retType = llvm::VectorType::get(_type, 2); - auto func = llvm::Function::Create(llvm::FunctionType::get(retType, {_type, _type}, false), llvm::Function::PrivateLinkage, _funcName, &_module); - func->setDoesNotThrow(); - func->setDoesNotAccessMemory(); - - 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"); - - auto entryBB = llvm::BasicBlock::Create(_module.getContext(), "Entry", func); - auto mainBB = llvm::BasicBlock::Create(_module.getContext(), "Main", func); - auto loopBB = llvm::BasicBlock::Create(_module.getContext(), "Loop", func); - auto continueBB = llvm::BasicBlock::Create(_module.getContext(), "Continue", func); - auto returnBB = llvm::BasicBlock::Create(_module.getContext(), "Return", func); - - auto builder = llvm::IRBuilder<>{entryBB}; - auto yLEx = builder.CreateICmpULE(yArg, x); - auto r0 = x; - builder.CreateCondBr(yLEx, mainBB, returnBB); - - builder.SetInsertPoint(mainBB); - auto ctlzIntr = llvm::Intrinsic::getDeclaration(&_module, llvm::Intrinsic::ctlz, _type); - // both y and r are non-zero - auto yLz = builder.CreateCall(ctlzIntr, {yArg, builder.getInt1(true)}, "y.lz"); - auto rLz = builder.CreateCall(ctlzIntr, {r0, builder.getInt1(true)}, "r.lz"); - auto i0 = builder.CreateNUWSub(yLz, rLz, "i0"); - auto y0 = builder.CreateShl(yArg, i0); - builder.CreateBr(loopBB); - - builder.SetInsertPoint(loopBB); - auto yPhi = builder.CreatePHI(_type, 2, "y.phi"); - auto rPhi = builder.CreatePHI(_type, 2, "r.phi"); - auto iPhi = builder.CreatePHI(_type, 2, "i.phi"); - auto qPhi = builder.CreatePHI(_type, 2, "q.phi"); - auto rUpdate = builder.CreateNUWSub(rPhi, yPhi); - auto qUpdate = builder.CreateOr(qPhi, one); // q += 1, q lowest bit is 0 - auto rGEy = builder.CreateICmpUGE(rPhi, yPhi); - auto r1 = builder.CreateSelect(rGEy, rUpdate, rPhi, "r1"); - auto q1 = builder.CreateSelect(rGEy, qUpdate, qPhi, "q"); - auto iZero = builder.CreateICmpEQ(iPhi, zero); - builder.CreateCondBr(iZero, returnBB, continueBB); - - builder.SetInsertPoint(continueBB); - auto i2 = builder.CreateNUWSub(iPhi, one); - auto q2 = builder.CreateShl(q1, one); - auto y2 = builder.CreateLShr(yPhi, one); - 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); - - builder.SetInsertPoint(returnBB); - auto qRet = builder.CreatePHI(_type, 2, "q.ret"); - qRet->addIncoming(zero, entryBB); - qRet->addIncoming(q1, loopBB); - auto rRet = builder.CreatePHI(_type, 2, "r.ret"); - rRet->addIncoming(r0, entryBB); - rRet->addIncoming(r1, loopBB); - auto ret = builder.CreateInsertElement(llvm::UndefValue::get(retType), qRet, uint64_t(0), "ret0"); - ret = builder.CreateInsertElement(ret, rRet, 1, "ret"); - builder.CreateRet(ret); - - return func; -} -} - -llvm::Function* Arith256::getUDivRem256Func(llvm::Module& _module) -{ - static const auto funcName = "evm.udivrem.i256"; - if (auto func = _module.getFunction(funcName)) - return func; - - return createUDivRemFunc(Type::Word, _module, funcName); -} - -llvm::Function* Arith256::getUDivRem512Func(llvm::Module& _module) -{ - static const auto funcName = "evm.udivrem.i512"; - if (auto func = _module.getFunction(funcName)) - return func; - - return createUDivRemFunc(llvm::IntegerType::get(_module.getContext(), 512), _module, funcName); -} - -llvm::Function* Arith256::getUDiv256Func(llvm::Module& _module) -{ - static const auto funcName = "evm.udiv.i256"; - if (auto func = _module.getFunction(funcName)) - return func; - - auto udivremFunc = getUDivRem256Func(_module); - - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module); - func->setDoesNotThrow(); - func->setDoesNotAccessMemory(); - - auto x = &func->getArgumentList().front(); - x->setName("x"); - auto y = x->getNextNode(); - y->setName("y"); - - auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func); - auto builder = llvm::IRBuilder<>{bb}; - auto udivrem = builder.CreateCall(udivremFunc, {x, y}); - auto udiv = builder.CreateExtractElement(udivrem, uint64_t(0)); - builder.CreateRet(udiv); - - return func; -} - -namespace -{ -llvm::Function* createURemFunc(llvm::Type* _type, llvm::Module& _module, char const* _funcName) -{ - auto udivremFunc = _type == Type::Word ? Arith256::getUDivRem256Func(_module) : Arith256::getUDivRem512Func(_module); - - auto func = llvm::Function::Create(llvm::FunctionType::get(_type, {_type, _type}, false), llvm::Function::PrivateLinkage, _funcName, &_module); - func->setDoesNotThrow(); - func->setDoesNotAccessMemory(); - - auto x = &func->getArgumentList().front(); - x->setName("x"); - auto y = x->getNextNode(); - y->setName("y"); - - auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func); - auto builder = llvm::IRBuilder<>{bb}; - auto udivrem = builder.CreateCall(udivremFunc, {x, y}); - auto r = builder.CreateExtractElement(udivrem, uint64_t(1)); - builder.CreateRet(r); - - return func; -} -} - -llvm::Function* Arith256::getURem256Func(llvm::Module& _module) -{ - static const auto funcName = "evm.urem.i256"; - if (auto func = _module.getFunction(funcName)) - return func; - return createURemFunc(Type::Word, _module, funcName); -} - -llvm::Function* Arith256::getURem512Func(llvm::Module& _module) -{ - static const auto funcName = "evm.urem.i512"; - if (auto func = _module.getFunction(funcName)) - return func; - return createURemFunc(llvm::IntegerType::get(_module.getContext(), 512), _module, funcName); -} - -llvm::Function* Arith256::getSDivRem256Func(llvm::Module& _module) -{ - static const auto funcName = "evm.sdivrem.i256"; - if (auto func = _module.getFunction(funcName)) - return func; - - auto udivremFunc = getUDivRem256Func(_module); - - auto retType = llvm::VectorType::get(Type::Word, 2); - auto func = llvm::Function::Create(llvm::FunctionType::get(retType, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module); - func->setDoesNotThrow(); - func->setDoesNotAccessMemory(); - - auto x = &func->getArgumentList().front(); - x->setName("x"); - auto y = x->getNextNode(); - y->setName("y"); - - auto bb = llvm::BasicBlock::Create(_module.getContext(), "", func); - auto builder = llvm::IRBuilder<>{bb}; - auto xIsNeg = builder.CreateICmpSLT(x, Constant::get(0)); - auto xNeg = builder.CreateSub(Constant::get(0), x); - auto xAbs = builder.CreateSelect(xIsNeg, xNeg, x); - - auto yIsNeg = builder.CreateICmpSLT(y, Constant::get(0)); - auto yNeg = builder.CreateSub(Constant::get(0), y); - auto yAbs = builder.CreateSelect(yIsNeg, yNeg, y); - - auto res = builder.CreateCall(udivremFunc, {xAbs, yAbs}); - auto qAbs = builder.CreateExtractElement(res, uint64_t(0)); - auto rAbs = builder.CreateExtractElement(res, 1); - - // the remainder has the same sign as dividend - auto rNeg = builder.CreateSub(Constant::get(0), rAbs); - auto r = builder.CreateSelect(xIsNeg, rNeg, rAbs); - - auto qNeg = builder.CreateSub(Constant::get(0), qAbs); - auto xyOpposite = builder.CreateXor(xIsNeg, yIsNeg); - auto q = builder.CreateSelect(xyOpposite, qNeg, qAbs); - - auto ret = builder.CreateInsertElement(llvm::UndefValue::get(retType), q, uint64_t(0)); - ret = builder.CreateInsertElement(ret, r, 1); - builder.CreateRet(ret); - - return func; -} - -llvm::Function* Arith256::getSDiv256Func(llvm::Module& _module) -{ - static const auto funcName = "evm.sdiv.i256"; - if (auto func = _module.getFunction(funcName)) - return func; - - auto sdivremFunc = getSDivRem256Func(_module); - - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module); - func->setDoesNotThrow(); - func->setDoesNotAccessMemory(); - - auto x = &func->getArgumentList().front(); - x->setName("x"); - auto y = x->getNextNode(); - y->setName("y"); - - auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func); - auto builder = llvm::IRBuilder<>{bb}; - auto sdivrem = builder.CreateCall(sdivremFunc, {x, y}); - auto q = builder.CreateExtractElement(sdivrem, uint64_t(0)); - builder.CreateRet(q); - - return func; -} - -llvm::Function* Arith256::getSRem256Func(llvm::Module& _module) -{ - static const auto funcName = "evm.srem.i256"; - if (auto func = _module.getFunction(funcName)) - return func; - - auto sdivremFunc = getSDivRem256Func(_module); - - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module); - func->setDoesNotThrow(); - func->setDoesNotAccessMemory(); - - auto x = &func->getArgumentList().front(); - x->setName("x"); - auto y = x->getNextNode(); - y->setName("y"); - - auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func); - auto builder = llvm::IRBuilder<>{bb}; - auto sdivrem = builder.CreateCall(sdivremFunc, {x, y}); - auto r = builder.CreateExtractElement(sdivrem, uint64_t(1)); - builder.CreateRet(r); - - 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()); - m_exp->setDoesNotThrow(); - m_exp->setDoesNotAccessMemory(); - - 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 mul256Func = getMulFunc(*getModule()); - auto r0 = createCall(mul256Func, {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(mul256Func, {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::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}); -} - -} -} -} - -extern "C" -{ - EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) - { - 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/Arith256.h b/evmjit/libevmjit/Arith256.h deleted file mode 100644 index 81535a792..000000000 --- a/evmjit/libevmjit/Arith256.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class Arith256 : public CompilerHelper -{ -public: - Arith256(llvm::IRBuilder<>& _builder); - - llvm::Value* exp(llvm::Value* _arg1, llvm::Value* _arg2); - - void debug(llvm::Value* _value, char _c); - - static llvm::Function* getMulFunc(llvm::Module& _module); - static llvm::Function* getMul512Func(llvm::Module& _module); - static llvm::Function* getUDiv256Func(llvm::Module& _module); - static llvm::Function* getURem256Func(llvm::Module& _module); - static llvm::Function* getURem512Func(llvm::Module& _module); - static llvm::Function* getUDivRem256Func(llvm::Module& _module); - static llvm::Function* getSDiv256Func(llvm::Module& _module); - static llvm::Function* getSRem256Func(llvm::Module& _module); - static llvm::Function* getSDivRem256Func(llvm::Module& _module); - static llvm::Function* getUDivRem512Func(llvm::Module& _module); - -private: - llvm::Function* getExpFunc(); - - llvm::Function* m_exp = nullptr; - llvm::Function* m_debug = nullptr; -}; - - -} -} -} diff --git a/evmjit/libevmjit/Array.cpp b/evmjit/libevmjit/Array.cpp deleted file mode 100644 index 4f1f47d6e..000000000 --- a/evmjit/libevmjit/Array.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "Array.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#include -#include "preprocessor/llvm_includes_end.h" - -#include "RuntimeManager.h" -#include "Utils.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -static const auto c_reallocStep = 1; - -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(getType(), arrayPtr, 0, "dataPtr"); - auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr"); - auto capPtr = m_builder.CreateStructGEP(getType(), 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"); - 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(getType(), 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(getType(), 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(getType(), 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(getType(), arrayPtr, 1, "sizePtr"); - auto capPtr = m_builder.CreateStructGEP(getType(), 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_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_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array); -} - - -void Array::pop(llvm::Value* _count) -{ - auto sizePtr = m_builder.CreateStructGEP(getType(), 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(getType(), _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}); -} - -} -} -} - -extern "C" -{ - EXPORT void* ext_realloc(void* _data, size_t _size) noexcept - { - return std::realloc(_data, _size); - } - - EXPORT void ext_free(void* _data) noexcept - { - std::free(_data); - } -} diff --git a/evmjit/libevmjit/Array.h b/evmjit/libevmjit/Array.h deleted file mode 100644 index c85c8c1f9..000000000 --- a/evmjit/libevmjit/Array.h +++ /dev/null @@ -1,72 +0,0 @@ -#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(); }}; - LazyFunction m_setFunc = {[this](){ return createArraySetFunc(); }}; - LazyFunction m_getPtrFunc = {[this](){ return createGetPtrFunc(); }}; - LazyFunction m_getFunc = {[this](){ return createArrayGetFunc(); }}; - LazyFunction m_freeFunc = {[this](){ return createFreeFunc(); }}; - LazyFunction m_extendFunc = {[this](){ return createExtendFunc(); }}; - LazyFunction m_reallocFunc = {[this](){ return getReallocFunc(); }}; -}; - -} -} -} diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp deleted file mode 100644 index 6ded81c73..000000000 --- a/evmjit/libevmjit/BasicBlock.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "BasicBlock.h" - -#include - -#include "preprocessor/llvm_includes_start.h" -#include -#include -#include -#include -#include -#include "preprocessor/llvm_includes_end.h" - -#include "Type.h" -#include "Utils.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc): - m_firstInstrIdx{_firstInstrIdx}, - m_begin(_begin), - m_end(_end), - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_firstInstrIdx)}, _mainFunc)) -{} - -LocalStack::LocalStack(Stack& _globalStack): - m_global(_globalStack) -{} - -void LocalStack::push(llvm::Value* _value) -{ - assert(_value->getType() == Type::Word); - m_local.push_back(_value); - m_maxSize = std::max(m_maxSize, size()); -} - -llvm::Value* LocalStack::pop() -{ - auto item = get(0); - assert(!m_local.empty() || !m_input.empty()); - - if (m_local.size() > 0) - m_local.pop_back(); - else - ++m_globalPops; - - m_minSize = std::min(m_minSize, size()); - return item; -} - -/** - * Pushes a copy of _index-th element (tos is 0-th elem). - */ -void 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 LocalStack::swap(size_t _index) -{ - assert(_index > 0); - auto val = get(_index); - auto tos = get(0); - set(_index, tos); - set(0, val); -} - -llvm::Value* LocalStack::get(size_t _index) -{ - if (_index < m_local.size()) - return *(m_local.rbegin() + _index); // count from back - - auto idx = _index - m_local.size() + m_globalPops; - if (idx >= m_input.size()) - m_input.resize(idx + 1); - auto& item = m_input[idx]; - - if (!item) - { - item = m_global.get(idx); // Reach an item from global stack - m_minSize = std::min(m_minSize, -static_cast(idx) - 1); // and remember required stack size - } - - return item; -} - -void LocalStack::set(size_t _index, llvm::Value* _word) -{ - if (_index < m_local.size()) - { - *(m_local.rbegin() + _index) = _word; - return; - } - - auto idx = _index - m_local.size() + m_globalPops; - assert(idx < m_input.size()); - m_input[idx] = _word; -} - - -void LocalStack::finalize(llvm::IRBuilder<>& _builder, llvm::BasicBlock& _bb) -{ - auto blockTerminator = _bb.getTerminator(); - if (!blockTerminator || blockTerminator->getOpcode() != llvm::Instruction::Ret) - { - // Not needed in case of ret instruction. Ret invalidates the stack. - if (blockTerminator) - _builder.SetInsertPoint(blockTerminator); - else - _builder.SetInsertPoint(&_bb); - - // Update items fetched from global stack ignoring the poped ones - assert(m_globalPops <= m_input.size()); // pop() always does get() - for (auto i = m_globalPops; i < m_input.size(); ++i) - { - if (m_input[i]) - m_global.set(i, m_input[i]); - } - - // Add new items - auto pops = m_globalPops; // Copy pops counter to keep original value - for (auto& item: m_local) - { - if (pops) // Override poped global items - m_global.set(--pops, item); // using pops counter as the index - else - m_global.push(item); - } - - // Pop not overriden items - if (pops) - m_global.pop(pops); - } -} - - -} -} -} diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h deleted file mode 100644 index a6e420efc..000000000 --- a/evmjit/libevmjit/BasicBlock.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include - -#include "Common.h" -#include "Stack.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ -using namespace evmjit; -using instr_idx = uint64_t; - -class LocalStack -{ -public: - explicit LocalStack(Stack& _globalStack); - LocalStack(LocalStack const&) = delete; - void operator=(LocalStack const&) = delete; - - /// 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); - - ssize_t size() const { return static_cast(m_local.size()) - static_cast(m_globalPops); } - ssize_t minSize() const { return m_minSize; } - ssize_t maxSize() const { return m_maxSize; } - - /// Finalize local stack: check the requirements and update of the global stack. - void finalize(llvm::IRBuilder<>& _builder, llvm::BasicBlock& _bb); - -private: - /// 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); - - /// Items fetched from global stack. First element matches the top of the global stack. - /// Can contain nulls if some items has been skipped. - std::vector m_input; - - /// Local stack items that has not been pushed to global stack. First item is just above global stack. - std::vector m_local; - - Stack& m_global; ///< Reference to global stack. - - size_t m_globalPops = 0; ///< Number of items poped from global stack. In other words: global - local stack overlap. - ssize_t m_minSize = 0; ///< Minimum reached local stack size. Can be negative. - ssize_t m_maxSize = 0; ///< Maximum reached local stack size. -}; - -class BasicBlock -{ -public: - explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc); - - 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; } - -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; ///< Reference to the LLVM BasicBlock -}; - -} -} -} diff --git a/evmjit/libevmjit/BuildInfo.h.in b/evmjit/libevmjit/BuildInfo.h.in deleted file mode 100644 index bca9d0624..000000000 --- a/evmjit/libevmjit/BuildInfo.h.in +++ /dev/null @@ -1,9 +0,0 @@ - -#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 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 deleted file mode 100644 index 65a1beb72..000000000 --- a/evmjit/libevmjit/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -set(TARGET_NAME evmjit) - -get_filename_component(EVMJIT_INCLUDE_DIR ../include ABSOLUTE) - -set(SOURCES - JIT.cpp ${EVMJIT_INCLUDE_DIR}/evmjit/JIT.h - JIT-c.cpp ${EVMJIT_INCLUDE_DIR}/evmjit/JIT-c.h - 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 - Ext.cpp Ext.h - GasMeter.cpp GasMeter.h - Instruction.cpp Instruction.h - Memory.cpp Memory.h - Optimizer.cpp Optimizer.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") -else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") -endif() - -if(${EVMJIT_VERSION_MAJOR} EQUAL 0) - set(EVMJIT_SOVERSION "0.${EVMJIT_VERSION_MINOR}") -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}") - -add_library(${TARGET_NAME} SHARED ${SOURCES} gen/BuildInfo.gen.h) -set_target_properties(${TARGET_NAME} PROPERTIES - VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} - FOLDER "libs") - -target_include_directories(${TARGET_NAME} PUBLIC ${EVMJIT_INCLUDE_DIR}) -target_include_directories(${TARGET_NAME} PRIVATE ${LLVM_INCLUDE_DIRS}) -target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/gen) -target_compile_definitions(${TARGET_NAME} PRIVATE ${LLVM_DEFINITIONS}) -target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) - -install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) -install(DIRECTORY ${EVMJIT_INCLUDE_DIR} DESTINATION include) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp deleted file mode 100644 index f32175c72..000000000 --- a/evmjit/libevmjit/Cache.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "Cache.h" - -#include - -#include "preprocessor/llvm_includes_start.h" -#include -#include -#include -#include -#include -#include -#include -#include "preprocessor/llvm_includes_end.h" - -#include "ExecStats.h" -#include "Utils.h" -#include "BuildInfo.gen.h" - -namespace dev -{ -namespace evmjit -{ - -namespace -{ - using Guard = std::lock_guard; - std::mutex x_cacheMutex; - CacheMode g_mode; - std::unique_ptr g_lastObject; - JITListener* g_listener; - - llvm::StringRef getLibVersionStamp() - { - return EVMJIT_VERSION; - } -} - -ObjectCache* Cache::init(CacheMode _mode, JITListener* _listener) -{ - Guard g{x_cacheMutex}; - - g_mode = _mode; - g_listener = _listener; - - if (g_mode == CacheMode::clear) - { - Cache::clear(); - g_mode = CacheMode::off; - } - - if (g_mode != CacheMode::off) - { - static ObjectCache objectCache; - return &objectCache; - } - return nullptr; -} - -void Cache::clear() -{ - Guard g{x_cacheMutex}; - - using namespace llvm::sys; - llvm::SmallString<256> cachePath; - path::system_temp_directory(false, cachePath); - path::append(cachePath, "evm_objs"); - - std::error_code err; - for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err)) - fs::remove(it->path()); -} - -void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map& _funcCache) -{ - Guard g{x_cacheMutex}; - - // TODO: Cache dir should be in one place - using namespace llvm::sys; - llvm::SmallString<256> cachePath; - path::system_temp_directory(false, cachePath); - path::append(cachePath, "evm_objs"); - - // Disable listener - auto listener = g_listener; - g_listener = nullptr; - - std::error_code err; - for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err)) - { - auto name = it->path().substr(cachePath.size() + 1); - if (auto module = getObject(name)) - { - DLOG(cache) << "Preload: " << name << "\n"; - _ee.addModule(std::move(module)); - auto addr = _ee.getFunctionAddress(name); - assert(addr); - _funcCache[std::move(name)] = addr; - } - } - - g_listener = listener; -} - -std::unique_ptr Cache::getObject(std::string const& id) -{ - Guard g{x_cacheMutex}; - - if (g_mode != CacheMode::on && g_mode != CacheMode::read) - return nullptr; - - // TODO: Disabled because is not thread-safe. - //if (g_listener) - // g_listener->stateChanged(ExecState::CacheLoad); - - DLOG(cache) << 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 (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - { - auto& buf = r.get(); - auto expectedStamp = getLibVersionStamp(); - auto stampSize = expectedStamp.size(); - auto objStamp = buf->getBufferSize() >= stampSize ? llvm::StringRef{buf->getBufferEnd() - stampSize, stampSize} : llvm::StringRef{}; - if (objStamp == expectedStamp) - g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); - else - DLOG(cache) << "Unmatched version: " << objStamp.str() << ", expected " << expectedStamp.str() << "\n"; - } - else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) - DLOG(cache) << r.getError().message(); // TODO: Add warning log - - if (g_lastObject) // if object found create fake module - { - DLOG(cache) << 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; - } - DLOG(cache) << id << ": not found\n"; - return nullptr; -} - - -void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _object) -{ - Guard g{x_cacheMutex}; - - // Only in "on" and "write" mode - if (g_mode != CacheMode::on && g_mode != CacheMode::write) - return; - - // TODO: Disabled because is not thread-safe. - // 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())) - DLOG(cache) << "Cannot create cache dir " << cachePath.str().str() << "\n"; - - llvm::sys::path::append(cachePath, id); - - DLOG(cache) << id << ": write\n"; - std::error_code error; - llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); - cacheFile << _object.getBuffer() << getLibVersionStamp(); -} - -std::unique_ptr ObjectCache::getObject(llvm::Module const* _module) -{ - Guard g{x_cacheMutex}; - - DLOG(cache) << _module->getModuleIdentifier() << ": use\n"; - return std::move(g_lastObject); -} - -} -} diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h deleted file mode 100644 index 5de4222fc..000000000 --- a/evmjit/libevmjit/Cache.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include - -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - -namespace llvm -{ - class ExecutionEngine; -} - -namespace dev -{ -namespace evmjit -{ -class JITListener; - -enum class CacheMode -{ - on, - off, - read, - write, - clear, - preload -}; - -class ObjectCache : public llvm::ObjectCache -{ -public: - /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. - virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _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 std::unique_ptr getObject(llvm::Module const* _module) final override; -}; - - -class Cache -{ -public: - static ObjectCache* init(CacheMode _mode, JITListener* _listener); - static std::unique_ptr getObject(std::string const& id); - - /// Clears cache storage - static void clear(); - - /// Loads all available cached objects to ExecutionEngine - static void preload(llvm::ExecutionEngine& _ee, std::unordered_map& _funcCache); -}; - -} -} diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h deleted file mode 100644 index 4a6d7b4f3..000000000 --- a/evmjit/libevmjit/Common.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -namespace dev -{ -namespace evmjit -{ - -using byte = uint8_t; -using code_iterator = byte const*; - -#define UNTESTED assert(false) - -} -} diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp deleted file mode 100644 index 9bde352c3..000000000 --- a/evmjit/libevmjit/Compiler.cpp +++ /dev/null @@ -1,800 +0,0 @@ -#include "Compiler.h" - -#include -#include -#include -#include - -#include "preprocessor/llvm_includes_start.h" -#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 -{ - -static const auto c_destIdxLabel = "destIdx"; - -Compiler::Compiler(Options const& _options): - m_options(_options), - m_builder(llvm::getGlobalContext()) -{ - Type::init(m_builder.getContext()); -} - -std::vector Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd, llvm::SwitchInst& _jumpTable) -{ - /// 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; - }; - - // Skip all STOPs in the end - for (; _codeEnd != _codeBegin; --_codeEnd) - if (*(_codeEnd - 1) != static_cast(Instruction::STOP)) - break; - - std::vector blocks; - - auto begin = _codeBegin; // begin of current block - 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; - - default: - break; - } - - assert(next <= _codeEnd); - if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) - isEnd = true; - - if (isEnd) - { - auto beginIdx = begin - _codeBegin; - blocks.emplace_back(beginIdx, begin, next, m_mainFunc); - if (Instruction(*begin) == Instruction::JUMPDEST) - _jumpTable.addCase(Constant::get(beginIdx), blocks.back().llvm()); - begin = next; - } - } - - return blocks; -} - -void Compiler::resolveJumps() -{ - // Iterate through all EVM instructions blocks (skip first 4 - special blocks). - for (auto it = std::next(m_mainFunc->begin(), 4); it != m_mainFunc->end(); ++it) - { - auto jumpTable = llvm::cast(m_jumpTableBB->getTerminator()); - auto jumpTableInput = llvm::cast(m_jumpTableBB->begin()); - auto nextBlock = it->getNextNode() != m_mainFunc->end() ? it->getNextNode() : m_stopBB; - auto term = it->getTerminator(); - - if (!term) // Block may have no terminator if the next instruction is a jump destination. - llvm::IRBuilder<>{it}.CreateBr(nextBlock); - else if (auto jump = llvm::dyn_cast(term)) - if (jump->getSuccessor(0) == m_jumpTableBB) - { - auto destIdx = llvm::cast(jump->getMetadata(c_destIdxLabel)->getOperand(0))->getValue(); - if (auto constant = llvm::dyn_cast(destIdx)) - { - // If destination index is a constant do direct jump to the destination block. - auto bb = jumpTable->findCaseValue(constant).getCaseSuccessor(); - jump->setSuccessor(0, bb); - } - else - jumpTableInput->addIncoming(destIdx, it); // Fill up PHI node - - if (jump->isConditional()) - jump->setSuccessor(1, nextBlock); // Set next block for conditional jumps - } - } -} - -std::unique_ptr Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) -{ - 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_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); - m_jumpTableBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "JumpTable", m_mainFunc); - m_builder.SetInsertPoint(m_jumpTableBB); - auto target = m_builder.CreatePHI(Type::Word, 16, "target"); - auto& jumpTable = *m_builder.CreateSwitch(target, m_abortBB); - - m_builder.SetInsertPoint(entryBlock); - - auto blocks = createBasicBlocks(_begin, _end, jumpTable); - - // Init runtime structures. - RuntimeManager runtimeManager(m_builder, _begin, _end); - GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(runtimeManager, gasMeter); - Ext ext(runtimeManager, memory); - Stack stack(m_builder); - runtimeManager.setStack(stack); // Runtime Manager will free stack memory - Arith256 arith(m_builder); - - 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)); - runtimeManager.setJmpBuf(jmpBuf); - - auto firstBB = blocks.empty() ? m_stopBB : blocks.front().llvm(); - m_builder.CreateCondBr(normalFlow, firstBB, m_abortBB, Type::expectTrue); - - for (auto& block: blocks) - compileBasicBlock(block, runtimeManager, arith, memory, ext, gasMeter, stack); - - // Code for special blocks: - m_builder.SetInsertPoint(m_stopBB); - runtimeManager.exit(ReturnCode::Stop); - - m_builder.SetInsertPoint(m_abortBB); - runtimeManager.exit(ReturnCode::OutOfGas); - - resolveJumps(); - - return module; -} - - -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager, - Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, Stack& _globalStack) -{ - m_builder.SetInsertPoint(_basicBlock.llvm()); - LocalStack stack{_globalStack}; - - 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 = m_builder.CreateMul(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::DIV: - { - auto d = stack.pop(); - auto n = stack.pop(); - auto divByZero = m_builder.CreateICmpEQ(n, Constant::get(0)); - n = m_builder.CreateSelect(divByZero, Constant::get(1), n); // protect against hardware signal - auto r = m_builder.CreateUDiv(d, n); - r = m_builder.CreateSelect(divByZero, Constant::get(0), r); - stack.push(r); - break; - } - - case Instruction::SDIV: - { - auto d = stack.pop(); - auto n = stack.pop(); - auto divByZero = m_builder.CreateICmpEQ(n, Constant::get(0)); - auto divByMinusOne = m_builder.CreateICmpEQ(n, Constant::get(-1)); - n = m_builder.CreateSelect(divByZero, Constant::get(1), n); // protect against hardware signal - auto r = m_builder.CreateSDiv(d, n); - r = m_builder.CreateSelect(divByZero, Constant::get(0), r); - auto dNeg = m_builder.CreateSub(Constant::get(0), d); - r = m_builder.CreateSelect(divByMinusOne, dNeg, r); // protect against undef i256.min / -1 - stack.push(r); - break; - } - - case Instruction::MOD: - { - auto d = stack.pop(); - auto n = stack.pop(); - auto divByZero = m_builder.CreateICmpEQ(n, Constant::get(0)); - n = m_builder.CreateSelect(divByZero, Constant::get(1), n); // protect against hardware signal - auto r = m_builder.CreateURem(d, n); - r = m_builder.CreateSelect(divByZero, Constant::get(0), r); - stack.push(r); - break; - } - - case Instruction::SMOD: - { - auto d = stack.pop(); - auto n = stack.pop(); - auto divByZero = m_builder.CreateICmpEQ(n, Constant::get(0)); - auto divByMinusOne = m_builder.CreateICmpEQ(n, Constant::get(-1)); - n = m_builder.CreateSelect(divByZero, Constant::get(1), n); // protect against hardware signal - auto r = m_builder.CreateSRem(d, n); - r = m_builder.CreateSelect(divByZero, Constant::get(0), r); - r = m_builder.CreateSelect(divByMinusOne, Constant::get(0), r); // protect against undef i256.min / -1 - stack.push(r); - break; - } - - case Instruction::ADDMOD: - { - auto i512Ty = m_builder.getIntNTy(512); - auto a = stack.pop(); - auto b = stack.pop(); - auto m = stack.pop(); - auto divByZero = m_builder.CreateICmpEQ(m, Constant::get(0)); - a = m_builder.CreateZExt(a, i512Ty); - b = m_builder.CreateZExt(b, i512Ty); - m = m_builder.CreateZExt(m, i512Ty); - auto s = m_builder.CreateNUWAdd(a, b); - s = m_builder.CreateURem(s, m); - s = m_builder.CreateTrunc(s, Type::Word); - s = m_builder.CreateSelect(divByZero, Constant::get(0), s); - stack.push(s); - break; - } - - case Instruction::MULMOD: - { - auto i512Ty = m_builder.getIntNTy(512); - auto a = stack.pop(); - auto b = stack.pop(); - auto m = stack.pop(); - auto divByZero = m_builder.CreateICmpEQ(m, Constant::get(0)); - m = m_builder.CreateZExt(m, i512Ty); - // TODO: Add support for i256 x i256 -> i512 in LowerEVM pass - llvm::Value* p = m_builder.CreateCall(Arith256::getMul512Func(*_basicBlock.llvm()->getParent()->getParent()), {a, b}); - p = m_builder.CreateURem(p, m); - p = m_builder.CreateTrunc(p, Type::Word); - p = m_builder.CreateSelect(divByZero, Constant::get(0), p); - stack.push(p); - 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 idx = stack.pop(); - auto value = Endianness::toBE(m_builder, stack.pop()); - - auto idxValid = m_builder.CreateICmpULT(idx, Constant::get(32), "idxValid"); - auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); - // TODO: Workaround for LLVM bug. Using big value of index causes invalid memory access. - auto safeIdx = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5)); - // TODO: Workaround for LLVM bug. DAG Builder used sext on index instead of zext - safeIdx = m_builder.CreateZExt(safeIdx, Type::Size); - auto byte = m_builder.CreateExtractElement(bytes, safeIdx, "byte"); - value = m_builder.CreateZExt(byte, Type::Word); - value = m_builder.CreateSelect(idxValid, value, Constant::get(0)); - stack.push(value); - 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::Size); - 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 bitval = m_builder.CreateLShr(word, bitposEx, "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: - { - stack.pop(); - 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: - { - auto destIdx = llvm::MDNode::get(m_builder.getContext(), llvm::ValueAsMetadata::get(stack.pop())); - - // Create branch instruction, initially to jump table. - // Destination will be optimized with direct jump during jump resolving if destination index is a constant. - auto jumpInst = (inst == Instruction::JUMP) ? - m_builder.CreateBr(m_jumpTableBB) : - m_builder.CreateCondBr(m_builder.CreateICmpNE(stack.pop(), Constant::get(0), "jump.check"), m_jumpTableBB, nullptr); - - // Attach medatada to branch instruction with information about destination index. - jumpInst->setMetadata(c_destIdxLabel, destIdx); - 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: - 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 idx = stack.pop(); - auto value = _ext.calldataload(idx); - 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 callGas = 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 ret = _ext.call(callGas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.count(m_builder.getInt64(0), _runtimeManager.getJmpBuf(), _runtimeManager.getGasPtr()); - stack.push(ret); - break; - } - - case Instruction::RETURN: - { - auto index = stack.pop(); - auto size = stack.pop(); - - _memory.require(index, size); - _runtimeManager.registerReturnData(index, size); - - _runtimeManager.exit(ReturnCode::Return); - break; - } - - case Instruction::SUICIDE: - { - _runtimeManager.registerSuicide(stack.pop()); - _runtimeManager.exit(ReturnCode::Suicide); - break; - } - - - case Instruction::STOP: - { - m_builder.CreateBr(m_stopBB); - 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.CreateBr(m_abortBB); - it = _basicBlock.end() - 1; // finish block compilation - } - } - - _gasMeter.commitCostBlock(); - - stack.finalize(m_builder, *_basicBlock.llvm()); // TODO: Use references - - m_builder.SetInsertPoint(_basicBlock.llvm()->getFirstNonPHI()); // TODO: Move to LocalStack::finalize - _runtimeManager.checkStackLimit(stack.minSize(), stack.maxSize(), stack.size()); -} - - -} -} -} diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h deleted file mode 100644 index 3835d2e81..000000000 --- a/evmjit/libevmjit/Compiler.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "BasicBlock.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class Compiler -{ -public: - - struct Options - { - /// Rewrite switch instructions to sequences of branches - bool rewriteSwitchToBranches = true; - - /// Dump CFG as a .dot file for graphviz - bool dumpCFG = false; - }; - - Compiler(Options const& _options); - - std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); - -private: - - std::vector createBasicBlocks(code_iterator _begin, code_iterator _end, llvm::SwitchInst& _switchInst); - - void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, - class Stack& _globalStack); - - void resolveJumps(); - - /// Compiler options - Options const& m_options; - - /// Helper class for generating IR - llvm::IRBuilder<> m_builder; - - /// Stop basic block - terminates execution with STOP code (0) - llvm::BasicBlock* m_stopBB = nullptr; - - /// Abort basic block - terminates execution with OOG-like state - llvm::BasicBlock* m_abortBB = nullptr; - - /// Block with a jump table. - llvm::BasicBlock* m_jumpTableBB = nullptr; - - /// Main program function - llvm::Function* m_mainFunc = nullptr; // TODO: Remove -}; - -} -} -} diff --git a/evmjit/libevmjit/CompilerHelper.cpp b/evmjit/libevmjit/CompilerHelper.cpp deleted file mode 100644 index 5c8ee8574..000000000 --- a/evmjit/libevmjit/CompilerHelper.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#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 deleted file mode 100644 index ecdfce14d..000000000 --- a/evmjit/libevmjit/CompilerHelper.h +++ /dev/null @@ -1,64 +0,0 @@ -#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; -}; - -struct InsertPointGuard -{ - explicit InsertPointGuard(llvm::IRBuilderBase& _builder): m_builder(_builder), m_insertPoint(_builder.saveIP()) {} - ~InsertPointGuard() { m_builder.restoreIP(m_insertPoint); } - -private: - llvm::IRBuilderBase& m_builder; - llvm::IRBuilderBase::InsertPoint m_insertPoint; -}; - -} -} -} diff --git a/evmjit/libevmjit/Endianness.cpp b/evmjit/libevmjit/Endianness.cpp deleted file mode 100644 index 25b66c0d5..000000000 --- a/evmjit/libevmjit/Endianness.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "Endianness.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#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) -{ - if (llvm::sys::IsLittleEndianHost) - { - 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 deleted file mode 100644 index 19fd8fc58..000000000 --- a/evmjit/libevmjit/Endianness.h +++ /dev/null @@ -1,25 +0,0 @@ -#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 deleted file mode 100644 index c7f6ef0cd..000000000 --- a/evmjit/libevmjit/ExecStats.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "ExecStats.h" - -#include -#include -#include - -#include "Utils.h" - -namespace dev -{ -namespace evmjit -{ - -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::Optimization: return "Optimization"; - 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 deleted file mode 100644 index 4a5ae00e1..000000000 --- a/evmjit/libevmjit/ExecStats.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace dev -{ -namespace evmjit -{ - -enum class ExecState -{ - Started, - CacheLoad, - CacheWrite, - Compilation, - Optimization, - CodeGen, - Execution, - Return, - Finished -}; - -class JITListener -{ -public: - JITListener() = default; - JITListener(JITListener const&) = delete; - JITListener& operator=(JITListener) = delete; - virtual ~JITListener() {} - - virtual void executionStarted() {} - virtual void executionEnded() {} - - virtual void stateChanged(ExecState) {} -}; - -class ExecStats : public JITListener -{ -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/Ext.cpp b/evmjit/libevmjit/Ext.cpp deleted file mode 100644 index 3bbb47cdf..000000000 --- a/evmjit/libevmjit/Ext.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#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::Gas, 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()})}, - }}; - - 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* _idx) -{ - auto ret = getArgAlloca(); - auto result = m_builder.CreateBitCast(ret, Type::BytePtr); - - auto callDataSize = getRuntimeManager().getCallDataSize(); - auto callDataSize64 = m_builder.CreateTrunc(callDataSize, Type::Size); - auto idxValid = m_builder.CreateICmpULT(_idx, callDataSize); - auto idx = m_builder.CreateTrunc(m_builder.CreateSelect(idxValid, _idx, callDataSize), Type::Size, "idx"); - - auto end = m_builder.CreateNUWAdd(idx, m_builder.getInt64(32)); - end = m_builder.CreateSelect(m_builder.CreateICmpULE(end, callDataSize64), end, callDataSize64); - auto copySize = m_builder.CreateNUWSub(end, idx); - auto padSize = m_builder.CreateNUWSub(m_builder.getInt64(32), copySize); - auto dataBegin = m_builder.CreateGEP(Type::Byte, getRuntimeManager().getCallData(), idx); - m_builder.CreateMemCpy(result, dataBegin, copySize, 1); - auto pad = m_builder.CreateGEP(Type::Byte, result, copySize); - m_builder.CreateMemSet(pad, m_builder.getInt8(0), padSize, 1); - - m_argCounter = 0; // Release args allocas. TODO: This is a bad design - return Endianness::toNative(m_builder, m_builder.CreateLoad(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* _callGas, 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 callGas = m_builder.CreateSelect( - m_builder.CreateICmpULE(_callGas, m_builder.CreateZExt(Constant::gasMax, Type::Word)), - m_builder.CreateTrunc(_callGas, Type::Gas), - Constant::gasMax); - auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), callGas, 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 deleted file mode 100644 index 5ac37deea..000000000 --- a/evmjit/libevmjit/Ext.h +++ /dev/null @@ -1,79 +0,0 @@ -#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, - - _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* _callGas, 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; - - 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 deleted file mode 100644 index 4cd053316..000000000 --- a/evmjit/libevmjit/GasMeter.cpp +++ /dev/null @@ -1,299 +0,0 @@ -#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[] = {0, 2, 3, 5, 8, 10, 20}; -int64_t const c_expByteGas = 10; -int64_t const c_sha3Gas = 30; -int64_t const c_sha3WordGas = 6; -int64_t const c_sloadGas = 50; -int64_t const c_sstoreSetGas = 20000; -int64_t const c_sstoreResetGas = 5000; -int64_t const c_sstoreClearGas = 5000; -int64_t const c_jumpdestGas = 1; -int64_t const c_logGas = 375; -int64_t const c_logTopicGas = 375; -int64_t const c_logDataGas = 8; -int64_t const c_callGas = 40; -int64_t const c_createGas = 32000; -int64_t const c_memoryGas = 3; -int64_t const c_copyGas = 3; - -int64_t getStepCost(Instruction inst) -{ - switch (inst) - { - // Tier 0 - case Instruction::STOP: - case Instruction::RETURN: - case Instruction::SUICIDE: - case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() - return c_stepGas[0]; - - // Tier 1 - case Instruction::ADDRESS: - case Instruction::ORIGIN: - case Instruction::CALLER: - case Instruction::CALLVALUE: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::GASPRICE: - case Instruction::COINBASE: - case Instruction::TIMESTAMP: - case Instruction::NUMBER: - case Instruction::DIFFICULTY: - case Instruction::GASLIMIT: - case Instruction::POP: - case Instruction::PC: - case Instruction::MSIZE: - case Instruction::GAS: - return c_stepGas[1]; - - // Tier 2 - case Instruction::ADD: - case Instruction::SUB: - case Instruction::LT: - case Instruction::GT: - case Instruction::SLT: - case Instruction::SGT: - case Instruction::EQ: - case Instruction::ISZERO: - case Instruction::AND: - case Instruction::OR: - case Instruction::XOR: - case Instruction::NOT: - case Instruction::BYTE: - case Instruction::CALLDATALOAD: - case Instruction::CALLDATACOPY: - case Instruction::CODECOPY: - case Instruction::MLOAD: - case Instruction::MSTORE: - case Instruction::MSTORE8: - case Instruction::ANY_PUSH: - case Instruction::ANY_DUP: - case Instruction::ANY_SWAP: - return c_stepGas[2]; - - // Tier 3 - case Instruction::MUL: - case Instruction::DIV: - case Instruction::SDIV: - case Instruction::MOD: - case Instruction::SMOD: - case Instruction::SIGNEXTEND: - return c_stepGas[3]; - - // Tier 4 - case Instruction::ADDMOD: - case Instruction::MULMOD: - case Instruction::JUMP: - return c_stepGas[4]; - - // Tier 5 - case Instruction::EXP: - case Instruction::JUMPI: - return c_stepGas[5]; - - // Tier 6 - case Instruction::BALANCE: - case Instruction::EXTCODESIZE: - case Instruction::EXTCODECOPY: - case Instruction::BLOCKHASH: - return c_stepGas[6]; - - case Instruction::SHA3: - return c_sha3Gas; - - case Instruction::SLOAD: - return c_sloadGas; - - case Instruction::JUMPDEST: - return c_jumpdestGas; - - 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; - } - - case Instruction::CALL: - case Instruction::CALLCODE: - return c_callGas; - - case Instruction::CREATE: - return c_createGas; - } - - return 0; // TODO: Add UNREACHABLE macro -} - -} - -GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : - CompilerHelper(_builder), - m_runtimeManager(_runtimeManager) -{ - llvm::Type* gasCheckArgs[] = {Type::Gas->getPointerTo(), Type::Gas, Type::BytePtr}; - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", getModule()); - m_gasCheckFunc->setDoesNotThrow(); - m_gasCheckFunc->setDoesNotCapture(1); - - auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); - auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); - - auto gasPtr = &m_gasCheckFunc->getArgumentList().front(); - gasPtr->setName("gasPtr"); - auto cost = gasPtr->getNextNode(); - cost->setName("cost"); - auto jmpBuf = cost->getNextNode(); - jmpBuf->setName("jmpBuf"); - - InsertPointGuard guard(m_builder); - m_builder.SetInsertPoint(checkBB); - auto gas = m_builder.CreateLoad(gasPtr, "gas"); - auto gasUpdated = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); - auto gasOk = m_builder.CreateICmpSGE(gasUpdated, m_builder.getInt64(0), "gasOk"); // gas >= 0, with gas == 0 we can still do 0 cost instructions - m_builder.CreateCondBr(gasOk, updateBB, outOfGasBB, Type::expectTrue); - - m_builder.SetInsertPoint(updateBB); - m_builder.CreateStore(gasUpdated, gasPtr); - m_builder.CreateRetVoid(); - - m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.abort(jmpBuf); - m_builder.CreateUnreachable(); -} - -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.getGasPtr(), llvm::UndefValue::get(Type::Gas), m_runtimeManager.getJmpBuf()}); - } - - m_blockCost += getStepCost(_inst); -} - -void GasMeter::count(llvm::Value* _cost, llvm::Value* _jmpBuf, llvm::Value* _gasPtr) -{ - 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, {_gasPtr ? _gasPtr : m_runtimeManager.getGasPtr(), _cost, _jmpBuf ? _jmpBuf : m_runtimeManager.getJmpBuf()}); -} - -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.CreateCall(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(m_builder.CreateNUWMul(sigBytes, m_builder.getInt64(c_expByteGas))); -} - -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 newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); - auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); - static_assert(c_sstoreResetGas == c_sstoreClearGas, "Update SSTORE gas cost"); - auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "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(m_builder.CreateNUWMul(_dataLength, Constant::get(c_logDataGas))); // TODO: Use i64 -} - -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, llvm::Value* _jmpBuf, llvm::Value* _gasPtr) -{ - static_assert(c_memoryGas != 1, "Memory gas cost has changed. Update GasMeter."); - count(_additionalMemoryInWords, _jmpBuf, _gasPtr); -} - -void GasMeter::countCopy(llvm::Value* _copyWords) -{ - static_assert(c_copyGas != 1, "Copy gas cost has changed. Update GasMeter."); - count(m_builder.CreateNUWMul(_copyWords, m_builder.getInt64(c_copyGas))); -} - -} -} -} - diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h deleted file mode 100644 index 93a6cc24c..000000000 --- a/evmjit/libevmjit/GasMeter.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "CompilerHelper.h" -#include "Instruction.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; -using namespace evmjit; - -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, llvm::Value* _jmpBuf = nullptr, llvm::Value* _gasPtr = nullptr); - - /// 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, llvm::Value* _jmpBuf, llvm::Value* _gasPtr); - - /// 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 deleted file mode 100644 index c2e267cdb..000000000 --- a/evmjit/libevmjit/Instruction.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "Instruction.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - -namespace dev -{ -namespace evmjit -{ - -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 deleted file mode 100644 index 89add0958..000000000 --- a/evmjit/libevmjit/Instruction.h +++ /dev/null @@ -1,236 +0,0 @@ -#pragma once - -#include "Common.h" - -namespace llvm -{ - class APInt; -} - -namespace dev -{ -namespace evmjit -{ - -/// 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/JIT-c.cpp b/evmjit/libevmjit/JIT-c.cpp deleted file mode 100644 index 7c5cd0b14..000000000 --- a/evmjit/libevmjit/JIT-c.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include - -extern "C" -{ -using namespace dev::evmjit; - -evmjit_context* evmjit_create(evmjit_runtime_data* _data, void* _env) -{ - auto data = reinterpret_cast(_data); - auto env = reinterpret_cast(_env); - - assert(!data && "Pointer to runtime data must not be null"); - if (!data) - return nullptr; - - // TODO: Make sure ExecutionEngine constructor does not throw + make JIT/ExecutionEngine interface all nothrow - auto context = new(std::nothrow) ExecutionContext{*data, env}; - return reinterpret_cast(context); -} - -void evmjit_destroy(evmjit_context* _context) -{ - auto context = reinterpret_cast(_context); - delete context; -} - -evmjit_return_code evmjit_exec(evmjit_context* _context) -{ - auto context = reinterpret_cast(_context); - - assert(!context && "Invalid context"); - if (!context) - return UnexpectedException; - - try - { - auto returnCode = JIT::exec(*context); - return static_cast(returnCode); - } - catch(...) - { - return UnexpectedException; - } -} - -} diff --git a/evmjit/libevmjit/JIT.cpp b/evmjit/libevmjit/JIT.cpp deleted file mode 100644 index dc5bc0beb..000000000 --- a/evmjit/libevmjit/JIT.cpp +++ /dev/null @@ -1,252 +0,0 @@ -#include "evmjit/JIT.h" - -#include -#include - -#include "preprocessor/llvm_includes_start.h" -#include -#include -#include -#include -#include -#include -#include -#include "preprocessor/llvm_includes_end.h" - -#include "Compiler.h" -#include "Optimizer.h" -#include "Cache.h" -#include "ExecStats.h" -#include "Utils.h" -#include "BuildInfo.gen.h" - -namespace dev -{ -namespace evmjit -{ -using namespace eth::jit; - -namespace -{ -using ExecFunc = ReturnCode(*)(ExecutionContext*); - -std::string hash2str(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; -} - -void printVersion() -{ - std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n" - << " EVMJIT version " << EVMJIT_VERSION << "\n" -#ifdef NDEBUG - << " Optimized build, " -#else - << " DEBUG build, " -#endif - << __DATE__ << " (" << __TIME__ << ")\n" - << std::endl; -} - -namespace cl = llvm::cl; -cl::opt g_optimize{"O", cl::desc{"Optimize"}}; -cl::opt g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"}, - cl::values( - clEnumValN(CacheMode::on, "1", "Enabled"), - clEnumValN(CacheMode::off, "0", "Disabled"), - clEnumValN(CacheMode::read, "r", "Read only. No new objects are added to cache."), - clEnumValN(CacheMode::write, "w", "Write only. No objects are loaded from cache."), - clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."), - clEnumValN(CacheMode::preload, "p", "Preload all cached objects."), - clEnumValEnd)}; -cl::opt g_stats{"st", cl::desc{"Statistics"}}; -cl::opt g_dump{"dump", cl::desc{"Dump LLVM IR module"}}; - -void parseOptions() -{ - static llvm::llvm_shutdown_obj shutdownObj{}; - cl::AddExtraVersionPrinter(printVersion); - cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); -} - -class JITImpl -{ - std::unique_ptr m_engine; - mutable std::mutex x_codeMap; - std::unordered_map m_codeMap; - -public: - static JITImpl& instance() - { - static JITImpl s_instance; - return s_instance; - } - - JITImpl(); - - llvm::ExecutionEngine& engine() { return *m_engine; } - - ExecFunc getExecFunc(h256 const& _codeHash) const; - void mapExecFunc(h256 _codeHash, ExecFunc _funcAddr); - - ExecFunc compile(byte const* _code, uint64_t _codeSize, h256 const& _codeHash); -}; - -JITImpl::JITImpl() -{ - parseOptions(); - - bool preloadCache = g_cache == CacheMode::preload; - if (preloadCache) - g_cache = CacheMode::on; - - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); - - // FIXME: LLVM 3.7: test on Windows - 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()); - - llvm::EngineBuilder builder(std::move(module)); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); - - m_engine.reset(builder.create()); - - // TODO: Update cache listener - m_engine->setObjectCache(Cache::init(g_cache, nullptr)); - - // FIXME: Disabled during API changes - //if (preloadCache) - // Cache::preload(*m_engine, funcCache); -} - -ExecFunc JITImpl::getExecFunc(h256 const& _codeHash) const -{ - std::lock_guard lock{x_codeMap}; - auto it = m_codeMap.find(_codeHash); - if (it != m_codeMap.end()) - return it->second; - return nullptr; -} - -void JITImpl::mapExecFunc(h256 _codeHash, ExecFunc _funcAddr) -{ - std::lock_guard lock{x_codeMap}; - m_codeMap.emplace(std::move(_codeHash), _funcAddr); -} - -ExecFunc JITImpl::compile(byte const* _code, uint64_t _codeSize, h256 const& _codeHash) -{ - auto name = hash2str(_codeHash); - auto module = Cache::getObject(name); - if (!module) - { - // TODO: Listener support must be redesigned. These should be a feature of JITImpl - //listener->stateChanged(ExecState::Compilation); - assert(_code || !_codeSize); //TODO: Is it good idea to execute empty code? - module = Compiler{{}}.compile(_code, _code + _codeSize, name); - - if (g_optimize) - { - //listener->stateChanged(ExecState::Optimization); - optimize(*module); - } - - prepare(*module); - } - if (g_dump) - module->dump(); - - m_engine->addModule(std::move(module)); - //listener->stateChanged(ExecState::CodeGen); - return (ExecFunc)m_engine->getFunctionAddress(name); -} - -} // anonymous namespace - -bool JIT::isCodeReady(h256 const& _codeHash) -{ - return JITImpl::instance().getExecFunc(_codeHash) != nullptr; -} - -void JIT::compile(byte const* _code, uint64_t _codeSize, h256 const& _codeHash) -{ - auto& jit = JITImpl::instance(); - auto execFunc = jit.compile(_code, _codeSize, _codeHash); - if (execFunc) // FIXME: What with error? - jit.mapExecFunc(_codeHash, execFunc); -} - -ReturnCode JIT::exec(ExecutionContext& _context) -{ - //std::unique_ptr listener{new ExecStats}; - //listener->stateChanged(ExecState::Started); - //static StatsCollector statsCollector; - - auto& jit = JITImpl::instance(); - auto codeHash = _context.codeHash(); - auto execFunc = jit.getExecFunc(codeHash); - if (!execFunc) - { - execFunc = jit.compile(_context.code(), _context.codeSize(), codeHash); - if (!execFunc) - return ReturnCode::LLVMError; - jit.mapExecFunc(codeHash, execFunc); - } - - //listener->stateChanged(ExecState::Execution); - auto returnCode = execFunc(&_context); - //listener->stateChanged(ExecState::Return); - - if (returnCode == ReturnCode::Return) - _context.returnData = _context.getReturnData(); // Save reference to return data - - //listener->stateChanged(ExecState::Finished); - // if (g_stats) - // statsCollector.stats.push_back(std::move(listener)); - - return returnCode; -} - - -extern "C" void ext_free(void* _data) noexcept; - -ExecutionContext::~ExecutionContext() noexcept -{ - if (m_memData) - ext_free(m_memData); // Use helper free to check memory leaks -} - -bytes_ref ExecutionContext::getReturnData() const -{ - auto data = m_data->callData; - auto size = static_cast(m_data->callDataSize); - - if (data < m_memData || data >= m_memData + m_memSize || 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/Memory.cpp b/evmjit/libevmjit/Memory.cpp deleted file mode 100644 index fdf5a6b98..000000000 --- a/evmjit/libevmjit/Memory.cpp +++ /dev/null @@ -1,246 +0,0 @@ -#include "Memory.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - -#include "Type.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_memory{getBuilder(), _runtimeManager.getMem()}, - m_gasMeter(_gasMeter) -{} - -llvm::Function* Memory::getRequireFunc() -{ - auto& func = m_require; - if (!func) - { - llvm::Type* argTypes[] = {Array::getType()->getPointerTo(), Type::Word, Type::Word, Type::BytePtr, Type::GasPtr}; - func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - func->setDoesNotThrow(); - - auto mem = &func->getArgumentList().front(); - mem->setName("mem"); - auto blkOffset = mem->getNextNode(); - blkOffset->setName("blkOffset"); - auto blkSize = blkOffset->getNextNode(); - blkSize->setName("blkSize"); - auto jmpBuf = blkSize->getNextNode(); - jmpBuf->setName("jmpBuf"); - auto gas = jmpBuf->getNextNode(); - gas->setName("gas"); - - 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); - m_builder.CreateCondBr(m_builder.CreateICmpNE(blkSize, Constant::get(0)), checkBB, returnBB, Type::expectTrue); - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - static const auto c_inputMax = uint64_t(1) << 33; // max value of blkSize and blkOffset that will not result in integer overflow in calculations below - auto blkOffsetOk = m_builder.CreateICmpULE(blkOffset, Constant::get(c_inputMax), "blkOffsetOk"); - auto blkO = m_builder.CreateSelect(blkOffsetOk, m_builder.CreateTrunc(blkOffset, Type::Size), m_builder.getInt64(c_inputMax), "bklO"); - auto blkSizeOk = m_builder.CreateICmpULE(blkSize, Constant::get(c_inputMax), "blkSizeOk"); - auto blkS = m_builder.CreateSelect(blkSizeOk, m_builder.CreateTrunc(blkSize, Type::Size), m_builder.getInt64(c_inputMax), "bklS"); - - auto sizeReq0 = m_builder.CreateNUWAdd(blkO, blkS, "sizeReq0"); - auto sizeReq = m_builder.CreateAnd(m_builder.CreateNUWAdd(sizeReq0, m_builder.getInt64(31)), uint64_t(-1) << 5, "sizeReq"); // s' = ((s0 + 31) / 32) * 32 - auto sizeCur = m_memory.size(mem); - auto sizeOk = m_builder.CreateICmpULE(sizeReq, sizeCur, "sizeOk"); - - m_builder.CreateCondBr(sizeOk, returnBB, resizeBB, Type::expectTrue); - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - auto w1 = m_builder.CreateLShr(sizeReq, 5); - auto w1s = m_builder.CreateNUWMul(w1, w1); - auto c1 = m_builder.CreateAdd(m_builder.CreateNUWMul(w1, m_builder.getInt64(3)), m_builder.CreateLShr(w1s, 9)); - auto w0 = m_builder.CreateLShr(sizeCur, 5); - auto w0s = m_builder.CreateNUWMul(w0, w0); - auto c0 = m_builder.CreateAdd(m_builder.CreateNUWMul(w0, m_builder.getInt64(3)), m_builder.CreateLShr(w0s, 9)); - auto cc = m_builder.CreateNUWSub(c1, c0); - auto costOk = m_builder.CreateAnd(blkOffsetOk, blkSizeOk, "costOk"); - auto c = m_builder.CreateSelect(costOk, cc, m_builder.getInt64(std::numeric_limits::max()), "c"); - m_gasMeter.count(c, jmpBuf, gas); - // Resize - m_memory.extend(mem, sizeReq); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); - } - return func; -} - -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType) -{ - auto isWord = _valueType == Type::Word; - - llvm::Type* storeArgs[] = {Array::getType()->getPointerTo(), Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Array::getType()->getPointerTo(), 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 mem = &func->getArgumentList().front(); - mem->setName("mem"); - auto index = mem->getNextNode(); - index->setName("index"); - - if (_isStore) - { - auto valueArg = index->getNextNode(); - valueArg->setName("value"); - auto value = isWord ? Endianness::toBE(m_builder, valueArg) : valueArg; - auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size)); - auto valuePtr = m_builder.CreateBitCast(memPtr, _valueType->getPointerTo(), "valuePtr"); - m_builder.CreateStore(value, valuePtr); - m_builder.CreateRetVoid(); - } - else - { - auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size)); - llvm::Value* ret = m_builder.CreateLoad(memPtr); - 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); - return func; -} - -llvm::Function* Memory::getStoreWordFunc() -{ - auto& func = m_storeWord; - if (!func) - func = createFunc(true, Type::Word); - return func; -} - -llvm::Function* Memory::getStoreByteFunc() -{ - auto& func = m_storeByte; - if (!func) - func = createFunc(true, Type::Byte); - return func; -} - - -llvm::Value* Memory::loadWord(llvm::Value* _addr) -{ - require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8)); - return createCall(getLoadWordFunc(), {getRuntimeManager().getMem(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8)); - createCall(getStoreWordFunc(), {getRuntimeManager().getMem(), _addr, _word}); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - require(_addr, Constant::get(Type::Byte->getPrimitiveSizeInBits() / 8)); - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(getStoreByteFunc(), {getRuntimeManager().getMem(), _addr, byte}); -} - -llvm::Value* Memory::getData() -{ - auto memPtr = m_builder.CreateBitCast(getRuntimeManager().getMem(), Type::BytePtr->getPointerTo()); - auto data = m_builder.CreateLoad(memPtr, "data"); - assert(data->getType() == Type::BytePtr); - return data; -} - -llvm::Value* Memory::getSize() -{ - return m_builder.CreateZExt(m_memory.size(), Type::Word, "msize"); // TODO: Allow placing i64 on stack -} - -llvm::Value* Memory::getBytePtr(llvm::Value* _index) -{ - return m_builder.CreateGEP(getData(), _index, "ptr"); -} - -void Memory::require(llvm::Value* _offset, llvm::Value* _size) -{ - if (auto constant = llvm::dyn_cast(_size)) - { - if (!constant->getValue()) - return; - } - createCall(getRequireFunc(), {getRuntimeManager().getMem(), _offset, _size, getRuntimeManager().getJmpBuf(), getRuntimeManager().getGasPtr()}); -} - -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, "bytesToCopy"); - auto bytesToZero = m_builder.CreateNUWSub(reqBytes, bytesToCopy, "bytesToZero"); - - auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); - auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); - auto padIdx = m_builder.CreateNUWAdd(dstIdx, bytesToCopy, "padIdx"); - auto dst = m_memory.getPtr(getRuntimeManager().getMem(), dstIdx); - auto pad = m_memory.getPtr(getRuntimeManager().getMem(), padIdx); - m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); - m_builder.CreateMemSet(pad, m_builder.getInt8(0), bytesToZero, 0); -} - -} -} -} diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h deleted file mode 100644 index beb535226..000000000 --- a/evmjit/libevmjit/Memory.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "Array.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: - Array m_memory; - - GasMeter& m_gasMeter; - - llvm::Function* createFunc(bool _isStore, llvm::Type* _type); - - 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/Optimizer.cpp b/evmjit/libevmjit/Optimizer.cpp deleted file mode 100644 index 9cc6aa54a..000000000 --- a/evmjit/libevmjit/Optimizer.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include "Optimizer.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#include -#include -#include -#include -#include "preprocessor/llvm_includes_end.h" - -#include "Arith256.h" -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -bool optimize(llvm::Module& _module) -{ - auto pm = llvm::legacy::PassManager{}; - pm.add(llvm::createFunctionInliningPass(2, 2)); - pm.add(llvm::createCFGSimplificationPass()); - pm.add(llvm::createInstructionCombiningPass()); - pm.add(llvm::createAggressiveDCEPass()); - pm.add(llvm::createLowerSwitchPass()); - return pm.run(_module); -} - -namespace -{ - -class LowerEVMPass: public llvm::BasicBlockPass -{ - static char ID; - -public: - LowerEVMPass(): - llvm::BasicBlockPass(ID) - {} - - virtual bool runOnBasicBlock(llvm::BasicBlock& _bb) override; - - using llvm::BasicBlockPass::doFinalization; - virtual bool doFinalization(llvm::Module& _module) override; -}; - -char LowerEVMPass::ID = 0; - -bool LowerEVMPass::runOnBasicBlock(llvm::BasicBlock& _bb) -{ - auto modified = false; - auto module = _bb.getParent()->getParent(); - auto i512Ty = llvm::IntegerType::get(_bb.getContext(), 512); - for (auto it = _bb.begin(); it != _bb.end(); ) - { - auto& inst = *it++; - llvm::Function* func = nullptr; - if (inst.getType() == Type::Word) - { - switch (inst.getOpcode()) - { - case llvm::Instruction::Mul: - func = Arith256::getMulFunc(*module); - break; - - case llvm::Instruction::UDiv: - func = Arith256::getUDiv256Func(*module); - break; - - case llvm::Instruction::URem: - func = Arith256::getURem256Func(*module); - break; - - case llvm::Instruction::SDiv: - func = Arith256::getSDiv256Func(*module); - break; - - case llvm::Instruction::SRem: - func = Arith256::getSRem256Func(*module); - break; - } - } - else if (inst.getType() == i512Ty) - { - switch (inst.getOpcode()) - { - case llvm::Instruction::URem: - func = Arith256::getURem512Func(*module); - break; - } - } - - if (func) - { - auto call = llvm::CallInst::Create(func, {inst.getOperand(0), inst.getOperand(1)}, "", &inst); - inst.replaceAllUsesWith(call); - inst.eraseFromParent(); - modified = true; - } - } - return modified; -} - -bool LowerEVMPass::doFinalization(llvm::Module&) -{ - return false; -} - -} - -bool prepare(llvm::Module& _module) -{ - auto pm = llvm::legacy::PassManager{}; - pm.add(llvm::createCFGSimplificationPass()); - pm.add(llvm::createDeadCodeEliminationPass()); - pm.add(new LowerEVMPass{}); - return pm.run(_module); -} - -} -} -} diff --git a/evmjit/libevmjit/Optimizer.h b/evmjit/libevmjit/Optimizer.h deleted file mode 100644 index 4b7ab7e9a..000000000 --- a/evmjit/libevmjit/Optimizer.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -namespace llvm -{ - class Module; -} - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -bool optimize(llvm::Module& _module); - -bool prepare(llvm::Module& _module); - -} -} -} diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp deleted file mode 100644 index bce378b64..000000000 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include "RuntimeManager.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - -#include "Stack.h" -#include "Utils.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* - Array::getType() // memory - }; - type = llvm::StructType::create(elems, "Runtime"); - } - return type; -} - -namespace -{ -llvm::Twine getName(RuntimeData::Index _index) -{ - switch (_index) - { - default: return ""; - case RuntimeData::Gas: return "msg.gas"; - case RuntimeData::GasPrice: return "tx.gasprice"; - case RuntimeData::CallData: return "msg.data.ptr"; - case RuntimeData::CallDataSize: return "msg.data.size"; - case RuntimeData::Address: return "this.address"; - case RuntimeData::Caller: return "msg.caller"; - case RuntimeData::Origin: return "tx.origin"; - case RuntimeData::CallValue: return "msg.value"; - case RuntimeData::CoinBase: return "block.coinbase"; - case RuntimeData::Difficulty: return "block.difficulty"; - case RuntimeData::GasLimit: return "block.gaslimit"; - case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; - case RuntimeData::Code: return "code.ptr"; - case RuntimeData::CodeSize: return "code.size"; - } -} -} - -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::eh_sjlj_longjmp); - - // Unpack data - auto rtPtr = getRuntimePtr(); - m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "dataPtr"); - assert(m_dataPtr->getType() == Type::RuntimeDataPtr); - m_memPtr = m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 2, "mem"); - assert(m_memPtr->getType() == Array::getType()->getPointerTo()); - m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 1), "env"); - assert(m_envPtr->getType() == Type::EnvPtr); - - m_stackSize = m_builder.CreateAlloca(Type::Size, nullptr, "stackSize"); - m_builder.CreateStore(m_builder.getInt64(0), m_stackSize); - - auto data = m_builder.CreateLoad(m_dataPtr, "data"); - for (unsigned i = 0; i < m_dataElts.size(); ++i) - m_dataElts[i] = m_builder.CreateExtractValue(data, i, getName(RuntimeData::Index(i))); - - m_gasPtr = m_builder.CreateAlloca(Type::Gas, nullptr, "gas.ptr"); - m_builder.CreateStore(m_dataElts[RuntimeData::Index::Gas], m_gasPtr); - - llvm::Type* checkStackLimitArgs[] = {Type::Size->getPointerTo(), Type::Size, Type::Size, Type::Size, Type::BytePtr}; - m_checkStackLimit = llvm::Function::Create(llvm::FunctionType::get(Type::Void, checkStackLimitArgs, false), llvm::Function::PrivateLinkage, "evm.stack.require", getModule()); - m_checkStackLimit->setDoesNotThrow(); - m_checkStackLimit->setDoesNotCapture(1); - - auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_checkStackLimit); - auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_checkStackLimit); - auto outOfStackBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfStack", m_checkStackLimit); - - auto currSizePtr = &m_checkStackLimit->getArgumentList().front(); - currSizePtr->setName("currSize"); - auto min = currSizePtr->getNextNode(); - min->setName("min"); - auto max = min->getNextNode(); - max->setName("max"); - auto diff = max->getNextNode(); - diff->setName("diff"); - auto jmpBuf = diff->getNextNode(); - jmpBuf->setName("jmpBuf"); - - InsertPointGuard guard{m_builder}; - m_builder.SetInsertPoint(checkBB); - auto currSize = m_builder.CreateLoad(currSizePtr, "cur"); - auto minSize = m_builder.CreateAdd(currSize, min, "minSize", false, true); - auto maxSize = m_builder.CreateAdd(currSize, max, "maxSize", true, true); - auto minOk = m_builder.CreateICmpSGE(minSize, m_builder.getInt64(0), "min.ok"); - auto maxOk = m_builder.CreateICmpULE(maxSize, m_builder.getInt64(1024), "max.ok"); - auto ok = m_builder.CreateAnd(minOk, maxOk, "ok"); - m_builder.CreateCondBr(ok, updateBB, outOfStackBB, Type::expectTrue); - - m_builder.SetInsertPoint(updateBB); - auto newSize = m_builder.CreateNSWAdd(currSize, diff); - m_builder.CreateStore(newSize, currSizePtr); - m_builder.CreateRetVoid(); - - m_builder.SetInsertPoint(outOfStackBB); - abort(jmpBuf); - m_builder.CreateUnreachable(); -} - -void RuntimeManager::checkStackLimit(ssize_t _min, ssize_t _max, ssize_t _diff) -{ - createCall(m_checkStackLimit, {m_stackSize, m_builder.getInt64(_min), m_builder.getInt64(_max), m_builder.getInt64(_diff), getJmpBuf()}); -} - -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(getRuntimeType(), 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(getRuntimeDataType(), getDataPtr(), _index); - assert(getRuntimeDataType()->getElementType(_index)->getPointerTo() == ptr->getType()); - return ptr; -} - -llvm::Value* RuntimeManager::get(RuntimeData::Index _index) -{ - return m_dataElts[_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 = m_builder.CreateBitCast(getMem(), Type::BytePtr->getPointerTo()); - auto mem = getBuilder().CreateLoad(memPtr, "memory"); - auto returnDataPtr = getBuilder().CreateGEP(mem, _offset); - 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::exit(ReturnCode _returnCode) -{ - if (m_stack) - m_stack->free(); - - auto extGasPtr = m_builder.CreateStructGEP(getRuntimeDataType(), getDataPtr(), RuntimeData::Index::Gas, "msg.gas.ptr"); - m_builder.CreateStore(getGas(), extGasPtr); - m_builder.CreateRet(Constant::get(_returnCode)); -} - -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::getGas() -{ - return getBuilder().CreateLoad(getGasPtr(), "gas"); -} - -llvm::Value* RuntimeManager::getGasPtr() -{ - assert(getMainFunction()); - return m_gasPtr; -} - -llvm::Value* RuntimeManager::getMem() -{ - assert(getMainFunction()); - return m_memPtr; -} - -void RuntimeManager::setGas(llvm::Value* _gas) -{ - assert(_gas->getType() == Type::Gas); - getBuilder().CreateStore(_gas, getGasPtr()); -} - -} -} -} diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h deleted file mode 100644 index 8511c8898..000000000 --- a/evmjit/libevmjit/RuntimeManager.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include - -#include "CompilerHelper.h" -#include "Type.h" -#include "Instruction.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ -using namespace evmjit; -class Stack; - -class RuntimeManager: public CompilerHelper -{ -public: - RuntimeManager(llvm::IRBuilder<>& _builder, 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); - - llvm::Value* getMem(); - - void registerReturnData(llvm::Value* _index, llvm::Value* _size); // TODO: Move to Memory. - void registerSuicide(llvm::Value* _balanceAddress); - - void exit(ReturnCode _returnCode); - - void abort(llvm::Value* _jmpBuf); - - void setStack(Stack& _stack) { m_stack = &_stack; } - void setJmpBuf(llvm::Value* _jmpBuf) { m_jmpBuf = _jmpBuf; } - - static llvm::StructType* getRuntimeType(); - static llvm::StructType* getRuntimeDataType(); - - void checkStackLimit(ssize_t _min, ssize_t _max, ssize_t _diff); - -private: - llvm::Value* getPtr(RuntimeData::Index _index); - void set(RuntimeData::Index _index, llvm::Value* _value); - - llvm::Function* m_longjmp = nullptr; - llvm::Value* m_jmpBuf = nullptr; - llvm::Value* m_dataPtr = nullptr; - llvm::Value* m_gasPtr = nullptr; - llvm::Value* m_memPtr = nullptr; - llvm::Value* m_envPtr = nullptr; - - std::array m_dataElts; - - llvm::Value* m_stackSize = nullptr; - llvm::Function* m_checkStackLimit = nullptr; - - code_iterator m_codeBegin = {}; - code_iterator m_codeEnd = {}; - - Stack* m_stack = nullptr; -}; - -} -} -} diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp deleted file mode 100644 index 037d71f1d..000000000 --- a/evmjit/libevmjit/Stack.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "Stack.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - -#include "RuntimeManager.h" -#include "Utils.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Stack::Stack(llvm::IRBuilder<>& _builder): - CompilerHelper(_builder), - m_stack(_builder, "stack") -{} - -llvm::Value* Stack::get(size_t _index) -{ - return m_stack.get(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1))); -} - -void Stack::set(size_t _index, llvm::Value* _value) -{ - m_stack.set(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1)), _value); -} - -void Stack::pop(size_t _count) -{ - m_stack.pop(m_builder.getInt64(_count)); -} - -void Stack::push(llvm::Value* _value) -{ - m_stack.push(_value); -} - -} -} -} diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h deleted file mode 100644 index 72e3d88d2..000000000 --- a/evmjit/libevmjit/Stack.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "Array.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class Stack: public CompilerHelper -{ -public: - Stack(llvm::IRBuilder<>& builder); - - llvm::Value* get(size_t _index); - void set(size_t _index, llvm::Value* _value); - void pop(size_t _count); - void push(llvm::Value* _value); - void free() { m_stack.free(); } - -private: - Array m_stack; -}; - - -} -} -} diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp deleted file mode 100644 index 6ac9a6467..000000000 --- a/evmjit/libevmjit/Type.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "Type.h" - -#include - -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::IntegerType* Type::Word; -llvm::PointerType* Type::WordPtr; -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; -llvm::MDNode* Type::expectTrue; - -void Type::init(llvm::LLVMContext& _context) -{ - if (!Word) // Do init only once - { - Word = llvm::Type::getIntNTy(_context, 256); - WordPtr = Word->getPointerTo(); - 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()); - - expectTrue = llvm::MDBuilder{_context}.createBranchWeights(1, 0); - } -} - -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 deleted file mode 100644 index 5e5b9dde5..000000000 --- a/evmjit/libevmjit/Type.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "preprocessor/llvm_includes_start.h" -#include -#include -#include -#include "preprocessor/llvm_includes_end.h" - -#include "evmjit/JIT.h" // ReturnCode - -namespace dev -{ -namespace eth -{ -namespace jit -{ -using namespace evmjit; - -struct Type -{ - static llvm::IntegerType* Word; - static llvm::PointerType* WordPtr; - - 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; - - // TODO: Redesign static LLVM objects - static llvm::MDNode* expectTrue; - - 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 deleted file mode 100644 index b010b1d96..000000000 --- a/evmjit/libevmjit/Utils.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "Utils.h" - -#include - -#include "BuildInfo.gen.h" - -#if !defined(NDEBUG) // Debug - -namespace dev -{ -namespace evmjit -{ - -std::ostream& getLogStream(char const* _channel) -{ - static std::ostream nullStream{nullptr}; -#if LLVM_DEBUG - return (llvm::DebugFlag && llvm::isCurrentDebugType(_channel)) ? std::cerr : nullStream; -#else - return (void)_channel, nullStream; -#endif -} - -} -} - -#endif diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h deleted file mode 100644 index 0caf5e1bd..000000000 --- a/evmjit/libevmjit/Utils.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -// The same as assert, but expression is always evaluated and result returned -#define CHECK(expr) (assert(expr), expr) - -#if !defined(NDEBUG) // Debug - -namespace dev -{ -namespace evmjit -{ - -std::ostream& getLogStream(char const* _channel); - -} -} - -#define DLOG(CHANNEL) ::dev::evmjit::getLogStream(#CHANNEL) - -#else // Release - -namespace dev -{ -namespace evmjit -{ - -struct Voider -{ - void operator=(std::ostream const&) {} -}; - -} -} - - -#define DLOG(CHANNEL) true ? (void)0 : ::dev::evmjit::Voider{} = std::cerr - -#endif diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_end.h b/evmjit/libevmjit/preprocessor/llvm_includes_end.h deleted file mode 100644 index 2ead6dda3..000000000 --- a/evmjit/libevmjit/preprocessor/llvm_includes_end.h +++ /dev/null @@ -1,7 +0,0 @@ -#if defined(_MSC_VER) - #pragma warning(pop) -#elif defined(__clang__) - #pragma clang diagnostic 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 deleted file mode 100644 index 12a6aeea6..000000000 --- a/evmjit/libevmjit/preprocessor/llvm_includes_start.h +++ /dev/null @@ -1,12 +0,0 @@ -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable: 4267 4244 4800 4624) -#elif defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wunused-parameter" - #pragma clang diagnostic ignored "-Wconversion" -#else - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-parameter" - #pragma GCC diagnostic ignored "-Wconversion" -#endif