summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/exception.cc27
-rw-r--r--gcc/eh-common.h18
-rw-r--r--gcc/libgcc2.c69
5 files changed, 105 insertions, 23 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7a6fcc9cc71..3f24d77affd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2000-06-06 Nathan Sidwell <nathan@codesourcery.com>
+
+ * eh-common.h (EH_ALLOC_SIZE, EH_ALLOC_ALIGN): New #defines.
+ (eh_context): Add alloc_mask and alloc_buffer emergency fallback
+ space.
+ * libgcc2.c (__eh_alloc): Moved from cp/exception.cc. Fallback on
+ emergency eh_context buffer, if malloc fails.
+ (__eh_free): Moved from cp/exception.cc. Release to emergency
+ eh_context buffer, if appropriate.
+
2000-06-06 Jason Merrill <jason@casey.soma.redhat.com>
* expr.c (store_expr): Fix typo.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 949f4c8cf0d..198ff67c02a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,7 @@
+2000-06-06 Nathan Sidwell <nathan@codesourcery.com>
+
+ * exception.cc: (__eh_alloc, __eh_free): Moved to libgcc2.c
+
2000-06-05 Jason Merrill <jason@casey.soma.redhat.com>
* search.c (maybe_suppress_debug_info): Don't check
diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc
index 9263bfeaa01..1ffd7624a09 100644
--- a/gcc/cp/exception.cc
+++ b/gcc/cp/exception.cc
@@ -118,6 +118,10 @@ struct cp_eh_info
extern "C" cp_eh_info **__get_eh_info (); // actually void **
+/* Exception allocate and free, defined in libgcc2. */
+extern "C" void *__eh_alloc(size_t);
+extern "C" void __eh_free();
+
/* Is P the type_info node for a pointer of some kind? */
extern bool __is_pointer (void *);
@@ -159,29 +163,6 @@ __start_cp_handler (void)
return p;
}
-/* Allocate a buffer for a cp_eh_info and an exception object of size SIZE,
- and return a pointer to the beginning of the object's space. */
-
-extern "C" void * malloc (size_t);
-extern "C" void *
-__eh_alloc (size_t size)
-{
- void *p = malloc (size);
- if (p == 0)
- terminate ();
- return p;
-}
-
-/* Free the memory for an cp_eh_info and associated exception, given
- a pointer to the cp_eh_info. */
-
-extern "C" void free (void *);
-extern "C" void
-__eh_free (void *p)
-{
- free (p);
-}
-
extern "C" int __throw_type_match_rtti_2 (const void *, const void *,
void *, void **);
diff --git a/gcc/eh-common.h b/gcc/eh-common.h
index 20adfd613f0..5303d6db474 100644
--- a/gcc/eh-common.h
+++ b/gcc/eh-common.h
@@ -39,6 +39,20 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
The routine get_dynamic_handler_chain() also has a dependancy on
the location of 'dynamic_handler_chain'. If its location is changed,
that routine must be modified as well. */
+#ifndef EH_ALLOC_SIZE
+/* 192 bytes means the entire eh_context plus malloc overhead fits in 256
+ bytes (assuming 8 byte pointers). 192 bytes gives an eh_info and object
+ size limit of 96 bytes. This should be sufficient for throwing bad_alloc. */
+#define EH_ALLOC_SIZE 192
+#endif
+#ifndef EH_ALLOC_ALIGN
+/* We can't use BIGGEST_ALIGNMENT, because on some systems, that expands to
+ a check on a compile time switch like
+ 'target_flags & MASK_ALIGN_DOUBLE ? 64 : 32'. There's no macro for
+ 'largest alignment for any code this compiler can build for', which is
+ really what is needed. */
+#define EH_ALLOC_ALIGN 16
+#endif
struct eh_context
{
@@ -48,6 +62,10 @@ struct eh_context
void *info;
/* This is used to remember where we threw for re-throws */
void *table_index; /* address of exception table entry to rethrow from */
+ /* emergency fallback space, if malloc fails during handling */
+ char alloc_buffer[EH_ALLOC_SIZE]
+ __attribute__((__aligned__(EH_ALLOC_ALIGN)));
+ unsigned alloc_mask;
};
#ifndef EH_TABLE_LOOKUP
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c
index 822d84e0851..305d7f085d5 100644
--- a/gcc/libgcc2.c
+++ b/gcc/libgcc2.c
@@ -3190,6 +3190,75 @@ eh_context_specific (void)
}
#endif /* __GTHREADS */
+/* Support routines for alloc/free during exception handling */
+
+/* __eh_alloc and __eh_free attempt allocation using malloc, but fall back to
+ the small arena in the eh_context. This is needed because throwing an
+ out-of-memory exception would fail otherwise. The emergency space is
+ allocated in blocks of size EH_ALLOC_ALIGN, the
+ minimum allocation being two blocks. A bitmask indicates which blocks
+ have been allocated. To indicate the size of an allocation, the bit for
+ the final block is not set. Hence each allocation is a run of 1s followed
+ by a zero. */
+void *
+__eh_alloc (size_t size)
+{
+ void *p;
+
+ if (!size)
+ abort();
+ p = malloc (size);
+ if (p == 0)
+ {
+ struct eh_context *eh = __get_eh_context ();
+ unsigned blocks = (size + EH_ALLOC_ALIGN - 1) / EH_ALLOC_ALIGN;
+ unsigned real_mask = eh->alloc_mask | (eh->alloc_mask << 1);
+ unsigned our_mask;
+ unsigned ix;
+
+ if (blocks > EH_ALLOC_SIZE / EH_ALLOC_ALIGN)
+ __terminate ();
+ blocks += blocks == 1;
+ our_mask = (1 << blocks) - 1;
+
+ for (ix = EH_ALLOC_SIZE / EH_ALLOC_ALIGN - blocks; ix; ix--)
+ if (! ((real_mask >> ix) & our_mask))
+ {
+ /* found some space */
+ p = &eh->alloc_buffer[ix * EH_ALLOC_ALIGN];
+ eh->alloc_mask |= (our_mask >> 1) << ix;
+ return p;
+ }
+ __terminate ();
+ }
+ return p;
+}
+
+/* Free the memory for an cp_eh_info and associated exception, given
+ a pointer to the cp_eh_info. */
+void
+__eh_free (void *p)
+{
+ struct eh_context *eh = __get_eh_context ();
+
+ ptrdiff_t diff = (char *)p - &eh->alloc_buffer[0];
+ if (diff >= 0 && diff < EH_ALLOC_SIZE)
+ {
+ unsigned mask = eh->alloc_mask;
+ unsigned bit = 1 << (diff / EH_ALLOC_ALIGN);
+
+ do
+ {
+ mask ^= bit;
+ bit <<= 1;
+ }
+ while (mask & bit);
+ eh->alloc_mask = mask;
+ }
+ else
+ free (p);
+}
+
/* Support routines for setjmp/longjmp exception handling. */
/* Calls to __sjthrow are generated by the compiler when an exception