llvm.org GIT mirror llvm / df5a7da
Add a JITEventListener interface that gets called back when a new function is emitted or the machine code for a function is freed. Chris mentioned that we may also want a notification when a stub is emitted, but that'll be a future change. I intend to use this to tell oprofile where functions are emitted and what lines correspond to what addresses. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74157 91177308-0d34-0410-b5e6-96231b3b80d8 Jeffrey Yasskin 11 years ago
11 changed file(s) with 600 addition(s) and 170 deletion(s). Raw diff Collapse all Expand all
2828 class Function;
2929 class GlobalVariable;
3030 class GlobalValue;
31 class JITEventListener;
32 class JITMemoryManager;
33 class MachineCodeInfo;
3134 class Module;
3235 class ModuleProvider;
36 class MutexGuard;
3337 class TargetData;
3438 class Type;
35 class MutexGuard;
36 class JITMemoryManager;
37 class MachineCodeInfo;
3839
3940 class ExecutionEngineState {
4041 private:
275276 virtual void *getOrEmitGlobalVariable(const GlobalVariable *GV) {
276277 return getPointerToGlobal((GlobalValue*)GV);
277278 }
278
279
280 /// Registers a listener to be called back on various events within
281 /// the JIT. See JITEventListener.h for more details. Does not
282 /// take ownership of the argument. The argument may be NULL, in
283 /// which case these functions do nothing.
284 virtual void RegisterJITEventListener(JITEventListener *L) {}
285 virtual void UnregisterJITEventListener(JITEventListener *L) {}
286
279287 /// DisableLazyCompilation - If called, the JIT will abort if lazy compilation
280288 /// is ever attempted.
281289 void DisableLazyCompilation(bool Disabled = true) {
0 //===- JITEventListener.h - Exposes events from JIT compilation -*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the JITEventListener interface, which lets users get
10 // callbacks when significant events happen during the JIT compilation process.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_EXECUTION_ENGINE_JIT_EVENTLISTENER_H
15 #define LLVM_EXECUTION_ENGINE_JIT_EVENTLISTENER_H
16
17 #include "llvm/Support/DataTypes.h"
18
19 namespace llvm {
20 class Function;
21
22 /// Empty for now, but this object will contain all details about the
23 /// generated machine code that a Listener might care about.
24 struct JITEvent_EmittedFunctionDetails {
25 };
26
27 /// JITEventListener - This interface is used by the JIT to notify clients about
28 /// significant events during compilation. For example, we could have
29 /// implementations for profilers and debuggers that need to know where
30 /// functions have been emitted.
31 ///
32 /// Each method defaults to doing nothing, so you only need to override the ones
33 /// you care about.
34 class JITEventListener {
35 public:
36 JITEventListener() {}
37 virtual ~JITEventListener(); // Defined in JIT.cpp.
38
39 typedef JITEvent_EmittedFunctionDetails EmittedFunctionDetails;
40 /// NotifyFunctionEmitted - Called after a function has been successfully
41 /// emitted to memory. The function still has its MachineFunction attached,
42 /// if you should happen to need that.
43 virtual void NotifyFunctionEmitted(const Function &F,
44 void *Code, size_t Size,
45 const EmittedFunctionDetails &Details) {}
46
47 /// NotifyFreeingMachineCode - This is called inside of
48 /// freeMachineCodeForFunction(), after the global mapping is removed, but
49 /// before the machine code is returned to the allocator. OldPtr is the
50 /// address of the machine code.
51 virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr) {}
52 };
53
54 JITEventListener *createMacOSJITEventListener();
55
56 } // end namespace llvm.
57
58 #endif
1919 #include "llvm/Instructions.h"
2020 #include "llvm/ModuleProvider.h"
2121 #include "llvm/CodeGen/JITCodeEmitter.h"
22 #include "llvm/CodeGen/MachineCodeInfo.h"
2223 #include "llvm/ExecutionEngine/GenericValue.h"
23 #include "llvm/CodeGen/MachineCodeInfo.h"
24 #include "llvm/ExecutionEngine/JITEventListener.h"
2425 #include "llvm/Target/TargetData.h"
2526 #include "llvm/Target/TargetMachine.h"
2627 #include "llvm/Target/TargetJITInfo.h"
506507 return runFunction(Stub, std::vector());
507508 }
508509
510 void JIT::RegisterJITEventListener(JITEventListener *L) {
511 if (L == NULL)
512 return;
513 MutexGuard locked(lock);
514 EventListeners.push_back(L);
515 }
516 void JIT::UnregisterJITEventListener(JITEventListener *L) {
517 if (L == NULL)
518 return;
519 MutexGuard locked(lock);
520 std::vector::reverse_iterator I=
521 std::find(EventListeners.rbegin(), EventListeners.rend(), L);
522 if (I != EventListeners.rend()) {
523 std::swap(*I, EventListeners.back());
524 EventListeners.pop_back();
525 }
526 }
527 void JIT::NotifyFunctionEmitted(
528 const Function &F,
529 void *Code, size_t Size,
530 const JITEvent_EmittedFunctionDetails &Details) {
531 MutexGuard locked(lock);
532 for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
533 EventListeners[I]->NotifyFunctionEmitted(F, Code, Size, Details);
534 }
535 }
536
537 void JIT::NotifyFreeingMachineCode(const Function &F, void *OldPtr) {
538 MutexGuard locked(lock);
539 for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
540 EventListeners[I]->NotifyFreeingMachineCode(F, OldPtr);
541 }
542 }
543
509544 /// runJITOnFunction - Run the FunctionPassManager full of
510545 /// just-in-time compilation passes on F, hopefully filling in
511546 /// GlobalAddress[F] with the address of F's machine code.
513548 void JIT::runJITOnFunction(Function *F, MachineCodeInfo *MCI) {
514549 MutexGuard locked(lock);
515550
516 registerMachineCodeInfo(MCI);
551 class MCIListener : public JITEventListener {
552 MachineCodeInfo *const MCI;
553 public:
554 MCIListener(MachineCodeInfo *mci) : MCI(mci) {}
555 virtual void NotifyFunctionEmitted(const Function &,
556 void *Code, size_t Size,
557 const EmittedFunctionDetails &) {
558 MCI->setAddress(Code);
559 MCI->setSize(Size);
560 }
561 };
562 MCIListener MCIL(MCI);
563 RegisterJITEventListener(&MCIL);
517564
518565 runJITOnFunctionUnlocked(F, locked);
519566
520 registerMachineCodeInfo(0);
567 UnregisterJITEventListener(&MCIL);
521568 }
522569
523570 void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) {
708755 MutexGuard locked(lock);
709756 jitstate->getPendingFunctions(locked).push_back(F);
710757 }
758
759
760 JITEventListener::~JITEventListener() {}
1919 namespace llvm {
2020
2121 class Function;
22 class TargetMachine;
23 class TargetJITInfo;
22 class JITEvent_EmittedFunctionDetails;
2423 class MachineCodeEmitter;
2524 class MachineCodeInfo;
25 class TargetJITInfo;
26 class TargetMachine;
2627
2728 class JITState {
2829 private:
5152 TargetMachine &TM; // The current target we are compiling to
5253 TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
5354 JITCodeEmitter *JCE; // JCE object
55 std::vector EventListeners;
5456
5557 JITState *jitstate;
5658
156158 // Run the JIT on F and return information about the generated code
157159 void runJITOnFunction(Function *F, MachineCodeInfo *MCI = 0);
158160
161 virtual void RegisterJITEventListener(JITEventListener *L);
162 virtual void UnregisterJITEventListener(JITEventListener *L);
163 /// These functions correspond to the methods on JITEventListener. They
164 /// iterate over the registered listeners and call the corresponding method on
165 /// each.
166 void NotifyFunctionEmitted(
167 const Function &F, void *Code, size_t Size,
168 const JITEvent_EmittedFunctionDetails &Details);
169 void NotifyFreeingMachineCode(const Function &F, void *OldPtr);
170
159171 private:
160172 static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM);
161 void registerMachineCodeInfo(MachineCodeInfo *MCI);
162173 void runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked);
163174 void updateFunctionStub(Function *F);
164175 void updateDlsymStubTable();
2323 #include "llvm/CodeGen/MachineJumpTableInfo.h"
2424 #include "llvm/CodeGen/MachineModuleInfo.h"
2525 #include "llvm/CodeGen/MachineRelocation.h"
26 #include "llvm/ExecutionEngine/GenericValue.h"
27 #include "llvm/ExecutionEngine/JITEventListener.h"
2628 #include "llvm/ExecutionEngine/JITMemoryManager.h"
27 #include "llvm/ExecutionEngine/GenericValue.h"
2829 #include "llvm/CodeGen/MachineCodeInfo.h"
2930 #include "llvm/Target/TargetData.h"
3031 #include "llvm/Target/TargetJITInfo.h"
410411 }
411412
412413 //===----------------------------------------------------------------------===//
413 // Function Index Support
414
415 // On MacOS we generate an index of currently JIT'd functions so that
416 // performance tools can determine a symbol name and accurate code range for a
417 // PC value. Because performance tools are generally asynchronous, the code
418 // below is written with the hope that it could be interrupted at any time and
419 // have useful answers. However, we don't go crazy with atomic operations, we
420 // just do a "reasonable effort".
421 #ifdef __APPLE__
422 #define ENABLE_JIT_SYMBOL_TABLE 0
423 #endif
424
425 /// JitSymbolEntry - Each function that is JIT compiled results in one of these
426 /// being added to an array of symbols. This indicates the name of the function
427 /// as well as the address range it occupies. This allows the client to map
428 /// from a PC value to the name of the function.
429 struct JitSymbolEntry {
430 const char *FnName; // FnName - a strdup'd string.
431 void *FnStart;
432 intptr_t FnSize;
433 };
434
435
436 struct JitSymbolTable {
437 /// NextPtr - This forms a linked list of JitSymbolTable entries. This
438 /// pointer is not used right now, but might be used in the future. Consider
439 /// it reserved for future use.
440 JitSymbolTable *NextPtr;
441
442 /// Symbols - This is an array of JitSymbolEntry entries. Only the first
443 /// 'NumSymbols' symbols are valid.
444 JitSymbolEntry *Symbols;
445
446 /// NumSymbols - This indicates the number entries in the Symbols array that
447 /// are valid.
448 unsigned NumSymbols;
449
450 /// NumAllocated - This indicates the amount of space we have in the Symbols
451 /// array. This is a private field that should not be read by external tools.
452 unsigned NumAllocated;
453 };
454
455 #if ENABLE_JIT_SYMBOL_TABLE
456 JitSymbolTable *__jitSymbolTable;
457 #endif
458
459 static void AddFunctionToSymbolTable(const char *FnName,
460 void *FnStart, intptr_t FnSize) {
461 assert(FnName != 0 && FnStart != 0 && "Bad symbol to add");
462 JitSymbolTable **SymTabPtrPtr = 0;
463 #if !ENABLE_JIT_SYMBOL_TABLE
464 return;
465 #else
466 SymTabPtrPtr = &__jitSymbolTable;
467 #endif
468
469 // If this is the first entry in the symbol table, add the JitSymbolTable
470 // index.
471 if (*SymTabPtrPtr == 0) {
472 JitSymbolTable *New = new JitSymbolTable();
473 New->NextPtr = 0;
474 New->Symbols = 0;
475 New->NumSymbols = 0;
476 New->NumAllocated = 0;
477 *SymTabPtrPtr = New;
478 }
479
480 JitSymbolTable *SymTabPtr = *SymTabPtrPtr;
481
482 // If we have space in the table, reallocate the table.
483 if (SymTabPtr->NumSymbols >= SymTabPtr->NumAllocated) {
484 // If we don't have space, reallocate the table.
485 unsigned NewSize = std::max(64U, SymTabPtr->NumAllocated*2);
486 JitSymbolEntry *NewSymbols = new JitSymbolEntry[NewSize];
487 JitSymbolEntry *OldSymbols = SymTabPtr->Symbols;
488
489 // Copy the old entries over.
490 memcpy(NewSymbols, OldSymbols, SymTabPtr->NumSymbols*sizeof(OldSymbols[0]));
491
492 // Swap the new symbols in, delete the old ones.
493 SymTabPtr->Symbols = NewSymbols;
494 SymTabPtr->NumAllocated = NewSize;
495 delete [] OldSymbols;
496 }
497
498 // Otherwise, we have enough space, just tack it onto the end of the array.
499 JitSymbolEntry &Entry = SymTabPtr->Symbols[SymTabPtr->NumSymbols];
500 Entry.FnName = strdup(FnName);
501 Entry.FnStart = FnStart;
502 Entry.FnSize = FnSize;
503 ++SymTabPtr->NumSymbols;
504 }
505
506 static void RemoveFunctionFromSymbolTable(void *FnStart) {
507 assert(FnStart && "Invalid function pointer");
508 JitSymbolTable **SymTabPtrPtr = 0;
509 #if !ENABLE_JIT_SYMBOL_TABLE
510 return;
511 #else
512 SymTabPtrPtr = &__jitSymbolTable;
513 #endif
514
515 JitSymbolTable *SymTabPtr = *SymTabPtrPtr;
516 JitSymbolEntry *Symbols = SymTabPtr->Symbols;
517
518 // Scan the table to find its index. The table is not sorted, so do a linear
519 // scan.
520 unsigned Index;
521 for (Index = 0; Symbols[Index].FnStart != FnStart; ++Index)
522 assert(Index != SymTabPtr->NumSymbols && "Didn't find function!");
523
524 // Once we have an index, we know to nuke this entry, overwrite it with the
525 // entry at the end of the array, making the last entry redundant.
526 const char *OldName = Symbols[Index].FnName;
527 Symbols[Index] = Symbols[SymTabPtr->NumSymbols-1];
528 free((void*)OldName);
529
530 // Drop the number of symbols in the table.
531 --SymTabPtr->NumSymbols;
532
533 // Finally, if we deleted the final symbol, deallocate the table itself.
534 if (SymTabPtr->NumSymbols != 0)
535 return;
536
537 *SymTabPtrPtr = 0;
538 delete [] Symbols;
539 delete SymTabPtr;
540 }
541
542 //===----------------------------------------------------------------------===//
543414 // JITEmitter code.
544415 //
545416 namespace {
615486 // in the JITResolver's ExternalFnToStubMap.
616487 StringMap ExtFnStubs;
617488
618 // MCI - A pointer to a MachineCodeInfo object to update with information.
619 MachineCodeInfo *MCI;
620
621489 public:
622 JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit), CurFn(0), MCI(0) {
490 JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit), CurFn(0) {
623491 MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager();
624492 if (jit.getJITInfo().needsGOT()) {
625493 MemMgr->AllocateGOT();
714582 }
715583
716584 JITMemoryManager *getMemMgr(void) const { return MemMgr; }
717
718 void setMachineCodeInfo(MachineCodeInfo *mci) {
719 MCI = mci;
720 }
721585
722586 private:
723587 void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub);
11561020
11571021 // Invalidate the icache if necessary.
11581022 sys::Memory::InvalidateInstructionCache(FnStart, FnEnd-FnStart);
1159
1160 // Add it to the JIT symbol table if the host wants it.
1161 AddFunctionToSymbolTable(F.getFunction()->getNameStart(),
1162 FnStart, FnEnd-FnStart);
1023
1024 JITEvent_EmittedFunctionDetails Details;
1025 TheJIT->NotifyFunctionEmitted(*F.getFunction(), FnStart, FnEnd-FnStart,
1026 Details);
11631027
11641028 DOUT << "JIT: Finished CodeGen of [" << (void*)FnStart
11651029 << "] Function: " << F.getFunction()->getName()
11661030 << ": " << (FnEnd-FnStart) << " bytes of text, "
11671031 << Relocations.size() << " relocations\n";
1168
1169 if (MCI) {
1170 MCI->setAddress(FnStart);
1171 MCI->setSize(FnEnd-FnStart);
1172 }
11731032
11741033 Relocations.clear();
11751034 ConstPoolAddresses.clear();
14941353 return JE->getJITResolver().getFunctionStub(F);
14951354 }
14961355
1497 void JIT::registerMachineCodeInfo(MachineCodeInfo *mc) {
1498 assert(isa(JCE) && "Unexpected MCE?");
1499 JITEmitter *JE = cast(getCodeEmitter());
1500
1501 JE->setMachineCodeInfo(mc);
1502 }
1503
15041356 void JIT::updateFunctionStub(Function *F) {
15051357 // Get the empty stub we generated earlier.
15061358 assert(isa(JCE) && "Unexpected MCE?");
16081460 void *OldPtr = updateGlobalMapping(F, 0);
16091461
16101462 if (OldPtr)
1611 RemoveFunctionFromSymbolTable(OldPtr);
1463 TheJIT->NotifyFreeingMachineCode(*F, OldPtr);
16121464
16131465 // Free the actual memory for the function body and related stuff.
16141466 assert(isa(JCE) && "Unexpected MCE?");
16151467 cast(JCE)->deallocateMemForFunction(F);
16161468 }
1617
0 //===-- MacOSJITEventListener.cpp - Save symbol table for OSX perf tools --===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a JITEventListener object that records JITted functions to
10 // a global __jitSymbolTable linked list. Apple's performance tools use this to
11 // determine a symbol name and accurate code range for a PC value. Because
12 // performance tools are generally asynchronous, the code below is written with
13 // the hope that it could be interrupted at any time and have useful answers.
14 // However, we don't go crazy with atomic operations, we just do a "reasonable
15 // effort".
16 //
17 //===----------------------------------------------------------------------===//
18
19 #define DEBUG_TYPE "macos-jit-event-listener"
20 #include "llvm/Function.h"
21 #include "llvm/ExecutionEngine/JITEventListener.h"
22 #include
23 using namespace llvm;
24
25 #ifdef __APPLE__
26 #define ENABLE_JIT_SYMBOL_TABLE 0
27 #endif
28
29 #if ENABLE_JIT_SYMBOL_TABLE
30
31 namespace {
32
33 /// JITSymbolEntry - Each function that is JIT compiled results in one of these
34 /// being added to an array of symbols. This indicates the name of the function
35 /// as well as the address range it occupies. This allows the client to map
36 /// from a PC value to the name of the function.
37 struct JITSymbolEntry {
38 const char *FnName; // FnName - a strdup'd string.
39 void *FnStart;
40 intptr_t FnSize;
41 };
42
43
44 struct JITSymbolTable {
45 /// NextPtr - This forms a linked list of JitSymbolTable entries. This
46 /// pointer is not used right now, but might be used in the future. Consider
47 /// it reserved for future use.
48 JITSymbolTable *NextPtr;
49
50 /// Symbols - This is an array of JitSymbolEntry entries. Only the first
51 /// 'NumSymbols' symbols are valid.
52 JITSymbolEntry *Symbols;
53
54 /// NumSymbols - This indicates the number entries in the Symbols array that
55 /// are valid.
56 unsigned NumSymbols;
57
58 /// NumAllocated - This indicates the amount of space we have in the Symbols
59 /// array. This is a private field that should not be read by external tools.
60 unsigned NumAllocated;
61 };
62
63 class MacOSJITEventListener : public JITEventListener {
64 public:
65 virtual void NotifyFunctionEmitted(const Function &F,
66 void *FnStart, size_t FnSize,
67 const EmittedFunctionDetails &Details);
68 virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr);
69 };
70
71 } // anonymous namespace.
72
73 // This is a public symbol so the performance tools can find it.
74 JITSymbolTable *__jitSymbolTable;
75
76 namespace llvm {
77 JITEventListener *createMacOSJITEventListener() {
78 return new MacOSJITEventListener;
79 }
80 }
81
82 // Adds the just-emitted function to the symbol table.
83 void MacOSJITEventListener::NotifyFunctionEmitted(
84 const Function &F, void *FnStart, size_t FnSize,
85 const EmittedFunctionDetails &) {
86 const char *const FnName = F.getNameStart();
87 assert(FnName != 0 && FnStart != 0 && "Bad symbol to add");
88 JITSymbolTable **SymTabPtrPtr = 0;
89 SymTabPtrPtr = &__jitSymbolTable;
90
91 // If this is the first entry in the symbol table, add the JITSymbolTable
92 // index.
93 if (*SymTabPtrPtr == 0) {
94 JITSymbolTable *New = new JITSymbolTable();
95 New->NextPtr = 0;
96 New->Symbols = 0;
97 New->NumSymbols = 0;
98 New->NumAllocated = 0;
99 *SymTabPtrPtr = New;
100 }
101
102 JITSymbolTable *SymTabPtr = *SymTabPtrPtr;
103
104 // If we have space in the table, reallocate the table.
105 if (SymTabPtr->NumSymbols >= SymTabPtr->NumAllocated) {
106 // If we don't have space, reallocate the table.
107 unsigned NewSize = std::max(64U, SymTabPtr->NumAllocated*2);
108 JITSymbolEntry *NewSymbols = new JITSymbolEntry[NewSize];
109 JITSymbolEntry *OldSymbols = SymTabPtr->Symbols;
110
111 // Copy the old entries over.
112 memcpy(NewSymbols, OldSymbols, SymTabPtr->NumSymbols*sizeof(OldSymbols[0]));
113
114 // Swap the new symbols in, delete the old ones.
115 SymTabPtr->Symbols = NewSymbols;
116 SymTabPtr->NumAllocated = NewSize;
117 delete [] OldSymbols;
118 }
119
120 // Otherwise, we have enough space, just tack it onto the end of the array.
121 JITSymbolEntry &Entry = SymTabPtr->Symbols[SymTabPtr->NumSymbols];
122 Entry.FnName = strdup(FnName);
123 Entry.FnStart = FnStart;
124 Entry.FnSize = FnSize;
125 ++SymTabPtr->NumSymbols;
126 }
127
128 // Removes the to-be-deleted function from the symbol table.
129 void MacOSJITEventListener::NotifyFreeingMachineCode(
130 const Function &, void *FnStart) {
131 assert(FnStart && "Invalid function pointer");
132 JITSymbolTable **SymTabPtrPtr = 0;
133 SymTabPtrPtr = &__jitSymbolTable;
134
135 JITSymbolTable *SymTabPtr = *SymTabPtrPtr;
136 JITSymbolEntry *Symbols = SymTabPtr->Symbols;
137
138 // Scan the table to find its index. The table is not sorted, so do a linear
139 // scan.
140 unsigned Index;
141 for (Index = 0; Symbols[Index].FnStart != FnStart; ++Index)
142 assert(Index != SymTabPtr->NumSymbols && "Didn't find function!");
143
144 // Once we have an index, we know to nuke this entry, overwrite it with the
145 // entry at the end of the array, making the last entry redundant.
146 const char *OldName = Symbols[Index].FnName;
147 Symbols[Index] = Symbols[SymTabPtr->NumSymbols-1];
148 free((void*)OldName);
149
150 // Drop the number of symbols in the table.
151 --SymTabPtr->NumSymbols;
152
153 // Finally, if we deleted the final symbol, deallocate the table itself.
154 if (SymTabPtr->NumSymbols != 0)
155 return;
156
157 *SymTabPtrPtr = 0;
158 delete [] Symbols;
159 delete SymTabPtr;
160 }
161
162 #else // !ENABLE_JIT_SYMBOL_TABLE
163
164 namespace llvm {
165 // By defining this to return NULL, we can let clients call it unconditionally,
166 // even if they aren't on an Apple system.
167 JITEventListener *createMacOSJITEventListener() {
168 return NULL;
169 }
170 } // namespace llvm
171
172 #endif // ENABLE_JIT_SYMBOL_TABLE
1717 #include "llvm/Type.h"
1818 #include "llvm/Bitcode/ReaderWriter.h"
1919 #include "llvm/CodeGen/LinkAllCodegenComponents.h"
20 #include "llvm/ExecutionEngine/GenericValue.h"
21 #include "llvm/ExecutionEngine/Interpreter.h"
2022 #include "llvm/ExecutionEngine/JIT.h"
21 #include "llvm/ExecutionEngine/Interpreter.h"
22 #include "llvm/ExecutionEngine/GenericValue.h"
23 #include "llvm/ExecutionEngine/JITEventListener.h"
2324 #include "llvm/Support/CommandLine.h"
2425 #include "llvm/Support/ManagedStatic.h"
2526 #include "llvm/Support/MemoryBuffer.h"
147148 std::cerr << argv[0] << ":error creating EE: " << ErrorMsg << "\n";
148149 exit(1);
149150 }
151
152 EE->RegisterJITEventListener(createMacOSJITEventListener());
150153
151154 if (NoLazyCompilation)
152155 EE->DisableLazyCompilation();
0 //===- JITEventListenerTest.cpp - Unit tests for JITEventListeners --------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ExecutionEngine/JITEventListener.h"
10
11 #include "llvm/Instructions.h"
12 #include "llvm/Module.h"
13 #include "llvm/ModuleProvider.h"
14 #include "llvm/ADT/OwningPtr.h"
15 #include "llvm/CodeGen/MachineCodeInfo.h"
16 #include "llvm/ExecutionEngine/JIT.h"
17 #include "llvm/Support/TypeBuilder.h"
18 #include "llvm/Target/TargetSelect.h"
19 #include "gtest/gtest.h"
20 #include
21
22 using namespace llvm;
23
24 namespace {
25
26 struct FunctionEmittedEvent {
27 // Indices are local to the RecordingJITEventListener, since the
28 // JITEventListener interface makes no guarantees about the order of
29 // calls between Listeners.
30 unsigned Index;
31 const Function *F;
32 void *Code;
33 size_t Size;
34 JITEvent_EmittedFunctionDetails Details;
35 };
36 struct FunctionFreedEvent {
37 unsigned Index;
38 const Function *F;
39 void *Code;
40 };
41
42 struct RecordingJITEventListener : public JITEventListener {
43 std::vector EmittedEvents;
44 std::vector FreedEvents;
45
46 int NextIndex;
47
48 RecordingJITEventListener() : NextIndex(0) {}
49
50 virtual void NotifyFunctionEmitted(const Function &F,
51 void *Code, size_t Size,
52 const EmittedFunctionDetails &Details) {
53 FunctionEmittedEvent Event = {NextIndex++, &F, Code, Size, Details};
54 EmittedEvents.push_back(Event);
55 }
56
57 virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr) {
58 FunctionFreedEvent Event = {NextIndex++, &F, OldPtr};
59 FreedEvents.push_back(Event);
60 }
61 };
62
63 class JITEventListenerTest : public testing::Test {
64 protected:
65 JITEventListenerTest()
66 : M(new Module("module")),
67 EE(ExecutionEngine::createJIT(new ExistingModuleProvider(M))) {
68 }
69
70 Module *M;
71 const OwningPtr EE;
72 };
73
74 Function *buildFunction(Module *M) {
75 Function *Result = Function::Create(
76 TypeBuilder::get(),
77 GlobalValue::ExternalLinkage, "id", M);
78 Value *Arg = Result->arg_begin();
79 BasicBlock *BB = BasicBlock::Create("entry", Result);
80 ReturnInst::Create(Arg, BB);
81 return Result;
82 }
83
84 // Tests that a single JITEventListener follows JIT events accurately.
85 TEST_F(JITEventListenerTest, Simple) {
86 RecordingJITEventListener Listener;
87 EE->RegisterJITEventListener(&Listener);
88 Function *F1 = buildFunction(M);
89 Function *F2 = buildFunction(M);
90
91 void *F1_addr = EE->getPointerToFunction(F1);
92 void *F2_addr = EE->getPointerToFunction(F2);
93 EE->getPointerToFunction(F1); // Should do nothing.
94 EE->freeMachineCodeForFunction(F1);
95 EE->freeMachineCodeForFunction(F2);
96
97 ASSERT_EQ(2U, Listener.EmittedEvents.size());
98 ASSERT_EQ(2U, Listener.FreedEvents.size());
99
100 EXPECT_EQ(0U, Listener.EmittedEvents[0].Index);
101 EXPECT_EQ(F1, Listener.EmittedEvents[0].F);
102 EXPECT_EQ(F1_addr, Listener.EmittedEvents[0].Code);
103 EXPECT_LT(0U, Listener.EmittedEvents[0].Size)
104 << "We don't know how big the function will be, but it had better"
105 << " contain some bytes.";
106
107 EXPECT_EQ(1U, Listener.EmittedEvents[1].Index);
108 EXPECT_EQ(F2, Listener.EmittedEvents[1].F);
109 EXPECT_EQ(F2_addr, Listener.EmittedEvents[1].Code);
110 EXPECT_LT(0U, Listener.EmittedEvents[1].Size)
111 << "We don't know how big the function will be, but it had better"
112 << " contain some bytes.";
113
114 EXPECT_EQ(2U, Listener.FreedEvents[0].Index);
115 EXPECT_EQ(F1, Listener.FreedEvents[0].F);
116 EXPECT_EQ(F1_addr, Listener.FreedEvents[0].Code);
117
118 EXPECT_EQ(3U, Listener.FreedEvents[1].Index);
119 EXPECT_EQ(F2, Listener.FreedEvents[1].F);
120 EXPECT_EQ(F2_addr, Listener.FreedEvents[1].Code);
121
122 F1->eraseFromParent();
123 F2->eraseFromParent();
124 }
125
126 // Tests that a single JITEventListener follows JIT events accurately.
127 TEST_F(JITEventListenerTest, MultipleListenersDontInterfere) {
128 RecordingJITEventListener Listener1;
129 RecordingJITEventListener Listener2;
130 RecordingJITEventListener Listener3;
131 Function *F1 = buildFunction(M);
132 Function *F2 = buildFunction(M);
133
134 EE->RegisterJITEventListener(&Listener1);
135 EE->RegisterJITEventListener(&Listener2);
136 void *F1_addr = EE->getPointerToFunction(F1);
137 EE->RegisterJITEventListener(&Listener3);
138 EE->UnregisterJITEventListener(&Listener1);
139 void *F2_addr = EE->getPointerToFunction(F2);
140 EE->UnregisterJITEventListener(&Listener2);
141 EE->UnregisterJITEventListener(&Listener3);
142 EE->freeMachineCodeForFunction(F1);
143 EE->RegisterJITEventListener(&Listener2);
144 EE->RegisterJITEventListener(&Listener3);
145 EE->RegisterJITEventListener(&Listener1);
146 EE->freeMachineCodeForFunction(F2);
147 EE->UnregisterJITEventListener(&Listener1);
148 EE->UnregisterJITEventListener(&Listener2);
149 EE->UnregisterJITEventListener(&Listener3);
150
151 // Listener 1.
152 ASSERT_EQ(1U, Listener1.EmittedEvents.size());
153 ASSERT_EQ(1U, Listener1.FreedEvents.size());
154
155 EXPECT_EQ(0U, Listener1.EmittedEvents[0].Index);
156 EXPECT_EQ(F1, Listener1.EmittedEvents[0].F);
157 EXPECT_EQ(F1_addr, Listener1.EmittedEvents[0].Code);
158 EXPECT_LT(0U, Listener1.EmittedEvents[0].Size)
159 << "We don't know how big the function will be, but it had better"
160 << " contain some bytes.";
161
162 EXPECT_EQ(1U, Listener1.FreedEvents[0].Index);
163 EXPECT_EQ(F2, Listener1.FreedEvents[0].F);
164 EXPECT_EQ(F2_addr, Listener1.FreedEvents[0].Code);
165
166 // Listener 2.
167 ASSERT_EQ(2U, Listener2.EmittedEvents.size());
168 ASSERT_EQ(1U, Listener2.FreedEvents.size());
169
170 EXPECT_EQ(0U, Listener2.EmittedEvents[0].Index);
171 EXPECT_EQ(F1, Listener2.EmittedEvents[0].F);
172 EXPECT_EQ(F1_addr, Listener2.EmittedEvents[0].Code);
173 EXPECT_LT(0U, Listener2.EmittedEvents[0].Size)
174 << "We don't know how big the function will be, but it had better"
175 << " contain some bytes.";
176
177 EXPECT_EQ(1U, Listener2.EmittedEvents[1].Index);
178 EXPECT_EQ(F2, Listener2.EmittedEvents[1].F);
179 EXPECT_EQ(F2_addr, Listener2.EmittedEvents[1].Code);
180 EXPECT_LT(0U, Listener2.EmittedEvents[1].Size)
181 << "We don't know how big the function will be, but it had better"
182 << " contain some bytes.";
183
184 EXPECT_EQ(2U, Listener2.FreedEvents[0].Index);
185 EXPECT_EQ(F2, Listener2.FreedEvents[0].F);
186 EXPECT_EQ(F2_addr, Listener2.FreedEvents[0].Code);
187
188 // Listener 3.
189 ASSERT_EQ(1U, Listener3.EmittedEvents.size());
190 ASSERT_EQ(1U, Listener3.FreedEvents.size());
191
192 EXPECT_EQ(0U, Listener3.EmittedEvents[0].Index);
193 EXPECT_EQ(F2, Listener3.EmittedEvents[0].F);
194 EXPECT_EQ(F2_addr, Listener3.EmittedEvents[0].Code);
195 EXPECT_LT(0U, Listener3.EmittedEvents[0].Size)
196 << "We don't know how big the function will be, but it had better"
197 << " contain some bytes.";
198
199 EXPECT_EQ(1U, Listener3.FreedEvents[0].Index);
200 EXPECT_EQ(F2, Listener3.FreedEvents[0].F);
201 EXPECT_EQ(F2_addr, Listener3.FreedEvents[0].Code);
202
203 F1->eraseFromParent();
204 F2->eraseFromParent();
205 }
206
207 TEST_F(JITEventListenerTest, MatchesMachineCodeInfo) {
208 RecordingJITEventListener Listener;
209 MachineCodeInfo MCI;
210 Function *F = buildFunction(M);
211
212 EE->RegisterJITEventListener(&Listener);
213 EE->runJITOnFunction(F, &MCI);
214 void *F_addr = EE->getPointerToFunction(F);
215 EE->freeMachineCodeForFunction(F);
216
217 ASSERT_EQ(1U, Listener.EmittedEvents.size());
218 ASSERT_EQ(1U, Listener.FreedEvents.size());
219
220 EXPECT_EQ(0U, Listener.EmittedEvents[0].Index);
221 EXPECT_EQ(F, Listener.EmittedEvents[0].F);
222 EXPECT_EQ(F_addr, Listener.EmittedEvents[0].Code);
223 EXPECT_EQ(MCI.address(), Listener.EmittedEvents[0].Code);
224 EXPECT_EQ(MCI.size(), Listener.EmittedEvents[0].Size);
225
226 EXPECT_EQ(1U, Listener.FreedEvents[0].Index);
227 EXPECT_EQ(F, Listener.FreedEvents[0].F);
228 EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code);
229 }
230
231 class JITEnvironment : public testing::Environment {
232 virtual void SetUp() {
233 // Required for ExecutionEngine::createJIT to create a JIT.
234 InitializeNativeTarget();
235 }
236 };
237 testing::Environment* const jit_env =
238 testing::AddGlobalTestEnvironment(new JITEnvironment);
239
240 } // anonymous namespace
0 ##===- unittests/ExecutionEngine/JIT/Makefile --------------*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file is distributed under the University of Illinois Open Source
5 # License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8
9 LEVEL = ../../..
10 TESTNAME = JIT
11 LINK_COMPONENTS := core support jit native
12
13 include $(LEVEL)/Makefile.config
14 include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
0 ##===- unittests/ExecutionEngine/Makefile ------------------*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file is distributed under the University of Illinois Open Source
5 # License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8
9 LEVEL = ../..
10
11 include $(LEVEL)/Makefile.config
12
13 PARALLEL_DIRS = JIT
14
15 include $(LEVEL)/Makefile.common
16
17 clean::
18 $(Verb) $(RM) -f *Tests
1515 CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include/
1616 CPP.Flags += -Wno-variadic-macros
1717
18 PARALLEL_DIRS = ADT Support VMCore MC
18 PARALLEL_DIRS = ADT ExecutionEngine Support VMCore MC
1919
2020 include $(LEVEL)/Makefile.common
2121