Adding multiple module support for MCJIT.
authorAndrew Kaylor <andrew.kaylor@intel.com>
Tue, 1 Oct 2013 01:47:35 +0000 (01:47 +0000)
committerAndrew Kaylor <andrew.kaylor@intel.com>
Tue, 1 Oct 2013 01:47:35 +0000 (01:47 +0000)
Tests to follow.

PIC with small code model and  EH frame handling will not work with multiple modules.  There are also some rough edges to be smoothed out for remote target support.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191722 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ExecutionEngine/ExecutionEngine.h
include/llvm/ExecutionEngine/RTDyldMemoryManager.h
lib/ExecutionEngine/MCJIT/MCJIT.cpp
lib/ExecutionEngine/MCJIT/MCJIT.h
lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
lib/ExecutionEngine/RTDyldMemoryManager.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
tools/lli/lli.cpp

index ceac298655e85bce87079ff73bf4579382b30c89..46ee7a648605f3a8614604db5c01f41fa33638de 100644 (file)
@@ -240,6 +240,8 @@ public:
   /// found, this function silently returns a null pointer. Otherwise,
   /// it prints a message to stderr and aborts.
   ///
+  /// This function is deprecated for the MCJIT execution engine.
+  ///
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true) = 0;
 
@@ -252,6 +254,23 @@ public:
                      "EE!");
   }
 
+  /// generateCodeForModule - Run code generationen for the specified module and
+  /// load it into memory.
+  ///
+  /// When this function has completed, all code and data for the specified
+  /// module, and any module on which this module depends, will be generated
+  /// and loaded into memory, but relocations will not yet have been applied
+  /// and all memory will be readable and writable but not executable.
+  ///
+  /// This function is primarily useful when generating code for an external
+  /// target, allowing the client an opportunity to remap section addresses
+  /// before relocations are applied.  Clients that intend to execute code
+  /// locally can use the getFunctionAddress call, which will generate code
+  /// and apply final preparations all in one step.
+  ///
+  /// This method has no effect for the legacy JIT engine or the interpeter.
+  virtual void generateCodeForModule(Module *M) {}
+
   /// finalizeObject - ensure the module is fully processed and is usable.
   ///
   /// It is the user-level function for completing the process of making the
@@ -307,10 +326,16 @@ public:
   /// getPointerToGlobalIfAvailable - This returns the address of the specified
   /// global value if it is has already been codegen'd, otherwise it returns
   /// null.
+  ///
+  /// This function is deprecated for the MCJIT execution engine.  It doesn't
+  /// seem to be needed in that case, but an equivalent can be added if it is.
   void *getPointerToGlobalIfAvailable(const GlobalValue *GV);
 
   /// getPointerToGlobal - This returns the address of the specified global
   /// value. This may involve code generation if it's a function.
+  ///
+  /// This function is deprecated for the MCJIT execution engine.  Use
+  /// getGlobalValueAddress instead.
   void *getPointerToGlobal(const GlobalValue *GV);
 
   /// getPointerToFunction - The different EE's represent function bodies in
@@ -318,22 +343,48 @@ public:
   /// pointer should look like.  When F is destroyed, the ExecutionEngine will
   /// remove its global mapping and free any machine code.  Be sure no threads
   /// are running inside F when that happens.
+  ///
+  /// This function is deprecated for the MCJIT execution engine.  Use
+  /// getFunctionAddress instead.
   virtual void *getPointerToFunction(Function *F) = 0;
 
   /// getPointerToBasicBlock - The different EE's represent basic blocks in
   /// different ways.  Return the representation for a blockaddress of the
   /// specified block.
+  ///
+  /// This function will not be implemented for the MCJIT execution engine.
   virtual void *getPointerToBasicBlock(BasicBlock *BB) = 0;
 
   /// getPointerToFunctionOrStub - If the specified function has been
   /// code-gen'd, return a pointer to the function.  If not, compile it, or use
   /// a stub to implement lazy compilation if available.  See
   /// getPointerToFunction for the requirements on destroying F.
+  ///
+  /// This function is deprecated for the MCJIT execution engine.  Use
+  /// getFunctionAddress instead.
   virtual void *getPointerToFunctionOrStub(Function *F) {
     // Default implementation, just codegen the function.
     return getPointerToFunction(F);
   }
 
