summaryrefslogtreecommitdiffstats
path: root/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp
blob: 53585b877b19a9dedf4cfee6dd33a2b7337d8c4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//===-- 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
OpenPOWER on IntegriCloud