Browse Source

Merge remote-tracking branch 'upstream/develop' into evmjit-llvm37

cl-refactor
Paweł Bylica 10 years ago
parent
commit
195f00cf2f
  1. 4
      CMakeLists.txt
  2. 56
      include/evmjit/DataTypes.h
  3. 36
      include/evmjit/JIT.h
  4. 3
      libevmjit-cpp/CMakeLists.txt
  5. 38
      libevmjit-cpp/Env.cpp
  6. 22
      libevmjit-cpp/JitVM.cpp
  7. 6
      libevmjit-cpp/JitVM.h
  8. 14
      libevmjit-cpp/Utils.h
  9. 43
      libevmjit/Array.cpp
  10. 3
      libevmjit/CMakeLists.txt
  11. 27
      libevmjit/Cache.cpp
  12. 12
      libevmjit/Common.h
  13. 24
      libevmjit/ExecutionEngine.cpp
  14. 46
      libevmjit/JIT.cpp
  15. 7
      libevmjit/RuntimeData.h

4
CMakeLists.txt

@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF)
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
else() else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas ${CMAKE_CXX_FLAGS}")
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
@ -33,6 +33,8 @@ else()
link_directories(/usr/lib/llvm-3.7/lib) link_directories(/usr/lib/llvm-3.7/lib)
endif() endif()
get_filename_component(EVMJIT_INCLUDE_DIR include ABSOLUTE)
add_subdirectory(libevmjit) add_subdirectory(libevmjit)
if(EVMJIT_CPP) if(EVMJIT_CPP)

56
include/evmjit/DataTypes.h

@ -0,0 +1,56 @@
#pragma once
#include <cstdint>
#include <functional>
namespace dev
{
namespace evmjit
{
struct h256
{
uint64_t words[4];
};
inline bool operator==(h256 _h1, h256 _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 a = 0;
uint64_t b = 0;
uint64_t c = 0;
uint64_t d = 0;
i256() = default;
i256(h256 _h)
{
a = _h.words[0];
b = _h.words[1];
c = _h.words[2];
d = _h.words[3];
}
};
}
}
namespace std
{
template<> struct hash<dev::evmjit::h256>
{
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<size_t>(_h.words[0]);
};
};
}

36
include/evmjit/JIT.h

@ -0,0 +1,36 @@
#pragma once
#include "evmjit/DataTypes.h"
namespace dev
{
namespace eth
{
namespace jit
{
class ExecutionEngine;
}
}
namespace evmjit
{
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.
static bool isCodeReady(h256 _codeHash);
private:
friend class dev::eth::jit::ExecutionEngine;
static uint64_t getCode(h256 _codeHash);
static void mapCode(h256 _codeHash, uint64_t _funcAddr);
};
}
}

3
libevmjit-cpp/CMakeLists.txt

@ -15,10 +15,11 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive
endif() endif()
add_library(${TARGET_NAME} ${SOURCES}) add_library(${TARGET_NAME} STATIC ${SOURCES})
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs")
include_directories(../..) include_directories(../..)
include_directories(${EVMJIT_INCLUDE_DIR})
include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})

38
libevmjit-cpp/Env.cpp

