[LLVMdev] Exception Handling Tables Question

Duncan Sands duncan.sands at math.u-psud.fr
Fri Sep 18 02:30:11 PDT 2009


Hi Nick,

> But _Unwind_Resume() is special.  It never returns. It does not throw.

I disagree - this depends on the system libgcc version.  Starting from
gcc-4.3, mainline gcc uses _Unwind_GetCFA rather than _Unwind_GetIP in
uw_identify_context.  So from gcc-4.3 onwards, libgcc will indeed ignore
any call-site entry covering the position of the _Unwind_Resume call, so
indeed it doesn't matter what you put there.  However lots of systems
still use libgcc from gcc-4.2 or earlier (for example, all of the LLVM
nightly testers running linux), and for them it does matter what is in
the call site table: they need an entry appropriate for a "throwing
call".  [To be honest I didn't test this, but since on such systems it
is perfectly possible to catch the exception "thrown" by _Unwind_Resume
by placing an appropriate entry in the call-site table, it seems that
the address of the call is being looked up in the usual way in the
table].

So for compatibility with systems with an older libgcc, it is important
to have a call-site entry for _Unwind_Resume, like we produce right now.

> The purpose of  _Unwind_Resume() is for when you have a function with a 
> destructor that implicitly needs running during exception processing as 
> the exception unwinds through the stack.  The unwinder jumps into that 
> function's landing pad where the compiler has laid down a call to the 
> destructor followed by a call to _Unwind_Resume() which then continues 
> where the unwinding left off in processing the exception.
> 
> Therefore, I don't see the point of having a call-site entry for the 
> _Unwind_Resume() "call".

As I mentioned above, this behaviour can't be relied upon on linux at
least.  However maybe it can be relied upon for darwin, since the CFA
change has been in Apple gcc for a long time now.  If you want to
exploit this, it can be done in a generic way as part of a more general
optimization, as follows.

First, observe that it doesn't matter if you have a call-site entry
or not for the _Unwind_Resume call, since the call is never looked up
in the table.  It may not be optimal to omit the call-site entry, since
if the preceding and following entries have the same catches and
landing pads, all three entries (i.e. preceding, _Unwind_Resume and
following) could be merged into one entry with an address range that
covers all three.  This kind of merging logic already exists in
ComputeCallSiteTable, it just needs to be taught that it doesn't matter
whether _Unwind_Resume is in any particular call-site or not.  What
needs to happen is that in this line
         SawPotentiallyThrowing |= MI->getDesc().isCall();
you shouldn't set SawPotentiallyThrowing to true if the call is to
_Unwind_Resume.

However, there is no need to special case _Unwind_Resume, since there
is a whole class of calls for which you can do the same: all calls with
the nounwind attribute.  If such a call does throw an exception, that
results in undefined behaviour, so it is perfectly fine to not have a
call-site entry for it, or to have one, just like for _Unwind_Resume.
Thus I suggest adding a codegen flag to say whether a call is a
"nounwind" call.  The above line can change to something like:

         SawPotentiallyThrowing |= (MI->getDesc().isCall() && 
!MI->getDesc().isNoUnwind);

The code in ComputeCallSiteTable will then compute a minimal set of
call-sites in a way that should make you happy :)

In DwarfEHPrepare.cpp, if the platform is darwin then the calls to
_Unwind_Resume it generates can be marked "nounwind", and the rest
will happen automagically.

By the way, since nounwind calls occur a lot, this may result in
a big win in call-site table size, so I think it's worth doing
whether or not you do something special for _Unwind_Resume.

Ciao,

Duncan.

PS: I said to Bill that in fact SawPotentiallyThrowing was not what
he was looking for for nounwind calls, but I changed my mind again :)



More information about the llvm-dev mailing list