1 //===-- MacOSJITEventListener.cpp - Save symbol table for OSX perf tools --===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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
18 //===----------------------------------------------------------------------===//
20 #define DEBUG_TYPE "macos-jit-event-listener"
21 #include "llvm/Function.h"
22 #include "llvm/ExecutionEngine/JITEventListener.h"
27 #define ENABLE_JIT_SYMBOL_TABLE 0
30 #if ENABLE_JIT_SYMBOL_TABLE
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.
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
;
51 /// Symbols - This is an array of JitSymbolEntry entries. Only the first
52 /// 'NumSymbols' symbols are valid.
53 JITSymbolEntry
*Symbols
;
55 /// NumSymbols - This indicates the number entries in the Symbols array that
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
;
64 class MacOSJITEventListener
: public JITEventListener
{
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
);
72 } // anonymous namespace.
74 // This is a public symbol so the performance tools can find it.
75 JITSymbolTable
*__jitSymbolTable
;
78 JITEventListener
*createMacOSJITEventListener() {
79 return new MacOSJITEventListener
;
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 assert(F
.hasName() && FnStart
!= 0 && "Bad symbol to add");
88 JITSymbolTable
**SymTabPtrPtr
= 0;
89 SymTabPtrPtr
= &__jitSymbolTable
;
91 // If this is the first entry in the symbol table, add the JITSymbolTable
93 if (*SymTabPtrPtr
== 0) {
94 JITSymbolTable
*New
= new JITSymbolTable();
98 New
->NumAllocated
= 0;
102 JITSymbolTable
*SymTabPtr
= *SymTabPtrPtr
;
104 // If we have space in the table, reallocate the table.
105 if (SymTabPtr
->NumSymbols
>= SymTabPtr
->NumAllocated
) {
106 // If we don't have space, reallocate the table.
107 unsigned NewSize
= std::max(64U, SymTabPtr
->NumAllocated
*2);
108 JITSymbolEntry
*NewSymbols
= new JITSymbolEntry
[NewSize
];
109 JITSymbolEntry
*OldSymbols
= SymTabPtr
->Symbols
;
111 // Copy the old entries over.
112 memcpy(NewSymbols
, OldSymbols
, SymTabPtr
->NumSymbols
*sizeof(OldSymbols
[0]));
114 // Swap the new symbols in, delete the old ones.
115 SymTabPtr
->Symbols
= NewSymbols
;
116 SymTabPtr
->NumAllocated
= NewSize
;
117 delete [] OldSymbols
;
120 // Otherwise, we have enough space, just tack it onto the end of the array.
121 JITSymbolEntry
&Entry
= SymTabPtr
->Symbols
[SymTabPtr
->NumSymbols
];
122 Entry
.FnName
= strdup(F
.getName().data());
123 Entry
.FnStart
= FnStart
;
124 Entry
.FnSize
= FnSize
;
125 ++SymTabPtr
->NumSymbols
;
128 // Removes the to-be-deleted function from the symbol table.
129 void MacOSJITEventListener::NotifyFreeingMachineCode(
130 const Function
&, void *FnStart
) {
131 assert(FnStart
&& "Invalid function pointer");
132 JITSymbolTable
**SymTabPtrPtr
= 0;
133 SymTabPtrPtr
= &__jitSymbolTable
;
135 JITSymbolTable
*SymTabPtr
= *SymTabPtrPtr
;
136 JITSymbolEntry
*Symbols
= SymTabPtr
->Symbols
;
138 // Scan the table to find its index. The table is not sorted, so do a linear
141 for (Index
= 0; Symbols
[Index
].FnStart
!= FnStart
; ++Index
)
142 assert(Index
!= SymTabPtr
->NumSymbols
&& "Didn't find function!");
144 // Once we have an index, we know to nuke this entry, overwrite it with the
145 // entry at the end of the array, making the last entry redundant.
146 const char *OldName
= Symbols
[Index
].FnName
;
147 Symbols
[Index
] = Symbols
[SymTabPtr
->NumSymbols
-1];
148 free((void*)OldName
);
150 // Drop the number of symbols in the table.
151 --SymTabPtr
->NumSymbols
;
153 // Finally, if we deleted the final symbol, deallocate the table itself.
154 if (SymTabPtr
->NumSymbols
!= 0)
162 #else // !ENABLE_JIT_SYMBOL_TABLE
165 // By defining this to return NULL, we can let clients call it unconditionally,
166 // even if they aren't on an Apple system.
167 JITEventListener
*createMacOSJITEventListener() {
172 #endif // ENABLE_JIT_SYMBOL_TABLE