[llvm-commits] Enable exceptions in JIT for Darwin

Nicolas Geoffray nicolas.geoffray at lip6.fr
Sun Aug 24 02:21:21 PDT 2008


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...

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
>   




More information about the llvm-commits mailing list