blob: 3b8b84ce5bcb22d5f57b8393fc50aee4c44c5f29 [file] [log] [blame]
Jeffrey Yasskindf5a7da2009-06-25 02:04:04 +00001//===-- 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>
24using namespace llvm;
25
26#ifdef __APPLE__
27#define ENABLE_JIT_SYMBOL_TABLE 0
28#endif
29
30#if ENABLE_JIT_SYMBOL_TABLE
31
32namespace {
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.
38struct JITSymbolEntry {
39 const char *FnName; // FnName - a strdup'd string.
40 void *FnStart;
41 intptr_t FnSize;
42};
43
44
45struct 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
64class MacOSJITEventListener : public JITEventListener {
65public:
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.
75JITSymbolTable *__jitSymbolTable;
76
77namespace llvm {
78JITEventListener *createMacOSJITEventListener() {
79 return new MacOSJITEventListener;
80}
81}
82
83// Adds the just-emitted function to the symbol table.
84void 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.
130void 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
165namespace 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.
168JITEventListener *createMacOSJITEventListener() {
169 return NULL;
170}
171} // namespace llvm
172
173#endif // ENABLE_JIT_SYMBOL_TABLE