public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: __attribute__((cleanup(function)) versus try/finally
       [not found]     ` <1052249890.31850.338.camel@doubledemon.codesourcery.com>
@ 2003-05-06 21:04       ` Jason Merrill
  2003-05-06 21:24         ` Mark Mitchell
                           ` (2 more replies)
  0 siblings, 3 replies; 52+ messages in thread
From: Jason Merrill @ 2003-05-06 21:04 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: gcc, Jason Merrill

On 06 May 2003 12:38:09 -0700, Mark Mitchell <mark@codesourcery.com> wrote:

>> In any case, how are you thinking to do this?  You've mentioned such a
>> thing before, but I haven't noticed an implementation sketch.
>
> I did on the gcc list, but it got lost in the noise, I think.  
>
> The strategy is:
>
> (1) Have pthread_cleanup_push include the current $sp in the cleanup
> record.  Otherwise, use the same data structures currently used by
> glibc's pthread_cleanup_push.
>
> (2) When an exception is thrown:
>
> - Figure out where the next handler/cleanup will be.
>
>   (By hypothesis, this is not going to be in C code, because we don't
>   have try/finally in C.)
>
> - If unwinding the stack to that destination will result in $sp be older
> than the $sp recorded in the cleanup at the top of the C cleanup stack,
> run C cleanups until that is no longer true.

> - Transfer control to the handler as is done now.

Hmm, I suppose you can assume that $sp is linear.  I guess that would work,
except that you can't unwind through C unless the C code has unwind info.

If you assume that you won't be trying to unwind through C code without
unwind info into C++ code, this still requires that you handle the
cancellation exception specially.  When you run out of unwind info, rather
than call terminate you need to hand off to the old pthread_exit.

Of course, that could be implemented by setting the terminate_handler field
in the exception header, but then you'd call it in all situations where you
would otherwise call terminate.

And if you need to handle unwinding out to C++ code in some cases, you
might as well always use the same technique.  Regardless of what we do
about C cleanups, any C code which both calls cancellation points and is
called from C++ must have unwind info.  Otherwise we lose the C++ cleanups
(and we can't catch the cancellation exception, as you've been asking for).

In effect, this means that any library code that does I/O must have unwind
info.  At that point, it seems to me that we might as well always emit it,
since it only costs us in disk space.  That's what Tru64 does.  And Irix.
A compromise would be for -pthreads to imply -fexceptions.

>> > The try/finally solution cannot be implemented with this same
>> > performance; it will, in fact, exact a performance price, in terms of
>> > both code space and the speed at which cleanups are run, on all
>> > systems.  On systems with setjmp/longjmp exceptions, both costs will be
>> > very high indeed.

I think you're exaggerating the costs.  This is the way the C++ frontend
works, and you only incur the costs when you use the feature.  The design
philosophy of EH has always been that the speed of the normal code is what
matters, not the cleanups.

>> Hmm.  Are you talking about representing cleanups in the LSDA via a
>> function pointer and a CFA offset for the argument object?  That way you
>> still need unwind info and PC range tables, but you don't put any code into
>> the function itself.
>
> I'm not as sophisticated as you about this; I don't actually know what
> all the EH implementation details are.  With the scheme above, you do
> still need PC range tables and (some?) unwind information, but you don't
> put any code into the function.  I keep mumbling that I think you might
> be able to avoid some of the unwind information for C, but I've never
> done what it would take to prove or disprove that assertion.  

> The key point is that you don't need any handler code in the function.

I'm not sure why that's key.  Exception handlers in the function can be
moved aside to improve cache locality.  I think we already do this.

> The observation behind this is that pthread cleanups -- unlike C++ catch
> clauses -- do not need to execute in the frame of the function that
> pushed them.  They just need to execute while the stack is still there,
> in case the "arg" to the function directly or indirectly references
> stuff on the stack.

No, they don't need to.  Nor do C++ destructors.  But they do anyway.  If
we decide that moving cleanup calls out of line is an important
optimization, doing it via analysis of the cleanup expression would allow
C++ and Java to benefit from it as well.

One major practical problem with attribute(cleanup): It doesn't map very
well onto pthread_cleanup_push.  With attribute(cleanup) the cleanup
argument is the variable to which the attribute is attached, but with
pthread_cleanup_push, the cleanup argument is usually a local variable
which has already been declared, so you need to indirect through another
function.

It seems to me that a lot of your objections come from resistance to
letting EH into C.  But if we want to interleave pthread and C++ cleanups,
we don't have any choice.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-06 21:04       ` __attribute__((cleanup(function)) versus try/finally Jason Merrill
@ 2003-05-06 21:24         ` Mark Mitchell
  2003-05-07 21:21           ` Jason Merrill
  2003-05-06 21:52         ` Anthony Green
  2003-05-08 17:44         ` Mike Stump
  2 siblings, 1 reply; 52+ messages in thread
From: Mark Mitchell @ 2003-05-06 21:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc

> Hmm, I suppose you can assume that $sp is linear.  I guess that would work,
> except that you can't unwind through C unless the C code has unwind info.

The C code must have unwind info -- but it does not need to have handler
code.  Moving the handler code out-of-line is only part of the issue;
the code size is the other issue.

> cancellation exception specially.  When you run out of unwind info, rather
> than call terminate you need to hand off to the old pthread_exit.

I had suggested simply having the pthread-launching routine (the first
thing called in the new thread) be written in C++.  It can then just
catch the exception and do whatever's required.
 
> In effect, this means that any library code that does I/O must have unwind
> info.  At that point, it seems to me that we might as well always emit it,
> since it only costs us in disk space.  That's what Tru64 does.  And Irix.

Yes, I don't argue with any of this.  It would be nice to avoid unwind
info, but I'm not sure we can.  We can avoid handlers, however.

> >> > The try/finally solution cannot be implemented with this same
> >> > performance; it will, in fact, exact a performance price, in terms of
> >> > both code space and the speed at which cleanups are run, on all
> >> > systems.  On systems with setjmp/longjmp exceptions, both costs will be
> >> > very high indeed.
> 
> I think you're exaggerating the costs.  This is the way the C++ frontend
> works, and you only incur the costs when you use the feature.  The design
> philosophy of EH has always been that the speed of the normal code is what
> matters, not the cleanups.

With setjmp/longjmp, there are big costs even if you don't use the
feature.  With the scheme I propose, you shouldn't need as many setjmps
-- you only need one setjmp at the beginning of the function to be able
to unwind.  You never need to land in the middle of the function.

Without setjmp/longjmp, you save mostly code space.  You also improve
cleanup time (in that you need not transfer control to the local frame
of the function before running the cleanup), but this is a smaller
advantage.
 
> > The observation behind this is that pthread cleanups -- unlike C++ catch
> > clauses -- do not need to execute in the frame of the function that
> > pushed them.  They just need to execute while the stack is still there,
> > in case the "arg" to the function directly or indirectly references
> > stuff on the stack.
> 
> No, they don't need to.  Nor do C++ destructors.  But they do anyway.  

Catch-clauses and destructors are different.

Given:

  int i;
  try { ... } catch (...) { i = 3; }

the catch-clause had better execute in the frame of this function.

With a destructor or (analogously) a pthread cleanup handler, the
execution just has to take place while the frame is still active.

-- 
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-06 21:04       ` __attribute__((cleanup(function)) versus try/finally Jason Merrill
  2003-05-06 21:24         ` Mark Mitchell
@ 2003-05-06 21:52         ` Anthony Green
  2003-05-08 17:44         ` Mike Stump
  2 siblings, 0 replies; 52+ messages in thread
From: Anthony Green @ 2003-05-06 21:52 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Mark Mitchell, gcc

On Tue, 2003-05-06 at 14:02, Jason Merrill wrote:
> Hmm, I suppose you can assume that $sp is linear. 

I know of one proprietary platform where this is not true.  On the other
hand, GCC does not currently support this system.  

FWIW, I strongly support the try/finally proposal.  One advantage that
hasn't been mentioned is that it may help people migrate from
proprietary compilers to GCC.  I think that this user-centric argument
is compelling just on it's own.

AG


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
       [not found] ` <1052245742.2583.315.camel@doubledemon.codesourcery.com>
       [not found]   ` <wvlissnc2e3.fsf@prospero.boston.redhat.com>
@ 2003-05-07  0:14   ` Richard Henderson
  2003-05-07  2:32     ` Mark Mitchell
  1 sibling, 1 reply; 52+ messages in thread
From: Richard Henderson @ 2003-05-07  0:14 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: gcc

On Tue, May 06, 2003 at 11:29:01AM -0700, Mark Mitchell wrote:
> I think RTH accepts the attribute solution as well.  He would prefer
> try/finally, as I would prefer no extension, but I think we are both
> willing to accept the attribute.

To some extent I kind-of like the attribute solution on its own.
It provides much more structured access to cleanups than the
arbitrary block of code that __finally allows.

I'm not sure I want to explain to users that jumping out of the
__finally block (via goto/break/return) will lead to undefined
results.  It's less difficult to explain that using longjmp out
of a function (under certain conditions) is undefined.

> In fact, that solution delivers maximum performance:
> 
> (1) C functions do not need to have handler code inserted.

This is false.  Handler code gets inserted with the attribute too.

> (2) You do not have to transfer control from the EH mechanism to the
> stack frame of the caller in order to perform the cleanups.

This is false as well.

Indeed, I'd expect the most common case would be for the cleanup
function to be expanded inline, and reference data cached in 
registers in the function.

> The try/finally solution cannot be implemented with this same
> performance; it will, in fact, exact a performance price, in terms of
> both code space and the speed at which cleanups are run, on all
> systems.  On systems with setjmp/longjmp exceptions, both costs will be
> very high indeed.

No, the overhead is identical.


r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-07  0:14   ` Richard Henderson
@ 2003-05-07  2:32     ` Mark Mitchell
  0 siblings, 0 replies; 52+ messages in thread
From: Mark Mitchell @ 2003-05-07  2:32 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc

On Tue, 2003-05-06 at 17:11, Richard Henderson wrote:
> On Tue, May 06, 2003 at 11:29:01AM -0700, Mark Mitchell wrote:
> > I think RTH accepts the attribute solution as well.  He would prefer
> > try/finally, as I would prefer no extension, but I think we are both
> > willing to accept the attribute.
> 
> To some extent I kind-of like the attribute solution on its own.
> It provides much more structured access to cleanups than the
> arbitrary block of code that __finally allows.
> 
> I'm not sure I want to explain to users that jumping out of the
> __finally block (via goto/break/return) will lead to undefined
> results.  It's less difficult to explain that using longjmp out
> of a function (under certain conditions) is undefined.
> 
> > In fact, that solution delivers maximum performance:
> > 
> > (1) C functions do not need to have handler code inserted.
> 
> This is false.  Handler code gets inserted with the attribute too.

I wasn't talking about the attribute solution in this context.

-- 
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-06 21:24         ` Mark Mitchell
@ 2003-05-07 21:21           ` Jason Merrill
  2003-05-07 22:18             ` Mark Mitchell
  0 siblings, 1 reply; 52+ messages in thread
From: Jason Merrill @ 2003-05-07 21:21 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: gcc, Jason Merrill

On 06 May 2003 14:24:49 -0700, Mark Mitchell <mark@codesourcery.com> wrote:

>> cancellation exception specially.  When you run out of unwind info, rather
>> than call terminate you need to hand off to the old pthread_exit.
>
> I had suggested simply having the pthread-launching routine (the first
> thing called in the new thread) be written in C++.  It can then just
> catch the exception and do whatever's required.

Sure, that works so long as you don't run out of unwind info.

>> >> > The try/finally solution cannot be implemented with this same
>> >> > performance; it will, in fact, exact a performance price, in terms of
>> >> > both code space and the speed at which cleanups are run, on all
>> >> > systems.  On systems with setjmp/longjmp exceptions, both costs will be
>> >> > very high indeed.
>> 
>> I think you're exaggerating the costs.  This is the way the C++ frontend
>> works, and you only incur the costs when you use the feature.  The design
>> philosophy of EH has always been that the speed of the normal code is what
>> matters, not the cleanups.
>
> With setjmp/longjmp, there are big costs even if you don't use the
> feature.

There are no costs unless there are cleanups.

> With the scheme I propose, you shouldn't need as many setjmps -- you only
> need one setjmp at the beginning of the function to be able to unwind.
> You never need to land in the middle of the function.

The C++ setjmp/longjump EH scheme also only requires one setjmp per
function unless there are nested catches; the EH runtime jumps there, runs
all the cleanups for the current function, and calls back into the
unwinder.

> Without setjmp/longjmp, you save mostly code space.  You also improve
> cleanup time (in that you need not transfer control to the local frame
> of the function before running the cleanup), but this is a smaller
> advantage.

Which may or may not outweigh the advantages of having the cleanups in the
function (code motion into the landing pad, inlining destructors, not
forcing the argument into the stack).

How to run simple cleanups (a call to a function which takes a pointer to
an object in the current frame) is an optimization question.  We already
have to handle more complex cleanups for Java try/finally, and for inlined
destructors in C++.  Allowing people to write them in C doesn't make our
job any harder.

>> > The observation behind this is that pthread cleanups -- unlike C++ catch
>> > clauses -- do not need to execute in the frame of the function that
>> > pushed them.  They just need to execute while the stack is still there,
>> > in case the "arg" to the function directly or indirectly references
>> > stuff on the stack.
>> 
>> No, they don't need to.  Nor do C++ destructors.  But they do anyway.  
>
> Catch-clauses and destructors are different.

I don't disagree.

> Given:
>
>   int i;
>   try { ... } catch (...) { i = 3; }
>
> the catch-clause had better execute in the frame of this function.
>
> With a destructor or (analogously) a pthread cleanup handler, the
> execution just has to take place while the frame is still active.

Well, if you really wanted to, you could turn the catch clause into a
nested function which takes an argument pointing to the frame, though you
probably wouldn't want to, as it would force all variables used in the
catch clause into the stack.

My point, however, was that in the current implementation, destructors are
run within the frame of the function, even though they don't need to be.
We could make a different choice, but again, it's just a question of
optimization strategy.  The same choices would apply to Java and C.

Basically, what I'm saying is that the question of what sorts of cleanups
to allow can be separated from the question of how to implement them.  If
we can set aside the implementation issues, it becomes just a question of
language design, and I still think that try/finally is the elegant
solution.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-07 21:21           ` Jason Merrill
@ 2003-05-07 22:18             ` Mark Mitchell
  2003-05-07 23:01               ` Jason Merrill
                                 ` (2 more replies)
  0 siblings, 3 replies; 52+ messages in thread
From: Mark Mitchell @ 2003-05-07 22:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc

> There are no costs unless there are cleanups.

Yes -- but I'm talking about the situation where there are cleanups.

Concretely, consider the following C function:

  void f() {
    FILE *f1, *f2, *f3;

    f1 = fopen ("/tmp/foo");
    pthread_cleanup_push (fclose, f1);
    g();
    f2 = fopen ("/tmp/bar");
    pthread_cleanup_push (fclose, f2);
    g();
    f3 = fopen ("/tmp/baz");
    pthread_cleanup_push (fclose, f3);
    g ();
    pthread_cleanup_pop (1);
    pthread_cleanup_pop (1); 
    pthread_cleanup_pop (1);
  }

Now, with my scheme this function has no handler code; i.e, the EH
run-time library will never transfer control back to this function.  

Even when using setjmp/longjmp the cost is just one setjmp at the start
of the function, so that the stack can be unwound.

If pthread_cleanup_push uses try/finally, it's my understanding that
there will be multiple calls to setjmp, before each of the calls to g.

And in the non-setjmp case, there will be landing pads and unwind
information for each of the exception regions, rather than just one for
the entire function.

> > Without setjmp/longjmp, you save mostly code space.  You also improve
> > cleanup time (in that you need not transfer control to the local frame
> > of the function before running the cleanup), but this is a smaller
> > advantage.
> 
> Which may or may not outweigh the advantages of having the cleanups in the
> function (code motion into the landing pad, inlining destructors, not
> forcing the argument into the stack).

For pthread_cleanup_push, this is generally not an issue; the cleanup is
a function pointer.  Unless that function pointer is to an inline
function, you're going to make a call here anyhow; there's no real
advantage.
 
> Basically, what I'm saying is that the question of what sorts of cleanups
> to allow can be separated from the question of how to implement them.  If
> we can set aside the implementation issues, it becomes just a question of
> language design, and I still think that try/finally is the elegant
> solution.

(There's nothing wrong with try/finally as a construct in the abstract. 
I'm all for continuations, too!  And real closures!   If C had
templates, objects, exceptions, and namespaces, I'd love it to pieces!

Seriously, one of the few remaining objections to programming in C++ has
been "exceptions add too much overhead".  Once we add unwind tables to C
-- as all of our proposals do, including mine -- I'm not really sure
what the point of programming in C is going to be any more.  Maybe if
you really like the fact that "struct S {};" doesn't introduce a
typedef, or that "void f()" isn't a prototype.  Maybe we should add
-fnothing-but-exceptions to G++, and just use that as the C compiler.)

Adding EH to C is a very dramatic change.  The spirit of C is "no hidden
stuff."  Calling exceptions "zero-cost" is a lie; we say that because
they require no additional instructions be executed unless an exception
is thrown, not because they actually have no cost.  The unwind tables
are a significant cost, for example.

To that end, I've toyed with the following idea:

- When building a library written in C, provide two sets of entry points
for the globally visible functions: a version that is called from C, and
a version called from everything else.  The non-C version of the entry
point calls setjmp.  Then, you can unwind through C code with a single
longjmp, no unwind tables, no handlers.  (You do this by saying "huh, no
unwind info for this frame; must be C; call the top entry on the longjmp
stack.)  You actually only need this setjmp on those entry points that
are going to call things that might throw exceptions; in glibc, for
example, that means functions that call cancellation points, or take
callbacks (ala qsort).

- The cost of this scheme for a pure C program is exactly zero.  No
unwind info, no setjmps, no nothing.  You get correct mixed C++/C
semantics with slight cost; on entry to a C library from C++ code you
take a hit if you need to call setjmp.

This kind of solution is awfully attractive if you're on an embedded
system.  (I want pthreads on my cell-phone, but I sure don't want to
have extra unwind info around.  I want to be able to support C++, but if
it's not in use, I don't want to have to pay the cost of supporting C++
by my making my C libraries bigger.)

-- 
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-07 22:18             ` Mark Mitchell
@ 2003-05-07 23:01               ` Jason Merrill
  2003-05-08 12:05               ` Gabriel Dos Reis
  2003-05-09  5:46               ` Kai Henningsen
  2 siblings, 0 replies; 52+ messages in thread
From: Jason Merrill @ 2003-05-07 23:01 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: gcc, Jason Merrill

On 07 May 2003 15:18:01 -0700, Mark Mitchell <mark@codesourcery.com> wrote:

> Now, with my scheme this function has no handler code; i.e, the EH
> run-time library will never transfer control back to this function.  

Yes.  With the alternative look-aside optimization I mentioned, the same
would be true.  And it wouldn't even require a library call to register the
cleanup.

> Even when using setjmp/longjmp the cost is just one setjmp at the start
> of the function, so that the stack can be unwound.

I think the longjmp_unwind scheme uses multiple setjmps, though I'm not
sure; it doesn't have the benefit of the whole-function analysis that the
compiler can do when inserting EH code.

> If pthread_cleanup_push uses try/finally, it's my understanding that
> there will be multiple calls to setjmp, before each of the calls to g.

I'm pretty sure there's just one at the beginning of the function, emitted
if needed.

The parallel look-aside optimization for the setjmp case could be to
register EH cleanups via a call into the EH runtime much like
pthread_cleanup_push; this would avoid the need for any setjmps if a
function only has cleanups.

> And in the non-setjmp case, there will be landing pads and unwind
> information for each of the exception regions, rather than just one for
> the entire function.

Landing pads, yes, but they're just one instruction unless an optimizer has
moved code there, in which case it's presumably beneficial.

Unwind info is always per-function.  There is, however, an entry in the
LSDA for each region, typically 4 bytes in a small function.  The
look-aside optimization would make this larger, of course.

> Adding EH to C is a very dramatic change.  The spirit of C is "no hidden
> stuff."  Calling exceptions "zero-cost" is a lie; we say that because
> they require no additional instructions be executed unless an exception
> is thrown, not because they actually have no cost.  The unwind tables
> are a significant cost, for example.

Significant, but not unreasonable IMO.  As I mentioned, Irix and Tru64
always emit them.  We always emit them for S/390 and x86-64.  Always
emitting them for pthreads code seems appropriate to me, and much easier
than creating a whole new system to deal with what is basically an already
solved problem.

> To that end, I've toyed with the following idea:
>
> - When building a library written in C, provide two sets of entry points
> for the globally visible functions
>[...]

This sounds like a rather heavy weight solution to this problem.  I'd much
rather re-use mechanisms we already have.

> This kind of solution is awfully attractive if you're on an embedded
> system.  (I want pthreads on my cell-phone, but I sure don't want to have
> extra unwind info around.  I want to be able to support C++, but if it's
> not in use, I don't want to have to pay the cost of supporting C++ by my
> making my C libraries bigger.)

Then you probably want to use setjmp/longjmp exceptions.  With the
optimization described above, it would be no more expensive than the old
mechanism.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-07 22:18             ` Mark Mitchell
  2003-05-07 23:01               ` Jason Merrill
@ 2003-05-08 12:05               ` Gabriel Dos Reis
  2003-05-09  5:46               ` Kai Henningsen
  2 siblings, 0 replies; 52+ messages in thread
From: Gabriel Dos Reis @ 2003-05-08 12:05 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Jason Merrill, gcc

Mark Mitchell <mark@codesourcery.com> writes:

[...]

| Seriously, one of the few remaining objections to programming in C++ has
| been "exceptions add too much overhead".  Once we add unwind tables to C
| -- as all of our proposals do, including mine -- I'm not really sure
| what the point of programming in C is going to be any more.

Exactly!

We should refrain from adding extensions to C or C++ from a
short-sighted point of view. At any point we n eed to have the picture
in the foreground, or else we would end up in one or two years cursing
after the same extensions  (Did I mention statement-expression ? :-)

|  Maybe if
| you really like the fact that "struct S {};" doesn't introduce a
| typedef,

Well, in the C++ front-end there is no reason we should be creating
that artificial typedef all around: it wastes memory and unnecessarily
complicates routines. 

-- Gaby

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-06 21:04       ` __attribute__((cleanup(function)) versus try/finally Jason Merrill
  2003-05-06 21:24         ` Mark Mitchell
  2003-05-06 21:52         ` Anthony Green
@ 2003-05-08 17:44         ` Mike Stump
  2003-05-08 17:45           ` Jason Merrill
  2 siblings, 1 reply; 52+ messages in thread
From: Mike Stump @ 2003-05-08 17:44 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Mark Mitchell, gcc

On Tuesday, May 6, 2003, at 02:02 PM, Jason Merrill wrote:
> Hmm, I suppose you can assume that $sp is linear.

One can track discontinuities in an along side data structure at the 
discontinuity creation points, and use that to order the comparisons 
during throw time, should we want to.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 17:44         ` Mike Stump
@ 2003-05-08 17:45           ` Jason Merrill
  2003-05-08 18:40             ` Mark Mitchell
  0 siblings, 1 reply; 52+ messages in thread
From: Jason Merrill @ 2003-05-08 17:45 UTC (permalink / raw)
  To: Mike Stump; +Cc: Mark Mitchell, gcc

On Thu, 8 May 2003 10:44:04 -0700, Mike Stump <mrs@apple.com> wrote:

> On Tuesday, May 6, 2003, at 02:02 PM, Jason Merrill wrote:
>> Hmm, I suppose you can assume that $sp is linear.
>
> One can track discontinuities in an along side data structure at the
> discontinuity creation points, and use that to order the comparisons during
> throw time, should we want to.

Again, this sort of thing sounds like a cure that's worse than the disease.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 17:45           ` Jason Merrill
@ 2003-05-08 18:40             ` Mark Mitchell
  2003-05-08 19:06               ` Alexandre Oliva
  2003-05-08 19:37               ` Jason Merrill
  0 siblings, 2 replies; 52+ messages in thread
From: Mark Mitchell @ 2003-05-08 18:40 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Mike Stump, gcc

On Thu, 2003-05-08 at 10:44, Jason Merrill wrote:
> On Thu, 8 May 2003 10:44:04 -0700, Mike Stump <mrs@apple.com> wrote:
> 
> > On Tuesday, May 6, 2003, at 02:02 PM, Jason Merrill wrote:
> >> Hmm, I suppose you can assume that $sp is linear.
> >
> > One can track discontinuities in an along side data structure at the
> > discontinuity creation points, and use that to order the comparisons during
> > throw time, should we want to.
> 
> Again, this sort of thing sounds like a cure that's worse than the disease.

I think our value-functions are not the same.

If we were designing a new language, I'd certainly agree with you that
exceptions are a good feature.  When discussing C on a workstation-class
machine, I'd be more likely to agree with you, even though I think
adding exceptions to C is antithetical of that language's key design
goals. 

When discussing C for embedded systems, though, I just can't see it.  I
fully concede that my scheme is less beautiful -- unless you see beauty
in the number of bytes saved.

I think what really happened here was that the pthreads designers wanted
to add pthread_atexit -- and then got carried away.

(In fact, so far as I can tell, a careful reading of 

  http://www.unix.org/single_unix_specification/

would suggest that:

  pthread_cleanup_push (f, a);
  goto l;
  pthread_cleanup_pop (1);
 l:

is well-defined, and does not result in the cleanup being executed. 
Presumably, this should be undefined behavior, as it does not work at
all with the sample implementation in the specification.

The question of whether pthread_cleanup_push should create a new scope
is also important, at least in C99 and C++: is

   int i;
   pthread_cleanup_push (f, a);
   int i;

valid, or not, or is this unspecified?)

Also, doesn't the execute argument to pthread_cleanup_pop mean that
try/finally isn't the right construct?  

I would think that the EH version of:

  pthread_cleanup_push (f, a);
  g ();
  pthread_cleanup_pop (x);

would be:

  try {
    g();
  } catch (...) {
    f(a);
    throw;
  }
  if (x) f(a);

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 18:40             ` Mark Mitchell
@ 2003-05-08 19:06               ` Alexandre Oliva
  2003-05-08 19:47                 ` Mark Mitchell
  2003-05-08 19:37               ` Jason Merrill
  1 sibling, 1 reply; 52+ messages in thread
From: Alexandre Oliva @ 2003-05-08 19:06 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Jason Merrill, Mike Stump, gcc

On May  8, 2003, Mark Mitchell <mark@codesourcery.com> wrote:

> Also, doesn't the execute argument to pthread_cleanup_pop mean that
> try/finally isn't the right construct?  

>   pthread_cleanup_push (f, a);
>   g ();
>   pthread_cleanup_pop (x);

> would be:

>   try {
>     g();
>   } catch (...) {
>     f(a);
>     throw;
>   }
>   if (x) f(a);

Err...  You're not using try/finally above, and you're not necessarily
using the values of f and a that were passed to pthread_cleanup_push.

// expanded from pthread_cleanup_push
if (1) {
  void (*__pthr_saved_f)(void *) = (f);
  void *__pthr_saved_a = (a);
  bool __pthr_execute = true;
  try { ;
// end of pthread_cleanup_push
    g ();
// expanded from pthread_cleanup_pop
    __pthr_execute = x;
  } finally {
    if (x)
      __pthr_saved_f(__pthr_saved_a);
  }
} else ;
// end of pthread_cleanup_pop

it's too bad we can't use the cleaner do/while(0) approach for this,
because otherwise we'd change the meaning of break :-(

Fortunately a dangling else does almost as well to eat the `;' after
pthread_cleanup_pop.  This still leaves us with an empty statement
after try, but that's not much of a problem.

It's not like this is so important, either...  Since
pthread_cleanup_push and pop are even documented to introduce nesting
levels and all, nobody should expect them to expand to a single
statement anyway.  But still, we need a scope for the temporaries, so
we might as well go ahead and make them have block begin/end
properties.

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist                Professional serial bug killer

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 18:40             ` Mark Mitchell
  2003-05-08 19:06               ` Alexandre Oliva
@ 2003-05-08 19:37               ` Jason Merrill
  1 sibling, 0 replies; 52+ messages in thread
From: Jason Merrill @ 2003-05-08 19:37 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Mike Stump, gcc, Jason Merrill

On 08 May 2003 11:40:21 -0700, Mark Mitchell <mark@codesourcery.com> wrote:

> If we were designing a new language, I'd certainly agree with you that
> exceptions are a good feature.  When discussing C on a workstation-class
> machine, I'd be more likely to agree with you, even though I think
> adding exceptions to C is antithetical of that language's key design
> goals. 
>
> When discussing C for embedded systems, though, I just can't see it.  I
> fully concede that my scheme is less beautiful -- unless you see beauty
> in the number of bytes saved.

I argued in my last reply that sjlj EH can have the same cost as the
existing pthread cleanup mechanism.  Do you disagree?

> I think what really happened here was that the pthreads designers wanted
> to add pthread_atexit -- and then got carried away.

I think they wanted exactly what they wrote.  atexit isn't useful for
cleanups of a fixed duration.

> (In fact, so far as I can tell, a careful reading of
>
>   http://www.unix.org/single_unix_specification/
>
> would suggest that:
>
>   pthread_cleanup_push (f, a);
>   goto l;
>   pthread_cleanup_pop (1);
>  l:
>
> is well-defined, and does not result in the cleanup being executed. 
> Presumably, this should be undefined behavior, as it does not work at
> all with the sample implementation in the specification.

Agreed.

> The question of whether pthread_cleanup_push should create a new scope
> is also important, at least in C99 and C++: is
>
>    int i;
>    pthread_cleanup_push (f, a);
>    int i;
>
> valid, or not, or is this unspecified?)

I'd say unspecified or valid.  The spec talks about implementation as
macros containing { and }.

> Also, doesn't the execute argument to pthread_cleanup_pop mean that
> try/finally isn't the right construct?  
>
> I would think that the EH version of:
>
>   pthread_cleanup_push (f, a);
>   g ();
>   pthread_cleanup_pop (x);
>
> would be:
>
>   try {
>     g();
>   } catch (...) {
>     f(a);
>     throw;
>   }
>   if (x) f(a);

Hard to do that with macros; you need to store the push args into temporary
variables.  You'd need to do something like

  {
    void (*_f)(void *) = f;
    void *_a = a;

    try {
      g();
    } catch (...) {
      _f (_a);
      throw;
    }
    if (x) _f (_a);
  }

but nobody's advocating adding catch to C, are they?  Besides,
catch/rethrow is more expensive than running a cleanup.

A try/finally implementation would look like

  {
    void (*_f)(void *) = f;
    void *_a = a;
    int _x = 1;

    try {
      g ();
      _x = x;
    } finally {
      if (_x) _f (_a);
    }
  }

An implementation using C++ destructors would work similarly:

  struct cleanup {
    void (*_f)(void *);
    void *_a;
    bool _x;

    cleanup (void (*fn)(void *), void *arg): _f (fn), _a (arg), _x (true) {}
    ~cleanup () { if (_x) _f(_a); }
  };
  ...
  {
    cleanup c (f, a);

    g ();

    c._x = x;
  }

Or, using attribute (cleanup):

  struct cleanup {
    void (*_f)(void *);
    void *_a;
    int _x;
  };

  void cleanup_dtor (struct cleanup *p)
  {
    if (p->_x) (p->_f)(p->_a);
  }
  ...
  {
    struct cleanup c __attribute ((__cleanup (cleanup_dtor)))
      = { f, a, 1 };

    g ();

    c._x = x;
  }

Any of these would do the job.  All of them involve adding EH to C.
I think that try/finally is the most elegant way to do that.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 19:06               ` Alexandre Oliva
@ 2003-05-08 19:47                 ` Mark Mitchell
  2003-05-08 20:19                   ` Alexandre Oliva
                                     ` (2 more replies)
  0 siblings, 3 replies; 52+ messages in thread
From: Mark Mitchell @ 2003-05-08 19:47 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jason Merrill, Mike Stump, gcc


> Err...  You're not using try/finally above,

That was my point: try/finally isn't really the ideal construct.

Your version does work, of course -- as does my try/catch expression of
the idea, modulo your comments below.

> and you're not necessarily
> using the values of f and a that were passed to pthread_cleanup_push.

This was a mistake, thanks.  You're right that the values need to be
saved, of course.

I agree that all of this is parenthetical; the key question is whether C
needs to have EH constructs or not, not which particular constructs they
are.

Let's just drop that train of thought; it's not going to be productive. 
I was just musing.

It would be nice, though, if the "goto" issue got back to the right
people; that should definitely be specified.  In the same light, the
behavior of "break" and "continue" should be specified; those are also
ways of exiting the scope.  

Undefined behavior might be the right answer.  Running the cleanup might
not be a good idea; the argument to pthread_cleanup_pop means that the
designers thought that sometimes you don't want to run the cleanup. 
(It's not really like a C++ destructor.)  

Maybe jumping out of the scope should just be ill-formed, no diagnostic
required.

I'm not sure, but this isn't the right forum to decide anyhow; I'd just
like for the POSIX people to know about the issue.

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 19:47                 ` Mark Mitchell
@ 2003-05-08 20:19                   ` Alexandre Oliva
  2003-05-08 21:18                   ` Jason Merrill
  2003-05-09 19:41                   ` Kai Henningsen
  2 siblings, 0 replies; 52+ messages in thread
From: Alexandre Oliva @ 2003-05-08 20:19 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Jason Merrill, Mike Stump, gcc

On May  8, 2003, Mark Mitchell <mark@codesourcery.com> wrote:

>> Err...  You're not using try/finally above,

> That was my point: try/finally isn't really the ideal construct.

Why not?  See, the finally case doesn't have the rethrow.  It comes
automatically from the semantics of finally.  This is the right
semantics for cleanups.  catch(...) doesn't get it right.

I do agree that the fact that the pthread cleanup is conditional in
the non-unwinding case makes it unsuitable for direct representation
as either a cleanup or a finally.  You need the conditional in either
case.

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist                Professional serial bug killer

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 19:47                 ` Mark Mitchell
  2003-05-08 20:19                   ` Alexandre Oliva
@ 2003-05-08 21:18                   ` Jason Merrill
  2003-05-13 21:10                     ` Mark Mitchell
  2003-05-09 19:41                   ` Kai Henningsen
  2 siblings, 1 reply; 52+ messages in thread
From: Jason Merrill @ 2003-05-08 21:18 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Alexandre Oliva, Mike Stump, gcc, Jason Merrill

On 08 May 2003 12:47:09 -0700, Mark Mitchell <mark@codesourcery.com> wrote:

> I agree that all of this is parenthetical; the key question is whether C
> needs to have EH constructs or not, not which particular constructs they
> are.

I think it does.  If we want to be able to interleave pthread cleanups from
C and C++ exception handling, then the C code needs to interface with the
EH runtime somehow; the obvious way to accomplish this is to use EH for
cleanups in threaded C code.

For a target that uses sjlj exceptions, this can have exactly the same
overhead as the old mechanism.

For a target that uses unwind tables, the normal case should be slightly
faster than in the old mechanism, since we don't need to call the pthread
library to register the cleanup.  Code size should be similar.  The main
overhead is the unwind tables, which just take up disk space unless they're
needed.  And there's more and more precedent for always emitting unwind
tables (ia64, x86-64).

I don't see any compelling reason to consider inventing a new mechanism.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-07 22:18             ` Mark Mitchell
  2003-05-07 23:01               ` Jason Merrill
  2003-05-08 12:05               ` Gabriel Dos Reis
@ 2003-05-09  5:46               ` Kai Henningsen
  2 siblings, 0 replies; 52+ messages in thread
From: Kai Henningsen @ 2003-05-09  5:46 UTC (permalink / raw)
  To: gcc

mark@codesourcery.com (Mark Mitchell)  wrote on 07.05.03 in <1052345885.5665.64.camel@doubledemon.codesourcery.com>:

> Seriously, one of the few remaining objections to programming in C++ has
> been "exceptions add too much overhead".  Once we add unwind tables to C
> -- as all of our proposals do, including mine -- I'm not really sure
> what the point of programming in C is going to be any more.

To me, the worst thing about C++ is the syntax. As someone who wrote a  
parser, I'm sure you know better than I where all the skeletons lie.

The second worst thing is the concept of "POD" vs. "non-POD" types. This  
seems expressly designed to violate the principle of least surprise.

Exceptions aren't even in the running. Exceptions are something that's  
present in almost every modern language - but most don't have syntax  
backtracking, or types both with and without initialization by default  
(and you can't add it to those that haven't got it without major surgery).

Programmer overhead, to me, is much more important than implementation  
overhead. Especially if the implementation overhead is only on the slow  
path.

MfG Kai

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 19:47                 ` Mark Mitchell
  2003-05-08 20:19                   ` Alexandre Oliva
  2003-05-08 21:18                   ` Jason Merrill
@ 2003-05-09 19:41                   ` Kai Henningsen
  2 siblings, 0 replies; 52+ messages in thread
From: Kai Henningsen @ 2003-05-09 19:41 UTC (permalink / raw)
  To: gcc

mark@codesourcery.com (Mark Mitchell)  wrote on 08.05.03 in <1052423229.3329.125.camel@minax.codesourcery.com>:

> I'm not sure, but this isn't the right forum to decide anyhow; I'd just
> like for the POSIX people to know about the issue.

Then you might want to contact austin-group-l@opengroup.org - that's the  
relevant mailing list for discussing this stuff. The Austin Group created  
both POSIX 2003 and TC1 for that. (And the Single Unix spec V3 aka #define  
_XOPEN_SOURCE 600 - it's all one text these days.)

Or you can use the "Send in a Defect Report" link on the online version at  
http://unix-systems.org/single_unix_specification/.

I think they're about to start work on TC2, so now would be the right  
moment to bring it up (and possibly the general "what does this mean for  
C++" question).

Subscription to that list is open to everyone, and every subscriber has  
access to all the drafts. See http://www.opengroup.org/austin/lists.html.

MfG Kai

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 21:18                   ` Jason Merrill
@ 2003-05-13 21:10                     ` Mark Mitchell
  2003-05-13 21:25                       ` Richard Henderson
                                         ` (2 more replies)
  0 siblings, 3 replies; 52+ messages in thread
From: Mark Mitchell @ 2003-05-13 21:10 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Alexandre Oliva, Mike Stump, gcc

On Thu, 2003-05-08 at 14:16, Jason Merrill wrote:
> On 08 May 2003 12:47:09 -0700, Mark Mitchell <mark@codesourcery.com> wrote:
> 
> > I agree that all of this is parenthetical; the key question is whether C
> > needs to have EH constructs or not, not which particular constructs they
> > are.
> 
> I think it does.  If we want to be able to interleave pthread cleanups from
> C and C++ exception handling, then the C code needs to interface with the
> EH runtime somehow; the obvious way to accomplish this is to use EH for
> cleanups in threaded C code.
> 
> For a target that uses sjlj exceptions, this can have exactly the same
> overhead as the old mechanism.

I owe you an answer on this thread; I apologize for the slow reply.

I don't really understand how the SJLJ trick you're describing works,
but I am happy to believe you if you are convinced that it does.  I'm
surprised that there's not a setjmp every time you use
pthread_cleanup_push, but it's great if that's not true, and your claim
obviously invalidates my performance complaint.

I'm still concerned in that doing this to C means that there is no going
back -- if something like my alternate-entry-point idea turns out to 
make sense for some platform there's no way to implement it because
people will now be using try/finally all through their code.

I'd also still prefer to see a solution that was maximally circumspect;
rather than approach this from a "what is the most elegant language
design?" point of view, I'd prefer a "what is the absolute minimal
feature needed to implement this POSIX requirement?" point of view.

That leads me towards __builtin_pthread_cleanup_push.  

For now, I'd much rather we just do as little as possible in the
compiler, and I'd also rather that we encourage people who really want
exceptions to use a language that has them.  We do ourselves a
disservice if we implicitly perpetuate the myth that using the C subset
of C++ is somehow worse than just using "straight" C.

In any case, there are some semantics to be defined; if a cleanup throws
an exception, what happens?  (You can't call std::terminate in a pure C
program.)

Yours,

-- 
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-13 21:10                     ` Mark Mitchell
@ 2003-05-13 21:25                       ` Richard Henderson
  2003-05-13 21:41                         ` Mark Mitchell
  2003-05-13 21:31                       ` Gabriel Dos Reis
  2003-05-15 17:00                       ` Jason Merrill
  2 siblings, 1 reply; 52+ messages in thread
From: Richard Henderson @ 2003-05-13 21:25 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Jason Merrill, Alexandre Oliva, Mike Stump, gcc

On Tue, May 13, 2003 at 02:06:50PM -0700, Mark Mitchell wrote:
> In any case, there are some semantics to be defined; if a cleanup throws
> an exception, what happens?

At present, the old exception doesn't get destroyed, and
the new exception propagates.  I'm not really sure *what*
should be said except that it's undefined behaviour.



r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-13 21:10                     ` Mark Mitchell
  2003-05-13 21:25                       ` Richard Henderson
@ 2003-05-13 21:31                       ` Gabriel Dos Reis
  2003-05-15 17:00                       ` Jason Merrill
  2 siblings, 0 replies; 52+ messages in thread
From: Gabriel Dos Reis @ 2003-05-13 21:31 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Jason Merrill, Alexandre Oliva, Mike Stump, gcc

Mark Mitchell <mark@codesourcery.com> writes:

[...]

| For now, I'd much rather we just do as little as possible in the
| compiler, and I'd also rather that we encourage people who really want
| exceptions to use a language that has them.  We do ourselves a
| disservice if we implicitly perpetuate the myth that using the C subset
| of C++ is somehow worse than just using "straight" C.

I think that the last sentence needs to be emphasized.

-- Gaby

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-13 21:25                       ` Richard Henderson
@ 2003-05-13 21:41                         ` Mark Mitchell
  2003-05-13 22:16                           ` Richard Henderson
  0 siblings, 1 reply; 52+ messages in thread
From: Mark Mitchell @ 2003-05-13 21:41 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Jason Merrill, Alexandre Oliva, Mike Stump, gcc

On Tue, 2003-05-13 at 14:19, Richard Henderson wrote:
> On Tue, May 13, 2003 at 02:06:50PM -0700, Mark Mitchell wrote:
> > In any case, there are some semantics to be defined; if a cleanup throws
> > an exception, what happens?
> 
> At present, the old exception doesn't get destroyed, and
> the new exception propagates.  I'm not really sure *what*
> should be said except that it's undefined behaviour.

That's perhaps acceptable; "undefined behavior" is at least an
affirmative non-specification.

Calling "abort" would seem to be the C-ish equivalent of the C++
std::terminate.

-- 
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-13 21:41                         ` Mark Mitchell
@ 2003-05-13 22:16                           ` Richard Henderson
  0 siblings, 0 replies; 52+ messages in thread
From: Richard Henderson @ 2003-05-13 22:16 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Jason Merrill, Alexandre Oliva, Mike Stump, gcc

On Tue, May 13, 2003 at 02:40:17PM -0700, Mark Mitchell wrote:
> Calling "abort" would seem to be the C-ish equivalent of the C++
> std::terminate.

Yeah.  I guess we still have MAY_NOT_THROW regions available with
which to attach this call to abort, so it wouldn't be too hard.
I dunno if this really warrents such enforcement though...


r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-13 21:10                     ` Mark Mitchell
  2003-05-13 21:25                       ` Richard Henderson
  2003-05-13 21:31                       ` Gabriel Dos Reis
@ 2003-05-15 17:00                       ` Jason Merrill
  2003-05-15 17:23                         ` Mark Mitchell
  2 siblings, 1 reply; 52+ messages in thread
From: Jason Merrill @ 2003-05-15 17:00 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Alexandre Oliva, Mike Stump, gcc

On 13 May 2003 14:06:50 -0700, Mark Mitchell <mark@codesourcery.com> wrote:

> I'd also still prefer to see a solution that was maximally circumspect;
> rather than approach this from a "what is the most elegant language
> design?" point of view, I'd prefer a "what is the absolute minimal
> feature needed to implement this POSIX requirement?" point of view.
>
> That leads me towards __builtin_pthread_cleanup_push.  

I think this is the core of the disagreement, and it seems like a
philosophical difference which can't really be addressed with technical
arguments.  Perhaps this is a matter for the steering committee, after all.

Basically, the choice is between a general language extension and a
specific compiler hook.

> For now, I'd much rather we just do as little as possible in the
> compiler, and I'd also rather that we encourage people who really want
> exceptions to use a language that has them.  We do ourselves a
> disservice if we implicitly perpetuate the myth that using the C subset
> of C++ is somehow worse than just using "straight" C.

But try/finally doesn't provide exceptions.  It provides a way of making
cleanups explicit, which in turn provides exception safety.  People who
really want exceptions would still need to use a language that have them.

try/finally is a useful construct even in the absence of exceptions; it
provides a structured alternative to "goto cleanup_and_return;".

> In any case, there are some semantics to be defined; if a cleanup throws
> an exception, what happens?  (You can't call std::terminate in a pure C
> program.)

A C++ exception carries a pointer to terminate; we could generalize that.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-15 17:00                       ` Jason Merrill
@ 2003-05-15 17:23                         ` Mark Mitchell
  0 siblings, 0 replies; 52+ messages in thread
From: Mark Mitchell @ 2003-05-15 17:23 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Alexandre Oliva, Mike Stump, gcc

On Thu, 2003-05-15 at 09:57, Jason Merrill wrote:
> On 13 May 2003 14:06:50 -0700, Mark Mitchell <mark@codesourcery.com> wrote:
> 
> > I'd also still prefer to see a solution that was maximally circumspect;
> > rather than approach this from a "what is the most elegant language
> > design?" point of view, I'd prefer a "what is the absolute minimal
> > feature needed to implement this POSIX requirement?" point of view.
> >
> > That leads me towards __builtin_pthread_cleanup_push.  
> 
> I think this is the core of the disagreement, and it seems like a
> philosophical difference which can't really be addressed with technical
> arguments.  Perhaps this is a matter for the steering committee, after all.
> 
> Basically, the choice is between a general language extension and a
> specific compiler hook.

I agree.

I think that are some semi-technical issues involved, but we have
resolved many of them, and the core policy decision seems to be more
important than the remaining ones.

-- 
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-14 21:11               ` Geoff Keating
@ 2003-05-14 22:20                 ` Richard Henderson
  0 siblings, 0 replies; 52+ messages in thread
From: Richard Henderson @ 2003-05-14 22:20 UTC (permalink / raw)
  To: Geoff Keating; +Cc: mrs, jason, gcc

On Wed, May 14, 2003 at 02:11:24PM -0700, Geoff Keating wrote:
> But that's the truly neat part of the plan, you don't need to make it
> robust.  All you need is to be able to look at RTL and determine
> whether the object-code reader will be successful in deducing the
> unwind information; if it would get it wrong, you just output explicit
> unwind information.

Oh, right.

You've got to maintain N+1 versions (rtl, plus N target assemblies)
of the same heuristics that (1) operate on different source languages
and (2) must be kept in exact sync lest we get incorrect results.

That sounds completely unmaintainable.

Lets just stick with dwarf2 unwind information, shall we?



r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-14  7:41             ` Richard Henderson
@ 2003-05-14 21:11               ` Geoff Keating
  2003-05-14 22:20                 ` Richard Henderson
  0 siblings, 1 reply; 52+ messages in thread
From: Geoff Keating @ 2003-05-14 21:11 UTC (permalink / raw)
  To: rth; +Cc: mrs, jason, gcc

> X-Original-To: geoffk@foam.wonderslug.com
> Date: Wed, 14 May 2003 00:39:01 -0700
> From: Richard Henderson <rth@redhat.com>
> Cc: mrs@apple.com, jason@redhat.com, gcc@gcc.gnu.org
> Mail-Followup-To: Richard Henderson <rth@redhat.com>,
> 	Geoff Keating <geoffk@geoffk.org>, mrs@apple.com, jason@redhat.com,
> 	gcc@gcc.gnu.org
> Content-Disposition: inline
> User-Agent: Mutt/1.4i
> X-OriginalArrivalTime: 14 May 2003 07:41:37.0074 (UTC) FILETIME=[3FDA1920:01C319EC]
> 
> On Tue, May 13, 2003 at 06:14:35PM -0700, Geoff Keating wrote:
> > I wasn't thinking of changing the prologue at all; the plan would be
> > to make the object-code reader sufficiently robust that it can handle
> > most routines, and to include a check for whether this particular
> > routine can be handled by the object-code reader.  The reader would
> > do things like skip over opcodes that it didn't understand.
> 
> I don't like this at all.  There's no way we can make
> this *that* robust.  You need to have prologues in a
> canonical form, no shrink-wrapping, no complicated block
> reordering, etc.

But that's the truly neat part of the plan, you don't need to make it
robust.  All you need is to be able to look at RTL and determine
whether the object-code reader will be successful in deducing the
unwind information; if it would get it wrong, you just output explicit
unwind information.

-- 
- Geoffrey Keating <geoffk@geoffk.org>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-14  1:14           ` Geoff Keating
@ 2003-05-14  7:41             ` Richard Henderson
  2003-05-14 21:11               ` Geoff Keating
  0 siblings, 1 reply; 52+ messages in thread
From: Richard Henderson @ 2003-05-14  7:41 UTC (permalink / raw)
  To: Geoff Keating; +Cc: mrs, jason, gcc

On Tue, May 13, 2003 at 06:14:35PM -0700, Geoff Keating wrote:
> I wasn't thinking of changing the prologue at all; the plan would be
> to make the object-code reader sufficiently robust that it can handle
> most routines, and to include a check for whether this particular
> routine can be handled by the object-code reader.  The reader would
> do things like skip over opcodes that it didn't understand.

I don't like this at all.  There's no way we can make
this *that* robust.  You need to have prologues in a
canonical form, no shrink-wrapping, no complicated block
reordering, etc.


r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-13 21:27         ` Richard Henderson
@ 2003-05-14  1:14           ` Geoff Keating
  2003-05-14  7:41             ` Richard Henderson
  0 siblings, 1 reply; 52+ messages in thread
From: Geoff Keating @ 2003-05-14  1:14 UTC (permalink / raw)
  To: rth; +Cc: mrs, jason, gcc

> X-Original-To: geoffk@foam.wonderslug.com
> Date: Tue, 13 May 2003 14:24:26 -0700
> From: Richard Henderson <rth@redhat.com>
> Cc: Mike Stump <mrs@apple.com>, Jason Merrill <jason@redhat.com>,
>    gcc@gcc.gnu.org
> Mail-Followup-To: Richard Henderson <rth@redhat.com>,
> 	Geoff Keating <geoffk@geoffk.org>, Mike Stump <mrs@apple.com>,
> 	Jason Merrill <jason@redhat.com>, gcc@gcc.gnu.org
> Content-Disposition: inline
> User-Agent: Mutt/1.4i
> X-OriginalArrivalTime: 13 May 2003 21:28:01.0403 (UTC) FILETIME=[880084B0:01C31996]
> 
> On Mon, May 12, 2003 at 05:07:36PM -0700, Geoff Keating wrote:
> > For instance, much of the information in the tables is included in the
> > object code (nearly all of it in the case of routines that don't
> > actually have cleanups).  It wouldn't be that hard to write a routine
> > that, given a return address, can determine what registers need to be
> > restored and from where in 90% of the cases by looking at the object
> > code; those routines (in the 90%) can have an abbreviated EH entry
> > that just says "use the object code", and the remaining 10% could have
> > a real EH entry.
> 
> If you have an entry at all, it means you know the extent of the
> function being described.  So you know where the entry point is.
> So no searching for that.  You'd just read forward from the start.
> 
> However, if you make the prologue regular enough that code reading
> is going to work, you're talking about *maybe* 2 bytes per saved
> register in the EH information, at which point I disbelieve that
> we're saving enough data space to make this worthwhile.

I was thinking that what you'd do is simply block out large regions of
the program with "if you want EH information in here, go look at the
object code", so entries would be combined: more space saving, but you
do have to search backwards.

I wasn't thinking of changing the prologue at all; the plan would be
to make the object-code reader sufficiently robust that it can handle
most routines, and to include a check for whether this particular
routine can be handled by the object-code reader.  The reader would
do things like skip over opcodes that it didn't understand.

-- 
- Geoffrey Keating <geoffk@geoffk.org>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-13 21:33 Richard Kenner
@ 2003-05-13 22:11 ` Richard Henderson
  0 siblings, 0 replies; 52+ messages in thread
From: Richard Henderson @ 2003-05-13 22:11 UTC (permalink / raw)
  To: Richard Kenner; +Cc: gcc

On Tue, May 13, 2003 at 05:38:19PM -0400, Richard Kenner wrote:
> Just FYI, in Ada this is defined and the action depends on how the
> cleanup was invoked.

C++ and Java define this as well (though differently).
There's certainly ample functionality in except.c to
handle this in any way that Ada would like.

Mark's question concerned C.


r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
@ 2003-05-13 21:33 Richard Kenner
  2003-05-13 22:11 ` Richard Henderson
  0 siblings, 1 reply; 52+ messages in thread
From: Richard Kenner @ 2003-05-13 21:33 UTC (permalink / raw)
  To: rth; +Cc: gcc

    > In any case, there are some semantics to be defined; if a cleanup throws
    > an exception, what happens?

    At present, the old exception doesn't get destroyed, and the new
    exception propagates.  I'm not really sure *what* should be said
    except that it's undefined behaviour.

Just FYI, in Ada this is defined and the action depends on how the
cleanup was invoked.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-13  0:07       ` Geoff Keating
@ 2003-05-13 21:27         ` Richard Henderson
  2003-05-14  1:14           ` Geoff Keating
  0 siblings, 1 reply; 52+ messages in thread
From: Richard Henderson @ 2003-05-13 21:27 UTC (permalink / raw)
  To: Geoff Keating; +Cc: Mike Stump, Jason Merrill, gcc

On Mon, May 12, 2003 at 05:07:36PM -0700, Geoff Keating wrote:
> For instance, much of the information in the tables is included in the
> object code (nearly all of it in the case of routines that don't
> actually have cleanups).  It wouldn't be that hard to write a routine
> that, given a return address, can determine what registers need to be
> restored and from where in 90% of the cases by looking at the object
> code; those routines (in the 90%) can have an abbreviated EH entry
> that just says "use the object code", and the remaining 10% could have
> a real EH entry.

If you have an entry at all, it means you know the extent of the
function being described.  So you know where the entry point is.
So no searching for that.  You'd just read forward from the start.

However, if you make the prologue regular enough that code reading
is going to work, you're talking about *maybe* 2 bytes per saved
register in the EH information, at which point I disbelieve that
we're saving enough data space to make this worthwhile.


r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 22:29     ` Mike Stump
@ 2003-05-13  0:07       ` Geoff Keating
  2003-05-13 21:27         ` Richard Henderson
  0 siblings, 1 reply; 52+ messages in thread
From: Geoff Keating @ 2003-05-13  0:07 UTC (permalink / raw)
  To: Mike Stump; +Cc: Jason Merrill, gcc

Mike Stump <mrs@apple.com> writes:

> On Thursday, May 8, 2003, at 01:46 PM, Richard Henderson wrote:
> > On Thu, May 08, 2003 at 11:29:50AM -0700, Mike Stump wrote:
> >> If table size is a big issue, we can have C default to sjlj EH (lower
> >> cost in non-EH code), and integrate in handling for sjlj exceptions
> >> into the dwarf EH system.
> >
> > Lets not, please.  This is much harder than you realize, and
> > involves a siginificant performance impact to dwarf-only EH.
> 
> Ok.  I was imagining a scheme that elaborated a failure case (lookup
> the pc and not find any entries) and just checked the new sp value
> against sjlh_EH_stack->sp and did the sjlj stack processing if
> required.  Maybe there are other nits that complicate it.

If table size is an issue, how about we just reduce it?

For instance, much of the information in the tables is included in the
object code (nearly all of it in the case of routines that don't
actually have cleanups).  It wouldn't be that hard to write a routine
that, given a return address, can determine what registers need to be
restored and from where in 90% of the cases by looking at the object
code; those routines (in the 90%) can have an abbreviated EH entry
that just says "use the object code", and the remaining 10% could have
a real EH entry.

For powerpc-elf, this could be as simple as this algorithm:

1. Look back in the object code until you see a stack push
2. That stack push creates the initial frame, so you know the size of the frame
2. Look forward from here until you see a branch
   3a. For the first store of each callee-saved register at an offset from
       the stack (maybe with some special code for altivec), restore it
       from that offset.

Now, this doesn't work in every case; routines with a too-large stack
frame, or that use alloca, won't work, and you won't want to try this
with any routine that's larger than a certain size for efficiency
reasons, and there may be other cases.  But it does work for the vast
majority of routines, and it's easy to check (given some RTL) whether
it'll work, and that's enough.

For x86, you'll want something a bit more complicated, because you'll
want to track push/pop operations, but if you can find the start of
the routine, you can follow code flow and assume that the stack depth
is constant at any particular point to avoid needing to go around
loops (like the Java verifier).

-- 
- Geoffrey Keating <geoffk@geoffk.org>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-09 10:16 ` Andrew Haley
  2003-05-09 12:08   ` Fergus Henderson
@ 2003-05-09 12:49   ` Jamie Lokier
  1 sibling, 0 replies; 52+ messages in thread
From: Jamie Lokier @ 2003-05-09 12:49 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Ranjit Mathew, gcc

Andrew Haley wrote:
>  > 1. Linux does not care if the signal handler returns or not (unlike 
>  > Windows).
> 
> Actually, the C standard is quite explicit about this: signal handlers
> may return either by a return statement of calling longjmp().  Maybe
> the Windows version of longjmp() does some magic to make this work.

Last time I tried it (a few years ago now), longjmp() out of a signal
handler which is interrupting a select() system call crashed Cygwin.
So, I had to use a different strategy for picking up SIGCHLD events on
that platform - limiting select() calls to a maximum timeout of a few
seconds.

-- Jamie

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-09 10:16 ` Andrew Haley
@ 2003-05-09 12:08   ` Fergus Henderson
  2003-05-09 12:49   ` Jamie Lokier
  1 sibling, 0 replies; 52+ messages in thread
From: Fergus Henderson @ 2003-05-09 12:08 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Ranjit Mathew, gcc

On 09-May-2003, Andrew Haley <aph@redhat.com> wrote:
> Actually, the C standard is quite explicit about this: signal handlers
> may return either by a return statement of calling longjmp().

[I think you meant to say "or" instead of "of".]

What you say is true to some extent, but it only applies to signal
handlers for synchronous signals, i.e. those caused by an explicit
call to abort() or raise().  For asynchronous signals, the behaviour
is undefined if the signal handler calls longjmp(), due to 
C99 7.14.1.1 paragraph 5, which prohibits such signal handlers
from calling *any* standard library function other than abort(),
_Exit(), or signal():

 |        If the signal  occurs  other  than  as  the  result  of
 |        calling  the  abort  or  raise  function,  the  behavior  is
 |        undefined if the signal handler refers to  any  object  with
 |        static  storage  duration other than by assigning a value to
 |        an object declared as volatile sig_atomic_t, or  the  signal
 |        handler  calls  any  function  in the standard library other
 |        than the abort function, the _Exit function, or  the  signal
 |        function  with the first argument equal to the signal number
 |        corresponding to the signal that caused  the  invocation  of
 |        the  handler.

-- 
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-09  9:54 Ranjit Mathew
@ 2003-05-09 10:16 ` Andrew Haley
  2003-05-09 12:08   ` Fergus Henderson
  2003-05-09 12:49   ` Jamie Lokier
  0 siblings, 2 replies; 52+ messages in thread
From: Andrew Haley @ 2003-05-09 10:16 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: gcc

Ranjit Mathew writes:
 > >  > > > The __finally block is executed in case of both "normal" C++ 
 > >exceptions
 > >  > > > as well as "faults" such as accessing a NULL pointer, dividing by 
 > >zero,
 > >  > > > etc.
 > >  > >
 > >  > >And your point is... ?  Libjava does this for dwarf2 EH on Linux.
 > >  >
 > >  > Yes, I know (http://gcc.gnu.org/java/port-signals.html).
 > >
 > >Oh no, that page is way, way out of date.  I must rewrite it.
 > >There's not even any mention of MD_FALLBACK_FRAME_STATE_FOR, which is
 > >the crucial part of the job.
 > 
 > Maybe laymen aren't supposed to be implementing MAKE_THROW_FRAME for
 > libgcj ;-), but I think it should at least be pointed out that the crucial 
 > reasons
 > the given example works *at all* are that:
 > 
 > 1. Linux does not care if the signal handler returns or not (unlike 
 > Windows).

Actually, the C standard is quite explicit about this: signal handlers
may return either by a return statement of calling longjmp().  Maybe
the Windows version of longjmp() does some magic to make this work.

 > 2. A proper MD_FALLBACK_FRAME_STATE_FOR definition for Linux/x86 

Or for any other OS, for that matter.  The trouble with doing
MD_FALLBACK_FRAME_STATE_FOR for other OSs is that it necessarily
requires knowledge of kernel data structures.

 >    ensures that unwinding works through the intervening signal
 >    handler frame when a "throw" occurs, instead of aborting the
 >    process with an uncerimonious "abnormal program termination" as
 >    would have happened otherwise.

Actually, that example was written before MD_FALLBACK_FRAME_STATE_FOR,
as was the whole page.  That's why it's so inaccurate.

Andrew.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
@ 2003-05-09  9:54 Ranjit Mathew
  2003-05-09 10:16 ` Andrew Haley
  0 siblings, 1 reply; 52+ messages in thread
From: Ranjit Mathew @ 2003-05-09  9:54 UTC (permalink / raw)
  To: aph; +Cc: gcc

>  > > > The __finally block is executed in case of both "normal" C++ 
>exceptions
>  > > > as well as "faults" such as accessing a NULL pointer, dividing by 
>zero,
>  > > > etc.
>  > >
>  > >And your point is... ?  Libjava does this for dwarf2 EH on Linux.
>  >
>  > Yes, I know (http://gcc.gnu.org/java/port-signals.html).
>
>Oh no, that page is way, way out of date.  I must rewrite it.
>There's not even any mention of MD_FALLBACK_FRAME_STATE_FOR, which is
>the crucial part of the job.

Maybe laymen aren't supposed to be implementing MAKE_THROW_FRAME for
libgcj ;-), but I think it should at least be pointed out that the crucial 
reasons
the given example works *at all* are that:

1. Linux does not care if the signal handler returns or not (unlike 
Windows).

2. A proper MD_FALLBACK_FRAME_STATE_FOR definition for Linux/x86 ensures
   that unwinding works through the intervening signal handler frame when a
   "throw" occurs, instead of aborting the process with an uncerimonious
   "abnormal program termination" as would have happened otherwise.

Ranjit.

_________________________________________________________________
Want to get married? Try online matrimony. 
http://server1.msn.co.in/features/onlinematrimony/index.asp It's cool.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-09  9:23 Ranjit Mathew
@ 2003-05-09  9:31 ` Andrew Haley
  0 siblings, 0 replies; 52+ messages in thread
From: Andrew Haley @ 2003-05-09  9:31 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: rth, gcc

Ranjit Mathew writes:
 > > > The __finally block is executed in case of both "normal" C++ exceptions
 > > > as well as "faults" such as accessing a NULL pointer, dividing by zero,
 > > > etc.
 > >
 > >And your point is... ?  Libjava does this for dwarf2 EH on Linux.
 > 
 > Yes, I know (http://gcc.gnu.org/java/port-signals.html).

Oh no, that page is way, way out of date.  I must rewrite it.
There's not even any mention of MD_FALLBACK_FRAME_STATE_FOR, which is
the crucial part of the job.

Andrew.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
@ 2003-05-09  9:23 Ranjit Mathew
  2003-05-09  9:31 ` Andrew Haley
  0 siblings, 1 reply; 52+ messages in thread
From: Ranjit Mathew @ 2003-05-09  9:23 UTC (permalink / raw)
  To: rth; +Cc: gcc

> > The __finally block is executed in case of both "normal" C++ exceptions
> > as well as "faults" such as accessing a NULL pointer, dividing by zero,
> > etc.
>
>And your point is... ?  Libjava does this for dwarf2 EH on Linux.

Yes, I know (http://gcc.gnu.org/java/port-signals.html).

The Windows port of GCJ also has a similar hack using SEH Win32 APIs. 
However,
unlike signal handlers on Linux, Windows actually expects the
"UnexpectedExceptionHandler" routine to *return* with a value to it - since
the current implementation doesn't, a simple thing like two Java
NullPointerExceptions results in a hung process on Win2K!

So if we manage to make it work reliably, we can then claim identical
semantics indeed. Touche.


>Incidentally, I would be willing to review and incorporate pieces
>of this into gcc.
>
>I can't promise anything about "__except" or "__leave" (indeed, I
>suspect that they _won't_ be incorporated), but we can at least talk
>about including SEH for general exception handling.  At minimum you'd
>be able to use catch(...) instead of "__except" in C++.

This is good news for all MinGW users, thank you! Casper Hornstrup
(chorns at users dot sourceforge dot net) of the ReactOS team, who
has created the SEH enabled GCC mentioned earlier, would be delighted
to hear this I think.

Ranjit.

_________________________________________________________________
Dreaming of a holiday? Make it happen.  
http://server1.msn.co.in/sp03/switzerlandtourism/index.asp In Switzerland!

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 20:49   ` Richard Henderson
@ 2003-05-08 22:29     ` Mike Stump
  2003-05-13  0:07       ` Geoff Keating
  0 siblings, 1 reply; 52+ messages in thread
From: Mike Stump @ 2003-05-08 22:29 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Jason Merrill, gcc

On Thursday, May 8, 2003, at 01:46 PM, Richard Henderson wrote:
> On Thu, May 08, 2003 at 11:29:50AM -0700, Mike Stump wrote:
>> If table size is a big issue, we can have C default to sjlj EH (lower
>> cost in non-EH code), and integrate in handling for sjlj exceptions
>> into the dwarf EH system.
>
> Lets not, please.  This is much harder than you realize, and
> involves a siginificant performance impact to dwarf-only EH.

Ok.  I was imagining a scheme that elaborated a failure case (lookup 
the pc and not find any entries) and just checked the new sp value 
against sjlh_EH_stack->sp and did the sjlj stack processing if 
required.  Maybe there are other nits that complicate it.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08  7:49 Ranjit Mathew
@ 2003-05-08 21:21 ` Richard Henderson
  0 siblings, 0 replies; 52+ messages in thread
From: Richard Henderson @ 2003-05-08 21:21 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: gcc

On Thu, May 08, 2003 at 01:19:23PM +0530, Ranjit Mathew wrote:
> The __finally block is executed in case of both "normal" C++ exceptions
> as well as "faults" such as accessing a NULL pointer, dividing by zero,
> etc.

And your point is... ?  Libjava does this for dwarf2 EH on Linux.

> Of course this would tie in with integrating SEH support into GCC,
> a brave attempt at which can be found at:
> 
>    http://reactos.wox.org/index.php?page=gccseh
> 
> in which case my point becomes moot.

Exactly.

Incidentally, I would be willing to review and incorporate pieces
of this into gcc.

I can't promise anything about "__except" or "__leave" (indeed, I
suspect that they _won't_ be incorporated), but we can at least talk
about including SEH for general exception handling.  At minimum you'd
be able to use catch(...) instead of "__except" in C++.

> Does anyone know why "fsjlj-exceptions" support was
> dropped and made a configure time option?

The runtime libraries can't handle both at once.

> SEH is an SJLJ type scheme:
> 
> http://www.microsoft.com/msj/0197/Exception/Exception.aspx

That's too bad.  Not *horrible* given that x86 only has
3 call-saved registers, but...


r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 18:30 ` Mike Stump
@ 2003-05-08 20:49   ` Richard Henderson
  2003-05-08 22:29     ` Mike Stump
  0 siblings, 1 reply; 52+ messages in thread
From: Richard Henderson @ 2003-05-08 20:49 UTC (permalink / raw)
  To: Mike Stump; +Cc: Jason Merrill, gcc

On Thu, May 08, 2003 at 11:29:50AM -0700, Mike Stump wrote:
> If table size is a big issue, we can have C default to sjlj EH (lower 
> cost in non-EH code), and integrate in handling for sjlj exceptions 
> into the dwarf EH system.

Lets not, please.  This is much harder than you realize, and
involves a siginificant performance impact to dwarf-only EH.

I *did* investigate this once upon a time, when rewriting the
exception handling code the last go-round.


r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-06 19:56 Jason Merrill
  2003-05-08 11:59 ` Gabriel Dos Reis
@ 2003-05-08 18:30 ` Mike Stump
  2003-05-08 20:49   ` Richard Henderson
  1 sibling, 1 reply; 52+ messages in thread
From: Mike Stump @ 2003-05-08 18:30 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc

On Tuesday, May 6, 2003, at 12:54 PM, Jason Merrill wrote:
>>  o RTH (and others) are strongly in favor of try/finally, which is
>>  implemented by several others compilers.
>
> Myself among them.  try/finally is well defined, and already 
> implemented in
> other languages and other C compilers.  IMO the explicit syntax is in
> keeping with the spirit of C.  If we have any exception handling 
> support
> whatsoever in C, it should be try/finally.  And we've (for some 
> definition
> of we) always intended to have some EH in C someday.  Now that we're 
> trying
> to integrate pthreads with EH, it's time.

try/finally I think is a reasonable approach.

If table size is a big issue, we can have C default to sjlj EH (lower 
cost in non-EH code), and integrate in handling for sjlj exceptions 
into the dwarf EH system.  It might be possible to bracket the C code 
with a single dummy region that just grabs the top element of the sjlj 
EH stack and throws it, so that non-gcc unwinders can unwind and throw 
through and into the C code while still being ABI compatible.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-07 10:18 Ranjit Mathew
  2003-05-07 13:54 ` Jason Merrill
  2003-05-07 18:23 ` Richard Henderson
@ 2003-05-08 18:02 ` Mike Stump
  2 siblings, 0 replies; 52+ messages in thread
From: Mike Stump @ 2003-05-08 18:02 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: jason, gcc

On Wednesday, May 7, 2003, at 03:19 AM, Ranjit Mathew wrote:
> Now I have an issue somewhat related to this
> discussion that I hope someone would be able to
> shed some light on: on Windows, the Cygwin/MinGW
> targets have had to give up on DW2 EH in favour of
> SJLJ purely because exceptions could not be
> thrown from a callback function, across the
> Windows Event Dispatcher stack to the handler
> of the exception.

This can be made to work given an integrated sjlj/dwarf2 EH scheme.  At 
transition points into and out of code compiled by other compilation 
systems (or -fno-exception code), we introduce a sjlj cleanup point 
there.  For, take for example:

foo() {
   DispatchMessage();
}

we have to know that DispatchMessage is going to go to `outside', 
imagine if you will:

#pragma gcc EH doesnt have unwind tables: DispatchMessage

foo() {
   ...
   DispatchMessage();
   ...
}

then it is a simple process to generate:

foo() {
	...
	sjljtry {
		DispatchMessage();
	} catch (...) {
		rethrow;
	}
	...
}

instead.  We can get back `into' the unwind tables by doing the lj back 
to this point.

> In fact, this seems to be a fundamental limitation
> of the DW2 EH mechanism and not just on Windows.

An unimplemented feature, I'd say, not a fundamental limitation.  
Though, such a change would be probably have ABI impact, as only the 
enhanced thrower would be able to fall back to doing the throw when it 
runs out of unwind information.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-08 11:59 ` Gabriel Dos Reis
@ 2003-05-08 15:02   ` Jason Merrill
  0 siblings, 0 replies; 52+ messages in thread
From: Jason Merrill @ 2003-05-08 15:02 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: gcc

On 08 May 2003 13:58:54 +0200, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:

> Jason Merrill <jason@redhat.com> writes:
>
> [...]
>
> | >  o Mark (and others) are against adding try/finally and favor adding
> | >  a different extension: __attribute__((cleanup(function)) which is
> | >  "lighter" in a sense.
> | 
> | I agree with Alex's comments on this approach; it's trying to introduce the
> | C++ object model into C, which seems like rather a backwards way to
> | approach exception cleanliness.
>
> Well, whatever is put in C will (implementation-wise speaking) end up
> in C++.  Therefore if you try to put try/finally in C then you've got to
> think about how it is suposed to work with C++.

Indeed, that's why Aldy's patch added __finally to C++ as well.  We did
think about how it would work.  It works just like it does in Java--there,
that was easy.

Specifically, a try-block can have both catch and __finally clauses; the
__finally must come at the end, and the construct is equivalent to two
separate try blocks, with the try/catch inside the try/__finally.

> And if there is an existing or close to existing mechanism in C++ to
> achieve those effects then I think it makes sense to write out the C++
> approach and try to see which bits can be safely added to C.  There is
> nothing backward in that approach.  Rather, it looks rather smooth.

I'm sympathetic to this approach, but the fundamental difference between C
and C++ (at least originally) is that C is a procedural abstraction
language, and C++ is an object-oriented language.  It makes sense to tie
cleanups to objects in an object-oriented language; it makes sense to write
them explicitly in a procedural language.

> In the past a bunch of extensions have been added to C without thinking
> about how they would intereact with the rest of the langage and the rest
> of C++.  I believe that is clearly a bogus way to extend C.

That's not the case here.  try/finally has already been implemented many
times.  The semantics are well understood.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-06 19:56 Jason Merrill
@ 2003-05-08 11:59 ` Gabriel Dos Reis
  2003-05-08 15:02   ` Jason Merrill
  2003-05-08 18:30 ` Mike Stump
  1 sibling, 1 reply; 52+ messages in thread
From: Gabriel Dos Reis @ 2003-05-08 11:59 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc

Jason Merrill <jason@redhat.com> writes:

[...]

| >  o Mark (and others) are against adding try/finally and favor adding
| >  a different extension: __attribute__((cleanup(function)) which is
| >  "lighter" in a sense.
| 
| I agree with Alex's comments on this approach; it's trying to introduce the
| C++ object model into C, which seems like rather a backwards way to
| approach exception cleanliness.

Well, whatever is put in C will (implementation-wise speaking) end up
in C++.  Therefore if you try to put try/finally in C then you've got to
think about how it is suposed to work with C++.  And if there is an
existing or close to existing mechanism in C++ to achieve those effects
then I think it makes sense to write out the C++ approach and try to
see which bits can be safely added to C.  There is nothing backward in
that approach.  Rather, it looks rather smooth.

In the past kbunch ox extensions have been added to C without thinking
about how they would intereact with the rest of the langage and the
rest of C++.  I believe that is clearly a bogus way to extend C.

-- Gaby

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
@ 2003-05-08  7:49 Ranjit Mathew
  2003-05-08 21:21 ` Richard Henderson
  0 siblings, 1 reply; 52+ messages in thread
From: Ranjit Mathew @ 2003-05-08  7:49 UTC (permalink / raw)
  To: gcc

> > The same issue was pointed out (albeit in passing)
> > when Aldy Hernandez had submitted his __try/__finally
> > patch to GCC for C.
>
>And I responded at the time claiming that the semantics of
>the two extensions are identical.

Very similar, but not identical, AFAICT:

    http://msdn.microsoft.com/library/en-us/vccelng/htm/state_14.asp

The __finally block is executed in case of both "normal" C++ exceptions
as well as "faults" such as accessing a NULL pointer, dividing by zero,
etc.

Of course this would tie in with integrating SEH support into GCC,
a brave attempt at which can be found at:

    http://reactos.wox.org/index.php?page=gccseh

in which case my point becomes moot.


> > Since the Win32 API stack does not have DW2 EH
> > unwind information, the program just terminates
> > when an exception is thrown (if using DW2 EH).
> >
> > SJLJ does not have any such problems.
> >
> > In fact, this seems to be a fundamental limitation
> > of the DW2 EH mechanism and not just on Windows.
>
>Yes.  Such is the price you pay for not saving all of the
>registers up front when an exception is *not* thrown.

IIRC, till some time ago "-fsjlj-exceptions" used to be available
that should allow such fringe cases to work albeit with a
performance hit.

Otherwise DW2 EH is *way better* than SJLJ as you all
know very well and should be the default.

Does anyone know why "fsjlj-exceptions" support was
dropped and made a configure time option?


> > MD_FALLBACK_FRAME_STATE_FOR looks a bit promising
> > but how do we generalise it to any "foreign" caller?
>
>Eh, MD_FALLBACK_FRAME_STATE_FOR isn't really generalizable.
>You could perhaps hack it to parse SEH unwind data, but...

SEH is an SJLJ type scheme:

http://www.microsoft.com/msj/0197/Exception/Exception.aspx


>Another possibility is to give up on unwind-dw2.c entirely
>and write a new unwinder that uses the SEH bits in the Win32
>API directly, all the time.  Then (1) you'd be able to unwind
>through Windows routines and (2) there'd be no "confusion"
>about the supposed "differences" in try/finally.

Possible, but it feels awful to throw away the fantastic DW2 EH...

:-(

Ranjit.

_________________________________________________________________
Dreaming of a holiday? Make it happen.  
http://server1.msn.co.in/sp03/switzerlandtourism/index.asp In Switzerland!

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-07 10:18 Ranjit Mathew
  2003-05-07 13:54 ` Jason Merrill
@ 2003-05-07 18:23 ` Richard Henderson
  2003-05-08 18:02 ` Mike Stump
  2 siblings, 0 replies; 52+ messages in thread
From: Richard Henderson @ 2003-05-07 18:23 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: jason, gcc

On Wed, May 07, 2003 at 03:49:06PM +0530, Ranjit Mathew wrote:
> The same issue was pointed out (albeit in passing)
> when Aldy Hernandez had submitted his __try/__finally
> patch to GCC for C.

And I responded at the time claiming that the semantics of
the two extensions are identical.

> Since the Win32 API stack does not have DW2 EH
> unwind information, the program just terminates
> when an exception is thrown (if using DW2 EH).
> 
> SJLJ does not have any such problems.
> 
> In fact, this seems to be a fundamental limitation
> of the DW2 EH mechanism and not just on Windows.

Yes.  Such is the price you pay for not saving all of the
registers up front when an exception is *not* thrown.

> MD_FALLBACK_FRAME_STATE_FOR looks a bit promising
> but how do we generalise it to any "foreign" caller?

Eh, MD_FALLBACK_FRAME_STATE_FOR isn't really generalizable.
You could perhaps hack it to parse SEH unwind data, but...

Another possibility is to give up on unwind-dw2.c entirely
and write a new unwinder that uses the SEH bits in the Win32
API directly, all the time.  Then (1) you'd be able to unwind
through Windows routines and (2) there'd be no "confusion"
about the supposed "differences" in try/finally.


r~

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
  2003-05-07 10:18 Ranjit Mathew
@ 2003-05-07 13:54 ` Jason Merrill
  2003-05-07 18:23 ` Richard Henderson
  2003-05-08 18:02 ` Mike Stump
  2 siblings, 0 replies; 52+ messages in thread
From: Jason Merrill @ 2003-05-07 13:54 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: gcc

On Wed, 07 May 2003 15:49:06 +0530, Ranjit Mathew <rmathew@hotmail.com> wrote:

> Sorry to butt in into this discussion, but I would like to point out that
> it would be a BAD idea to name these "__try/__finally" simply because
> these are used in the Windows world to deal with Windows Structured
> Exception Handling (SEH) and are a language extension introduced by MS
> Visual C/C++ (and adopted by other commercial compilers for Windows):
>[...]
> However unfortunate you consider this situation to be, if GCC introduces
> these keywords, it is going to create a lot of confusion.

Why would it cause confusion?  The VC++ version has the same semantics.

> Now I have an issue somewhat related to this discussion that I hope
> someone would be able to shed some light on: on Windows, the Cygwin/MinGW
> targets have had to give up on DW2 EH in favour of SJLJ purely because
> exceptions could not be thrown from a callback function, across the
> Windows Event Dispatcher stack to the handler of the exception.
>[...]
> Since the Win32 API stack does not have DW2 EH
> unwind information, the program just terminates
> when an exception is thrown (if using DW2 EH).

Sure.

> In fact, this seems to be a fundamental limitation of the DW2 EH
> mechanism and not just on Windows.

Yes, any callback API would have similar problems if the dispatcher is not
compiled with -fexceptions.

> So is there a way out of this?
>
> MD_FALLBACK_FRAME_STATE_FOR looks a bit promising but how do we
> generalise it to any "foreign" caller?

This is difficult on the x86; you would need to scan back to the beginning
of the function and disassemble the function prologue to find out where
registers are saved.  You could probably use some code from gdb as a
starting point.

Jason

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: __attribute__((cleanup(function)) versus try/finally
@ 2003-05-07 10:18 Ranjit Mathew
  2003-05-07 13:54 ` Jason Merrill
                   ` (2 more replies)
  0 siblings, 3 replies; 52+ messages in thread
From: Ranjit Mathew @ 2003-05-07 10:18 UTC (permalink / raw)
  To: jason; +Cc: gcc

 > 2) implementing something before standardization
 >
 >   That's why the patch doesn't create "try" and "finally" keywords, but
 >   rather "__try" and "__finally".  Though I can't imagine any similar
 >   construct having different semantics.

Sorry to butt in into this discussion, but I would
like to point out that it would be a BAD idea to name
these "__try/__finally" simply because these are used
in the Windows world to deal with Windows Structured
Exception Handling (SEH) and are a language extension
introduced by MS Visual C/C++ (and adopted by other
commercial compilers for Windows):

http://msdn.microsoft.com/library/en-us/vccelng/htm/statem_31.asp

There are quite a few commercial and non-commercial
programs out there that use these keywords.

However unfortunate you consider this situation to be,
if GCC introduces these keywords, it is going to create
a lot of confusion.

The same issue was pointed out (albeit in passing)
when Aldy Hernandez had submitted his __try/__finally
patch to GCC for C.

Now I have an issue somewhat related to this
discussion that I hope someone would be able to
shed some light on: on Windows, the Cygwin/MinGW
targets have had to give up on DW2 EH in favour of
SJLJ purely because exceptions could not be
thrown from a callback function, across the
Windows Event Dispatcher stack to the handler
of the exception.

Such code is common in Windows GUI applications
created with GCC (MinGW).

The "core" message loop of such Windows GUI programs
is roughly like the following:

   while( GetMessage( &msg, NULL, 0, 0)) {
     try {
       TranslateMessage( &msg);
       DispatchMessage( &msg);
     } catch (...) {
       /* Whatever */
     }
   }

DispatchMessage( ) is a Win32 API that ultimately
delivers the message to a registered "window procedure"
callback function within the application that
handles this message and might possibly throw an
exception.

Since the Win32 API stack does not have DW2 EH
unwind information, the program just terminates
when an exception is thrown (if using DW2 EH).

SJLJ does not have any such problems.

In fact, this seems to be a fundamental limitation
of the DW2 EH mechanism and not just on Windows.

So is there a way out of this?

MD_FALLBACK_FRAME_STATE_FOR looks a bit promising
but how do we generalise it to any "foreign"
caller?

Many thanks in advance for answering these.

Ranjit.

-- 
Ranjit Mathew          Email: rmathew AT hotmail DOT com

Bangalore, INDIA.      Web: http://ranjitmathew.tripod.com/

^ permalink raw reply	[flat|nested] 52+ messages in thread

* __attribute__((cleanup(function)) versus try/finally
@ 2003-05-06 19:56 Jason Merrill
  2003-05-08 11:59 ` Gabriel Dos Reis
  2003-05-08 18:30 ` Mike Stump
  0 siblings, 2 replies; 52+ messages in thread
From: Jason Merrill @ 2003-05-06 19:56 UTC (permalink / raw)
  To: gcc

[-- Attachment #1: Type: text/plain, Size: 162 bytes --]

This discussion started on the steering committee list, but we agreed that
it didn't belong there, so I'm forwarding my and Mark's mail to start the
discussion.


[-- Attachment #2.1: Type: text/plain, Size: 286 bytes --]

Subject: Topics
Content-length: 249

Topics:
   Re: __attribute__((cleanup(function)) versus try/finally
   Re: __attribute__((cleanup(function)) versus try/finally
   Re: __attribute__((cleanup(function)) versus try/finally
   Re: __attribute__((cleanup(function)) versus try/finally


[-- Attachment #2.2: Type: text/plain, Size: 3705 bytes --]

Date: Tue, 06 May 2003 12:50:25 -0400
From: Jason Merrill <jason@redhat.com>
Subject: Re: __attribute__((cleanup(function)) versus try/finally
Message-ID: <wvlwuh4aujy.fsf@prospero.boston.redhat.com>
References: <Pine.BSF.4.55.0305061457450.57349@acrux.dbai.tuwien.ac.at>
MIME-Version: 1.0
Content-length: 3393

On Tue, 6 May 2003 15:20:59 +0200 (CEST), Gerald Pfeifer wrote:

> For those that didn't follow gcc-patches, there has been strong
> disagreement on how to implement exception handling in C for some
> time now:
>
>  o RTH (and others) are strongly in favor of try/finally, which is
>  implemented by several others compilers.

Myself among them.  try/finally is well defined, and already implemented in
other languages and other C compilers.  IMO the explicit syntax is in
keeping with the spirit of C.  If we have any exception handling support
whatsoever in C, it should be try/finally.  And we've (for some definition
of we) always intended to have some EH in C someday.  Now that we're trying
to integrate pthreads with EH, it's time.

>  o Mark (and others) are against adding try/finally and favor adding
>  a different extension: __attribute__((cleanup(function)) which is
>  "lighter" in a sense.

I agree with Alex's comments on this approach; it's trying to introduce the
C++ object model into C, which seems like rather a backwards way to
approach exception cleanliness.

FWIW, here's a post to the glibc list from someone who worked on threading
in Tru64, the closest thing to a prior implementation.

  http://sources.redhat.com/ml/libc-alpha/1999-08/msg00038.html

Here's the beginning of the try/finally thread:

  http://gcc.gnu.org/ml/gcc-patches/2002-11/threads.html#00239

Which includes the message Michael mentions:

  http://gcc.gnu.org/ml/gcc-patches/2002-11/msg00451.html

To sum up, the objections to try/finally amounted to:

1) -fexceptions overhead

  On any modern OS, the overhead is only on disk unless EH constructs are
  actually used.  The unwind tables are only loaded if an exception is
  thrown.  By contrast, registering pthread cleanups to work with the
  longjmp_unwind solution involves a setjmp, which needs to run whether or
  not you throw an exception.

2) implementing something before standardization

  That's why the patch doesn't create "try" and "finally" keywords, but
  rather "__try" and "__finally".  Though I can't imagine any similar
  construct having different semantics.

3) poorly defined semantics

  Nonsense.  As I wrote early in the thread:

  The code in the finally block is run on exit from the try block, except
  that exiting a try block with a corresponding finally block via longjmp
  or computed goto has undefined behavior.

  It's simple, it's straightforward, it shares implementation with the Java
  frontend.  There's tons of prior art.

4) it's the wrong choice

  Other proposed solutions were:
    adding destructors to C (i.e. attribute cleanup),
      Again, I don't want to get into object lifetime stuff in C.
    try/catch instead
      C++ doesn't have try/finally because it has destructors.  C doesn't
      need catch for pthreads, but we could implement it later if we want
      full EH in C.
    specialized pthread primitive builtins
      ...which would be modelled internally with TRY_FINALLY_EXPR.  I could
      accept this, but I'd rather provide the more general facility and let
      the pthreads library worry about pthreads semantics.
    longjmp_unwind
      ...which has now been implemented, though I don't think the pthread
      library uses it yet.

  IMO none of these are nearly as clean in design as try/finally.  Any one
  of them will be more of a maintenance headache.

Jason


[-- Attachment #2.3: Type: text/plain, Size: 2160 bytes --]

Date: 06 May 2003 11:29:01 -0700
From: Mark Mitchell <mark@codesourcery.com>
Subject: Re: __attribute__((cleanup(function)) versus try/finally
Message-Id: <1052245742.2583.315.camel@doubledemon.codesourcery.com>
References: <Pine.BSF.4.55.0305061457450.57349@acrux.dbai.tuwien.ac.at>
MIME-Version: 1.0
Content-length: 1836

On Tue, 2003-05-06 at 06:20, Gerald Pfeifer wrote:
> Michael Matz asked that the SC addresses this issue, and I'm forwarding
> his message below.  I have also suggested to provide more detailed
> technical arguments which I'll forward as well.
> 
> For those that didn't follow gcc-patches, there has been strong
> disagreement on how to implement exception handling in C for some
> time now:
> 
>  o RTH (and others) are strongly in favor of try/finally, which is
>  implemented by several others compilers.
> 
>  o Mark (and others) are against adding try/finally and favor adding
>  a different extension: __attribute__((cleanup(function)) which is
>  "lighter" in a sense.

I think RTH accepts the attribute solution as well.  He would prefer
try/finally, as I would prefer no extension, but I think we are both
willing to accept the attribute.

A key point (which seems to be missed by most people in this dicussion)
is that you do not need a language extension to get the correct
behavior.  

You simply need to have the exception-handling mechanism aware of the C
cleanup stack.

In fact, that solution delivers maximum performance:

(1) C functions do not need to have handler code inserted.

(2) You do not have to transfer control from the EH mechanism to the
stack frame of the caller in order to perform the cleanups.

The __attribute__ solution can be implemented with the same optimal
performance, but that does not seem to be the way in which people intend
to implement it.

The try/finally solution cannot be implemented with this same
performance; it will, in fact, exact a performance price, in terms of
both code space and the speed at which cleanups are run, on all
systems.  On systems with setjmp/longjmp exceptions, both costs will be
very high indeed.

-- 
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com


[-- Attachment #2.4: Type: text/plain, Size: 2498 bytes --]

Date: Tue, 06 May 2003 15:15:48 -0400
From: Jason Merrill <jason@redhat.com>
To: Mark Mitchell <mark@codesourcery.com>
Subject: Re: __attribute__((cleanup(function)) versus try/finally
Message-ID: <wvlissnc2e3.fsf@prospero.boston.redhat.com>
References: <Pine.BSF.4.55.0305061457450.57349@acrux.dbai.tuwien.ac.at>
	<1052245742.2583.315.camel@doubledemon.codesourcery.com>
MIME-Version: 1.0
Content-length: 2086

On 06 May 2003 11:29:01 -0700, Mark Mitchell <mark@codesourcery.com> wrote:

> A key point (which seems to be missed by most people in this dicussion)
> is that you do not need a language extension to get the correct behavior.
>
> You simply need to have the exception-handling mechanism aware of the C
> cleanup stack.

That would be an extension too, wouldn't it?

In any case, how are you thinking to do this?  You've mentioned such a
thing before, but I haven't noticed an implementation sketch.

> In fact, that solution delivers maximum performance:
>
> (1) C functions do not need to have handler code inserted.
>
> (2) You do not have to transfer control from the EH mechanism to the
> stack frame of the caller in order to perform the cleanups.
>
> The __attribute__ solution can be implemented with the same optimal
> performance, but that does not seem to be the way in which people intend
> to implement it.

> The try/finally solution cannot be implemented with this same
> performance; it will, in fact, exact a performance price, in terms of
> both code space and the speed at which cleanups are run, on all
> systems.  On systems with setjmp/longjmp exceptions, both costs will be
> very high indeed.

Hmm.  Are you talking about representing cleanups in the LSDA via a
function pointer and a CFA offset for the argument object?  That way you
still need unwind info and PC range tables, but you don't put any code into
the function itself.

This strategy was discussed at the ABI meetings; I think Intel was
advocating it.  We all agreed that it was a valid approach, but most of us
thought that having the cleanups inline offered more optimization
opportunities (code motion into the landing pad, jumping between cleanups,
inlining destructors, not forcing the object into the stack).

It might make sense to do this for C functions, though.

It's somewhat more complicated to do this sort of thing with try/finally,
since it allows an arbitrary block of code, not just a call, but the
GOTO_SUBROUTINE_EXPR expansion of TRY_FINALLY_EXPR is a very similar idea.

Jason


[-- Attachment #2.5: Type: text/plain, Size: 3013 bytes --]

Date: 06 May 2003 12:38:09 -0700
From: Mark Mitchell <mark@codesourcery.com>
To: Jason Merrill <jason@redhat.com>
Subject: Re: __attribute__((cleanup(function)) versus try/finally
Message-Id: <1052249890.31850.338.camel@doubledemon.codesourcery.com>
References: <Pine.BSF.4.55.0305061457450.57349@acrux.dbai.tuwien.ac.at>
	<1052245742.2583.315.camel@doubledemon.codesourcery.com> 
	<wvlissnc2e3.fsf@prospero.boston.redhat.com>
MIME-Version: 1.0
Content-length: 2546

> > You simply need to have the exception-handling mechanism aware of the C
> > cleanup stack.
> 
> That would be an extension too, wouldn't it?

Yes -- but on the library side, not on the compiler side.  The library's
going to have extensions no matter what -- this whole pthread
cancellation strategy is an extension.
 
> In any case, how are you thinking to do this?  You've mentioned such a
> thing before, but I haven't noticed an implementation sketch.

I did on the gcc list, but it got lost in the noise, I think.  

The strategy is:

(1) Have pthread_cleanup_push include the current $sp in the cleanup
record.  Otherwise, use the same data structures currently used by
glibc's pthread_cleanup_push.

(2) When an exception is thrown:

- Figure out where the next handler/cleanup will be.

  (By hypothesis, this is not going to be in C code, because we don't
  have try/finally in C.)

- If unwinding the stack to that destination will result in $sp be older
than the $sp recorded in the cleanup at the top of the C cleanup stack,
run C cleanups until that is no longer true.

- Transfer control to the handler as is done now.

> > The try/finally solution cannot be implemented with this same
> > performance; it will, in fact, exact a performance price, in terms of
> > both code space and the speed at which cleanups are run, on all
> > systems.  On systems with setjmp/longjmp exceptions, both costs will be
> > very high indeed.
> 
> Hmm.  Are you talking about representing cleanups in the LSDA via a
> function pointer and a CFA offset for the argument object?  That way you
> still need unwind info and PC range tables, but you don't put any code into
> the function itself.

I'm not as sophisticated as you about this; I don't actually know what
all the EH implementation details are.  With the scheme above, you do
still need PC range tables and (some?) unwind information, but you don't
put any code into the function.  I keep mumbling that I think you might
be able to avoid some of the unwind information for C, but I've never
done what it would take to prove or disprove that assertion.  

The key point is that you don't need any handler code in the function.

The observation behind this is that pthread cleanups -- unlike C++ catch
clauses -- do not need to execute in the frame of the function that
pushed them.  They just need to execute while the stack is still there,
in case the "arg" to the function directly or indirectly references
stuff on the stack.

-- 
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com


^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2003-05-15 17:23 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <Pine.BSF.4.55.0305061457450.57349@acrux.dbai.tuwien.ac.at>
     [not found] ` <1052245742.2583.315.camel@doubledemon.codesourcery.com>
     [not found]   ` <wvlissnc2e3.fsf@prospero.boston.redhat.com>
     [not found]     ` <1052249890.31850.338.camel@doubledemon.codesourcery.com>
2003-05-06 21:04       ` __attribute__((cleanup(function)) versus try/finally Jason Merrill
2003-05-06 21:24         ` Mark Mitchell
2003-05-07 21:21           ` Jason Merrill
2003-05-07 22:18             ` Mark Mitchell
2003-05-07 23:01               ` Jason Merrill
2003-05-08 12:05               ` Gabriel Dos Reis
2003-05-09  5:46               ` Kai Henningsen
2003-05-06 21:52         ` Anthony Green
2003-05-08 17:44         ` Mike Stump
2003-05-08 17:45           ` Jason Merrill
2003-05-08 18:40             ` Mark Mitchell
2003-05-08 19:06               ` Alexandre Oliva
2003-05-08 19:47                 ` Mark Mitchell
2003-05-08 20:19                   ` Alexandre Oliva
2003-05-08 21:18                   ` Jason Merrill
2003-05-13 21:10                     ` Mark Mitchell
2003-05-13 21:25                       ` Richard Henderson
2003-05-13 21:41                         ` Mark Mitchell
2003-05-13 22:16                           ` Richard Henderson
2003-05-13 21:31                       ` Gabriel Dos Reis
2003-05-15 17:00                       ` Jason Merrill
2003-05-15 17:23                         ` Mark Mitchell
2003-05-09 19:41                   ` Kai Henningsen
2003-05-08 19:37               ` Jason Merrill
2003-05-07  0:14   ` Richard Henderson
2003-05-07  2:32     ` Mark Mitchell
2003-05-13 21:33 Richard Kenner
2003-05-13 22:11 ` Richard Henderson
  -- strict thread matches above, loose matches on Subject: below --
2003-05-09  9:54 Ranjit Mathew
2003-05-09 10:16 ` Andrew Haley
2003-05-09 12:08   ` Fergus Henderson
2003-05-09 12:49   ` Jamie Lokier
2003-05-09  9:23 Ranjit Mathew
2003-05-09  9:31 ` Andrew Haley
2003-05-08  7:49 Ranjit Mathew
2003-05-08 21:21 ` Richard Henderson
2003-05-07 10:18 Ranjit Mathew
2003-05-07 13:54 ` Jason Merrill
2003-05-07 18:23 ` Richard Henderson
2003-05-08 18:02 ` Mike Stump
2003-05-06 19:56 Jason Merrill
2003-05-08 11:59 ` Gabriel Dos Reis
2003-05-08 15:02   ` Jason Merrill
2003-05-08 18:30 ` Mike Stump
2003-05-08 20:49   ` Richard Henderson
2003-05-08 22:29     ` Mike Stump
2003-05-13  0:07       ` Geoff Keating
2003-05-13 21:27         ` Richard Henderson
2003-05-14  1:14           ` Geoff Keating
2003-05-14  7:41             ` Richard Henderson
2003-05-14 21:11               ` Geoff Keating
2003-05-14 22:20                 ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).