+  /// getGlobalValueAddress - Return the address of the specified global
+  /// value. This may involve code generation.
+  ///
+  /// This function should not be called with the JIT or interpreter engines.
+  virtual uint64_t getGlobalValueAddress(const std::string &Name) {
+    // Default implementation for JIT and interpreter.  MCJIT will override this.
+    // JIT and interpreter clients should use getPointerToGlobal instead.
+    return 0;
+  }
+
+  /// getFunctionAddress - Return the address of the specified function.
+  /// This may involve code generation.
+  virtual uint64_t getFunctionAddress(const std::string &Name) {
+    // Default implementation for JIT and interpreter.  MCJIT will override this.
+    // JIT and interpreter clients should use getPointerToFunction instead.
+    return 0;
+  }
+
   // The JIT overrides a version that actually does this.
   virtual void runJITOnFunction(Function *, MachineCodeInfo * = 0) { }
 
@@ -366,6 +417,9 @@ public:
   /// getOrEmitGlobalVariable - Return the address of the specified global
   /// variable, possibly emitting it to memory if needed.  This is used by the
   /// Emitter.
+  ///
+  /// This function is deprecated for the MCJIT execution engine.  Use
+  /// getGlobalValueAddress instead.
   virtual void *getOrEmitGlobalVariable(const GlobalVariable *GV) {
     return getPointerToGlobal((const GlobalValue *)GV);
   }
index 99e2594f3cc7e2727fe47a722100275181281a8c..02e6b19b91cf48dd5908448e59f1b57a1649d54a 100644 (file)
@@ -50,12 +50,19 @@ public:
   /// Register the EH frames with the runtime so that c++ exceptions work.
   virtual void registerEHFrames(StringRef SectionData);
 
+  /// This method returns the address of the specified function or variable.
+  /// It is used to resolve symbols during module linking.
+  virtual uint64_t getSymbolAddress(const std::string &Name);
+
   /// This method returns the address of the specified function. As such it is
   /// only useful for resolving library symbols, not code generated symbols.
   ///
   /// If \p AbortOnFailure is false and no function with the given name is
   /// found, this function returns a null pointer. Otherwise, it prints a
   /// message to stderr and aborts.
+  ///
+  /// This function is deprecated for memory managers used to be used with
+  /// MCJIT or RuntimeDyld.  Use getSymbolAddress instead.
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true);
 
index 09dd92471708dee99f4ff283d8a1644381020225..9eaff4d68a2c8cb0aca7ce47eae2260b4d238c22 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -53,37 +54,45 @@ ExecutionEngine *MCJIT::createJIT(Module *M,
 
 MCJIT::MCJIT(Module *m, TargetMachine *tm, RTDyldMemoryManager *MM,
              bool AllocateGVsWithCode)
-  : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(MM), Dyld(MM),
-    IsLoaded(false), M(m), ObjCache(0) {
+  : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(this, MM), Dyld(&MemMgr),
+    ObjCache(0) {
 
+  ModuleStates[m] = ModuleAdded;
   setDataLayout(TM->getDataLayout());
 }
 
 MCJIT::~MCJIT() {
-  if (LoadedObject)
-    NotifyFreeingObject(*LoadedObject.get());
-  delete MemMgr;
+  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) {
+  Modules.push_back(M);
+  ModuleStates[M] = MCJITModuleState();
+}
+
 void MCJIT::setObjectCache(ObjectCache* NewCache) {
   ObjCache = NewCache;
 }
 
-ObjectBufferStream* 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
-  /// the future.
-  assert(M == m);
+ObjectBufferStream* MCJIT::emitObject(Module *M) {
+  // 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());
 
   // Get a thread lock to make sure we aren't trying to compile multiple times
   MutexGuard locked(lock);
 
-  // FIXME: Track compilation state on a per-module basis when multiple modules
-  //        are supported.
   // Re-compilation is not supported
-  assert(!IsLoaded);
+  assert(!ModuleStates[M].hasBeenEmitted());
 
   PassManager PM;
 
@@ -99,7 +108,7 @@ ObjectBufferStream* MCJIT::emitObject(Module *m) {
   }
 
   // Initialize passes.
-  PM.run(*m);
+  PM.run(*M);
   // Flush the output buffer to get the generated code into memory
   CompiledObject->flush();
 
@@ -109,21 +118,22 @@ ObjectBufferStream* MCJIT::emitObject(Module *m) {
     // 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.
     OwningPtr<MemoryBuffer> MB(CompiledObject->getMemBuffer());
-    ObjCache->notifyObjectCompiled(m, MB.get());
+    ObjCache->notifyObjectCompiled(M, MB.get());
   }
 
   return CompiledObject.take();
 }
 
-void MCJIT::loadObject(Module *M) {
+void MCJIT::generateCodeForModule(Module *M) {
+  // 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());
 
   // Get a thread lock to make sure we aren't trying to load multiple times
   MutexGuard locked(lock);
 
-  // FIXME: Track compilation state on a per-module basis when multiple modules
-  //        are supported.
   // Re-compilation is not supported
-  if (IsLoaded)
+  if (ModuleStates[M].hasBeenLoaded())
     return;
 
   OwningPtr<ObjectBuffer> ObjectToLoad;
@@ -141,59 +151,190 @@ void MCJIT::loadObject(Module *M) {
   }
 
   // Load the object into the dynamic linker.
-  // handing off ownership of the buffer
-  LoadedObject.reset(Dyld.loadObject(ObjectToLoad.take()));
+  // MCJIT now owns the ObjectImage pointer (via its LoadedObjects map).
+  ObjectImage *LoadedObject = Dyld.loadObject(ObjectToLoad.take());
+  LoadedObjects[M] = LoadedObject;
   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
-  IsLoaded = true;
+  ModuleStates[M] = ModuleLoaded;
+}
+
+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()) {
+      // FIXME: This should be module specific!
+      StringRef EHData = Dyld.getEHFrameSection();
+      if (!EHData.empty())
+        MemMgr.registerEHFrames(EHData);
+      ModuleStates[M] = ModuleFinalized;
+    }
+  }
+
+  // Set page permissions.
+  MemMgr.finalizeMemory();
 }
 
