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:
- The typeinfo to catch. This can be null for catch-all handlers.
- The alloca that the exception object is stored into. This can be null if there is no catch parameter.
- 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?