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 ? -Peter Lawrence. 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. On Aug 4, 2011, at 3:20 PM, Bill Wendling wrote:> On Aug 4, 2011, at 2:58 PM, Peter Lawrence wrote: > >> Bill, >> I suspect we're talking about two different aspects, >> I think you are saying that there is an ability for the DWARF >> Actions Table >> to contain multiple lists, including multiple filter lists - no >> disagreement >> there, >> I am saying that for any one landing-pad it might not make sense >> for it to be able to have more than one filter list. >> > In general, it's not bad. But there is one problem, which your > example illustrates. > > void foo() throw() { /* ... */ } > > When "foo()" is inlined into its caller, the resulting function's > EH table should be set up to disallow exceptions thrown for the > inlined contents of foo(). Our current scheme is to mark foo() as > "nounwind" and make it a normal "call" instruction. Some care will > have to be taken during inlining to keep the "no throwing" > attribute around for the code that cares about it. > > -bw >
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
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 >