diff options
author | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 1997-04-23 20:04:25 +0000 |
---|---|---|
committer | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 1997-04-23 20:04:25 +0000 |
commit | 694ec51983be9bfc22d051e98e22e185c6b00651 (patch) | |
tree | ed1bd25525ef36f94c97fb911c74203e02095a25 /gcc/libgcc2.c | |
parent | c446d93c756b52b25588a6816d1728f4852d2068 (diff) | |
download | gcc-694ec51983be9bfc22d051e98e22e185c6b00651.tar.gz |
Add setjmp/longjmp exception handling.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@13968 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/libgcc2.c')
-rw-r--r-- | gcc/libgcc2.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 338707029ce..725161865dd 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -3102,6 +3102,172 @@ EH_TABLE_LOOKUP #else +void +__default_terminate () +{ + abort (); +} + +void (*__terminate_func)() = __default_terminate; + +void +__terminate () +{ + (*__terminate_func)(); +} + +/* Calls to __sjthrow are generated by the compiler when an exception + is raised when using the setjmp/longjmp exception handling codegen + method. */ + +extern longjmp (void *, int); + +extern void *__eh_type; + +static void *top_elt[2]; +void **__dynamic_handler_chain = top_elt; + +/* Routine to get the head of the current thread's dynamic handler chain + use for exception handling. + + TODO: make thread safe. */ + +void *** +__get_dynamic_handler_chain () +{ + return &__dynamic_handler_chain; +} + +/* This is used to throw an exception when the setjmp/longjmp codegen + method is used for exception handling. + + We call __terminate if there are no handlers left (we know this + when the dynamic handler chain is top_elt). Otherwise we run the + cleanup actions off the dynamic cleanup stack, and pop the top of + the dynamic handler chain, and use longjmp to transfer back to the + associated handler. */ + +void +__sjthrow () +{ + void ***dhc = __get_dynamic_handler_chain (); + void *jmpbuf; + void (*func)(void *, int); + void *arg; + void ***cleanup; + + /* The cleanup chain is one word into the buffer. Get the cleanup + chain. */ + cleanup = (void***)&(*dhc)[1]; + + /* If there are any cleanups in the chain, run them now. */ + if (cleanup[0]) + { + double store[200]; + void **buf = (void**)store; + buf[1] = 0; + buf[0] = (*dhc); + + /* try { */ + if (! setjmp (&buf[2])) + { + *dhc = buf; + while (cleanup[0]) + { + func = (void(*)(void*, int))cleanup[0][1]; + arg = (void*)cleanup[0][2]; + + /* Update this before running the cleanup. */ + cleanup[0] = (void **)cleanup[0][0]; + + (*func)(arg, 2); + } + *dhc = buf[0]; + } + /* catch (...) */ + else + { + __terminate (); + } + } + + /* We must call terminate if we try and rethrow an exception, when + there is no exception currently active and when there are no + handlers left. */ + if (! __eh_type || (*dhc) == top_elt) + __terminate (); + + /* Find the jmpbuf associated with the top element of the dynamic + handler chain. The jumpbuf starts two words into the buffer. */ + jmpbuf = &(*dhc)[2]; + + /* Then we pop the top element off the dynamic handler chain. */ + *dhc = (void**)(*dhc)[0]; + + /* And then we jump to the handler. */ + +#ifdef USE_BUILTIN_SETJMP + __builtin_longjmp (jmpbuf, 1); +#else + longjmp (jmpbuf, 1); +#endif +} + +/* Run cleanups on the dynamic cleanup stack for the current dynamic + handler, then pop the handler off the dynamic handler stack, and + then throw. This is used to skip the first handler, and transfer + control to the next handler in the dynamic handler stack. */ + +void +__sjpopnthrow () +{ + void ***dhc = __get_dynamic_handler_chain (); + void *jmpbuf; + void (*func)(void *, int); + void *arg; + void ***cleanup; + + /* The cleanup chain is one word into the buffer. Get the cleanup + chain. */ + cleanup = (void***)&(*dhc)[1]; + + /* If there are any cleanups in the chain, run them now. */ + if (cleanup[0]) + { + double store[200]; + void **buf = (void**)store; + buf[1] = 0; + buf[0] = (*dhc); + + /* try { */ + if (! setjmp (&buf[2])) + { + *dhc = buf; + while (cleanup[0]) + { + func = (void(*)(void*, int))cleanup[0][1]; + arg = (void*)cleanup[0][2]; + + /* Update this before running the cleanup. */ + cleanup[0] = (void **)cleanup[0][0]; + + (*func)(arg, 2); + } + *dhc = buf[0]; + } + /* catch (...) */ + else + { + __terminate (); + } + } + + /* Then we pop the top element off the dynamic handler chain. */ + *dhc = (void**)(*dhc)[0]; + + __sjthrow (); +} + typedef struct { void *start; void *end; |