[llvm] r193291 - Optimizing MCJIT module state tracking

Andrew Kaylor andrew.kaylor at intel.com
Wed Oct 23 17:19:14 PDT 2013


Author: akaylor
Date: Wed Oct 23 19:19:14 2013
New Revision: 193291

URL: http://llvm.org/viewvc/llvm-project?rev=193291&view=rev
Log:
Optimizing MCJIT module state tracking

Patch co-developed with Yaron Keren.



Modified:
    llvm/trunk/include/llvm/ExecutionEngine/ExecutionEngine.h
    llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp
    llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h

Modified: llvm/trunk/include/llvm/ExecutionEngine/ExecutionEngine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/ExecutionEngine.h?rev=193291&r1=193290&r2=193291&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/ExecutionEngine.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/ExecutionEngine.h Wed Oct 23 19:19:14 2013
@@ -215,7 +215,7 @@ public:
   /// FindFunctionNamed - Search all of the active modules to find the one that
   /// defines FnName.  This is very slow operation and shouldn't be used for
   /// general code.
-  Function *FindFunctionNamed(const char *FnName);
+  virtual Function *FindFunctionNamed(const char *FnName);
 
   /// runFunction - Execute the specified function with the specified arguments,
   /// and return the result.
@@ -232,6 +232,9 @@ public:
   ///
   /// This function is deprecated for the MCJIT execution engine.
   ///
+  /// FIXME: the JIT and MCJIT interfaces should be disentangled or united 
+  /// again, if possible.
+  ///
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true) = 0;
 
@@ -275,7 +278,7 @@ public:
   /// the static constructors or destructors for a program.
   ///
   /// \param isDtors - Run the destructors instead of constructors.
-  void runStaticConstructorsDestructors(bool isDtors);
+  virtual void runStaticConstructorsDestructors(bool isDtors);
 
   /// runStaticConstructorsDestructors - This method is used to execute all of
   /// the static constructors or destructors for a particular module.

Modified: llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp?rev=193291&r1=193290&r2=193291&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp Wed Oct 23 19:19:14 2013
@@ -14,6 +14,7 @@
 #include "llvm/ExecutionEngine/MCJIT.h"
 #include "llvm/ExecutionEngine/ObjectBuffer.h"
 #include "llvm/ExecutionEngine/ObjectImage.h"
