diff options
Diffstat (limited to 'lib/ExecutionEngine/JIT/JIT.cpp')
-rw-r--r-- | lib/ExecutionEngine/JIT/JIT.cpp | 137 |
1 files changed, 135 insertions, 2 deletions
diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 9a3bd3bda1..39ecc2796c 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -64,9 +64,127 @@ namespace llvm { } } + #if defined (__GNUC__) + +// libgcc defines the __register_frame function to dynamically register new +// dwarf frames for exception handling. This functionality is not portable +// across compilers and is only provided by GCC. We use the __register_frame +// function here so that code generated by the JIT cooperates with the unwinding +// runtime of libgcc. When JITting with exception handling enable, LLVM +// generates dwarf frames and registers it to libgcc with __register_frame. +// +// The __register_frame function works with Linux. +// +// Unfortunately, this functionality seems to be in libgcc after the unwinding +// library of libgcc for darwin was written. The code for darwin overwrites the +// value updated by __register_frame with a value fetched with "keymgr". +// "keymgr" is an obsolete functionality, which should be rewritten some day. +// In the meantime, since "keymgr" is on all libgccs shipped with apple-gcc, we +// need a workaround in LLVM which uses the "keymgr" to dynamically modify the +// values of an opaque key, used by libgcc to find dwarf tables. + extern "C" void __register_frame(void*); -#endif + +#if defined (__APPLE__) + +namespace { + +// LibgccObject - This is the structure defined in libgcc. There is no #include +// provided for this structure, so we also define it here. libgcc calls it +// "struct object". The structure is undocumented in libgcc. +struct LibgccObject { + void *unused1; + void *unused2; + void *unused3; + + /// frame - Pointer to the exception table. + void *frame; + + /// encoding - The encoding of the object? + union { + struct { + unsigned long sorted : 1; + unsigned long from_array : 1; + unsigned long mixed_encoding : 1; + unsigned long encoding : 8; + unsigned long count : 21; + } b; + size_t i; + } encoding; + + /// fde_end - libgcc defines this field only if some macro is defined. We + /// include this field even if it may not there, to make libgcc happy. + char *fde_end; + + /// next - At least we know it's a chained list! + struct LibgccObject *next; +}; + +// "kemgr" stuff. Apparently, all frame tables are stored there. +extern "C" void _keymgr_set_and_unlock_processwide_ptr(int, void *); +extern "C" void *_keymgr_get_and_lock_processwide_ptr(int); +#define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */ + +/// LibgccObjectInfo - libgcc defines this struct as km_object_info. It +/// probably contains all dwarf tables that are loaded. +struct LibgccObjectInfo { + + /// seenObjects - LibgccObjects already parsed by the unwinding runtime. + /// + struct LibgccObject* seenObjects; + + /// unseenObjects - LibgccObjects not parsed yet by the unwinding runtime. + /// + struct LibgccObject* unseenObjects; + + unsigned unused[2]; +}; + +// for DW_EH_PE_omit +#include "llvm/Support/Dwarf.h" + +/// darwin_register_frame - Since __register_frame does not work with darwin's +/// libgcc,we provide our own function, which "tricks" libgcc by modifying the +/// "Dwarf2 object list" key. +void DarwinRegisterFrame(void* FrameBegin) { + // Get the key. + struct LibgccObjectInfo* LOI = (struct LibgccObjectInfo*) + _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); + + // Allocate a new LibgccObject to represent this frame. Deallocation of this + // object may be impossible: since darwin code in libgcc was written after + // the ability to dynamically register frames, things may crash if we + // deallocate it. + struct LibgccObject* ob = (struct LibgccObject*) + malloc(sizeof(struct LibgccObject)); + + // Do like libgcc for the values of the field. + ob->unused1 = (void *)-1; + ob->unused2 = 0; + ob->unused3 = 0; + ob->frame = FrameBegin; + ob->encoding.i = 0; + ob->encoding.b.encoding = llvm::dwarf::DW_EH_PE_omit; + + // Put the info on both places, as libgcc uses the first or the the second + // field. Note that we rely on having two pointers here. If fde_end was a + // char, things would get complicated. + ob->fde_end = (char*)LOI->unseenObjects; + ob->next = LOI->unseenObjects; + + // Update the key's unseenObjects list. + LOI->unseenObjects = ob; + + // Finally update the "key". Apparently, libgcc requires it. + _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, + LOI); + +} + +} +#endif // __APPLE__ +#endif // __GNUC__ /// createJIT - This is the factory method for creating a JIT for the current /// machine, it does not fall back to the interpreter. This takes ownership @@ -108,8 +226,23 @@ JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji, // Register routine for informing unwinding runtime about new EH frames #if defined(__GNUC__) +#if defined(__APPLE__) + struct LibgccObjectInfo* LOI = (struct LibgccObjectInfo*) + _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); + + // The key is created on demand, and libgcc creates it the first time an + // exception occurs. Since we need the key to register frames, we create + // it now. + if (!LOI) { + LOI = (LibgccObjectInfo*)malloc(sizeof(struct LibgccObjectInfo)); + _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, + LOI); + } + InstallExceptionTableRegister(DarwinRegisterFrame); +#else InstallExceptionTableRegister(__register_frame); -#endif +#endif // __APPLE__ +#endif // __GNUC__ // Initialize passes. PM.doInitialization(); |