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