From e0c176f377654e509cdbe1e2e8c6c1005875b0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 15 May 2015 14:06:42 +0200 Subject: [PATCH] Extract execution context from ExecutionEngine::run. --- libevmjit-cpp/JitVM.cpp | 5 +- libevmjit-cpp/JitVM.h | 2 +- libevmjit/ExecutionEngine.cpp | 86 ++++++++++++++++++++--------------- libevmjit/ExecutionEngine.h | 24 +++++++--- libevmjit/interface.cpp | 14 +++--- 5 files changed, 76 insertions(+), 55 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 7acbec5c1..85109ebbc 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include "Utils.h" @@ -56,7 +55,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) m_data.codeHash = eth2llvm(sha3(_ext.code)); auto env = reinterpret_cast(&_ext); - auto exitCode = m_engine.run(&m_data, env); + auto exitCode = jit::ExecutionEngine::run(m_context, &m_data, env); switch (exitCode) { case ReturnCode::Suicide: @@ -79,7 +78,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) } m_gas = m_data.gas; // TODO: Remove m_gas field - return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)}; + return {std::get<0>(m_context.returnData), std::get<1>(m_context.returnData)}; } } diff --git a/libevmjit-cpp/JitVM.h b/libevmjit-cpp/JitVM.h index 58caa3648..4bd4a7bbf 100644 --- a/libevmjit-cpp/JitVM.h +++ b/libevmjit-cpp/JitVM.h @@ -17,7 +17,7 @@ private: explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} jit::RuntimeData m_data; - jit::ExecutionEngine m_engine; + jit::ExecutionContext m_context; std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT }; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 0377ac402..741a7d764 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -90,65 +90,77 @@ void parseOptions() cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); } +// FIXME: It is temporary, becaue ExecutionEngine.h is currently our public header +// and including llvm::ExecutionEngine there is not a good idea. +llvm::ExecutionEngine* g_ee = nullptr; + } +ExecutionEngine& ExecutionEngine::get() +{ + static ExecutionEngine instance; + return instance; +} -ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) +ExecutionEngine::ExecutionEngine() { - static std::once_flag flag; - std::call_once(flag, parseOptions); + /// ExecutionEngine is created only once - std::unique_ptr listener{new ExecStats}; - listener->stateChanged(ExecState::Started); + parseOptions(); + + if (g_cache == CacheMode::clear) + Cache::clear(); bool preloadCache = g_cache == CacheMode::preload; if (preloadCache) g_cache = CacheMode::on; - // 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; + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); - static std::unique_ptr ee; - if (!ee) - { - if (g_cache == CacheMode::clear) - Cache::clear(); + 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::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); + llvm::EngineBuilder builder(std::move(module)); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); - auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); + g_ee = (builder.create()); - // 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()); + // TODO: Update cache listener + auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, nullptr) : nullptr; + g_ee->setObjectCache(objectCache); - llvm::EngineBuilder builder(std::move(module)); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); + // FIXME: Disabled during API changes + //if (preloadCache) + // Cache::preload(*ee, funcCache); +} + + +ReturnCode ExecutionEngine::run(ExecutionContext& _context, RuntimeData* _data, Env* _env) +{ + ExecutionEngine::get(); // FIXME + + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); - ee.reset(builder.create()); - if (!CHECK(ee)) - return ReturnCode::LLVMConfigError; - ee->setObjectCache(objectCache); - // FIXME: Disabled during API changes - //if (preloadCache) - // Cache::preload(*ee, funcCache); - } static StatsCollector statsCollector; auto mainFuncName = codeHash(_data->codeHash); - m_runtime.init(_data, _env); + _context.m_runtime.init(_data, _env); // TODO: Remove cast auto entryFuncPtr = (EntryFuncPtr) JIT::getCode(_data->codeHash); if (!entryFuncPtr) { - auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; + auto module = Cache::getObject(mainFuncName); if (!module) { listener->stateChanged(ExecState::Compilation); @@ -166,20 +178,20 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (g_dump) module->dump(); - ee->addModule(std::move(module)); + g_ee->addModule(std::move(module)); listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + entryFuncPtr = (EntryFuncPtr)g_ee->getFunctionAddress(mainFuncName); if (!CHECK(entryFuncPtr)) return ReturnCode::LLVMLinkError; JIT::mapCode(_data->codeHash, (void*)entryFuncPtr); // FIXME: Remove cast } listener->stateChanged(ExecState::Execution); - auto returnCode = entryFuncPtr(&m_runtime); + auto returnCode = entryFuncPtr(&_context.m_runtime); listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) - returnData = m_runtime.getReturnData(); // Save reference to return data + _context.returnData = _context.m_runtime.getReturnData(); // Save reference to return data listener->stateChanged(ExecState::Finished); diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 26da6977c..c380b6cb5 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -38,22 +38,32 @@ public: virtual void stateChanged(ExecState) {} }; -class ExecutionEngine +class ExecutionContext { public: - ExecutionEngine() = default; - ExecutionEngine(ExecutionEngine const&) = delete; - ExecutionEngine& operator=(ExecutionEngine) = delete; - - EXPORT ReturnCode run(RuntimeData* _data, Env* _env); + ExecutionContext() = default; + ExecutionContext(ExecutionContext const&) = delete; + ExecutionContext& operator=(ExecutionContext const&) = delete; /// Reference to returned data (RETURN opcode used) bytes_ref returnData; -private: Runtime m_runtime; }; +class ExecutionEngine +{ +public: + ExecutionEngine(ExecutionEngine const&) = delete; + ExecutionEngine& operator=(ExecutionEngine const&) = delete; + + EXPORT static ReturnCode run(ExecutionContext& _context, RuntimeData* _data, Env* _env); + +private: + ExecutionEngine(); + static ExecutionEngine& get(); +}; + } } } diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index 01f743a2e..bc9d98474 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -7,23 +7,23 @@ using namespace dev::eth::jit; EXPORT void* evmjit_create() noexcept { - // TODO: Make sure ExecutionEngine constructor does not throw - return new(std::nothrow) ExecutionEngine; + // TODO: Make sure ExecutionEngine constructor does not throw + make JIT/ExecutionEngine interface all nothrow + return new(std::nothrow) ExecutionContext; } -EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept +EXPORT void evmjit_destroy(ExecutionContext* _context) noexcept { - delete _engine; + delete _context; } -EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept +EXPORT int evmjit_run(ExecutionContext* _context, RuntimeData* _data, Env* _env) noexcept { - if (!_engine || !_data) + if (!_context || !_data) return static_cast(ReturnCode::UnexpectedException); try { - auto returnCode = _engine->run(_data, _env); + auto returnCode = ExecutionEngine::run(*_context, _data, _env); return static_cast(returnCode); } catch(...)