Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Some issues with Technical Report on C++ Performance (DRAFT)

15 views
Skip to first unread message

Sergey P. Derevyago

unread,
Jun 22, 2002, 1:06:30 PM6/22/02
to
I've just read http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1359.pdf
and I'm really surprised. It has some issues w.r.t. EH that must be corrected.
And I'm surprised because these issues were (hotly) debated not so long ago
(clc++m, "EH implementation", late 2000).

Lets take a look at page 31 of the TR:

2.4.1.2 The "Table approach"
Typical implementations using the static approach will generate read-only
tables for determines the current execution context, locating catch clauses,
and tracking objects needing destruction.

It should be noted, that the read-only data is _not_ sufficient to track the
objects in question. One must remember that arrays of UDT also require the
number of already created objects. And these numbers are usually stored in
stack frames. So the phrase "... no run-time costs are associated with normal
execution" is just wrong: EH do involve certain run-time penalty.
BTW compilers often create additional code to destruct partially created
arrays so we usually have some code bloat aside from the "PC tables". And both
new and new[] operators incur similar "problems" because they also have to do
some clean-up.

And I suggest to add new "As each array of objects is created" bullet to the
2.4.1.2.2 subsection because this case has some "special traits" w.r.t.
table-diven EH implementations.
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

Andrew Koenig

unread,
Jun 23, 2002, 9:07:23 PM6/23/02
to
Sergey> It should be noted, that the read-only data is _not_ sufficient to track the
Sergey> objects in question. One must remember that arrays of UDT also require the
Sergey> number of already created objects. And these numbers are usually stored in
Sergey> stack frames. So the phrase "... no run-time costs are associated with normal
Sergey> execution" is just wrong: EH do involve certain run-time penalty.

Why? The compiled code needs a counter somewhere to initialize the
array anyway, even if that counter is only implicit (i.e. it can be
obtained only by doing arithmetic on the values of various registers
during the loop's execution). So all that needs to happen is for the
read-only table to contain enough information to allow the library
to determine the value of that counter. It might even be that to
do so, the compiler needs to put code into the table to locate the
right registers and do the appropriate arithmetic, and the algorithm
might even depend on the value of the program counter at the time
of the exception. But I see no reason for any extra run-time bookeeping.

--
Andrew Koenig, a...@research.att.com, http://www.research.att.com/info/ark

David Abrahams

unread,
Jun 23, 2002, 10:30:25 PM6/23/02
to

"Sergey P. Derevyago" <non-ex...@iobox.com> wrote in message
news:3D0E5E16...@iobox.com...

> Lets take a look at page 31 of the TR:


>
> 2.4.1.2 The "Table approach"
> Typical implementations using the static approach will generate read-only
> tables for determines the current execution context, locating catch
clauses,
> and tracking objects needing destruction.
>
> It should be noted, that the read-only data is _not_ sufficient to track
the
> objects in question. One must remember that arrays of UDT also require the
> number of already created objects. And these numbers are usually stored in
> stack frames. So the phrase "... no run-time costs are associated with
normal
> execution" is just wrong:

No, you need to keep track of that number even if you were going to ignore
errors, to know which one to construct next. It doesn't matter whether it's
in a stack frame or in a register; exception tables can record the location
of the information either way.

> EH do involve certain run-time penalty.

Not neccessarily.

> BTW compilers often create additional code to destruct partially created
> arrays so we usually have some code bloat aside from the "PC tables".

That's not "a run-time cost associated with normal execution". That's a cost
associated with recovering from errors, using EH or otherwise.

-Dave

James Kanze

unread,
Jun 23, 2002, 10:30:28 PM6/23/02
to
"Sergey P. Derevyago" <non-ex...@iobox.com> writes:

|> I've just read
|> http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1359.pdf and
|> I'm really surprised. It has some issues w.r.t. EH that must be
|> corrected. And I'm surprised because these issues were (hotly)
|> debated not so long ago (clc++m, "EH implementation", late 2000).

|> Lets take a look at page 31 of the TR:

|> 2.4.1.2 The "Table approach"
|> Typical implementations using the static approach will generate
|> read-only tables for determines the current execution context,
|> locating catch clauses, and tracking objects needing destruction.

|> It should be noted, that the read-only data is _not_
|> sufficient to track the objects in question. One must remember
|> that arrays of UDT also require the number of already created
|> objects. And these numbers are usually stored in stack frames.

The number is nothing more than the index (or pointer) used in the
loop to initialize the objects. Exception handling doesn't add
anything here.

Obviously, the code generated for the exception handler has to know
how to find this number (which is more likely in a register than on
the stack). But since this code is generated at the exact same place
as the loop, the compiler should have no problems with it.

|> So the phrase "... no run-time costs are associated with normal
|> execution" is just wrong: EH do involve certain run-time penalty.

No, see above.

|> BTW compilers often create additional code to destruct
|> partially created arrays so we usually have some code bloat aside
|> from the "PC tables". And both new and new[] operators incur
|> similar "problems" because they also have to do some clean-up.

This statement concerns runtime, not code size. It is well known that
the 0 runtime solutions for exception handling involve some additional
code. Which could be called code bloat.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Tel. +33 1 41 89 80 93

Sergey P. Derevyago

unread,
Jun 25, 2002, 2:51:46 PM6/25/02
to
Andrew Koenig wrote:
> Sergey> It should be noted, that the read-only data is _not_ sufficient to track the
> Sergey> objects in question. One must remember that arrays of UDT also require the
> Sergey> number of already created objects. And these numbers are usually stored in
> Sergey> stack frames. So the phrase "... no run-time costs are associated with normal
> Sergey> execution" is just wrong: EH do involve certain run-time penalty.
> Why? The compiled code needs a counter somewhere to initialize the
> array anyway, even if that counter is only implicit (i.e. it can be
> obtained only by doing arithmetic on the values of various registers
> during the loop's execution).
No, it can not: compiler can't keep the number of already created objects in
a register only. Consider the following code:
-----------------------------------8<-----------------------------------
struct A {
A();
~A();
};

void g();

void f()
{
A a[10];
g();
}
-----------------------------------8<-----------------------------------
Compiler doesn't know here whether A::A() (conditionally) calls f() so it has
to code for the "worst possible" case. I.e. it must be prepared for the
f()->A::A()->f()->A::A()->... chain of calls, where each f() has costructed
some part of the array (different for the different f()s).


--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

---

Sergey P. Derevyago

unread,
Jun 25, 2002, 3:19:51 PM6/25/02
to
David Abrahams wrote:
> > It should be noted, that the read-only data is _not_ sufficient to track
> > the objects in question. One must remember that arrays of UDT also
> > require the number of already created objects. And these numbers are
> > usually stored in stack frames. So the phrase "... no run-time costs are
> > associated with normal execution" is just wrong:
> No, you need to keep track of that number even if you were going to ignore
> errors, to know which one to construct next. It doesn't matter whether it's
> in a stack frame or in a register; exception tables can record the location
> of the information either way.
Please, take a look at my answer to Andrew Koenig. The point is that having
EH enabled, compiler has to save the number of the already created objects on
the stack before it calls A::A().

> > EH do involve certain run-time penalty.
> Not neccessarily.

Well, we still don't finish our "fight" :)) (Message-ID:
<3ACD7196...@iobox.com>):
-----------------------------------8<-----------------------------------
David Abrahams wrote:
> These costs have been addressed in post-2.95.x versions to varying degrees.
> I know the GCC 3.0 ABI has a "zero-runtime-overhead" exception model, and I
> believe you will find this implemented in the latest x86 and StrongArm
> linux-targeted compiler snapshots (among others).
Thanx. I'll check this statement with great pleasure :)
------------------------------------8<-----------------------------------
And I'm still going to check the statement to fight yet another
"zero-runtime-overhead" exception model :)


