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