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