--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

Sergey P. Derevyago

unread,
Jun 25, 2002, 3:25:16 PM6/25/02
to
James Kanze wrote:
> |> It should be noted, that the read-only data is _not_
> |> sufficient to track the objects in question. One must remember
> |> that arrays of UDT also require the number of already created
> |> objects. And these numbers are usually stored in stack frames.
> The number is nothing more than the index (or pointer) used in the
> loop to initialize the objects. Exception handling doesn't add
> anything here.
Yes, it does. Please see my answers to both Andrew Koenig and David Abrahams.

> Obviously, the code generated for the exception handler has to know
> how to find this number (which is more likely in a register than on
> the stack).

No, it will find it in memory, usually in stack frame.

> But since this code is generated at the exact same place
> as the loop, the compiler should have no problems with it.

Generally speaking, there might be several (unfinished) instancies of the
same array at the time, so...


--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

---

Ian McCulloch

unread,
Jun 25, 2002, 7:25:12 PM6/25/02
to
Sergey P. Derevyago wrote:

> James Kanze wrote:
>> |> It should be noted, that the read-only data is _not_
>> |> sufficient to track the objects in question. One must remember
>> |> that arrays of UDT also require the number of already created
>> |> objects. And these numbers are usually stored in stack frames.
>> The number is nothing more than the index (or pointer) used in the
>> loop to initialize the objects. Exception handling doesn't add
>> anything here.
> Yes, it does. Please see my answers to both Andrew Koenig and David
> Abrahams.

Dutifully read. Not understood, but read :-)

>
>> Obviously, the code generated for the exception handler has to know
>> how to find this number (which is more likely in a register than on
>> the stack).
> No, it will find it in memory, usually in stack frame.

Whether exception handling is used or not, a loop variable is needed to
initialize the array, and whether exception handling is used or not if the
constructor is not inlined the loop variable will need to be saved
somewhere (ie the stack) for the call. What is different about the
exception handling case?

>
>> But since this code is generated at the exact same place
>> as the loop, the compiler should have no problems with it.
> Generally speaking, there might be several (unfinished) instancies of the
> same array at the time, so...

so what?

Confused,
Ian McCulloch

Sean Parent

unread,
Jun 25, 2002, 7:45:22 PM6/25/02
to
in article 3D18BB03...@iobox.com, Sergey P. Derevyago at
non-ex...@iobox.com wrote on 6/25/02 11:51 AM:

> No, it can not: compiler can't keep the number of already created objects in
> a register only. Consider the following code:

You appear to making assumptions about the machine architecture and runtime.
Under IBM Power (and PowerPC) ABI the caller would reserve space on the
stack for any routine being called to flush registers but doesn't flush on
the call. The routine being called dumps registers into the reserved frame
if it uses them. In this way if A::A() is trivial, there is no overhead and
the index can stay in a register.

--
Sean Parent
Sr. Computer Scientist II
Advanced Technology Group
Adobe Systems Incorporated
spa...@adobe.com

James Kanze

unread,
Jun 26, 2002, 12:34:07 PM6/26/02
to
"Sergey P. Derevyago" <non-ex...@iobox.com> wrote in message
news:<3D18C16A...@iobox.com>...

> James Kanze wrote:
> > |> It should be noted, that the read-only data is _not_
> > |> sufficient to track the objects in question. One must remember
> > |> that arrays of UDT also require the number of already created
> > |> objects. And these numbers are usually stored in stack frames.

> > The number is nothing more than the index (or pointer) used in the
> > loop to initialize the objects. Exception handling doesn't add
> > anything here.

> Yes, it does. Please see my answers to both Andrew Koenig and David
> Abrahams.

I saw them. I still don't see where there is a problem.

> > Obviously, the code generated for the exception handler has to
> > know how to find this number (which is more likely in a register
> > than on the stack).

> No, it will find it in memory, usually in stack frame.

Implementation dependant. With g++ 3.1 for Sparc under Solaris 2.8,
compiled with -O3, the address of the element being constructed is in
register i0, the number of elements yet to be constructed in register
l1. The exception handling routine that gets generated knows this.

I would expect this to be the case for any RISC machine.

> > But since this code is generated at the exact same place as the
> > loop, the compiler should have no problems with it.

> Generally speaking, there might be several (unfinished)
> instancies of the same array at the time, so...

So? Of course there can be several unfinished instances of the same
array. Each will have its own context.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(0)69 63198627

David Abrahams

unread,
Jun 26, 2002, 5:48:20 PM6/26/02
to

"Sergey P. Derevyago" <non-ex...@iobox.com> wrote in message
news:3D18BB03...@iobox.com...

> No, it can not: compiler can't keep the number of already created objects
in
> a register only. Consider the following code:
> -----------------------------------8<-----------------------------------
> struct A {
> A();
> ~A();
> };
>
> void g();
>
> void f()
> {
> A a[10];
> g();
> }
> -----------------------------------8<-----------------------------------
> Compiler doesn't know here whether A::A() (conditionally) calls f() so it
has
> to code for the "worst possible" case. I.e. it must be prepared for the
> f()->A::A()->f()->A::A()->... chain of calls, where each f() has
costructed
> some part of the array (different for the different f()s).

