diff options
Diffstat (limited to 'lib/ExecutionEngine/JIT')
-rw-r--r-- | lib/ExecutionEngine/JIT/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JIT.cpp | 6 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JIT.h | 4 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp | 211 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITDebugRegisterer.h | 116 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITEmitter.cpp | 37 | ||||
-rw-r--r-- | lib/ExecutionEngine/JIT/JITMemoryManager.cpp | 44 |
7 files changed, 56 insertions, 363 deletions
diff --git a/lib/ExecutionEngine/JIT/CMakeLists.txt b/lib/ExecutionEngine/JIT/CMakeLists.txt index cefb0ae..dcef08c 100644 --- a/lib/ExecutionEngine/JIT/CMakeLists.txt +++ b/lib/ExecutionEngine/JIT/CMakeLists.txt @@ -4,7 +4,6 @@ add_definitions(-DENABLE_X86_JIT) add_llvm_library(LLVMJIT Intercept.cpp JIT.cpp - JITDebugRegisterer.cpp JITDwarfEmitter.cpp JITEmitter.cpp JITMemoryManager.cpp diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index e4f6bc4..f715f6f 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -475,7 +475,6 @@ GenericValue JIT::runFunction(Function *F, case Type::FP128TyID: case Type::PPC_FP128TyID: llvm_unreachable("long double not supported yet"); - return rv; case Type::PointerTyID: return PTOGV(((void*(*)())(intptr_t)FPtr)()); } @@ -707,9 +706,8 @@ void *JIT::getPointerToBasicBlock(BasicBlock *BB) { if (I != getBasicBlockAddressMap(locked).end()) { return I->second; } else { - assert(0 && "JIT does not have BB address for address-of-label, was" - " it eliminated by optimizer?"); - return 0; + llvm_unreachable("JIT does not have BB address for address-of-label, was" + " it eliminated by optimizer?"); } } diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h index fbb9416..17d33fe 100644 --- a/lib/ExecutionEngine/JIT/JIT.h +++ b/lib/ExecutionEngine/JIT/JIT.h @@ -124,8 +124,8 @@ public: /// found, this function silently returns a null pointer. Otherwise, /// it prints a message to stderr and aborts. /// - void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true); + virtual void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true); // CompilationCallback - Invoked the first time that a call site is found, // which causes lazy compilation of the target function. diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp deleted file mode 100644 index abb70fb..0000000 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp +++ /dev/null @@ -1,211 +0,0 @@ -//===-- JITDebugRegisterer.cpp - Register debug symbols for JIT -----------===// -// -// 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 JITDebugRegisterer object that is used by the JIT to -// register debug info with debuggers like GDB. -// -//===----------------------------------------------------------------------===// - -#include "JITDebugRegisterer.h" -#include "../../CodeGen/ELF.h" -#include "../../CodeGen/ELFWriter.h" -#include "llvm/LLVMContext.h" -#include "llvm/Function.h" -#include "llvm/Module.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/MutexGuard.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Mutex.h" -#include <string> - -namespace llvm { - -// This must be kept in sync with gdb/gdb/jit.h . -extern "C" { - - // Debuggers puts a breakpoint in this function. - LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { } - - // We put information about the JITed function in this global, which the - // debugger reads. Make sure to specify the version statically, because the - // debugger checks the version before we can set it during runtime. - struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; - -} - -namespace { - - /// JITDebugLock - Used to serialize all code registration events, since they - /// modify global variables. - sys::Mutex JITDebugLock; - -} - -JITDebugRegisterer::JITDebugRegisterer(TargetMachine &tm) : TM(tm), FnMap() { } - -JITDebugRegisterer::~JITDebugRegisterer() { - // Free all ELF memory. - for (RegisteredFunctionsMap::iterator I = FnMap.begin(), E = FnMap.end(); - I != E; ++I) { - // Call the private method that doesn't update the map so our iterator - // doesn't break. - UnregisterFunctionInternal(I); - } - FnMap.clear(); -} - -std::string JITDebugRegisterer::MakeELF(const Function *F, DebugInfo &I) { - // Stack allocate an empty module with an empty LLVMContext for the ELFWriter - // API. We don't use the real module because then the ELFWriter would write - // out unnecessary GlobalValues during finalization. - LLVMContext Context; - Module M("", Context); - - // Make a buffer for the ELF in memory. - std::string Buffer; - raw_string_ostream O(Buffer); - ELFWriter EW(O, TM); - EW.doInitialization(M); - - // Copy the binary into the .text section. This isn't necessary, but it's - // useful to be able to disassemble the ELF by hand. - ELFSection &Text = EW.getTextSection(const_cast<Function *>(F)); - Text.Addr = (uint64_t)I.FnStart; - // TODO: We could eliminate this copy if we somehow used a pointer/size pair - // instead of a vector. - Text.getData().assign(I.FnStart, I.FnEnd); - - // Copy the exception handling call frame information into the .eh_frame - // section. This allows GDB to get a good stack trace, particularly on - // linux x86_64. Mark this as a PROGBITS section that needs to be loaded - // into memory at runtime. - ELFSection &EH = EW.getSection(".eh_frame", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC); - // Pointers in the DWARF EH info are all relative to the EH frame start, - // which is stored here. - EH.Addr = (uint64_t)I.EhStart; - // TODO: We could eliminate this copy if we somehow used a pointer/size pair - // instead of a vector. - EH.getData().assign(I.EhStart, I.EhEnd); - - // Add this single function to the symbol table, so the debugger prints the - // name instead of '???'. We give the symbol default global visibility. - ELFSym *FnSym = ELFSym::getGV(F, - ELF::STB_GLOBAL, - ELF::STT_FUNC, - ELF::STV_DEFAULT); - FnSym->SectionIdx = Text.SectionIdx; - FnSym->Size = I.FnEnd - I.FnStart; - FnSym->Value = 0; // Offset from start of section. - EW.SymbolList.push_back(FnSym); - - EW.doFinalization(M); - O.flush(); - - // When trying to debug why GDB isn't getting the debug info right, it's - // awfully helpful to write the object file to disk so that it can be - // inspected with readelf and objdump. - if (TM.Options.JITEmitDebugInfoToDisk) { - std::string Filename; - raw_string_ostream O2(Filename); - O2 << "/tmp/llvm_function_" << I.FnStart << "_" << F->getName() << ".o"; - O2.flush(); - std::string Errors; - raw_fd_ostream O3(Filename.c_str(), Errors); - O3 << Buffer; - O3.close(); - } - - return Buffer; -} - -void JITDebugRegisterer::RegisterFunction(const Function *F, DebugInfo &I) { - // TODO: Support non-ELF platforms. - if (!TM.getELFWriterInfo()) - return; - - std::string Buffer = MakeELF(F, I); - - jit_code_entry *JITCodeEntry = new jit_code_entry(); - JITCodeEntry->symfile_addr = Buffer.c_str(); - JITCodeEntry->symfile_size = Buffer.size(); - - // Add a mapping from F to the entry and buffer, so we can delete this - // info later. - FnMap[F] = std::make_pair(Buffer, JITCodeEntry); - - // Acquire the lock and do the registration. - { - MutexGuard locked(JITDebugLock); - __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; - - // Insert this entry at the head of the list. - JITCodeEntry->prev_entry = NULL; - jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry; - JITCodeEntry->next_entry = NextEntry; - if (NextEntry != NULL) { - NextEntry->prev_entry = JITCodeEntry; - } - __jit_debug_descriptor.first_entry = JITCodeEntry; - __jit_debug_descriptor.relevant_entry = JITCodeEntry; - __jit_debug_register_code(); - } -} - -void JITDebugRegisterer::UnregisterFunctionInternal( - RegisteredFunctionsMap::iterator I) { - jit_code_entry *&JITCodeEntry = I->second.second; - - // Acquire the lock and do the unregistration. - { - MutexGuard locked(JITDebugLock); - __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; - - // Remove the jit_code_entry from the linked list. - jit_code_entry *PrevEntry = JITCodeEntry->prev_entry; - jit_code_entry *NextEntry = JITCodeEntry->next_entry; - if (NextEntry) { - NextEntry->prev_entry = PrevEntry; - } - if (PrevEntry) { - PrevEntry->next_entry = NextEntry; - } else { - assert(__jit_debug_descriptor.first_entry == JITCodeEntry); - __jit_debug_descriptor.first_entry = NextEntry; - } - - // Tell GDB which entry we removed, and unregister the code. - __jit_debug_descriptor.relevant_entry = JITCodeEntry; - __jit_debug_register_code(); - } - - delete JITCodeEntry; - JITCodeEntry = NULL; - - // Free the ELF file in memory. - std::string &Buffer = I->second.first; - Buffer.clear(); -} - -void JITDebugRegisterer::UnregisterFunction(const Function *F) { - // TODO: Support non-ELF platforms. - if (!TM.getELFWriterInfo()) - return; - - RegisteredFunctionsMap::iterator I = FnMap.find(F); - if (I == FnMap.end()) return; - UnregisterFunctionInternal(I); - FnMap.erase(I); -} - -} // end namespace llvm diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h deleted file mode 100644 index dce506b..0000000 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h +++ /dev/null @@ -1,116 +0,0 @@ -//===-- JITDebugRegisterer.h - Register debug symbols for JIT -------------===// -// -// 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 JITDebugRegisterer object that is used by the JIT to -// register debug info with debuggers like GDB. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H -#define LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/Support/DataTypes.h" -#include <string> - -// This must be kept in sync with gdb/gdb/jit.h . -extern "C" { - - typedef enum { - JIT_NOACTION = 0, - JIT_REGISTER_FN, - JIT_UNREGISTER_FN - } jit_actions_t; - - struct jit_code_entry { - struct jit_code_entry *next_entry; - struct jit_code_entry *prev_entry; - const char *symfile_addr; - uint64_t symfile_size; - }; - - struct jit_descriptor { - uint32_t version; - // This should be jit_actions_t, but we want to be specific about the - // bit-width. - uint32_t action_flag; - struct jit_code_entry *relevant_entry; - struct jit_code_entry *first_entry; - }; - -} - -namespace llvm { - -class ELFSection; -class Function; -class TargetMachine; - - -/// This class encapsulates information we want to send to the debugger. -/// -struct DebugInfo { - uint8_t *FnStart; - uint8_t *FnEnd; - uint8_t *EhStart; - uint8_t *EhEnd; - - DebugInfo() : FnStart(0), FnEnd(0), EhStart(0), EhEnd(0) {} -}; - -typedef DenseMap< const Function*, std::pair<std::string, jit_code_entry*> > - RegisteredFunctionsMap; - -/// This class registers debug info for JITed code with an attached debugger. -/// Without proper debug info, GDB can't do things like source level debugging -/// or even produce a proper stack trace on linux-x86_64. To use this class, -/// whenever a function is JITed, create a DebugInfo struct and pass it to the -/// RegisterFunction method. The method will then do whatever is necessary to -/// inform the debugger about the JITed function. -class JITDebugRegisterer { - - TargetMachine &TM; - - /// FnMap - A map of functions that have been registered to the associated - /// temporary files. Used for cleanup. - RegisteredFunctionsMap FnMap; - - /// MakeELF - Builds the ELF file in memory and returns a std::string that - /// contains the ELF. - std::string MakeELF(const Function *F, DebugInfo &I); - -public: - JITDebugRegisterer(TargetMachine &tm); - - /// ~JITDebugRegisterer - Unregisters all code and frees symbol files. - /// - ~JITDebugRegisterer(); - - /// RegisterFunction - Register debug info for the given function with an - /// attached debugger. Clients must call UnregisterFunction on all - /// registered functions before deleting them to free the associated symbol - /// file and unregister it from the debugger. - void RegisterFunction(const Function *F, DebugInfo &I); - - /// UnregisterFunction - Unregister the debug info for the given function - /// from the debugger and free associated memory. - void UnregisterFunction(const Function *F); - -private: - /// UnregisterFunctionInternal - Unregister the debug info for the given - /// function from the debugger and delete any temporary files. The private - /// version of this method does not remove the function from FnMap so that it - /// can be called while iterating over FnMap. - void UnregisterFunctionInternal(RegisteredFunctionsMap::iterator I); - -}; - -} // end namespace llvm - -#endif // LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index d9fa509..504c8bd 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -14,7 +14,6 @@ #define DEBUG_TYPE "jit" #include "JIT.h" -#include "JITDebugRegisterer.h" #include "JITDwarfEmitter.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Constants.h" @@ -77,8 +76,8 @@ namespace { 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."); + llvm_unreachable("The JIT doesn't know how to handle a" + " RAUW on a value it has emitted."); } }; @@ -324,9 +323,6 @@ namespace { /// DE - The dwarf emitter for the jit. 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. DenseMap<MCSymbol*, uintptr_t> LabelLocations; @@ -364,26 +360,20 @@ namespace { bool JITExceptionHandling; - bool JITEmitDebugInfo; - public: JITEmitter(JIT &jit, JITMemoryManager *JMM, TargetMachine &TM) : SizeEstimate(0), Resolver(jit, *this), MMI(0), CurFn(0), EmittedFunctions(this), TheJIT(&jit), - JITExceptionHandling(TM.Options.JITExceptionHandling), - JITEmitDebugInfo(TM.Options.JITEmitDebugInfo) { + JITExceptionHandling(TM.Options.JITExceptionHandling) { MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager(); if (jit.getJITInfo().needsGOT()) { MemMgr->AllocateGOT(); DEBUG(dbgs() << "JIT is managing a GOT\n"); } - if (JITExceptionHandling || JITEmitDebugInfo) { + if (JITExceptionHandling) { DE.reset(new JITDwarfEmitter(jit)); } - if (JITEmitDebugInfo) { - DR.reset(new JITDebugRegisterer(TM)); - } } ~JITEmitter() { delete MemMgr; @@ -974,7 +964,7 @@ bool JITEmitter::finishFunction(MachineFunction &F) { } }); - if (JITExceptionHandling || JITEmitDebugInfo) { + if (JITExceptionHandling) { uintptr_t ActualSize = 0; SavedBufferBegin = BufferBegin; SavedBufferEnd = BufferEnd; @@ -989,7 +979,6 @@ bool JITEmitter::finishFunction(MachineFunction &F) { EhStart); MemMgr->endExceptionTable(F.getFunction(), BufferBegin, CurBufferPtr, FrameRegister); - uint8_t *EhEnd = CurBufferPtr; BufferBegin = SavedBufferBegin; BufferEnd = SavedBufferEnd; CurBufferPtr = SavedCurBufferPtr; @@ -997,15 +986,6 @@ bool JITEmitter::finishFunction(MachineFunction &F) { if (JITExceptionHandling) { TheJIT->RegisterTable(F.getFunction(), FrameRegister); } - - if (JITEmitDebugInfo) { - DebugInfo I; - I.FnStart = FnStart; - I.FnEnd = FnEnd; - I.EhStart = EhStart; - I.EhEnd = EhEnd; - DR->RegisterFunction(F.getFunction(), I); - } } if (MMI) @@ -1046,10 +1026,6 @@ void JITEmitter::deallocateMemForFunction(const Function *F) { if (JITExceptionHandling) { TheJIT->DeregisterTable(F); } - - if (JITEmitDebugInfo) { - DR->UnregisterFunction(F); - } } @@ -1185,6 +1161,9 @@ void JITEmitter::emitJumpTableInfo(MachineJumpTableInfo *MJTI) { } break; } + case MachineJumpTableInfo::EK_GPRel64BlockAddress: + llvm_unreachable( + "JT Info emission not implemented for GPRel64BlockAddress yet."); } } diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp index eec23ce..efd570d 100644 --- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp +++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp @@ -441,6 +441,50 @@ namespace { return (uint8_t*)DataAllocator.Allocate(Size, Alignment); } + /// allocateCodeSection - Allocate memory for a code section. + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID) { + // FIXME: Alignement handling. + FreeRangeHeader* candidateBlock = FreeMemoryList; + FreeRangeHeader* head = FreeMemoryList; + FreeRangeHeader* iter = head->Next; + + uintptr_t largest = candidateBlock->BlockSize; + + // Search for the largest free block. + while (iter != head) { + if (iter->BlockSize > largest) { + largest = iter->BlockSize; + candidateBlock = iter; + } + iter = iter->Next; + } + + largest = largest - sizeof(MemoryRangeHeader); + + // If this block isn't big enough for the allocation desired, allocate + // another block of memory and add it to the free list. + if (largest < Size || largest <= FreeRangeHeader::getMinBlockSize()) { + DEBUG(dbgs() << "JIT: Allocating another slab of memory for function."); + candidateBlock = allocateNewCodeSlab((size_t)Size); + } + + // Select this candidate block for allocation + CurBlock = candidateBlock; + + // Allocate the entire memory block. + FreeMemoryList = candidateBlock->AllocateBlock(); + // Release the memory at the end of this block that isn't needed. + FreeMemoryList = CurBlock->TrimAllocationToSize(FreeMemoryList, Size); + return (uint8_t *)(CurBlock + 1); + } + + /// allocateDataSection - Allocate memory for a data section. + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID) { + return (uint8_t*)DataAllocator.Allocate(Size, Alignment); + } + /// startExceptionTable - Use startFunctionBody to allocate memory for the /// function's exception table. uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) { |