[llvm-commits] Enable exceptions in JIT for Darwin
Evan Cheng
evan.cheng at apple.com
Sun Aug 24 00:49:42 PDT 2008
Hi Nicolas,
It looks great. But this is scary:
+ // 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?
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
>>> 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
>>
>
> 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
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20080824/8e08c1f0/attachment.html>
More information about the llvm-commits
mailing list