That makes absolutely no difference at all. Throwing an exception is usually
implemented as a function call. That function can inspect the return address
from which it was called. Every instruction address in a program can be
associated with a record of which local variables are located in the stack
frame and registers, which of its caller's registers have been pushed onto
the stack, and where the return address of the calling function is stored
with respect to that stack frame. From that, the entire state each
function's local variables can be recovered all the way back to main.
Recursive functions and array constructions don't foul the scheme at all;
each one has its own frame of local data.**

Since you have apparently not done any research into actual EH
implementations and their theoretical limits, you might consider whether
your insistence that the rest of us don't know what we're talking about is
going to be taken seriously by the community. I have gone out of my way to
explain how this can work, but I don't plan to waste any more time on it
unless you change your tack.

-Dave


**Of course you don't represent this data separately for each instruction,
but you use address ranges and other techniques to compress it.

David Abrahams

unread,
Jun 26, 2002, 7:48:00 PM6/26/02
to

"James Kanze" <ka...@alex.gabi-soft.de> wrote in message
news:86y9d63...@alex.gabi-soft.de...

> "Sergey P. Derevyago" <non-ex...@iobox.com> writes:

> This statement concerns runtime, not code size. It is well known that
> the 0 runtime solutions for exception handling involve some additional
> code.

Or data. Or a combination. It depends on the implementation.

> Which could be called code bloat.

Or simply error-recovery code. What I would call it depends on its size as
compared to alternatives with the same semantics.

-Dave

Alexander Terekhov

unread,
Jun 27, 2002, 11:56:54 AM6/27/02
to

David Abrahams wrote:
[...]

> Since you have apparently not done any research into actual EH
> implementations and their theoretical limits, [...ego trip...]

I've done some research. Here is a few bits that make me think
that some folks indeed don't know what they are talking about:

http://www.codesourcery.com/cxx-abi/abi-eh.html

"....
As a consequence, it is not necessary for each personality
routine to know about any of the possible external agents
that may cause an unwind. For instance, the C++ personality
routine need deal only with C++ exceptions (and possibly
disguising foreign exceptions), but it does not need to
know anything specific about unwinding done on behalf of
longjmp or pthreads cancellation.
....
_UA_FORCE_UNWIND

During phase 2, indicates that no language is allowed to
"catch" the exception. This flag is set while unwinding
the stack for longjmp or during thread cancellation. User-
defined code in a catch clause may still be executed, but
the catch clause must resume unwinding with a call to
_Unwind_Resume when finished. ...."

Also, I'm still awaiting some answer to a couple of 'questions'
[misconceptions (AFAICT/IMNSHO)] hinted, for example, here:

http://groups.google.com/groups?selm=3CF802FB.98E837E9%40web.de

Mr. Abrahams, you might also want to reply something ["From
investing a few seconds reading your post I can't see what
question it is that you want answered, sorry" would by perfectly
OLL KORRECT here as well; 'be ahead'] to the following rather
old posting of mine:

http://groups.google.com/groups?selm=3C77AFCB.481D2587%40web.de
(Subject: Re: Guru of the Week #82: Solution)

regards,
alexander.

--
"....Still, people love the illusion of being able to "handle"
memory problems, and complain when they're not allowed to fool
themselves. ;-)" -- Bute...@c.p.t.

David Abrahams

unread,
Jun 27, 2002, 4:46:26 PM6/27/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:3D1AEFEE...@web.de...

>
> David Abrahams wrote:
> [...]
> > Since you have apparently not done any research into actual EH
> > implementations and their theoretical limits, [...ego trip...]
^^^^^^^^
This sort of ad-hominem remark is out of place. Sprinkling your posts with
this sort of attack doesn't help to make them any more credible.

> I've done some research. Here is a few bits that make me think
> that some folks indeed don't know what they are talking about:
>
> http://www.codesourcery.com/cxx-abi/abi-eh.html

<snip quoted section>

I don't see what the quote has to do with anything being discussed. I know
it's your policy to make people work to figure out what you're referring to,
but I guess I just don't have the time. If you'd care to explain its
relevance, I'll do my best to attempt an answer.

> Also, I'm still awaiting some answer to a couple of 'questions'
> [misconceptions (AFAICT/IMNSHO)] hinted, for example, here:
>
> http://groups.google.com/groups?selm=3CF802FB.98E837E9%40web.de

I looked there. I don't see any questions to answer, other than "or am I
wrong, folks?" at the end. Honestly, your writing style is hard for me to
decipher that I can't form an opinion on that question... so I'll give you
the benefit of the doubt, I guess.

> Mr. Abrahams, you might also want to reply something ["From
> investing a few seconds reading your post I can't see what
> question it is that you want answered, sorry" would by perfectly
> OLL KORRECT here as well; 'be ahead']

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Once again, you're speaking a language I can't understand. Plain english
helps.

