#define DEBUG_TYPE "jit"
#include "JIT.h"
+#include "JITDebugRegisterer.h"
#include "JITDwarfEmitter.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
namespace {
class JITResolverState {
public:
- typedef std::map<AssertingVH<Function>, void*> FunctionToStubMapTy;
- typedef std::map<void*, Function*> StubToFunctionMapTy;
+ typedef DenseMap<AssertingVH<Function>, void*> FunctionToStubMapTy;
+ typedef std::map<void*, AssertingVH<Function> > CallSiteToFunctionMapTy;
+ typedef DenseMap<AssertingVH<Function>, SmallPtrSet<void*, 1> >
+ FunctionToCallSitesMapTy;
typedef std::map<AssertingVH<GlobalValue>, void*> GlobalToIndirectSymMapTy;
private:
/// FunctionToStubMap - Keep track of the stub created for a particular
/// function so that we can reuse them if necessary.
FunctionToStubMapTy FunctionToStubMap;
- /// StubToFunctionMap - Keep track of the function that each stub
- /// corresponds to.
- StubToFunctionMapTy StubToFunctionMap;
+ /// CallSiteToFunctionMap - Keep track of the function that each lazy call
+ /// site corresponds to, and vice versa.
+ CallSiteToFunctionMapTy CallSiteToFunctionMap;
+ FunctionToCallSitesMapTy FunctionToCallSitesMap;
/// GlobalToIndirectSymMap - Keep track of the indirect symbol created for a
/// particular GlobalVariable so that we can reuse them if necessary.
return FunctionToStubMap;
}
- StubToFunctionMapTy& getStubToFunctionMap(const MutexGuard& locked) {
+ GlobalToIndirectSymMapTy& getGlobalToIndirectSymMap(const MutexGuard& locked) {
assert(locked.holds(TheJIT->lock));
- return StubToFunctionMap;
+ return GlobalToIndirectSymMap;
}
- GlobalToIndirectSymMapTy& getGlobalToIndirectSymMap(const MutexGuard& locked) {
+ pair<void *, Function *> LookupFunctionFromCallSite(
+ const MutexGuard &locked, void *CallSite) const {
assert(locked.holds(TheJIT->lock));
- return GlobalToIndirectSymMap;
+
+ // The address given to us for the stub may not be exactly right, it might be
+ // a little bit after the stub. As such, use upper_bound to find it.
+ CallSiteToFunctionMapTy::const_iterator I =
+ CallSiteToFunctionMap.upper_bound(CallSite);
+ assert(I != CallSiteToFunctionMap.begin() &&
+ "This is not a known call site!");
+ --I;
+ return *I;
+ }
+
+ 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");
+ FunctionToCallSitesMap[F].insert(CallSite);
+ }
+
+ // Returns the Function of the stub if a stub was erased, or NULL if there
+ // was no stub. This function uses the call-site->function map to find a
+ // relevant function, but asserts that only stubs and not other call sites
+ // will be passed in.
+ Function *EraseStub(const MutexGuard &locked, void *Stub) {
+ CallSiteToFunctionMapTy::iterator C2F_I =
+ CallSiteToFunctionMap.find(Stub);
+ if (C2F_I == CallSiteToFunctionMap.end()) {
+ // Not a stub.
+ return NULL;
+ }
+
+ Function *const F = C2F_I->second;
+#ifndef NDEBUG
+ void *RealStub = FunctionToStubMap.lookup(F);
+ assert(RealStub == Stub &&
+ "Call-site that wasn't a stub pass in to EraseStub");
+#endif
+ FunctionToStubMap.erase(F);
+ CallSiteToFunctionMap.erase(C2F_I);
+
+ // Remove the stub from the function->call-sites map, and remove the whole
+ // entry from the map if that was the last call site.
+ FunctionToCallSitesMapTy::iterator F2C_I = FunctionToCallSitesMap.find(F);
+ assert(F2C_I != FunctionToCallSitesMap.end() &&
+ "FunctionToCallSitesMap broken");
+ assert(F2C_I->second.erase(Stub) &&
+ "FunctionToCallSitesMap broken");
+ if (F2C_I->second.empty())
+ FunctionToCallSitesMap.erase(F2C_I);
+
+ return F;
+ }
+
+ void EraseAllCallSites(const MutexGuard &locked, Function *F) {
+ assert(locked.holds(TheJIT->lock));
+ 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");
+ }
+ FunctionToCallSitesMap.erase(F2C);
}
};
/// have not yet been compiled.
class JITResolver {
typedef JITResolverState::FunctionToStubMapTy FunctionToStubMapTy;
- typedef JITResolverState::StubToFunctionMapTy StubToFunctionMapTy;
+ typedef JITResolverState::CallSiteToFunctionMapTy CallSiteToFunctionMapTy;
typedef JITResolverState::GlobalToIndirectSymMapTy GlobalToIndirectSymMapTy;
/// LazyResolverFn - The target lazy resolver function that we actually
void *AddCallbackAtLocation(Function *F, void *Location) {
MutexGuard locked(TheJIT->lock);
/// Get the target-specific JIT resolver function.
- state.getStubToFunctionMap(locked)[Location] = F;
+ state.AddCallSite(locked, Location, F);
return (void*)(intptr_t)LazyResolverFn;
}
MutexGuard locked(TheJIT->lock);
// If we already have a stub for this function, recycle it.
- void *&Stub = state.getFunctionToStubMap(locked)[F];
- return Stub;
+ return state.getFunctionToStubMap(locked).lookup(F);
}
/// getFunctionStub - This returns a pointer to a function stub, creating
// 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 *Actual = TheJIT->isLazyCompilationDisabled()
? (void *)0 : (void *)(intptr_t)LazyResolverFn;
-
+
// If this is an external declaration, attempt to resolve the address now
// to place in the stub.
if (F->isDeclaration() && !F->hasNotBeenReadFromBitcode()) {
// Finally, keep track of the stub-to-Function mapping so that the
// JITCompilerFn knows which function to compile!
- state.getStubToFunctionMap(locked)[Stub] = F;
-
+ state.AddCallSite(locked, Stub, 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 (!F->isDeclaration() || F->hasNotBeenReadFromBitcode())
TheJIT->addPendingFunction(F);
-
+
return Stub;
}
SmallVectorImpl<void*> &Ptrs) {
MutexGuard locked(TheJIT->lock);
- FunctionToStubMapTy &FM = state.getFunctionToStubMap(locked);
+ const FunctionToStubMapTy &FM = state.getFunctionToStubMap(locked);
GlobalToIndirectSymMapTy &GM = state.getGlobalToIndirectSymMap(locked);
- for (FunctionToStubMapTy::iterator i = FM.begin(), e = FM.end(); i != e; ++i){
+ for (FunctionToStubMapTy::const_iterator i = FM.begin(), e = FM.end();
+ i != e; ++i){
Function *F = i->first;
if (F->isDeclaration() && F->hasExternalLinkage()) {
GVs.push_back(i->first);
GlobalValue *JITResolver::invalidateStub(void *Stub) {
MutexGuard locked(TheJIT->lock);
-
- FunctionToStubMapTy &FM = state.getFunctionToStubMap(locked);
- StubToFunctionMapTy &SM = state.getStubToFunctionMap(locked);
+
GlobalToIndirectSymMapTy &GM = state.getGlobalToIndirectSymMap(locked);
-
+
// Look up the cheap way first, to see if it's a function stub we are
// invalidating. If so, remove it from both the forward and reverse maps.
- if (SM.find(Stub) != SM.end()) {
- Function *F = SM[Stub];
- SM.erase(Stub);
- FM.erase(F);
+ if (Function *F = state.EraseStub(locked, Stub)) {
return F;
}
-
+
// Otherwise, it might be an indirect symbol stub. Find it and remove it.
for (GlobalToIndirectSymMapTy::iterator i = GM.begin(), e = GM.end();
i != e; ++i) {
// JIT lock to be unlocked.
MutexGuard locked(TheJIT->lock);
- // The address given to us for the stub may not be exactly right, it might be
- // a little bit after the stub. As such, use upper_bound to find it.
- StubToFunctionMapTy::iterator I =
- JR.state.getStubToFunctionMap(locked).upper_bound(Stub);
- assert(I != JR.state.getStubToFunctionMap(locked).begin() &&
- "This is not a known stub!");
- F = (--I)->second;
- ActualPtr = I->first;
+ // The address given to us for the stub may not be exactly right, it might
+ // be a little bit after the stub. As such, use upper_bound to find it.
+ pair<void*, Function*> I =
+ JR.state.LookupFunctionFromCallSite(locked, Stub);
+ F = I.second;
+ ActualPtr = I.first;
}
// If we have already code generated the function, just return the address.
+ F->getName() + "' when lazy compiles are disabled!");
}
- // We might like to remove the stub from the StubToFunction map.
- // We can't do that! Multiple threads could be stuck, waiting to acquire the
- // lock above. As soon as the 1st function finishes compiling the function,
- // the next one will be released, and needs to be able to find the function
- // it needs to call.
- //JR.state.getStubToFunctionMap(locked).erase(I);
-
DEBUG(errs() << "JIT: Lazily resolving function '" << F->getName()
<< "' In stub ptr = " << Stub << " actual ptr = "
<< ActualPtr << "\n");
Result = TheJIT->getPointerToFunction(F);
}
-
- // Reacquire the lock to erase the stub in the map.
+
+ // Reacquire the lock to update the GOT map.
MutexGuard locked(TheJIT->lock);
- // We don't need to reuse this stub in the future, as F is now compiled.
- JR.state.getFunctionToStubMap(locked).erase(F);
+ // We might like to remove the call site from the CallSiteToFunction map, but
+ // we can't do that! Multiple threads could be stuck, waiting to acquire the
+ // lock above. As soon as the 1st function finishes compiling the function,
+ // the next one will be released, and needs to be able to find the function it
+ // needs to call.
// FIXME: We could rewrite all references to this stub if we knew them.
/// Resolver - This contains info about the currently resolved functions.
JITResolver Resolver;
-
+
/// DE - The dwarf emitter for the jit.
- JITDwarfEmitter *DE;
+ OwningPtr<JITDwarfEmitter> DE;
+
+ /// DR - The debug registerer for the jit.
+ OwningPtr<JITDebugRegisterer> DR;
/// LabelLocations - This vector is a mapping from Label ID's to their
/// address.
DebugLocTuple PrevDLT;
public:
- JITEmitter(JIT &jit, JITMemoryManager *JMM)
- : SizeEstimate(0), Resolver(jit), CurFn(0) {
+ JITEmitter(JIT &jit, JITMemoryManager *JMM, TargetMachine &TM)
+ : SizeEstimate(0), Resolver(jit), MMI(0), CurFn(0) {
MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager();
if (jit.getJITInfo().needsGOT()) {
MemMgr->AllocateGOT();
DEBUG(errs() << "JIT is managing a GOT\n");
}
- if (DwarfExceptionHandling) DE = new JITDwarfEmitter(jit);
+ if (DwarfExceptionHandling || JITEmitDebugInfo) {
+ DE.reset(new JITDwarfEmitter(jit));
+ }
+ if (JITEmitDebugInfo) {
+ DR.reset(new JITDebugRegisterer(TM));
+ }
}
~JITEmitter() {
delete MemMgr;
- if (DwarfExceptionHandling) delete DE;
}
/// classof - Methods for support type inquiry through isa, cast, and
/// MachineRelocations that reference external functions by name.
const StringMap<void*> &getExternalFnStubs() const { return ExtFnStubs; }
- virtual void processDebugLoc(DebugLoc DL);
+ virtual void processDebugLoc(DebugLoc DL, bool BeforePrintingInsn);
virtual void emitLabel(uint64_t LabelID) {
if (LabelLocations.size() <= LabelID)
virtual void setModuleInfo(MachineModuleInfo* Info) {
MMI = Info;
- if (DwarfExceptionHandling) DE->setModuleInfo(Info);
+ if (DE.get()) DE->setModuleInfo(Info);
}
void setMemoryExecutable() {
// If we have already compiled the function, return a pointer to its body.
Function *F = cast<Function>(V);
void *ResultPtr;
- if (!DoesntNeedStub && !TheJIT->isLazyCompilationDisabled()) {
+ if (!DoesntNeedStub) {
// Return the function stub if it's already created.
ResultPtr = Resolver.getFunctionStubIfAvailable(F);
if (ResultPtr)
}
void JITEmitter::AddStubToCurrentFunction(void *StubAddr) {
- if (!TheJIT->areDlsymStubsEnabled())
- return;
-
assert(CurFn && "Stub added to current function, but current function is 0!");
-
+
SmallVectorImpl<void*> &StubsUsed = CurFnStubUses[CurFn];
StubsUsed.push_back(StubAddr);
FnRefs.insert(CurFn);
}
-void JITEmitter::processDebugLoc(DebugLoc DL) {
+void JITEmitter::processDebugLoc(DebugLoc DL, bool BeforePrintingInsn) {
if (!DL.isUnknown()) {
DebugLocTuple CurDLT = EmissionDetails.MF->getDebugLocTuple(DL);
- if (CurDLT.CompileUnit != 0 && PrevDLT != CurDLT) {
- JITEvent_EmittedFunctionDetails::LineStart NextLine;
- NextLine.Address = getCurrentPCValue();
- NextLine.Loc = DL;
- EmissionDetails.LineStarts.push_back(NextLine);
+ if (BeforePrintingInsn) {
+ if (CurDLT.Scope != 0 && PrevDLT != CurDLT) {
+ JITEvent_EmittedFunctionDetails::LineStart NextLine;
+ NextLine.Address = getCurrentPCValue();
+ NextLine.Loc = DL;
+ EmissionDetails.LineStarts.push_back(NextLine);
+ }
+
+ PrevDLT = CurDLT;
}
-
- PrevDLT = CurDLT;
}
}
}
);
- if (DwarfExceptionHandling) {
+ if (DwarfExceptionHandling || JITEmitDebugInfo) {
uintptr_t ActualSize = 0;
SavedBufferBegin = BufferBegin;
SavedBufferEnd = BufferEnd;
SavedCurBufferPtr = CurBufferPtr;
-
+
if (MemMgr->NeedsExactSize()) {
ActualSize = DE->GetDwarfTableSizeInBytes(F, *this, FnStart, FnEnd);
}
BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(),
ActualSize);
BufferEnd = BufferBegin+ActualSize;
- uint8_t* FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd);
+ uint8_t *EhStart;
+ uint8_t *FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd,
+ EhStart);
MemMgr->endExceptionTable(F.getFunction(), BufferBegin, CurBufferPtr,
FrameRegister);
+ uint8_t *EhEnd = CurBufferPtr;
BufferBegin = SavedBufferBegin;
BufferEnd = SavedBufferEnd;
CurBufferPtr = SavedCurBufferPtr;
- TheJIT->RegisterTable(FrameRegister);
+ if (DwarfExceptionHandling) {
+ TheJIT->RegisterTable(FrameRegister);
+ }
+
+ if (JITEmitDebugInfo) {
+ DebugInfo I;
+ I.FnStart = FnStart;
+ I.FnEnd = FnEnd;
+ I.EhStart = EhStart;
+ I.EhEnd = EhEnd;
+ DR->RegisterFunction(F.getFunction(), I);
+ }
}
if (MMI)
void JITEmitter::deallocateMemForFunction(const Function *F) {
MemMgr->deallocateMemForFunction(F);
+ // TODO: Do we need to unregister exception handling information from libgcc
+ // here?
+
+ if (JITEmitDebugInfo) {
+ DR->UnregisterFunction(F);
+ }
+
// If the function did not reference any stubs, return.
if (CurFnStubUses.find(F) == CurFnStubUses.end())
return;
// Public interface to this file
//===----------------------------------------------------------------------===//
-JITCodeEmitter *JIT::createEmitter(JIT &jit, JITMemoryManager *JMM) {
- return new JITEmitter(jit, JMM);
+JITCodeEmitter *JIT::createEmitter(JIT &jit, JITMemoryManager *JMM,
+ TargetMachine &tm) {
+ return new JITEmitter(jit, JMM, tm);
}
// getPointerToNamedFunction - This function is used as a global wrapper to