Optimizing MCJIT module state tracking

Patch co-developed with Yaron Keren.




git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193291 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Kaylor 2013-10-24 00:19:14 +00:00
parent faf1415c4f
commit 2ad18efdc7
3 changed files with 213 additions and 123 deletions

View File

@ -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.

View File

@ -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 *tm, RTDyldMemoryManager *MM,
: 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* NewCache) {
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 *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());
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 *M) {
NotifyObjectEmitted(*LoadedObject);
ModuleStates[M] = ModuleLoaded;
OwnedModules.markModuleAsLoaded(M);
}
void MCJIT::finalizeLoadedModules() {
@ -175,19 +181,9 @@ void MCJIT::finalizeLoadedModules() {
// Resolve any outstanding relocations.
Dyld.resolveRelocations();
OwnedModules.markAllLoadedModulesAsFinalized();
// 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;
}
}
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 std::string &Name,
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 std::string &Name,
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(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());
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(Function *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()");

View File

@ -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) {}
OwningModuleContainer() {
}
~OwningModuleContainer() {
freeModulePtrSet(AddedModules);
freeModulePtrSet(LoadedModules);
freeModulePtrSet(FinalizedModules);
}
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; }
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);