> to the following rather
> old posting of mine:
>
> http://groups.google.com/groups?selm=3C77AFCB.481D2587%40web.de
> (Subject: Re: Guru of the Week #82: Solution)

So I followed that link; as with most of your posts it seems somewhat
cryptic to me. All I can tell from it is that you think certain things in
the standard are "SILLY" and/or "BUSTED", that you want me to fix them, and
you don't feel the money you spent on your copy of the standard was worth
it. The things you don't like are rather vaguely described. I guess I
shouldn't be surprised that someone wants me to not only fix something in
the standard but also to invest the time to understand some vaguely-worded
description of what the supposed problem is and to invent a solution, but
you've been around here a while and had the process explained to you several
times so I am surprised to see it coming from you.

Finally, if I take my best guess as to what you're complaining about in the
standard, I have much bigger fish to fry for C++0X. EH is mostly pretty
well-specified in the standard IMO. BTW I had nothing to do with the core
language definition of EH; only understanding how to use it and apply it to
the library specification.

-Dave

Sergey P. Derevyago

unread,
Jun 28, 2002, 4:38:31 PM6/28/02
to
David Abrahams wrote:
> > Compiler doesn't know here whether A::A() (conditionally) calls f() so it
> > has to code for the "worst possible" case. I.e. it must be prepared for
> > the f()->A::A()->f()->A::A()->... chain of calls, where each f() has
> > costructed some part of the array (different for the different f()s).
> That makes absolutely no difference at all.
You're not right. This special case imposes certain constraints on calling
conversions and makes some optimizations impossible.
And, in particular, it proves that the only value of PC is not sufficient to
track the already created local objects (which hurts table-driven EH
implementations).

> Throwing an exception is usually
> implemented as a function call. That function can inspect the return address
> from which it was called. Every instruction address in a program can be
> associated with a record of which local variables are located in the stack
> frame and registers, which of its caller's registers have been pushed onto
> the stack, and where the return address of the calling function is stored
> with respect to that stack frame. From that, the entire state each
> function's local variables can be recovered all the way back to main.
> Recursive functions and array constructions don't foul the scheme at all;

Yes, "_the_ scheme". Do you really think that _this_ scheme is the most
optimal scheme when EH is disabled?

> each one has its own frame of local data.**

--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

Sergey P. Derevyago

unread,
Jun 28, 2002, 4:38:35 PM6/28/02
to
Ian McCulloch wrote:
> >> Obviously, the code generated for the exception handler has to know
> >> how to find this number (which is more likely in a register than on
> >> the stack).
> > No, it will find it in memory, usually in stack frame.
> Whether exception handling is used or not, a loop variable is needed to
> initialize the array, and whether exception handling is used or not if the
> constructor is not inlined the loop variable will need to be saved
> somewhere (ie the stack) for the call.
Not, really. If the callee doesn't change the register in question then its
value need not to be saved.
And such optimizations ("light" stack frames and/or calling convertions) for
_certain_ functions can significantly improve the quality of code.

> What is different about the exception handling case?

The presence of EH makes some of these optimizations impossible.


--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

Sergey P. Derevyago

unread,
Jun 28, 2002, 4:38:53 PM6/28/02
to
Sean Parent wrote:
> > No, it can not: compiler can't keep the number of already created objects in
> > a register only. Consider the following code:
> You appear to making assumptions about the machine architecture and runtime.
> Under IBM Power (and PowerPC) ABI the caller would reserve space
^^^^^ Does it point that the
caller has another ways? Can it be that without EH a compiler (on PowerPC) can
choose more optimal calling conversion?

> on the
> stack for any routine being called to flush registers but doesn't flush on
> the call. The routine being called dumps registers into the reserved frame
> if it uses them.

What does it mean "The routine being called ... uses them"? Consider the
following code:

void f()
{
g();
}

Does f() "use them"? In principle, the only job of f() is to call g(), which
can use the register in question. So must f() flush the register (while g()
flushes it anyway)?

> In this way if A::A() is trivial, there is no overhead and
> the index can stay in a register.
--

With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

David Abrahams

unread,
Jun 28, 2002, 5:44:16 PM6/28/02
to

"Sergey P. Derevyago" <non-ex...@iobox.com> wrote in message
news:3D1CB91C...@iobox.com...

> David Abrahams wrote:
> > > Compiler doesn't know here whether A::A() (conditionally) calls f() so
it
> > > has to code for the "worst possible" case. I.e. it must be prepared
for
> > > the f()->A::A()->f()->A::A()->... chain of calls, where each f() has
> > > costructed some part of the array (different for the different f()s).
> > That makes absolutely no difference at all.

> You're not right. This special case imposes certain constraints on calling
> conversions

"Calling conversion" is not a term I'm familiar with.
Do you perhaps mean "calling convention"?
If so, what constraints do you imagine that it imposes?

> and makes some optimizations impossible.

Please demonstrate an otherwise-allowable optimization which can't be done
if EH info is generated in this case.

> And, in particular, it proves that the only value of PC is not sufficient
to
> track the already created local objects (which hurts table-driven EH
> implementations).

Nobody claimed the PC was sufficient. You also need the entire contents of
the stack and registers.

> > Throwing an exception is usually
> > implemented as a function call. That function can inspect the return
address
> > from which it was called. Every instruction address in a program can be
> > associated with a record of which local variables are located in the
stack
> > frame and registers, which of its caller's registers have been pushed
onto
> > the stack, and where the return address of the calling function is
stored
> > with respect to that stack frame. From that, the entire state each
> > function's local variables can be recovered all the way back to main.
> > Recursive functions and array constructions don't foul the scheme at
all;

> Yes, "_the_ scheme". Do you really think that _this_ scheme is the most
> optimal scheme when EH is disabled?

The scheme doesn't describe anything which affects code generation, so in
that sense, yes, I do. BTW, I acknowledge that error-recovery may in some
cases require the preservation of information which could have been
discarded if errors were to be ignored. That will occasionally exert some
extra register pressure on the optimizer. However, that "overhead" is
associated with *any* form of error-recovery (not just EH) and it doesn't
even occur in the cases you're bringing up.

-Dave

Sergey P. Derevyago

unread,
Jun 28, 2002, 5:43:57 PM6/28/02
to
James Kanze wrote:
> I saw them. I still don't see where there is a problem.
The point is that without EH compiler can use "light" stack frames and/or
calling convertions for certain functions.

> > > Obviously, the code generated for the exception handler has to
> > > know how to find this number (which is more likely in a register
> > > than on the stack).
> > No, it will find it in memory, usually in stack frame.
> Implementation dependant. With g++ 3.1 for Sparc under Solaris 2.8,
> compiled with -O3, the address of the element being constructed is in
> register i0, the number of elements yet to be constructed in register
> l1. The exception handling routine that gets generated knows this.

Could you please translate (using your g++ 3.1 for Sparc) the following code:
-----------------------------------8<-----------------------------------
// b.cpp

struct A {
A();
~A();
};

void g();

void f()
{
A a[10];
g();
}
-----------------------------------8<-----------------------------------

with and without EH:
g++ -O3 -fno-sjlj-exceptions -S -c b.cpp
g++ -O3 -fno-exceptions -S -c b.cpp
and post the result (assembly code of f() for the both cases). We'll get some
data to talk about :)
BTW the similar output from Sun CC "with zero run-time penalty" is also very
interesting to look at (I think we'll discover some run-time penalty anyway).

PS I'd like to see the highest possible opt. level, so fill free to add any
other opt. flags.


--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

---

David Abrahams

unread,
Jun 28, 2002, 9:20:42 PM6/28/02
to

"Sergey P. Derevyago" <non-ex...@iobox.com> wrote in message
news:3D1CC5E2...@iobox.com...

> Could you please translate (using your g++ 3.1 for Sparc) the following
code:
> -----------------------------------8<-----------------------------------
> // b.cpp
>
> struct A {
> A();
> ~A();
> };
>
> void g();
>
> void f()
> {
> A a[10];
> g();
> }
> -----------------------------------8<-----------------------------------
> with and without EH:
> g++ -O3 -fno-sjlj-exceptions -S -c b.cpp

^^^^^^^^^^^^^^^^^^^^
Illegal with gcc 3.1; there are never sjlj-exceptions.

> g++ -O3 -fno-exceptions -S -c b.cpp
> and post the result (assembly code of f() for the both cases). We'll get
some
> data to talk about :)

