Re: Reducing the size of C++ executables - eliminating malloc

2006-11-13 Thread Michael Eager

Olivier Galibert wrote:

On Sun, Nov 12, 2006 at 02:46:58PM -0800, Michael Eager wrote:

It would seem that the place to require the personality
routine would be in the routine which causes the stack
unwinding, not in every C++ object file, whether needed
or not.


Doesn't that otherwise very valid point of view break when you
remember that new can throw exceptions?


Folks who want to reduce the size of executables (e.g.,
embedded systems developers) know to avoid including
malloc by using either static or stack allocation
rather than using new.

--
Michael Eager[EMAIL PROTECTED]
1960 Park Blvd., Palo Alto, CA 94306  650-325-8077


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-13 Thread Olivier Galibert
On Sun, Nov 12, 2006 at 02:46:58PM -0800, Michael Eager wrote:
> It would seem that the place to require the personality
> routine would be in the routine which causes the stack
> unwinding, not in every C++ object file, whether needed
> or not.

Doesn't that otherwise very valid point of view break when you
remember that new can throw exceptions?

  OG.


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread jschopp

> GCC 4.1.1 for PowerPC generates a 162K executable for a
> minimal program  "int main() { return 0; }".  GCC 3.4.1
> generated a 7.2K executable.  Mark Mitchell mentioned the
> same problem for ARM and proposed a patch to remove the
> reference to malloc in atexit
> (http://sourceware.org/ml/newlib/2006/msg00181.html).

We've seen this on cell spu as well. And with only 256K total memory it was a really big 
deal for us.  Our minimal program dropped from 10566 bytes to 2822 bytes (text + data + 
bss) with the attached completely unacceptable for merging patch.  We were thinking that 
our platform has no need for more than 32 atexit handlers, and the proper solution is to 
make the code removed in the attached patch simply #ifdefed away for platforms like ours 
that are happy with 32 atexit handlers and are short on space.  This seems to be the 
approach in the patch you linked to.


-Joel
Index: newlib-1.14.0/newlib/libc/stdlib/__atexit.c
===
--- newlib-1.14.0.orig/newlib/libc/stdlib/__atexit.c
+++ newlib-1.14.0/newlib/libc/stdlib/__atexit.c
@@ -9,6 +9,7 @@
 #include "atexit.h"
 
 
+
 /*
  * Register a function to be performed at exit or on shared library unload.
  */
@@ -24,6 +25,10 @@ _DEFUN (__register_exitproc,
   struct _on_exit_args * args;
   register struct _atexit *p;
 
+#ifdef _REENT_SMALL
+  static struct _on_exit_args myargs;
+#endif
+
 #ifndef __SINGLE_THREAD__
   __LOCK_INIT(static, lock);
 
@@ -35,21 +40,10 @@ _DEFUN (__register_exitproc,
 _GLOBAL_REENT->_atexit = p = &_GLOBAL_REENT->_atexit0;
   if (p->_ind >= _ATEXIT_SIZE)
 {
-  p = (struct _atexit *) malloc (sizeof *p);
-  if (p == NULL)
-	{
 #ifndef __SINGLE_THREAD__
 	  __lock_release(lock);
 #endif
 	  return -1;
-	}
-  p->_ind = 0;
-  p->_next = _GLOBAL_REENT->_atexit;
-  _GLOBAL_REENT->_atexit = p;
-#ifndef _REENT_SMALL
-  p->_on_exit_args._fntypes = 0;
-  p->_on_exit_args._is_cxa = 0;
-#endif
 }
 
   if (type != __et_atexit)
@@ -58,7 +52,8 @@ _DEFUN (__register_exitproc,
   args = p->_on_exit_args_ptr;
   if (args == NULL)
 	{
-	  args = malloc (sizeof * p->_on_exit_args_ptr);
+/* 	  args = malloc (sizeof * p->_on_exit_args_ptr); */
+	  args = myargs;
 	  if (args == NULL)
 	{
 #ifndef __SINGLE_THREAD__
Index: newlib-1.14.0/newlib/libc/stdlib/__call_atexit.c
===
--- newlib-1.14.0.orig/newlib/libc/stdlib/__call_atexit.c
+++ newlib-1.14.0/newlib/libc/stdlib/__call_atexit.c
@@ -68,10 +68,10 @@ _DEFUN (__call_exitprocs, (code, d),
 	  /* Remove empty block from the list.  */
 	  *lastp = p->_next;
 #ifdef _REENT_SMALL
-	  if (args)
-	free (args);
+/* 	  if (args) */
+/* 	free (args); */
 #endif
-	  free (p);
+/* 	  free (p); */
 	  p = *lastp;
 	}
   else


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Mark Mitchell
Daniel Jacobowitz wrote:
> On Sun, Nov 12, 2006 at 05:11:39PM -0800, Mark Mitchell wrote:
>> Daniel Jacobowitz wrote:
>>
>>> If you try what Michael's been saying, you'll notice that trivial
>>> C++ files get the personality routine reference even if they don't
>>> have anything with a destructor which would need cleaning up.  We ought
>>> to be able to emit (somewhat smaller) unwind information which doesn't
>>> reference the personality routine if it's going to have nothing to do,
>>> shouldn't we?
>> Certainly, there are at least some such cases.  I guess a function whose
>> only callees (if any) are no-throw functions, and which itself does not
>> use "throw", does not need frame information.
> 
> You've talked right past me, since I wasn't saying that...

Well, for something like:

  int g() throw();
  int f(int a) {
return g() + a;
  }

I don't think you ever have to unwind through "f".  Exceptions are not
allowed to leave "g", and nothing in "f" can throw, so as far as the EH
systems is concerned, "f" doesn't even exist.  I think we could just
drop its frame info on the floor.  This might be a relatively
significant size improvement.

>> Unless the entire program doesn't
>> contain anything that needs cleaning up, we'll still need it in the
>> final executable,
> 
> Right.  So if you use local variables with destructors, even though you
> don't use exceptions, you'll get the personality routine.  The linker
> could straighten that out if we taught it to, though.

Correct.  It could notice that, globally, no throw-exception routines
(i.e., __cxa_throw, and equivalents for other languages) were included
and then discard the personality routine -- and, maybe, all of
.eh_frame.  You'd still have the cleanup code in function bodies,
though, so if you really want minimum size, you still have to compile
with -fno-exceptions.

-- 
Mark Mitchell
CodeSourcery
[EMAIL PROTECTED]
(650) 331-3385 x713


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Daniel Jacobowitz
On Sun, Nov 12, 2006 at 05:11:39PM -0800, Mark Mitchell wrote:
> Daniel Jacobowitz wrote:
> 
> > If you try what Michael's been saying, you'll notice that trivial
> > C++ files get the personality routine reference even if they don't
> > have anything with a destructor which would need cleaning up.  We ought
> > to be able to emit (somewhat smaller) unwind information which doesn't
> > reference the personality routine if it's going to have nothing to do,
> > shouldn't we?
> 
> Certainly, there are at least some such cases.  I guess a function whose
> only callees (if any) are no-throw functions, and which itself does not
> use "throw", does not need frame information.

You've talked right past me, since I wasn't saying that...

> However, I think you and Michael are right: we don't need to reference
> the personality routine here.

... but this.

> Unless the entire program doesn't
> contain anything that needs cleaning up, we'll still need it in the
> final executable,

Right.  So if you use local variables with destructors, even though you
don't use exceptions, you'll get the personality routine.  The linker
could straighten that out if we taught it to, though.

-- 
Daniel Jacobowitz
CodeSourcery


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Daniel Jacobowitz
On Mon, Nov 13, 2006 at 01:03:10AM +, Paul Brook wrote:
> > C++ files get the personality routine reference even if they don't
> > have anything with a destructor which would need cleaning up.  We ought
> > to be able to emit (somewhat smaller) unwind information which doesn't
> > reference the personality routine if it's going to have nothing to do,
> > shouldn't we?
> 
> Ah, ok, sorry. ARM unwinding works a bit differently, and you always need a 
> personality routine.

Right - which is why it was such a headache for us, isn't amenable to
_Unwind_Backtrace / _Unwind_ForcedUnwind, et cetera.  For .eh_frame,
though, the personality routine is only necessary to run cleanups
and check exception specs.

-- 
Daniel Jacobowitz
CodeSourcery


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Mark Mitchell
Daniel Jacobowitz wrote:

> If you try what Michael's been saying, you'll notice that trivial
> C++ files get the personality routine reference even if they don't
> have anything with a destructor which would need cleaning up.  We ought
> to be able to emit (somewhat smaller) unwind information which doesn't
> reference the personality routine if it's going to have nothing to do,
> shouldn't we?

Certainly, there are at least some such cases.  I guess a function whose
only callees (if any) are no-throw functions, and which itself does not
use "throw", does not need frame information.

But, for something like:

  extern void f();
  void g() {
f(); f();
  }

we do need unwind information, even though "g" has nothing to do with
exceptions.

However, I think you and Michael are right: we don't need to reference
the personality routine here.   Unless the entire program doesn't
contain anything that needs cleaning up, we'll still need it in the
final executable, but omitting it would make our object files smaller,
and unwinding a little faster, since we don't call personality routines
that aren't there.

-- 
Mark Mitchell
CodeSourcery
[EMAIL PROTECTED]
(650) 331-3385 x713


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Paul Brook
On Monday 13 November 2006 00:53, Daniel Jacobowitz wrote:
> On Sun, Nov 12, 2006 at 11:17:14PM +, Paul Brook wrote:
> > The code being unwound through (ie. with frame data) needs to be able to
> > say "I need routine X if __Unwind_Raise is used anywhere in this
> > program". I'm not aware of any way of doing this, other than trying it
> > and starting again if you guessed wrong.
>
> Again, IIRC ARM's linker does something clever here.  Of course the ABI
> in use there is somewhat different, but I suspect it could be adapted.

Probably.  I don't think the ABI differences are relevant here.

> On Sun, Nov 12, 2006 at 03:20:48PM -0800, Mark Mitchell wrote:
> > But, the way the ABI works requires a reference from each unit which may
> > cause unwinding.  Even if you lose the personality routine, you will
> > still have the exception tables, which themselves are a significant
> > cost.  If you don't want to pay for exceptions, you really have to
> > compile with -fno-exceptions.  In that case, certainly, we should be
> > able to avoid pulling in the personality routine.
>
> If you try what Michael's been saying, you'll notice that trivial
> C++ files get the personality routine reference even if they don't
> have anything with a destructor which would need cleaning up.  We ought
> to be able to emit (somewhat smaller) unwind information which doesn't
> reference the personality routine if it's going to have nothing to do,
> shouldn't we?

Ah, ok, sorry. ARM unwinding works a bit differently, and you always need a 
personality routine.

Paul


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Daniel Jacobowitz
On Sun, Nov 12, 2006 at 11:17:14PM +, Paul Brook wrote:
> The code being unwound through (ie. with frame data) needs to be able to 
> say "I need routine X if __Unwind_Raise is used anywhere in this program".
> I'm not aware of any way of doing this, other than trying it and starting 
> again if you guessed wrong.

Again, IIRC ARM's linker does something clever here.  Of course the ABI
in use there is somewhat different, but I suspect it could be adapted.

On Sun, Nov 12, 2006 at 03:20:48PM -0800, Mark Mitchell wrote:
> But, the way the ABI works requires a reference from each unit which may
> cause unwinding.  Even if you lose the personality routine, you will
> still have the exception tables, which themselves are a significant
> cost.  If you don't want to pay for exceptions, you really have to
> compile with -fno-exceptions.  In that case, certainly, we should be
> able to avoid pulling in the personality routine.

If you try what Michael's been saying, you'll notice that trivial
C++ files get the personality routine reference even if they don't
have anything with a destructor which would need cleaning up.  We ought
to be able to emit (somewhat smaller) unwind information which doesn't
reference the personality routine if it's going to have nothing to do,
shouldn't we?

-- 
Daniel Jacobowitz
CodeSourcery


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Michael Eager

Mark Mitchell wrote:

But, the way the ABI works requires a reference from each unit which may
cause unwinding.  Even if you lose the personality routine, you will
still have the exception tables, which themselves are a significant
cost.  If you don't want to pay for exceptions, you really have to
compile with -fno-exceptions.  In that case, certainly, we should be
able to avoid pulling in the personality routine.


I think that we are actually in agreement, for the most part.
The routines which need unwinding should have a reference to
the personality module.  Routines which don't need unwinding
shouldn't have a superfluous reference to it.

There is a check in doing_eh() in except.c which checks that
-fexceptions is set if any exception-specific functions are
used.  It seems that this would be the place to generate the
reference to __gxx_personality_v0.

--
Michael Eager[EMAIL PROTECTED]
1960 Park Blvd., Palo Alto, CA 94306  650-325-8077


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Mark Mitchell
Michael Eager wrote:
> Mark Mitchell wrote:
>> Michael Eager wrote:
>>> Why should the personality routine be included in all C++ programs?
>>
>> Because all non-trivial, exceptions-enabled programs, may need to do
>> stack unwinding.
> 
> It would seem that the place to require the personality
> routine would be in the routine which causes the stack
> unwinding, not in every C++ object file, whether needed
> or not.

But, the way the ABI works requires a reference from each unit which may
cause unwinding.  Even if you lose the personality routine, you will
still have the exception tables, which themselves are a significant
cost.  If you don't want to pay for exceptions, you really have to
compile with -fno-exceptions.  In that case, certainly, we should be
able to avoid pulling in the personality routine.

-- 
Mark Mitchell
CodeSourcery
[EMAIL PROTECTED]
(650) 331-3385 x713


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Paul Brook
On Sunday 12 November 2006 22:46, Michael Eager wrote:
> Mark Mitchell wrote:
> > Michael Eager wrote:
> >> Why should the personality routine be included in all C++ programs?
> >
> > Because all non-trivial, exceptions-enabled programs, may need to do
> > stack unwinding.
>
> It would seem that the place to require the personality
> routine would be in the routine which causes the stack
> unwinding, not in every C++ object file, whether needed
> or not.

The problem is that the places that knows we're using exceptions don't know 
how to do the stack unwinding, or what we're unwinding through. Only the code 
being unwound knows how to do the unwinding. 

The frame unwind information contains a function pointer that is called to 
interpret the rest of the frame data. eg. C, C++ and Java all have different 
exception table formats, and different personality routines to interpret 
those tables. The code that calls throw(), and the implementation of thow() 
don't know which of these routines are needed.

The code being unwound through (ie. with frame data) needs to be able to 
say "I need routine X if __Unwind_Raise is used anywhere in this program".
I'm not aware of any way of doing this, other than trying it and starting 
again if you guessed wrong.

Paul


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Michael Eager

Mark Mitchell wrote:

Michael Eager wrote:

Why should the personality routine be included in all C++ programs?


Because all non-trivial, exceptions-enabled programs, may need to do
stack unwinding.


It would seem that the place to require the personality
routine would be in the routine which causes the stack
unwinding, not in every C++ object file, whether needed
or not.

For embedded targets, there are many C++ programs which
are non-trivial and which do not require exception handling.

My thoughts:

1)  Exception support should be included only when used.

2)  The default for -exceptions should be target dependent.

--
Michael Eager[EMAIL PROTECTED]
1960 Park Blvd., Palo Alto, CA 94306  650-325-8077


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Mark Mitchell
Michael Eager wrote:
> Mark Mitchell wrote:
>>> Generating __gxx_personality_v0 is suppressed with the -fno-exceptions
>>> flag, but it would seem better if this symbol were only generated
>>> when catch/throw was used.  This happens in cxx_init_decl_processing(),
>>> which is called before it's known whether or not EH is really needed.
>>
>> I believe that you need the personality routine if you will be unwinding
>> through a function, which is why -fno-exceptions is the test.
> 
> You mean unwinding stack frames to handle a thrown exception?
> 
> That's true, but shouldn't this only be included when there
> exceptions are used?  

No, it must be included if exceptions are enabled, and there are any
objects which might require cleanups, which, in most C++ programs, is
equivalent to there are any objects with a destructor.

> One of the C++ percepts is that there
> is no overhead for features which are not used.

That objective does not hold for space, especially in the presence of
exceptions.

> Why should the personality routine be included in all C++ programs?

Because all non-trivial, exceptions-enabled programs, may need to do
stack unwinding.

-- 
Mark Mitchell
CodeSourcery
[EMAIL PROTECTED]
(650) 331-3385 x713


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Michael Eager

Mark Mitchell wrote:

Generating __gxx_personality_v0 is suppressed with the -fno-exceptions
flag, but it would seem better if this symbol were only generated
when catch/throw was used.  This happens in cxx_init_decl_processing(),
which is called before it's known whether or not EH is really needed.


I believe that you need the personality routine if you will be unwinding
through a function, which is why -fno-exceptions is the test.


You mean unwinding stack frames to handle a thrown exception?

That's true, but shouldn't this only be included when there
exceptions are used?  One of the C++ percepts is that there
is no overhead for features which are not used.

Why should the personality routine be included in all C++ programs?

--
Michael Eager[EMAIL PROTECTED]
1960 Park Blvd., Palo Alto, CA 94306  650-325-8077


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Mark Mitchell
Michael Eager wrote:

> Preallocating space is a good thing, particularly if the size
> can be computed at compile time.  It's a little bit more awkward
> if it has to be calculated at link time.

It's a bit awkward, but it's also one of the clever tricks ARM's
proprietary linker uses, and we should use it too!

> Generating __gxx_personality_v0 is suppressed with the -fno-exceptions
> flag, but it would seem better if this symbol were only generated
> when catch/throw was used.  This happens in cxx_init_decl_processing(),
> which is called before it's known whether or not EH is really needed.

I believe that you need the personality routine if you will be unwinding
through a function, which is why -fno-exceptions is the test.

-- 
Mark Mitchell
CodeSourcery
[EMAIL PROTECTED]
(650) 331-3385 x713


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Michael Eager

Mark Mitchell wrote:

Michael Eager wrote:

GCC 4.1.1 for PowerPC generates a 162K executable for a
minimal program  "int main() { return 0; }".  GCC 3.4.1
generated a 7.2K executable.  Mark Mitchell mentioned the
same problem for ARM and proposed a patch to remove the
reference to malloc in atexit
(http://sourceware.org/ml/newlib/2006/msg00181.html).

There are references to malloc in eh_alloc.c and
unwind-dw2-fde.c.  It looks like these are being
included even when there are no exception handlers.

Any suggestions on how to eliminate the references
to these routines?


These aren't full implementation sketches, but, yes, we can do better.
Here are some ideas:

1. For the DWARF unwind stuff, have the linker work out how much space
is required and pre-allocate it.  The space required is a statically
knowable property of the executable, modulo dynamic linking, and on the
cases where we care most (bare-metal) we don't have to worry about
dynamic linking.  (If you can afford a dynamic linker, you can probably
afford malloc, and it's in a shared library.)

2. For the EH stuff, the maximum size of an exception is also statically
knowable, again assuming no dynamic linking.  The maximum exception
nesting depth (i.e., the number of simultaneously active exceptions) is
not, though.  So, here, what I think you want is a small, statically
allocated stack, at least as big as the biggest exception, out of which
you allocate exception objects.  Happily, we already have this, in the
form of "emergency_buffer" -- although it uses a compile-time estimate
of the biggest object, rather than having the linker fill it in, as
would be ideal.  But, in the no-malloc case, just fall back to the
emergency mode.

You could also declare malloc "weak" in that file, and just not call it
if the value is zero.  That way, if malloc is around, you can use it --
but if it's not, you use the emergency buffer.  Put the emergency_buffer
in a separate file (rather than in eh_alloc.cc), so that users can
provide their own implementation to control the size, overriding the one
in the library.


Preallocating space is a good thing, particularly if the size
can be computed at compile time.  It's a little bit more awkward
if it has to be calculated at link time.

On the other hand, why should either DWARF unwind or the eh_*
files be included if C++ exception handling is not used?

The minimal executable has a reference to __gxx_personality_v0.
This is defined in eh_personality.o, which has a reference to
__cxa_allocate_exception in eh_alloc.o.  So this seems to be the
thread which pulls in all the other pieces.

Generating __gxx_personality_v0 is suppressed with the -fno-exceptions
flag, but it would seem better if this symbol were only generated
when catch/throw was used.  This happens in cxx_init_decl_processing(),
which is called before it's known whether or not EH is really needed.

Any suggestions on how to move this test later?

--
Michael Eager[EMAIL PROTECTED]
1960 Park Blvd., Palo Alto, CA 94306  650-325-8077


Re: Reducing the size of C++ executables - eliminating malloc

2006-11-12 Thread Mark Mitchell
Michael Eager wrote:
> GCC 4.1.1 for PowerPC generates a 162K executable for a
> minimal program  "int main() { return 0; }".  GCC 3.4.1
> generated a 7.2K executable.  Mark Mitchell mentioned the
> same problem for ARM and proposed a patch to remove the
> reference to malloc in atexit
> (http://sourceware.org/ml/newlib/2006/msg00181.html).
> 
> There are references to malloc in eh_alloc.c and
> unwind-dw2-fde.c.  It looks like these are being
> included even when there are no exception handlers.
> 
> Any suggestions on how to eliminate the references
> to these routines?

These aren't full implementation sketches, but, yes, we can do better.
Here are some ideas:

1. For the DWARF unwind stuff, have the linker work out how much space
is required and pre-allocate it.  The space required is a statically
knowable property of the executable, modulo dynamic linking, and on the
cases where we care most (bare-metal) we don't have to worry about
dynamic linking.  (If you can afford a dynamic linker, you can probably
afford malloc, and it's in a shared library.)

2. For the EH stuff, the maximum size of an exception is also statically
knowable, again assuming no dynamic linking.  The maximum exception
nesting depth (i.e., the number of simultaneously active exceptions) is
not, though.  So, here, what I think you want is a small, statically
allocated stack, at least as big as the biggest exception, out of which
you allocate exception objects.  Happily, we already have this, in the
form of "emergency_buffer" -- although it uses a compile-time estimate
of the biggest object, rather than having the linker fill it in, as
would be ideal.  But, in the no-malloc case, just fall back to the
emergency mode.

You could also declare malloc "weak" in that file, and just not call it
if the value is zero.  That way, if malloc is around, you can use it --
but if it's not, you use the emergency buffer.  Put the emergency_buffer
in a separate file (rather than in eh_alloc.cc), so that users can
provide their own implementation to control the size, overriding the one
in the library.

-- 
Mark Mitchell
CodeSourcery
[EMAIL PROTECTED]
(650) 331-3385 x713