+#include "llvm/PassManager.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
@@ -57,32 +58,40 @@ MCJIT::MCJIT(Module *m, TargetMachine *t
   : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(this, MM), Dyld(&MemMgr),
     ObjCache(0) {
 
-  ModuleStates[m] = ModuleAdded;
+  OwnedModules.addModule(m);
   setDataLayout(TM->getDataLayout());
 }
 
 MCJIT::~MCJIT() {
   MutexGuard locked(lock);
+  // 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
+  // we remove it from EE and will destruct it ourselves.
+  //
+  // It may make sense to move our module manager (based on SmallStPtr) back
+  // into EE if the JIT and Interpreter can live with it.
+  // If so, additional functions: addModule, removeModule, FindFunctionNamed,
+  // runStaticConstructorsDestructors could be moved back to EE as well.
+  //
+  Modules.clear();
   Dyld.deregisterEHFrames();
-
-  LoadedObjectMap::iterator it, end = LoadedObjects.end();
-  for (it = LoadedObjects.begin(); it != end; ++it) {
-    ObjectImage *Obj = it->second;
-    if (Obj) {
-      NotifyFreeingObject(*Obj);
-      delete Obj;
-    }
-  }
   LoadedObjects.clear();
   delete TM;
 }
 
 void MCJIT::addModule(Module *M) {
   MutexGuard locked(lock);
-  Modules.push_back(M);
-  ModuleStates[M] = MCJITModuleState();
+  OwnedModules.addModule(M);
+}
+
+bool MCJIT::removeModule(Module *M) {
+  MutexGuard locked(lock);
+  return OwnedModules.removeModule(M);
 }
 
+
+
 void MCJIT::setObjectCache(ObjectCache* NewCache) {
   MutexGuard locked(lock);
   ObjCache = NewCache;
@@ -91,12 +100,9 @@ void MCJIT::setObjectCache(ObjectCache*
 ObjectBufferStream* MCJIT::emitObject(Module *M) {
   MutexGuard locked(lock);
 
-  // This must be a module which has already been added to this MCJIT instance.
-  assert(std::find(Modules.begin(), Modules.end(), M) != Modules.end());
-  assert(ModuleStates.find(M) != ModuleStates.end());
-
-  // Re-compilation is not supported
-  assert(!ModuleStates[M].hasBeenEmitted());
+  // 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;
 
@@ -133,11 +139,11 @@ void MCJIT::generateCodeForModule(Module
   MutexGuard locked(lock);
 
   // This must be a module which has already been added to this MCJIT instance.
-  assert(std::find(Modules.begin(), Modules.end(), M) != Modules.end());
-  assert(ModuleStates.find(M) != ModuleStates.end());
+  assert(OwnedModules.ownsModule(M) &&
+         "MCJIT::generateCodeForModule: Unknown module.");
 
   // Re-compilation is not supported
-  if (ModuleStates[M].hasBeenLoaded())
+  if (OwnedModules.hasModuleBeenLoaded(M))
     return;
 
   OwningPtr<ObjectBuffer> ObjectToLoad;
@@ -166,7 +172,7 @@ void MCJIT::generateCodeForModule(Module
 
   NotifyObjectEmitted(*LoadedObject);
 
-  ModuleStates[M] = ModuleLoaded;
+  OwnedModules.markModuleAsLoaded(M);
 }
 
 void MCJIT::finalizeLoadedModules() {
@@ -175,19 +181,9 @@ void MCJIT::finalizeLoadedModules() {
   // Resolve any outstanding relocations.
   Dyld.resolveRelocations();
 
-  // Register EH frame data for any module we own which has been loaded
-  SmallVector<Module *, 1>::iterator end = Modules.end();
-  SmallVector<Module *, 1>::iterator it;
-  for (it = Modules.begin(); it != end; ++it) {
-    Module *M = *it;
-    assert(ModuleStates.find(M) != ModuleStates.end());
-
-    if (ModuleStates[M].hasBeenLoaded() &&
-        !ModuleStates[M].hasBeenFinalized()) {
-      ModuleStates[M] = ModuleFinalized;
-    }
-  }
+  OwnedModules.markAllLoadedModulesAsFinalized();
 
+  // Register EH frame data for any module we own which has been loaded
   Dyld.registerEHFrames();
 
   // Set page permissions.
@@ -198,68 +194,27 @@ void MCJIT::finalizeLoadedModules() {
 void MCJIT::finalizeObject() {
   MutexGuard locked(lock);
 
-  // FIXME: This is a temporary hack to get around problems with calling
-  // finalize multiple times.
-  bool finalizeNeeded = false;
-  SmallVector<Module *, 1>::iterator end = Modules.end();
-  SmallVector<Module *, 1>::iterator it;
-  for (it = Modules.begin(); it != end; ++it) {
-    Module *M = *it;
-    assert(ModuleStates.find(M) != ModuleStates.end());
-    if (!ModuleStates[M].hasBeenFinalized())
-      finalizeNeeded = true;
-
-    // I don't really like this, but the C API depends on this behavior.
-    // I suppose it's OK for a deprecated function.
-    if (!ModuleStates[M].hasBeenLoaded())
-      generateCodeForModule(M);
-  }
-  if (!finalizeNeeded)
-    return;
-
-  // Resolve any outstanding relocations.
-  Dyld.resolveRelocations();
-
-  // Register EH frame data for any module we own which has been loaded
-  for (it = Modules.begin(); it != end; ++it) {
-    Module *M = *it;
-    assert(ModuleStates.find(M) != ModuleStates.end());
-
-    if (ModuleStates[M].hasBeenLoaded() &&
-        !ModuleStates[M].hasBeenFinalized()) {
-      ModuleStates[M] = ModuleFinalized;
-    }
+  for (ModulePtrSet::iterator I = OwnedModules.begin_added(),
+                              E = OwnedModules.end_added();
+       I != E; ++I) {
+    Module *M = *I;
+    generateCodeForModule(M);
   }
 
-  Dyld.registerEHFrames();
-
-  // Set page permissions.
-  MemMgr.finalizeMemory();
+  finalizeLoadedModules();
 }
 
 void MCJIT::finalizeModule(Module *M) {
   MutexGuard locked(lock);
 
   // This must be a module which has already been added to this MCJIT instance.
-  assert(std::find(Modules.begin(), Modules.end(), M) != Modules.end());
-  assert(ModuleStates.find(M) != ModuleStates.end());
-
-  if (ModuleStates[M].hasBeenFinalized())
-    return;
+  assert(OwnedModules.ownsModule(M) && "MCJIT::finalizeModule: Unknown module.");
 
   // If the module hasn't been compiled, just do that.
-  if (!ModuleStates[M].hasBeenLoaded())
+  if (!OwnedModules.hasModuleBeenLoaded(M))
     generateCodeForModule(M);
 
-  // Resolve any outstanding relocations.
-  Dyld.resolveRelocations();
-
-  Dyld.registerEHFrames();
-
-  // Set page permissions.
-  MemMgr.finalizeMemory();
-
-  ModuleStates[M] = ModuleFinalized;
+  finalizeLoadedModules();
 }
 
 void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {
@@ -279,10 +234,10 @@ Module *MCJIT::findModuleForSymbol(const
   MutexGuard locked(lock);
 
   // If it hasn't already been generated, see if it's in one of our modules.
-  SmallVector<Module *, 1>::iterator end = Modules.end();
-  SmallVector<Module *, 1>::iterator it;
-  for (it = Modules.begin(); it != end; ++it) {
-    Module *M = *it;
+  for (ModulePtrSet::iterator I = OwnedModules.begin_added(),
+                              E = OwnedModules.end_added();
+       I != E; ++I) {
+    Module *M = *I;
     Function *F = M->getFunction(Name);
     if (F && !F->empty())
       return M;
@@ -312,12 +267,6 @@ uint64_t MCJIT::getSymbolAddress(const s
   if (!M)
     return 0;
 
-  // If this is in one of our modules, generate code for that module.
-  assert(ModuleStates.find(M) != ModuleStates.end());
-  // If the module code has already been generated, we won't find the symbol.
-  if (ModuleStates[M].hasBeenLoaded())
-    return 0;
-
   generateCodeForModule(M);
 
   // Check the RuntimeDyld table again, it should be there now.
@@ -351,16 +300,15 @@ void *MCJIT::getPointerToFunction(Functi
     return Addr;
   }
 
-  // If this function doesn't belong to one of our modules, we're done.
   Module *M = F->getParent();
-  if (std::find(Modules.begin(), Modules.end(), M) == Modules.end())
-    return NULL;
-
-  assert(ModuleStates.find(M) != ModuleStates.end());
+  bool HasBeenAddedButNotLoaded = OwnedModules.hasModuleBeenAddedButNotLoaded(M);
 
   // Make sure the relevant module has been compiled and loaded.
-  if (!ModuleStates[M].hasBeenLoaded())
+  if (HasBeenAddedButNotLoaded)
     generateCodeForModule(M);
+  else if (!OwnedModules.hasModuleBeenLoaded(M))
+    // If this function doesn't belong to one of our modules, we're done.
+    return NULL;
 
   // FIXME: Should the Dyld be retaining module information? Probably not.
   // FIXME: Should we be using the mangler for this? Probably.
@@ -382,6 +330,45 @@ void MCJIT::freeMachineCodeForFunction(F
   report_fatal_error("not yet implemented");
 }
 
+void MCJIT::runStaticConstructorsDestructorsInModulePtrSet(
+    bool isDtors, ModulePtrSet::iterator I, ModulePtrSet::iterator E) {
+  for (; I != E; ++I) {
+    ExecutionEngine::runStaticConstructorsDestructors(*I, isDtors);
+  }
+}
+
+void MCJIT::runStaticConstructorsDestructors(bool isDtors) {
+  // Execute global ctors/dtors for each module in the program.
+  runStaticConstructorsDestructorsInModulePtrSet(
+      isDtors, OwnedModules.begin_added(), OwnedModules.end_added());
+  runStaticConstructorsDestructorsInModulePtrSet(
+      isDtors, OwnedModules.begin_loaded(), OwnedModules.end_loaded());
+  runStaticConstructorsDestructorsInModulePtrSet(
+      isDtors, OwnedModules.begin_finalized(), OwnedModules.end_finalized());
+}
+
+Function *MCJIT::FindFunctionNamedInModulePtrSet(const char *FnName,
+                                                 ModulePtrSet::iterator I,
+                                                 ModulePtrSet::iterator E) {
+  for (; I != E; ++I) {
+    if (Function *F = (*I)->getFunction(FnName))
+      return F;
+  }
+  return 0;
+}
+
+Function *MCJIT::FindFunctionNamed(const char *FnName) {
+  Function *F = FindFunctionNamedInModulePtrSet(
+      FnName, OwnedModules.begin_added(), OwnedModules.end_added());
+  if (!F)
+    F = FindFunctionNamedInModulePtrSet(FnName, OwnedModules.begin_loaded(),
+                                        OwnedModules.end_loaded());
+  if (!F)
+    F = FindFunctionNamedInModulePtrSet(FnName, OwnedModules.begin_finalized(),
+                                        OwnedModules.end_finalized());
+  return F;
+}
+
 GenericValue MCJIT::runFunction(Function *F,
                                 const std::vector<GenericValue> &ArgValues) {
   assert(F && "Function *F was null at entry to run()");

Modified: llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h?rev=193291&r1=193290&r2=193291&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h (original)
+++ llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h Wed Oct 23 19:19:14 2013
@@ -11,15 +11,15 @@
 #define LLVM_LIB_EXECUTIONENGINE_MCJIT_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/PassManager.h"
+#include "llvm/IR/Module.h"
 
 namespace llvm {
-
 class MCJIT;
 
 // This is a helper class that the MCJIT execution engine uses for linking
@@ -70,7 +70,7 @@ private:
   OwningPtr<RTDyldMemoryManager> ClientMM;
 };
 
-// About Module states:
+// About Module states: added->loaded->finalized.
 //
 // The purpose of the "added" state is having modules in standby. (added=known
 // but not compiled). The idea is that you can add a module to provide function
@@ -94,27 +94,108 @@ class MCJIT : public ExecutionEngine {
   MCJIT(Module *M, TargetMachine *tm, RTDyldMemoryManager *MemMgr,
         bool AllocateGVsWithCode);
 
-  enum ModuleState {
-    ModuleAdded,
-    ModuleEmitted,
-    ModuleLoading,
-    ModuleLoaded,
-    ModuleFinalizing,
-    ModuleFinalized
-  };
+  typedef llvm::SmallPtrSet<Module *, 4> ModulePtrSet;
 
-  class MCJITModuleState {
+  class OwningModuleContainer {
   public:
-    MCJITModuleState() : State(ModuleAdded) {}
-
-    MCJITModuleState & operator=(ModuleState s) { State = s; return *this; }
-    bool hasBeenEmitted() { return State != ModuleAdded; }
-    bool hasBeenLoaded() { return State != ModuleAdded &&
-                                  State != ModuleEmitted; }
-    bool hasBeenFinalized() { return State == ModuleFinalized; }
+    OwningModuleContainer() {
+    }
+    ~OwningModuleContainer() {
+      freeModulePtrSet(AddedModules);
+      freeModulePtrSet(LoadedModules);
+      freeModulePtrSet(FinalizedModules);
+    }
+
+    ModulePtrSet::iterator begin_added() { return AddedModules.begin(); }
+    ModulePtrSet::iterator end_added() { return AddedModules.end(); }
+
+    ModulePtrSet::iterator begin_loaded() { return LoadedModules.begin(); }
+    ModulePtrSet::iterator end_loaded() { return LoadedModules.end(); }
+
+    ModulePtrSet::iterator begin_finalized() { return FinalizedModules.begin(); }
+    ModulePtrSet::iterator end_finalized() { return FinalizedModules.end(); }
+
+    void addModule(Module *M) {
+      AddedModules.insert(M);
+    }
+
+    bool removeModule(Module *M) {
+      return AddedModules.erase(M) || LoadedModules.erase(M) ||
+             FinalizedModules.erase(M);
+    }
+
+    bool hasModuleBeenAddedButNotLoaded(Module *M) {
+      return AddedModules.count(M) != 0;
+    }
+
+    bool hasModuleBeenLoaded(Module *M) {
+      // If the module is in either the "loaded" or "finalized" sections it
+      // has been loaded.
+      return (LoadedModules.count(M) != 0 ) || (FinalizedModules.count(M) != 0);
+    }
+
+    bool hasModuleBeenFinalized(Module *M) {
+      return FinalizedModules.count(M) != 0;
+    }
+
+    bool ownsModule(Module* M) {
+      return (AddedModules.count(M) != 0) || (LoadedModules.count(M) != 0) ||
+             (FinalizedModules.count(M) != 0);
+    }
+
+    void markModuleAsLoaded(Module *M) {
+      // This checks against logic errors in the MCJIT implementation.
+      // This function should never be called with either a Module that MCJIT
+      // does not own or a Module that has already been loaded and/or finalized.
+      assert(AddedModules.count(M) &&
+             "markModuleAsLoaded: Module not found in AddedModules");
+
+      // Remove the module from the "Added" set.
+      AddedModules.erase(M);
+
+      // Add the Module to the "Loaded" set.
+      LoadedModules.insert(M);
+    }
+
+    void markModuleAsFinalized(Module *M) {
+      // This checks against logic errors in the MCJIT implementation.
+      // This function should never be called with either a Module that MCJIT
+      // does not own, a Module that has not been loaded or a Module that has
+      // already been finalized.
+      assert(LoadedModules.count(M) &&
+             "markModuleAsFinalized: Module not found in LoadedModules");
+
+      // Remove the module from the "Loaded" section of the list.
+      LoadedModules.erase(M);
+
+      // Add the Module to the "Finalized" section of the list by inserting it
+      // before the 'end' iterator.
+      FinalizedModules.insert(M);
+    }
+
+    void markAllLoadedModulesAsFinalized() {
+      for (ModulePtrSet::iterator I = LoadedModules.begin(),
+                                  E = LoadedModules.end();
+           I != E; ++I) {
+        Module *M = *I;
+        FinalizedModules.insert(M);
+      }
+      LoadedModules.clear();
+    }
 
   private:
-    ModuleState State;
+    ModulePtrSet AddedModules;
+    ModulePtrSet LoadedModules;
+    ModulePtrSet FinalizedModules;
+
+    void freeModulePtrSet(ModulePtrSet& MPS) {
+      // Go through the module set and delete everything.
+      for (ModulePtrSet::iterator I = MPS.begin(), E = MPS.end(); I != E; ++I) {
+        Module *M = *I;
+        delete M;
+      }
+      MPS.clear();
+    }
   };
 
   TargetMachine *TM;
@@ -123,8 +204,7 @@ class MCJIT : public ExecutionEngine {
   RuntimeDyld Dyld;
   SmallVector<JITEventListener*, 2> EventListeners;
 
-  typedef DenseMap<Module *, MCJITModuleState> ModuleStateMap;
-  ModuleStateMap  ModuleStates;
+  OwningModuleContainer OwnedModules;
 
   typedef DenseMap<Module *, ObjectImage *> LoadedObjectMap;
   LoadedObjectMap  LoadedObjects;
@@ -133,12 +213,26 @@ class MCJIT : public ExecutionEngine {
   // perform lookup of pre-compiled code to avoid re-compilation.
   ObjectCache *ObjCache;
 
+  Function *FindFunctionNamedInModulePtrSet(const char *FnName,
+                                            ModulePtrSet::iterator I,
+                                            ModulePtrSet::iterator E);
+
+  void runStaticConstructorsDestructorsInModulePtrSet(bool isDtors,
+                                                      ModulePtrSet::iterator I,
+                                                      ModulePtrSet::iterator E);
+
 public:
   ~MCJIT();
 
   /// @name ExecutionEngine interface implementation
   /// @{
   virtual void addModule(Module *M);
+  virtual bool removeModule(Module *M);
+
+  /// FindFunctionNamed - Search all of the active modules to find the one that
+  /// defines FnName.  This is very slow operation and shouldn't be used for
+  /// general code.
+  virtual Function *FindFunctionNamed(const char *FnName);
 
   /// Sets the object manager that MCJIT should use to avoid compilation.
   virtual void setObjectCache(ObjectCache *manager);
@@ -158,6 +252,12 @@ public:
   virtual void finalizeModule(Module *);
   void finalizeLoadedModules();
 
+  /// runStaticConstructorsDestructors - This method is used to execute all of
+  /// the static constructors or destructors for a program.
+  ///
+  /// \param isDtors - Run the destructors instead of constructors.
+  void runStaticConstructorsDestructors(bool isDtors);
+
   virtual void *getPointerToBasicBlock(BasicBlock *BB);
 
   virtual void *getPointerToFunction(Function *F);





More information about the llvm-commits mailing list