[LLVMdev] Catching C++ exceptions, cleaning up, rethrowing

Paul J. Lucas paul at lucasmail.org
Sun Apr 8 08:47:57 PDT 2012


On Apr 8, 2012, at 4:20 AM, Bill Wendling wrote:

> On Apr 4, 2012, at 9:32 PM, Paul J. Lucas wrote:
> 
>> This all seems to work just fine.  I can throw a C++ exception either in a C++ object's constructor or in an ordinary member function and the stack unwinds correctly (the object's destructors are called) and the exception is propagated back up the C++ code that called the JIT'd code.
>> 
>> So is this the right way to do this?  Am I missing anything?
> 
> This looks like roughly what I would expect the code to be. I'd have to see the LLVM IR it generated to be sure. But it looks okay to me. (And if it's working for you, all the better. ;-) )

A snippet of the IR code is:

> entry:
>   %add_it = alloca %add_iterator, align 8
>   %y_it = alloca %singleton_iterator, align 8
>   %x_it = alloca %singleton_iterator, align 8
>   %y = alloca %item, align 8
>   %x = alloca %item, align 8
>   %exception_caught_flag = alloca i8, align 1
>   store i8 0, i8* %exception_caught_flag, align 1
>   %caught_result_storage = alloca %0, align 8
>   store %0 zeroinitializer, %0* %caught_result_storage, align 8
>   %0 = bitcast %item* %x to void*
>   invoke void @thunk_item_M_new_i(void* %0, i32 1)
>           to label %normal unwind label %unwind
> 
> exit:                                             ; preds = %unwind, %dtor
>   %1 = phi %0 [ %5, %unwind ], [ %6, %dtor ]
>   %2 = phi i8 [ 1, %unwind ], [ %7, %dtor ]
>   %3 = icmp eq i8 %2, 0
>   br i1 %3, label %return, label %unwind_resume
> 
> return:                                           ; preds = %exit
>   ret void
> 
> unwind_resume:                                    ; preds = %exit
>   resume %0 %1
> 
> normal:                                           ; preds = %entry
>   %4 = bitcast %item* %y to void*
>   invoke void @thunk_item_M_new_i(void* %4, i32 2)
>           to label %normal1 unwind label %unwind2
> 
> unwind:                                           ; preds = %entry
>   %5 = landingpad %0 personality i32 (...)* @__gxx_personality_v0
>           cleanup
>   store %0 %5, %0* %caught_result_storage, align 8
>   store i8 1, i8* %exception_caught_flag, align 1
>   br label %exit
> 
> dtor:                                             ; preds = %unwind2, %dtor3
>   %6 = phi %0 [ %9, %unwind2 ], [ %10, %dtor3 ]
>   %7 = phi i8 [ 1, %unwind2 ], [ %11, %dtor3 ]
>   call void @thunk_item_M_delete(void* %0)
>   br label %exit
> 
> normal1:                                          ; preds = %normal
>   %8 = bitcast %singleton_iterator* %x_it to void*
>   invoke void @thunk_singleton_iterator_M_new(void* %8, void* %0)
>           to label %normal4 unwind label %unwind5
> 
> ; ...

I generate the "exit", "return", and "unwind_resume" blocks first followed by a sequence of "normal", "unwind", and "dtor" blocks.  A dtorN block calls dtorN-1 unless N=0 in which case it calls exit instead.

Now I think my last part of the puzzle is the personality function.  Running on a *nix system (Mac OS X), my code has:

> Function* getPersonalityFunction( Module *m ) {
>   if ( Function *const f = m->getFunction( "__gxx_personality_v0" ) )
>     return f;
>   return Function::Create(
>     FunctionType::get( Type::getInt32Ty( m->getContext() ), true ),
>     Function::ExternalLinkage,
>     "__gxx_personality_v0",
>     m
>   );
> }

for the personality function and it works.  But I assume that works only for a *nix/g++ system.  My code also needs to work when compiled on Windows using Visual Studio and I'm guessing that it needs a different personality function.  Where do I get that?

The code in ExceptionDemo.cpp doesn't say whether it's cross-platform.  Is it?  Would I instead need to copy/past all that code for the personality function?

- Paul





More information about the llvm-dev mailing list