From 3df5a125fa0baa579528abce80402118cad803fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 16:04:38 +0100 Subject: [PATCH] Do not compile LLVM module if machine code available in memory --- evmcc/evmcc.cpp | 5 ++- libevmjit/Compiler.cpp | 11 ++--- libevmjit/Compiler.h | 2 +- libevmjit/ExecutionEngine.cpp | 80 ++++++++++++++++++----------------- libevmjit/ExecutionEngine.h | 7 --- 5 files changed, 49 insertions(+), 56 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 9ac3639e2c..3c43ab78bf 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -132,7 +132,7 @@ int main(int argc, char** argv) compilerOptions.rewriteSwitchToBranches = optimize || options.count("rewrite-switch") > 0; auto compiler = eth::jit::Compiler(compilerOptions); - auto module = compiler.compile(bytecode); + auto module = compiler.compile(bytecode, "main"); auto compilationEndTime = std::chrono::high_resolution_clock::now(); @@ -201,7 +201,8 @@ int main(int argc, char** argv) data.code = bytecode.data(); // BROKEN: env_* functions must be implemented & RuntimeData struct created - auto result = engine.run(std::move(module), &data, nullptr, bytecode); + // TODO: Do not compile module again + auto result = engine.run(bytecode, &data, nullptr); return static_cast(result); } } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8d4556d87f..73c96b60bc 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -152,19 +152,14 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); } -std::unique_ptr Compiler::compile(bytes const& _bytecode) +std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) { - // TODO: Better hash of code needed, probably SHA3 - std::string code{reinterpret_cast(_bytecode.data()), _bytecode.size()}; - auto hash = std::hash{}(code); - auto strHash = std::to_string(hash); - auto compilationStartTime = std::chrono::high_resolution_clock::now(); - auto module = std::unique_ptr(new llvm::Module(strHash, m_builder.getContext())); + 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, strHash, module.get()); + m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); // Create the basic blocks. diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index e021bfdefa..8e3bf357c9 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -39,7 +39,7 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytes const& _bytecode); + std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); private: diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 5c0125f35a..23a64da655 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -21,13 +21,6 @@ namespace eth namespace jit { -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) -{ - auto module = Compiler({}).compile(_code); - //module->dump(); - return run(std::move(module), _data, _env, _code); -} - namespace { typedef ReturnCode(*EntryFuncPtr)(Runtime*); @@ -48,50 +41,61 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) } } -ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) +ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? + + // TODO: Better hash of code needed, probably SHA3 + std::string code{reinterpret_cast(_code.data()), _code.size()}; + auto hash = std::hash{}(code); + auto mainFuncName = std::to_string(hash); + EntryFuncPtr entryFuncPtr{}; - auto&& mainFuncName = _module->getModuleIdentifier(); Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls - if (!ee) + if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(_module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); - - 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()); - - ee.reset(builder.create()); - if (!ee) - return ReturnCode::LLVMConfigError; - - _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - //ee->setObjectCache(Cache::getObjectCache()); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else { - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - if (!entryFuncPtr) + auto module = Compiler({}).compile(_code, mainFuncName); + if (!ee) { - ee->addModule(_module.get()); - _module.release(); + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + std::unique_ptr memoryManager(new llvm::SectionMemoryManager); + builder.setMCJITMemoryManager(memoryManager.get()); + builder.setOptLevel(llvm::CodeGenOpt::None); + + 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()); + + ee.reset(builder.create()); + if (!ee) + return ReturnCode::LLVMConfigError; + + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + memoryManager.release(); // and memory manager + + //ee->setObjectCache(Cache::getObjectCache()); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } + else + { + if (!entryFuncPtr) + { + ee->addModule(module.get()); + module.release(); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + } + } } assert(entryFuncPtr); diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 8ca416c48d..559701bba7 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,10 +1,5 @@ #pragma once -namespace llvm -{ - class Module; -} - #include "RuntimeData.h" namespace dev @@ -13,7 +8,6 @@ namespace eth { namespace jit { -class ExecBundle; class ExecutionEngine { @@ -23,7 +17,6 @@ public: void operator=(ExecutionEngine) = delete; ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); - ReturnCode run(std::unique_ptr module, RuntimeData* _data, Env* _env, bytes const& _code); bytes returnData; };