diff options
author | Lang Hames <lhames@gmail.com> | 2014-11-26 06:53:26 +0000 |
---|---|---|
committer | Lang Hames <lhames@gmail.com> | 2014-11-26 06:53:26 +0000 |
commit | 7acaefabf62d31a3edc830e06385495b73bdb8a8 (patch) | |
tree | c6b9cccbbdb86eb6ae04c02fc09de9ae84b9b37c /lib/ExecutionEngine/MCJIT | |
parent | 568f7e8228a560753c23842a81817b6b3211046e (diff) |
[MCJIT] Clean up RuntimeDyld's quirky object-ownership/modification scheme.
Previously, when loading an object file, RuntimeDyld (1) took ownership of the
ObjectFile instance (and associated MemoryBuffer), (2) potentially modified the
object in-place, and (3) returned an ObjectImage that managed ownership of the
now-modified object and provided some convenience methods. This scheme accreted
over several years as features were tacked on to RuntimeDyld, and was both
unintuitive and unsafe (See e.g. http://llvm.org/PR20722).
This patch fixes the issue by removing all ownership and in-place modification
of object files from RuntimeDyld. Existing behavior, including debugger
registration, is preserved.
Noteworthy changes include:
(1) ObjectFile instances are now passed to RuntimeDyld by const-ref.
(2) The ObjectImage and ObjectBuffer classes have been removed entirely, they
existed to model ownership within RuntimeDyld, and so are no longer needed.
(3) RuntimeDyld::loadObject now returns an instance of a new class,
RuntimeDyld::LoadedObjectInfo, which can be used to construct a modified
object suitable for registration with the debugger, following the existing
debugger registration scheme.
(4) The JITRegistrar class has been removed, and the GDBRegistrar class has been
re-written as a JITEventListener.
This should fix http://llvm.org/PR20722 .
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222810 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ExecutionEngine/MCJIT')
-rw-r--r-- | lib/ExecutionEngine/MCJIT/MCJIT.cpp | 71 | ||||
-rw-r--r-- | lib/ExecutionEngine/MCJIT/MCJIT.h | 13 | ||||
-rw-r--r-- | lib/ExecutionEngine/MCJIT/ObjectBuffer.h | 48 |
3 files changed, 93 insertions, 39 deletions
diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp index da5f03799e3..58cf4e5e6dd 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -11,8 +11,6 @@ #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" @@ -21,6 +19,7 @@ #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/PassManager.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/ErrorHandling.h" @@ -31,6 +30,8 @@ using namespace llvm; +void ObjectCache::anchor() {} + namespace { static struct RegisterJIT { @@ -74,6 +75,7 @@ MCJIT::MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> tm, OwnedModules.addModule(std::move(First)); setDataLayout(TM->getSubtargetImpl()->getDataLayout()); + RegisterJITEventListener(JITEventListener::createGDBRegistrationListener()); } MCJIT::~MCJIT() { @@ -99,13 +101,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,7 +127,7 @@ 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 @@ -138,30 +140,32 @@ std::unique_ptr<ObjectBufferStream> MCJIT::emitObject(Module *M) { 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 +180,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 +193,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); } @@ -549,6 +550,7 @@ void MCJIT::RegisterJITEventListener(JITEventListener *L) { MutexGuard locked(lock); EventListeners.push_back(L); } + void MCJIT::UnregisterJITEventListener(JITEventListener *L) { if (!L) return; @@ -559,14 +561,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 bc943b9b886..6f92e51b64c 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -10,12 +10,12 @@ #ifndef LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H #define LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H +#include "ObjectBuffer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/Module.h" @@ -57,7 +57,7 @@ public: } void notifyObjectLoaded(ExecutionEngine *EE, - const ObjectImage *Obj) override { + const object::ObjectFile &Obj) override { ClientMM->notifyObjectLoaded(EE, Obj); } @@ -222,7 +222,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. @@ -341,10 +341,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 00000000000..92310f3eb54 --- /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 |