Given what I saw when I did this on x86 Linux, I don't think the Sun case
will generate much discussion. The code for the non-exception path is nearly
identical, with the only differences I can see being that different
registers are used and a few instructions are re-ordered before the
array-initialization loop. Of course, there are a lot more labels in the
first case; they surely slow the code down a lot <0.001 wink>.

I'd post the results, but of course they don't prove anything. You can still
claim that the second case could have been optimized more, just as I would
claim that the first case was needlessly pessimized if it turned out the
other way. I'm certain that if you look hard enough, you can find a case
where GCC 3.1 makes you pay in execution speed for having EH enabled, even
in the non-exception path.** Optimization reorganizes lots of data, and not
having to keep track of where all of it ends up for EH can make the job of
writing an optimizer easier. Real compiler implementors have to make
real-world trade-offs, but it doesn't affect what's possible in theory.

-Dave

P.S. It's time for you to do some of the legwork in this argument. Repeated
insistence that other people are wrong just doesn't amount to holding up
your end of the work. If you are going to continue to claim there's a
problem with the statements in the draft TR, please provide evidence, with a
full explanation and a detailed description.

**I'm also certain that you can easily manufacture cases which run faster
with EH than with alternative error-handling schemes (e.g. using error
codes).

Sergey P. Derevyago

unread,
Jul 1, 2002, 12:52:38 PM7/1/02
to
David Abrahams wrote:
> > > > Compiler doesn't know here whether A::A() (conditionally) calls f() so
> > > > it has to code for the "worst possible" case. I.e. it must be
> > > > prepared for the f()->A::A()->f()->A::A()->... chain of calls, where
> > > > each f() has costructed some part of the array (different for the
> > > > different f()s).
> > > >
> > > That makes absolutely no difference at all.
>
> > You're not right. This special case imposes certain constraints on calling
> > conversions
>
> "Calling conversion" is not a term I'm familiar with.
> Do you perhaps mean "calling convention"?
Yes, I did (sorry).

> If so, what constraints do you imagine that it imposes?

If A::A()->...->A::A()->... recursion is not allowed (for arrays of A), you
don't have to put the number of already created objects in every stack frame
(associated with A::A()) and table-driven EH becomes near perfect.

> > and makes some optimizations impossible.
>
> Please demonstrate an otherwise-allowable optimization which can't be done
> if EH info is generated in this case.

In principle, some stack frames can be omitted or significantly reduced (e.g.
void f() { g(); } ).

> > And, in particular, it proves that the only value of PC is not sufficient
> > to track the already created local objects (which hurts table-driven EH
> > implementations).
>
> Nobody claimed the PC was sufficient.

Did you read the top of this thread?
-----------------------------------8<-----------------------------------


Lets take a look at page 31 of the TR:

2.4.1.2 The "Table approach"
Typical implementations using the static approach will generate read-only
tables for determines the current execution context, locating catch clauses,
and tracking objects needing destruction.

It should be noted, that the read-only data is _not_ sufficient to
track the objects in question. [...]
-----------------------------------8<-----------------------------------

> You also need the entire contents of the stack and registers.

Not, really: we don't need the values of (BTW did you mean _all_?) registers
but certain values associated with certain C++ constructs (i.e. arrays of
UTD). In other cases the stack + r/o PC tables seem to be sufficient.

> > > Recursive functions and array constructions don't foul the scheme at
> > > all;
>
> > Yes, "_the_ scheme". Do you really think that _this_ scheme is the most
> > optimal scheme when EH is disabled?
>
> The scheme doesn't describe anything which affects code generation, so in
> that sense, yes, I do.

In the absence of EH you don't even need stack frames (for certain functions)
not only the values of (all) registers in these stack frames. So ...

> BTW, I acknowledge that error-recovery may in some
> cases require the preservation of information which could have been
> discarded if errors were to be ignored.

Yes, that's the point.


--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

Alexander Terekhov

unread,
Jul 1, 2002, 6:12:37 PM7/1/02
to

David Abrahams wrote:
[...]

> > I've done some research. Here is a few bits that make me think
> > that some folks indeed don't know what they are talking about:
> >
> > http://www.codesourcery.com/cxx-abi/abi-eh.html
>
> <snip quoted section>

<resurrect quoted text>

"....
As a consequence, it is not necessary for each personality
routine to know about any of the possible external agents
that may cause an unwind. For instance, the C++ personality
routine need deal only with C++ exceptions (and possibly
disguising foreign exceptions), but it does not need to
know anything specific about unwinding done on behalf of
longjmp or pthreads cancellation.
....
_UA_FORCE_UNWIND

During phase 2, indicates that no language is allowed to
"catch" the exception. This flag is set while unwinding
the stack for longjmp or during thread cancellation. User-
defined code in a catch clause may still be executed, but
the catch clause must resume unwinding with a call to
_Unwind_Resume when finished. ...."

Oh, BTW, you can find almost the same stuff in the following
*official* document [part of one recent and already rather
{in}famous probably-multi-billion grand project]:

ftp://download.intel.com/design/Itanium/Downloads/24537003.pdf

< for example >

"....
A catch-all block may be executed during unwinding. For instance,
longjmp may execute code in catch(...) during stack unwinding.
However, if this happens, unwinding will proceed at the end of
catch-all block, whether or not there is an explicit rethrow.
...."

> I don't see what the quote has to do with anything being discussed.

It has NOTHING to do with anything being discussed in this thread
thus far [in the sense of "EH do involve certain run-time penalty"
point raised by ders-at-skeptik.net in his original posting and/or
the one you've replied to].

> I know
> it's your policy to make people work to figure out what you're referring to,
> but I guess I just don't have the time. If you'd care to explain its
> relevance, I'll do my best to attempt an answer.

Explanation [relevance w.r.t. C++ exceptions 'model']:

A) longjmp and C++ exceptions:

The standard says: "The function signature longjmp(jmp_buf jbuf, int val)
has more restricted behavior in this International Standard. If any automatic
objects would be destroyed by a thrown exception transferring control to
another (destination) point in the program, then a call to longjmp( jbuf, val)
at the throw point that transfers control to the same (destination) point has
undefined behavior.

Now, of course, any implementation MAY define whatever behavior it wants for
everything left undefined in the standard [portability aside]... however,
unwinding via-an-exception-that-simply-can't-be-finally-caught ["no language
is allowed to 'catch'"] doesn't really work in C++, AFAICS; please see the
next (B)-item below;

B) "it does not need to know anything specific about unwinding
done on behalf of longjmp or pthreads cancellation":

Well, one problem {among couple of others} is that C++ language has
'a catch thing' with three dots in it:

try{/**/}/**/catch(...){/**/}

Now, "User-defined code in a catch clause may still be executed,

