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 35 using namespace llvm; 36 37 namespace { 38 39 typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations; 40 typedef std::map<uint64_t, SourceLocations> NativeCodeMap; 41 42 NativeCodeMap ReportedDebugFuncs; 43 44 int 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 93 iJIT_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 99 unsigned int GetNewMethodID(void) { 100 static unsigned int id = 0; 101 return ++id; 102 } 103 104 class JitEventListenerTest { 105 protected: 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 167 public: 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 188 static cl::opt<std::string> 189 InputFilename(cl::Positional, cl::desc("<input IR file>"), 190 cl::Required); 191 192 int 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