[LLVMdev] Nested exception handlers
baldrick at free.fr
Sat May 30 01:21:55 PDT 2009
> Since llvm-gcc is a rather large code base, which I have never looked at
> (or even run), could you give me a starting point of where to look?
I meant: compile some nested C++ with llvm-gcc to see what it does.
Otherwise, look in llvm-convert.cpp, especially EmitLandingPads.
> One thing I'd be interested in knowing is whether the
> llvm.eh.exception() intrinsic can be called more than once in a landing pad.
I committed some stuff a week or so ago which means that you can now
call llvm.eh.exception as many times as you like, from wherever you
like, and get the right result.
> Say for example I have a nested try block, so that there are two landing
> pads, one for the inner try block, and one for the outer. Let's say that
> the inner landing pad has a "finally" block - a cleanup handler. This
> means that the inner try block must catch every exception type so that
> it can execute the cleanup even if there was no specific catch handler
> for that exception type.
> At the end of the finally block, we need to jump to various different
> destinations depending on how the finally block was entered - return,
> fall through, throw, etc. In the case where we failed to catch an
> exception in the inner try block, but the outer try block has a catch
> handler for that exception, the finally block needs to jump to the outer
> landing pad. There are three ways this could happen:
> 1) Call _Unwind_Resume, using an "invoke" IR instruction whose unwind
> block points to the outer landing pad. This seems like it would be
> expensive however.
You need to be very careful with _Unwind_Resume. Due to a change in
libgcc (starting from gcc-4.3) you can only use _Unwind_Resume on an
exception if it didn't match anything (i.e. you can use it only if you
matched a "cleanup"). This is extremely annoying.
> 2) Branch directly to the start of the outer landing pad, and restart
> the exception dispatch all over. The problem with this is that the outer
> landing pad calls llvm.eh.exception() and llvm.eh.selector(), and I
> don't know if it's valid to call them at this point. Normally you don't
> jump to a landing pad directly, you get there via the personality
> function forcing a jump to that label. I don't know whether it is legal
> for the inner landing pad to jump to the start of the outer landing pad.
LLVM doesn't yet support calling llvm.eh.selector far away from a
landing pad, or multiple times. This is something I would like to
support but it is hard.
> 3) Branch directly to the individual catch blocks in the outer landing
> pad. In order to know which catch block to branch to, we need to add
> additional selectors to the inner landing pad representing the possible
> catch blocks in the outer landing pad that might catch the inner exception.
This is what llvm-gcc does, if I understand you right.
> The problem with this scheme is that now the liveness of the current
> exception object is all tangled up. The jump from the inner landing pad
> to the outer catch block passes through one or more cleanup blocks, each
> of which ends with a conditional jump. Each cleanup block has multiple
> predecessors, each predecessor setting a state variable telling the
> cleanup block where to jump to after finishing the cleanup. For a given
> cleanup block, "return" might set state = 0, "fall through" = 1, "catch
> block 1" = 2, "catch block 2" = 3 and so on. Notice that for some of
> those states (2, 3), there is a current active exception object, and for
> some (0, 1) there is not. That means that the value of the exception
> object is undefined for some predecessor blocks, so a regular phi node,
> won't work, and even storing the exception pointer in a local variable
> won't work because the compiler will notice that there are some code
> paths where the exception variable never gets set. Now, I happen to know
> that the code will never jump to a catch handler when there is no active
> throwable, but I am not sure that the compiler knows this.
IIRC, llvm-gcc duplicates cleanups a lot. Less than gcc though!
More information about the llvm-dev