aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ExecutionEngine/MCJIT
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ExecutionEngine/MCJIT')
-rw-r--r--lib/ExecutionEngine/MCJIT/CMakeLists.txt2
-rw-r--r--lib/ExecutionEngine/MCJIT/LLVMBuild.txt2
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJIT.cpp104
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJIT.h24
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJITMemoryManager.cpp14
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h50
-rw-r--r--lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp226
7 files changed, 327 insertions, 95 deletions
diff --git a/lib/ExecutionEngine/MCJIT/CMakeLists.txt b/lib/ExecutionEngine/MCJIT/CMakeLists.txt
index fef7176..088635a 100644
--- a/lib/ExecutionEngine/MCJIT/CMakeLists.txt
+++ b/lib/ExecutionEngine/MCJIT/CMakeLists.txt
@@ -1,4 +1,4 @@
add_llvm_library(LLVMMCJIT
MCJIT.cpp
- MCJITMemoryManager.cpp
+ SectionMemoryManager.cpp
)
diff --git a/lib/ExecutionEngine/MCJIT/LLVMBuild.txt b/lib/ExecutionEngine/MCJIT/LLVMBuild.txt
index 90f4d2f..900460b 100644
--- a/lib/ExecutionEngine/MCJIT/LLVMBuild.txt
+++ b/lib/ExecutionEngine/MCJIT/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Library
name = MCJIT
parent = ExecutionEngine
-required_libraries = Core ExecutionEngine RuntimeDyld Support Target
+required_libraries = Core ExecutionEngine RuntimeDyld Support Target JIT
diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
index fa71305..fee10e1 100644
--- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp
+++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
@@ -8,18 +8,20 @@
//===----------------------------------------------------------------------===//
#include "MCJIT.h"
-#include "MCJITMemoryManager.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Function.h"
#include "llvm/ExecutionEngine/GenericValue.h"
-#include "llvm/ExecutionEngine/MCJIT.h"
+#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/ExecutionEngine/MCJIT.h"
+#include "llvm/ExecutionEngine/ObjectBuffer.h"
+#include "llvm/ExecutionEngine/ObjectImage.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/MutexGuard.h"
-#include "llvm/Target/TargetData.h"
using namespace llvm;
@@ -44,18 +46,20 @@ ExecutionEngine *MCJIT::createJIT(Module *M,
// FIXME: Don't do this here.
sys::DynamicLibrary::LoadLibraryPermanently(0, NULL);
- return new MCJIT(M, TM, new MCJITMemoryManager(JMM), GVsWithCode);
+ return new MCJIT(M, TM, JMM, GVsWithCode);
}
MCJIT::MCJIT(Module *m, TargetMachine *tm, RTDyldMemoryManager *MM,
bool AllocateGVsWithCode)
: ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(MM), Dyld(MM),
- isCompiled(false), M(m), OS(Buffer) {
+ isCompiled(false), M(m) {
- setTargetData(TM->getTargetData());
+ setDataLayout(TM->getDataLayout());
}
MCJIT::~MCJIT() {
+ if (LoadedObject)
+ NotifyFreeingObject(*LoadedObject.get());
delete MemMgr;
delete TM;
}
@@ -63,7 +67,7 @@ MCJIT::~MCJIT() {
void MCJIT::emitObject(Module *m) {
/// Currently, MCJIT only supports a single module and the module passed to
/// 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
+ /// is passed as a parameter here to prepare for multiple module support in
/// the future.
assert(M == m);
@@ -78,36 +82,64 @@ void MCJIT::emitObject(Module *m) {
PassManager PM;
- PM.add(new TargetData(*TM->getTargetData()));
+ PM.add(new DataLayout(*TM->getDataLayout()));
+
+ // The RuntimeDyld will take ownership of this shortly
+ OwningPtr<ObjectBufferStream> Buffer(new ObjectBufferStream());
// Turn the machine code intermediate representation into bytes in memory
// that may be executed.
- if (TM->addPassesToEmitMC(PM, Ctx, OS, false)) {
+ if (TM->addPassesToEmitMC(PM, Ctx, Buffer->getOStream(), false)) {
report_fatal_error("Target does not support MC emission!");
}
// Initialize passes.
- // FIXME: When we support multiple modules, we'll want to move the code
- // gen and finalization out of the constructor here and do it more
- // on-demand as part of getPointerToFunction().
PM.run(*m);
- // Flush the output buffer so the SmallVector gets its data.
- OS.flush();
+ // Flush the output buffer to get the generated code into memory
+ Buffer->flush();
// Load the object into the dynamic linker.
- MemoryBuffer* MB = MemoryBuffer::getMemBuffer(StringRef(Buffer.data(),
- Buffer.size()),
- "", false);
- if (Dyld.loadObject(MB))
+ // handing off ownership of the buffer
+ LoadedObject.reset(Dyld.loadObject(Buffer.take()));
+ if (!LoadedObject)
report_fatal_error(Dyld.getErrorString());
// Resolve any relocations.
Dyld.resolveRelocations();
+ // FIXME: Make this optional, maybe even move it to a JIT event listener
+ LoadedObject->registerWithDebugger();
+
+ NotifyObjectEmitted(*LoadedObject);
+
// FIXME: Add support for per-module compilation state
isCompiled = true;
}
+// FIXME: Add a parameter to identify which object is being finalized when
+// MCJIT supports multiple modules.
+// FIXME: Provide a way to separate code emission, relocations and page
+// protection in the interface.
+void MCJIT::finalizeObject() {
+ // If the module hasn't been compiled, just do that.
+ if (!isCompiled) {
+ // If the call to Dyld.resolveRelocations() is removed from emitObject()
+ // we'll need to do that here.
+ emitObject(M);
+
+ // Set page permissions.
+ MemMgr->applyPermissions();
+
+ return;
+ }
+
+ // Resolve any relocations.
+ Dyld.resolveRelocations();
+
+ // Set page permissions.
+ MemMgr->applyPermissions();
+}
+
void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {
report_fatal_error("not yet implemented");
}
@@ -272,3 +304,33 @@ void *MCJIT::getPointerToNamedFunction(const std::string &Name,
}
return 0;
}
+
+void MCJIT::RegisterJITEventListener(JITEventListener *L) {
+ if (L == NULL)
+ return;
+ MutexGuard locked(lock);
+ EventListeners.push_back(L);
+}
+void MCJIT::UnregisterJITEventListener(JITEventListener *L) {
+ if (L == NULL)
+ return;
+ MutexGuard locked(lock);
+ SmallVector<JITEventListener*, 2>::reverse_iterator I=
+ std::find(EventListeners.rbegin(), EventListeners.rend(), L);
+ if (I != EventListeners.rend()) {
+ std::swap(*I, EventListeners.back());
+ EventListeners.pop_back();
+ }
+}
+void MCJIT::NotifyObjectEmitted(const ObjectImage& Obj) {
+ MutexGuard locked(lock);
+ for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
+ EventListeners[I]->NotifyObjectEmitted(Obj);
+ }
+}
+void MCJIT::NotifyFreeingObject(const ObjectImage& Obj) {
+ MutexGuard locked(lock);
+ for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
+ EventListeners[I]->NotifyFreeingObject(Obj);
+ }
+}
diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.h b/lib/ExecutionEngine/MCJIT/MCJIT.h
index 138a7b6..283a8e5 100644
--- a/lib/ExecutionEngine/MCJIT/MCJIT.h
+++ b/lib/ExecutionEngine/MCJIT/MCJIT.h
@@ -10,14 +10,15 @@
#ifndef LLVM_LIB_EXECUTIONENGINE_MCJIT_H
#define LLVM_LIB_EXECUTIONENGINE_MCJIT_H
-#include "llvm/PassManager.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/PassManager.h"
namespace llvm {
+class ObjectImage;
+
// FIXME: This makes all kinds of horrible assumptions for the time being,
// like only having one module, not needing to worry about multi-threading,
// blah blah. Purely in get-it-up-and-limping mode for now.
@@ -30,14 +31,12 @@ class MCJIT : public ExecutionEngine {
MCContext *Ctx;
RTDyldMemoryManager *MemMgr;
RuntimeDyld Dyld;
+ SmallVector<JITEventListener*, 2> EventListeners;
// FIXME: Add support for multiple modules
bool isCompiled;
Module *M;
-
- // FIXME: Move these to a single container which manages JITed objects
- SmallVector<char, 4096> Buffer; // Working buffer into which we JIT.
- raw_svector_ostream OS;
+ OwningPtr<ObjectImage> LoadedObject;
public:
~MCJIT();
@@ -45,6 +44,8 @@ public:
/// @name ExecutionEngine interface implementation
/// @{
+ virtual void finalizeObject();
+
virtual void *getPointerToBasicBlock(BasicBlock *BB);
virtual void *getPointerToFunction(Function *F);
@@ -71,10 +72,14 @@ public:
/// Map the address of a JIT section as returned from the memory manager
/// to the address in the target process as the running code will see it.
/// This is the address which will be used for relocation resolution.
- virtual void mapSectionAddress(void *LocalAddress, uint64_t TargetAddress) {
+ virtual void mapSectionAddress(const void *LocalAddress,
+ uint64_t TargetAddress) {
Dyld.mapSectionAddress(LocalAddress, TargetAddress);
}
+ virtual void RegisterJITEventListener(JITEventListener *L);
+ virtual void UnregisterJITEventListener(JITEventListener *L);
+
/// @}
/// @name (Private) Registration Interfaces
/// @{
@@ -98,6 +103,9 @@ protected:
/// is passed as a parameter here to prepare for multiple module support in
/// the future.
void emitObject(Module *M);
+
+ void NotifyObjectEmitted(const ObjectImage& Obj);
+ void NotifyFreeingObject(const ObjectImage& Obj);
};
} // End llvm namespace
diff --git a/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.cpp b/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.cpp
deleted file mode 100644
index 457fe5e..0000000
--- a/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-//==-- MCJITMemoryManager.cpp - Definition for the Memory Manager -*-C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MCJITMemoryManager.h"
-
-using namespace llvm;
-
-void MCJITMemoryManager::anchor() { }
diff --git a/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h b/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h
deleted file mode 100644
index 441aaeb..0000000
--- a/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h
+++ /dev/null
@@ -1,50 +0,0 @@
-//===-- MCJITMemoryManager.h - Definition for the Memory Manager ---C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIB_EXECUTIONENGINE_MCJITMEMORYMANAGER_H
-#define LLVM_LIB_EXECUTIONENGINE_MCJITMEMORYMANAGER_H
-
-#include "llvm/Module.h"
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
-#include "llvm/ExecutionEngine/RuntimeDyld.h"
-#include <assert.h>
-
-namespace llvm {
-
-// The MCJIT memory manager is a layer between the standard JITMemoryManager
-// and the RuntimeDyld interface that maps objects, by name, onto their
-// matching LLVM IR counterparts in the module(s) being compiled.
-class MCJITMemoryManager : public RTDyldMemoryManager {
- virtual void anchor();
- OwningPtr<JITMemoryManager> JMM;
-
-public:
- MCJITMemoryManager(JITMemoryManager *jmm) :
- JMM(jmm?jmm:JITMemoryManager::CreateDefaultMemManager()) {}
-
- uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID) {
- return JMM->allocateDataSection(Size, Alignment, SectionID);
- }
-
- uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID) {
- return JMM->allocateCodeSection(Size, Alignment, SectionID);
- }
-
- virtual void *getPointerToNamedFunction(const std::string &Name,
- bool AbortOnFailure = true) {
- return JMM->getPointerToNamedFunction(Name, AbortOnFailure);
- }
-
-};
-
-} // End llvm namespace
-
-#endif
diff --git a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
new file mode 100644
index 0000000..fa35acd
--- /dev/null
+++ b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
@@ -0,0 +1,226 @@
+//===- 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/DynamicLibrary.h"
+#include "llvm/Support/MathExtras.h"
+
+#ifdef __linux__
+ // These includes used by SectionMemoryManager::getPointerToNamedFunction()
+ // for Glibc trickery. See comments in this function for more information.
+ #ifdef HAVE_SYS_STAT_H
+ #include <sys/stat.h>
+ #endif
+ #include <fcntl.h>
+ #include <unistd.h>
+#endif
+
+namespace llvm {
+
+uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
+ unsigned Alignment,
+ unsigned SectionID,
+ 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) {
+ 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.
+ 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 propogation to the interface.
+ return NULL;
+ }
+
+ // 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::applyPermissions(std::string *ErrMsg)
+{
+ // FIXME: Should in-progress permissions be reverted if an error occurs?
+ error_code ec;
+
+ // Make code memory executable.
+ ec = applyMemoryGroupPermissions(CodeMem,
+ sys::Memory::MF_READ | sys::Memory::MF_EXEC);
+ if (ec) {
+ if (ErrMsg) {
+ *ErrMsg = ec.message();
+ }
+ return true;
+ }
+
+ // 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
+
+ return false;
+}
+
+error_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
+ unsigned Permissions) {
+
+ for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) {
+ error_code ec;
+ ec = sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i],
+ Permissions);
+ if (ec) {
+ return ec;
+ }
+ }
+
+ return error_code::success();
+}
+
+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());
+}
+
+static int jit_noop() {
+ return 0;
+}
+
+void *SectionMemoryManager::getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure) {
+#if defined(__linux__)
+ //===--------------------------------------------------------------------===//
+ // Function stubs that are invoked instead of certain library calls
+ //
+ // Force the following functions to be linked in to anything that uses the
+ // JIT. This is a hack designed to work around the all-too-clever Glibc
+ // strategy of making these functions work differently when inlined vs. when
+ // not inlined, and hiding their real definitions in a separate archive file
+ // that the dynamic linker can't see. For more info, search for
+ // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
+ if (Name == "stat") return (void*)(intptr_t)&stat;
+ if (Name == "fstat") return (void*)(intptr_t)&fstat;
+ if (Name == "lstat") return (void*)(intptr_t)&lstat;
+ if (Name == "stat64") return (void*)(intptr_t)&stat64;
+ if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
+ if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
+ if (Name == "atexit") return (void*)(intptr_t)&atexit;
+ if (Name == "mknod") return (void*)(intptr_t)&mknod;
+#endif // __linux__
+
+ // We should not invoke parent's ctors/dtors from generated main()!
+ // On Mingw and Cygwin, the symbol __main is resolved to
+ // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
+ // (and register wrong callee's dtors with atexit(3)).
+ // We expect ExecutionEngine::runStaticConstructorsDestructors()
+ // is called before ExecutionEngine::runFunctionAsMain() is called.
+ if (Name == "__main") return (void*)(intptr_t)&jit_noop;
+
+ const char *NameStr = Name.c_str();
+ void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
+ if (Ptr) return Ptr;
+
+ // If it wasn't found and if it starts with an underscore ('_') character,
+ // try again without the underscore.
+ if (NameStr[0] == '_') {
+ Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
+ if (Ptr) return Ptr;
+ }
+
+ if (AbortOnFailure)
+ report_fatal_error("Program used external function '" + Name +
+ "' which could not be resolved!");
+ return 0;
+}
+
+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
+