This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: throw(), pure and const flags on functions


> Gabriel Dos Reis wrote:
> 
> > Well, the reason I'm pointing this out is that there are
> > influencial people in the C++ community who make claims
> > tthat 'throw()' is to be discouraged because it makes compilers
> > generate worse code.  You are claiming to the opposite, that is
> > why the issue is so important.
> 
> That's because it depends on where you use throw().
> 
> If you write:
> 
>   extern void f();
>   void g() throw() {
>     f();
>   }
> 
> the "throw()" on "g" probably makes "g" bigger (and/or slower, depending
> on how your compiler implements exceptions).  That's because the
> compiler has to turn "g" into something like:
> 
>   void g() {
>     try {
>       f();
>     } catch (...) {
>       std::unexpected();
>     }
>   }

I was actually looking into this problem earlier this month too.  We
expand it into the form above in C++ frontend. However when the
exception is not delivered locally (i.e.  we don't see nested EH region
like:
   void g() {
     try {
       {
         f();
       }
       cleanup {....}
     } catch (...) {
       std::unexpected();
     }
   }
Where cleanup contains RESX that compile to direct goto to the basic
block containing std::terminate() call) We use MUST_NOT_THROW region
that is handled by runtime, therefore the wrapper becomes quite cheap
adding just little of EH space.  It should be monotonously smaller than
the EH then.

I found out that on tramp this is very common scenario.  The constructs
are not comming from throw () keyword, but from the fact that standard
require throwing destructor in implicit cleanup at the end of block to
lead to terminate as well and we tend to have a lot of cleanups and
ontained must not throws expanding code size quite a bit.

I added EH cleanup pass that is able to detect cleanups that are
completely empty (and there are many of them after inlining
representative destructors) and remove them.  Removing the inner empty
cleanups subsequently leads to elimination of that std::terminate() call
too.

There is still room for improvement, since after inlining we can end up
with several terminate calls in single function (in tramp it is about
60).  Crossjumping can take care of them at cost of messed up backtrace.

Also this is only argument on why the throws that can be derrived from
fact that function body present in other compilation unit calls only
functions not throwing ought to be explicitly marked in header.  Doing
so will prevent people from being disapointed that adding throw()
markers bloats code size when the inner functions are mistakely believed
to throw.

Honza


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]