diff options
author | Jeffrey Yasskin <jyasskin@google.com> | 2009-06-25 02:04:04 +0000 |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@google.com> | 2009-06-25 02:04:04 +0000 |
commit | df5a7daff9c7664bff8b713e8ed5155319bc6041 (patch) | |
tree | d0a7b2a265916b1e0e36ef6423b56749d3429c9a /lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp | |
parent | b6c29d55123f6b8c3f9e4d56e4be653a1fd2a472 (diff) |
Add a JITEventListener interface that gets called back when a new function is
emitted or the machine code for a function is freed. Chris mentioned that we
may also want a notification when a stub is emitted, but that'll be a future
change. I intend to use this to tell oprofile where functions are emitted and
what lines correspond to what addresses.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74157 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp')
-rw-r--r-- | lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp b/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp new file mode 100644 index 0000000000..3b8b84ce5b --- /dev/null +++ b/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp @@ -0,0 +1,173 @@ +//===-- 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 &) { + const char *const FnName = F.getNameStart(); + assert(FnName != 0 && 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(FnName); + 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 |