@ -1,8 +1,9 @@
#pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wconversion"
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include <libethcore/Params.h> #include <libevmcore/Params.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include <evmjit/DataTypes.h>
#include "Utils.h" #include "Utils.h"
@ -16,7 +17,7 @@ extern "C"
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using jit::i256; using evmjit::i256;
EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value)
{ {
@ -53,7 +54,7 @@ extern "C"
if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024)
{ {
u256 gas = *io_gas; u256 gas = *io_gas;
h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); h256 address(_env->create(endowment, gas, {_initBeg, (size_t)_initSize}, {}), h256::AlignRight);
*io_gas = static_cast<int64_t>(gas); *io_gas = static_cast<int64_t>(gas);
*o_address = address; *o_address = address;
} }
@ -63,19 +64,24 @@ extern "C"
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) EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, int64_t _callGas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress)
{ {
auto value = llvm2eth(*_value); CallParameters params;
auto receiveAddress = right160(*_receiveAddress); params.value = llvm2eth(*_value);
auto codeAddress = right160(*_codeAddress); params.senderAddress = _env->myAddress;
const auto isCall = receiveAddress == codeAddress; // OPT: The same address pointer can be used if not CODECALL 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; *io_gas -= _callGas;
if (*io_gas < 0) if (*io_gas < 0)
return false; return false;
if (isCall && !_env->exists(receiveAddress)) if (isCall && !_env->exists(params.receiveAddress))
*io_gas -= static_cast<int64_t>(c_callNewAccountGas); // no underflow, *io_gas non-negative before *io_gas -= static_cast<int64_t>(c_callNewAccountGas); // no underflow, *io_gas non-negative before
if (value > 0) // value transfer if (params.value > 0) // value transfer
{ {
/*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible"); /*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible");
*io_gas -= static_cast<int64_t>(c_callValueTransferGas); // no underflow *io_gas -= static_cast<int64_t>(c_callValueTransferGas); // no underflow
@ -86,17 +92,17 @@ extern "C"
return false; return false;
auto ret = false; auto ret = false;
auto callGas = u256{_callGas}; params.gas = u256{_callGas};
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) if (_env->balance(_env->myAddress) >= params.value && _env->depth < 1024)
ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress); ret = _env->call(params);
*io_gas += static_cast<int64_t>(callGas); // it is never more than initial _callGas *io_gas += static_cast<int64_t>(params.gas); // it is never more than initial _callGas
return ret; return ret;
} }
EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash)
{ {
auto hash = sha3({_begin, _size}); auto hash = sha3({_begin, (size_t)_size});
*o_hash = hash; *o_hash = hash;
} }
@ -124,7 +130,7 @@ extern "C"
if (_topic4) if (_topic4)
topics.push_back(*_topic4); topics.push_back(*_topic4);
_env->log(std::move(topics), {_beg, _size}); _env->log(std::move(topics), {_beg, (size_t)_size});
} }
} }

22
libevmjit-cpp/JitVM.cpp

@ -4,7 +4,7 @@
#include "JitVM.h" #include "JitVM.h"
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h> #include <libdevcore/SHA3.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <evmjit/libevmjit/ExecutionEngine.h> #include <evmjit/libevmjit/ExecutionEngine.h>
@ -18,29 +18,25 @@ namespace eth
extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below
bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
{ {
using namespace jit; using namespace jit;
auto rejected = false; auto rejected = false;
// TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope
rejected |= m_gas > std::numeric_limits<decltype(m_data.gas)>::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= io_gas > std::numeric_limits<decltype(m_data.gas)>::max(); // Do not accept requests with gas > 2^63 (int64 max)
rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max(); rejected |= _ext.gasPrice > std::numeric_limits<decltype(m_data.gasPrice)>::max();
rejected |= _ext.currentBlock.number > std::numeric_limits<decltype(m_data.number)>::max(); rejected |= _ext.currentBlock.number > std::numeric_limits<decltype(m_data.number)>::max();
rejected |= _ext.currentBlock.timestamp > std::numeric_limits<decltype(m_data.timestamp)>::max(); rejected |= _ext.currentBlock.timestamp > std::numeric_limits<decltype(m_data.timestamp)>::max();
if (rejected) if (rejected)
{ {
cwarn << "Execution rejected by EVM JIT (gas limit: " << m_gas << "), executing with interpreter"; cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter";
VMFactory::setKind(VMKind::Interpreter); m_fallbackVM = VMFactory::create(VMKind::Interpreter);
m_fallbackVM = VMFactory::create(m_gas); return m_fallbackVM->execImpl(io_gas, _ext, _onOp);
VMFactory::setKind(VMKind::JIT);
auto&& output = m_fallbackVM->go(_ext, _onOp, _step);
m_gas = m_fallbackVM->gas(); // copy remaining gas, Executive expects it
return output;
} }
m_data.gas = static_cast<decltype(m_data.gas)>(m_gas); m_data.gas = static_cast<decltype(m_data.gas)>(io_gas);
m_data.gasPrice = static_cast<decltype(m_data.gasPrice)>(_ext.gasPrice); m_data.gasPrice = static_cast<decltype(m_data.gasPrice)>(_ext.gasPrice);
m_data.callData = _ext.data.data(); m_data.callData = _ext.data.data();
m_data.callDataSize = _ext.data.size(); m_data.callDataSize = _ext.data.size();
@ -55,7 +51,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
m_data.timestamp = static_cast<decltype(m_data.timestamp)>(_ext.currentBlock.timestamp); m_data.timestamp = static_cast<decltype(m_data.timestamp)>(_ext.currentBlock.timestamp);
m_data.code = _ext.code.data(); m_data.code = _ext.code.data();
m_data.codeSize = _ext.code.size(); m_data.codeSize = _ext.code.size();
m_data.codeHash = eth2llvm(sha3(_ext.code)); m_data.codeHash = eth2llvm(_ext.codeHash);
auto env = reinterpret_cast<Env*>(&_ext); auto env = reinterpret_cast<Env*>(&_ext);
auto exitCode = m_engine.run(&m_data, env); auto exitCode = m_engine.run(&m_data, env);
@ -80,7 +76,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
break; break;
} }
m_gas = m_data.gas; // TODO: Remove m_gas field io_gas = m_data.gas;
return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)}; return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)};
} }

6
libevmjit-cpp/JitVM.h

@ -10,12 +10,10 @@ namespace eth
class JitVM: public VMFace class JitVM: public VMFace
{ {
virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; public:
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final;
private: private:
friend class VMFactory;
explicit JitVM(u256 _gas = 0) : VMFace(_gas) {}
jit::RuntimeData m_data; jit::RuntimeData m_data;
jit::ExecutionEngine m_engine; jit::ExecutionEngine m_engine;
std::unique_ptr<VMFace> m_fallbackVM; ///< VM used in case of input data rejected by JIT std::unique_ptr<VMFace> m_fallbackVM; ///< VM used in case of input data rejected by JIT

14
libevmjit-cpp/Utils.h

@ -1,13 +1,13 @@
#pragma once #pragma once
#include <evmjit/libevmjit/Common.h> #include <evmjit/DataTypes.h>
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
inline u256 llvm2eth(jit::i256 _i) inline u256 llvm2eth(evmjit::i256 _i)
{ {
u256 u = 0; u256 u = 0;
u |= _i.d; u |= _i.d;
@ -20,9 +20,9 @@ inline u256 llvm2eth(jit::i256 _i)
return u; return u;
} }
inline jit::i256 eth2llvm(u256 _u) inline evmjit::i256 eth2llvm(u256 _u)
{ {
jit::i256 i; evmjit::i256 i;
u256 mask = 0xFFFFFFFFFFFFFFFF; u256 mask = 0xFFFFFFFFFFFFFFFF;
i.a = static_cast<uint64_t>(_u & mask); i.a = static_cast<uint64_t>(_u & mask);
_u >>= 64; _u >>= 64;
@ -34,5 +34,11 @@ inline jit::i256 eth2llvm(u256 _u)
return i; return i;
} }
inline evmjit::h256 eth2llvm(h256 _u)
{
/// Just directly copies memory
return *(evmjit::h256*)&_u;
}
} }
} }

43
libevmjit/Array.cpp

@ -9,8 +9,6 @@
#include "Runtime.h" #include "Runtime.h"
#include "Utils.h" #include "Utils.h"
#include <set> // DEBUG only
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -269,52 +267,15 @@ void Array::extend(llvm::Value* _arrayPtr, llvm::Value* _size)
} }
} }
namespace
{
struct AllocatedMemoryWatchdog
{
std::set<void*> allocatedMemory;
~AllocatedMemoryWatchdog()
{
if (!allocatedMemory.empty())
{
DLOG(mem) << allocatedMemory.size() << " MEM LEAKS!\n";
for (auto&& leak : allocatedMemory)
DLOG(mem) << "\t" << leak << "\n";
}
}
};
AllocatedMemoryWatchdog watchdog;
}
extern "C" extern "C"
{ {
using namespace dev::eth::jit;
EXPORT void* ext_realloc(void* _data, size_t _size) noexcept EXPORT void* ext_realloc(void* _data, size_t _size) noexcept
{ {
//std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl; return std::realloc(_data, _size);
auto newData = std::realloc(_data, _size);
if (_data != newData)
{
DLOG(mem) << "REALLOC: " << newData << " <- " << _data << " [" << _size << "]\n";
watchdog.allocatedMemory.erase(_data);
watchdog.allocatedMemory.insert(newData);
}
return newData;
} }
EXPORT void ext_free(void* _data) noexcept EXPORT void ext_free(void* _data) noexcept
{ {
std::free(_data); std::free(_data);
if (_data)
{
DLOG(mem) << "FREE : " << _data << "\n";
watchdog.allocatedMemory.erase(_data);
}
} }
}
} // extern "C"

3
libevmjit/CMakeLists.txt

@ -8,6 +8,7 @@ set(SOURCES
Common.h Common.h
Compiler.cpp Compiler.h Compiler.cpp Compiler.h
CompilerHelper.cpp CompilerHelper.h CompilerHelper.cpp CompilerHelper.h
${EVMJIT_INCLUDE_DIR}/evmjit/DataTypes.h
Endianness.cpp Endianness.h Endianness.cpp Endianness.h
ExecStats.cpp ExecStats.h ExecStats.cpp ExecStats.h
ExecutionEngine.cpp ExecutionEngine.h ExecutionEngine.cpp ExecutionEngine.h
@ -15,6 +16,7 @@ set(SOURCES
GasMeter.cpp GasMeter.h GasMeter.cpp GasMeter.h
Instruction.cpp Instruction.h Instruction.cpp Instruction.h
interface.cpp interface.h interface.cpp interface.h
JIT.cpp ${EVMJIT_INCLUDE_DIR}/evmjit/JIT.h
Memory.cpp Memory.h Memory.cpp Memory.h
Optimizer.cpp Optimizer.h Optimizer.cpp Optimizer.h
Runtime.cpp Runtime.h Runtime.cpp Runtime.h
@ -79,6 +81,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES
VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION}
FOLDER "libs") FOLDER "libs")
include_directories(${EVMJIT_INCLUDE_DIR})
include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen)

27
libevmjit/Cache.cpp

@ -1,5 +1,7 @@
#include "Cache.h" #include "Cache.h"
#include <mutex>
#include "preprocessor/llvm_includes_start.h" #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h> #include <llvm/IR/LLVMContext.h>
@ -23,6 +25,8 @@ namespace jit
namespace namespace
{ {
using Guard = std::lock_guard<std::mutex>;
std::mutex x_cacheMutex;
CacheMode g_mode; CacheMode g_mode;
std::unique_ptr<llvm::MemoryBuffer> g_lastObject; std::unique_ptr<llvm::MemoryBuffer> g_lastObject;
ExecutionEngineListener* g_listener; ExecutionEngineListener* g_listener;
@ -43,6 +47,9 @@ namespace
ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener) ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener)
{ {
static ObjectCache objectCache; static ObjectCache objectCache;
Guard g{x_cacheMutex};
g_mode = _mode; g_mode = _mode;
g_listener = _listener; g_listener = _listener;
return &objectCache; return &objectCache;
@ -50,6 +57,8 @@ ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _li
void Cache::clear() void Cache::clear()
{ {
Guard g{x_cacheMutex};
using namespace llvm::sys; using namespace llvm::sys;
llvm::SmallString<256> cachePath; llvm::SmallString<256> cachePath;
path::system_temp_directory(false, cachePath); path::system_temp_directory(false, cachePath);
@ -62,6 +71,8 @@ void Cache::clear()
void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache) void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache)
{ {
Guard g{x_cacheMutex};
// TODO: Cache dir should be in one place // TODO: Cache dir should be in one place
using namespace llvm::sys; using namespace llvm::sys;
llvm::SmallString<256> cachePath; llvm::SmallString<256> cachePath;
@ -91,11 +102,14 @@ void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string,
std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id) std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
{ {
Guard g{x_cacheMutex};
if (g_mode != CacheMode::on && g_mode != CacheMode::read) if (g_mode != CacheMode::on && g_mode != CacheMode::read)
return nullptr; return nullptr;
if (g_listener) // TODO: Disabled because is not thread-safe.
g_listener->stateChanged(ExecState::CacheLoad); //if (g_listener)
// g_listener->stateChanged(ExecState::CacheLoad);
DLOG(cache) << id << ": search\n"; DLOG(cache) << id << ": search\n";
if (!CHECK(!g_lastObject)) if (!CHECK(!g_lastObject))
@ -135,12 +149,15 @@ std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _object) void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _object)
{ {
Guard g{x_cacheMutex};
// Only in "on" and "write" mode // Only in "on" and "write" mode
if (g_mode != CacheMode::on && g_mode != CacheMode::write) if (g_mode != CacheMode::on && g_mode != CacheMode::write)
return; return;
if (g_listener) // TODO: Disabled because is not thread-safe.
g_listener->stateChanged(ExecState::CacheWrite); // if (g_listener)
// g_listener->stateChanged(ExecState::CacheWrite);
auto&& id = _module->getModuleIdentifier(); auto&& id = _module->getModuleIdentifier();
llvm::SmallString<256> cachePath; llvm::SmallString<256> cachePath;
@ -160,6 +177,8 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory
std::unique_ptr<llvm::MemoryBuffer> ObjectCache::getObject(llvm::Module const* _module) std::unique_ptr<llvm::MemoryBuffer> ObjectCache::getObject(llvm::Module const* _module)
{ {
Guard g{x_cacheMutex};
DLOG(cache) << _module->getModuleIdentifier() << ": use\n"; DLOG(cache) << _module->getModuleIdentifier() << ": use\n";
return std::move(g_lastObject); return std::move(g_lastObject);
} }

12
libevmjit/Common.h

@ -31,7 +31,7 @@ enum class ReturnCode
// Standard error codes // Standard error codes
OutOfGas = -1, OutOfGas = -1,
StackUnderflow = -2, StackUnderflow = -2,
BadJumpDestination = -3, BadJumpDestination = -3,
BadInstruction = -4, BadInstruction = -4,
Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected
@ -46,16 +46,6 @@ enum class ReturnCode
LinkerWorkaround = -299, LinkerWorkaround = -299,
}; };
/// Representation of 256-bit value binary compatible with LLVM i256
struct i256
{
uint64_t a = 0;
uint64_t b = 0;
uint64_t c = 0;
uint64_t d = 0;
};
static_assert(sizeof(i256) == 32, "Wrong i265 size");
#define UNTESTED assert(false) #define UNTESTED assert(false)
} }

24
libevmjit/ExecutionEngine.cpp

@ -19,6 +19,7 @@
#include <llvm/Support/ManagedStatic.h> #include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h" #include "preprocessor/llvm_includes_end.h"
#include "evmjit/JIT.h"
#include "Runtime.h" #include "Runtime.h"
#include "Compiler.h" #include "Compiler.h"
#include "Optimizer.h" #include "Optimizer.h"
@ -33,6 +34,7 @@ namespace eth
{ {
namespace jit namespace jit
{ {
using evmjit::JIT;
namespace namespace
{ {
@ -106,8 +108,6 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
// TODO: Do not pseudo-init the cache every time // TODO: Do not pseudo-init the cache every time
auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr; auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr;
static std::unordered_map<std::string, uint64_t> funcCache;
static std::unique_ptr<llvm::ExecutionEngine> ee; static std::unique_ptr<llvm::ExecutionEngine> ee;
if (!ee) if (!ee)
{ {
@ -134,8 +134,9 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
return ReturnCode::LLVMConfigError; return ReturnCode::LLVMConfigError;
ee->setObjectCache(objectCache); ee->setObjectCache(objectCache);
if (preloadCache) // FIXME: Disabled during API changes
Cache::preload(*ee, funcCache); //if (preloadCache)
// Cache::preload(*ee, funcCache);
} }
static StatsCollector statsCollector; static StatsCollector statsCollector;
@ -143,11 +144,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
auto mainFuncName = codeHash(_data->codeHash); auto mainFuncName = codeHash(_data->codeHash);
m_runtime.init(_data, _env); m_runtime.init(_data, _env);
EntryFuncPtr entryFuncPtr = nullptr; // TODO: Remove cast
auto it = funcCache.find(mainFuncName); auto entryFuncPtr = (EntryFuncPtr) JIT::getCode(_data->codeHash);
if (it != funcCache.end())
entryFuncPtr = (EntryFuncPtr) it->second;
if (!entryFuncPtr) if (!entryFuncPtr)
{ {
auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
@ -169,12 +167,10 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
ee->addModule(std::move(module)); ee->addModule(std::move(module));
listener->stateChanged(ExecState::CodeGen); listener->stateChanged(ExecState::CodeGen);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
JIT::mapCode(_data->codeHash, (uint64_t)entryFuncPtr); // FIXME: Remove cast
} }
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
if (it == funcCache.end())
funcCache[mainFuncName] = (uint64_t) entryFuncPtr;
listener->stateChanged(ExecState::Execution); listener->stateChanged(ExecState::Execution);
auto returnCode = entryFuncPtr(&m_runtime); auto returnCode = entryFuncPtr(&m_runtime);

46
libevmjit/JIT.cpp

@ -0,0 +1,46 @@
#include "evmjit/JIT.h"
#include <unordered_map>
namespace dev
{
namespace evmjit
{
namespace
{
class JITImpl: JIT
{
public:
std::unordered_map<h256, uint64_t> codeMap;
static JITImpl& instance()
{
static JITImpl s_instance;
return s_instance;
}
};
} // anonymous namespace
bool JIT::isCodeReady(h256 _codeHash)
{
return JITImpl::instance().codeMap.count(_codeHash) != 0;
}
uint64_t JIT::getCode(h256 _codeHash)
{
auto& codeMap = JITImpl::instance().codeMap;
auto it = codeMap.find(_codeHash);
if (it != codeMap.end())
return it->second;
return 0;
}
void JIT::mapCode(h256 _codeHash, uint64_t _funcAddr)
{
JITImpl::instance().codeMap.insert(std::make_pair(_codeHash, _funcAddr));
}
}
}

7
libevmjit/RuntimeData.h

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "evmjit/DataTypes.h"
#include "Common.h" #include "Common.h"
namespace dev namespace dev
@ -8,7 +9,9 @@ namespace eth
{ {
namespace jit namespace jit
{ {
using evmjit::i256;
using evmjit::h256;
struct RuntimeData struct RuntimeData
{ {
enum Index enum Index
@ -49,7 +52,7 @@ struct RuntimeData
int64_t timestamp = 0; int64_t timestamp = 0;
byte const* code = nullptr; byte const* code = nullptr;
uint64_t codeSize = 0; uint64_t codeSize = 0;
i256 codeHash; h256 codeHash;
}; };
/// VM Environment (ExtVM) opaque type /// VM Environment (ExtVM) opaque type

Loading…
Cancel
Save