Add a JITEventListener interface that gets called back when a new function is
[oota-llvm.git] / lib / ExecutionEngine / JIT / MacOSJITEventListener.cpp
1 //===-- MacOSJITEventListener.cpp - Save symbol table for OSX perf tools --===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines a JITEventListener object that records JITted functions to
11 // a global __jitSymbolTable linked list.  Apple's performance tools use this to
12 // determine a symbol name and accurate code range for a PC value.  Because
13 // performance tools are generally asynchronous, the code below is written with
14 // the hope that it could be interrupted at any time and have useful answers.
15 // However, we don't go crazy with atomic operations, we just do a "reasonable
16 // effort".
17 //
18 //===----------------------------------------------------------------------===//
19
20 #define DEBUG_TYPE "macos-jit-event-listener"
21 #include "llvm/Function.h"
22 #include "llvm/ExecutionEngine/JITEventListener.h"
23 #include <stddef.h>
24 using namespace llvm;
25
26 #ifdef __APPLE__
27 #define ENABLE_JIT_SYMBOL_TABLE 0
28 #endif
29
30 #if ENABLE_JIT_SYMBOL_TABLE
31
32 namespace {
33
34 /// JITSymbolEntry - Each function that is JIT compiled results in one of these
35 /// being added to an array of symbols.  This indicates the name of the function
36 /// as well as the address range it occupies.  This allows the client to map
37 /// from a PC value to the name of the function.
38 struct JITSymbolEntry {
39   const char *FnName;   // FnName - a strdup'd string.
40   void *FnStart;
41   intptr_t FnSize;
42 };
43
44
45 struct JITSymbolTable {
46   /// NextPtr - This forms a linked list of JitSymbolTable entries.  This
47   /// pointer is not used right now, but might be used in the future.  Consider
48   /// it reserved for future use.
49   JITSymbolTable *NextPtr;
50   
51   /// Symbols - This is an array of JitSymbolEntry entries.  Only the first
52   /// 'NumSymbols' symbols are valid.
53   JITSymbolEntry *Symbols;
54   
55   /// NumSymbols - This indicates the number entries in the Symbols array that
56   /// are valid.
57   unsigned NumSymbols;
58   
59   /// NumAllocated - This indicates the amount of space we have in the Symbols
60   /// array.  This is a private field that should not be read by external tools.
61   unsigned NumAllocated;
62 };
63
64 class MacOSJITEventListener : public JITEventListener {
65 public:
66   virtual void NotifyFunctionEmitted(const Function &F,
67                                      void *FnStart, size_t FnSize,
68                                      const EmittedFunctionDetails &Details);
69   virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr);
70 };
71
72 }  // anonymous namespace.
73
74 // This is a public symbol so the performance tools can find it.
75 JITSymbolTable *__jitSymbolTable;
76
77 namespace llvm {
78 JITEventListener *createMacOSJITEventListener() {
79   return new MacOSJITEventListener;
80 }
81 }
82
83 // Adds the just-emitted function to the symbol table.
84 void MacOSJITEventListener::NotifyFunctionEmitted(
85     const Function &F, void *FnStart, size_t FnSize,
86     const EmittedFunctionDetails &) {
87   const char *const FnName = F.getNameStart();
88   assert(FnName != 0 && FnStart != 0 && "Bad symbol to add");
89   JITSymbolTable **SymTabPtrPtr = 0;
90   SymTabPtrPtr = &__jitSymbolTable;
91
92   // If this is the first entry in the symbol table, add the JITSymbolTable
93   // index.
94   if (*SymTabPtrPtr == 0) {
95     JITSymbolTable *New = new JITSymbolTable();
96     New->NextPtr = 0;
97     New->Symbols = 0;
98     New->NumSymbols = 0;
99     New->NumAllocated = 0;
100     *SymTabPtrPtr = New;
101   }
102
103   JITSymbolTable *SymTabPtr = *SymTabPtrPtr;
104
105   // If we have space in the table, reallocate the table.
106   if (SymTabPtr->NumSymbols >= SymTabPtr->NumAllocated) {
107     // If we don't have space, reallocate the table.
108     unsigned NewSize = std::max(64U, SymTabPtr->NumAllocated*2);
109     JITSymbolEntry *NewSymbols = new JITSymbolEntry[NewSize];
110     JITSymbolEntry *OldSymbols = SymTabPtr->Symbols;
111
112     // Copy the old entries over.
113     memcpy(NewSymbols, OldSymbols, SymTabPtr->NumSymbols*sizeof(OldSymbols[0]));
114
115     // Swap the new symbols in, delete the old ones.
116     SymTabPtr->Symbols = NewSymbols;
117     SymTabPtr->NumAllocated = NewSize;
118     delete [] OldSymbols;
119   }
120
121   // Otherwise, we have enough space, just tack it onto the end of the array.
122   JITSymbolEntry &Entry = SymTabPtr->Symbols[SymTabPtr->NumSymbols];
123   Entry.FnName = strdup(FnName);
124   Entry.FnStart = FnStart;
125   Entry.FnSize = FnSize;
126   ++SymTabPtr->NumSymbols;
127 }
128
129 // Removes the to-be-deleted function from the symbol table.
130 void MacOSJITEventListener::NotifyFreeingMachineCode(
131     const Function &, void *FnStart) {
132   assert(FnStart && "Invalid function pointer");
133   JITSymbolTable **SymTabPtrPtr = 0;
134   SymTabPtrPtr = &__jitSymbolTable;
135
136   JITSymbolTable *SymTabPtr = *SymTabPtrPtr;
137   JITSymbolEntry *Symbols = SymTabPtr->Symbols;
138
139   // Scan the table to find its index.  The table is not sorted, so do a linear
140   // scan.
141   unsigned Index;
142   for (Index = 0; Symbols[Index].FnStart != FnStart; ++Index)
143     assert(Index != SymTabPtr->NumSymbols && "Didn't find function!");
144
145   // Once we have an index, we know to nuke this entry, overwrite it with the
146   // entry at the end of the array, making the last entry redundant.
147   const char *OldName = Symbols[Index].FnName;
148   Symbols[Index] = Symbols[SymTabPtr->NumSymbols-1];
149   free((void*)OldName);
150
151   // Drop the number of symbols in the table.
152   --SymTabPtr->NumSymbols;
153
154   // Finally, if we deleted the final symbol, deallocate the table itself.
155   if (SymTabPtr->NumSymbols != 0)
156     return;
157
158   *SymTabPtrPtr = 0;
159   delete [] Symbols;
160   delete SymTabPtr;
161 }
162
163 #else  // !ENABLE_JIT_SYMBOL_TABLE
164
165 namespace llvm {
166 // By defining this to return NULL, we can let clients call it unconditionally,
167 // even if they aren't on an Apple system.
168 JITEventListener *createMacOSJITEventListener() {
169   return NULL;
170 }
171 }  // namespace llvm
172
173 #endif  // ENABLE_JIT_SYMBOL_TABLE