but the catch clause must resume unwinding with a call to

_Unwind_Resume when finished. " is basically nothing but
'auto_rethrow_exception' and 'catch(...)' illustrated here
[transformations of 'legal-throws' into 'now-suddenly-colliding-
throws' plus Ex.Specs 'fencing' aside, for a moment]:

http://lists.boost.org/MailArchives/boost/msg23046.php

It simply doesn't work, unless I'm just missing something...
then I apologize in advance for the noise.

> > Also, I'm still awaiting some answer to a couple of 'questions'
> > [misconceptions (AFAICT/IMNSHO)] hinted, for example, here:
> >
> > http://groups.google.com/groups?selm=3CF802FB.98E837E9%40web.de
>
> I looked there. I don't see any questions to answer, other than "or am I
> wrong, folks?" at the end.

Well, another question was [w/o corresponding question mark, though ;-) ]:

---
[1] http://groups.google.com/groups?selm=c29b5e33.0202161451.2ef75f1f%40posting.google.com

"Herb Sutter <hsu...@acm.org> wrote in message
news:<jtas6uggftq6lt2o3...@4ax.com>...
[...]
> Yes, but you can have the nothrow guarantee whether the exception
> specification says so or not. In fact, I usually write declarations for such
> functions like this: "X f( Y ) // throw()".

And who is protecting your clients from really bad
things (exceptions/faults) along the lines of:

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51_HTML/ARH9RBTE/DOCU0011.HTM#excep_defs
...."

< NO answer from Mr. Sutter... yet.. here is @ *MICROSOFT* now, BTW >
---

> Honestly, your writing style is hard for me to
> decipher that I can't form an opinion on that question... so I'll give you
> the benefit of the doubt, I guess.

Thanks.

> > Mr. Abrahams, you might also want to reply something ["From
> > investing a few seconds reading your post I can't see what
> > question it is that you want answered, sorry" would by perfectly
> > OLL KORRECT here as well; 'be ahead']
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> Once again, you're speaking a language I can't understand.

'OLL KORRECT' -> 'okay';
'be ahead' -> 'to be winning or in a superior position'.

> Plain english helps.

http://www.m-w.com [and alike; I have a local replica] helps as well.

> > to the following rather
> > old posting of mine:
> >
> > http://groups.google.com/groups?selm=3C77AFCB.481D2587%40web.de
> > (Subject: Re: Guru of the Week #82: Solution)

[...]


> BTW I had nothing to do with the core language definition of EH;

Does anyone know who invented these

- implementation-defined -> "If no matching handler is found in
a program, the function terminate() is called; whether or not
the stack is unwound*** before this call to terminate() is
implementation-defined (15.5.1)", "In the situation where no
matching handler is found, it is implementation-defined whether
or not the stack is unwound before terminate() is called.".

- Ex.Specs. -> "catch(...) { std::unexpected(); }"-stack-unwound

just-wonderful-things? I'll then provide some details
['plain english' including] in a private e-mail... TIA.

regards,
alexander.

[***] Uhmm. Y'know, given the definitions of:

"The process of calling destructors for automatic objects
constructed on the path from a try block to a throw-expression
^^^^^^^^^
is called 'stack unwinding.'"
^^^^^^^^^^^^^^^

"tryblock: try compound-statement handler-seq

function-try-block: try ctor-initializer-opt function-body handler-seq

<snip>

A try-block is a statement (clause 6). .... [Note: within
this clause "try block" is taken to mean both try-block
and function-try-block.]

I just wonder >>WHAT 'try block'<< [according to clause 6]
is actually meant here:

int main() {
object o; // <-- 'unwinding' is implementation-defined
throw "trouble";
}

and here:

void Main() throw() {
object o; // <-- 'unwinding' seems to be REQUIRED here
throw "trouble";
}

I personally don't see any 'try-block' statements here...
which would make 'unwinding' LEGAL {in my view}, to begin
with [whether-or-not-it-actually-makes-sense-here is a
somewhat different topic, I guess...].

David Abrahams

unread,
Jul 1, 2002, 6:13:34 PM7/1/02
to

"Sergey P. Derevyago" <non-ex...@iobox.com> wrote in message
news:3D1F4099...@iobox.com...

> > If so, what constraints do you imagine that it imposes?
> If A::A()->...->A::A()->... recursion is not allowed (for arrays of A),
you
> don't have to put the number of already created objects in every stack
frame
> (associated with A::A()) and table-driven EH becomes near perfect.

You already don't. The example code you posted, when compiled by GCC 3.1,
keeps the number of already-created objects in a register. Any called
function that wants to use that register has to put it on the stack, so it
may end up on the stack eventually... but that's irrelevant.

> > > and makes some optimizations impossible.
> >
> > Please demonstrate an otherwise-allowable optimization which can't be
done
> > if EH info is generated in this case.
> In principle, some stack frames can be omitted or significantly reduced
(e.g.
> void f() { g(); } ).

You seem to have a rigid notion of what constitutes a stack frame. Even if I
adopt that definition of "frame", table-driven EH does not have to interfere
with the ommission or reduction of stack frames.

> > > And, in particular, it proves that the only value of PC is not
sufficient
> > > to track the already created local objects (which hurts table-driven
EH
> > > implementations).
> >
> > Nobody claimed the PC was sufficient.
> Did you read the top of this thread?

Yeah.

> -----------------------------------8<-----------------------------------
> Lets take a look at page 31 of the TR:
>
> 2.4.1.2 The "Table approach"
> Typical implementations using the static approach will generate read-only
> tables for determines the current execution context, locating catch
clauses,
> and tracking objects needing destruction.
>
> It should be noted, that the read-only data is _not_ sufficient to
> track the objects in question. [...]
> -----------------------------------8<-----------------------------------

I don't see any implication that the PC was sufficient. I still say that
nobody has claimed it was.

> > You also need the entire contents of the stack and registers.
> Not, really: we don't need the values of (BTW did you mean _all_?)
registers

Yes, I meant all, in the general case. And of course you need the values of
registers, unless you're willing to inhibit optimizations. Some of the
important information may be located in registers... like, for example, the
number of already-initialized objects in an array.

> but certain values associated with certain C++ constructs (i.e. arrays of
> UTD). In other cases the stack + r/o PC tables seem to be sufficient.

You put way too much trust in your own perception of what's sufficient.

> > The scheme doesn't describe anything which affects code generation, so
in
> > that sense, yes, I do.
> In the absence of EH you don't even need stack frames (for certain
functions)

Nor do you need "stack frames" for those functions with EH on. I'm sure you
could prove that to yourself by compiling some code with and without EH
using GCC 3.1.

