#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
-#include "llvm/CodeGen/MachineCodeEmitter.h"
+#include "llvm/CodeGen/JITCodeEmitter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRelocation.h"
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/ExecutionEngine/GenericValue.h"
+#include "llvm/ExecutionEngine/JITEventListener.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/CodeGen/MachineCodeInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetJITInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/ValueHandle.h"
#include "llvm/System/Disassembler.h"
#include "llvm/System/Memory.h"
#include "llvm/Target/TargetInstrInfo.h"
//
namespace {
class JITResolverState {
+ public:
+ typedef std::map<AssertingVH<Function>, void*> FunctionToStubMapTy;
+ typedef std::map<void*, Function*> StubToFunctionMapTy;
+ 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.
- std::map<Function*, void*> FunctionToStubMap;
+ FunctionToStubMapTy FunctionToStubMap;
/// StubToFunctionMap - Keep track of the function that each stub
/// corresponds to.
- std::map<void*, Function*> StubToFunctionMap;
+ StubToFunctionMapTy StubToFunctionMap;
/// GlobalToIndirectSymMap - Keep track of the indirect symbol created for a
/// particular GlobalVariable so that we can reuse them if necessary.
- std::map<GlobalValue*, void*> GlobalToIndirectSymMap;
+ GlobalToIndirectSymMapTy GlobalToIndirectSymMap;
public:
- std::map<Function*, void*>& getFunctionToStubMap(const MutexGuard& locked) {
+ FunctionToStubMapTy& getFunctionToStubMap(const MutexGuard& locked) {
assert(locked.holds(TheJIT->lock));
return FunctionToStubMap;
}
- std::map<void*, Function*>& getStubToFunctionMap(const MutexGuard& locked) {
+ StubToFunctionMapTy& getStubToFunctionMap(const MutexGuard& locked) {
assert(locked.holds(TheJIT->lock));
return StubToFunctionMap;
}
- std::map<GlobalValue*, void*>&
- getGlobalToIndirectSymMap(const MutexGuard& locked) {
+ GlobalToIndirectSymMapTy& getGlobalToIndirectSymMap(const MutexGuard& locked) {
assert(locked.holds(TheJIT->lock));
return GlobalToIndirectSymMap;
}
/// JITResolver - Keep track of, and resolve, call sites for functions that
/// have not yet been compiled.
class JITResolver {
+ typedef JITResolverState::FunctionToStubMapTy FunctionToStubMapTy;
+ typedef JITResolverState::StubToFunctionMapTy StubToFunctionMapTy;
+ typedef JITResolverState::GlobalToIndirectSymMapTy GlobalToIndirectSymMapTy;
+
/// LazyResolverFn - The target lazy resolver function that we actually
/// rewrite instructions to use.
TargetJITInfo::LazyResolverFn LazyResolverFn;
SmallVectorImpl<void*> &Ptrs) {
MutexGuard locked(TheJIT->lock);
- std::map<Function*,void*> &FM = state.getFunctionToStubMap(locked);
- std::map<GlobalValue*,void*> &GM = state.getGlobalToIndirectSymMap(locked);
+ FunctionToStubMapTy &FM = state.getFunctionToStubMap(locked);
+ GlobalToIndirectSymMapTy &GM = state.getGlobalToIndirectSymMap(locked);
- for (std::map<Function*,void*>::iterator i = FM.begin(), e = FM.end();
- i != e; ++i) {
+ for (FunctionToStubMapTy::iterator i = FM.begin(), e = FM.end(); i != e; ++i){
Function *F = i->first;
if (F->isDeclaration() && F->hasExternalLinkage()) {
GVs.push_back(i->first);
Ptrs.push_back(i->second);
}
}
- for (std::map<GlobalValue*,void*>::iterator i = GM.begin(), e = GM.end();
+ for (GlobalToIndirectSymMapTy::iterator i = GM.begin(), e = GM.end();
i != e; ++i) {
GVs.push_back(i->first);
Ptrs.push_back(i->second);
GlobalValue *JITResolver::invalidateStub(void *Stub) {
MutexGuard locked(TheJIT->lock);
- std::map<Function*,void*> &FM = state.getFunctionToStubMap(locked);
- std::map<void*,Function*> &SM = state.getStubToFunctionMap(locked);
- std::map<GlobalValue*,void*> &GM = state.getGlobalToIndirectSymMap(locked);
+ 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.
}
// Otherwise, it might be an indirect symbol stub. Find it and remove it.
- for (std::map<GlobalValue*,void*>::iterator i = GM.begin(), e = GM.end();
+ for (GlobalToIndirectSymMapTy::iterator i = GM.begin(), e = GM.end();
i != e; ++i) {
if (i->second != Stub)
continue;
// 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.
- std::map<void*, Function*>::iterator I =
+ StubToFunctionMapTy::iterator I =
JR.state.getStubToFunctionMap(locked).upper_bound(Stub);
assert(I != JR.state.getStubToFunctionMap(locked).begin() &&
"This is not a known stub!");
return Result;
}
-//===----------------------------------------------------------------------===//
-// Function Index Support
-
-// On MacOS we generate an index of currently JIT'd functions so that
-// performance tools can 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".
-#ifdef __APPLE__
-#define ENABLE_JIT_SYMBOL_TABLE 0
-#endif
-
-/// 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;
-};
-
-#if ENABLE_JIT_SYMBOL_TABLE
-JitSymbolTable *__jitSymbolTable;
-#endif
-
-static void AddFunctionToSymbolTable(const char *FnName,
- void *FnStart, intptr_t FnSize) {
- assert(FnName != 0 && FnStart != 0 && "Bad symbol to add");
- JitSymbolTable **SymTabPtrPtr = 0;
-#if !ENABLE_JIT_SYMBOL_TABLE
- return;
-#else
- SymTabPtrPtr = &__jitSymbolTable;
-#endif
-
- // 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(FnName);
- Entry.FnStart = FnStart;
- Entry.FnSize = FnSize;
- ++SymTabPtr->NumSymbols;
-}
-
-static void RemoveFunctionFromSymbolTable(void *FnStart) {
- assert(FnStart && "Invalid function pointer");
- JitSymbolTable **SymTabPtrPtr = 0;
-#if !ENABLE_JIT_SYMBOL_TABLE
- return;
-#else
- SymTabPtrPtr = &__jitSymbolTable;
-#endif
-
- 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;
-}
-
//===----------------------------------------------------------------------===//
// JITEmitter code.
//
namespace {
/// JITEmitter - The JIT implementation of the MachineCodeEmitter, which is
/// used to output functions to memory for execution.
- class JITEmitter : public MachineCodeEmitter {
+ class JITEmitter : public JITCodeEmitter {
JITMemoryManager *MemMgr;
// When outputting a function stub in the context of some other function, we
// save BufferBegin/BufferEnd/CurBufferPtr here.
- unsigned char *SavedBufferBegin, *SavedBufferEnd, *SavedCurBufferPtr;
+ uint8_t *SavedBufferBegin, *SavedBufferEnd, *SavedCurBufferPtr;
/// Relocations - These are the relocations that the function needs, as
/// emitted.
// ExtFnStubs - A map of external function names to stubs which have entries
// in the JITResolver's ExternalFnToStubMap.
StringMap<void *> ExtFnStubs;
-
+
public:
JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit), CurFn(0) {
MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager();
unsigned AlignMask = CPE.getAlignment() - 1;
Size = (Size + AlignMask) & ~AlignMask;
const Type *Ty = CPE.getType();
- Size += TD->getTypePaddedSize(Ty);
+ Size += TD->getTypeAllocSize(Ty);
}
return Size;
}
unsigned JITEmitter::addSizeOfGlobal(const GlobalVariable *GV, unsigned Size) {
const Type *ElTy = GV->getType()->getElementType();
- size_t GVSize = (size_t)TheJIT->getTargetData()->getTypePaddedSize(ElTy);
+ size_t GVSize = (size_t)TheJIT->getTargetData()->getTypeAllocSize(ElTy);
size_t GVAlign =
(size_t)TheJIT->getTargetData()->getPreferredAlignment(GV);
DOUT << "JIT: Adding in size " << GVSize << " alignment " << GVAlign;
break;
}
case Instruction::Add:
+ case Instruction::FAdd:
case Instruction::Sub:
+ case Instruction::FSub:
case Instruction::Mul:
+ case Instruction::FMul:
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::URem:
// FnStart is the start of the text, not the start of the constant pool and
// other per-function data.
- unsigned char *FnStart =
- (unsigned char *)TheJIT->getPointerToGlobalIfAvailable(F.getFunction());
+ uint8_t *FnStart =
+ (uint8_t *)TheJIT->getPointerToGlobalIfAvailable(F.getFunction());
+
+ // FnEnd is the end of the function's machine code.
+ uint8_t *FnEnd = CurBufferPtr;
if (!Relocations.empty()) {
CurFn = F.getFunction();
}
}
- unsigned char *FnEnd = CurBufferPtr;
-
- MemMgr->endFunctionBody(F.getFunction(), BufferBegin, FnEnd);
+ // CurBufferPtr may have moved beyond FnEnd, due to memory allocation for
+ // global variables that were referenced in the relocations.
+ MemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
if (CurBufferPtr == BufferEnd) {
// FIXME: Allocate more space, then try again.
// Invalidate the icache if necessary.
sys::Memory::InvalidateInstructionCache(FnStart, FnEnd-FnStart);
-
- // Add it to the JIT symbol table if the host wants it.
- AddFunctionToSymbolTable(F.getFunction()->getNameStart(),
- FnStart, FnEnd-FnStart);
+
+ JITEvent_EmittedFunctionDetails Details;
+ TheJIT->NotifyFunctionEmitted(*F.getFunction(), FnStart, FnEnd-FnStart,
+ Details);
DOUT << "JIT: Finished CodeGen of [" << (void*)FnStart
<< "] Function: " << F.getFunction()->getName()
<< ": " << (FnEnd-FnStart) << " bytes of text, "
<< Relocations.size() << " relocations\n";
+
Relocations.clear();
ConstPoolAddresses.clear();
} else {
DOUT << "JIT: Binary code:\n";
DOUT << std::hex;
- unsigned char* q = FnStart;
+ uint8_t* q = FnStart;
for (int i = 0; q < FnEnd; q += 4, ++i) {
if (i == 4)
i = 0;
BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(),
ActualSize);
BufferEnd = BufferBegin+ActualSize;
- unsigned char* FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd);
+ uint8_t* FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd);
MemMgr->endExceptionTable(F.getFunction(), BufferBegin, CurBufferPtr,
FrameRegister);
BufferBegin = SavedBufferBegin;
void* JITEmitter::allocateSpace(uintptr_t Size, unsigned Alignment) {
if (BufferBegin)
- return MachineCodeEmitter::allocateSpace(Size, Alignment);
+ return JITCodeEmitter::allocateSpace(Size, Alignment);
// create a new memory block if there is no active one.
// care must be taken so that BufferBegin is invalidated when a
<< std::hex << CAddr << std::dec << "]\n";
const Type *Ty = CPE.Val.ConstVal->getType();
- Offset += TheJIT->getTargetData()->getTypePaddedSize(Ty);
+ Offset += TheJIT->getTargetData()->getTypeAllocSize(Ty);
}
}
SavedBufferEnd = BufferEnd;
SavedCurBufferPtr = CurBufferPtr;
- BufferBegin = CurBufferPtr = (unsigned char *)Buffer;
+ BufferBegin = CurBufferPtr = (uint8_t *)Buffer;
BufferEnd = BufferBegin+StubSize+1;
}
// Public interface to this file
//===----------------------------------------------------------------------===//
-MachineCodeEmitter *JIT::createEmitter(JIT &jit, JITMemoryManager *JMM) {
+JITCodeEmitter *JIT::createEmitter(JIT &jit, JITMemoryManager *JMM) {
return new JITEmitter(jit, JMM);
}
return Addr;
// Get a stub if the target supports it.
- assert(isa<JITEmitter>(MCE) && "Unexpected MCE?");
+ assert(isa<JITEmitter>(JCE) && "Unexpected MCE?");
JITEmitter *JE = cast<JITEmitter>(getCodeEmitter());
return JE->getJITResolver().getFunctionStub(F);
}
void JIT::updateFunctionStub(Function *F) {
// Get the empty stub we generated earlier.
- assert(isa<JITEmitter>(MCE) && "Unexpected MCE?");
+ assert(isa<JITEmitter>(JCE) && "Unexpected MCE?");
JITEmitter *JE = cast<JITEmitter>(getCodeEmitter());
void *Stub = JE->getJITResolver().getFunctionStub(F);
/// that were emitted during code generation.
///
void JIT::updateDlsymStubTable() {
- assert(isa<JITEmitter>(MCE) && "Unexpected MCE?");
+ assert(isa<JITEmitter>(JCE) && "Unexpected MCE?");
JITEmitter *JE = cast<JITEmitter>(getCodeEmitter());
SmallVector<GlobalValue*, 8> GVs;
JE->startGVStub(0, offset, 4);
// Emit the number of records
- MCE->emitInt32(nStubs);
+ JE->emitInt32(nStubs);
// Emit the string offsets
for (unsigned i = 0; i != nStubs; ++i)
- MCE->emitInt32(Offsets[i]);
+ JE->emitInt32(Offsets[i]);
// Emit the pointers. Verify that they are at least 2-byte aligned, and set
// the low bit to 0 == GV, 1 == Function, so that the client code doing the
Ptr |= (intptr_t)1;
if (sizeof(Ptr) == 8)
- MCE->emitInt64(Ptr);
+ JE->emitInt64(Ptr);
else
- MCE->emitInt32(Ptr);
+ JE->emitInt32(Ptr);
}
for (StringMapConstIterator<void*> i = ExtFns.begin(), e = ExtFns.end();
i != e; ++i) {
intptr_t Ptr = (intptr_t)i->second | 1;
if (sizeof(Ptr) == 8)
- MCE->emitInt64(Ptr);
+ JE->emitInt64(Ptr);
else
- MCE->emitInt32(Ptr);
+ JE->emitInt32(Ptr);
}
// Emit the strings.
for (unsigned i = 0; i != GVs.size(); ++i)
- MCE->emitString(GVs[i]->getName());
+ JE->emitString(GVs[i]->getName());
for (StringMapConstIterator<void*> i = ExtFns.begin(), e = ExtFns.end();
i != e; ++i)
- MCE->emitString(i->first());
+ JE->emitString(i->first());
// Tell the JIT memory manager where it is. The JIT Memory Manager will
// deallocate space for the old one, if one existed.
void *OldPtr = updateGlobalMapping(F, 0);
if (OldPtr)
- RemoveFunctionFromSymbolTable(OldPtr);
+ TheJIT->NotifyFreeingMachineCode(*F, OldPtr);
// Free the actual memory for the function body and related stuff.
- assert(isa<JITEmitter>(MCE) && "Unexpected MCE?");
- cast<JITEmitter>(MCE)->deallocateMemForFunction(F);
+ assert(isa<JITEmitter>(JCE) && "Unexpected MCE?");
+ cast<JITEmitter>(JCE)->deallocateMemForFunction(F);
}
-