[LLVMdev] Catching C++ exceptions, cleaning up, rethrowing
Bill Wendling
wendling at apple.com
Fri Mar 23 16:46:31 PDT 2012
On Mar 23, 2012, at 4:29 PM, Paul J. Lucas wrote:
> On Mar 23, 2012, at 3:25 PM, Bill Wendling wrote:
>
>> Let's take your example. You will have code that looks like this:
>>
>> extern "C" void thunk_item_M_delete( void *v_that ) {
>> item *that = 0;
>> try {
>> that = static_cast<item*>( v_that );
>> that->~item();
>> } catch (...) {
>> that->~item();
>> }
>> }
>
> No I wouldn't since destructors should never throw exceptions:
You're missing the point.
>> Now the point I was making is that all of the locally scoped variables will have their d'tors called automatically by the unwinding mechanism. So something like this:
>>
>> void foo() {
>> try {
>> Bar b;
>> mux(b); // may throw an exception.
>> } catch (...) {
>> // The d'tor for 'b' is called before the code is is executed.
>> }
>> }
>
> Except I don't have code like that. Again, the object is *not* constructed by a normal function, but a JIT'd function. Since LLVM knows nothing about C++ or destructors, I certainly have to call the destructor manually, e.g., obj->~Class();, for the case where no exception is thrown. My JIT'd code looks like:
>
> %item = type { [16 x i8] }
> %singleton_iterator = type { [24 x i8] }
> %add_iterator = type { [24 x i8] }
>
> define void @program(void* %result) {
> entry:
> ; alloc raw space for x on the stack
> %x = alloca %item, align 8
>
> ; alloc raw space for y on the stack
> %y = alloca %item, align 8
>
> ; call item::item(1) constructor for x as new(%0) item(1);
> %0 = bitcast %item* %x to void*
> call void @thunk_item_M_new_i(void* %0, i32 1)
>
> ; call item::item(2) constructor for y as new(%1) item(2);
> %1 = bitcast %item* %y to void*
> call void @thunk_item_M_new_i(void* %1, i32 2)
>
> ; Do something with x & y via another thunk_ function that MIGHT throw an exception.
> ; If an exception is thrown, the code below will never be reached.
>
> ; call destructor for x as %1->!item();
> call void @thunk_item_M_delete(void* %1)
>
> ; call destructor for y as %1->!item();
> call void @thunk_item_M_delete(void* %0)
> ret void
> }
>
> Clearly, I *must* call the destructors manually for the case where no exception is thrown (again, because LLVM knows nothing about C++ or destructors). If I do nothing else and an exception is thrown during the use of x & y, then control flow will never reach my JIT'd code that calls the destructors manually. I've tested this. It behaves as I describe it.
>
> So, to ensure the destructors are called, I have to catch the exception, call the destructors, and rethrow. I can't see any other way despite what you've been saying. If I'm still wrong, I'd really appreciate your continued patience in explaining where.
>
You need to look at how the equivalent code in C++ looks in LLVM IR. The "do something with x & y" part will be an 'invoke' that lands on at landing pad, where you will then call the d'tor to your allocated object.
-bw
More information about the llvm-dev
mailing list