diff options
Diffstat (limited to 'lib/ExecutionEngine/MCJIT')
-rw-r--r-- | lib/ExecutionEngine/MCJIT/Android.mk | 5 | ||||
-rw-r--r-- | lib/ExecutionEngine/MCJIT/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/ExecutionEngine/MCJIT/MCJIT.cpp | 101 | ||||
-rw-r--r-- | lib/ExecutionEngine/MCJIT/MCJIT.h | 22 | ||||
-rw-r--r-- | lib/ExecutionEngine/MCJIT/ObjectBuffer.h | 48 | ||||
-rw-r--r-- | lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp | 178 |
6 files changed, 116 insertions, 239 deletions
diff --git a/lib/ExecutionEngine/MCJIT/Android.mk b/lib/ExecutionEngine/MCJIT/Android.mk index 0314958..5827212 100644 --- a/lib/ExecutionEngine/MCJIT/Android.mk +++ b/lib/ExecutionEngine/MCJIT/Android.mk @@ -4,9 +4,8 @@ LOCAL_PATH:= $(call my-dir) # ===================================================== include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - MCJIT.cpp \ - SectionMemoryManager.cpp +LOCAL_SRC_FILES := \ + MCJIT.cpp LOCAL_MODULE:= libLLVMMCJIT diff --git a/lib/ExecutionEngine/MCJIT/CMakeLists.txt b/lib/ExecutionEngine/MCJIT/CMakeLists.txt index 088635a..2911a50 100644 --- a/lib/ExecutionEngine/MCJIT/CMakeLists.txt +++ b/lib/ExecutionEngine/MCJIT/CMakeLists.txt @@ -1,4 +1,3 @@ add_llvm_library(LLVMMCJIT MCJIT.cpp - SectionMemoryManager.cpp ) diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp index da5f037..e500d3d 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -11,26 +11,25 @@ #include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/ExecutionEngine/JITEventListener.h" #include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/ObjectBuffer.h" -#include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/Object/Archive.h" -#include "llvm/PassManager.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MutexGuard.h" -#include "llvm/Target/TargetLowering.h" -#include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; +void ObjectCache::anchor() {} + namespace { static struct RegisterJIT { @@ -44,21 +43,24 @@ extern "C" void LLVMLinkInMCJIT() { ExecutionEngine *MCJIT::createJIT(std::unique_ptr<Module> M, std::string *ErrorStr, - RTDyldMemoryManager *MemMgr, + std::unique_ptr<RTDyldMemoryManager> MemMgr, std::unique_ptr<TargetMachine> TM) { // Try to register the program as a source of symbols to resolve against. // // FIXME: Don't do this here. sys::DynamicLibrary::LoadLibraryPermanently(nullptr, nullptr); - return new MCJIT(std::move(M), std::move(TM), - MemMgr ? MemMgr : new SectionMemoryManager()); + std::unique_ptr<RTDyldMemoryManager> MM = std::move(MemMgr); + if (!MM) + MM = std::unique_ptr<SectionMemoryManager>(new SectionMemoryManager()); + + return new MCJIT(std::move(M), std::move(TM), std::move(MM)); } MCJIT::MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> tm, - RTDyldMemoryManager *MM) + std::unique_ptr<RTDyldMemoryManager> MM) : ExecutionEngine(std::move(M)), TM(std::move(tm)), Ctx(nullptr), - MemMgr(this, MM), Dyld(&MemMgr), ObjCache(nullptr) { + MemMgr(this, std::move(MM)), Dyld(&MemMgr), ObjCache(nullptr) { // FIXME: We are managing our modules, so we do not want the base class // ExecutionEngine to manage them as well. To avoid double destruction // of the first (and only) module added in ExecutionEngine constructor @@ -73,7 +75,8 @@ MCJIT::MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> tm, Modules.clear(); OwnedModules.addModule(std::move(First)); - setDataLayout(TM->getSubtargetImpl()->getDataLayout()); + setDataLayout(TM->getDataLayout()); + RegisterJITEventListener(JITEventListener::createGDBRegistrationListener()); } MCJIT::~MCJIT() { @@ -99,13 +102,13 @@ bool MCJIT::removeModule(Module *M) { } void MCJIT::addObjectFile(std::unique_ptr<object::ObjectFile> Obj) { - std::unique_ptr<ObjectImage> LoadedObject = Dyld.loadObject(std::move(Obj)); - if (!LoadedObject || Dyld.hasError()) + std::unique_ptr<RuntimeDyld::LoadedObjectInfo> L = Dyld.loadObject(*Obj); + if (Dyld.hasError()) report_fatal_error(Dyld.getErrorString()); - NotifyObjectEmitted(*LoadedObject); + NotifyObjectEmitted(*Obj, *L); - LoadedObjects.push_back(std::move(LoadedObject)); + LoadedObjects.push_back(std::move(Obj)); } void MCJIT::addObjectFile(object::OwningBinary<object::ObjectFile> Obj) { @@ -125,43 +128,45 @@ void MCJIT::setObjectCache(ObjectCache* NewCache) { ObjCache = NewCache; } -std::unique_ptr<ObjectBufferStream> MCJIT::emitObject(Module *M) { +std::unique_ptr<MemoryBuffer> MCJIT::emitObject(Module *M) { MutexGuard locked(lock); // This must be a module which has already been added but not loaded to this // MCJIT instance, since these conditions are tested by our caller, // generateCodeForModule. - PassManager PM; + legacy::PassManager PM; - M->setDataLayout(TM->getSubtargetImpl()->getDataLayout()); + M->setDataLayout(TM->getDataLayout()); PM.add(new DataLayoutPass()); // The RuntimeDyld will take ownership of this shortly - std::unique_ptr<ObjectBufferStream> CompiledObject(new ObjectBufferStream()); + SmallVector<char, 4096> ObjBufferSV; + raw_svector_ostream ObjStream(ObjBufferSV); // Turn the machine code intermediate representation into bytes in memory // that may be executed. - if (TM->addPassesToEmitMC(PM, Ctx, CompiledObject->getOStream(), - !getVerifyModules())) { + if (TM->addPassesToEmitMC(PM, Ctx, ObjStream, !getVerifyModules())) report_fatal_error("Target does not support MC emission!"); - } // Initialize passes. PM.run(*M); // Flush the output buffer to get the generated code into memory - CompiledObject->flush(); + ObjStream.flush(); + + std::unique_ptr<MemoryBuffer> CompiledObjBuffer( + new ObjectMemoryBuffer(std::move(ObjBufferSV))); // If we have an object cache, tell it about the new object. // Note that we're using the compiled image, not the loaded image (as below). if (ObjCache) { // MemoryBuffer is a thin wrapper around the actual memory, so it's OK // to create a temporary object here and delete it after the call. - MemoryBufferRef MB = CompiledObject->getMemBuffer(); + MemoryBufferRef MB = CompiledObjBuffer->getMemBufferRef(); ObjCache->notifyObjectCompiled(M, MB); } - return CompiledObject; + return CompiledObjBuffer; } void MCJIT::generateCodeForModule(Module *M) { @@ -176,14 +181,10 @@ void MCJIT::generateCodeForModule(Module *M) { if (OwnedModules.hasModuleBeenLoaded(M)) return; - std::unique_ptr<ObjectBuffer> ObjectToLoad; + std::unique_ptr<MemoryBuffer> ObjectToLoad; // Try to load the pre-compiled object from cache if possible - if (ObjCache) { - if (std::unique_ptr<MemoryBuffer> PreCompiledObject = - ObjCache->getObject(M)) - ObjectToLoad = - llvm::make_unique<ObjectBuffer>(std::move(PreCompiledObject)); - } + if (ObjCache) + ObjectToLoad = ObjCache->getObject(M); // If the cache did not contain a suitable object, compile the object if (!ObjectToLoad) { @@ -193,17 +194,18 @@ void MCJIT::generateCodeForModule(Module *M) { // Load the object into the dynamic linker. // MCJIT now owns the ObjectImage pointer (via its LoadedObjects list). - std::unique_ptr<ObjectImage> LoadedObject = - Dyld.loadObject(std::move(ObjectToLoad)); - if (!LoadedObject) - report_fatal_error(Dyld.getErrorString()); + ErrorOr<std::unique_ptr<object::ObjectFile>> LoadedObject = + object::ObjectFile::createObjectFile(ObjectToLoad->getMemBufferRef()); + std::unique_ptr<RuntimeDyld::LoadedObjectInfo> L = + Dyld.loadObject(*LoadedObject.get()); - // FIXME: Make this optional, maybe even move it to a JIT event listener - LoadedObject->registerWithDebugger(); + if (Dyld.hasError()) + report_fatal_error(Dyld.getErrorString()); - NotifyObjectEmitted(*LoadedObject); + NotifyObjectEmitted(*LoadedObject.get(), *L); - LoadedObjects.push_back(std::move(LoadedObject)); + Buffers.push_back(std::move(ObjectToLoad)); + LoadedObjects.push_back(std::move(*LoadedObject)); OwnedModules.markModuleAsLoaded(M); } @@ -253,7 +255,7 @@ void MCJIT::finalizeModule(Module *M) { } uint64_t MCJIT::getExistingSymbolAddress(const std::string &Name) { - Mangler Mang(TM->getSubtargetImpl()->getDataLayout()); + Mangler Mang(TM->getDataLayout()); SmallString<128> FullName; Mang.getNameWithPrefix(FullName, Name); return Dyld.getSymbolLoadAddress(FullName); @@ -353,7 +355,7 @@ uint64_t MCJIT::getFunctionAddress(const std::string &Name) { void *MCJIT::getPointerToFunction(Function *F) { MutexGuard locked(lock); - Mangler Mang(TM->getSubtargetImpl()->getDataLayout()); + Mangler Mang(TM->getDataLayout()); SmallString<128> Name; TM->getNameWithPrefix(Name, F, Mang); @@ -406,7 +408,8 @@ Function *MCJIT::FindFunctionNamedInModulePtrSet(const char *FnName, ModulePtrSet::iterator I, ModulePtrSet::iterator E) { for (; I != E; ++I) { - if (Function *F = (*I)->getFunction(FnName)) + Function *F = (*I)->getFunction(FnName); + if (F && !F->isDeclaration()) return F; } return nullptr; @@ -549,6 +552,7 @@ void MCJIT::RegisterJITEventListener(JITEventListener *L) { MutexGuard locked(lock); EventListeners.push_back(L); } + void MCJIT::UnregisterJITEventListener(JITEventListener *L) { if (!L) return; @@ -559,14 +563,17 @@ void MCJIT::UnregisterJITEventListener(JITEventListener *L) { EventListeners.pop_back(); } } -void MCJIT::NotifyObjectEmitted(const ObjectImage& Obj) { + +void MCJIT::NotifyObjectEmitted(const object::ObjectFile& Obj, + const RuntimeDyld::LoadedObjectInfo &L) { MutexGuard locked(lock); - MemMgr.notifyObjectLoaded(this, &Obj); + MemMgr.notifyObjectLoaded(this, Obj); for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { - EventListeners[I]->NotifyObjectEmitted(Obj); + EventListeners[I]->NotifyObjectEmitted(Obj, L); } } -void MCJIT::NotifyFreeingObject(const ObjectImage& Obj) { + +void MCJIT::NotifyFreeingObject(const object::ObjectFile& Obj) { MutexGuard locked(lock); for (JITEventListener *L : EventListeners) L->NotifyFreeingObject(Obj); diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.h b/lib/ExecutionEngine/MCJIT/MCJIT.h index bc943b9..de4a8f6 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -15,7 +15,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/ExecutionEngine/ObjectMemoryBuffer.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/Module.h" @@ -28,8 +28,9 @@ class MCJIT; // to that object. class LinkingMemoryManager : public RTDyldMemoryManager { public: - LinkingMemoryManager(MCJIT *Parent, RTDyldMemoryManager *MM) - : ParentEngine(Parent), ClientMM(MM) {} + LinkingMemoryManager(MCJIT *Parent, + std::unique_ptr<RTDyldMemoryManager> MM) + : ParentEngine(Parent), ClientMM(std::move(MM)) {} uint64_t getSymbolAddress(const std::string &Name) override; @@ -57,7 +58,7 @@ public: } void notifyObjectLoaded(ExecutionEngine *EE, - const ObjectImage *Obj) override { + const object::ObjectFile &Obj) override { ClientMM->notifyObjectLoaded(EE, Obj); } @@ -102,7 +103,7 @@ private: class MCJIT : public ExecutionEngine { MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> tm, - RTDyldMemoryManager *MemMgr); + std::unique_ptr<RTDyldMemoryManager> MemMgr); typedef llvm::SmallPtrSet<Module *, 4> ModulePtrSet; @@ -222,7 +223,7 @@ class MCJIT : public ExecutionEngine { SmallVector<object::OwningBinary<object::Archive>, 2> Archives; SmallVector<std::unique_ptr<MemoryBuffer>, 2> Buffers; - SmallVector<std::unique_ptr<ObjectImage>, 2> LoadedObjects; + SmallVector<std::unique_ptr<object::ObjectFile>, 2> LoadedObjects; // An optional ObjectCache to be notified of compiled objects and used to // perform lookup of pre-compiled code to avoid re-compilation. @@ -325,7 +326,7 @@ public: static ExecutionEngine *createJIT(std::unique_ptr<Module> M, std::string *ErrorStr, - RTDyldMemoryManager *MemMgr, + std::unique_ptr<RTDyldMemoryManager> MemMgr, std::unique_ptr<TargetMachine> TM); // @} @@ -341,10 +342,11 @@ protected: /// this function call is expected to be the contained module. The module /// is passed as a parameter here to prepare for multiple module support in /// the future. - std::unique_ptr<ObjectBufferStream> emitObject(Module *M); + std::unique_ptr<MemoryBuffer> emitObject(Module *M); - void NotifyObjectEmitted(const ObjectImage& Obj); - void NotifyFreeingObject(const ObjectImage& Obj); + void NotifyObjectEmitted(const object::ObjectFile& Obj, + const RuntimeDyld::LoadedObjectInfo &L); + void NotifyFreeingObject(const object::ObjectFile& Obj); uint64_t getExistingSymbolAddress(const std::string &Name); Module *findModuleForSymbol(const std::string &Name, diff --git a/lib/ExecutionEngine/MCJIT/ObjectBuffer.h b/lib/ExecutionEngine/MCJIT/ObjectBuffer.h new file mode 100644 index 0000000..92310f3 --- /dev/null +++ b/lib/ExecutionEngine/MCJIT/ObjectBuffer.h @@ -0,0 +1,48 @@ +//===--- ObjectBuffer.h - Utility class to wrap object memory ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares a wrapper class to hold the memory into which an +// object will be generated. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_OBJECTBUFFER_H +#define LLVM_EXECUTIONENGINE_OBJECTBUFFER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +class ObjectMemoryBuffer : public MemoryBuffer { +public: + template <unsigned N> + ObjectMemoryBuffer(SmallVector<char, N> SV) + : SV(SV), BufferName("<in-memory object>") { + init(this->SV.begin(), this->SV.end(), false); + } + + template <unsigned N> + ObjectMemoryBuffer(SmallVector<char, N> SV, StringRef Name) + : SV(SV), BufferName(Name) { + init(this->SV.begin(), this->SV.end(), false); + } + const char* getBufferIdentifier() const override { return BufferName.c_str(); } + + BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; } + +private: + SmallVector<char, 4096> SV; + std::string BufferName; +}; + +} // namespace llvm + +#endif diff --git a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp deleted file mode 100644 index 5986084..0000000 --- a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp +++ /dev/null @@ -1,178 +0,0 @@ -//===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the section-based memory manager used by the MCJIT -// execution engine and RuntimeDyld -// -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/Support/MathExtras.h" - -namespace llvm { - -uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, - unsigned Alignment, - unsigned SectionID, - StringRef SectionName, - bool IsReadOnly) { - if (IsReadOnly) - return allocateSection(RODataMem, Size, Alignment); - return allocateSection(RWDataMem, Size, Alignment); -} - -uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, - unsigned Alignment, - unsigned SectionID, - StringRef SectionName) { - return allocateSection(CodeMem, Size, Alignment); -} - -uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup, - uintptr_t Size, - unsigned Alignment) { - if (!Alignment) - Alignment = 16; - - assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); - - uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1); - uintptr_t Addr = 0; - - // Look in the list of free memory regions and use a block there if one - // is available. - for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) { - sys::MemoryBlock &MB = MemGroup.FreeMem[i]; - if (MB.size() >= RequiredSize) { - Addr = (uintptr_t)MB.base(); - uintptr_t EndOfBlock = Addr + MB.size(); - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - // Store cutted free memory block. - MemGroup.FreeMem[i] = sys::MemoryBlock((void*)(Addr + Size), - EndOfBlock - Addr - Size); - return (uint8_t*)Addr; - } - } - - // No pre-allocated free block was large enough. Allocate a new memory region. - // Note that all sections get allocated as read-write. The permissions will - // be updated later based on memory group. - // - // FIXME: It would be useful to define a default allocation size (or add - // it as a constructor parameter) to minimize the number of allocations. - // - // FIXME: Initialize the Near member for each memory group to avoid - // interleaving. - std::error_code ec; - sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize, - &MemGroup.Near, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE, - ec); - if (ec) { - // FIXME: Add error propagation to the interface. - return nullptr; - } - - // Save this address as the basis for our next request - MemGroup.Near = MB; - - MemGroup.AllocatedMem.push_back(MB); - Addr = (uintptr_t)MB.base(); - uintptr_t EndOfBlock = Addr + MB.size(); - - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - - // The allocateMappedMemory may allocate much more memory than we need. In - // this case, we store the unused memory as a free memory block. - unsigned FreeSize = EndOfBlock-Addr-Size; - if (FreeSize > 16) - MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); - - // Return aligned address - return (uint8_t*)Addr; -} - -bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) -{ - // FIXME: Should in-progress permissions be reverted if an error occurs? - std::error_code ec; - - // Don't allow free memory blocks to be used after setting protection flags. - CodeMem.FreeMem.clear(); - - // Make code memory executable. - ec = applyMemoryGroupPermissions(CodeMem, - sys::Memory::MF_READ | sys::Memory::MF_EXEC); - if (ec) { - if (ErrMsg) { - *ErrMsg = ec.message(); - } - return true; - } - - // Don't allow free memory blocks to be used after setting protection flags. - RODataMem.FreeMem.clear(); - - // Make read-only data memory read-only. - ec = applyMemoryGroupPermissions(RODataMem, - sys::Memory::MF_READ | sys::Memory::MF_EXEC); - if (ec) { - if (ErrMsg) { - *ErrMsg = ec.message(); - } - return true; - } - - // Read-write data memory already has the correct permissions - - // Some platforms with separate data cache and instruction cache require - // explicit cache flush, otherwise JIT code manipulations (like resolved - // relocations) will get to the data cache but not to the instruction cache. - invalidateInstructionCache(); - - return false; -} - -std::error_code -SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, - unsigned Permissions) { - - for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) { - std::error_code ec; - ec = - sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i], Permissions); - if (ec) { - return ec; - } - } - - return std::error_code(); -} - -void SectionMemoryManager::invalidateInstructionCache() { - for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) - sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(), - CodeMem.AllocatedMem[i].size()); -} - -SectionMemoryManager::~SectionMemoryManager() { - for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) - sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]); - for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i) - sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]); - for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i) - sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]); -} - -} // namespace llvm - |