[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