[LLVMdev] RFC: Exception Handling Rewrite

Peter Lawrence peterl95124 at sbcglobal.net
Fri Aug 5 10:57:38 PDT 2011


Bill,
        ooops, yes, I described the meaning of "throw(A)" backwards,  
but I still
think my example shows why you cannot merge LandingpadInst while
inlining because multiple filter-lists on a LandingpadInst don't make  
sense.

Perhaps I'm reading your original spec wrong, perhaps I'm mis-reading
Duncan's emails, but I read them to mean that your syntax supports
multiple filter-lists on a single LandingpadInst.

first off, I think we agree on what I think you're saying below, that  
if foo calls
something, and bar calls somethingelse, and that if these have different
exception-specifications, then we can translate into different DWARF  
Action
and Types Tables, each call has it's own (in this case unique) Actions.

second, do you agree that if one exception-spec says to unexpected()
if anything other than 'A' is thrown, and another exception-spec says
to unexpected() if anything other than 'B' is thrown, that these cannot
be merged --> by that I mean they cannot have the same landingpad <-- ?



-Peter Lawrence.




On Aug 4, 2011, at 5:11 PM, Bill Wendling wrote:

> On Aug 4, 2011, at 4:03 PM, Peter Lawrence wrote:
>
>> Bill,
>>       I believe the empty-exception-specification example is a red- 
>> herring,
>> but that if you can construct an example where you think a landing- 
>> pad
>> requires multiple filter lists then I think we can then have a  
>> productive
>> conversation about it.
>>
>> I believe we can only get multiple filter lists in a landing-pad  
>> if we attempt
>> to merge exception-regions, and since filters are only an outer- 
>> function
>> concept (not an inner try-statement concept) this can only come about
>> from function inlining.
>>
>> so say we're considering inlining "void foo() throw(A) { ... }"  into
>> "void bar() throw (B) {...  foo(); ... ; frob(); ...}"
>>
>> if you attempt to merge the landing pad for these functions (perhaps
>> assuming it is going to be simple because there are no cleanups in  
>> either
>> function that would complicate things) then...
>>
>> there has to be a filter for A that will terminate the program if  
>> A is thrown,
>> but you cannot terminate the program if exception A comes from frob()
>> since it has not exception specification.
>>
>>
>> my conclusion is that you can only merge landing-pads if they already
>> have *identical* filters, so multiple filter lists isn't  
>> mathematically possible.
>>
>> thoughts ?
>> comments ?
>>
> I think you might have the concept backwards. The call to foo()  
> will call "unexpected" if anything *other* than A is thrown out of  
> foo(). The EH tables can be set up to accommodate this situation.  
> Let's say you have this example:
>
> 	void frob() { }
> 	void foo() throw (A) { }
> 	void bar() throw (B) { foo(); frob(); }
>
> The exception table for "foo" will look something like this for the  
> action (the indexes are negative offsets into the exception spec  
> table):
>
>   .byte 0x7f   # index into the exception specification table (-1)
>   .byte 0      # index to the next "action"
> ...
>   # Start of exception specification table
>   .long _A     # Only "A" can be thrown
>   .byte 0      # The end of this exception spec.
>
> This is as you'd expect. The EH table for bar is similar:
>
>   .byte 0x7f   # index into the exception specification table (-1)
>   .byte 0      # index to the next "action"
> ...
>   # Start of exception specification table
>   .long _B     # Only "B" can be thrown
>   .byte 0      # The end of this exception spec.
>
> Now, when we inline "foo()" into "bar()", we get something that  
> looks like this:
>
>   .byte 0x7f   # index into the exception specification table (-1)
>   .byte 0      # index to the next "action"
>   .byte 0x7d   # index into the exception specification table (-3)
>   .byte 0      # index to the next "action"
> ...
>   # Start of exception specification table
>   .long _A     # Only "A" can be thrown
>   .byte 0      # The end of this exception spec.
>   .long _B     # Only "B" can be thrown
>   .byte 0      # The end of this exception spec.
>
> Any call from foo will point to the ".byte 7f" action, which says  
> that it can only throw "A" All calls from bar will point to the  
> ".byte 0x7d" entry, which says that it can only throw "B". So in  
> that way we can combine two functions with different filters.
>
>> PS.  I believe the empty-exception-specification example is a
>> red-herring because I believe you are making the same mistake that
>> everyone does concerning "exception specifications", which is  
>> assuming
>> they imply compile time correct information --  like "const" is  
>> enforced at
>> compile time  --  which is false  (and why exception  
>> specifications are a
>> bad design).
>>
>>
>> __attribute__((nothrow))  <--- user guarantee that the function
>> does not throw, the compiler is free to optimize based on this
>> assertion, and if the program violates that guarantee then the
>> the program is "undefined" and can "do anything".
>>
>> throw()                                  <--- not a user guarantee  
>> of anything,
>> rather a user requirement that the compiler generate runtime checking
>> code to enforce that no exception is propagated out.
>
>
> I'm aware of the semantics of "throw()". This is taken care of with  
> the exception handling table. We would have an action of something  
> like this:
>
>   .byte 0x7f
>   .byte 0
>
> where the exception specification table is this:
>
>   .byte 0x0
>
> This indicates to the personality function won't find a matching  
> exception specification (there are none to match) and then we call  
> the unexpected dealy.
>
> -bw
>




More information about the llvm-dev mailing list