-// 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.
+// FIXME: Rename this.
 void MCJIT::finalizeObject() {
-  // If the module hasn't been compiled, just do that.
-  if (!IsLoaded) {
-    // If the call to Dyld.resolveRelocations() is removed from loadObject()
-    // we'll need to do that here.
-    loadObject(M);
-  } else {
-    // Resolve any relocations.
-    Dyld.resolveRelocations();
+  // 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()) {
+      // FIXME: This should be module specific!
+      StringRef EHData = Dyld.getEHFrameSection();
+      if (!EHData.empty())
+        MemMgr.registerEHFrames(EHData);
+      ModuleStates[M] = ModuleFinalized;
+    }
   }
 
+  // Set page permissions.
+  MemMgr.finalizeMemory();
+}
+
+void MCJIT::finalizeModule(Module *M) {
+  // 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;
+
+  // If the module hasn't been compiled, just do that.
+  if (!ModuleStates[M].hasBeenLoaded())
+    generateCodeForModule(M);
+
+  // Resolve any outstanding relocations.
+  Dyld.resolveRelocations();
+
+  // FIXME: Should this be module specific?
   StringRef EHData = Dyld.getEHFrameSection();
   if (!EHData.empty())
-    MemMgr->registerEHFrames(EHData);
+    MemMgr.registerEHFrames(EHData);
 
   // Set page permissions.
-  MemMgr->finalizeMemory();
+  MemMgr.finalizeMemory();
+
+  ModuleStates[M] = ModuleFinalized;
 }
 
 void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {
   report_fatal_error("not yet implemented");
 }
 
