Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index


On Mon, 2012-03-05 at 15:29 +0000, Michael Meeks wrote:
On Fri, 2012-03-02 at 17:16 +0000, Caolán McNamara wrote:
At the most banal level, I suspect that:

      struct Empty { int unused; };
      Empty *p = new Empty();
      delete p;

      can't legitimately be optimised away if we have a throwing constructor,
but of course I can dig out some compiler people who know what they're
on about here.

In the general case presumably you then need to run around sticking
throw()/nothrow onto loads of things in order to tell the compiler that
stuff isn't going to throw exceptions, and/or disabling exceptions to
get the compiler to do something different.

Amusingly, for the trivial example

#include <new>
void foo()
{
        struct Empty { int unused; };
#ifdef TESTNOTHROW
        Empty *p = new(std::nothrow) Empty();
#else
        Empty *p = new Empty();
#endif
        delete p;
}

and pure .o size.
g++ -O2 -DTESTNOTHROW -c test.cxx gives a 1060byte .o
while
g++ -O2 -c test.cxx gives a 996 byte .o
and
g++ -O2 -fno-exceptions -c test.cxx
gives a 996 byte .o as well. Doesn't appear to be the case that gcc
optimizes out the call to new regardless of what optimization level or
-fno-exceptions that might let it know it could do it if it wanted.

      Consistently calling std::abort() somewhere rather than waiting for a
SEGV sounds fine, though preferably not in-lined into many tens if not
hundreds of thousands of duplicate compare/branch/call-function sides at
every object construction.

Looking at std::abort vs std::throw for new, assuming something is built
with -fexceptions, and once there's *something* in a function called
that might throw an exception I *guess* you pay a fixed penalty and it
doesn't really matter how many things in that function might throw
something ?, that's the way I internalized it anyway.

Anyway, FWIW I'm not massively interested in the allocate, "oh we don't
have enough, lets try and release some" unrealistic path, just the load
binary file format scenario of
int32_t foo = read_foo();
new Foo[foo] where foo is approx MAX_SIZE, and new should immediately
throws without even making any effort to allocate, given that the number
to allocate would overflow and the .wmf/.doc or whatever import is
aborted with a toplevel import-level catch without the app exiting. If
we didn't have a single-process-app none of this would matter much I
suppose.

      I guess I now need to go and characterise how much of the saving is
from removing tens of thousands of in-lined 'if (baa) throw
std::bad_alloc();' calls vs. the exception unwind and knock-on optimiser
impact of having all that there.

hmm, initially I would have said that the savings must all be from the
removal of the inlining of the "check for NULL and throw itself" given
that the compiler can only see the body of rtl_uString2String when
building one object file and not for any of the others, but I see now
that rtl_uString2String is marked as nothrow so the compiler could make
use of that I guess.

C.


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.