Throwing and catching exceptions – Advanced IR Generation-3
The handling of an exception is framed by calls to __cxa_begin_catch() and __cxa_end_catch(). The __cxa_begin_catch() function needs one argument – the current exception – which is one of the values returned by the landingpad instruction. It returns a pointer to the exception payload – an int value in our case.
The __cxa_end_catch() function marks the end of exception handling and deallocates the memory allocated with __cxa_allocate_exception(). Please note that the runtime behavior is much more complicated if another exception is thrown inside the catch block. The exception is handled as follows:
catchint:
%payload = call ptr @__cxa_begin_catch(ptr %exc.ptr)
%retval = load i32, ptr %payload
call void @__cxa_end_catch()
br label %return
If the type of the current exception does not match the list in the throws() declaration, the unexpected exception handler is called. First, we need to check the type selector again:
filterorcleanup:
%tst.blzero = icmp slt i32 %exc.sel, 0
br i1 %tst.blzero, label %filter, label %cleanup
If the value of the type selector is lower than 0, then we call the handler:
filter:
call void @__cxa_call_unexpected(ptr %exc.ptr) 4
unreachable
Again, the handler is not expected to come back.
No cleanup work is needed in this case, so all the cleanup code does is resume the execution of the stack unwinder:
cleanup:
resume { ptr, i32 } %exc
One piece is still missing: libunwind drives the stack unwinding process, but it is not tied to a single language. Language-dependent handling is done in the personality function. For C++ on Linux, the personality function is called __gxx_personality_v0(). Depending on the platform or compiler, this name can vary. Each function that needs to take part in stack unwinding has a personality function attached. This personality function analyzes if the function catches an exception, has a non-matching filter list, or needs a cleanup call. It gives this information back to the unwinder, which acts accordingly. In LLVM IR, the pointer to the personality function is given as a part of the function definition:
define i32 @_Z3fooi(i32) personality ptr @__gxx_personality_v0