-void *MCJIT::getPointerToFunction(Function *F) {
-  // FIXME: This should really return a uint64_t since it's a pointer in the
-  // target address space, not our local address space. That's part of the
-  // ExecutionEngine interface, though. Fix that when the old JIT finally
-  // dies.
+uint64_t MCJIT::getExistingSymbolAddress(const std::string &Name) {
+  // Check with the RuntimeDyld to see if we already have this symbol.
+  if (Name[0] == '\1')
+    return Dyld.getSymbolLoadAddress(Name.substr(1));
+  return Dyld.getSymbolLoadAddress((TM->getMCAsmInfo()->getGlobalPrefix()
+                                       + Name));
+}
+
+Module *MCJIT::findModuleForSymbol(const std::string &Name,
+                                   bool CheckFunctionsOnly) {
+  // 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;
+    Function *F = M->getFunction(Name);
+    if (F && !F->empty())
+      return M;
+    if (!CheckFunctionsOnly) {
+      GlobalVariable *G = M->getGlobalVariable(Name);
+      if (G)
+        return M;
+      // FIXME: Do we need to worry about global aliases?
+    }
+  }
+  // We didn't find the symbol in any of our modules.
+  return NULL;
+}
+
+uint64_t MCJIT::getSymbolAddress(const std::string &Name,
+                                 bool CheckFunctionsOnly)
+{
+  // First, check to see if we already have this symbol.
+  uint64_t Addr = getExistingSymbolAddress(Name);
+  if (Addr)
+    return Addr;
+
+  // If it hasn't already been generated, see if it's in one of our modules.
+  Module *M = findModuleForSymbol(Name, CheckFunctionsOnly);
+  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;
 
-  // FIXME: Add support for per-module compilation state
-  if (!IsLoaded)
-    loadObject(M);
+  // FIXME: We probably need to make sure we aren't in the process of
+  //        loading or finalizing this module.
+  generateCodeForModule(M);
+
+  // Check the RuntimeDyld table again, it should be there now.
+  return getExistingSymbolAddress(Name);
+}
+
+uint64_t MCJIT::getGlobalValueAddress(const std::string &Name) {
+  uint64_t Result = getSymbolAddress(Name, false);
+  if (Result != 0)
+    finalizeLoadedModules();
+  return Result;
+}
+
+uint64_t MCJIT::getFunctionAddress(const std::string &Name) {
+  uint64_t Result = getSymbolAddress(Name, true);
+  if (Result != 0)
+    finalizeLoadedModules();
+  return Result;
+}
+
+// Deprecated.  Use getFunctionAddress instead.
+void *MCJIT::getPointerToFunction(Function *F) {
 
   if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
     bool AbortOnFailure = !F->hasExternalWeakLinkage();
@@ -202,6 +343,17 @@ void *MCJIT::getPointerToFunction(Function *F) {
     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());
+
+  // Make sure the relevant module has been compiled and loaded.
+  if (!ModuleStates[M].hasBeenLoaded())
+    generateCodeForModule(M);
+
   // FIXME: Should the Dyld be retaining module information? Probably not.
   // FIXME: Should we be using the mangler for this? Probably.
   //
@@ -324,12 +476,8 @@ GenericValue MCJIT::runFunction(Function *F,
 
 void *MCJIT::getPointerToNamedFunction(const std::string &Name,
                                        bool AbortOnFailure) {
-  // FIXME: Add support for per-module compilation state
-  if (!IsLoaded)
-    loadObject(M);
-
-  if (!isSymbolSearchingDisabled() && MemMgr) {
-    void *ptr = MemMgr->getPointerToNamedFunction(Name, false);
+  if (!isSymbolSearchingDisabled()) {
+    void *ptr = MemMgr.getPointerToNamedFunction(Name, false);
     if (ptr)
       return ptr;
   }
@@ -375,3 +523,10 @@ void MCJIT::NotifyFreeingObject(const ObjectImage& Obj) {
     EventListeners[I]->NotifyFreeingObject(Obj);
   }
 }
+
+uint64_t LinkingMemoryManager::getSymbolAddress(const std::string &Name) {
+  uint64_t Result = ParentEngine->getSymbolAddress(Name, false);
+  if (Result)
+    return Result;
+  return ClientMM->getSymbolAddress(Name);
+}
index a899d4f4080ceff2320c628c4232f2fce029d322..5fb2eebd92ae0f95b8fa128d6072269e1f254299 100644 (file)
 #ifndef LLVM_LIB_EXECUTIONENGINE_MCJIT_H
 #define LLVM_LIB_EXECUTIONENGINE_MCJIT_H
 
+#include "llvm/ADT/DenseMap.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"
 
 namespace llvm {
 
-class ObjectImage;
+class MCJIT;
+
+// This is a helper class that the MCJIT execution engine uses for linking
+// functions across modules that it owns.  It aggregates the memory manager
+// that is passed in to the MCJIT constructor and defers most functionality
+// to that object.
+class LinkingMemoryManager : public RTDyldMemoryManager {
+public:
+  LinkingMemoryManager(MCJIT *Parent, RTDyldMemoryManager *MM)
+    : ParentEngine(Parent), ClientMM(MM) {}
+
+  virtual uint64_t getSymbolAddress(const std::string &Name);
+
+  // Functions deferred to client memory manager
+  virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+                                       unsigned SectionID) {
+    return ClientMM->allocateCodeSection(Size, Alignment, SectionID);
+  }
+
+  virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
+                                       unsigned SectionID, bool IsReadOnly) {
+    return ClientMM->allocateDataSection(Size, Alignment,
+                                         SectionID, IsReadOnly);
+  }
+
+  virtual void registerEHFrames(StringRef SectionData) {
+    ClientMM->registerEHFrames(SectionData);
+  }
+
+  virtual bool finalizeMemory(std::string *ErrMsg = 0) {
+    return ClientMM->finalizeMemory(ErrMsg);
+  }
+
+private:
+  MCJIT *ParentEngine;
+  OwningPtr<RTDyldMemoryManager> ClientMM;
+};
 
 // FIXME: This makes all kinds of horrible assumptions for the time being,
 // like only having one module, not needing to worry about multi-threading,
@@ -28,16 +66,40 @@ class MCJIT : public ExecutionEngine {
   MCJIT(Module *M, TargetMachine *tm, RTDyldMemoryManager *MemMgr,
         bool AllocateGVsWithCode);
 
+  enum ModuleState {
+    ModuleAdded,
+    ModuleEmitted,
+    ModuleLoading,
+    ModuleLoaded,
+    ModuleFinalizing,
+    ModuleFinalized
+  };
+
+  class MCJITModuleState {
+  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; }
+
+  private:
+    ModuleState State;
+  };
+
   TargetMachine *TM;
   MCContext *Ctx;
-  RTDyldMemoryManager *MemMgr;
+  LinkingMemoryManager MemMgr;
   RuntimeDyld Dyld;
   SmallVector<JITEventListener*, 2> EventListeners;
 
-  // FIXME: Add support for multiple modules
-  bool IsLoaded;
-  Module *M;
-  OwningPtr<ObjectImage> LoadedObject;
+  typedef DenseMap<Module *, MCJITModuleState> ModuleStateMap;
+  ModuleStateMap  ModuleStates;
+
+  typedef DenseMap<Module *, ObjectImage *> LoadedObjectMap;
+  LoadedObjectMap  LoadedObjects;
 
   // An optional ObjectCache to be notified of compiled objects and used to
   // perform lookup of pre-compiled code to avoid re-compilation.
@@ -48,10 +110,13 @@ public:
 
   /// @name ExecutionEngine interface implementation
   /// @{
+  virtual void addModule(Module *M);
 
   /// Sets the object manager that MCJIT should use to avoid compilation.
   virtual void setObjectCache(ObjectCache *manager);
 
+  virtual void generateCodeForModule(Module *M);
+
   /// finalizeObject - ensure the module is fully processed and is usable.
   ///
   /// It is the user-level function for completing the process of making the
@@ -59,7 +124,10 @@ public:
   /// object have been relocated using mapSectionAddress.  When this method is
   /// called the MCJIT execution engine will reapply relocations for a loaded
   /// object.
+  /// FIXME: Do we really need both of these?
   virtual void finalizeObject();
+  virtual void finalizeModule(Module *);
+  void finalizeLoadedModules();
 
   virtual void *getPointerToBasicBlock(BasicBlock *BB);
 
@@ -91,10 +159,15 @@ public:
                                  uint64_t TargetAddress) {
     Dyld.mapSectionAddress(LocalAddress, TargetAddress);
   }
-
   virtual void RegisterJITEventListener(JITEventListener *L);
   virtual void UnregisterJITEventListener(JITEventListener *L);
 
+  // If successful, these function will implicitly finalize all loaded objects.
+  // To get a function address within MCJIT without causing a finalize, use
+  // getSymbolAddress.
+  virtual uint64_t getGlobalValueAddress(const std::string &Name);
+  virtual uint64_t getFunctionAddress(const std::string &Name);
+
   /// @}
   /// @name (Private) Registration Interfaces
   /// @{
@@ -111,6 +184,11 @@ public:
 
   // @}
 
+  // This is not directly exposed via the ExecutionEngine API, but it is
+  // used by the LinkingMemoryManager.
+  uint64_t getSymbolAddress(const std::string &Name,
+                          bool CheckFunctionsOnly);
+
 protected:
   /// emitObject -- Generate a JITed object in memory from the specified module
   /// Currently, MCJIT only supports a single module and the module passed to
@@ -119,10 +197,12 @@ protected:
   /// the future.
   ObjectBufferStream* emitObject(Module *M);
 
-  void loadObject(Module *M);
-
   void NotifyObjectEmitted(const ObjectImage& Obj);
   void NotifyFreeingObject(const ObjectImage& Obj);
+
+  uint64_t getExistingSymbolAddress(const std::string &Name);
+  Module *findModuleForSymbol(const std::string &Name,
+                              bool CheckFunctionsOnly);
 };
 
 } // End llvm namespace
