Making llvm.eh.actions work

llvm.eh.actions is basically a sequenced list of actions to take when an invoke throws to the landing pad containing the actions call. The prototype is just ‘i8* llvm.eh.actions(…)’, but it needs some structure. LLVM IR supports three types of actions: cleanup, catch, and filter. __CxxFrameHandler3 doesn’t support filters, so it isn’t really relevant here.

Catch actions need three pieces of information:

  1. The typeinfo to catch. This can be null for catch-all handlers.
  2. The alloca that the exception object is stored into. This can be null if there is no catch parameter.
  3. The handler to run. This is required.

Cleanup actions only need one piece of information: the handler to run.

There are two main ways I can think of to encode this list.

The first is that we have a constant i32 parameter of 0 or 1 to indicate if this is a cleanup or catch, followed by constants representing the information required. We’d pass 3 args for catches and 1 for cleanups.

The second way is that we invent some kind of not-quite-a-catch-all sentinel to use instead of the i32 argument. We could use i32 -1, i8* undef, or something else. This all pretty confusing though.

The i32 argument approach extends to handle filters pretty naturally. It’s extensible, but it uses a lot of memory just to communicate a single bit.

The EH state number isn’t encoded in the action list, it’s computed later using the algorithm you described in the “RFC: Native Windows C++ exception handling” thread.

Does this seem reasonable?

Having the number of arguments for each handler depend on the handler type feels a bit shaky to me, but I can’t think of an actually problem with it that wouldn’t be handled by checking the type of each argument as we process it.

There are a couple of other pieces of information that need to end up in the catch handler array in the .xdata section, but I don’t think they have any reason to be included here.

So, yeah, I think this form for llvm.eh.actions is reasonable. We can always replace it later if we come up with a cleaner idea.

-Andy

Having the number of arguments for each handler depend on the handler
type feels a bit shaky to me, but I can’t think of an actually problem with
it that wouldn’t be handled by checking the type of each argument as we
process it.

We could definitely put in a dummy i8* null to make the number of arguments
per action match, but we still wouldn't be able to tell cleanups from
catches without using some sentinel other than i8* null. We really can use
any sentinel, since vararg functions don't have a prototype.

There are a couple of other pieces of information that need to end up in
the catch handler array in the .xdata section, but I don’t think they have
any reason to be included here.

So, yeah, I think this form for llvm.eh.actions is reasonable. We can
always replace it later if we come up with a cleaner idea.

Cool.