summaryrefslogtreecommitdiff
path: root/gcc/libgcc2.c
diff options
context:
space:
mode:
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2000-06-06 16:38:49 +0000
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2000-06-06 16:38:49 +0000
commitd3e1375a3557529dff71be71bf0449f94918e27c (patch)
treecd362ecde7373e378f1d9a95a1254c3695dd5541 /gcc/libgcc2.c
parent67bb7b2d71cbf6bd6c793aa68fa76b6760bb53a7 (diff)
downloadgcc-d3e1375a3557529dff71be71bf0449f94918e27c.tar.gz
gcc:
* 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. gcc/cp: * exception.cc: (__eh_alloc, __eh_free): Moved to libgcc2.c git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@34429 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/libgcc2.c')
-rw-r--r--gcc/libgcc2.c69
1 files changed, 69 insertions, 0 deletions
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