Replace OwningPtr<T> with std::unique_ptr<T>.
[oota-llvm.git] / lib / ExecutionEngine / IntelJITEvents / IntelJITEventListener.cpp
1 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
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 to tell Intel(R) VTune(TM)
11 // Amplifier XE 2011 about JITted functions.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/Config/config.h"
16 #include "llvm/ExecutionEngine/JITEventListener.h"
17
18 #define DEBUG_TYPE "amplifier-jit-event-listener"
19 #include "llvm/IR/DebugInfo.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/IR/Metadata.h"
22 #include "llvm/ADT/DenseMap.h"
23 #include "llvm/CodeGen/MachineFunction.h"
24 #include "llvm/DebugInfo/DIContext.h"
25 #include "llvm/ExecutionEngine/ObjectImage.h"
26 #include "llvm/Object/ObjectFile.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include "llvm/Support/Errno.h"
30 #include "llvm/IR/ValueHandle.h"
31 #include "EventListenerCommon.h"
32 #include "IntelJITEventsWrapper.h"
33
34 using namespace llvm;
35 using namespace llvm::jitprofiling;
36
37 namespace {
38
39 class IntelJITEventListener : public JITEventListener {
40   typedef DenseMap<void*, unsigned int> MethodIDMap;
41
42   std::unique_ptr<IntelJITEventsWrapper> Wrapper;
43   MethodIDMap MethodIDs;
44   FilenameCache Filenames;
45
46   typedef SmallVector<const void *, 64> MethodAddressVector;
47   typedef DenseMap<const void *, MethodAddressVector>  ObjectMap;
48
49   ObjectMap  LoadedObjectMap;
50
51 public:
52   IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
53       Wrapper.reset(libraryWrapper);
54   }
55
56   ~IntelJITEventListener() {
57   }
58
59   virtual void NotifyFunctionEmitted(const Function &F,
60                                      void *FnStart, size_t FnSize,
61                                      const EmittedFunctionDetails &Details);
62
63   virtual void NotifyFreeingMachineCode(void *OldPtr);
64
65   virtual void NotifyObjectEmitted(const ObjectImage &Obj);
66
67   virtual void NotifyFreeingObject(const ObjectImage &Obj);
68 };
69
70 static LineNumberInfo LineStartToIntelJITFormat(
71     uintptr_t StartAddress,
72     uintptr_t Address,
73     DebugLoc Loc) {
74   LineNumberInfo Result;
75
76   Result.Offset = Address - StartAddress;
77   Result.LineNumber = Loc.getLine();
78
79   return Result;
80 }
81
82 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
83                                                  uintptr_t Address,
84                                                  DILineInfo Line) {
85   LineNumberInfo Result;
86
87   Result.Offset = Address - StartAddress;
88   Result.LineNumber = Line.getLine();
89
90   return Result;
91 }
92
93 static iJIT_Method_Load FunctionDescToIntelJITFormat(
94     IntelJITEventsWrapper& Wrapper,
95     const char* FnName,
96     uintptr_t FnStart,
97     size_t FnSize) {
98   iJIT_Method_Load Result;
99   memset(&Result, 0, sizeof(iJIT_Method_Load));
100
101   Result.method_id = Wrapper.iJIT_GetNewMethodID();
102   Result.method_name = const_cast<char*>(FnName);
103   Result.method_load_address = reinterpret_cast<void*>(FnStart);
104   Result.method_size = FnSize;
105
106   Result.class_id = 0;
107   Result.class_file_name = NULL;
108   Result.user_data = NULL;
109   Result.user_data_size = 0;
110   Result.env = iJDE_JittingAPI;
111
112   return Result;
113 }
114
115 // Adds the just-emitted function to the symbol table.
116 void IntelJITEventListener::NotifyFunctionEmitted(
117     const Function &F, void *FnStart, size_t FnSize,
118     const EmittedFunctionDetails &Details) {
119   iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
120                                       F.getName().data(),
121                                       reinterpret_cast<uint64_t>(FnStart),
122                                       FnSize);
123
124   std::vector<LineNumberInfo> LineInfo;
125
126   if (!Details.LineStarts.empty()) {
127     // Now convert the line number information from the address/DebugLoc
128     // format in Details to the offset/lineno in Intel JIT API format.
129
130     LineInfo.reserve(Details.LineStarts.size() + 1);
131
132     DebugLoc FirstLoc = Details.LineStarts[0].Loc;
133     assert(!FirstLoc.isUnknown()
134            && "LineStarts should not contain unknown DebugLocs");
135
136     MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
137     DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
138     if (FunctionDI.Verify()) {
139       FunctionMessage.source_file_name = const_cast<char*>(
140                                           Filenames.getFullPath(FirstLocScope));
141
142       LineNumberInfo FirstLine;
143       FirstLine.Offset = 0;
144       FirstLine.LineNumber = FunctionDI.getLineNumber();
145       LineInfo.push_back(FirstLine);
146     }
147
148     for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
149           Details.LineStarts.begin(), E = Details.LineStarts.end();
150           I != E; ++I) {
151       // This implementation ignores the DebugLoc filename because the Intel
152       // JIT API does not support multiple source files associated with a single
153       // JIT function
154       LineInfo.push_back(LineStartToIntelJITFormat(
155                           reinterpret_cast<uintptr_t>(FnStart),
156                           I->Address,
157                           I->Loc));
158
159       // If we have no file name yet for the function, use the filename from
160       // the first instruction that has one
161       if (FunctionMessage.source_file_name == 0) {
162         MDNode *scope = I->Loc.getScope(
163           Details.MF->getFunction()->getContext());
164         FunctionMessage.source_file_name = const_cast<char*>(
165                                                   Filenames.getFullPath(scope));
166       }
167     }
168
169     FunctionMessage.line_number_size = LineInfo.size();
170     FunctionMessage.line_number_table = &*LineInfo.begin();
171   } else {
172     FunctionMessage.line_number_size = 0;
173     FunctionMessage.line_number_table = 0;
174   }
175
176   Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
177                             &FunctionMessage);
178   MethodIDs[FnStart] = FunctionMessage.method_id;
179 }
180
181 void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
182   MethodIDMap::iterator I = MethodIDs.find(FnStart);
183   if (I != MethodIDs.end()) {
184     Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second);
185     MethodIDs.erase(I);
186   }
187 }
188
189 void IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
190   // Get the address of the object image for use as a unique identifier
191   const void* ObjData = Obj.getData().data();
192   DIContext* Context = DIContext::getDWARFContext(Obj.getObjectFile());
193   MethodAddressVector Functions;
194
195   // Use symbol info to iterate functions in the object.
196   error_code ec;
197   for (object::symbol_iterator I = Obj.begin_symbols(),
198                                E = Obj.end_symbols();
199                         I != E && !ec;
200                         I.increment(ec)) {
201     std::vector<LineNumberInfo> LineInfo;
202     std::string SourceFileName;
203
204     object::SymbolRef::Type SymType;
205     if (I->getType(SymType)) continue;
206     if (SymType == object::SymbolRef::ST_Function) {
207       StringRef  Name;
208       uint64_t   Addr;
209       uint64_t   Size;
210       if (I->getName(Name)) continue;
211       if (I->getAddress(Addr)) continue;
212       if (I->getSize(Size)) continue;
213
214       // Record this address in a local vector
215       Functions.push_back((void*)Addr);
216
217       // Build the function loaded notification message
218       iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
219                                            Name.data(),
220                                            Addr,
221                                            Size);
222       if (Context) {
223         DILineInfoTable  Lines = Context->getLineInfoForAddressRange(Addr, Size);
224         DILineInfoTable::iterator  Begin = Lines.begin();
225         DILineInfoTable::iterator  End = Lines.end();
226         for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
227           LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr,
228                                                         It->first,
229                                                         It->second));
230         }
231         if (LineInfo.size() == 0) {
232           FunctionMessage.source_file_name = 0;
233           FunctionMessage.line_number_size = 0;
234           FunctionMessage.line_number_table = 0;
235         } else {
236           SourceFileName = Lines.front().second.getFileName();
237           FunctionMessage.source_file_name = (char *)SourceFileName.c_str();
238           FunctionMessage.line_number_size = LineInfo.size();
239           FunctionMessage.line_number_table = &*LineInfo.begin();
240         }
241       } else {
242         FunctionMessage.source_file_name = 0;
243         FunctionMessage.line_number_size = 0;
244         FunctionMessage.line_number_table = 0;
245       }
246
247       Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
248                                 &FunctionMessage);
249       MethodIDs[(void*)Addr] = FunctionMessage.method_id;
250     }
251   }
252
253   // To support object unload notification, we need to keep a list of
254   // registered function addresses for each loaded object.  We will
255   // use the MethodIDs map to get the registered ID for each function.
256   LoadedObjectMap[ObjData] = Functions;
257 }
258
259 void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
260   // Get the address of the object image for use as a unique identifier
261   const void* ObjData = Obj.getData().data();
262
263   // Get the object's function list from LoadedObjectMap
264   ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
265   if (OI == LoadedObjectMap.end())
266     return;
267   MethodAddressVector& Functions = OI->second;
268
269   // Walk the function list, unregistering each function
270   for (MethodAddressVector::iterator FI = Functions.begin(),
271                                      FE = Functions.end();
272        FI != FE;
273        ++FI) {
274     void* FnStart = const_cast<void*>(*FI);
275     MethodIDMap::iterator MI = MethodIDs.find(FnStart);
276     if (MI != MethodIDs.end()) {
277       Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
278                                 &MI->second);
279       MethodIDs.erase(MI);
280     }
281   }
282
283   // Erase the object from LoadedObjectMap
284   LoadedObjectMap.erase(OI);
285 }
286
287 }  // anonymous namespace.
288
289 namespace llvm {
290 JITEventListener *JITEventListener::createIntelJITEventListener() {
291   return new IntelJITEventListener(new IntelJITEventsWrapper);
292 }
293
294 // for testing
295 JITEventListener *JITEventListener::createIntelJITEventListener(
296                                       IntelJITEventsWrapper* TestImpl) {
297   return new IntelJITEventListener(TestImpl);
298 }
299
300 } // namespace llvm
301