diff options
author | Ian Lance Taylor <iant@google.com> | 2016-11-22 17:58:04 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-11-22 17:58:04 +0000 |
commit | 9d1e3afb5484c71eaaea23fc3a4b86fe35418d43 (patch) | |
tree | 2110ef75ee2708c685482ea2ace4dfbf1461d4aa /libgo/runtime/go-unwind.c | |
parent | 6c7509bc070b29293ca9874518b89227ce05361c (diff) | |
download | gcc-9d1e3afb5484c71eaaea23fc3a4b86fe35418d43.zip gcc-9d1e3afb5484c71eaaea23fc3a4b86fe35418d43.tar.gz gcc-9d1e3afb5484c71eaaea23fc3a4b86fe35418d43.tar.bz2 |
runtime: rewrite panic/defer code from C to Go
The actual stack unwind code is still in C, but the rest of the code,
notably all the memory allocation, is now in Go. The names are changed
to the names used in the Go 1.7 runtime, but the code is necessarily
somewhat different.
The __go_makefunc_can_recover function is dropped, as the uses of it
were removed in https://golang.org/cl/198770044.
Reviewed-on: https://go-review.googlesource.com/33414
From-SVN: r242715
Diffstat (limited to 'libgo/runtime/go-unwind.c')
-rw-r--r-- | libgo/runtime/go-unwind.c | 142 |
1 files changed, 36 insertions, 106 deletions
diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c index fb59115..9e85b4b 100644 --- a/libgo/runtime/go-unwind.c +++ b/libgo/runtime/go-unwind.c @@ -15,7 +15,6 @@ #include "runtime.h" #include "go-alloc.h" -#include "go-panic.h" /* The code for a Go exception. */ @@ -34,110 +33,16 @@ static const _Unwind_Exception_Class __go_exception_class = << 8 | (_Unwind_Exception_Class) '\0'); #endif +/* Rethrow an exception. */ -/* This function is called by exception handlers used when unwinding - the stack after a recovered panic. The exception handler looks - like this: - __go_check_defer (frame); - return; - If we have not yet reached the frame we are looking for, we - continue unwinding. */ +void rethrowException (void) __asm__(GOSYM_PREFIX "runtime.rethrowException"); void -__go_check_defer (_Bool *frame) +rethrowException () { - G *g; struct _Unwind_Exception *hdr; - g = runtime_g (); - - if (g == NULL) - { - /* Some other language has thrown an exception. We know there - are no defer handlers, so there is nothing to do. */ - } - else if (g->isforeign) - { - Panic *n; - _Bool recovered; - - /* Some other language has thrown an exception. We need to run - the local defer handlers. If they call recover, we stop - unwinding the stack here. */ - - n = (Panic *) __go_alloc (sizeof (Panic)); - - n->arg._type = NULL; - n->arg.data = NULL; - n->recovered = 0; - n->isforeign = 1; - n->next = g->_panic; - g->_panic = n; - - while (1) - { - Defer *d; - void (*pfn) (void *); - - d = g->_defer; - if (d == NULL || d->frame != frame || d->pfn == 0) - break; - - pfn = (void (*) (void *)) d->pfn; - g->_defer = d->next; - - (*pfn) (d->arg); - - if (runtime_m () != NULL) - runtime_freedefer (d); - - if (n->recovered) - { - /* The recover function caught the panic thrown by some - other language. */ - break; - } - } - - recovered = n->recovered; - g->_panic = n->next; - __go_free (n); - - if (recovered) - { - /* Just return and continue executing Go code. */ - *frame = 1; - return; - } - - /* We are panicing through this function. */ - *frame = 0; - } - else if (g->_defer != NULL - && g->_defer->pfn == 0 - && g->_defer->frame == frame) - { - Defer *d; - - /* This is the defer function which called recover. Simply - return to stop the stack unwind, and let the Go code continue - to execute. */ - d = g->_defer; - g->_defer = d->next; - - if (runtime_m () != NULL) - runtime_freedefer (d); - - /* We are returning from this function. */ - *frame = 1; - - return; - } - - /* This is some other defer function. It was already run by the - call to panic, or just above. Rethrow the exception. */ - - hdr = (struct _Unwind_Exception *) g->exception; + hdr = (struct _Unwind_Exception *) runtime_g()->exception; #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_Resume_or_Rethrow (hdr); @@ -153,23 +58,48 @@ __go_check_defer (_Bool *frame) abort(); } -/* Unwind function calls until we reach the one which used a defer - function which called recover. Each function which uses a defer - statement will have an exception handler, as shown above. */ +/* Return the size of the type that holds an exception header, so that + it can be allocated by Go code. */ + +uintptr unwindExceptionSize(void) + __asm__ (GOSYM_PREFIX "runtime.unwindExceptionSize"); + +uintptr +unwindExceptionSize () +{ + uintptr ret, align; + + ret = sizeof (struct _Unwind_Exception); + /* Adjust the size fo make sure that we can get an aligned value. */ + align = __alignof__ (struct _Unwind_Exception); + if (align > __alignof__ (uintptr)) + ret += align - __alignof__ (uintptr); + return ret; +} + +/* Throw an exception. This is called with g->exception pointing to + an uninitialized _Unwind_Exception instance. */ + +void throwException (void) __asm__(GOSYM_PREFIX "runtime.throwException"); void -__go_unwind_stack () +throwException () { struct _Unwind_Exception *hdr; + uintptr align; + + hdr = (struct _Unwind_Exception *)runtime_g ()->exception; + /* Make sure the value is correctly aligned. It will be large + enough, because of unwindExceptionSize. */ + align = __alignof__ (struct _Unwind_Exception); hdr = ((struct _Unwind_Exception *) - __go_alloc (sizeof (struct _Unwind_Exception))); + (((uintptr) hdr + align - 1) &~ (align - 1))); + __builtin_memcpy (&hdr->exception_class, &__go_exception_class, sizeof hdr->exception_class); hdr->exception_cleanup = NULL; - runtime_g ()->exception = hdr; - #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_RaiseException (hdr); #else |