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

Bill Wendling isanbard at gmail.com
Fri Aug 21 11:05:42 PDT 2009


On Aug 21, 2009, at 3:48 AM, Duncan Sands wrote:

> 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.
>
Good idea.

One general comment. I wrote the comments directly from the exception  
handling document. I'll need to modify them to be more in line with  
how LLVM does things. I'll rework the comments today and hopefully  
incorporate your suggestions. :-)

Thanks!

-bw

>> +  // 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