For PR540:
authorReid Spencer <rspencer@reidspencer.com>
Tue, 12 Jul 2005 15:51:55 +0000 (15:51 +0000)
committerReid Spencer <rspencer@reidspencer.com>
Tue, 12 Jul 2005 15:51:55 +0000 (15:51 +0000)
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

autoconf/configure.ac
configure
include/llvm/ExecutionEngine/ExecutionEngine.h
include/llvm/Support/MutexGuard.h
include/llvm/Support/ThreadSupport-NoSupport.h [deleted file]
include/llvm/Support/ThreadSupport-PThreads.h [deleted file]
include/llvm/Support/ThreadSupport.h.in [deleted file]
lib/ExecutionEngine/ExecutionEngine.cpp
lib/ExecutionEngine/JIT/JIT.cpp
lib/ExecutionEngine/JIT/JIT.h
lib/ExecutionEngine/JIT/JITEmitter.cpp

index 1c3bc1372ce9a031734f6435d9e3950dd5ad412b..f20c567f03b7fa390baa04b3b999def64c575fa9 100644 (file)
@@ -606,12 +606,10 @@ dnl===
 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
index b785a780e1aa521e78b8479795eb458a0b398c63..90fda9a9435327b9c1a2181799d1a05978ec1fae 100755 (executable)
--- a/configure
+++ b/configure
@@ -30489,15 +30489,12 @@ _ACEOF
 
           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 @@ do
   "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;}
index 13bc9ccc139f13a0a0e41936586fa4fbf15987b5..301b6d6eeb849b3e8b9ba64c8af097af5b86fb62 100644 (file)
@@ -19,6 +19,7 @@
 #include <map>
 #include <cassert>
 #include <string>
+#include "llvm/Support/MutexGuard.h"
 
 namespace llvm {
 
@@ -33,10 +34,9 @@ class TargetData;
 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 @@ class ExecutionEngine {
   /// 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 @@ protected:
   }
 
 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 @@ public:
 
 
   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 @@ public:
   /// 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 @@ public:
   /// 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
index bed1a9cec7a9d463ec704c03d32176e68be22ab2..24bbbe1bb312ec4acd3960da276ad626f3677a96 100644 (file)
@@ -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 (file)
index 058f82b..0000000
+++ /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 (file)
index 84c6fac..0000000
+++ /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 (file)
index bed1a9c..0000000
+++ /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
index f72ddcbba6ec76de6ef147b6de58b8f771181c47..36f7d2fdfc4e078f170d04d3eb29031a78fbdc3c 100644 (file)
@@ -50,16 +50,18 @@ ExecutionEngine::~ExecutionEngine() {
 /// 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 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) {
   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
index cf4e14481b8c7b8f68efacb72e195a50dc559db1..d97f1970d51010e601803674c0d5511d0c5b5f3f 100644 (file)
 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 @@ GenericValue JIT::runFunction(Function *F,
 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 @@ void JIT::runJITOnFunction(Function *F) {
 /// 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 @@ void *JIT::getPointerToFunction(Function *F) {
 /// 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 @@ void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
     // 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;
index 3c14cf71db56ea79935232d42391fd6104d0cb98..4cce144712fc1642109ec41e9a0e4578b9b837b0 100644 (file)
@@ -27,18 +27,35 @@ class TargetMachine;
 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();
index 301f5e77eec4c34cc61aa6f828cd329c7299e474..47adee00192eab0333eccfafb1407808af5c4d86 100644 (file)
@@ -120,6 +120,28 @@ void JITMemoryManager::endFunctionBody(unsigned char *FunctionEnd) {
 // 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 @@ namespace {
     /// 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 @@ namespace {
     /// 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 @@ static JITResolver &getJITResolver(MachineCodeEmitter *MCE = 0) {
 /// 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 @@ void *JITResolver::getFunctionStub(Function *F) {
 
   // 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::getExternalFunctionStub(void *FnAddr) {
 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 *JITResolver::JITCompilerFn(void *Stub) {
   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;