[llvm-commits] Enable exceptions in JIT for Darwin
Evan Cheng
evan.cheng at apple.com
Tue Aug 26 23:43:06 PDT 2008
On Aug 24, 2008, at 2:21 AM, Nicolas Geoffray wrote:
> Hi Evan,
>
> Evan Cheng wrote:
>>
>> + // Allocate a new LibgccObject to represent this frame.
>> Deallocation of this
>> + // object may be impossible: libgcc does not seem to deallocate
>> it,
>> even with
>> + // __deregister_frame. Deallocating it manually may also cause
>> libgcc to
>> + // crash.
>> + struct LibgccObject* ob = (struct LibgccObject*)
>> + malloc(sizeof(struct LibgccObject));
>>
>> Are you sure you can't deallocate it when the JIT is teared down?
>>
>
> Not really sure. I can add a table of LibgccObject* to the LLVM JIT,
> and
> deallocate them when the JIT is destroyed. However, libgcc will
> probably
> dislike this if exceptions still occur after the JIT is destroyed. It
> may be feasible to remove the exception tables from libgcc's linked
> list, but libgcc may cache the tables some places I don't know.
>
> A deep understanding of how things work in libgcc is needed :). And I
> double-checked, my comment is actually wrong, the __deregister_frame
> function does deallocate the objects. However, it does not work with
> the
> darwin code for libgcc...
After looking into this a bit, I think this is ok.
Nick, do you know anything about this?
Thanks,
Evan
>
>
> Nicolas
>
>
>> Evan
>>
>>
>> On Aug 21, 2008, at 1:20 AM, Nicolas Geoffray wrote:
>>
>>> Hi Evan,
>>>
>>> New patch with new un-gcc documentation :)
>>>
>>> Thanks for reviewing!
>>>
>>> Nicolas
>>>
>>> Evan Cheng wrote:
>>>> Hi Nicolas,
>>>>
>>>> Comments in line.
>>>>
>>>> On Aug 19, 2008, at 8:04 AM, Nicolas Geoffray wrote:
>>>>
>>>>
>>>>> Dear all,
>>>>>
>>>>> Here's a patch that enables exception handling on Darwin with the
>>>>> JIT. It's really ugly, it's a workaround to work with libgcc which
>>>>> is doing crazy stuff when unwinding the stack. The
>>>>> __register_frame function was sufficient enough for Linux, but
>>>>> unfortunately, the code for darwin erases by default the
>>>>> registered frames. In a perfect world, I think libgcc should be
>>>>> modified....
>>>>>
>>>>>
>>>>> I'd be totally OK if you don't want this patch in, as it's an ugly
>>>>> workaround. I can move the patch to vmkit, and that would be fine
>>>>> by me. However, this makes lli work out of the box with
>>>>> exceptions
>>>>> and darwin, so it's still an improvement.
>>>>>
>>>>> Nicolas
>>>>> Index: lib/ExecutionEngine/JIT/JIT.cpp
>>>>> =
>>>>> ==================================================================
>>>>> --- lib/ExecutionEngine/JIT/JIT.cpp (revision 54920)
>>>>> +++ lib/ExecutionEngine/JIT/JIT.cpp (working copy)
>>>>> @@ -64,10 +64,73 @@
>>>>> }
>>>>> }
>>>>>
>>>>> +
>>>>> #if defined (__GNUC__)
>>>>> extern "C" void __register_frame(void*);
>>>>> -#endif
>>>>>
>>>>> +#if defined (__APPLE__)
>>>>> +struct object {
>>>>> + void *pc_begin;
>>>>> + void *tbase;
>>>>> + void *dbase;
>>>>> + void* real_begin;
>>>>> +
>>>>> + 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;
>>>>> + } s;
>>>>>
>>>>
>>>> Please pick more descriptive names than object, etc. Also, please
>>>> try to match the naming convention used in the file. Some
>>>> documentation is definitely welcome. :-)
>>>>
>>>>> +
>>>>> + // Be pessimistic, include this field even if GCC
>>>>> + // may not have it.
>>>>> + char *fde_end;
>>>>> +
>>>>> + struct object *next;
>>>>> +};
>>>>> +
>>>>> +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 */
>>>>> +
>>>>> +struct km_object_info {
>>>>> + struct object* seen_objects;
>>>>> + struct object* unseen_objects;
>>>>> + unsigned spare[2];
>>>>> +};
>>>>> +
>>>>> +extern "C" void darwin_register_frame(void* begin) {
>>>>> + struct km_object_info* the_obj_info = (struct km_object_info*)
>>>>> + _keymgr_get_and_lock_processwide_ptr
>>>>> (KEYMGR_GCC3_DW2_OBJ_LIST);
>>>>> +
>>>>> + struct object* ob = (struct object*)malloc(sizeof(struct
>>>>> object));
>>>>>
>>>>
>>>> Who frees this?
>>>>
>>>>
>>>>> + ob->pc_begin = (void *)-1;
>>>>> + ob->tbase = 0;
>>>>> + ob->dbase = 0;
>>>>> + ob->real_begin = begin;
>>>>> + ob->s.i = 0;
>>>>> + //ob->s.b.encoding = DW_EH_PE_omit;
>>>>>
>>>>
>>>> Why is this commented out?
>>>>
>>>>
>>>>> + ob->s.b.encoding = 0xff;
>>>>> +
>>>>> + // Put the info on both places, as libgcc uses the first or the
>>>>> + // the second field.
>>>>> + ob->fde_end = (char*)the_obj_info->unseen_objects;
>>>>> + ob->next = (struct object*)the_obj_info->unseen_objects;
>>>>>
>>>>
>>>> Are the casting necessary? Why not just define the types correctly.
>>>>
>>>>
>>>>> +
>>>>> + the_obj_info->unseen_objects = ob;
>>>>> +
>>>>> + _keymgr_set_and_unlock_processwide_ptr
>>>>> (KEYMGR_GCC3_DW2_OBJ_LIST,
>>>>> + the_obj_info);
>>>>> +
>>>>> +}
>>>>>
>>>>
>>>> Function level documentation please.
>>>>
>>>> Thanks!
>>>>
>>>> Evan
>>>>
>>>>
>>>>> +
>>>>> +#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
>>>>> /// of the module provider.
>>>>> @@ -108,8 +171,20 @@
>>>>>
>>>>> // Register routine for informing unwinding runtime about new EH
>>>>> frames
>>>>> #if defined(__GNUC__)
>>>>> +#if defined(__APPLE__)
>>>>> + struct km_object_info* the_obj_info = (struct km_object_info*)
>>>>> + _keymgr_get_and_lock_processwide_ptr
>>>>> (KEYMGR_GCC3_DW2_OBJ_LIST);
>>>>> +
>>>>> + if (!the_obj_info) {
>>>>> + the_obj_info = (km_object_info*)malloc(sizeof(struct
>>>>> km_object_info));
>>>>> + _keymgr_set_and_unlock_processwide_ptr
>>>>> (KEYMGR_GCC3_DW2_OBJ_LIST,
>>>>> + the_obj_info);
>>>>> + }
>>>>> + InstallExceptionTableRegister(darwin_register_frame);
>>>>> +#else
>>>>> InstallExceptionTableRegister(__register_frame);
>>>>> -#endif
>>>>> +#endif // __APPLE__
>>>>> +#endif // __GNUC__
>>>>>
>>>>>
>>>>> // Initialize passes.
>>>>> PM.doInitialization();
>>>>> _______________________________________________
>>>>> llvm-commits mailing list
>>>>> llvm-commits at cs.uiuc.edu <mailto:llvm-commits at cs.uiuc.edu>
>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>>>>
>>>>
>>>> _______________________________________________
>>>> llvm-commits mailing list
>>>> llvm-commits at cs.uiuc.edu <mailto:llvm-commits at cs.uiuc.edu>
>>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>>>
>>>
>>> Index: lib/ExecutionEngine/JIT/JIT.cpp
>>> ===================================================================
>>> --- lib/ExecutionEngine/JIT/JIT.cpp (revision 54988)
>>> +++ lib/ExecutionEngine/JIT/JIT.cpp (working copy)
>>> @@ -64,10 +64,128 @@
>>> }
>>> }
>>>
>>> +
>>> #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: libgcc does not seem to deallocate
>>> it, even with
>>> + // __deregister_frame. Deallocating it manually may also cause
>>> libgcc to
>>> + // crash.
>>> + 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
>>> /// of the module provider.
>>> @@ -108,8 +226,23 @@
>>>
>>> // 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();
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at cs.uiuc.edu <mailto:llvm-commits at cs.uiuc.edu>
>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list