diff options
Diffstat (limited to 'lib/ExecutionEngine/JIT')
-rw-r--r-- | lib/ExecutionEngine/JIT/JIT.cpp | 10 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JIT.h | 7 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITDebugRegisterer.h | 2 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITEmitter.cpp | 111 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp | 172 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp | 12 |
6 files changed, 99 insertions, 215 deletions
diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index b2a268b..e21d760 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -556,10 +556,10 @@ void JIT::NotifyFunctionEmitted( } } -void JIT::NotifyFreeingMachineCode(const Function &F, void *OldPtr) { +void JIT::NotifyFreeingMachineCode(void *OldPtr) { MutexGuard locked(lock); for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { - EventListeners[I]->NotifyFreeingMachineCode(F, OldPtr); + EventListeners[I]->NotifyFreeingMachineCode(OldPtr); } } @@ -599,7 +599,7 @@ void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) { isAlreadyCodeGenerating = false; // If the function referred to another function that had not yet been - // read from bitcode, but we are jitting non-lazily, emit it now. + // read from bitcode, and we are jitting non-lazily, emit it now. while (!jitstate->getPendingFunctions(locked).empty()) { Function *PF = jitstate->getPendingFunctions(locked).back(); jitstate->getPendingFunctions(locked).pop_back(); @@ -616,7 +616,7 @@ void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) { // If the JIT is configured to emit info so that dlsym can be used to // rewrite stubs to external globals, do so now. - if (areDlsymStubsEnabled() && isLazyCompilationDisabled()) + if (areDlsymStubsEnabled() && !isCompilingLazily()) updateDlsymStubTable(); } @@ -659,7 +659,7 @@ void *JIT::getPointerToFunction(Function *F) { return Addr; } - if (F->isDeclaration()) { + if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) { bool AbortOnFailure = !areDlsymStubsEnabled() && !F->hasExternalWeakLinkage(); void *Addr = getPointerToNamedFunction(F->getName(), AbortOnFailure); diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h index 525cc84..fb3cb24 100644 --- a/lib/ExecutionEngine/JIT/JIT.h +++ b/lib/ExecutionEngine/JIT/JIT.h @@ -128,6 +128,11 @@ public: /// void *getPointerToFunction(Function *F); + void *getPointerToBasicBlock(BasicBlock *BB) { + assert(0 && "JIT does not support address-of-label yet!"); + return 0; + } + /// getOrEmitGlobalVariable - Return the address of the specified global /// variable, possibly emitting it to memory if needed. This is used by the /// Emitter. @@ -183,7 +188,7 @@ public: void NotifyFunctionEmitted( const Function &F, void *Code, size_t Size, const JITEvent_EmittedFunctionDetails &Details); - void NotifyFreeingMachineCode(const Function &F, void *OldPtr); + void NotifyFreeingMachineCode(void *OldPtr); private: static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM, diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h index dce506b..7e53d78 100644 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h +++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h @@ -16,7 +16,7 @@ #define LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H #include "llvm/ADT/DenseMap.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <string> // This must be kept in sync with gdb/gdb/jit.h . diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 073d6fb..79f1eb4 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -46,6 +46,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/ValueMap.h" #include <algorithm> #ifndef NDEBUG #include <iomanip> @@ -62,12 +63,29 @@ static JIT *TheJIT = 0; // JIT lazy compilation code. // namespace { + class JITResolverState; + + template<typename ValueTy> + struct NoRAUWValueMapConfig : public ValueMapConfig<ValueTy> { + typedef JITResolverState *ExtraData; + static void onRAUW(JITResolverState *, Value *Old, Value *New) { + assert(false && "The JIT doesn't know how to handle a" + " RAUW on a value it has emitted."); + } + }; + + struct CallSiteValueMapConfig : public NoRAUWValueMapConfig<Function*> { + typedef JITResolverState *ExtraData; + static void onDelete(JITResolverState *JRS, Function *F); + }; + class JITResolverState { public: - typedef DenseMap<AssertingVH<Function>, void*> FunctionToStubMapTy; + typedef ValueMap<Function*, void*, NoRAUWValueMapConfig<Function*> > + FunctionToStubMapTy; typedef std::map<void*, AssertingVH<Function> > CallSiteToFunctionMapTy; - typedef DenseMap<AssertingVH<Function>, SmallPtrSet<void*, 1> > - FunctionToCallSitesMapTy; + typedef ValueMap<Function *, SmallPtrSet<void*, 1>, + CallSiteValueMapConfig> FunctionToCallSitesMapTy; typedef std::map<AssertingVH<GlobalValue>, void*> GlobalToIndirectSymMapTy; private: /// FunctionToStubMap - Keep track of the stub created for a particular @@ -84,6 +102,9 @@ namespace { GlobalToIndirectSymMapTy GlobalToIndirectSymMap; public: + JITResolverState() : FunctionToStubMap(this), + FunctionToCallSitesMap(this) {} + FunctionToStubMapTy& getFunctionToStubMap(const MutexGuard& locked) { assert(locked.holds(TheJIT->lock)); return FunctionToStubMap; @@ -111,8 +132,10 @@ namespace { void AddCallSite(const MutexGuard &locked, void *CallSite, Function *F) { assert(locked.holds(TheJIT->lock)); - assert(CallSiteToFunctionMap.insert(std::make_pair(CallSite, F)).second && - "Pair was already in CallSiteToFunctionMap"); + bool Inserted = CallSiteToFunctionMap.insert( + std::make_pair(CallSite, F)).second; + (void)Inserted; + assert(Inserted && "Pair was already in CallSiteToFunctionMap"); FunctionToCallSitesMap[F].insert(CallSite); } @@ -142,8 +165,9 @@ namespace { FunctionToCallSitesMapTy::iterator F2C_I = FunctionToCallSitesMap.find(F); assert(F2C_I != FunctionToCallSitesMap.end() && "FunctionToCallSitesMap broken"); - assert(F2C_I->second.erase(Stub) && - "FunctionToCallSitesMap broken"); + bool Erased = F2C_I->second.erase(Stub); + (void)Erased; + assert(Erased && "FunctionToCallSitesMap broken"); if (F2C_I->second.empty()) FunctionToCallSitesMap.erase(F2C_I); @@ -152,13 +176,17 @@ namespace { void EraseAllCallSites(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) { - assert(CallSiteToFunctionMap.erase(*I) == 1 && - "Missing call site->function mapping"); + bool Erased = CallSiteToFunctionMap.erase(*I); + (void)Erased; + assert(Erased && "Missing call site->function mapping"); } FunctionToCallSitesMap.erase(F2C); } @@ -245,6 +273,10 @@ namespace { JITResolver *JITResolver::TheJITResolver = 0; +void CallSiteValueMapConfig::onDelete(JITResolverState *JRS, Function *F) { + JRS->EraseAllCallSitesPrelocked(F); +} + /// getFunctionStubIfAvailable - This returns a pointer to a function stub /// if it has already been created. void *JITResolver::getFunctionStubIfAvailable(Function *F) { @@ -263,11 +295,11 @@ void *JITResolver::getFunctionStub(Function *F) { void *&Stub = state.getFunctionToStubMap(locked)[F]; if (Stub) return Stub; - // Call the lazy resolver function unless we are JIT'ing non-lazily, in which - // case we must resolve the symbol now. - void *Actual = TheJIT->isLazyCompilationDisabled() - ? (void *)0 : (void *)(intptr_t)LazyResolverFn; - + // Call the lazy resolver function if we are JIT'ing lazily. Otherwise we + // must resolve the symbol now. + void *Actual = TheJIT->isCompilingLazily() + ? (void *)(intptr_t)LazyResolverFn : (void *)0; + // If this is an external declaration, attempt to resolve the address now // to place in the stub. if (F->isDeclaration() && !F->hasNotBeenReadFromBitcode()) { @@ -302,7 +334,7 @@ void *JITResolver::getFunctionStub(Function *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->isLazyCompilationDisabled()) + if (!Actual && !TheJIT->isCompilingLazily()) if (!F->isDeclaration() || F->hasNotBeenReadFromBitcode()) TheJIT->addPendingFunction(F); @@ -439,7 +471,7 @@ void *JITResolver::JITCompilerFn(void *Stub) { // Otherwise we don't have it, do lazy compilation now. // If lazy compilation is disabled, emit a useful error message and abort. - if (TheJIT->isLazyCompilationDisabled()) { + if (!TheJIT->isCompilingLazily()) { llvm_report_error("LLVM JIT requested to do lazy compilation of function '" + F->getName() + "' when lazy compiles are disabled!"); } @@ -550,17 +582,24 @@ namespace { JITEvent_EmittedFunctionDetails EmissionDetails; struct EmittedCode { - void *FunctionBody; + void *FunctionBody; // Beginning of the function's allocation. + void *Code; // The address the function's code actually starts at. void *ExceptionTable; - EmittedCode() : FunctionBody(0), ExceptionTable(0) {} + EmittedCode() : FunctionBody(0), Code(0), ExceptionTable(0) {} + }; + struct EmittedFunctionConfig : public ValueMapConfig<const Function*> { + typedef JITEmitter *ExtraData; + static void onDelete(JITEmitter *, const Function*); + static void onRAUW(JITEmitter *, const Function*, const Function*); }; - DenseMap<const Function *, EmittedCode> EmittedFunctions; + ValueMap<const Function *, EmittedCode, + EmittedFunctionConfig> EmittedFunctions; // CurFnStubUses - For a given Function, a vector of stubs that it // references. This facilitates the JIT detecting that a stub is no // longer used, so that it may be deallocated. - DenseMap<const Function *, SmallVector<void*, 1> > CurFnStubUses; - + DenseMap<AssertingVH<const Function>, SmallVector<void*, 1> > CurFnStubUses; + // StubFnRefs - For a given pointer to a stub, a set of Functions which // reference the stub. When the count of a stub's references drops to zero, // the stub is unused. @@ -574,7 +613,8 @@ namespace { public: JITEmitter(JIT &jit, JITMemoryManager *JMM, TargetMachine &TM) - : SizeEstimate(0), Resolver(jit), MMI(0), CurFn(0) { + : SizeEstimate(0), Resolver(jit), MMI(0), CurFn(0), + EmittedFunctions(this) { MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager(); if (jit.getJITInfo().needsGOT()) { MemMgr->AllocateGOT(); @@ -729,7 +769,7 @@ void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference, // mechanism is capable of rewriting the instruction directly, prefer to do // that instead of emitting a stub. This uses the lazy resolver, so is not // legal if lazy compilation is disabled. - if (DoesntNeedStub && !TheJIT->isLazyCompilationDisabled()) + if (DoesntNeedStub && TheJIT->isCompilingLazily()) return Resolver.AddCallbackAtLocation(F, Reference); // Otherwise, we have to emit a stub. @@ -1030,6 +1070,7 @@ void JITEmitter::startFunction(MachineFunction &F) { // About to start emitting the machine code for the function. emitAlignment(std::max(F.getFunction()->getAlignment(), 8U)); TheJIT->updateGlobalMapping(F.getFunction(), CurBufferPtr); + EmittedFunctions[F.getFunction()].Code = CurBufferPtr; MBBLocations.clear(); @@ -1253,12 +1294,15 @@ void JITEmitter::retryWithMoreMemory(MachineFunction &F) { /// deallocateMemForFunction - Deallocate all memory for the specified /// function body. Also drop any references the function has to stubs. +/// May be called while the Function is being destroyed inside ~Value(). void JITEmitter::deallocateMemForFunction(const Function *F) { - DenseMap<const Function *, EmittedCode>::iterator Emitted = - EmittedFunctions.find(F); + ValueMap<const Function *, EmittedCode, EmittedFunctionConfig>::iterator + Emitted = EmittedFunctions.find(F); if (Emitted != EmittedFunctions.end()) { MemMgr->deallocateFunctionBody(Emitted->second.FunctionBody); MemMgr->deallocateExceptionTable(Emitted->second.ExceptionTable); + TheJIT->NotifyFreeingMachineCode(Emitted->second.Code); + EmittedFunctions.erase(Emitted); } @@ -1487,6 +1531,17 @@ uintptr_t JITEmitter::getJumpTableEntryAddress(unsigned Index) const { return (uintptr_t)((char *)JumpTableBase + Offset); } +void JITEmitter::EmittedFunctionConfig::onDelete( + JITEmitter *Emitter, const Function *F) { + Emitter->deallocateMemForFunction(F); +} +void JITEmitter::EmittedFunctionConfig::onRAUW( + JITEmitter *, const Function*, const Function*) { + llvm_unreachable("The JIT doesn't know how to handle a" + " RAUW on a value it has emitted."); +} + + //===----------------------------------------------------------------------===// // Public interface to this file //===----------------------------------------------------------------------===// @@ -1625,13 +1680,9 @@ void JIT::updateDlsymStubTable() { /// freeMachineCodeForFunction - release machine code memory for given Function. /// void JIT::freeMachineCodeForFunction(Function *F) { - // Delete translation for this from the ExecutionEngine, so it will get // retranslated next time it is used. - void *OldPtr = updateGlobalMapping(F, 0); - - if (OldPtr) - TheJIT->NotifyFreeingMachineCode(*F, OldPtr); + updateGlobalMapping(F, 0); // Free the actual memory for the function body and related stuff. assert(isa<JITEmitter>(JCE) && "Unexpected MCE?"); diff --git a/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp b/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp deleted file mode 100644 index 53585b8..0000000 --- a/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp +++ /dev/null @@ -1,172 +0,0 @@ -//===-- MacOSJITEventListener.cpp - Save symbol table for OSX perf tools --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a JITEventListener object that records JITted functions to -// a global __jitSymbolTable linked list. Apple's performance tools use this to -// determine a symbol name and accurate code range for a PC value. Because -// performance tools are generally asynchronous, the code below is written with -// the hope that it could be interrupted at any time and have useful answers. -// However, we don't go crazy with atomic operations, we just do a "reasonable -// effort". -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "macos-jit-event-listener" -#include "llvm/Function.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include <stddef.h> -using namespace llvm; - -#ifdef __APPLE__ -#define ENABLE_JIT_SYMBOL_TABLE 0 -#endif - -#if ENABLE_JIT_SYMBOL_TABLE - -namespace { - -/// JITSymbolEntry - Each function that is JIT compiled results in one of these -/// being added to an array of symbols. This indicates the name of the function -/// as well as the address range it occupies. This allows the client to map -/// from a PC value to the name of the function. -struct JITSymbolEntry { - const char *FnName; // FnName - a strdup'd string. - void *FnStart; - intptr_t FnSize; -}; - - -struct JITSymbolTable { - /// NextPtr - This forms a linked list of JitSymbolTable entries. This - /// pointer is not used right now, but might be used in the future. Consider - /// it reserved for future use. - JITSymbolTable *NextPtr; - - /// Symbols - This is an array of JitSymbolEntry entries. Only the first - /// 'NumSymbols' symbols are valid. - JITSymbolEntry *Symbols; - - /// NumSymbols - This indicates the number entries in the Symbols array that - /// are valid. - unsigned NumSymbols; - - /// NumAllocated - This indicates the amount of space we have in the Symbols - /// array. This is a private field that should not be read by external tools. - unsigned NumAllocated; -}; - -class MacOSJITEventListener : public JITEventListener { -public: - virtual void NotifyFunctionEmitted(const Function &F, - void *FnStart, size_t FnSize, - const EmittedFunctionDetails &Details); - virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr); -}; - -} // anonymous namespace. - -// This is a public symbol so the performance tools can find it. -JITSymbolTable *__jitSymbolTable; - -namespace llvm { -JITEventListener *createMacOSJITEventListener() { - return new MacOSJITEventListener; -} -} - -// Adds the just-emitted function to the symbol table. -void MacOSJITEventListener::NotifyFunctionEmitted( - const Function &F, void *FnStart, size_t FnSize, - const EmittedFunctionDetails &) { - assert(F.hasName() && FnStart != 0 && "Bad symbol to add"); - JITSymbolTable **SymTabPtrPtr = 0; - SymTabPtrPtr = &__jitSymbolTable; - - // If this is the first entry in the symbol table, add the JITSymbolTable - // index. - if (*SymTabPtrPtr == 0) { - JITSymbolTable *New = new JITSymbolTable(); - New->NextPtr = 0; - New->Symbols = 0; - New->NumSymbols = 0; - New->NumAllocated = 0; - *SymTabPtrPtr = New; - } - - JITSymbolTable *SymTabPtr = *SymTabPtrPtr; - - // If we have space in the table, reallocate the table. - if (SymTabPtr->NumSymbols >= SymTabPtr->NumAllocated) { - // If we don't have space, reallocate the table. - unsigned NewSize = std::max(64U, SymTabPtr->NumAllocated*2); - JITSymbolEntry *NewSymbols = new JITSymbolEntry[NewSize]; - JITSymbolEntry *OldSymbols = SymTabPtr->Symbols; - - // Copy the old entries over. - memcpy(NewSymbols, OldSymbols, SymTabPtr->NumSymbols*sizeof(OldSymbols[0])); - - // Swap the new symbols in, delete the old ones. - SymTabPtr->Symbols = NewSymbols; - SymTabPtr->NumAllocated = NewSize; - delete [] OldSymbols; - } - - // Otherwise, we have enough space, just tack it onto the end of the array. - JITSymbolEntry &Entry = SymTabPtr->Symbols[SymTabPtr->NumSymbols]; - Entry.FnName = strdup(F.getName().data()); - Entry.FnStart = FnStart; - Entry.FnSize = FnSize; - ++SymTabPtr->NumSymbols; -} - -// Removes the to-be-deleted function from the symbol table. -void MacOSJITEventListener::NotifyFreeingMachineCode( - const Function &, void *FnStart) { - assert(FnStart && "Invalid function pointer"); - JITSymbolTable **SymTabPtrPtr = 0; - SymTabPtrPtr = &__jitSymbolTable; - - JITSymbolTable *SymTabPtr = *SymTabPtrPtr; - JITSymbolEntry *Symbols = SymTabPtr->Symbols; - - // Scan the table to find its index. The table is not sorted, so do a linear - // scan. - unsigned Index; - for (Index = 0; Symbols[Index].FnStart != FnStart; ++Index) - assert(Index != SymTabPtr->NumSymbols && "Didn't find function!"); - - // Once we have an index, we know to nuke this entry, overwrite it with the - // entry at the end of the array, making the last entry redundant. - const char *OldName = Symbols[Index].FnName; - Symbols[Index] = Symbols[SymTabPtr->NumSymbols-1]; - free((void*)OldName); - - // Drop the number of symbols in the table. - --SymTabPtr->NumSymbols; - - // Finally, if we deleted the final symbol, deallocate the table itself. - if (SymTabPtr->NumSymbols != 0) - return; - - *SymTabPtrPtr = 0; - delete [] Symbols; - delete SymTabPtr; -} - -#else // !ENABLE_JIT_SYMBOL_TABLE - -namespace llvm { -// By defining this to return NULL, we can let clients call it unconditionally, -// even if they aren't on an Apple system. -JITEventListener *createMacOSJITEventListener() { - return NULL; -} -} // namespace llvm - -#endif // ENABLE_JIT_SYMBOL_TABLE diff --git a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp index 00c4af7..b45c71f 100644 --- a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp +++ b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp @@ -43,7 +43,7 @@ public: virtual void NotifyFunctionEmitted(const Function &F, void *FnStart, size_t FnSize, const EmittedFunctionDetails &Details); - virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr); + virtual void NotifyFreeingMachineCode(void *OldPtr); }; OProfileJITEventListener::OProfileJITEventListener() @@ -147,13 +147,13 @@ void OProfileJITEventListener::NotifyFunctionEmitted( } } -// Removes the to-be-deleted function from the symbol table. -void OProfileJITEventListener::NotifyFreeingMachineCode( - const Function &F, void *FnStart) { +// Removes the being-deleted function from the symbol table. +void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) { assert(FnStart && "Invalid function pointer"); if (op_unload_native_code(Agent, reinterpret_cast<uint64_t>(FnStart)) == -1) { - DEBUG(errs() << "Failed to tell OProfile about unload of native function " - << F.getName() << " at " << FnStart << "\n"); + DEBUG(errs() + << "Failed to tell OProfile about unload of native function at " + << FnStart << "\n"); } } |