Browse Source

Extract execution context from ExecutionEngine::run.

cl-refactor
Paweł Bylica 10 years ago
parent
commit
e0c176f377
  1. 5
      libevmjit-cpp/JitVM.cpp
  2. 2
      libevmjit-cpp/JitVM.h
  3. 86
      libevmjit/ExecutionEngine.cpp
  4. 24
      libevmjit/ExecutionEngine.h
  5. 14
      libevmjit/interface.cpp

5
libevmjit-cpp/JitVM.cpp

@ -7,7 +7,6 @@
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <evmjit/libevmjit/ExecutionEngine.h>
#include "Utils.h" #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)); m_data.codeHash = eth2llvm(sha3(_ext.code));
auto env = reinterpret_cast<Env*>(&_ext); auto env = reinterpret_cast<Env*>(&_ext);
auto exitCode = m_engine.run(&m_data, env); auto exitCode = jit::ExecutionEngine::run(m_context, &m_data, env);
switch (exitCode) switch (exitCode)
{ {
case ReturnCode::Suicide: 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 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)};
} }
} }

2
libevmjit-cpp/JitVM.h

@ -17,7 +17,7 @@ private:
explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} explicit JitVM(u256 _gas = 0) : VMFace(_gas) {}
jit::RuntimeData m_data; jit::RuntimeData m_data;
jit::ExecutionEngine m_engine; jit::ExecutionContext m_context;
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
}; };

86
libevmjit/ExecutionEngine.cpp

@ -90,65 +90,77 @@ void parseOptions()
cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); 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; /// ExecutionEngine is created only once
std::call_once(flag, parseOptions);
std::unique_ptr<ExecStats> listener{new ExecStats}; parseOptions();
listener->stateChanged(ExecState::Started);
if (g_cache == CacheMode::clear)
Cache::clear();
bool preloadCache = g_cache == CacheMode::preload; bool preloadCache = g_cache == CacheMode::preload;
if (preloadCache) if (preloadCache)
g_cache = CacheMode::on; g_cache = CacheMode::on;
// TODO: Do not pseudo-init the cache every time llvm::InitializeNativeTarget();
auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr; llvm::InitializeNativeTargetAsmPrinter();
static std::unique_ptr<llvm::ExecutionEngine> ee; auto module = std::unique_ptr<llvm::Module>(new llvm::Module({}, llvm::getGlobalContext()));
if (!ee)
{ // FIXME: LLVM 3.7: test on Windows
if (g_cache == CacheMode::clear) auto triple = llvm::Triple(llvm::sys::getProcessTriple());
Cache::clear(); 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::EngineBuilder builder(std::move(module));
llvm::InitializeNativeTargetAsmPrinter(); builder.setEngineKind(llvm::EngineKind::JIT);
builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);
auto module = std::unique_ptr<llvm::Module>(new llvm::Module({}, llvm::getGlobalContext())); g_ee = (builder.create());
// FIXME: LLVM 3.7: test on Windows // TODO: Update cache listener
auto triple = llvm::Triple(llvm::sys::getProcessTriple()); auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, nullptr) : nullptr;
if (triple.getOS() == llvm::Triple::OSType::Win32) g_ee->setObjectCache(objectCache);
triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format
module->setTargetTriple(triple.str());
llvm::EngineBuilder builder(std::move(module)); // FIXME: Disabled during API changes
builder.setEngineKind(llvm::EngineKind::JIT); //if (preloadCache)
builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); // Cache::preload(*ee, funcCache);
}
ReturnCode ExecutionEngine::run(ExecutionContext& _context, RuntimeData* _data, Env* _env)
{
ExecutionEngine::get(); // FIXME
std::unique_ptr<ExecStats> 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; static StatsCollector statsCollector;
auto mainFuncName = codeHash(_data->codeHash); auto mainFuncName = codeHash(_data->codeHash);
m_runtime.init(_data, _env); _context.m_runtime.init(_data, _env);
// TODO: Remove cast // TODO: Remove cast
auto entryFuncPtr = (EntryFuncPtr) JIT::getCode(_data->codeHash); auto entryFuncPtr = (EntryFuncPtr) JIT::getCode(_data->codeHash);
if (!entryFuncPtr) if (!entryFuncPtr)
{ {
auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; auto module = Cache::getObject(mainFuncName);
if (!module) if (!module)
{ {
listener->stateChanged(ExecState::Compilation); listener->stateChanged(ExecState::Compilation);
@ -166,20 +178,20 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
if (g_dump) if (g_dump)
module->dump(); module->dump();
ee->addModule(std::move(module)); g_ee->addModule(std::move(module));
listener->stateChanged(ExecState::CodeGen); listener->stateChanged(ExecState::CodeGen);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); entryFuncPtr = (EntryFuncPtr)g_ee->getFunctionAddress(mainFuncName);
if (!CHECK(entryFuncPtr)) if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError; return ReturnCode::LLVMLinkError;
JIT::mapCode(_data->codeHash, (void*)entryFuncPtr); // FIXME: Remove cast JIT::mapCode(_data->codeHash, (void*)entryFuncPtr); // FIXME: Remove cast
} }
listener->stateChanged(ExecState::Execution); listener->stateChanged(ExecState::Execution);
auto returnCode = entryFuncPtr(&m_runtime); auto returnCode = entryFuncPtr(&_context.m_runtime);
listener->stateChanged(ExecState::Return); listener->stateChanged(ExecState::Return);
if (returnCode == ReturnCode::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); listener->stateChanged(ExecState::Finished);

24
libevmjit/ExecutionEngine.h

@ -38,22 +38,32 @@ public:
virtual void stateChanged(ExecState) {} virtual void stateChanged(ExecState) {}
}; };
class ExecutionEngine class ExecutionContext
{ {
public: public:
ExecutionEngine() = default; ExecutionContext() = default;
ExecutionEngine(ExecutionEngine const&) = delete; ExecutionContext(ExecutionContext const&) = delete;
ExecutionEngine& operator=(ExecutionEngine) = delete; ExecutionContext& operator=(ExecutionContext const&) = delete;
EXPORT ReturnCode run(RuntimeData* _data, Env* _env);
/// Reference to returned data (RETURN opcode used) /// Reference to returned data (RETURN opcode used)
bytes_ref returnData; bytes_ref returnData;
private:
Runtime m_runtime; 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();
};
} }
} }
} }

14
libevmjit/interface.cpp

@ -7,23 +7,23 @@ using namespace dev::eth::jit;
EXPORT void* evmjit_create() noexcept EXPORT void* evmjit_create() noexcept
{ {
// TODO: Make sure ExecutionEngine constructor does not throw // TODO: Make sure ExecutionEngine constructor does not throw + make JIT/ExecutionEngine interface all nothrow
return new(std::nothrow) ExecutionEngine; 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<int>(ReturnCode::UnexpectedException); return static_cast<int>(ReturnCode::UnexpectedException);
try try
{ {
auto returnCode = _engine->run(_data, _env); auto returnCode = ExecutionEngine::run(*_context, _data, _env);
return static_cast<int>(returnCode); return static_cast<int>(returnCode);
} }
catch(...) catch(...)

Loading…
Cancel
Save