diff options
Diffstat (limited to 'lib/ExecutionEngine')
-rw-r--r-- | lib/ExecutionEngine/ExecutionEngine.cpp | 47 | ||||
-rw-r--r-- | lib/ExecutionEngine/Interpreter/Execution.cpp | 41 | ||||
-rw-r--r-- | lib/ExecutionEngine/Interpreter/Interpreter.h | 7 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JIT.cpp | 10 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JIT.h | 7 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITDebugRegisterer.h | 2 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITEmitter.cpp | 111 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp | 172 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp | 12 |
9 files changed, 150 insertions, 259 deletions
diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index 053d960..21499e5 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -49,7 +49,7 @@ ExecutionEngine::EERegisterFn ExecutionEngine::ExceptionTableRegister = 0; ExecutionEngine::ExecutionEngine(ModuleProvider *P) : EEState(*this), LazyFunctionCreator(0) { - LazyCompilationDisabled = false; + CompilingLazily = false; GVCompilationDisabled = false; SymbolSearchingDisabled = false; DlsymStubsEnabled = false; @@ -117,8 +117,7 @@ Function *ExecutionEngine::FindFunctionNamed(const char *FnName) { void *ExecutionEngineState::RemoveMapping( const MutexGuard &, const GlobalValue *ToUnmap) { - std::map<MapUpdatingCVH, void *>::iterator I = - GlobalAddressMap.find(getVH(ToUnmap)); + GlobalAddressMapTy::iterator I = GlobalAddressMap.find(ToUnmap); void *OldVal; if (I == GlobalAddressMap.end()) OldVal = 0; @@ -141,7 +140,7 @@ void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) { DEBUG(errs() << "JIT: Map \'" << GV->getName() << "\' to [" << Addr << "]\n";); - void *&CurVal = EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)]; + void *&CurVal = EEState.getGlobalAddressMap(locked)[GV]; assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!"); CurVal = Addr; @@ -183,7 +182,7 @@ void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) { void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) { MutexGuard locked(lock); - std::map<ExecutionEngineState::MapUpdatingCVH, void *> &Map = + ExecutionEngineState::GlobalAddressMapTy &Map = EEState.getGlobalAddressMap(locked); // Deleting from the mapping? @@ -191,7 +190,7 @@ void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) { return EEState.RemoveMapping(locked, GV); } - void *&CurVal = Map[EEState.getVH(GV)]; + void *&CurVal = Map[GV]; void *OldVal = CurVal; if (CurVal && !EEState.getGlobalAddressReverseMap(locked).empty()) @@ -214,8 +213,8 @@ void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) { void *ExecutionEngine::getPointerToGlobalIfAvailable(const GlobalValue *GV) { MutexGuard locked(lock); - std::map<ExecutionEngineState::MapUpdatingCVH, void*>::iterator I = - EEState.getGlobalAddressMap(locked).find(EEState.getVH(GV)); + ExecutionEngineState::GlobalAddressMapTy::iterator I = + EEState.getGlobalAddressMap(locked).find(GV); return I != EEState.getGlobalAddressMap(locked).end() ? I->second : 0; } @@ -227,7 +226,7 @@ const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) { // If we haven't computed the reverse mapping yet, do so first. if (EEState.getGlobalAddressReverseMap(locked).empty()) { - for (std::map<ExecutionEngineState::MapUpdatingCVH, void *>::iterator + for (ExecutionEngineState::GlobalAddressMapTy::iterator I = EEState.getGlobalAddressMap(locked).begin(), E = EEState.getGlobalAddressMap(locked).end(); I != E; ++I) EEState.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second, @@ -476,7 +475,7 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) { return getPointerToFunction(F); MutexGuard locked(lock); - void *p = EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)]; + void *p = EEState.getGlobalAddressMap(locked)[GV]; if (p) return p; @@ -486,7 +485,7 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) { EmitGlobalVariable(GVar); else llvm_unreachable("Global hasn't had an address allocated yet!"); - return EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)]; + return EEState.getGlobalAddressMap(locked)[GV]; } /// This function converts a Constant* into a GenericValue. The interesting @@ -761,8 +760,11 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { Result.PointerVal = 0; else if (const Function *F = dyn_cast<Function>(C)) Result = PTOGV(getPointerToFunctionOrStub(const_cast<Function*>(F))); - else if (const GlobalVariable* GV = dyn_cast<GlobalVariable>(C)) + else if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) Result = PTOGV(getOrEmitGlobalVariable(const_cast<GlobalVariable*>(GV))); + else if (const BlockAddress *BA = dyn_cast<BlockAddress>(C)) + Result = PTOGV(getPointerToBasicBlock(const_cast<BasicBlock*>( + BA->getBasicBlock()))); else llvm_unreachable("Unknown constant pointer type!"); break; @@ -1072,17 +1074,22 @@ void ExecutionEngine::EmitGlobalVariable(const GlobalVariable *GV) { ++NumGlobals; } -ExecutionEngineState::MapUpdatingCVH::MapUpdatingCVH( - ExecutionEngineState &EES, const GlobalValue *GV) - : CallbackVH(const_cast<GlobalValue*>(GV)), EES(EES) {} +ExecutionEngineState::ExecutionEngineState(ExecutionEngine &EE) + : EE(EE), GlobalAddressMap(this) { +} -void ExecutionEngineState::MapUpdatingCVH::deleted() { - MutexGuard locked(EES.EE.lock); - EES.RemoveMapping(locked, *this); // Destroys *this. +sys::Mutex *ExecutionEngineState::AddressMapConfig::getMutex( + ExecutionEngineState *EES) { + return &EES->EE.lock; +} +void ExecutionEngineState::AddressMapConfig::onDelete( + ExecutionEngineState *EES, const GlobalValue *Old) { + void *OldVal = EES->GlobalAddressMap.lookup(Old); + EES->GlobalAddressReverseMap.erase(OldVal); } -void ExecutionEngineState::MapUpdatingCVH::allUsesReplacedWith( - Value *new_value) { +void ExecutionEngineState::AddressMapConfig::onRAUW( + ExecutionEngineState *, const GlobalValue *, const GlobalValue *) { assert(false && "The ExecutionEngine doesn't know how to handle a" " RAUW on a value it has a global mapping for."); } diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp index f8c775e..01bd2c7 100644 --- a/lib/ExecutionEngine/Interpreter/Execution.cpp +++ b/lib/ExecutionEngine/Interpreter/Execution.cpp @@ -572,9 +572,9 @@ void Interpreter::exitCalled(GenericValue GV) { // runAtExitHandlers() assumes there are no stack frames, but // if exit() was called, then it had a stack frame. Blow away // the stack before interpreting atexit handlers. - ECStack.clear (); - runAtExitHandlers (); - exit (GV.IntVal.zextOrTrunc(32).getZExtValue()); + ECStack.clear(); + runAtExitHandlers(); + exit(GV.IntVal.zextOrTrunc(32).getZExtValue()); } /// Pop the last stack frame off of ECStack and then copy the result @@ -585,8 +585,8 @@ void Interpreter::exitCalled(GenericValue GV) { /// care of switching to the normal destination BB, if we are returning /// from an invoke. /// -void Interpreter::popStackAndReturnValueToCaller (const Type *RetTy, - GenericValue Result) { +void Interpreter::popStackAndReturnValueToCaller(const Type *RetTy, + GenericValue Result) { // Pop the current stack frame. ECStack.pop_back(); @@ -629,15 +629,15 @@ void Interpreter::visitUnwindInst(UnwindInst &I) { // Unwind stack Instruction *Inst; do { - ECStack.pop_back (); - if (ECStack.empty ()) + ECStack.pop_back(); + if (ECStack.empty()) llvm_report_error("Empty stack during unwind!"); - Inst = ECStack.back ().Caller.getInstruction (); - } while (!(Inst && isa<InvokeInst> (Inst))); + Inst = ECStack.back().Caller.getInstruction(); + } while (!(Inst && isa<InvokeInst>(Inst))); // Return from invoke - ExecutionContext &InvokingSF = ECStack.back (); - InvokingSF.Caller = CallSite (); + ExecutionContext &InvokingSF = ECStack.back(); + InvokingSF.Caller = CallSite(); // Go to exceptional destination BB of invoke instruction SwitchToNewBasicBlock(cast<InvokeInst>(Inst)->getUnwindDest(), InvokingSF); @@ -678,6 +678,13 @@ void Interpreter::visitSwitchInst(SwitchInst &I) { SwitchToNewBasicBlock(Dest, SF); } +void Interpreter::visitIndirectBrInst(IndirectBrInst &I) { + ExecutionContext &SF = ECStack.back(); + void *Dest = GVTOP(getOperandValue(I.getAddress(), SF)); + SwitchToNewBasicBlock((BasicBlock*)Dest, SF); +} + + // SwitchToNewBasicBlock - This method is used to jump to a new basic block. // This function handles the actual updating of block and instruction iterators // as well as execution of all of the PHI nodes in the destination block. @@ -720,7 +727,7 @@ void Interpreter::SwitchToNewBasicBlock(BasicBlock *Dest, ExecutionContext &SF){ // Memory Instruction Implementations //===----------------------------------------------------------------------===// -void Interpreter::visitAllocationInst(AllocationInst &I) { +void Interpreter::visitAllocaInst(AllocaInst &I) { ExecutionContext &SF = ECStack.back(); const Type *Ty = I.getType()->getElementType(); // Type to be allocated @@ -749,14 +756,6 @@ void Interpreter::visitAllocationInst(AllocationInst &I) { ECStack.back().Allocas.add(Memory); } -void Interpreter::visitFreeInst(FreeInst &I) { - ExecutionContext &SF = ECStack.back(); - assert(isa<PointerType>(I.getOperand(0)->getType()) && "Freeing nonptr?"); - GenericValue Value = getOperandValue(I.getOperand(0), SF); - // TODO: Check to make sure memory is allocated - free(GVTOP(Value)); // Free memory -} - // getElementOffset - The workhorse for getelementptr. // GenericValue Interpreter::executeGEPOperation(Value *Ptr, gep_type_iterator I, @@ -835,7 +834,7 @@ void Interpreter::visitCallSite(CallSite CS) { // Check to see if this is an intrinsic function call... Function *F = CS.getCalledFunction(); - if (F && F->isDeclaration ()) + if (F && F->isDeclaration()) switch (F->getIntrinsicID()) { case Intrinsic::not_intrinsic: break; diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h index e026287..038830c 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.h +++ b/lib/ExecutionEngine/Interpreter/Interpreter.h @@ -19,7 +19,7 @@ #include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/CallSite.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/InstVisitor.h" #include "llvm/Support/raw_ostream.h" @@ -135,12 +135,12 @@ public: void visitReturnInst(ReturnInst &I); void visitBranchInst(BranchInst &I); void visitSwitchInst(SwitchInst &I); + void visitIndirectBrInst(IndirectBrInst &I); void visitBinaryOperator(BinaryOperator &I); void visitICmpInst(ICmpInst &I); void visitFCmpInst(FCmpInst &I); - void visitAllocationInst(AllocationInst &I); - void visitFreeInst(FreeInst &I); + void visitAllocaInst(AllocaInst &I); void visitLoadInst(LoadInst &I); void visitStoreInst(StoreInst &I); void visitGetElementPtrInst(GetElementPtrInst &I); @@ -203,6 +203,7 @@ private: // Helper functions void SwitchToNewBasicBlock(BasicBlock *Dest, ExecutionContext &SF); void *getPointerToFunction(Function *F) { return (void*)F; } + void *getPointerToBasicBlock(BasicBlock *BB) { return (void*)BB; } void initializeExecutionEngine() { } void initializeExternalFunctions(); diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index b2a268b..e21d760 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -556,10 +556,10 @@ void JIT::NotifyFunctionEmitted( } } -void JIT::NotifyFreeingMachineCode(const Function &F, void *OldPtr) { +void JIT::NotifyFreeingMachineCode(void *OldPtr) { MutexGuard locked(lock); for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { - EventListeners[I]->NotifyFreeingMachineCode(F, OldPtr); + EventListeners[I]->NotifyFreeingMachineCode(OldPtr); } } @@ -599,7 +599,7 @@ void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) { isAlreadyCodeGenerating = false; // If the function referred to another function that had not yet been - // read from bitcode, but we are jitting non-lazily, emit it now. + // read from bitcode, and we are jitting non-lazily, emit it now. while (!jitstate->getPendingFunctions(locked).empty()) { Function *PF = jitstate->getPendingFunctions(locked).back(); jitstate->getPendingFunctions(locked).pop_back(); @@ -616,7 +616,7 @@ void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) { // If the JIT is configured to emit info so that dlsym can be used to // rewrite stubs to external globals, do so now. - if (areDlsymStubsEnabled() && isLazyCompilationDisabled()) + if (areDlsymStubsEnabled() && !isCompilingLazily()) updateDlsymStubTable(); } @@ -659,7 +659,7 @@ void *JIT::getPointerToFunction(Function *F) { return Addr; } - if (F->isDeclaration()) { + if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) { bool AbortOnFailure = !areDlsymStubsEnabled() && !F->hasExternalWeakLinkage(); void *Addr = getPointerToNamedFunction(F->getName(), AbortOnFailure); diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h index 525cc84..fb3cb24 100644 --- a/lib/ExecutionEngine/JIT/JIT.h +++ b/lib/ExecutionEngine/JIT/JIT.h @@ -128,6 +128,11 @@ public: /// void *getPointerToFunction(Function *F); + void *getPointerToBasicBlock(BasicBlock *BB) { + assert(0 && "JIT does not support address-of-label yet!"); + return 0; + } + /// getOrEmitGlobalVariable - Return the address of the specified global /// variable, possibly emitting it to memory if needed. This is used by the /// Emitter. @@ -183,7 +188,7 @@ public: void NotifyFunctionEmitted( const Function &F, void *Code, size_t Size, const JITEvent_EmittedFunctionDetails &Details); - void NotifyFreeingMachineCode(const Function &F, void *OldPtr); + void NotifyFreeingMachineCode(void *OldPtr); private: static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM, diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h index dce506b..7e53d78 100644 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h +++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h @@ -16,7 +16,7 @@ #define LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H #include "llvm/ADT/DenseMap.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <string> // This must be kept in sync with gdb/gdb/jit.h . diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 073d6fb..79f1eb4 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -46,6 +46,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/ValueMap.h" #include <algorithm> #ifndef NDEBUG #include <iomanip> @@ -62,12 +63,29 @@ static JIT *TheJIT = 0; // JIT lazy compilation code. // namespace { + class JITResolverState; + + template<typename ValueTy> + struct NoRAUWValueMapConfig : public ValueMapConfig<ValueTy> { + typedef JITResolverState *ExtraData; + static void onRAUW(JITResolverState *, Value *Old, Value *New) { + assert(false && "The JIT doesn't know how to handle a" + " RAUW on a value it has emitted."); + } + }; + + struct CallSiteValueMapConfig : public NoRAUWValueMapConfig<Function*> { + typedef JITResolverState *ExtraData; + static void onDelete(JITResolverState *JRS, Function *F); + }; + class JITResolverState { public: - typedef DenseMap<AssertingVH<Function>, void*> FunctionToStubMapTy; + typedef ValueMap<Function*, void*, NoRAUWValueMapConfig<Function*> > + FunctionToStubMapTy; typedef std::map<void*, AssertingVH<Function> > CallSiteToFunctionMapTy; - typedef DenseMap<AssertingVH<Function>, SmallPtrSet<void*, 1> > - FunctionToCallSitesMapTy; + typedef ValueMap<Function *, SmallPtrSet<void*, 1>, + CallSiteValueMapConfig> FunctionToCallSitesMapTy; typedef std::map<AssertingVH<GlobalValue>, void*> GlobalToIndirectSymMapTy; private: /// FunctionToStubMap - Keep track of the stub created for a particular @@ -84,6 +102,9 @@ namespace { GlobalToIndirectSymMapTy GlobalToIndirectSymMap; public: + JITResolverState() : FunctionToStubMap(this), + FunctionToCallSitesMap(this) {} + FunctionToStubMapTy& getFunctionToStubMap(const MutexGuard& locked) { assert(locked.holds(TheJIT->lock)); return FunctionToStubMap; @@ -111,8 +132,10 @@ namespace { void AddCallSite(const MutexGuard &locked, void *CallSite, Function *F) { assert(locked.holds(TheJIT->lock)); - assert(CallSiteToFunctionMap.insert(std::make_pair(CallSite, F)).second && - "Pair was already in CallSiteToFunctionMap"); + bool Inserted = CallSiteToFunctionMap.insert( + std::make_pair(CallSite, F)).second; + (void)Inserted; + assert(Inserted && "Pair was already in CallSiteToFunctionMap"); FunctionToCallSitesMap[F].insert(CallSite); } @@ -142,8 +165,9 @@ namespace { FunctionToCallSitesMapTy::iterator F2C_I = FunctionToCallSitesMap.find(F); assert(F2C_I != FunctionToCallSitesMap.end() && "FunctionToCallSitesMap broken"); - assert(F2C_I->second.erase(Stub) && - "FunctionToCallSitesMap broken"); + bool Erased = F2C_I->second.erase(Stub); + (void)Erased; + assert(Erased && "FunctionToCallSitesMap broken"); if (F2C_I->second.empty()) FunctionToCallSitesMap.erase(F2C_I); @@ -152,13 +176,17 @@ namespace { void EraseAllCallSites(const MutexGuard &locked, Function *F) { assert(locked.holds(TheJIT->lock)); + EraseAllCallSitesPrelocked(F); + } + void EraseAllCallSitesPrelocked(Function *F) { FunctionToCallSitesMapTy::iterator F2C = FunctionToCallSitesMap.find(F); if (F2C == FunctionToCallSitesMap.end()) return; for (SmallPtrSet<void*, 1>::const_iterator I = F2C->second.begin(), E = F2C->second.end(); I != E; ++I) { - assert(CallSiteToFunctionMap.erase(*I) == 1 && - "Missing call site->function mapping"); + bool Erased = CallSiteToFunctionMap.erase(*I); + (void)Erased; + assert(Erased && "Missing call site->function mapping"); } FunctionToCallSitesMap.erase(F2C); } @@ -245,6 +273,10 @@ namespace { JITResolver *JITResolver::TheJITResolver = 0; +void CallSiteValueMapConfig::onDelete(JITResolverState *JRS, Function *F) { + JRS->EraseAllCallSitesPrelocked(F); +} + /// getFunctionStubIfAvailable - This returns a pointer to a function stub /// if it has already been created. void *JITResolver::getFunctionStubIfAvailable(Function *F) { @@ -263,11 +295,11 @@ void *JITResolver::getFunctionStub(Function *F) { void *&Stub = state.getFunctionToStubMap(locked)[F]; if (Stub) return Stub; - // Call the lazy resolver function unless we are JIT'ing non-lazily, in which - // case we must resolve the symbol now. - void *Actual = TheJIT->isLazyCompilationDisabled() - ? (void *)0 : (void *)(intptr_t)LazyResolverFn; - + // Call the lazy resolver function if we are JIT'ing lazily. Otherwise we + // must resolve the symbol now. + void *Actual = TheJIT->isCompilingLazily() + ? (void *)(intptr_t)LazyResolverFn : (void *)0; + // If this is an external declaration, attempt to resolve the address now // to place in the stub. if (F->isDeclaration() && !F->hasNotBeenReadFromBitcode()) { @@ -302,7 +334,7 @@ void *JITResolver::getFunctionStub(Function *F) { // If we are JIT'ing non-lazily but need to call a function that does not // exist yet, add it to the JIT's work list so that we can fill in the stub // address later. - if (!Actual && TheJIT->isLazyCompilationDisabled()) + if (!Actual && !TheJIT->isCompilingLazily()) if (!F->isDeclaration() || F->hasNotBeenReadFromBitcode()) TheJIT->addPendingFunction(F); @@ -439,7 +471,7 @@ void *JITResolver::JITCompilerFn(void *Stub) { // Otherwise we don't have it, do lazy compilation now. // If lazy compilation is disabled, emit a useful error message and abort. - if (TheJIT->isLazyCompilationDisabled()) { + if (!TheJIT->isCompilingLazily()) { llvm_report_error("LLVM JIT requested to do lazy compilation of function '" + F->getName() + "' when lazy compiles are disabled!"); } @@ -550,17 +582,24 @@ namespace { JITEvent_EmittedFunctionDetails EmissionDetails; struct EmittedCode { - void *FunctionBody; + void *FunctionBody; // Beginning of the function's allocation. + void *Code; // The address the function's code actually starts at. void *ExceptionTable; - EmittedCode() : FunctionBody(0), ExceptionTable(0) {} + EmittedCode() : FunctionBody(0), Code(0), ExceptionTable(0) {} + }; + struct EmittedFunctionConfig : public ValueMapConfig<const Function*> { + typedef JITEmitter *ExtraData; + static void onDelete(JITEmitter *, const Function*); + static void onRAUW(JITEmitter *, const Function*, const Function*); }; - DenseMap<const Function *, EmittedCode> EmittedFunctions; + ValueMap<const Function *, EmittedCode, + EmittedFunctionConfig> EmittedFunctions; // CurFnStubUses - For a given Function, a vector of stubs that it // references. This facilitates the JIT detecting that a stub is no // longer used, so that it may be deallocated. - DenseMap<const Function *, SmallVector<void*, 1> > CurFnStubUses; - + DenseMap<AssertingVH<const Function>, SmallVector<void*, 1> > CurFnStubUses; + // StubFnRefs - For a given pointer to a stub, a set of Functions which // reference the stub. When the count of a stub's references drops to zero, // the stub is unused. @@ -574,7 +613,8 @@ namespace { public: JITEmitter(JIT &jit, JITMemoryManager *JMM, TargetMachine &TM) - : SizeEstimate(0), Resolver(jit), MMI(0), CurFn(0) { + : SizeEstimate(0), Resolver(jit), MMI(0), CurFn(0), + EmittedFunctions(this) { MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager(); if (jit.getJITInfo().needsGOT()) { MemMgr->AllocateGOT(); @@ -729,7 +769,7 @@ void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference, // mechanism is capable of rewriting the instruction directly, prefer to do // that instead of emitting a stub. This uses the lazy resolver, so is not // legal if lazy compilation is disabled. - if (DoesntNeedStub && !TheJIT->isLazyCompilationDisabled()) + if (DoesntNeedStub && TheJIT->isCompilingLazily()) return Resolver.AddCallbackAtLocation(F, Reference); // Otherwise, we have to emit a stub. @@ -1030,6 +1070,7 @@ void JITEmitter::startFunction(MachineFunction &F) { // About to start emitting the machine code for the function. emitAlignment(std::max(F.getFunction()->getAlignment(), 8U)); TheJIT->updateGlobalMapping(F.getFunction(), CurBufferPtr); + EmittedFunctions[F.getFunction()].Code = CurBufferPtr; MBBLocations.clear(); @@ -1253,12 +1294,15 @@ void JITEmitter::retryWithMoreMemory(MachineFunction &F) { /// deallocateMemForFunction - Deallocate all memory for the specified /// function body. Also drop any references the function has to stubs. +/// May be called while the Function is being destroyed inside ~Value(). void JITEmitter::deallocateMemForFunction(const Function *F) { - DenseMap<const Function *, EmittedCode>::iterator Emitted = - EmittedFunctions.find(F); + ValueMap<const Function *, EmittedCode, EmittedFunctionConfig>::iterator + Emitted = EmittedFunctions.find(F); if (Emitted != EmittedFunctions.end()) { MemMgr->deallocateFunctionBody(Emitted->second.FunctionBody); MemMgr->deallocateExceptionTable(Emitted->second.ExceptionTable); + TheJIT->NotifyFreeingMachineCode(Emitted->second.Code); + EmittedFunctions.erase(Emitted); } @@ -1487,6 +1531,17 @@ uintptr_t JITEmitter::getJumpTableEntryAddress(unsigned Index) const { return (uintptr_t)((char *)JumpTableBase + Offset); } +void JITEmitter::EmittedFunctionConfig::onDelete( + JITEmitter *Emitter, const Function *F) { + Emitter->deallocateMemForFunction(F); +} +void JITEmitter::EmittedFunctionConfig::onRAUW( + JITEmitter *, const Function*, const Function*) { + llvm_unreachable("The JIT doesn't know how to handle a" + " RAUW on a value it has emitted."); +} + + //===----------------------------------------------------------------------===// // Public interface to this file //===----------------------------------------------------------------------===// @@ -1625,13 +1680,9 @@ void JIT::updateDlsymStubTable() { /// freeMachineCodeForFunction - release machine code memory for given Function. /// void JIT::freeMachineCodeForFunction(Function *F) { - // Delete translation for this from the ExecutionEngine, so it will get // retranslated next time it is used. - void *OldPtr = updateGlobalMapping(F, 0); - - if (OldPtr) - TheJIT->NotifyFreeingMachineCode(*F, OldPtr); + updateGlobalMapping(F, 0); // Free the actual memory for the function body and related stuff. assert(isa<JITEmitter>(JCE) && "Unexpected MCE?"); diff --git a/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp b/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp deleted file mode 100644 index 53585b8..0000000 --- a/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp +++ /dev/null @@ -1,172 +0,0 @@ -//===-- MacOSJITEventListener.cpp - Save symbol table for OSX perf tools --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a JITEventListener object that records JITted functions to -// a global __jitSymbolTable linked list. Apple's performance tools use this to -// determine a symbol name and accurate code range for a PC value. Because -// performance tools are generally asynchronous, the code below is written with -// the hope that it could be interrupted at any time and have useful answers. -// However, we don't go crazy with atomic operations, we just do a "reasonable -// effort". -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "macos-jit-event-listener" -#include "llvm/Function.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include <stddef.h> -using namespace llvm; - -#ifdef __APPLE__ -#define ENABLE_JIT_SYMBOL_TABLE 0 -#endif - -#if ENABLE_JIT_SYMBOL_TABLE - -namespace { - -/// JITSymbolEntry - Each function that is JIT compiled results in one of these -/// being added to an array of symbols. This indicates the name of the function -/// as well as the address range it occupies. This allows the client to map -/// from a PC value to the name of the function. -struct JITSymbolEntry { - const char *FnName; // FnName - a strdup'd string. - void *FnStart; - intptr_t FnSize; -}; - - -struct JITSymbolTable { - /// NextPtr - This forms a linked list of JitSymbolTable entries. This - /// pointer is not used right now, but might be used in the future. Consider - /// it reserved for future use. - JITSymbolTable *NextPtr; - - /// Symbols - This is an array of JitSymbolEntry entries. Only the first - /// 'NumSymbols' symbols are valid. - JITSymbolEntry *Symbols; - - /// NumSymbols - This indicates the number entries in the Symbols array that - /// are valid. - unsigned NumSymbols; - - /// NumAllocated - This indicates the amount of space we have in the Symbols - /// array. This is a private field that should not be read by external tools. - unsigned NumAllocated; -}; - -class MacOSJITEventListener : public JITEventListener { -public: - virtual void NotifyFunctionEmitted(const Function &F, - void *FnStart, size_t FnSize, - const EmittedFunctionDetails &Details); - virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr); -}; - -} // anonymous namespace. - -// This is a public symbol so the performance tools can find it. -JITSymbolTable *__jitSymbolTable; - -namespace llvm { -JITEventListener *createMacOSJITEventListener() { - return new MacOSJITEventListener; -} -} - -// Adds the just-emitted function to the symbol table. -void MacOSJITEventListener::NotifyFunctionEmitted( - const Function &F, void *FnStart, size_t FnSize, - const EmittedFunctionDetails &) { - assert(F.hasName() && FnStart != 0 && "Bad symbol to add"); - JITSymbolTable **SymTabPtrPtr = 0; - SymTabPtrPtr = &__jitSymbolTable; - - // If this is the first entry in the symbol table, add the JITSymbolTable - // index. - if (*SymTabPtrPtr == 0) { - JITSymbolTable *New = new JITSymbolTable(); - New->NextPtr = 0; - New->Symbols = 0; - New->NumSymbols = 0; - New->NumAllocated = 0; - *SymTabPtrPtr = New; - } - - JITSymbolTable *SymTabPtr = *SymTabPtrPtr; - - // If we have space in the table, reallocate the table. - if (SymTabPtr->NumSymbols >= SymTabPtr->NumAllocated) { - // If we don't have space, reallocate the table. - unsigned NewSize = std::max(64U, SymTabPtr->NumAllocated*2); - JITSymbolEntry *NewSymbols = new JITSymbolEntry[NewSize]; - JITSymbolEntry *OldSymbols = SymTabPtr->Symbols; - - // Copy the old entries over. - memcpy(NewSymbols, OldSymbols, SymTabPtr->NumSymbols*sizeof(OldSymbols[0])); - - // Swap the new symbols in, delete the old ones. - SymTabPtr->Symbols = NewSymbols; - SymTabPtr->NumAllocated = NewSize; - delete [] OldSymbols; - } - - // Otherwise, we have enough space, just tack it onto the end of the array. - JITSymbolEntry &Entry = SymTabPtr->Symbols[SymTabPtr->NumSymbols]; - Entry.FnName = strdup(F.getName().data()); - Entry.FnStart = FnStart; - Entry.FnSize = FnSize; - ++SymTabPtr->NumSymbols; -} - -// Removes the to-be-deleted function from the symbol table. -void MacOSJITEventListener::NotifyFreeingMachineCode( - const Function &, void *FnStart) { - assert(FnStart && "Invalid function pointer"); - JITSymbolTable **SymTabPtrPtr = 0; - SymTabPtrPtr = &__jitSymbolTable; - - JITSymbolTable *SymTabPtr = *SymTabPtrPtr; - JITSymbolEntry *Symbols = SymTabPtr->Symbols; - - // Scan the table to find its index. The table is not sorted, so do a linear - // scan. - unsigned Index; - for (Index = 0; Symbols[Index].FnStart != FnStart; ++Index) - assert(Index != SymTabPtr->NumSymbols && "Didn't find function!"); - - // Once we have an index, we know to nuke this entry, overwrite it with the - // entry at the end of the array, making the last entry redundant. - const char *OldName = Symbols[Index].FnName; - Symbols[Index] = Symbols[SymTabPtr->NumSymbols-1]; - free((void*)OldName); - - // Drop the number of symbols in the table. - --SymTabPtr->NumSymbols; - - // Finally, if we deleted the final symbol, deallocate the table itself. - if (SymTabPtr->NumSymbols != 0) - return; - - *SymTabPtrPtr = 0; - delete [] Symbols; - delete SymTabPtr; -} - -#else // !ENABLE_JIT_SYMBOL_TABLE - -namespace llvm { -// By defining this to return NULL, we can let clients call it unconditionally, -// even if they aren't on an Apple system. -JITEventListener *createMacOSJITEventListener() { - return NULL; -} -} // namespace llvm - -#endif // ENABLE_JIT_SYMBOL_TABLE diff --git a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp index 00c4af7..b45c71f 100644 --- a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp +++ b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp @@ -43,7 +43,7 @@ public: virtual void NotifyFunctionEmitted(const Function &F, void *FnStart, size_t FnSize, const EmittedFunctionDetails &Details); - virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr); + virtual void NotifyFreeingMachineCode(void *OldPtr); }; OProfileJITEventListener::OProfileJITEventListener() @@ -147,13 +147,13 @@ void OProfileJITEventListener::NotifyFunctionEmitted( } } -// Removes the to-be-deleted function from the symbol table. -void OProfileJITEventListener::NotifyFreeingMachineCode( - const Function &F, void *FnStart) { +// Removes the being-deleted function from the symbol table. +void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) { assert(FnStart && "Invalid function pointer"); if (op_unload_native_code(Agent, reinterpret_cast<uint64_t>(FnStart)) == -1) { - DEBUG(errs() << "Failed to tell OProfile about unload of native function " - << F.getName() << " at " << FnStart << "\n"); + DEBUG(errs() + << "Failed to tell OProfile about unload of native function at " + << FnStart << "\n"); } } |