index 650832e1292daa872620813282c42a049081650f..5469c8374b1a0ff042eaaeb479db441c6ad6f059 100644 (file)
@@ -105,6 +105,9 @@ bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
   // FIXME: Should in-progress permissions be reverted if an error occurs?
   error_code ec;
 
+  // Don't allow free memory blocks to be used after setting protection flags.
+  CodeMem.FreeMem.clear();
+
   // Make code memory executable.
   ec = applyMemoryGroupPermissions(CodeMem,
                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
@@ -115,6 +118,9 @@ bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
     return true;
   }
 
+  // Don't allow free memory blocks to be used after setting protection flags.
+  RODataMem.FreeMem.clear();
+
   // Make read-only data memory read-only.
   ec = applyMemoryGroupPermissions(RODataMem,
                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
index c5500dfdbc1871b0875a655fa8b969255bc4f62b..de38b38d64ba2ad1030a477a0e1cde717820ab9d 100644 (file)
@@ -68,8 +68,10 @@ static int jit_noop() {
   return 0;
 }
 
-void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
-                                                     bool AbortOnFailure) {
+uint64_t RTDyldMemoryManager::getSymbolAddress(const std::string &Name) {
+  // This implementation assumes that the host program is the target.
+  // Clients generating code for a remote target should implement their own
+  // memory manager.
 #if defined(__linux__)
   //===--------------------------------------------------------------------===//
   // Function stubs that are invoked instead of certain library calls
@@ -80,14 +82,14 @@ void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
   // 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;
+  if (Name == "stat") return (uint64_t)&stat;
+  if (Name == "fstat") return (uint64_t)&fstat;
+  if (Name == "lstat") return (uint64_t)&lstat;
+  if (Name == "stat64") return (uint64_t)&stat64;
+  if (Name == "fstat64") return (uint64_t)&fstat64;
+  if (Name == "lstat64") return (uint64_t)&lstat64;
+  if (Name == "atexit") return (uint64_t)&atexit;
+  if (Name == "mknod") return (uint64_t)&mknod;
 #endif // __linux__
 
   // We should not invoke parent's ctors/dtors from generated main()!
@@ -96,23 +98,31 @@ void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
   // (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;
+  if (Name == "__main") return (uint64_t)&jit_noop;
 
   const char *NameStr = Name.c_str();
   void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
-  if (Ptr) return Ptr;
+  if (Ptr)
+    return (uint64_t)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 (Ptr)
+      return (uint64_t)Ptr;
   }
+  return 0;
+}
 