> not only the values of (all) registers in these stack frames. So ...
> > BTW, I acknowledge that error-recovery may in some
> > cases require the preservation of information which could have been
> > discarded if errors were to be ignored.
> Yes, that's the point.

Sure, those cases arise only when:

1. You explicitly write a try/catch block
2. You write an exception-specification

In all the other cases, error-recovery consists of running destructors of
UDTs. The compiler wasn't free to discard the information needed to run
those destructors, since they have to run even if we turn off EH. So, in the
absence of try/catch blocks or exception-specifications (which you can't
compile anyway with EH turned off), the compiler can generate code
equivalent to the no-EH case.

And now, I'm done with this futile argument. I'm sure you can build a GCC
3.1 for your favorite platform, to look at what it can and cannot do. Run
some tests. If you find a case that generates suboptimal code with EH
enabled, and you can't see a way that the compiler could have done better
without disabling EH, *then* we might have something to talk about.

-Dave

David Abrahams

unread,
Jul 1, 2002, 7:12:26 PM7/1/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:3D205A8A...@web.de...

> > I don't see what the quote has to do with anything being discussed.
>
> It has NOTHING to do with anything being discussed in this thread
> thus far [in the sense of "EH do involve certain run-time penalty"
> point raised by ders-at-skeptik.net in his original posting and/or
> the one you've replied to].

It's a huge help to know that.

First, I think you should make it clear that you're discussing a particular
ABI specification and not just the C++ standard. This ABI corresponds to a
set of particular C++ implementations. I'm not sure whether you're drawing
the right conclusions about "No language is allowed to 'catch'" here, but I
haven't read the ABI spec. Is it possible that catch clauses are prohibited
from stopping the unwinding process, but that unwinding will stop, e.g.,
when it reaches setjmp?

> next (B)-item below;
>
> B) "it does not need to know anything specific about unwinding
> done on behalf of longjmp or pthreads cancellation":
>
> Well, one problem {among couple of others} is that C++ language has
> 'a catch thing' with three dots in it:
>
> try{/**/}/**/catch(...){/**/}
>
> Now, "User-defined code in a catch clause may still be executed,
> but the catch clause must resume unwinding with a call to
> _Unwind_Resume when finished. " is basically nothing but
> 'auto_rethrow_exception'

Yes, I think you've interpreted that correctly.

> and 'catch(...)' illustrated here
> [transformations of 'legal-throws' into 'now-suddenly-colliding-
> throws'

I don't know what you mean by that. Are you saying that a
non-type-preserving rethrow from a catch clause is outlawed by this ABI
specification if a pthreads cancellation or a longjmp passes through it?

> plus Ex.Specs 'fencing' aside, for a moment]:

Again, it's very unclear what you mean.

> http://lists.boost.org/MailArchives/boost/msg23046.php
>
> It simply doesn't work, unless I'm just missing something...
> then I apologize in advance for the noise.

Well, I'm not really sure what you think doesn't work about it, but it does
seem to me (from what I understand of it) that the ABI specification you're
referring to is problematic. It seems as though it would have similar issues
to good-ol-Win32 structured exceptions.

> > I looked there. I don't see any questions to answer, other than "or am I
> > wrong, folks?" at the end.
>
> Well, another question was [w/o corresponding question mark, though ;-) ]:

You actually got me to read that entire post thinking that there was an
unanswered question for me in there, but it was just a red herring?!? I am
*such* a sucker! That's the last time I'm going to try to help you out!

> ---
> [1]
http://groups.google.com/groups?selm=c29b5e33.0202161451.2ef75f1f%40posting.


google.com
>
> "Herb Sutter <hsu...@acm.org> wrote in message
> news:<jtas6uggftq6lt2o3...@4ax.com>...
> [...]
> > Yes, but you can have the nothrow guarantee whether the exception
> > specification says so or not. In fact, I usually write declarations for
such
> > functions like this: "X f( Y ) // throw()".
>
> And who is protecting your clients from really bad
> things (exceptions/faults) along the lines of:
>
>
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51_HTML/ARH9RBT
E/DOCU0011.HTM#excep_defs
> ...."
>
> < NO answer from Mr. Sutter... yet.. here is @ *MICROSOFT* now, BTW >

Yes, I was just visiting with him there.

I don't know what Herb's answer would be, but IMO it's not really possible
to protect anyone from most "really bad things", except by carefully coding
to avoid them. If you have better ideas about this, I guess the world would
love to know them.

> > Once again, you're speaking a language I can't understand.
>
> 'OLL KORRECT' -> 'okay';
> 'be ahead' -> 'to be winning or in a superior position'.
>
> > Plain english helps.
>
> http://www.m-w.com [and alike; I have a local replica] helps as well.

Is "oll korrect" in there?

-Dave

Alexander Terekhov

unread,
Jul 3, 2002, 1:12:10 PM7/3/02
to

David Abrahams wrote:
[...]

> First, I think you should make it clear that you're discussing a particular
> ABI specification and not just the C++ standard.

Both; C++ standard stuff: a) implementation-defined propagation to
'nowhere' of uncaught exceptions and b) *required* propagation of
*unexpected* [ex.specs.-wise] exceptions way up to the [sort of]
catch(...) handler of [sort-of] function-try-block *implicitly*
added to each and every function with ex.specs... unless compiler
can prove somehow [a rather interesting job given the existence
(>>in real life<<; NOT in the current version of the C++ standard)
of things like "pthread_stackovf_e -- attempted stack overflow was
detected"] that no exception could ever be trapped by that implicit
catch(...)-in-the-function-try-block, AFAICS.

> This ABI corresponds to a
> set of particular C++ implementations. I'm not sure whether you're drawing
> the right conclusions about "No language is allowed to 'catch'" here, but I
> haven't read the ABI spec. Is it possible that catch clauses are prohibited
> from stopping the unwinding process, but that unwinding will stop, e.g.,
> when it reaches setjmp?

Yes, I think so. Basically, the idea [a rather foolish idea, in my
opinion] is to have "nonlocal GOTO in a multilanguage environment"
that would cause FORCED unwinding [way up to the destination point]
that no one is supposed/allowed to 'intercept'. Well, that's how
thread cancelation works in POSIX... but that's pure C... even w/o
exceptions macros! ;-) I think that in C++, one could either declare
that cancel shall always be re-thrown ['undefined behavior' otherwise],
or, probably even better, allow the 'finalization' of cancel exceptions
in the 'user code' with {implicit, maybe} re-activation of thread
cancelability [it should be disabled while the cancel process/unwinding
running].

[...]


