[llvm-commits] [llvm] r79567 - /llvm/trunk/lib/CodeGen/AsmPrinter/DwarfException.cpp

Duncan Sands baldrick at free.fr
Fri Aug 21 03:48:50 PDT 2009


Hi Bill, thanks for doing this.  I always meant to write a document
about this, but never got around to it.  I think it would be helpful
to give a complete example table, extracted from some real assembler,
and put it here along with comments showing how the various bits point
to the other bits, etc.

> +  // The two record kinds have the same format, with only small differences.
> +  // They are distinguished by the "switch value" field: Catch clauses
> +  // (TypeInfos) have strictly positive switch values, and exception
> +  // specifications (FilterIds) have strictly negative switch values. Value 0
> +  // indicates a catch-all clause.

in fact value 0 indicates a cleanup, which is not the same as catch-all.
For example, when unwinding a C++ exception, if the unwinder sees that
the only actions to be performed are cleanups, then it doesn't perform
them and just terminates the program (unlike in Ada, where the cleanups
are always run).  This is different to a catch-all action, which will
always be performed (the way of specifying a catch-all is language
specific however, C++ uses a null typeinfo but Ada does not).  Also,
in general if you rethrow an exception "caught" with a cleanup using
_UnwindResume, then it will unwind out of the function even if there
is an action for the place _UnwindResume is called - the action will
not be performed.  That's because the runtime "knows" that cleanups
are never thrown to be recaught, unlike catch-alls.

> +    // biased by 1 (1 in dicating the start of the actions table), and 0

in dicating -> indicating

> +    // indicates that there are no actions.

Actually in this situation 0 indicates a cleanup action.  This seems
to be a space saving scheme in the situation where the only action is
a cleanup, as opposed to a several typeids followed by a cleanup.  It is
the combination of 0 *and* a null landing pad that indicates no action.

> +      // Offset of the first associated action record, relative to the start of
> +      // the action table. This value is biased by 1 (1 indicates the start of
> +      // the action table), and 0 indicates that there are no actions.

See above about 0.  That said, this seems to be for the sj/lj case, so
maybe it is different there?

> +    // The call-site table is a list of all call sites that may throw an
> +    // exception (including C++ 'throw' statements) in the procedure

It's not really a list of call sites, but a list of code regions, each
of which may contain multiple calls/throwing instructions.  Probably
they should be called "throw regions" rather than call sites, but call
site seems to be the standard terminology...

> +    // A missing entry in the call-site table indicates that a call is not
 > +    // supposed to throw. Such calls include:

I think it would be clearer to say that if a code address is not
contained in any throw region (= call site), then it is not allowed
to throw.  Actually this is language specific: in C++ the runtime
will terminate the program if this happens, but in Ada unwinding
will just continue.  [So for Ada all the regions will null landing
pad could be omitted, saving space].

> +    //   * Calls to destructors within cleanup code. C++ semantics forbids these
> +    //     calls to throw.
> +    //   * Calls to intrinsic routines in the standard library which are known
> +    //     not to throw (sin, memcpy, et al).

Yeah, so-called "no throw" regions.  I think you should make it clear
that these are just some examples, and that they are C++ specific.

> +    // If the runtime does not find the call-site entry for a given call, it

I think you should clarify that you are talking about a call/instruction
that has thrown an exception.

> +    // will call `terminate()'.

This is C++ specific.  Ada will just continue unwinding.

> +      // Offset of the call site relative to the previous call site, counted in
> +      // number of 16-byte bundles. The first call site is counted relative to
> +      // the start of the procedure fragment.
>        EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount,
>                          true, true);

Not sure why you are talking about 16-byte bundles here?  Also, it's not
relative to the previous call site, but to the start of the function
IIRC.

> +      // Offset of the landing pad, counted in 16-byte bundles relative to the
> +      // @LPStart address.
>        if (!S.PadLabel)
>          Asm->EmitInt32(0);

Likewise.

> +      // Offset of the first associated action record, relative to the start of
> +      // the action table. This value is biased by 1 (1 indicates the start of
> +      // the action table), and 0 indicates that there are no actions.

As mentioned above, 0 indicates a cleanup.  It is 0 associated with
a null landing pad that indicates no action.

> -  // Emit the type ids.
> +  // Emit the Catch Clauses. The code for the catch clauses following the same
> +  // try is similar to a switch statement. The catch clause action record
> +  // informs the runtime about the type of a catch clause and about the
> +  // associated switch value.
> +  //
> +  //  Action Record Fields:
> +  //  
> +  //   * Filter Value
> +  //     Positive value, starting at 1. Index in the types table of the
> +  //     __typeinfo for the catch-clause type. 1 is the first word preceding
> +  //     TTBase, 2 is the second word, and so on. Used by the runtime to check
> +  //     if the thrown exception type matches the catch-clause type. Back-end
> +  //     generated switch statements check against this value.
> +  //
> +  //   * Next
> +  //     Signed offset, in bytes from the start of this field, to the next
> +  //     chained action record, or zero if none.
> +  //
> +  // The order of the action records determined by the next field is the order
> +  // of the catch clauses as they appear in the source code, and must be kept in
> +  // the same order. As a result, changing the order of the catch clause would
> +  // change the semantics of the program.

The above bit of comment seems out of place here.  It seems more
appropriate before the action table, or even right at the start.
It doesn't seem to have anything to do with the list of types infos
(which can be output in any order we like), or the filters (likewise,
in fact probably we could save space by carefully choosing the way
filters are output, and having them share each others tails), so I
don't see why it is placed before this bit of code, which is just
writing out the typeinfos (and filters)?

Ciao,

Duncan.



More information about the llvm-commits mailing list