1//===-- llvm-jitlistener.cpp - Utility for testing MCJIT event listener ---===//
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 program is a used by lit tests to verify the MCJIT JITEventListener
11// interface.  It registers a mock JIT event listener, generates a module from
12// an input IR file and dumps the reported event information to stdout.
13//
14//===----------------------------------------------------------------------===//
15
16#include "../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h"
17#include "llvm/ADT/Triple.h"
18#include "llvm/ExecutionEngine/JITEventListener.h"
19#include "llvm/ExecutionEngine/MCJIT.h"
20#include "llvm/ExecutionEngine/SectionMemoryManager.h"
21#include "llvm/IR/LLVMContext.h"
22#include "llvm/IR/Module.h"
23#include "llvm/IRReader/IRReader.h"
24#include "llvm/Support/CommandLine.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/Host.h"
27#include "llvm/Support/ManagedStatic.h"
28#include "llvm/Support/MemoryBuffer.h"
29#include "llvm/Support/PrettyStackTrace.h"
30#include "llvm/Support/Signals.h"
31#include "llvm/Support/SourceMgr.h"
32#include "llvm/Support/TargetSelect.h"
33#include "llvm/Support/raw_ostream.h"
34#include <string>
35
36using namespace llvm;
37
38namespace {
39
40typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations;
41typedef std::map<uint64_t, SourceLocations> NativeCodeMap;
42
43NativeCodeMap  ReportedDebugFuncs;
44
45int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) {
46  switch (EventType) {
47    case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: {
48      if (!EventSpecificData) {
49        errs() <<
50          "Error: The JIT event listener did not provide a event data.";
51        return -1;
52      }
53      iJIT_Method_Load* msg = static_cast<iJIT_Method_Load*>(EventSpecificData);
54
55      ReportedDebugFuncs[msg->method_id];
56
57      outs() << "Method load [" << msg->method_id << "]: " << msg->method_name
58             << ", Size = " << msg->method_size << "\n";
59
60      for(unsigned int i = 0; i < msg->line_number_size; ++i) {
61        if (!msg->line_number_table) {
62          errs() << "A function with a non-zero line count had no line table.";
63          return -1;
64        }
65        std::pair<std::string, unsigned int> loc(
66          std::string(msg->source_file_name),
67          msg->line_number_table[i].LineNumber);
68        ReportedDebugFuncs[msg->method_id].push_back(loc);
69        outs() << "  Line info @ " << msg->line_number_table[i].Offset
70               << ": " << msg->source_file_name
71               << ", line " << msg->line_number_table[i].LineNumber << "\n";
72      }
73      outs() << "\n";
74    }
75    break;
76    case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: {
77      if (!EventSpecificData) {
78        errs() <<
79          "Error: The JIT event listener did not provide a event data.";
80        return -1;
81      }
82      unsigned int UnloadId
83        = *reinterpret_cast<unsigned int*>(EventSpecificData);
84      assert(1 == ReportedDebugFuncs.erase(UnloadId));
85      outs() << "Method unload [" << UnloadId << "]\n";
86    }
87    break;
88    default:
89      break;
90  }
91  return 0;
92}
93
94iJIT_IsProfilingActiveFlags IsProfilingActive(void) {
95  // for testing, pretend we have an Intel Parallel Amplifier XE 2011
96  // instance attached
97  return iJIT_SAMPLING_ON;
98}
99
100unsigned int GetNewMethodID(void) {
101  static unsigned int id = 0;
102  return ++id;
103}
104
105class JitEventListenerTest {
106protected:
107  void InitEE(const std::string &IRFile) {
108    LLVMContext &Context = getGlobalContext();
109
110    // If we have a native target, initialize it to ensure it is linked in and
111    // usable by the JIT.
112    InitializeNativeTarget();
113    InitializeNativeTargetAsmPrinter();
114
115    // Parse the bitcode...
116    SMDiagnostic Err;
117    std::unique_ptr<Module> TheModule(parseIRFile(IRFile, Err, Context));
118    if (!TheModule) {
119      errs() << Err.getMessage();
120      return;
121    }
122
123    RTDyldMemoryManager *MemMgr = new SectionMemoryManager();
124    if (!MemMgr) {
125      errs() << "Unable to create memory manager.";
126      return;
127    }
128
129    // Override the triple to generate ELF on Windows since that's supported
130    Triple Tuple(TheModule->getTargetTriple());
131    if (Tuple.getTriple().empty())
132      Tuple.setTriple(sys::getProcessTriple());
133
134    if (Tuple.isOSWindows() && !Tuple.isOSBinFormatELF()) {
135      Tuple.setObjectFormat(Triple::ELF);
136      TheModule->setTargetTriple(Tuple.getTriple());
137    }
138
139    // Compile the IR
140    std::string Error;
141    TheJIT.reset(EngineBuilder(std::move(TheModule))
142      .setEngineKind(EngineKind::JIT)
143      .setErrorStr(&Error)
144      .setMCJITMemoryManager(std::unique_ptr<RTDyldMemoryManager>(MemMgr))
145      .create());
146    if (Error.empty() == false)
147      errs() << Error;
148  }
149
150  void DestroyEE() {
151    TheJIT.reset();
152  }
153
154  LLVMContext Context; // Global ownership
155  std::unique_ptr<ExecutionEngine> TheJIT;
156
157public:
158  void ProcessInput(const std::string &Filename) {
159    InitEE(Filename);
160
161    std::unique_ptr<llvm::JITEventListener> Listener(
162        JITEventListener::createIntelJITEventListener(new IntelJITEventsWrapper(
163            NotifyEvent, 0, IsProfilingActive, 0, 0, GetNewMethodID)));
164
165    TheJIT->RegisterJITEventListener(Listener.get());
166
167    TheJIT->finalizeObject();
168
169    // Destroy the JIT engine instead of unregistering to get unload events.
170    DestroyEE();
171  }
172};
173
174
175
176} // end anonymous namespace
177
178static cl::opt<std::string>
179InputFilename(cl::Positional, cl::desc("<input IR file>"),
180               cl::Required);
181
182int main(int argc, char **argv) {
183  // Print a stack trace if we signal out.
184  sys::PrintStackTraceOnErrorSignal();
185  PrettyStackTraceProgram X(argc, argv);
186  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
187
188  cl::ParseCommandLineOptions(argc, argv, "llvm jit event listener test utility\n");
189
190  JitEventListenerTest Test;
191
192  Test.ProcessInput(InputFilename);
193
194  return 0;
195}
196