|
@ -26,7 +26,7 @@ using namespace eth::jit; |
|
|
|
|
|
|
|
|
namespace |
|
|
namespace |
|
|
{ |
|
|
{ |
|
|
using EntryFuncPtr = ReturnCode(*)(ExecutionContext*); |
|
|
using ExecFunc = ReturnCode(*)(ExecutionContext*); |
|
|
|
|
|
|
|
|
std::string hash2str(i256 const& _hash) |
|
|
std::string hash2str(i256 const& _hash) |
|
|
{ |
|
|
{ |
|
@ -78,10 +78,28 @@ void parseOptions() |
|
|
cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); |
|
|
cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::unique_ptr<llvm::ExecutionEngine> init() |
|
|
class JITImpl |
|
|
{ |
|
|
{ |
|
|
/// ExecutionEngine is created only once
|
|
|
std::unique_ptr<llvm::ExecutionEngine> m_engine; |
|
|
|
|
|
std::unordered_map<h256, ExecFunc> 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); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
JITImpl::JITImpl() |
|
|
|
|
|
{ |
|
|
parseOptions(); |
|
|
parseOptions(); |
|
|
|
|
|
|
|
|
bool preloadCache = g_cache == CacheMode::preload; |
|
|
bool preloadCache = g_cache == CacheMode::preload; |
|
@ -103,57 +121,39 @@ std::unique_ptr<llvm::ExecutionEngine> init() |
|
|
builder.setEngineKind(llvm::EngineKind::JIT); |
|
|
builder.setEngineKind(llvm::EngineKind::JIT); |
|
|
builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); |
|
|
builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); |
|
|
|
|
|
|
|
|
auto ee = std::unique_ptr<llvm::ExecutionEngine>{builder.create()}; |
|
|
m_engine.reset(builder.create()); |
|
|
|
|
|
|
|
|
// TODO: Update cache listener
|
|
|
// TODO: Update cache listener
|
|
|
ee->setObjectCache(Cache::init(g_cache, nullptr)); |
|
|
m_engine->setObjectCache(Cache::init(g_cache, nullptr)); |
|
|
|
|
|
|
|
|
// FIXME: Disabled during API changes
|
|
|
// FIXME: Disabled during API changes
|
|
|
//if (preloadCache)
|
|
|
//if (preloadCache)
|
|
|
// Cache::preload(*ee, funcCache);
|
|
|
// Cache::preload(*m_engine, funcCache);
|
|
|
|
|
|
|
|
|
return ee; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
class JITImpl |
|
|
ExecFunc JITImpl::getExecFunc(h256 const& _codeHash) const |
|
|
{ |
|
|
|
|
|
public: |
|
|
|
|
|
std::unordered_map<h256, void*> codeMap; |
|
|
|
|
|
|
|
|
|
|
|
static JITImpl& instance() |
|
|
|
|
|
{ |
|
|
|
|
|
static JITImpl s_instance; |
|
|
|
|
|
return s_instance; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void* getCode(h256 _codeHash); |
|
|
|
|
|
static void mapCode(h256 _codeHash, void* _funcAddr); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
void* JITImpl::getCode(h256 _codeHash) |
|
|
|
|
|
{ |
|
|
{ |
|
|
auto& codeMap = JITImpl::instance().codeMap; |
|
|
auto it = m_codeMap.find(_codeHash); |
|
|
auto it = codeMap.find(_codeHash); |
|
|
if (it != m_codeMap.end()) |
|
|
if (it != codeMap.end()) |
|
|
|
|
|
return it->second; |
|
|
return it->second; |
|
|
return nullptr; |
|
|
return nullptr; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void JITImpl::mapCode(h256 _codeHash, void* _funcAddr) |
|
|
void JITImpl::mapExecFunc(h256 _codeHash, ExecFunc _funcAddr) |
|
|
{ |
|
|
{ |
|
|
JITImpl::instance().codeMap.insert(std::make_pair(_codeHash, _funcAddr)); |
|
|
m_codeMap.emplace(std::move(_codeHash), _funcAddr); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
|
bool JIT::isCodeReady(h256 _codeHash) |
|
|
bool JIT::isCodeReady(h256 const& _codeHash) |
|
|
{ |
|
|
{ |
|
|
return JITImpl::instance().codeMap.count(_codeHash) != 0; |
|
|
return JITImpl::instance().getExecFunc(_codeHash) != nullptr; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ReturnCode JIT::exec(ExecutionContext& _context) |
|
|
ReturnCode JIT::exec(ExecutionContext& _context) |
|
|
{ |
|
|
{ |
|
|
static auto s_ee = init(); |
|
|
auto& jit = JITImpl::instance(); |
|
|
|
|
|
|
|
|
std::unique_ptr<ExecStats> listener{new ExecStats}; |
|
|
std::unique_ptr<ExecStats> listener{new ExecStats}; |
|
|
listener->stateChanged(ExecState::Started); |
|
|
listener->stateChanged(ExecState::Started); |
|
@ -167,8 +167,8 @@ ReturnCode JIT::exec(ExecutionContext& _context) |
|
|
auto mainFuncName = hash2str(codeHash); |
|
|
auto mainFuncName = hash2str(codeHash); |
|
|
|
|
|
|
|
|
// TODO: Remove cast
|
|
|
// TODO: Remove cast
|
|
|
auto entryFuncPtr = (EntryFuncPtr) JITImpl::getCode(codeHash); |
|
|
auto execFunc = jit.getExecFunc(codeHash); |
|
|
if (!entryFuncPtr) |
|
|
if (!execFunc) |
|
|
{ |
|
|
{ |
|
|
auto module = Cache::getObject(mainFuncName); |
|
|
auto module = Cache::getObject(mainFuncName); |
|
|
if (!module) |
|
|
if (!module) |
|
@ -188,16 +188,16 @@ ReturnCode JIT::exec(ExecutionContext& _context) |
|
|
if (g_dump) |
|
|
if (g_dump) |
|
|
module->dump(); |
|
|
module->dump(); |
|
|
|
|
|
|
|
|
s_ee->addModule(std::move(module)); |
|
|
jit.engine().addModule(std::move(module)); |
|
|
listener->stateChanged(ExecState::CodeGen); |
|
|
listener->stateChanged(ExecState::CodeGen); |
|
|
entryFuncPtr = (EntryFuncPtr)s_ee->getFunctionAddress(mainFuncName); |
|
|
execFunc = (ExecFunc)jit.engine().getFunctionAddress(mainFuncName); |
|
|
if (!CHECK(entryFuncPtr)) |
|
|
if (!CHECK(execFunc)) |
|
|
return ReturnCode::LLVMLinkError; |
|
|
return ReturnCode::LLVMLinkError; |
|
|
JITImpl::mapCode(codeHash, (void*)entryFuncPtr); // FIXME: Remove cast
|
|
|
jit.mapExecFunc(codeHash, execFunc); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
listener->stateChanged(ExecState::Execution); |
|
|
listener->stateChanged(ExecState::Execution); |
|
|
auto returnCode = entryFuncPtr(&_context); |
|
|
auto returnCode = execFunc(&_context); |
|
|
listener->stateChanged(ExecState::Return); |
|
|
listener->stateChanged(ExecState::Return); |
|
|
|
|
|
|
|
|
if (returnCode == ReturnCode::Return) |
|
|
if (returnCode == ReturnCode::Return) |
|
|