]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/ExecutionEngine/IntelJITEvents/IntelJITEventListener.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / 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 "IntelJITEventsWrapper.h"
16 #include "llvm-c/ExecutionEngine.h"
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/CodeGen/MachineFunction.h"
19 #include "llvm/Config/config.h"
20 #include "llvm/DebugInfo/DIContext.h"
21 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
22 #include "llvm/ExecutionEngine/JITEventListener.h"
23 #include "llvm/IR/DebugInfo.h"
24 #include "llvm/IR/Function.h"
25 #include "llvm/IR/Metadata.h"
26 #include "llvm/IR/ValueHandle.h"
27 #include "llvm/Object/ObjectFile.h"
28 #include "llvm/Object/SymbolSize.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/Errno.h"
31 #include "llvm/Support/raw_ostream.h"
32
33 using namespace llvm;
34 using namespace llvm::object;
35
36 #define DEBUG_TYPE "amplifier-jit-event-listener"
37
38 namespace {
39
40 class IntelJITEventListener : public JITEventListener {
41   typedef DenseMap<void*, unsigned int> MethodIDMap;
42
43   std::unique_ptr<IntelJITEventsWrapper> Wrapper;
44   MethodIDMap MethodIDs;
45
46   typedef SmallVector<const void *, 64> MethodAddressVector;
47   typedef DenseMap<const void *, MethodAddressVector>  ObjectMap;
48
49   ObjectMap  LoadedObjectMap;
50   std::map<const char*, OwningBinary<ObjectFile>> DebugObjects;
51
52 public:
53   IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
54       Wrapper.reset(libraryWrapper);
55   }
56
57   ~IntelJITEventListener() {
58   }
59
60   void NotifyObjectEmitted(const ObjectFile &Obj,
61                            const RuntimeDyld::LoadedObjectInfo &L) override;
62
63   void NotifyFreeingObject(const ObjectFile &Obj) override;
64 };
65
66 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
67                                                  uintptr_t Address,
68                                                  DILineInfo Line) {
69   LineNumberInfo Result;
70
71   Result.Offset = Address - StartAddress;
72   Result.LineNumber = Line.Line;
73
74   return Result;
75 }
76
77 static iJIT_Method_Load FunctionDescToIntelJITFormat(
78     IntelJITEventsWrapper& Wrapper,
79     const char* FnName,
80     uintptr_t FnStart,
81     size_t FnSize) {
82   iJIT_Method_Load Result;
83   memset(&Result, 0, sizeof(iJIT_Method_Load));
84
85   Result.method_id = Wrapper.iJIT_GetNewMethodID();
86   Result.method_name = const_cast<char*>(FnName);
87   Result.method_load_address = reinterpret_cast<void*>(FnStart);
88   Result.method_size = FnSize;
89
90   Result.class_id = 0;
91   Result.class_file_name = NULL;
92   Result.user_data = NULL;
93   Result.user_data_size = 0;
94   Result.env = iJDE_JittingAPI;
95
96   return Result;
97 }
98
99 void IntelJITEventListener::NotifyObjectEmitted(
100                                        const ObjectFile &Obj,
101                                        const RuntimeDyld::LoadedObjectInfo &L) {
102
103   OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
104   const ObjectFile *DebugObj = DebugObjOwner.getBinary();
105   if (!DebugObj)
106     return;
107
108   // Get the address of the object image for use as a unique identifier
109   const void* ObjData = DebugObj->getData().data();
110   std::unique_ptr<DIContext> Context = DWARFContext::create(*DebugObj);
111   MethodAddressVector Functions;
112
113   // Use symbol info to iterate functions in the object.
114   for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(*DebugObj)) {
115     SymbolRef Sym = P.first;
116     std::vector<LineNumberInfo> LineInfo;
117     std::string SourceFileName;
118
119     Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
120     if (!SymTypeOrErr) {
121       // TODO: Actually report errors helpfully.
122       consumeError(SymTypeOrErr.takeError());
123       continue;
124     }
125     SymbolRef::Type SymType = *SymTypeOrErr;
126     if (SymType != SymbolRef::ST_Function)
127       continue;
128
129     Expected<StringRef> Name = Sym.getName();
130     if (!Name) {
131       // TODO: Actually report errors helpfully.
132       consumeError(Name.takeError());
133       continue;
134     }
135
136     Expected<uint64_t> AddrOrErr = Sym.getAddress();
137     if (!AddrOrErr) {
138       // TODO: Actually report errors helpfully.
139       consumeError(AddrOrErr.takeError());
140       continue;
141     }
142     uint64_t Addr = *AddrOrErr;
143     uint64_t Size = P.second;
144
145     // Record this address in a local vector
146     Functions.push_back((void*)Addr);
147
148     // Build the function loaded notification message
149     iJIT_Method_Load FunctionMessage =
150       FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size);
151     DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
152     DILineInfoTable::iterator Begin = Lines.begin();
153     DILineInfoTable::iterator End = Lines.end();
154     for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
155       LineInfo.push_back(
156           DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second));
157     }
158     if (LineInfo.size() == 0) {
159       FunctionMessage.source_file_name = 0;
160       FunctionMessage.line_number_size = 0;
161       FunctionMessage.line_number_table = 0;
162     } else {
163       // Source line information for the address range is provided as
164       // a code offset for the start of the corresponding sub-range and
165       // a source line. JIT API treats offsets in LineNumberInfo structures
166       // as the end of the corresponding code region. The start of the code
167       // is taken from the previous element. Need to shift the elements.
168
169       LineNumberInfo last = LineInfo.back();
170       last.Offset = FunctionMessage.method_size;
171       LineInfo.push_back(last);
172       for (size_t i = LineInfo.size() - 2; i > 0; --i)
173         LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber;
174
175       SourceFileName = Lines.front().second.FileName;
176       FunctionMessage.source_file_name =
177         const_cast<char *>(SourceFileName.c_str());
178       FunctionMessage.line_number_size = LineInfo.size();
179       FunctionMessage.line_number_table = &*LineInfo.begin();
180     }
181
182     Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
183                               &FunctionMessage);
184     MethodIDs[(void*)Addr] = FunctionMessage.method_id;
185   }
186
187   // To support object unload notification, we need to keep a list of
188   // registered function addresses for each loaded object.  We will
189   // use the MethodIDs map to get the registered ID for each function.
190   LoadedObjectMap[ObjData] = Functions;
191   DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner);
192 }
193
194 void IntelJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) {
195   // This object may not have been registered with the listener. If it wasn't,
196   // bail out.
197   if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end())
198     return;
199
200   // Get the address of the object image for use as a unique identifier
201   const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary();
202   const void* ObjData = DebugObj.getData().data();
203
204   // Get the object's function list from LoadedObjectMap
205   ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
206   if (OI == LoadedObjectMap.end())
207     return;
208   MethodAddressVector& Functions = OI->second;
209
210   // Walk the function list, unregistering each function
211   for (MethodAddressVector::iterator FI = Functions.begin(),
212                                      FE = Functions.end();
213        FI != FE;
214        ++FI) {
215     void* FnStart = const_cast<void*>(*FI);
216     MethodIDMap::iterator MI = MethodIDs.find(FnStart);
217     if (MI != MethodIDs.end()) {
218       Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
219                                 &MI->second);
220       MethodIDs.erase(MI);
221     }
222   }
223
224   // Erase the object from LoadedObjectMap
225   LoadedObjectMap.erase(OI);
226   DebugObjects.erase(Obj.getData().data());
227 }
228
229 }  // anonymous namespace.
230
231 namespace llvm {
232 JITEventListener *JITEventListener::createIntelJITEventListener() {
233   return new IntelJITEventListener(new IntelJITEventsWrapper);
234 }
235
236 // for testing
237 JITEventListener *JITEventListener::createIntelJITEventListener(
238                                       IntelJITEventsWrapper* TestImpl) {
239   return new IntelJITEventListener(TestImpl);
240 }
241
242 } // namespace llvm
243
244 LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void)
245 {
246   return wrap(JITEventListener::createIntelJITEventListener());
247 }