diff options
Diffstat (limited to 'lib/ExecutionEngine')
| -rw-r--r-- | lib/ExecutionEngine/Interpreter/Execution.cpp | 7 | ||||
| -rw-r--r-- | lib/ExecutionEngine/Interpreter/Interpreter.cpp | 5 | ||||
| -rw-r--r-- | lib/ExecutionEngine/Interpreter/Interpreter.h | 2 | ||||
| -rw-r--r-- | lib/ExecutionEngine/JIT/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lib/ExecutionEngine/JIT/JIT.cpp | 60 | ||||
| -rw-r--r-- | lib/ExecutionEngine/JIT/JIT.h | 17 | ||||
| -rw-r--r-- | lib/ExecutionEngine/JIT/JITEmitter.cpp | 165 | ||||
| -rw-r--r-- | lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp | 173 | 
8 files changed, 253 insertions, 177 deletions
diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp index 7dfeae0ab2eb..bb3f64e626f0 100644 --- a/lib/ExecutionEngine/Interpreter/Execution.cpp +++ b/lib/ExecutionEngine/Interpreter/Execution.cpp @@ -29,7 +29,6 @@  using namespace llvm;  STATISTIC(NumDynamicInsts, "Number of dynamic instructions executed"); -static Interpreter *TheEE = 0;  static cl::opt<bool> PrintVolatile("interpreter-print-volatile", cl::Hidden,            cl::desc("make the interpreter print every volatile load and store")); @@ -51,10 +50,6 @@ static void SetValue(Value *V, GenericValue Val, ExecutionContext &SF) {    SF.Values[V] = Val;  } -void Interpreter::initializeExecutionEngine() { -  TheEE = this; -} -  //===----------------------------------------------------------------------===//  //                    Binary Instruction Implementations  //===----------------------------------------------------------------------===// @@ -815,7 +810,7 @@ GenericValue Interpreter::executeGEPOperation(Value *Ptr, gep_type_iterator I,  void Interpreter::visitGetElementPtrInst(GetElementPtrInst &I) {    ExecutionContext &SF = ECStack.back(); -  SetValue(&I, TheEE->executeGEPOperation(I.getPointerOperand(), +  SetValue(&I, executeGEPOperation(I.getPointerOperand(),                                     gep_type_begin(I), gep_type_end(I), SF), SF);  } diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.cpp b/lib/ExecutionEngine/Interpreter/Interpreter.cpp index ded65d546701..d7f38ef548f2 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.cpp +++ b/lib/ExecutionEngine/Interpreter/Interpreter.cpp @@ -29,10 +29,7 @@ static struct RegisterInterp {  } -namespace llvm { -  void LinkInInterpreter() { -  } -} +extern "C" void LLVMLinkInInterpreter() { }  /// create - Create a new interpreter object.  This can never fail.  /// diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h index 8a285ecb82c0..6b13c90f6671 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.h +++ b/lib/ExecutionEngine/Interpreter/Interpreter.h @@ -202,7 +202,7 @@ private:  // Helper functions    void *getPointerToFunction(Function *F) { return (void*)F; } -  void initializeExecutionEngine(); +  void initializeExecutionEngine() { }    void initializeExternalFunctions();    GenericValue getConstantExprValue(ConstantExpr *CE, ExecutionContext &SF);    GenericValue getOperandValue(Value *V, ExecutionContext &SF); diff --git a/lib/ExecutionEngine/JIT/CMakeLists.txt b/lib/ExecutionEngine/JIT/CMakeLists.txt index e0c13a10f0b3..bf915f7c4ca1 100644 --- a/lib/ExecutionEngine/JIT/CMakeLists.txt +++ b/lib/ExecutionEngine/JIT/CMakeLists.txt @@ -7,5 +7,6 @@ add_llvm_library(LLVMJIT    JITDwarfEmitter.cpp    JITEmitter.cpp    JITMemoryManager.cpp +  MacOSJITEventListener.cpp    TargetSelect.cpp    ) diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 43995cb0ecd6..db5a306badc4 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -20,8 +20,9 @@  #include "llvm/Instructions.h"  #include "llvm/ModuleProvider.h"  #include "llvm/CodeGen/JITCodeEmitter.h" -#include "llvm/ExecutionEngine/GenericValue.h"  #include "llvm/CodeGen/MachineCodeInfo.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/JITEventListener.h"  #include "llvm/Target/TargetData.h"  #include "llvm/Target/TargetMachine.h"  #include "llvm/Target/TargetJITInfo.h" @@ -60,9 +61,7 @@ static struct RegisterJIT {  } -namespace llvm { -  void LinkInJIT() { -  } +extern "C" void LLVMLinkInJIT() {  } @@ -509,6 +508,40 @@ GenericValue JIT::runFunction(Function *F,    return runFunction(Stub, std::vector<GenericValue>());  } +void JIT::RegisterJITEventListener(JITEventListener *L) { +  if (L == NULL) +    return; +  MutexGuard locked(lock); +  EventListeners.push_back(L); +} +void JIT::UnregisterJITEventListener(JITEventListener *L) { +  if (L == NULL) +    return; +  MutexGuard locked(lock); +  std::vector<JITEventListener*>::reverse_iterator I= +      std::find(EventListeners.rbegin(), EventListeners.rend(), L); +  if (I != EventListeners.rend()) { +    std::swap(*I, EventListeners.back()); +    EventListeners.pop_back(); +  } +} +void JIT::NotifyFunctionEmitted( +    const Function &F, +    void *Code, size_t Size, +    const JITEvent_EmittedFunctionDetails &Details) { +  MutexGuard locked(lock); +  for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { +    EventListeners[I]->NotifyFunctionEmitted(F, Code, Size, Details); +  } +} + +void JIT::NotifyFreeingMachineCode(const Function &F, void *OldPtr) { +  MutexGuard locked(lock); +  for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { +    EventListeners[I]->NotifyFreeingMachineCode(F, OldPtr); +  } +} +  /// runJITOnFunction - Run the FunctionPassManager full of  /// just-in-time compilation passes on F, hopefully filling in  /// GlobalAddress[F] with the address of F's machine code. @@ -516,11 +549,23 @@ GenericValue JIT::runFunction(Function *F,  void JIT::runJITOnFunction(Function *F, MachineCodeInfo *MCI) {    MutexGuard locked(lock); -  registerMachineCodeInfo(MCI); +  class MCIListener : public JITEventListener { +    MachineCodeInfo *const MCI; +   public: +    MCIListener(MachineCodeInfo *mci) : MCI(mci) {} +    virtual void NotifyFunctionEmitted(const Function &, +                                       void *Code, size_t Size, +                                       const EmittedFunctionDetails &) { +      MCI->setAddress(Code); +      MCI->setSize(Size); +    } +  }; +  MCIListener MCIL(MCI); +  RegisterJITEventListener(&MCIL);    runJITOnFunctionUnlocked(F, locked); -  registerMachineCodeInfo(0); +  UnregisterJITEventListener(&MCIL);  }  void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) { @@ -711,3 +756,6 @@ void JIT::addPendingFunction(Function *F) {    MutexGuard locked(lock);    jitstate->getPendingFunctions(locked).push_back(F);  } + + +JITEventListener::~JITEventListener() {} diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h index 3ccb2dd8126b..66417a71b2c8 100644 --- a/lib/ExecutionEngine/JIT/JIT.h +++ b/lib/ExecutionEngine/JIT/JIT.h @@ -20,10 +20,11 @@  namespace llvm {  class Function; -class TargetMachine; -class TargetJITInfo; +class JITEvent_EmittedFunctionDetails;  class MachineCodeEmitter;  class MachineCodeInfo; +class TargetJITInfo; +class TargetMachine;  class JITState {  private: @@ -52,6 +53,7 @@ class JIT : public ExecutionEngine {    TargetMachine &TM;       // The current target we are compiling to    TargetJITInfo &TJI;      // The JITInfo for the target we are compiling to    JITCodeEmitter *JCE;     // JCE object +  std::vector<JITEventListener*> EventListeners;    JITState *jitstate; @@ -157,9 +159,18 @@ public:    // Run the JIT on F and return information about the generated code    void runJITOnFunction(Function *F, MachineCodeInfo *MCI = 0); +  virtual void RegisterJITEventListener(JITEventListener *L); +  virtual void UnregisterJITEventListener(JITEventListener *L); +  /// These functions correspond to the methods on JITEventListener.  They +  /// iterate over the registered listeners and call the corresponding method on +  /// each. +  void NotifyFunctionEmitted( +      const Function &F, void *Code, size_t Size, +      const JITEvent_EmittedFunctionDetails &Details); +  void NotifyFreeingMachineCode(const Function &F, void *OldPtr); +  private:    static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM); -  void registerMachineCodeInfo(MachineCodeInfo *MCI);    void runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked);    void updateFunctionStub(Function *F);    void updateDlsymStubTable(); diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 43f23e443426..8fe7ab848b73 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -24,8 +24,9 @@  #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" @@ -411,136 +412,6 @@ void *JITResolver::JITCompilerFn(void *Stub) {  }  //===----------------------------------------------------------------------===// -// 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 { @@ -616,11 +487,8 @@ namespace {      // in the JITResolver's ExternalFnToStubMap.      StringMap<void *> ExtFnStubs; -    // MCI - A pointer to a MachineCodeInfo object to update with information. -    MachineCodeInfo *MCI; -    public: -    JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit), CurFn(0), MCI(0) { +    JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit), CurFn(0) {        MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager();        if (jit.getJITInfo().needsGOT()) {          MemMgr->AllocateGOT(); @@ -716,10 +584,6 @@ namespace {      JITMemoryManager *getMemMgr(void) const { return MemMgr; } -    void setMachineCodeInfo(MachineCodeInfo *mci) { -      MCI = mci; -    } -    private:      void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub);      void *getPointerToGVIndirectSym(GlobalValue *V, void *Reference, @@ -1157,21 +1021,16 @@ bool JITEmitter::finishFunction(MachineFunction &F) {    // 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"; -  if (MCI) { -    MCI->setAddress(FnStart); -    MCI->setSize(FnEnd-FnStart); -  } -    Relocations.clear();    ConstPoolAddresses.clear(); @@ -1495,13 +1354,6 @@ void *JIT::getPointerToFunctionOrStub(Function *F) {    return JE->getJITResolver().getFunctionStub(F);  } -void JIT::registerMachineCodeInfo(MachineCodeInfo *mc) { -  assert(isa<JITEmitter>(JCE) && "Unexpected MCE?"); -  JITEmitter *JE = cast<JITEmitter>(getCodeEmitter()); - -  JE->setMachineCodeInfo(mc); -} -  void JIT::updateFunctionStub(Function *F) {    // Get the empty stub we generated earlier.    assert(isa<JITEmitter>(JCE) && "Unexpected MCE?"); @@ -1609,10 +1461,9 @@ void JIT::freeMachineCodeForFunction(Function *F) {    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>(JCE) && "Unexpected MCE?");    cast<JITEmitter>(JCE)->deallocateMemForFunction(F);  } - diff --git a/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp b/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp new file mode 100644 index 000000000000..3b8b84ce5bcb --- /dev/null +++ b/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp @@ -0,0 +1,173 @@ +//===-- 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 &) { +  const char *const FnName = F.getNameStart(); +  assert(FnName != 0 && 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(FnName); +  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  | 
