1234285Sdim//===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
2234285Sdim//
3234285Sdim//                     The LLVM Compiler Infrastructure
4234285Sdim//
5234285Sdim// This file is distributed under the University of Illinois Open Source
6234285Sdim// License. See LICENSE.TXT for details.
7234285Sdim//
8234285Sdim//===----------------------------------------------------------------------===//
9234285Sdim//
10234285Sdim// This file defines a JITEventListener object to tell Intel(R) VTune(TM)
11234285Sdim// Amplifier XE 2011 about JITted functions.
12234285Sdim//
13234285Sdim//===----------------------------------------------------------------------===//
14234285Sdim
15234285Sdim#include "llvm/Config/config.h"
16234285Sdim#include "llvm/ExecutionEngine/JITEventListener.h"
17234285Sdim
18234285Sdim#define DEBUG_TYPE "amplifier-jit-event-listener"
19239462Sdim#include "llvm/DebugInfo.h"
20249423Sdim#include "llvm/IR/Function.h"
21249423Sdim#include "llvm/IR/Metadata.h"
22234285Sdim#include "llvm/ADT/DenseMap.h"
23234285Sdim#include "llvm/ADT/OwningPtr.h"
24234285Sdim#include "llvm/CodeGen/MachineFunction.h"
25249423Sdim#include "llvm/DebugInfo/DIContext.h"
26249423Sdim#include "llvm/ExecutionEngine/ObjectImage.h"
27249423Sdim#include "llvm/Object/ObjectFile.h"
28234285Sdim#include "llvm/Support/Debug.h"
29234285Sdim#include "llvm/Support/raw_ostream.h"
30234285Sdim#include "llvm/Support/Errno.h"
31234285Sdim#include "llvm/Support/ValueHandle.h"
32234285Sdim#include "EventListenerCommon.h"
33243830Sdim#include "IntelJITEventsWrapper.h"
34234285Sdim
35234285Sdimusing namespace llvm;
36234285Sdimusing namespace llvm::jitprofiling;
37234285Sdim
38234285Sdimnamespace {
39234285Sdim
40234285Sdimclass IntelJITEventListener : public JITEventListener {
41234285Sdim  typedef DenseMap<void*, unsigned int> MethodIDMap;
42234285Sdim
43243830Sdim  OwningPtr<IntelJITEventsWrapper> Wrapper;
44234285Sdim  MethodIDMap MethodIDs;
45234285Sdim  FilenameCache Filenames;
46234285Sdim
47249423Sdim  typedef SmallVector<const void *, 64> MethodAddressVector;
48249423Sdim  typedef DenseMap<const void *, MethodAddressVector>  ObjectMap;
49249423Sdim
50249423Sdim  ObjectMap  LoadedObjectMap;
51249423Sdim
52234285Sdimpublic:
53243830Sdim  IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
54243830Sdim      Wrapper.reset(libraryWrapper);
55234285Sdim  }
56234285Sdim
57234285Sdim  ~IntelJITEventListener() {
58234285Sdim  }
59234285Sdim
60234285Sdim  virtual void NotifyFunctionEmitted(const Function &F,
61234285Sdim                                     void *FnStart, size_t FnSize,
62234285Sdim                                     const EmittedFunctionDetails &Details);
63234285Sdim
64234285Sdim  virtual void NotifyFreeingMachineCode(void *OldPtr);
65243830Sdim
66243830Sdim  virtual void NotifyObjectEmitted(const ObjectImage &Obj);
67243830Sdim
68243830Sdim  virtual void NotifyFreeingObject(const ObjectImage &Obj);
69234285Sdim};
70234285Sdim
71234285Sdimstatic LineNumberInfo LineStartToIntelJITFormat(
72234285Sdim    uintptr_t StartAddress,
73234285Sdim    uintptr_t Address,
74234285Sdim    DebugLoc Loc) {
75234285Sdim  LineNumberInfo Result;
76234285Sdim
77234285Sdim  Result.Offset = Address - StartAddress;
78234285Sdim  Result.LineNumber = Loc.getLine();
79234285Sdim
80234285Sdim  return Result;
81234285Sdim}
82234285Sdim
83249423Sdimstatic LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
84249423Sdim                                                 uintptr_t Address,
85249423Sdim                                                 DILineInfo Line) {
86249423Sdim  LineNumberInfo Result;
87249423Sdim
88249423Sdim  Result.Offset = Address - StartAddress;
89249423Sdim  Result.LineNumber = Line.getLine();
90249423Sdim
91249423Sdim  return Result;
92249423Sdim}
93249423Sdim
94234285Sdimstatic iJIT_Method_Load FunctionDescToIntelJITFormat(
95234285Sdim    IntelJITEventsWrapper& Wrapper,
96234285Sdim    const char* FnName,
97234285Sdim    uintptr_t FnStart,
98234285Sdim    size_t FnSize) {
99234285Sdim  iJIT_Method_Load Result;
100234285Sdim  memset(&Result, 0, sizeof(iJIT_Method_Load));
101234285Sdim
102234285Sdim  Result.method_id = Wrapper.iJIT_GetNewMethodID();
103234285Sdim  Result.method_name = const_cast<char*>(FnName);
104234285Sdim  Result.method_load_address = reinterpret_cast<void*>(FnStart);
105234285Sdim  Result.method_size = FnSize;
106234285Sdim
107234285Sdim  Result.class_id = 0;
108234285Sdim  Result.class_file_name = NULL;
109234285Sdim  Result.user_data = NULL;
110234285Sdim  Result.user_data_size = 0;
111234285Sdim  Result.env = iJDE_JittingAPI;
112234285Sdim
113234285Sdim  return Result;
114234285Sdim}
115234285Sdim
116234285Sdim// Adds the just-emitted function to the symbol table.
117234285Sdimvoid IntelJITEventListener::NotifyFunctionEmitted(
118234285Sdim    const Function &F, void *FnStart, size_t FnSize,
119234285Sdim    const EmittedFunctionDetails &Details) {
120243830Sdim  iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
121234285Sdim                                      F.getName().data(),
122234285Sdim                                      reinterpret_cast<uint64_t>(FnStart),
123234285Sdim                                      FnSize);
124234285Sdim
125234285Sdim  std::vector<LineNumberInfo> LineInfo;
126234285Sdim
127234285Sdim  if (!Details.LineStarts.empty()) {
128234285Sdim    // Now convert the line number information from the address/DebugLoc
129234285Sdim    // format in Details to the offset/lineno in Intel JIT API format.
130234285Sdim
131234285Sdim    LineInfo.reserve(Details.LineStarts.size() + 1);
132234285Sdim
133234285Sdim    DebugLoc FirstLoc = Details.LineStarts[0].Loc;
134234285Sdim    assert(!FirstLoc.isUnknown()
135234285Sdim           && "LineStarts should not contain unknown DebugLocs");
136234285Sdim
137234285Sdim    MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
138234285Sdim    DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
139234285Sdim    if (FunctionDI.Verify()) {
140234285Sdim      FunctionMessage.source_file_name = const_cast<char*>(
141234285Sdim                                          Filenames.getFullPath(FirstLocScope));
142234285Sdim
143234285Sdim      LineNumberInfo FirstLine;
144234285Sdim      FirstLine.Offset = 0;
145234285Sdim      FirstLine.LineNumber = FunctionDI.getLineNumber();
146234285Sdim      LineInfo.push_back(FirstLine);
147234285Sdim    }
148234285Sdim
149234285Sdim    for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
150234285Sdim          Details.LineStarts.begin(), E = Details.LineStarts.end();
151234285Sdim          I != E; ++I) {
152234285Sdim      // This implementation ignores the DebugLoc filename because the Intel
153234285Sdim      // JIT API does not support multiple source files associated with a single
154234285Sdim      // JIT function
155234285Sdim      LineInfo.push_back(LineStartToIntelJITFormat(
156234285Sdim                          reinterpret_cast<uintptr_t>(FnStart),
157234285Sdim                          I->Address,
158234285Sdim                          I->Loc));
159234285Sdim
160234285Sdim      // If we have no file name yet for the function, use the filename from
161234285Sdim      // the first instruction that has one
162234285Sdim      if (FunctionMessage.source_file_name == 0) {
163234285Sdim        MDNode *scope = I->Loc.getScope(
164239462Sdim          Details.MF->getFunction()->getContext());
165234285Sdim        FunctionMessage.source_file_name = const_cast<char*>(
166234285Sdim                                                  Filenames.getFullPath(scope));
167234285Sdim      }
168234285Sdim    }
169234285Sdim
170234285Sdim    FunctionMessage.line_number_size = LineInfo.size();
171234285Sdim    FunctionMessage.line_number_table = &*LineInfo.begin();
172234285Sdim  } else {
173234285Sdim    FunctionMessage.line_number_size = 0;
174234285Sdim    FunctionMessage.line_number_table = 0;
175234285Sdim  }
176234285Sdim
177243830Sdim  Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
178243830Sdim                            &FunctionMessage);
179234285Sdim  MethodIDs[FnStart] = FunctionMessage.method_id;
180234285Sdim}
181234285Sdim
182234285Sdimvoid IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
183234285Sdim  MethodIDMap::iterator I = MethodIDs.find(FnStart);
184234285Sdim  if (I != MethodIDs.end()) {
185243830Sdim    Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second);
186234285Sdim    MethodIDs.erase(I);
187234285Sdim  }
188234285Sdim}
189234285Sdim
190243830Sdimvoid IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
191249423Sdim  // Get the address of the object image for use as a unique identifier
192249423Sdim  const void* ObjData = Obj.getData().data();
193249423Sdim  DIContext* Context = DIContext::getDWARFContext(Obj.getObjectFile());
194249423Sdim  MethodAddressVector Functions;
195249423Sdim
196249423Sdim  // Use symbol info to iterate functions in the object.
197249423Sdim  error_code ec;
198249423Sdim  for (object::symbol_iterator I = Obj.begin_symbols(),
199249423Sdim                               E = Obj.end_symbols();
200249423Sdim                        I != E && !ec;
201249423Sdim                        I.increment(ec)) {
202249423Sdim    std::vector<LineNumberInfo> LineInfo;
203249423Sdim    std::string SourceFileName;
204249423Sdim
205249423Sdim    object::SymbolRef::Type SymType;
206249423Sdim    if (I->getType(SymType)) continue;
207249423Sdim    if (SymType == object::SymbolRef::ST_Function) {
208249423Sdim      StringRef  Name;
209249423Sdim      uint64_t   Addr;
210249423Sdim      uint64_t   Size;
211249423Sdim      if (I->getName(Name)) continue;
212249423Sdim      if (I->getAddress(Addr)) continue;
213249423Sdim      if (I->getSize(Size)) continue;
214249423Sdim
215249423Sdim      // Record this address in a local vector
216249423Sdim      Functions.push_back((void*)Addr);
217249423Sdim
218249423Sdim      // Build the function loaded notification message
219249423Sdim      iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
220249423Sdim                                           Name.data(),
221249423Sdim                                           Addr,
222249423Sdim                                           Size);
223249423Sdim      if (Context) {
224249423Sdim        DILineInfoTable  Lines = Context->getLineInfoForAddressRange(Addr, Size);
225249423Sdim        DILineInfoTable::iterator  Begin = Lines.begin();
226249423Sdim        DILineInfoTable::iterator  End = Lines.end();
227249423Sdim        for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
228249423Sdim          LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr,
229249423Sdim                                                        It->first,
230249423Sdim                                                        It->second));
231249423Sdim        }
232249423Sdim        if (LineInfo.size() == 0) {
233249423Sdim          FunctionMessage.source_file_name = 0;
234249423Sdim          FunctionMessage.line_number_size = 0;
235249423Sdim          FunctionMessage.line_number_table = 0;
236249423Sdim        } else {
237249423Sdim          SourceFileName = Lines.front().second.getFileName();
238249423Sdim          FunctionMessage.source_file_name = (char *)SourceFileName.c_str();
239249423Sdim          FunctionMessage.line_number_size = LineInfo.size();
240249423Sdim          FunctionMessage.line_number_table = &*LineInfo.begin();
241249423Sdim        }
242249423Sdim      } else {
243249423Sdim        FunctionMessage.source_file_name = 0;
244249423Sdim        FunctionMessage.line_number_size = 0;
245249423Sdim        FunctionMessage.line_number_table = 0;
246249423Sdim      }
247249423Sdim
248249423Sdim      Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
249249423Sdim                                &FunctionMessage);
250249423Sdim      MethodIDs[(void*)Addr] = FunctionMessage.method_id;
251249423Sdim    }
252249423Sdim  }
253249423Sdim
254249423Sdim  // To support object unload notification, we need to keep a list of
255249423Sdim  // registered function addresses for each loaded object.  We will
256249423Sdim  // use the MethodIDs map to get the registered ID for each function.
257249423Sdim  LoadedObjectMap[ObjData] = Functions;
258243830Sdim}
259243830Sdim
260243830Sdimvoid IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
261249423Sdim  // Get the address of the object image for use as a unique identifier
262249423Sdim  const void* ObjData = Obj.getData().data();
263249423Sdim
264249423Sdim  // Get the object's function list from LoadedObjectMap
265249423Sdim  ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
266249423Sdim  if (OI == LoadedObjectMap.end())
267249423Sdim    return;
268249423Sdim  MethodAddressVector& Functions = OI->second;
269249423Sdim
270249423Sdim  // Walk the function list, unregistering each function
271249423Sdim  for (MethodAddressVector::iterator FI = Functions.begin(),
272249423Sdim                                     FE = Functions.end();
273249423Sdim       FI != FE;
274249423Sdim       ++FI) {
275249423Sdim    void* FnStart = const_cast<void*>(*FI);
276249423Sdim    MethodIDMap::iterator MI = MethodIDs.find(FnStart);
277249423Sdim    if (MI != MethodIDs.end()) {
278249423Sdim      Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
279249423Sdim                                &MI->second);
280249423Sdim      MethodIDs.erase(MI);
281249423Sdim    }
282249423Sdim  }
283249423Sdim
284249423Sdim  // Erase the object from LoadedObjectMap
285249423Sdim  LoadedObjectMap.erase(OI);
286243830Sdim}
287243830Sdim
288234285Sdim}  // anonymous namespace.
289234285Sdim
290234285Sdimnamespace llvm {
291234285SdimJITEventListener *JITEventListener::createIntelJITEventListener() {
292243830Sdim  return new IntelJITEventListener(new IntelJITEventsWrapper);
293234285Sdim}
294234285Sdim
295234285Sdim// for testing
296234285SdimJITEventListener *JITEventListener::createIntelJITEventListener(
297234285Sdim                                      IntelJITEventsWrapper* TestImpl) {
298243830Sdim  return new IntelJITEventListener(TestImpl);
299234285Sdim}
300234285Sdim
301234285Sdim} // namespace llvm
302234285Sdim
303