diff options
author | Jeffrey Yasskin <jyasskin@google.com> | 2010-03-04 00:32:33 +0000 |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@google.com> | 2010-03-04 00:32:33 +0000 |
commit | 1b1400dd772d6708390257d8688b9eab1089a701 (patch) | |
tree | 8eb4cf6586b7ecad0891ded2cee6c4de8807d46f /lib/ExecutionEngine | |
parent | dc48d1413ee8f5c19448a4f7370b966e1a294aaa (diff) | |
download | external_llvm-1b1400dd772d6708390257d8688b9eab1089a701.zip external_llvm-1b1400dd772d6708390257d8688b9eab1089a701.tar.gz external_llvm-1b1400dd772d6708390257d8688b9eab1089a701.tar.bz2 |
Make sure JITResolvers don't leave any stubs behind. When a JITResolver was
destroyed, it could leave stubs in the StubToResolverMap, which would confuse
the lookup for subsequent lazy compilations.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@97698 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ExecutionEngine')
-rw-r--r-- | lib/ExecutionEngine/JIT/JITEmitter.cpp | 164 |
1 files changed, 105 insertions, 59 deletions
diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 57c4375..5faf0ee 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -156,53 +156,18 @@ namespace { // was no stub. This function uses the call-site->function map to find a // relevant function, but asserts that only stubs and not other call sites // will be passed in. - Function *EraseStub(const MutexGuard &locked, void *Stub) { - CallSiteToFunctionMapTy::iterator C2F_I = - CallSiteToFunctionMap.find(Stub); - if (C2F_I == CallSiteToFunctionMap.end()) { - // Not a stub. - return NULL; - } - - Function *const F = C2F_I->second; -#ifndef NDEBUG - void *RealStub = FunctionToLazyStubMap.lookup(F); - assert(RealStub == Stub && - "Call-site that wasn't a stub pass in to EraseStub"); -#endif - FunctionToLazyStubMap.erase(F); - CallSiteToFunctionMap.erase(C2F_I); - - // Remove the stub from the function->call-sites map, and remove the whole - // entry from the map if that was the last call site. - FunctionToCallSitesMapTy::iterator F2C_I = FunctionToCallSitesMap.find(F); - assert(F2C_I != FunctionToCallSitesMap.end() && - "FunctionToCallSitesMap broken"); - bool Erased = F2C_I->second.erase(Stub); - (void)Erased; - assert(Erased && "FunctionToCallSitesMap broken"); - if (F2C_I->second.empty()) - FunctionToCallSitesMap.erase(F2C_I); - - return F; - } + Function *EraseStub(const MutexGuard &locked, void *Stub); - void EraseAllCallSites(const MutexGuard &locked, Function *F) { + void EraseAllCallSitesFor(const MutexGuard &locked, Function *F) { assert(locked.holds(TheJIT->lock)); - EraseAllCallSitesPrelocked(F); - } - void EraseAllCallSitesPrelocked(Function *F) { - FunctionToCallSitesMapTy::iterator F2C = FunctionToCallSitesMap.find(F); - if (F2C == FunctionToCallSitesMap.end()) - return; - for (SmallPtrSet<void*, 1>::const_iterator I = F2C->second.begin(), - E = F2C->second.end(); I != E; ++I) { - bool Erased = CallSiteToFunctionMap.erase(*I); - (void)Erased; - assert(Erased && "Missing call site->function mapping"); - } - FunctionToCallSitesMap.erase(F2C); + EraseAllCallSitesForPrelocked(F); } + void EraseAllCallSitesForPrelocked(Function *F); + + // Erases _all_ call sites regardless of their function. This is used to + // unregister the stub addresses from the StubToResolverMap in + // ~JITResolver(). + void EraseAllCallSitesPrelocked(); }; /// JITResolver - Keep track of, and resolve, call sites for functions that @@ -240,6 +205,8 @@ namespace { LazyResolverFn = jit.getJITInfo().getLazyResolverFunction(JITCompilerFn); } + ~JITResolver(); + /// getLazyFunctionStubIfAvailable - This returns a pointer to a function's /// lazy-compilation stub if it has already been created. void *getLazyFunctionStubIfAvailable(Function *F); @@ -305,6 +272,17 @@ namespace { --I; return I->second; } + /// True if any stubs refer to the given resolver. Only used in an assert(). + /// O(N) + bool ResolverHasStubs(JITResolver* Resolver) const { + MutexGuard guard(Lock); + for (std::map<void*, JITResolver*>::const_iterator I = Map.begin(), + E = Map.end(); I != E; ++I) { + if (I->second == Resolver) + return true; + } + return false; + } }; /// This needs to be static so that a lazy call stub can access it with no /// context except the address of the stub. @@ -536,7 +514,73 @@ namespace { } void CallSiteValueMapConfig::onDelete(JITResolverState *JRS, Function *F) { - JRS->EraseAllCallSitesPrelocked(F); + JRS->EraseAllCallSitesForPrelocked(F); +} + +Function *JITResolverState::EraseStub(const MutexGuard &locked, void *Stub) { + CallSiteToFunctionMapTy::iterator C2F_I = + CallSiteToFunctionMap.find(Stub); + if (C2F_I == CallSiteToFunctionMap.end()) { + // Not a stub. + return NULL; + } + + StubToResolverMap->UnregisterStubResolver(Stub); + + Function *const F = C2F_I->second; +#ifndef NDEBUG + void *RealStub = FunctionToLazyStubMap.lookup(F); + assert(RealStub == Stub && + "Call-site that wasn't a stub passed in to EraseStub"); +#endif + FunctionToLazyStubMap.erase(F); + CallSiteToFunctionMap.erase(C2F_I); + + // Remove the stub from the function->call-sites map, and remove the whole + // entry from the map if that was the last call site. + FunctionToCallSitesMapTy::iterator F2C_I = FunctionToCallSitesMap.find(F); + assert(F2C_I != FunctionToCallSitesMap.end() && + "FunctionToCallSitesMap broken"); + bool Erased = F2C_I->second.erase(Stub); + (void)Erased; + assert(Erased && "FunctionToCallSitesMap broken"); + if (F2C_I->second.empty()) + FunctionToCallSitesMap.erase(F2C_I); + + return F; +} + +void JITResolverState::EraseAllCallSitesForPrelocked(Function *F) { + FunctionToCallSitesMapTy::iterator F2C = FunctionToCallSitesMap.find(F); + if (F2C == FunctionToCallSitesMap.end()) + return; + StubToResolverMapTy &S2RMap = *StubToResolverMap; + for (SmallPtrSet<void*, 1>::const_iterator I = F2C->second.begin(), + E = F2C->second.end(); I != E; ++I) { + S2RMap.UnregisterStubResolver(*I); + bool Erased = CallSiteToFunctionMap.erase(*I); + (void)Erased; + assert(Erased && "Missing call site->function mapping"); + } + FunctionToCallSitesMap.erase(F2C); +} + +void JITResolverState::EraseAllCallSitesPrelocked() { + StubToResolverMapTy &S2RMap = *StubToResolverMap; + for (CallSiteToFunctionMapTy::const_iterator + I = CallSiteToFunctionMap.begin(), + E = CallSiteToFunctionMap.end(); I != E; ++I) { + S2RMap.UnregisterStubResolver(I->first); + } + CallSiteToFunctionMap.clear(); + FunctionToCallSitesMap.clear(); +} + +JITResolver::~JITResolver() { + // No need to lock because we're in the destructor, and state isn't shared. + state.EraseAllCallSitesPrelocked(); + assert(!StubToResolverMap->ResolverHasStubs(this) && + "Resolver destroyed with stubs still alive."); } /// getLazyFunctionStubIfAvailable - This returns a pointer to a function stub @@ -589,20 +633,22 @@ void *JITResolver::getLazyFunctionStub(Function *F) { DEBUG(dbgs() << "JIT: Lazy stub emitted at [" << Stub << "] for function '" << F->getName() << "'\n"); - // Register this JITResolver as the one corresponding to this call site so - // JITCompilerFn will be able to find it. - StubToResolverMap->RegisterStubResolver(Stub, this); - - // Finally, keep track of the stub-to-Function mapping so that the - // JITCompilerFn knows which function to compile! - state.AddCallSite(locked, Stub, F); - - // If we are JIT'ing non-lazily but need to call a function that does not - // exist yet, add it to the JIT's work list so that we can fill in the stub - // address later. - if (!Actual && !TheJIT->isCompilingLazily()) - if (!isNonGhostDeclaration(F) && !F->hasAvailableExternallyLinkage()) - TheJIT->addPendingFunction(F); + if (TheJIT->isCompilingLazily()) { + // Register this JITResolver as the one corresponding to this call site so + // JITCompilerFn will be able to find it. + StubToResolverMap->RegisterStubResolver(Stub, this); + + // Finally, keep track of the stub-to-Function mapping so that the + // JITCompilerFn knows which function to compile! + state.AddCallSite(locked, Stub, F); + } else if (!Actual) { + // If we are JIT'ing non-lazily but need to call a function that does not + // exist yet, add it to the JIT's work list so that we can fill in the + // stub address later. + assert(!isNonGhostDeclaration(F) && !F->hasAvailableExternallyLinkage() && + "'Actual' should have been set above."); + TheJIT->addPendingFunction(F); + } return Stub; } |