-  if (AbortOnFailure)
+void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
+                                                     bool AbortOnFailure) {
+  uint64_t Addr = getSymbolAddress(Name);
+
+  if (!Addr && AbortOnFailure)
     report_fatal_error("Program used external function '" + Name +
                        "' which could not be resolved!");
-  return 0;
+  return (void*)Addr;
 }
 
 } // namespace llvm
index d36126a9e2db776b979e1da7496477a5a57be90e..89c04dd007b867f75b241482d33b54735d635355 100644 (file)
@@ -49,6 +49,7 @@ void RuntimeDyldImpl::resolveRelocations() {
             << "\t" << format("%p", (uint8_t *)Addr)
             << "\n");
     resolveRelocationList(Relocations[i], Addr);
+    Relocations.erase(i);
   }
 }
 
@@ -464,31 +465,42 @@ void RuntimeDyldImpl::resolveRelocationList(const RelocationList &Relocs,
 }
 
 void RuntimeDyldImpl::resolveExternalSymbols() {
-  StringMap<RelocationList>::iterator i = ExternalSymbolRelocations.begin(),
-                                      e = ExternalSymbolRelocations.end();
-  for (; i != e; i++) {
+  while(!ExternalSymbolRelocations.empty()) {
+    StringMap<RelocationList>::iterator i = ExternalSymbolRelocations.begin();
+
     StringRef Name = i->first();
     RelocationList &Relocs = i->second;
-    SymbolTableMap::const_iterator Loc = GlobalSymbolTable.find(Name);
-    if (Loc == GlobalSymbolTable.end()) {
-      if (Name.size() == 0) {
-        // This is an absolute symbol, use an address of zero.
-        DEBUG(dbgs() << "Resolving absolute relocations." << "\n");
-        resolveRelocationList(Relocs, 0);
+    if (Name.size() == 0) {
+      // This is an absolute symbol, use an address of zero.
+      DEBUG(dbgs() << "Resolving absolute relocations." << "\n");
+      resolveRelocationList(Relocs, 0);
+    } else {
+      uint64_t Addr = 0;
+      SymbolTableMap::const_iterator Loc = GlobalSymbolTable.find(Name);
+      if (Loc == GlobalSymbolTable.end()) {
+          // This is an external symbol, try to get its address from
+          // MemoryManager.
+          Addr = MemMgr->getSymbolAddress(Name.data());
       } else {
-        // This is an external symbol, try to get its address from
-        // MemoryManager.
-        uint8_t *Addr = (uint8_t*) MemMgr->getPointerToNamedFunction(Name.data(),
-                                                                   true);
-        updateGOTEntries(Name, (uint64_t)Addr);
-        DEBUG(dbgs() << "Resolving relocations Name: " << Name
-                << "\t" << format("%p", Addr)
-                << "\n");
-        resolveRelocationList(Relocs, (uintptr_t)Addr);
+        // We found the symbol in our global table.  It was probably in a
+        // Module that we loaded previously.
+        SymbolLoc SymLoc = GlobalSymbolTable.lookup(Name);
+        Addr = getSectionLoadAddress(SymLoc.first) + SymLoc.second;
       }
-    } else {
-      report_fatal_error("Expected external symbol");
+
+      // FIXME: Implement error handling that doesn't kill the host program!
+      if (!Addr)
+        report_fatal_error("Program used external function '" + Name +
+                          "' which could not be resolved!");
+
+      updateGOTEntries(Name, Addr);
+      DEBUG(dbgs() << "Resolving relocations Name: " << Name
+              << "\t" << format("0x%lx", Addr)
+              << "\n");
+      resolveRelocationList(Relocs, Addr);
     }
+
+    ExternalSymbolRelocations.erase(i->first());
   }
 }
 
@@ -550,10 +562,14 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
 }
 
 void *RuntimeDyld::getSymbolAddress(StringRef Name) {
+  if (!Dyld)
+    return NULL;
   return Dyld->getSymbolAddress(Name);
 }
 
 uint64_t RuntimeDyld::getSymbolLoadAddress(StringRef Name) {
+  if (!Dyld)
+    return 0;
   return Dyld->getSymbolLoadAddress(Name);
 }
 
index 8d74b2326d73f12c50d92d83707d7c56c633a0dd..ba9cb99d5a6f085bb795fbf69b609bdeb5d13205 100644 (file)
@@ -460,18 +460,18 @@ int main(int argc, char **argv, char * const *envp) {
   //
   // Run static constructors.
   if (!RemoteMCJIT) {
-      if (UseMCJIT && !ForceInterpreter) {
-        // Give MCJIT a chance to apply relocations and set page permissions.
-        EE->finalizeObject();
-      }
-      EE->runStaticConstructorsDestructors(false);
-  }
+    if (UseMCJIT && !ForceInterpreter) {
+      // Give MCJIT a chance to apply relocations and set page permissions.
+      EE->finalizeObject();
+    }
+    EE->runStaticConstructorsDestructors(false);
 
-  if (NoLazyCompilation) {
-    for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
-      Function *Fn = &*I;
-      if (Fn != EntryFn && !Fn->isDeclaration())
-        EE->getPointerToFunction(Fn);
+    if (!UseMCJIT && NoLazyCompilation) {
+      for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
+        Function *Fn = &*I;
+        if (Fn != EntryFn && !Fn->isDeclaration())
+          EE->getPointerToFunction(Fn);
+      }
     }
   }
 
@@ -484,12 +484,10 @@ int main(int argc, char **argv, char * const *envp) {
     RemoteTarget Target;
     Target.create();
 
-    // Ask for a pointer to the entry function. This triggers the actual
-    // compilation.
-    (void)EE->getPointerToFunction(EntryFn);
+    // Trigger compilation.
+    EE->generateCodeForModule(Mod);
 
-    // Enough has been compiled to execute the entry function now, so
-    // layout the target memory.
+    // Layout the target memory.
     layoutRemoteTargetMemory(&Target, MM);
 
     // Since we're executing in a (at least simulated) remote address space,