diff options
author | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-06-06 16:38:49 +0000 |
---|---|---|
committer | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-06-06 16:38:49 +0000 |
commit | d3e1375a3557529dff71be71bf0449f94918e27c (patch) | |
tree | cd362ecde7373e378f1d9a95a1254c3695dd5541 /gcc/libgcc2.c | |
parent | 67bb7b2d71cbf6bd6c793aa68fa76b6760bb53a7 (diff) | |
download | gcc-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.c | 69 |
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 |