[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