How to initiate/throw an exception (resume just continues)

I'm trying to add some basic exception handling to my language now and
I'm uncertain of how I actually start the exception propagation. It
appears that "resume" will continue the exception, but I see no mention
of how the exception actually starts.

If I look at the IR output of a simple C++ program I see that it calls
@__cxa_throw, but that is a library function. Somehow I must be able to
initiate the exception in LLVM?

Yes, by calling a library function. You will need to implement this for your language, along with a personality function (or reuse ones from some existing language). The __cxa_throw() function is responsible for allocating an exception structure that contains two things, the C++ information (such as the thrown object, its type_info, the current values of the terminate and unexpected handlers, and so on), and a generic structure for the unwind library. It then passes it to _Unwind_RaiseException(), which is the generic unwind routine.

The _Unwind_RaiseException() function walks up the stack, invoking the personality routine once to find a landing pad for a catch. If it fails to find one then it returns an error. If it succeeds, then it invokes them again to run cleanup code. The personality function is passed the thrown object and also a reference to the language-specific data area. This area is filled in by LLVM via landingpad instructions.

The resume instruction is just a convenience. It will be expanded to a call to another library function (_Unwind_Resume(), I think, but possible _Unwind_ResumeOrRethrow()), and it exists so that the IR doesn't have to have hard-coded knowledge of the semantics of one these functions.

The exact implementation of the personality function differs slightly between ARM and pretty much everything else for *NIX platforms. Win64 also has a very similar mechanism for exceptions, but I don't believe it is currently supported by LLVM. ARM now works in some cases, but is still quite buggy.

The personality function is probably the least fun code I've ever written (I've now done it three times, for three different languages, and it doesn't become any more fun). If you get it wrong, the stack is gone by the time you get into the debugger, so lots and lots of logging statements are your friend...

David

handlers, and so on), and a generic structure for the unwind library.
It then passes it to _Unwind_RaiseException(), which is the generic
unwind routine.

Excuse me if this sounds silly, but what "library" does the _Unwind_
series of functions come from? Is this a kind of target ABI instrinsic
library, or must I link with a particular runtime library to get these
functions?

I assume using the JIT there will somehow already be there, so at least
I can start experimenting. Perhaps another question, since this does
generate ABI compliant EH-tables, could my throw function just invoke a
native throw? That is, for really quick testing can I just create a c++
function which does a throw?

The personality function is probably the least fun code I've ever
written (I've now done it three times, for three different languages,
and it doesn't become any more fun). If you get it wrong, the stack
is gone by the time you get into the debugger, so lots and lots of
logging statements are your friend...

I feel excited already. :slight_smile:
I'm still quite unclear on this part as well. Don't suppose you ever
wrote a tutorial on this aspect, or have some example code you could show?

handlers, and so on), and a generic structure for the unwind library.
It then passes it to _Unwind_RaiseException(), which is the generic
unwind routine.

Excuse me if this sounds silly, but what "library" does the _Unwind_
series of functions come from? Is this a kind of target ABI instrinsic
library, or must I link with a particular runtime library to get these
functions?

It's usually either libunwind or libgcc_s.

I assume using the JIT there will somehow already be there, so at least
I can start experimenting. Perhaps another question, since this does
generate ABI compliant EH-tables, could my throw function just invoke a
native throw? That is, for really quick testing can I just create a c++
function which does a throw?

The usual way of doing this is to write your throw and personality functions in C (or possibly C++) and then call them from your compiler. The JIT should correctly generate and register unwind tables, although you may have to explicitly opt in to this. You can use the C++ personality function if you create a typeinfo structure for all of the exceptions in your language and then use this type for everything. Apple's Objective-C runtime does something similar, creating typeinfo structures corresponding to Objective-C classes and delegating the exception handling to them.

You probably also need to think about bracketing your catch blocks with something so that you can rethrow foreign exceptions and correctly clean up the memory from yours. The old GCC Objective-C ABI got this wrong, and it was a colossal pain to try to fix.

The personality function is probably the least fun code I've ever
written (I've now done it three times, for three different languages,
and it doesn't become any more fun). If you get it wrong, the stack
is gone by the time you get into the debugger, so lots and lots of
logging statements are your friend...

I feel excited already. :slight_smile:
I'm still quite unclear on this part as well. Don't suppose you ever
wrote a tutorial on this aspect, or have some example code you could show?

No, I probably should write a tutorial, since it's a frequently asked question. Drop me an email off-list and I can point you at some existing code.

David