For PR540:
This patch completes the changes for making lli thread-safe. Here's the list
of changes:
* The Support/ThreadSupport* files were removed and replaced with the
MutexGuard.h file since all ThreadSupport* declared was a Mutex Guard.
The implementation of MutexGuard.h is now based on sys::Mutex which hides
its implementation and makes it unnecessary to have the -NoSupport.h and
-PThreads.h versions of ThreadSupport.
* All places in ExecutionEngine that previously referred to "Mutex" now
refer to sys::Mutex
* All places in ExecutionEngine that previously referred to "MutexLocker"
now refer to MutexGuard (this is frivolous but I believe the technically
correct name for such a class is "Guard" not a "Locker").
These changes passed all of llvm-test. All we need now are some test cases
that actually use multiple threads.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22404 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/autoconf/configure.ac b/autoconf/configure.ac
index 1c3bc13..f20c567 100644
--- a/autoconf/configure.ac
+++ b/autoconf/configure.ac
@@ -606,12 +606,10 @@
dnl===-----------------------------------------------------------------------===
dnl Configure header files
-AC_CONFIG_HEADERS(include/llvm/Config/config.h)
-
+AC_CONFIG_HEADERS([include/llvm/Config/config.h])
AC_CONFIG_HEADERS([include/llvm/Support/DataTypes.h])
AC_CONFIG_HEADERS([include/llvm/ADT/hash_map])
AC_CONFIG_HEADERS([include/llvm/ADT/hash_set])
-AC_CONFIG_HEADERS([include/llvm/Support/ThreadSupport.h])
AC_CONFIG_HEADERS([include/llvm/ADT/iterator])
dnl Configure the makefile's configuration data
diff --git a/configure b/configure
index b785a78..90fda9a 100755
--- a/configure
+++ b/configure
@@ -30489,15 +30489,12 @@
ac_config_headers="$ac_config_headers include/llvm/Config/config.h"
-
ac_config_headers="$ac_config_headers include/llvm/Support/DataTypes.h"
ac_config_headers="$ac_config_headers include/llvm/ADT/hash_map"
ac_config_headers="$ac_config_headers include/llvm/ADT/hash_set"
- ac_config_headers="$ac_config_headers include/llvm/Support/ThreadSupport.h"
-
ac_config_headers="$ac_config_headers include/llvm/ADT/iterator"
@@ -31106,7 +31103,6 @@
"include/llvm/Support/DataTypes.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/Support/DataTypes.h" ;;
"include/llvm/ADT/hash_map" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/ADT/hash_map" ;;
"include/llvm/ADT/hash_set" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/ADT/hash_set" ;;
- "include/llvm/Support/ThreadSupport.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/Support/ThreadSupport.h" ;;
"include/llvm/ADT/iterator" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/ADT/iterator" ;;
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h
index 13bc9cc..301b6d6 100644
--- a/include/llvm/ExecutionEngine/ExecutionEngine.h
+++ b/include/llvm/ExecutionEngine/ExecutionEngine.h
@@ -19,6 +19,7 @@
#include <map>
#include <cassert>
#include <string>
+#include "llvm/Support/MutexGuard.h"
namespace llvm {
@@ -33,10 +34,9 @@
class Type;
class IntrinsicLowering;
-class ExecutionEngine {
- Module &CurMod;
- const TargetData *TD;
+class ExecutionEngineState {
+private:
/// GlobalAddressMap - A mapping between LLVM global values and their
/// actualized version...
std::map<const GlobalValue*, void *> GlobalAddressMap;
@@ -46,6 +46,24 @@
/// at the address. This map is not computed unless getGlobalValueAtAddress
/// is called at some point.
std::map<void *, const GlobalValue*> GlobalAddressReverseMap;
+
+public:
+ std::map<const GlobalValue*, void *>& getGlobalAddressMap(const MutexGuard& locked) {
+ return GlobalAddressMap;
+ }
+
+ std::map<void *, const GlobalValue*>& getGlobalAddressReverseMap(const MutexGuard& locked) {
+ return GlobalAddressReverseMap;
+ }
+};
+
+
+class ExecutionEngine {
+ Module &CurMod;
+ const TargetData *TD;
+
+ ExecutionEngineState state;
+
protected:
ModuleProvider *MP;
@@ -54,6 +72,10 @@
}
public:
+ /// lock - This lock is protects the ExecutionEngine, JIT, JITResolver and JITEmitter classes.
+ /// It must be held while changing the internal state of any of those classes.
+ sys::Mutex lock; // Used to make this class and subclasses thread-safe
+
ExecutionEngine(ModuleProvider *P);
ExecutionEngine(Module *M);
virtual ~ExecutionEngine();
@@ -81,13 +103,15 @@
void addGlobalMapping(const GlobalValue *GV, void *Addr) {
- void *&CurVal = GlobalAddressMap[GV];
+ MutexGuard locked(lock);
+
+ void *&CurVal = state.getGlobalAddressMap(locked)[GV];
assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!");
CurVal = Addr;
// If we are using the reverse mapping, add it too
- if (!GlobalAddressReverseMap.empty()) {
- const GlobalValue *&V = GlobalAddressReverseMap[Addr];
+ if (!state.getGlobalAddressReverseMap(locked).empty()) {
+ const GlobalValue *&V = state.getGlobalAddressReverseMap(locked)[Addr];
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
V = GV;
}
@@ -96,21 +120,25 @@
/// clearAllGlobalMappings - Clear all global mappings and start over again
/// use in dynamic compilation scenarios when you want to move globals
void clearAllGlobalMappings() {
- GlobalAddressMap.clear();
- GlobalAddressReverseMap.clear();
+ MutexGuard locked(lock);
+
+ state.getGlobalAddressMap(locked).clear();
+ state.getGlobalAddressReverseMap(locked).clear();
}
/// updateGlobalMapping - Replace an existing mapping for GV with a new
/// address. This updates both maps as required.
void updateGlobalMapping(const GlobalValue *GV, void *Addr) {
- void *&CurVal = GlobalAddressMap[GV];
- if (CurVal && !GlobalAddressReverseMap.empty())
- GlobalAddressReverseMap.erase(CurVal);
+ MutexGuard locked(lock);
+
+ void *&CurVal = state.getGlobalAddressMap(locked)[GV];
+ if (CurVal && !state.getGlobalAddressReverseMap(locked).empty())
+ state.getGlobalAddressReverseMap(locked).erase(CurVal);
CurVal = Addr;
// If we are using the reverse mapping, add it too
- if (!GlobalAddressReverseMap.empty()) {
- const GlobalValue *&V = GlobalAddressReverseMap[Addr];
+ if (!state.getGlobalAddressReverseMap(locked).empty()) {
+ const GlobalValue *&V = state.getGlobalAddressReverseMap(locked)[Addr];
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
V = GV;
}
@@ -120,8 +148,10 @@
/// global value if it is available, otherwise it returns null.
///
void *getPointerToGlobalIfAvailable(const GlobalValue *GV) {
- std::map<const GlobalValue*, void*>::iterator I = GlobalAddressMap.find(GV);
- return I != GlobalAddressMap.end() ? I->second : 0;
+ MutexGuard locked(lock);
+
+ std::map<const GlobalValue*, void*>::iterator I = state.getGlobalAddressMap(locked).find(GV);
+ return I != state.getGlobalAddressMap(locked).end() ? I->second : 0;
}
/// getPointerToGlobal - This returns the address of the specified global
diff --git a/include/llvm/Support/MutexGuard.h b/include/llvm/Support/MutexGuard.h
index bed1a9c..24bbbe1 100644
--- a/include/llvm/Support/MutexGuard.h
+++ b/include/llvm/Support/MutexGuard.h
@@ -1,4 +1,4 @@
-//===-- Support/ThreadSupport.h - Generic threading support -----*- C++ -*-===//
+//===-- Support/MutexGuard.h - Acquire/Release Mutex In Scope ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,36 +7,35 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines platform-agnostic interfaces that can be used to write
-// multi-threaded programs. Autoconf is used to chose the correct
-// implementation of these interfaces, or default to a non-thread-capable system
-// if no matching system support is available.
+// This file defines a guard for a block of code that ensures a Mutex is locked
+// upon construction and released upon destruction.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_SUPPORT_THREADSUPPORT_H
-#define LLVM_SUPPORT_THREADSUPPORT_H
+#ifndef LLVM_SUPPORT_MUTEXGUARD_H
+#define LLVM_SUPPORT_MUTEXGUARD_H
-#undef HAVE_PTHREAD_MUTEX_LOCK
-
-#ifdef HAVE_PTHREAD_MUTEX_LOCK
-#include "llvm/Support/ThreadSupport-PThreads.h"
-#else
-#include "llvm/Support/ThreadSupport-NoSupport.h"
-#endif // If no system support is available
+#include <llvm/System/Mutex.h>
namespace llvm {
- /// MutexLocker - Instances of this class acquire a given Lock when
- /// constructed and hold that lock until destruction.
- ///
- class MutexLocker {
- Mutex &M;
- MutexLocker(const MutexLocker &); // DO NOT IMPLEMENT
- void operator=(const MutexLocker &); // DO NOT IMPLEMENT
+ /// Instances of this class acquire a given Mutex Lock when constructed and
+ /// hold that lock until destruction. The intention is to instantiate one of
+ /// these on the stack at the top of some scope to be assured that C++
+ /// destruction of the object will always release the Mutex and thus avoid
+ /// a host of nasty multi-threading problems in the face of exceptions, etc.
+ /// @brief Guard a section of code with a Mutex.
+ class MutexGuard {
+ sys::Mutex &M;
+ MutexGuard(const MutexGuard &); // DO NOT IMPLEMENT
+ void operator=(const MutexGuard &); // DO NOT IMPLEMENT
public:
- MutexLocker(Mutex &m) : M(m) { M.acquire(); }
- ~MutexLocker() { M.release(); }
+ MutexGuard(sys::Mutex &m) : M(m) { M.acquire(); }
+ ~MutexGuard() { M.release(); }
+ /// holds - Returns true if this locker instance holds the specified lock.
+ /// This is mostly used in assertions to validate that the correct mutex
+ /// is held.
+ bool holds(const sys::Mutex& lock) const { return &M == &lock; }
};
}
-#endif // SUPPORT_THREADSUPPORT_H
+#endif // LLVM_SUPPORT_MUTEXGUARD_H
diff --git a/include/llvm/Support/ThreadSupport-NoSupport.h b/include/llvm/Support/ThreadSupport-NoSupport.h
deleted file mode 100644
index 058f82b..0000000
--- a/include/llvm/Support/ThreadSupport-NoSupport.h
+++ /dev/null
@@ -1,34 +0,0 @@
-//===-- llvm/Support/ThreadSupport-NoSupport.h - Generic Impl ---*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a generic ThreadSupport implementation used when there is
-// no supported threading mechanism on the current system. Users should never
-// #include this file directly!
-//
-//===----------------------------------------------------------------------===//
-
-// Users should never #include this file directly! As such, no include guards
-// are needed.
-
-#ifndef LLVM_SUPPORT_THREADSUPPORT_H
-#error "Code should not #include Support/ThreadSupport-NoSupport.h directly!"
-#endif
-
-namespace llvm {
- /// Mutex - This class allows user code to protect variables shared between
- /// threads. It implements a "recursive" mutex, to simplify user code.
- ///
- /// Since there is no platform support for _creating threads_, the non-thread
- /// implementation of this class is a noop.
- ///
- struct Mutex {
- void acquire () {}
- void release () {}
- };
-}
diff --git a/include/llvm/Support/ThreadSupport-PThreads.h b/include/llvm/Support/ThreadSupport-PThreads.h
deleted file mode 100644
index 84c6fac..0000000
--- a/include/llvm/Support/ThreadSupport-PThreads.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//===-- llvm/Support/ThreadSupport-PThreads.h - PThreads support *- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines pthreads implementations of the generic threading
-// mechanisms. Users should never #include this file directly!
-//
-//===----------------------------------------------------------------------===//
-
-// Users should never #include this file directly! As such, no include guards
-// are needed.
-
-#ifndef LLVM_SUPPORT_THREADSUPPORT_H
-#error "Code should not #include Support/ThreadSupport/PThreads.h directly!"
-#endif
-
-#include <pthread.h>
-
-namespace llvm {
-
- /// Mutex - This class allows user code to protect variables shared between
- /// threads. It implements a "recursive" mutex, to simplify user code.
- ///
- class Mutex {
- pthread_mutex_t mutex;
- Mutex(const Mutex &); // DO NOT IMPLEMENT
- void operator=(const Mutex &); // DO NOT IMPLEMENT
- public:
- Mutex() {
- // Initialize the mutex as a recursive mutex
- pthread_mutexattr_t Attr;
- int errorcode = pthread_mutexattr_init(&Attr);
- assert(errorcode == 0);
-
- errorcode = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
- assert(errorcode == 0);
-
- errorcode = pthread_mutex_init(&mutex, &Attr);
- assert(errorcode == 0);
-
- errorcode = pthread_mutexattr_destroy(&Attr);
- assert(errorcode == 0);
- }
-
- ~Mutex() {
- int errorcode = pthread_mutex_destroy(&mutex);
- assert(errorcode == 0);
- }
-
- void acquire () {
- int errorcode = pthread_mutex_lock(&mutex);
- assert(errorcode == 0);
- }
-
- void release () {
- int errorcode = pthread_mutex_unlock(&mutex);
- assert(errorcode == 0);
- }
- };
-} // end namespace llvm
diff --git a/include/llvm/Support/ThreadSupport.h.in b/include/llvm/Support/ThreadSupport.h.in
deleted file mode 100644
index bed1a9c..0000000
--- a/include/llvm/Support/ThreadSupport.h.in
+++ /dev/null
@@ -1,42 +0,0 @@
-//===-- Support/ThreadSupport.h - Generic threading support -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines platform-agnostic interfaces that can be used to write
-// multi-threaded programs. Autoconf is used to chose the correct
-// implementation of these interfaces, or default to a non-thread-capable system
-// if no matching system support is available.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_SUPPORT_THREADSUPPORT_H
-#define LLVM_SUPPORT_THREADSUPPORT_H
-
-#undef HAVE_PTHREAD_MUTEX_LOCK
-
-#ifdef HAVE_PTHREAD_MUTEX_LOCK
-#include "llvm/Support/ThreadSupport-PThreads.h"
-#else
-#include "llvm/Support/ThreadSupport-NoSupport.h"
-#endif // If no system support is available
-
-namespace llvm {
- /// MutexLocker - Instances of this class acquire a given Lock when
- /// constructed and hold that lock until destruction.
- ///
- class MutexLocker {
- Mutex &M;
- MutexLocker(const MutexLocker &); // DO NOT IMPLEMENT
- void operator=(const MutexLocker &); // DO NOT IMPLEMENT
- public:
- MutexLocker(Mutex &m) : M(m) { M.acquire(); }
- ~MutexLocker() { M.release(); }
- };
-}
-
-#endif // SUPPORT_THREADSUPPORT_H
diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp
index f72ddcb..36f7d2f 100644
--- a/lib/ExecutionEngine/ExecutionEngine.cpp
+++ b/lib/ExecutionEngine/ExecutionEngine.cpp
@@ -50,16 +50,18 @@
/// at the specified address.
///
const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) {
+ MutexGuard locked(lock);
+
// If we haven't computed the reverse mapping yet, do so first.
- if (GlobalAddressReverseMap.empty()) {
+ if (state.getGlobalAddressReverseMap(locked).empty()) {
for (std::map<const GlobalValue*, void *>::iterator I =
- GlobalAddressMap.begin(), E = GlobalAddressMap.end(); I != E; ++I)
- GlobalAddressReverseMap.insert(std::make_pair(I->second, I->first));
+ state.getGlobalAddressMap(locked).begin(), E = state.getGlobalAddressMap(locked).end(); I != E; ++I)
+ state.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second, I->first));
}
std::map<void *, const GlobalValue*>::iterator I =
- GlobalAddressReverseMap.find(Addr);
- return I != GlobalAddressReverseMap.end() ? I->second : 0;
+ state.getGlobalAddressReverseMap(locked).find(Addr);
+ return I != state.getGlobalAddressReverseMap(locked).end() ? I->second : 0;
}
// CreateArgv - Turn a vector of strings into a nice argv style array of
@@ -168,8 +170,9 @@
if (Function *F = const_cast<Function*>(dyn_cast<Function>(GV)))
return getPointerToFunction(F);
- assert(GlobalAddressMap[GV] && "Global hasn't had an address allocated yet?");
- return GlobalAddressMap[GV];
+ MutexGuard locked(lock);
+ assert(state.getGlobalAddressMap(locked)[GV] && "Global hasn't had an address allocated yet?");
+ return state.getGlobalAddressMap(locked)[GV];
}
/// FIXME: document
diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp
index cf4e144..d97f197 100644
--- a/lib/ExecutionEngine/JIT/JIT.cpp
+++ b/lib/ExecutionEngine/JIT/JIT.cpp
@@ -30,13 +30,15 @@
using namespace llvm;
JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
- : ExecutionEngine(MP), TM(tm), TJI(tji), PM(MP) {
+ : ExecutionEngine(MP), TM(tm), TJI(tji), state(MP) {
setTargetData(TM.getTargetData());
// Initialize MCE
MCE = createEmitter(*this);
// Add target data
+ MutexGuard locked(lock);
+ FunctionPassManager& PM = state.getPM(locked);
PM.add(new TargetData(TM.getTargetData()));
// Compile LLVM Code down to machine code in the intermediate representation
@@ -216,18 +218,20 @@
void JIT::runJITOnFunction(Function *F) {
static bool isAlreadyCodeGenerating = false;
assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
+
+ MutexGuard locked(lock);
// JIT the function
isAlreadyCodeGenerating = true;
- PM.run(*F);
+ state.getPM(locked).run(*F);
isAlreadyCodeGenerating = false;
// If the function referred to a global variable that had not yet been
// emitted, it allocates memory for the global, but doesn't emit it yet. Emit
// all of these globals now.
- while (!PendingGlobals.empty()) {
- const GlobalVariable *GV = PendingGlobals.back();
- PendingGlobals.pop_back();
+ while (!state.getPendingGlobals(locked).empty()) {
+ const GlobalVariable *GV = state.getPendingGlobals(locked).back();
+ state.getPendingGlobals(locked).pop_back();
EmitGlobalVariable(GV);
}
}
@@ -236,6 +240,8 @@
/// specified function, compiling it if neccesary.
///
void *JIT::getPointerToFunction(Function *F) {
+ MutexGuard locked(lock);
+
if (void *Addr = getPointerToGlobalIfAvailable(F))
return Addr; // Check if function already code gen'd
@@ -270,6 +276,8 @@
/// variable, possibly emitting it to memory if needed. This is used by the
/// Emitter.
void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
+ MutexGuard locked(lock);
+
void *Ptr = getPointerToGlobalIfAvailable(GV);
if (Ptr) return Ptr;
@@ -287,7 +295,7 @@
// compilation.
uint64_t S = getTargetData().getTypeSize(GV->getType()->getElementType());
Ptr = new char[(size_t)S];
- PendingGlobals.push_back(GV);
+ state.getPendingGlobals(locked).push_back(GV);
}
addGlobalMapping(GV, Ptr);
return Ptr;
diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h
index 3c14cf7..4cce144 100644
--- a/lib/ExecutionEngine/JIT/JIT.h
+++ b/lib/ExecutionEngine/JIT/JIT.h
@@ -27,18 +27,35 @@
class TargetJITInfo;
class MachineCodeEmitter;
-class JIT : public ExecutionEngine {
- TargetMachine &TM; // The current target we are compiling to
- TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
-
+class JITState {
+private:
FunctionPassManager PM; // Passes to compile a function
- MachineCodeEmitter *MCE; // MCE object
/// PendingGlobals - Global variables which have had memory allocated for them
/// while a function was code generated, but which have not been initialized
/// yet.
std::vector<const GlobalVariable*> PendingGlobals;
+public:
+ JITState(ModuleProvider *MP) : PM(MP) {}
+
+ FunctionPassManager& getPM(const MutexGuard& locked) {
+ return PM;
+ }
+
+ std::vector<const GlobalVariable*>& getPendingGlobals(const MutexGuard& locked) {
+ return PendingGlobals;
+ }
+};
+
+
+class JIT : public ExecutionEngine {
+ TargetMachine &TM; // The current target we are compiling to
+ TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
+ MachineCodeEmitter *MCE; // MCE object
+
+ JITState state;
+
JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
public:
~JIT();
diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp
index 301f5e7..47adee0 100644
--- a/lib/ExecutionEngine/JIT/JITEmitter.cpp
+++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp
@@ -120,6 +120,28 @@
// JIT lazy compilation code.
//
namespace {
+ class JITResolverState {
+ private:
+ /// FunctionToStubMap - Keep track of the stub created for a particular
+ /// function so that we can reuse them if necessary.
+ std::map<Function*, void*> FunctionToStubMap;
+
+ /// StubToFunctionMap - Keep track of the function that each stub
+ /// corresponds to.
+ std::map<void*, Function*> StubToFunctionMap;
+
+ public:
+ std::map<Function*, void*>& getFunctionToStubMap(const MutexGuard& locked) {
+ assert(locked.holds(TheJIT->lock));
+ return FunctionToStubMap;
+ }
+
+ std::map<void*, Function*>& getStubToFunctionMap(const MutexGuard& locked) {
+ assert(locked.holds(TheJIT->lock));
+ return StubToFunctionMap;
+ }
+ };
+
/// JITResolver - Keep track of, and resolve, call sites for functions that
/// have not yet been compiled.
class JITResolver {
@@ -130,13 +152,7 @@
/// rewrite instructions to use.
TargetJITInfo::LazyResolverFn LazyResolverFn;
- // FunctionToStubMap - Keep track of the stub created for a particular
- // function so that we can reuse them if necessary.
- std::map<Function*, void*> FunctionToStubMap;
-
- // StubToFunctionMap - Keep track of the function that each stub corresponds
- // to.
- std::map<void*, Function*> StubToFunctionMap;
+ JITResolverState state;
/// ExternalFnToStubMap - This is the equivalent of FunctionToStubMap for
/// external functions.
@@ -159,8 +175,9 @@
/// instruction without the use of a stub, record the location of the use so
/// we know which function is being used at the location.
void *AddCallbackAtLocation(Function *F, void *Location) {
+ MutexGuard locked(TheJIT->lock);
/// Get the target-specific JIT resolver function.
- StubToFunctionMap[Location] = F;
+ state.getStubToFunctionMap(locked)[Location] = F;
return (void*)LazyResolverFn;
}
@@ -181,8 +198,10 @@
/// getFunctionStub - This returns a pointer to a function stub, creating
/// one on demand as needed.
void *JITResolver::getFunctionStub(Function *F) {
+ MutexGuard locked(TheJIT->lock);
+
// If we already have a stub for this function, recycle it.
- void *&Stub = FunctionToStubMap[F];
+ void *&Stub = state.getFunctionToStubMap(locked)[F];
if (Stub) return Stub;
// Call the lazy resolver function unless we already KNOW it is an external
@@ -207,7 +226,7 @@
// Finally, keep track of the stub-to-Function mapping so that the
// JITCompilerFn knows which function to compile!
- StubToFunctionMap[Stub] = F;
+ state.getStubToFunctionMap(locked)[Stub] = F;
return Stub;
}
@@ -231,16 +250,21 @@
void *JITResolver::JITCompilerFn(void *Stub) {
JITResolver &JR = getJITResolver();
+ MutexGuard locked(TheJIT->lock);
+
// The address given to us for the stub may not be exactly right, it might be
// a little bit after the stub. As such, use upper_bound to find it.
std::map<void*, Function*>::iterator I =
- JR.StubToFunctionMap.upper_bound(Stub);
- assert(I != JR.StubToFunctionMap.begin() && "This is not a known stub!");
+ JR.state.getStubToFunctionMap(locked).upper_bound(Stub);
+ assert(I != JR.state.getStubToFunctionMap(locked).begin() && "This is not a known stub!");
Function *F = (--I)->second;
- // The target function will rewrite the stub so that the compilation callback
- // function is no longer called from this stub.
- JR.StubToFunctionMap.erase(I);
+ // We might like to remove the stub from the StubToFunction map.
+ // We can't do that! Multiple threads could be stuck, waiting to acquire the
+ // lock above. As soon as the 1st function finishes compiling the function,
+ // the next one will be released, and needs to be able to find the function it needs
+ // to call.
+ //JR.state.getStubToFunctionMap(locked).erase(I);
DEBUG(std::cerr << "JIT: Lazily resolving function '" << F->getName()
<< "' In stub ptr = " << Stub << " actual ptr = "
@@ -249,7 +273,7 @@
void *Result = TheJIT->getPointerToFunction(F);
// We don't need to reuse this stub in the future, as F is now compiled.
- JR.FunctionToStubMap.erase(F);
+ JR.state.getFunctionToStubMap(locked).erase(F);
// FIXME: We could rewrite all references to this stub if we knew them.
return Result;