> I don't know what you mean by that. Are you saying that a
> non-type-preserving rethrow from a catch clause is outlawed by this ABI
> specification if a pthreads cancellation or a longjmp passes through it?

Uhmm. AFAICT, catch(...) [during forced unwinding] can't throw anything
other than 're-throw' ["throw;"]. According to my understanding of this
ABI, in the presence of its 'pthreads' cancellation or a 'longjmps', all
catch(...) handlers degenerate suddenly to sort-of function-try-block-
catch(...) handlers, but that a) can't translate anything since neither
cancelation nor 'jumps' can be caught, and b) can't throw anything else
[other than "throw;"] since that would result in *multiple* exceptions
all flying together... I don't think that folks really wanted to have
something like that. Here's the quotes:

"....
A runtime is not allowed to catch an exception if the _UA_FORCE_UNWIND
flag was passed to the personality routine.

Example: Foreign Exceptions in C++. In C++, foreign exceptions can be
caught by a catch(...) statement. They can also be caught as if they
were of a __foreign_exception class, defined in <exception>. The
__foreign_exception may have subclasses, such as __java_exception and
__ada_exception, if the runtime is capable of identifying some of the
foreign languages.

The behavior is undefined in the following cases:

A __foreign_exception catch argument is accessed in any way
(including taking its address).

A __foreign_exception is active at the same time as another
exception (either there is a nested exception while catching
the foreign exception, or the foreign exception was itself
nested).

uncaught_exception(), set_terminate(), set_unexpected(),
terminate(), or unexpected() is called at a time a foreign
exception exists (for example, calling set_terminate() during
unwinding of a foreign exception).

All these cases might involve accessing C++ specific content
of the thrown exception, for instance to chain active exceptions.

Otherwise, a catch block catching a foreign exception is allowed:

to resume normal execution, thereby stopping propagation of
the foreign exception and deleting it, or

to rethrow the foreign exception. In that case, the original
exception object must be unaltered by the C++ runtime.

A catch-all block may be executed during forced unwinding. For
instance, a longjmp may execute code in a catch(...) during stack

unwinding. However, if this happens, unwinding will proceed at

the end of the catch-all block, whether or not there is an explicit
rethrow.

...."

"....
_Unwind_ForcedUnwind

typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
(int version,
_Unwind_Action actions,
uint64 exceptionClass,
struct _Unwind_Exception *exceptionObject,
struct _Unwind_Context *context,
void *stop_parameter );

_Unwind_Reason_Code _Unwind_ForcedUnwind
( struct _Unwind_Exception *exception_object,
_Unwind_Stop_Fn stop,
void *stop_parameter );

Raise an exception for forced unwinding, passing along the
given exception object, which should have its exception_class
and exception_cleanup fields set. The exception object has been
allocated by the language-specific runtime, and has a language-
specific format, except that it must contain an _Unwind_Exception
struct (see Exception Header above).

Forced unwinding is a single-phase process (phase 2 of the normal
exception-handling process). The stop and stop_parameter parameters
control the termination of the unwind process, instead of the usual
personality routine query. The stop function parameter is called for
each unwind frame, with the parameters described for the usual
personality routine below, plus an additional stop_parameter.

When the stop function identifies the destination frame, it transfers
control (according to its own, unspecified, conventions) to the user
code as appropriate without returning, normally after calling
_Unwind_DeleteException. If not, it should return an
_Unwind_Reason_Code value as follows:

_URC_NO_REASON: This is not the destination frame. The unwind
runtime will call the frame's personality routine with the
_UA_FORCE_UNWIND and _UA_CLEANUP_PHASE flags set in actions,
and then unwind to the next frame and call the stop function
again.

_URC_END_OF_STACK: In order to allow _Unwind_ForcedUnwind to
perform special processing when it reaches the end of the stack,
the unwind runtime will call it after the last frame is rejected,
with a NULL stack pointer in the context, and the stop function
must catch this condition (i.e. by noticing the NULL stack pointer).
It may return this reason code if it cannot handle end-of-stack.

_URC_FATAL_PHASE2_ERROR: The stop function may return this code
for other fatal conditions, e.g. stack corruption.

If the stop function returns any reason code other than _URC_NO_REASON,
the stack state is indeterminate from the point of view of the caller
of _Unwind_ForcedUnwind. Rather than attempt to return, therefore, the
unwind library should return _URC_FATAL_PHASE2_ERROR to its caller.

Example: longjmp_unwind()

The expected implementation of longjmp_unwind() is as follows.
The setjmp() routine will have saved the state to be restored
in its customary place, including the frame pointer. The
longjmp_unwind() routine will call _Unwind_ForcedUnwind with
a stop function that compares the frame pointer in the context
record with the saved frame pointer. If equal, it will restore
the setjmp() state as customary, and otherwise it will return
_URC_NO_REASON or _URC_END_OF_STACK.

...."

> > plus Ex.Specs 'fencing' aside, for a moment]:
>
> Again, it's very unclear what you mean.

See "The behavior is undefined in the following cases" above.

[...]


> I don't know what Herb's answer would be, but IMO it's not really possible
> to protect anyone from most "really bad things", except by carefully coding
> to avoid them. If you have better ideas about this, I guess the world would
> love to know them.

Well, with "protection" I meant something that would prevent the
propagation [out of throw() routines, to begin with] of anything
raised [and left 'unhandled' or re-raised] due to "really bad
things" or whatever.

IOW, I believe strongly that a) TWO-PHASE exception processing
shall be declared MANDATORY[1] by the C++ standards committee
and b) exception specifications shall be revised/fixed so that
they shall NOT require unneeded/harmful unwinding on ex.specs.
violation [way up to that implicit 'catch(...)' handler that's
meant to invoke std::unexpected(); that should better be done
>>AT THROW POINT<< in the next version of C++, IMNSHO].

[...]


> > http://www.m-w.com [and alike; I have a local replica] helps as well.
>
> Is "oll korrect" in there?

Yep [indirectly, though]:

< from site referenced above >

"....
3 entries found for OK.
To select an entry, click on it.
OK[1,adverb or adjective]OK[2,noun]OK[3,transitive verb]

Main Entry: 1OK
Variant(s): or okay /O-'kA, in assenting or agreeing also 'O-"kA/
Function: adverb or adjective
Etymology: abbreviation of oll korrect, facetious alteration of all correct
^^^^^^^^^^^
Date: 1839
: ALL RIGHT"

;-)

regards,
alexander.

[1] Yes, [presuming that it's doable] that would add to the run-time
overhead of all those archaic setjmp/longjmp 'C-macro' exceptions;
but heck... 'big deal'.

0 new messages