llvm.org GIT mirror llvm / 7a9034c
Automatically do the equivalent of freeMachineCodeForFunction(F) when F is being destroyed. This allows users to run global optimizations like globaldce even after some functions have been jitted. This patch also removes the Function* parameter to JITEventListener::NotifyFreeingMachineCode() since it can cause that to be called when the Function is partially destroyed. This change will be even more helpful later when I think we'll want to allow machine code to actually outlive its Function. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85182 91177308-0d34-0410-b5e6-96231b3b80d8 Jeffrey Yasskin 10 years ago
8 changed file(s) with 209 addition(s) and 35 deletion(s). Raw diff Collapse all Expand all
262262 /// getPointerToFunction - The different EE's represent function bodies in
263263 /// different ways. They should each implement this to say what a function
264264 /// pointer should look like. When F is destroyed, the ExecutionEngine will
265 /// remove its global mapping but will not yet free its machine code. Call
266 /// freeMachineCodeForFunction(F) explicitly to do that. Note that global
267 /// optimizations can destroy Functions without notifying the ExecutionEngine.
265 /// remove its global mapping and free any machine code. Be sure no threads
266 /// are running inside F when that happens.
268267 ///
269268 virtual void *getPointerToFunction(Function *F) = 0;
270269
6262 /// NotifyFreeingMachineCode - This is called inside of
6363 /// freeMachineCodeForFunction(), after the global mapping is removed, but
6464 /// before the machine code is returned to the allocator. OldPtr is the
65 /// address of the machine code.
66 virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr) {}
65 /// address of the machine code and will be the same as the Code parameter to
66 /// a previous NotifyFunctionEmitted call. The Function passed to
67 /// NotifyFunctionEmitted may have been destroyed by the time of the matching
68 /// NotifyFreeingMachineCode call.
69 virtual void NotifyFreeingMachineCode(void *OldPtr) {}
6770 };
6871
6972 // This returns NULL if support isn't available.
555555 }
556556 }
557557
558 void JIT::NotifyFreeingMachineCode(const Function &F, void *OldPtr) {
558 void JIT::NotifyFreeingMachineCode(void *OldPtr) {
559559 MutexGuard locked(lock);
560560 for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
561 EventListeners[I]->NotifyFreeingMachineCode(F, OldPtr);
561 EventListeners[I]->NotifyFreeingMachineCode(OldPtr);
562562 }
563563 }
564564
182182 void NotifyFunctionEmitted(
183183 const Function &F, void *Code, size_t Size,
184184 const JITEvent_EmittedFunctionDetails &Details);
185 void NotifyFreeingMachineCode(const Function &F, void *OldPtr);
185 void NotifyFreeingMachineCode(void *OldPtr);
186186
187187 private:
188188 static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM,
581581 JITEvent_EmittedFunctionDetails EmissionDetails;
582582
583583 struct EmittedCode {
584 void *FunctionBody;
584 void *FunctionBody; // Beginning of the function's allocation.
585 void *Code; // The address the function's code actually starts at.
585586 void *ExceptionTable;
586 EmittedCode() : FunctionBody(0), ExceptionTable(0) {}
587 EmittedCode() : FunctionBody(0), Code(0), ExceptionTable(0) {}
587588 };
588 DenseMap EmittedFunctions;
589 struct EmittedFunctionConfig : public ValueMapConfig {
590 typedef JITEmitter *ExtraData;
591 static void onDelete(JITEmitter *, const Function*);
592 static void onRAUW(JITEmitter *, const Function*, const Function*);
593 };
594 ValueMap
595 EmittedFunctionConfig> EmittedFunctions;
589596
590597 // CurFnStubUses - For a given Function, a vector of stubs that it
591598 // references. This facilitates the JIT detecting that a stub is no
592599 // longer used, so that it may be deallocated.
593 DenseMap > CurFnStubUses;
594
600 DenseMap, SmallVector > CurFnStubUses;
601
595602 // StubFnRefs - For a given pointer to a stub, a set of Functions which
596603 // reference the stub. When the count of a stub's references drops to zero,
597604 // the stub is unused.
605612
606613 public:
607614 JITEmitter(JIT &jit, JITMemoryManager *JMM, TargetMachine &TM)
608 : SizeEstimate(0), Resolver(jit), MMI(0), CurFn(0) {
615 : SizeEstimate(0), Resolver(jit), MMI(0), CurFn(0),
616 EmittedFunctions(this) {
609617 MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager();
610618 if (jit.getJITInfo().needsGOT()) {
611619 MemMgr->AllocateGOT();
10611069 // About to start emitting the machine code for the function.
10621070 emitAlignment(std::max(F.getFunction()->getAlignment(), 8U));
10631071 TheJIT->updateGlobalMapping(F.getFunction(), CurBufferPtr);
1072 EmittedFunctions[F.getFunction()].Code = CurBufferPtr;
10641073
10651074 MBBLocations.clear();
10661075
12841293
12851294 /// deallocateMemForFunction - Deallocate all memory for the specified
12861295 /// function body. Also drop any references the function has to stubs.
1296 /// May be called while the Function is being destroyed inside ~Value().
12871297 void JITEmitter::deallocateMemForFunction(const Function *F) {
1288 DenseMap::iterator Emitted =
1289 EmittedFunctions.find(F);
1298 ValueMap::iterator
1299 Emitted = EmittedFunctions.find(F);
12901300 if (Emitted != EmittedFunctions.end()) {
12911301 MemMgr->deallocateFunctionBody(Emitted->second.FunctionBody);
12921302 MemMgr->deallocateExceptionTable(Emitted->second.ExceptionTable);
1303 TheJIT->NotifyFreeingMachineCode(Emitted->second.Code);
1304
12931305 EmittedFunctions.erase(Emitted);
12941306 }
12951307
15181530 return (uintptr_t)((char *)JumpTableBase + Offset);
15191531 }
15201532
1533 void JITEmitter::EmittedFunctionConfig::onDelete(
1534 JITEmitter *Emitter, const Function *F) {
1535 Emitter->deallocateMemForFunction(F);
1536 }
1537 void JITEmitter::EmittedFunctionConfig::onRAUW(
1538 JITEmitter *, const Function*, const Function*) {
1539 llvm_unreachable("The JIT doesn't know how to handle a"
1540 " RAUW on a value it has emitted.");
1541 }
1542
1543
15211544 //===----------------------------------------------------------------------===//
15221545 // Public interface to this file
15231546 //===----------------------------------------------------------------------===//
16561679 /// freeMachineCodeForFunction - release machine code memory for given Function.
16571680 ///
16581681 void JIT::freeMachineCodeForFunction(Function *F) {
1659
16601682 // Delete translation for this from the ExecutionEngine, so it will get
16611683 // retranslated next time it is used.
1662 void *OldPtr = updateGlobalMapping(F, 0);
1663
1664 if (OldPtr)
1665 TheJIT->NotifyFreeingMachineCode(*F, OldPtr);
1684 updateGlobalMapping(F, 0);
16661685
16671686 // Free the actual memory for the function body and related stuff.
16681687 assert(isa(JCE) && "Unexpected MCE?");
146146 }
147147 }
148148
149 // Removes the to-be-deleted function from the symbol table.
150 void OProfileJITEventListener::NotifyFreeingMachineCode(
151 const Function &F, void *FnStart) {
149 // Removes the being-deleted function from the symbol table.
150 void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
152151 assert(FnStart && "Invalid function pointer");
153152 if (op_unload_native_code(Agent, reinterpret_cast(FnStart)) == -1) {
154 DEBUG(errs() << "Failed to tell OProfile about unload of native function "
155 << F.getName() << " at " << FnStart << "\n");
153 DEBUG(errs()
154 << "Failed to tell OProfile about unload of native function at "
155 << FnStart << "\n");
156156 }
157157 }
158158
3636 };
3737 struct FunctionFreedEvent {
3838 unsigned Index;
39 const Function *F;
4039 void *Code;
4140 };
4241
5554 EmittedEvents.push_back(Event);
5655 }
5756
58 virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr) {
59 FunctionFreedEvent Event = {NextIndex++, &F, OldPtr};
57 virtual void NotifyFreeingMachineCode(void *OldPtr) {
58 FunctionFreedEvent Event = {NextIndex++, OldPtr};
6059 FreedEvents.push_back(Event);
6160 }
6261 };
115114 << " contain some bytes.";
116115
117116 EXPECT_EQ(2U, Listener.FreedEvents[0].Index);
118 EXPECT_EQ(F1, Listener.FreedEvents[0].F);
119117 EXPECT_EQ(F1_addr, Listener.FreedEvents[0].Code);
120118
121119 EXPECT_EQ(3U, Listener.FreedEvents[1].Index);
122 EXPECT_EQ(F2, Listener.FreedEvents[1].F);
123120 EXPECT_EQ(F2_addr, Listener.FreedEvents[1].Code);
124121
125122 F1->eraseFromParent();
163160 << " contain some bytes.";
164161
165162 EXPECT_EQ(1U, Listener1.FreedEvents[0].Index);
166 EXPECT_EQ(F2, Listener1.FreedEvents[0].F);
167163 EXPECT_EQ(F2_addr, Listener1.FreedEvents[0].Code);
168164
169165 // Listener 2.
185181 << " contain some bytes.";
186182
187183 EXPECT_EQ(2U, Listener2.FreedEvents[0].Index);
188 EXPECT_EQ(F2, Listener2.FreedEvents[0].F);
189184 EXPECT_EQ(F2_addr, Listener2.FreedEvents[0].Code);
190185
191186 // Listener 3.
200195 << " contain some bytes.";
201196
202197 EXPECT_EQ(1U, Listener3.FreedEvents[0].Index);
203 EXPECT_EQ(F2, Listener3.FreedEvents[0].F);
204198 EXPECT_EQ(F2_addr, Listener3.FreedEvents[0].Code);
205199
206200 F1->eraseFromParent();
227221 EXPECT_EQ(MCI.size(), Listener.EmittedEvents[0].Size);
228222
229223 EXPECT_EQ(1U, Listener.FreedEvents[0].Index);
230 EXPECT_EQ(F, Listener.FreedEvents[0].F);
231224 EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code);
232225 }
233226
88
99 #include "gtest/gtest.h"
1010 #include "llvm/ADT/OwningPtr.h"
11 #include "llvm/ADT/SmallPtrSet.h"
1112 #include "llvm/Assembly/Parser.h"
1213 #include "llvm/BasicBlock.h"
1314 #include "llvm/Constant.h"
2728 #include "llvm/Target/TargetSelect.h"
2829 #include "llvm/Type.h"
2930
31 #include
32
3033 using namespace llvm;
3134
3235 namespace {
4649 return F;
4750 }
4851
52 std::string DumpFunction(const Function *F) {
53 std::string Result;
54 raw_string_ostream(Result) << "" << *F;
55 return Result;
56 }
57
58 class RecordingJITMemoryManager : public JITMemoryManager {
59 const OwningPtr Base;
60 public:
61 RecordingJITMemoryManager()
62 : Base(JITMemoryManager::CreateDefaultMemManager()) {
63 }
64
65 virtual void setMemoryWritable() { Base->setMemoryWritable(); }
66 virtual void setMemoryExecutable() { Base->setMemoryExecutable(); }
67 virtual void setPoisonMemory(bool poison) { Base->setPoisonMemory(poison); }
68 virtual void AllocateGOT() { Base->AllocateGOT(); }
69 virtual uint8_t *getGOTBase() const { return Base->getGOTBase(); }
70 virtual void SetDlsymTable(void *ptr) { Base->SetDlsymTable(ptr); }
71 virtual void *getDlsymTable() const { return Base->getDlsymTable(); }
72 struct StartFunctionBodyCall {
73 StartFunctionBodyCall(uint8_t *Result, const Function *F,
74 uintptr_t ActualSize, uintptr_t ActualSizeResult)
75 : Result(Result), F(F), F_dump(DumpFunction(F)),
76 ActualSize(ActualSize), ActualSizeResult(ActualSizeResult) {}
77 uint8_t *Result;
78 const Function *F;
79 std::string F_dump;
80 uintptr_t ActualSize;
81 uintptr_t ActualSizeResult;
82 };
83 std::vector startFunctionBodyCalls;
84 virtual uint8_t *startFunctionBody(const Function *F,
85 uintptr_t &ActualSize) {
86 uintptr_t InitialActualSize = ActualSize;
87 uint8_t *Result = Base->startFunctionBody(F, ActualSize);
88 startFunctionBodyCalls.push_back(
89 StartFunctionBodyCall(Result, F, InitialActualSize, ActualSize));
90 return Result;
91 }
92 virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
93 unsigned Alignment) {
94 return Base->allocateStub(F, StubSize, Alignment);
95 }
96 struct EndFunctionBodyCall {
97 EndFunctionBodyCall(const Function *F, uint8_t *FunctionStart,
98 uint8_t *FunctionEnd)
99 : F(F), F_dump(DumpFunction(F)),
100 FunctionStart(FunctionStart), FunctionEnd(FunctionEnd) {}
101 const Function *F;
102 std::string F_dump;
103 uint8_t *FunctionStart;
104 uint8_t *FunctionEnd;
105 };
106 std::vector endFunctionBodyCalls;
107 virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart,
108 uint8_t *FunctionEnd) {
109 endFunctionBodyCalls.push_back(
110 EndFunctionBodyCall(F, FunctionStart, FunctionEnd));
111 Base->endFunctionBody(F, FunctionStart, FunctionEnd);
112 }
113 virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
114 return Base->allocateSpace(Size, Alignment);
115 }
116 virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
117 return Base->allocateGlobal(Size, Alignment);
118 }
119 struct DeallocateFunctionBodyCall {
120 DeallocateFunctionBodyCall(const void *Body) : Body(Body) {}
121 const void *Body;
122 };
123 std::vector deallocateFunctionBodyCalls;
124 virtual void deallocateFunctionBody(void *Body) {
125 deallocateFunctionBodyCalls.push_back(DeallocateFunctionBodyCall(Body));
126 Base->deallocateFunctionBody(Body);
127 }
128 struct DeallocateExceptionTableCall {
129 DeallocateExceptionTableCall(const void *ET) : ET(ET) {}
130 const void *ET;
131 };
132 std::vector deallocateExceptionTableCalls;
133 virtual void deallocateExceptionTable(void *ET) {
134 deallocateExceptionTableCalls.push_back(DeallocateExceptionTableCall(ET));
135 Base->deallocateExceptionTable(ET);
136 }
137 struct StartExceptionTableCall {
138 StartExceptionTableCall(uint8_t *Result, const Function *F,
139 uintptr_t ActualSize, uintptr_t ActualSizeResult)
140 : Result(Result), F(F), F_dump(DumpFunction(F)),
141 ActualSize(ActualSize), ActualSizeResult(ActualSizeResult) {}
142 uint8_t *Result;
143 const Function *F;
144 std::string F_dump;
145 uintptr_t ActualSize;
146 uintptr_t ActualSizeResult;
147 };
148 std::vector startExceptionTableCalls;
149 virtual uint8_t* startExceptionTable(const Function* F,
150 uintptr_t &ActualSize) {
151 uintptr_t InitialActualSize = ActualSize;
152 uint8_t *Result = Base->startExceptionTable(F, ActualSize);
153 startExceptionTableCalls.push_back(
154 StartExceptionTableCall(Result, F, InitialActualSize, ActualSize));
155 return Result;
156 }
157 struct EndExceptionTableCall {
158 EndExceptionTableCall(const Function *F, uint8_t *TableStart,
159 uint8_t *TableEnd, uint8_t* FrameRegister)
160 : F(F), F_dump(DumpFunction(F)),
161 TableStart(TableStart), TableEnd(TableEnd),
162 FrameRegister(FrameRegister) {}
163 const Function *F;
164 std::string F_dump;
165 uint8_t *TableStart;
166 uint8_t *TableEnd;
167 uint8_t *FrameRegister;
168 };
169 std::vector endExceptionTableCalls;
170 virtual void endExceptionTable(const Function *F, uint8_t *TableStart,
171 uint8_t *TableEnd, uint8_t* FrameRegister) {
172 endExceptionTableCalls.push_back(
173 EndExceptionTableCall(F, TableStart, TableEnd, FrameRegister));
174 return Base->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
175 }
176 };
177
49178 class JITTest : public testing::Test {
50179 protected:
51180 virtual void SetUp() {
52181 M = new Module("
", Context);
53182 MP = new ExistingModuleProvider(M);
183 RJMM = new RecordingJITMemoryManager;
54184 std::string Error;
55185 TheJIT.reset(EngineBuilder(MP).setEngineKind(EngineKind::JIT)
186 .setJITMemoryManager(RJMM)
56187 .setErrorStr(&Error).create());
57188 ASSERT_TRUE(TheJIT.get() != NULL) << Error;
58189 }
69200 LLVMContext Context;
70201 Module *M; // Owned by MP.
71202 ModuleProvider *MP; // Owned by ExecutionEngine.
203 RecordingJITMemoryManager *RJMM;
72204 OwningPtr TheJIT;
73205 };
74206
288420 Function *func = M->getFunction("main");
289421 TheJIT->getPointerToFunction(func);
290422 TheJIT->deleteModuleProvider(MP);
423
424 SmallPtrSet FunctionsDeallocated;
425 for (unsigned i = 0, e = RJMM->deallocateFunctionBodyCalls.size();
426 i != e; ++i) {
427 FunctionsDeallocated.insert(RJMM->deallocateFunctionBodyCalls[i].Body);
428 }
429 for (unsigned i = 0, e = RJMM->startFunctionBodyCalls.size(); i != e; ++i) {
430 EXPECT_TRUE(FunctionsDeallocated.count(
431 RJMM->startFunctionBodyCalls[i].Result))
432 << "Function leaked: \n" << RJMM->startFunctionBodyCalls[i].F_dump;
433 }
434 EXPECT_EQ(RJMM->startFunctionBodyCalls.size(),
435 RJMM->deallocateFunctionBodyCalls.size());
436
437 SmallPtrSet ExceptionTablesDeallocated;
438 for (unsigned i = 0, e = RJMM->deallocateExceptionTableCalls.size();
439 i != e; ++i) {
440 ExceptionTablesDeallocated.insert(
441 RJMM->deallocateExceptionTableCalls[i].ET);
442 }
443 for (unsigned i = 0, e = RJMM->startExceptionTableCalls.size(); i != e; ++i) {
444 EXPECT_TRUE(ExceptionTablesDeallocated.count(
445 RJMM->startExceptionTableCalls[i].Result))
446 << "Function's exception table leaked: \n"
447 << RJMM->startExceptionTableCalls[i].F_dump;
448 }
449 EXPECT_EQ(RJMM->startExceptionTableCalls.size(),
450 RJMM->deallocateExceptionTableCalls.size());
291451 }
292452
293453 // This code is copied from JITEventListenerTest, but it only runs once for all