Make the ExecutionEngine automatically remove global mappings on when their

GlobalValue is destroyed.  Function destruction still leaks machine code and
can crash on leaked stubs, but this is some progress.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@83987 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jeffrey Yasskin
2009-10-13 17:42:08 +00:00
parent 2d175064ab
commit 4c5b23b24f
3 changed files with 104 additions and 51 deletions

View File

@ -19,6 +19,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/System/Mutex.h" #include "llvm/System/Mutex.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
@ -26,6 +27,7 @@ namespace llvm {
struct GenericValue; struct GenericValue;
class Constant; class Constant;
class ExecutionEngine;
class Function; class Function;
class GlobalVariable; class GlobalVariable;
class GlobalValue; class GlobalValue;
@ -37,13 +39,29 @@ class ModuleProvider;
class MutexGuard; class MutexGuard;
class TargetData; class TargetData;
class Type; class Type;
template<typename> class AssertingVH;
class ExecutionEngineState { class ExecutionEngineState {
public:
class MapUpdatingCVH : public CallbackVH {
ExecutionEngineState &EES;
public:
MapUpdatingCVH(ExecutionEngineState &EES, const GlobalValue *GV);
operator const GlobalValue*() const {
return cast<GlobalValue>(getValPtr());
}
virtual void deleted();
virtual void allUsesReplacedWith(Value *new_value);
};
private: private:
ExecutionEngine &EE;
/// GlobalAddressMap - A mapping between LLVM global values and their /// GlobalAddressMap - A mapping between LLVM global values and their
/// actualized version... /// actualized version...
std::map<AssertingVH<const GlobalValue>, void *> GlobalAddressMap; std::map<MapUpdatingCVH, void *> GlobalAddressMap;
/// GlobalAddressReverseMap - This is the reverse mapping of GlobalAddressMap, /// GlobalAddressReverseMap - This is the reverse mapping of GlobalAddressMap,
/// used to convert raw addresses into the LLVM global value that is emitted /// used to convert raw addresses into the LLVM global value that is emitted
@ -52,7 +70,13 @@ private:
std::map<void *, AssertingVH<const GlobalValue> > GlobalAddressReverseMap; std::map<void *, AssertingVH<const GlobalValue> > GlobalAddressReverseMap;
public: public:
std::map<AssertingVH<const GlobalValue>, void *> & ExecutionEngineState(ExecutionEngine &EE) : EE(EE) {}
MapUpdatingCVH getVH(const GlobalValue *GV) {
return MapUpdatingCVH(*this, GV);
}
std::map<MapUpdatingCVH, void *> &
getGlobalAddressMap(const MutexGuard &) { getGlobalAddressMap(const MutexGuard &) {
return GlobalAddressMap; return GlobalAddressMap;
} }
@ -69,7 +93,7 @@ public:
class ExecutionEngine { class ExecutionEngine {
const TargetData *TD; const TargetData *TD;
ExecutionEngineState state; ExecutionEngineState EEState;
bool LazyCompilationDisabled; bool LazyCompilationDisabled;
bool GVCompilationDisabled; bool GVCompilationDisabled;
bool SymbolSearchingDisabled; bool SymbolSearchingDisabled;
@ -213,8 +237,8 @@ public:
/// at the specified location. This is used internally as functions are JIT'd /// at the specified location. This is used internally as functions are JIT'd
/// and as global variables are laid out in memory. It can and should also be /// and as global variables are laid out in memory. It can and should also be
/// used by clients of the EE that want to have an LLVM global overlay /// used by clients of the EE that want to have an LLVM global overlay
/// existing data in memory. After adding a mapping for GV, you must not /// existing data in memory. Mappings are automatically removed when their
/// destroy it until you've removed the mapping. /// GlobalValue is destroyed.
void addGlobalMapping(const GlobalValue *GV, void *Addr); void addGlobalMapping(const GlobalValue *GV, void *Addr);
/// clearAllGlobalMappings - Clear all global mappings and start over again /// clearAllGlobalMappings - Clear all global mappings and start over again
@ -238,29 +262,23 @@ public:
void *getPointerToGlobalIfAvailable(const GlobalValue *GV); void *getPointerToGlobalIfAvailable(const GlobalValue *GV);
/// getPointerToGlobal - This returns the address of the specified global /// getPointerToGlobal - This returns the address of the specified global
/// value. This may involve code generation if it's a function. After /// value. This may involve code generation if it's a function.
/// getting a pointer to GV, it and all globals it transitively refers to have
/// been passed to addGlobalMapping. You must clear the mapping for each
/// referred-to global before destroying it. If a referred-to global RTG is a
/// function and this ExecutionEngine is a JIT compiler, calling
/// updateGlobalMapping(RTG, 0) will leak the function's machine code, so you
/// should call freeMachineCodeForFunction(RTG) instead. Note that
/// optimizations can move and delete non-external GlobalValues without
/// notifying the ExecutionEngine.
/// ///
void *getPointerToGlobal(const GlobalValue *GV); void *getPointerToGlobal(const GlobalValue *GV);
/// getPointerToFunction - The different EE's represent function bodies in /// getPointerToFunction - The different EE's represent function bodies in
/// different ways. They should each implement this to say what a function /// different ways. They should each implement this to say what a function
/// pointer should look like. See getPointerToGlobal for the requirements on /// pointer should look like. When F is destroyed, the ExecutionEngine will
/// destroying F and any GlobalValues it refers to. /// remove its global mapping but will not yet free its machine code. Call
/// freeMachineCodeForFunction(F) explicitly to do that. Note that global
/// optimizations can destroy Functions without notifying the ExecutionEngine.
/// ///
virtual void *getPointerToFunction(Function *F) = 0; virtual void *getPointerToFunction(Function *F) = 0;
/// getPointerToFunctionOrStub - If the specified function has been /// getPointerToFunctionOrStub - If the specified function has been
/// code-gen'd, return a pointer to the function. If not, compile it, or use /// code-gen'd, return a pointer to the function. If not, compile it, or use
/// a stub to implement lazy compilation if available. See getPointerToGlobal /// a stub to implement lazy compilation if available. See
/// for the requirements on destroying F and any GlobalValues it refers to. /// getPointerToFunction for the requirements on destroying F.
/// ///
virtual void *getPointerToFunctionOrStub(Function *F) { virtual void *getPointerToFunctionOrStub(Function *F) {
// Default implementation, just codegen the function. // Default implementation, just codegen the function.
@ -296,8 +314,7 @@ public:
/// getOrEmitGlobalVariable - Return the address of the specified global /// getOrEmitGlobalVariable - Return the address of the specified global
/// variable, possibly emitting it to memory if needed. This is used by the /// variable, possibly emitting it to memory if needed. This is used by the
/// Emitter. See getPointerToGlobal for the requirements on destroying GV and /// Emitter.
/// any GlobalValues it refers to.
virtual void *getOrEmitGlobalVariable(const GlobalVariable *GV) { virtual void *getOrEmitGlobalVariable(const GlobalVariable *GV) {
return getPointerToGlobal((GlobalValue*)GV); return getPointerToGlobal((GlobalValue*)GV);
} }
@ -471,6 +488,12 @@ class EngineBuilder {
}; };
inline bool operator<(const ExecutionEngineState::MapUpdatingCVH& lhs,
const ExecutionEngineState::MapUpdatingCVH& rhs) {
return static_cast<const GlobalValue*>(lhs) <
static_cast<const GlobalValue*>(rhs);
}
} // End llvm namespace } // End llvm namespace
#endif #endif

View File

@ -46,7 +46,9 @@ ExecutionEngine *(*ExecutionEngine::InterpCtor)(ModuleProvider *MP,
ExecutionEngine::EERegisterFn ExecutionEngine::ExceptionTableRegister = 0; ExecutionEngine::EERegisterFn ExecutionEngine::ExceptionTableRegister = 0;
ExecutionEngine::ExecutionEngine(ModuleProvider *P) : LazyFunctionCreator(0) { ExecutionEngine::ExecutionEngine(ModuleProvider *P)
: EEState(*this),
LazyFunctionCreator(0) {
LazyCompilationDisabled = false; LazyCompilationDisabled = false;
GVCompilationDisabled = false; GVCompilationDisabled = false;
SymbolSearchingDisabled = false; SymbolSearchingDisabled = false;
@ -115,8 +117,8 @@ Function *ExecutionEngine::FindFunctionNamed(const char *FnName) {
void *ExecutionEngineState::RemoveMapping( void *ExecutionEngineState::RemoveMapping(
const MutexGuard &, const GlobalValue *ToUnmap) { const MutexGuard &, const GlobalValue *ToUnmap) {
std::map<AssertingVH<const GlobalValue>, void *>::iterator I = std::map<MapUpdatingCVH, void *>::iterator I =
GlobalAddressMap.find(ToUnmap); GlobalAddressMap.find(getVH(ToUnmap));
void *OldVal; void *OldVal;
if (I == GlobalAddressMap.end()) if (I == GlobalAddressMap.end())
OldVal = 0; OldVal = 0;
@ -139,14 +141,14 @@ void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) {
DEBUG(errs() << "JIT: Map \'" << GV->getName() DEBUG(errs() << "JIT: Map \'" << GV->getName()
<< "\' to [" << Addr << "]\n";); << "\' to [" << Addr << "]\n";);
void *&CurVal = state.getGlobalAddressMap(locked)[GV]; void *&CurVal = EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)];
assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!"); assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!");
CurVal = Addr; CurVal = Addr;
// If we are using the reverse mapping, add it too // If we are using the reverse mapping, add it too
if (!state.getGlobalAddressReverseMap(locked).empty()) { if (!EEState.getGlobalAddressReverseMap(locked).empty()) {
AssertingVH<const GlobalValue> &V = AssertingVH<const GlobalValue> &V =
state.getGlobalAddressReverseMap(locked)[Addr]; EEState.getGlobalAddressReverseMap(locked)[Addr];
assert((V == 0 || GV == 0) && "GlobalMapping already established!"); assert((V == 0 || GV == 0) && "GlobalMapping already established!");
V = GV; V = GV;
} }
@ -157,8 +159,8 @@ void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) {
void ExecutionEngine::clearAllGlobalMappings() { void ExecutionEngine::clearAllGlobalMappings() {
MutexGuard locked(lock); MutexGuard locked(lock);
state.getGlobalAddressMap(locked).clear(); EEState.getGlobalAddressMap(locked).clear();
state.getGlobalAddressReverseMap(locked).clear(); EEState.getGlobalAddressReverseMap(locked).clear();
} }
/// clearGlobalMappingsFromModule - Clear all global mappings that came from a /// clearGlobalMappingsFromModule - Clear all global mappings that came from a
@ -167,11 +169,11 @@ void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) {
MutexGuard locked(lock); MutexGuard locked(lock);
for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) { for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) {
state.RemoveMapping(locked, FI); EEState.RemoveMapping(locked, FI);
} }
for (Module::global_iterator GI = M->global_begin(), GE = M->global_end(); for (Module::global_iterator GI = M->global_begin(), GE = M->global_end();
GI != GE; ++GI) { GI != GE; ++GI) {
state.RemoveMapping(locked, GI); EEState.RemoveMapping(locked, GI);
} }
} }
@ -181,25 +183,25 @@ void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) {
void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) { void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) {
MutexGuard locked(lock); MutexGuard locked(lock);
std::map<AssertingVH<const GlobalValue>, void *> &Map = std::map<ExecutionEngineState::MapUpdatingCVH, void *> &Map =
state.getGlobalAddressMap(locked); EEState.getGlobalAddressMap(locked);
// Deleting from the mapping? // Deleting from the mapping?
if (Addr == 0) { if (Addr == 0) {
return state.RemoveMapping(locked, GV); return EEState.RemoveMapping(locked, GV);
} }
void *&CurVal = Map[GV]; void *&CurVal = Map[EEState.getVH(GV)];
void *OldVal = CurVal; void *OldVal = CurVal;
if (CurVal && !state.getGlobalAddressReverseMap(locked).empty()) if (CurVal && !EEState.getGlobalAddressReverseMap(locked).empty())
state.getGlobalAddressReverseMap(locked).erase(CurVal); EEState.getGlobalAddressReverseMap(locked).erase(CurVal);
CurVal = Addr; CurVal = Addr;
// If we are using the reverse mapping, add it too // If we are using the reverse mapping, add it too
if (!state.getGlobalAddressReverseMap(locked).empty()) { if (!EEState.getGlobalAddressReverseMap(locked).empty()) {
AssertingVH<const GlobalValue> &V = AssertingVH<const GlobalValue> &V =
state.getGlobalAddressReverseMap(locked)[Addr]; EEState.getGlobalAddressReverseMap(locked)[Addr];
assert((V == 0 || GV == 0) && "GlobalMapping already established!"); assert((V == 0 || GV == 0) && "GlobalMapping already established!");
V = GV; V = GV;
} }
@ -212,9 +214,9 @@ void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) {
void *ExecutionEngine::getPointerToGlobalIfAvailable(const GlobalValue *GV) { void *ExecutionEngine::getPointerToGlobalIfAvailable(const GlobalValue *GV) {
MutexGuard locked(lock); MutexGuard locked(lock);
std::map<AssertingVH<const GlobalValue>, void*>::iterator I = std::map<ExecutionEngineState::MapUpdatingCVH, void*>::iterator I =
state.getGlobalAddressMap(locked).find(GV); EEState.getGlobalAddressMap(locked).find(EEState.getVH(GV));
return I != state.getGlobalAddressMap(locked).end() ? I->second : 0; return I != EEState.getGlobalAddressMap(locked).end() ? I->second : 0;
} }
/// getGlobalValueAtAddress - Return the LLVM global value object that starts /// getGlobalValueAtAddress - Return the LLVM global value object that starts
@ -224,17 +226,17 @@ const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) {
MutexGuard locked(lock); MutexGuard locked(lock);
// If we haven't computed the reverse mapping yet, do so first. // If we haven't computed the reverse mapping yet, do so first.
if (state.getGlobalAddressReverseMap(locked).empty()) { if (EEState.getGlobalAddressReverseMap(locked).empty()) {
for (std::map<AssertingVH<const GlobalValue>, void *>::iterator for (std::map<ExecutionEngineState::MapUpdatingCVH, void *>::iterator
I = state.getGlobalAddressMap(locked).begin(), I = EEState.getGlobalAddressMap(locked).begin(),
E = state.getGlobalAddressMap(locked).end(); I != E; ++I) E = EEState.getGlobalAddressMap(locked).end(); I != E; ++I)
state.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second, EEState.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second,
I->first)); I->first));
} }
std::map<void *, AssertingVH<const GlobalValue> >::iterator I = std::map<void *, AssertingVH<const GlobalValue> >::iterator I =
state.getGlobalAddressReverseMap(locked).find(Addr); EEState.getGlobalAddressReverseMap(locked).find(Addr);
return I != state.getGlobalAddressReverseMap(locked).end() ? I->second : 0; return I != EEState.getGlobalAddressReverseMap(locked).end() ? I->second : 0;
} }
// CreateArgv - Turn a vector of strings into a nice argv style array of // CreateArgv - Turn a vector of strings into a nice argv style array of
@ -474,7 +476,7 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) {
return getPointerToFunction(F); return getPointerToFunction(F);
MutexGuard locked(lock); MutexGuard locked(lock);
void *p = state.getGlobalAddressMap(locked)[GV]; void *p = EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)];
if (p) if (p)
return p; return p;
@ -484,7 +486,7 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) {
EmitGlobalVariable(GVar); EmitGlobalVariable(GVar);
else else
llvm_unreachable("Global hasn't had an address allocated yet!"); llvm_unreachable("Global hasn't had an address allocated yet!");
return state.getGlobalAddressMap(locked)[GV]; return EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)];
} }
/// This function converts a Constant* into a GenericValue. The interesting /// This function converts a Constant* into a GenericValue. The interesting
@ -1069,3 +1071,18 @@ void ExecutionEngine::EmitGlobalVariable(const GlobalVariable *GV) {
NumInitBytes += (unsigned)GVSize; NumInitBytes += (unsigned)GVSize;
++NumGlobals; ++NumGlobals;
} }
ExecutionEngineState::MapUpdatingCVH::MapUpdatingCVH(
ExecutionEngineState &EES, const GlobalValue *GV)
: CallbackVH(const_cast<GlobalValue*>(GV)), EES(EES) {}
void ExecutionEngineState::MapUpdatingCVH::deleted() {
MutexGuard locked(EES.EE.lock);
EES.RemoveMapping(locked, *this); // Destroys *this.
}
void ExecutionEngineState::MapUpdatingCVH::allUsesReplacedWith(
Value *new_value) {
assert(false && "The ExecutionEngine doesn't know how to handle a"
" RAUW on a value it has a global mapping for.");
}

View File

@ -113,4 +113,17 @@ TEST_F(ExecutionEngineTest, ClearModuleMappings) {
EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1)); EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1));
} }
TEST_F(ExecutionEngineTest, DestructionRemovesGlobalMapping) {
GlobalVariable *G1 =
NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1");
int32_t Mem1 = 3;
Engine->addGlobalMapping(G1, &Mem1);
// Make sure the reverse mapping is enabled.
EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1));
// When the GV goes away, the ExecutionEngine should remove any
// mappings that refer to it.
G1->eraseFromParent();
EXPECT_EQ(NULL, Engine->getGlobalValueAtAddress(&Mem1));
}
} }