From a5974a584702f39174e0744e9647726e92f1a216 Mon Sep 17 00:00:00 2001 From: nicola Date: Wed, 8 Sep 2010 21:03:09 +0000 Subject: [PATCH] * objc/objc-exception.h: New file. * exception.c (objc_set_uncaught_exception_handler): Implemented. (objc_set_exception_matcher): Implemented. (objc_exception_throw): Use the uncaught exception handler if set. (PERSONALITY_FUNCTION): Use the exception matcher instead of the hardcoded isKindOf. (isKindOf): Renamed to is_kind_of_exception_matcher. Tidied code up. Removed segmentation fault when value is 'nil'. * objc/objc-api.h (_objc_unexpected_exception): Mark as deprecated. * Makefile.in (exception.lo, exception_gc.lo): Use -Wno-deprecated-declarations when compiling. (OBJC_H): Added objc-exception.h git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@164023 138bc75d-0d04-0410-961f-82ee72b054a4 --- libobjc/ChangeLog | 16 ++++++ libobjc/Makefile.in | 10 ++-- libobjc/exception.c | 111 ++++++++++++++++++++++++++++----------- libobjc/objc/objc-api.h | 12 +++-- libobjc/objc/objc-exception.h | 117 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 40 deletions(-) create mode 100644 libobjc/objc/objc-exception.h diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index e79318b..f4f8e18 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,3 +1,19 @@ +2010-09-08 Nicola Pero + + * objc/objc-exception.h: New file. + * exception.c (objc_set_uncaught_exception_handler): Implemented. + (objc_set_exception_matcher): Implemented. + (objc_exception_throw): Use the uncaught exception handler if set. + (PERSONALITY_FUNCTION): Use the exception matcher instead of the + hardcoded isKindOf. + (isKindOf): Renamed to is_kind_of_exception_matcher. Tidied code + up. Removed segmentation fault when value is 'nil'. + * objc/objc-api.h (_objc_unexpected_exception): Mark as + deprecated. + * Makefile.in (exception.lo, exception_gc.lo): Use + -Wno-deprecated-declarations when compiling. + (OBJC_H): Added objc-exception.h + 2010-09-08 Nicola Pero * objc/typedstream.h: Deprecate all functions in the file. This diff --git a/libobjc/Makefile.in b/libobjc/Makefile.in index 0a02e0a..d48c8dd 100644 --- a/libobjc/Makefile.in +++ b/libobjc/Makefile.in @@ -143,7 +143,7 @@ all: libobjc$(libsuffix).la $(OBJC_BOEHM_GC) # User-visible header files. -OBJC_H = hash.h objc-list.h sarray.h objc.h objc-api.h \ +OBJC_H = hash.h objc-list.h sarray.h objc.h objc-api.h objc-exception.h \ NXConstStr.h Object.h Protocol.h encoding.h typedstream.h \ thr.h objc-decls.h @@ -152,7 +152,7 @@ OBJC_H = hash.h objc-list.h sarray.h objc.h objc-api.h \ OBJS = archive.lo class.lo encoding.lo gc.lo hash.lo init.lo linking.lo \ misc.lo nil_method.lo NXConstStr.lo Object.lo objects.lo \ Protocol.lo sarray.lo selector.lo sendmsg.lo thr.lo \ - exception.lo + exception.lo OBJS_GC = archive_gc.lo class_gc.lo encoding_gc.lo gc_gc.lo hash_gc.lo \ init_gc.lo linking_gc.lo misc_gc.lo nil_method_gc.lo \ @@ -262,13 +262,15 @@ thr_gc.lo: thr.c $(LIBTOOL_COMPILE) $(CC) -c -o $@ $(ALL_CFLAGS) $(OBJC_GCFLAGS) \ $(INCLUDES) $< +# -Wno-deprecated-declarations is to silence warnings from using +# _objc_unexpected_exception. exception.lo: exception.c $(LIBTOOL_COMPILE) $(CC) -c -o $@ $(ALL_CFLAGS) \ - -fexceptions $(INCLUDES) $< + -fexceptions -Wno-deprecated-declarations $(INCLUDES) $< exception_gc.lo: exception.c $(LIBTOOL_COMPILE) $(CC) -c -o $@ $(ALL_CFLAGS) $(OBJC_GCFLAGS) \ - -fexceptions $(INCLUDES) $< + -fexceptions -Wno-deprecated-declarations $(INCLUDES) $< doc: info dvi pdf html diff --git a/libobjc/exception.c b/libobjc/exception.c index 0ac0b66..210beae 100644 --- a/libobjc/exception.c +++ b/libobjc/exception.c @@ -1,5 +1,5 @@ /* The implementation of exception handling primitives for Objective-C. - Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -25,9 +25,70 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include #include "config.h" #include "objc/objc-api.h" +#include "objc/objc-exception.h" #include "unwind.h" #include "unwind-pe.h" +/* This hook allows libraries to sepecify special actions when an + exception is thrown without a handler in place. This is deprecated + in favour of objc_set_uncaught_exception_handler (). + */ +void (*_objc_unexpected_exception) (id exception); /* !T:SAFE */ + + +/* 'is_kind_of_exception_matcher' is our default exception matcher - + it determines if the object 'exception' is of class 'catch_class', + or of a subclass. +*/ +static int +is_kind_of_exception_matcher (Class catch_class, id exception) +{ + /* NULL catch_class is catch-all (eg, @catch (id object)). */ + if (catch_class == Nil) + return 1; + + /* If exception is nil (eg, @throw nil;), then it can only be catched + * by a catch-all (eg, @catch (id object)). + */ + if (exception != nil) + { + Class c; + + for (c = exception->class_pointer; c != Nil; + c = class_get_super_class (c)) + if (c == catch_class) + return 1; + } + return 0; +} + +/* The exception matcher currently in use. */ +static objc_exception_matcher +__objc_exception_matcher = is_kind_of_exception_matcher; + +objc_exception_matcher +objc_set_exception_matcher (objc_exception_matcher new_matcher) +{ + objc_exception_matcher old_matcher = __objc_exception_matcher; + __objc_exception_matcher = new_matcher; + return old_matcher; +} + +/* The uncaught exception handler currently in use. */ +static objc_uncaught_exception_handler +__objc_uncaught_exception_handler = NULL; + +objc_uncaught_exception_handler +objc_set_uncaught_exception_handler (objc_uncaught_exception_handler + new_handler) +{ + objc_uncaught_exception_handler old_handler + = __objc_uncaught_exception_handler; + __objc_uncaught_exception_handler = new_handler; + return old_handler; +} + + #ifdef __ARM_EABI_UNWINDER__ @@ -84,11 +145,6 @@ struct lsda_header_info unsigned char call_site_encoding; }; -/* This hook allows libraries to sepecify special actions when an - exception is thrown without a handler in place. - */ -void (*_objc_unexpected_exception) (id exception); /* !T:SAFE */ - static const unsigned char * parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, struct lsda_header_info *info) @@ -160,25 +216,6 @@ get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i) #endif -/* Like unto the method of the same name on Object, but takes an id. */ -/* ??? Does this bork the meta-type system? Can/should we look up an - isKindOf method on the id? */ - -static int -isKindOf (id value, Class target) -{ - Class c; - - /* NULL target is catch-all. */ - if (target == 0) - return 1; - - for (c = value->class_pointer; c; c = class_get_super_class (c)) - if (c == target) - return 1; - return 0; -} - /* Using a different personality function name causes link failures when trying to mix code using different exception handling models. */ #ifdef SJLJ_EXCEPTIONS @@ -406,7 +443,7 @@ PERSONALITY_FUNCTION (int version, Class catch_type = get_ttype_entry (&info, ar_filter); - if (isKindOf (xh->value, catch_type)) + if ((*__objc_exception_matcher) (catch_type, xh->value)) { handler_switch_value = ar_filter; saw_handler = 1; @@ -473,14 +510,14 @@ __objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)), } void -objc_exception_throw (id value) +objc_exception_throw (id exception) { struct ObjcException *header = calloc (1, sizeof (*header)); - + memcpy (&header->base.exception_class, &__objc_exception_class, sizeof (__objc_exception_class)); header->base.exception_cleanup = __objc_exception_cleanup; - header->value = value; + header->value = exception; #ifdef SJLJ_EXCEPTIONS _Unwind_SjLj_RaiseException (&header->base); @@ -488,10 +525,22 @@ objc_exception_throw (id value) _Unwind_RaiseException (&header->base); #endif - /* Some sort of unwinding error. */ + /* No exception handler was installed. Call the uncaught exception + handler if any is defined. + */ + if (__objc_uncaught_exception_handler != 0) + { + (*__objc_uncaught_exception_handler) (exception); + } + + /* As a last resort support the old, deprecated way of setting an + uncaught exception handler. + */ if (_objc_unexpected_exception != 0) { - (*_objc_unexpected_exception) (value); + (*_objc_unexpected_exception) (exception); } + abort (); } + diff --git a/libobjc/objc/objc-api.h b/libobjc/objc/objc-api.h index 30984b1..8a634a4 100644 --- a/libobjc/objc/objc-api.h +++ b/libobjc/objc/objc-api.h @@ -431,12 +431,14 @@ objc_EXPORT IMP (*__objc_msg_forward)(SEL); objc_EXPORT IMP (*__objc_msg_forward2)(id, SEL); /* -** Hook for uncaught exceptions. This hook is called when an exception -** is thrown and no valid exception handler is in place. The function -** is expected never to return. If the function returns the result is -** currently undefined. +** Hook for uncaught exceptions. This hook is called when an +** exception is thrown and no valid exception handler is in place. +** The function is expected never to return. If the function returns +** the result is currently undefined. This is deprecated. Please use +** objc_set_uncaught_exception_handler() from objc/objc-exception.h +** instead. */ -objc_EXPORT void (*_objc_unexpected_exception)(id); +objc_EXPORT void (*_objc_unexpected_exception)(id) __attribute__ ((deprecated)); Method_t class_get_class_method(MetaClass _class, SEL aSel); diff --git a/libobjc/objc/objc-exception.h b/libobjc/objc/objc-exception.h new file mode 100644 index 0000000..e12ff3a --- /dev/null +++ b/libobjc/objc/objc-exception.h @@ -0,0 +1,117 @@ +/* GNU Objective C Runtime native exceptions + Copyright (C) 2010 Free Software Foundation, Inc. + Contributed by Nicola Pero + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +#ifndef __objc_exception_INCLUDE_GNU +#define __objc_exception_INCLUDE_GNU + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* 'objc_exception_throw' throws the exception 'exception', which is + an exception object. + + Calls to 'objc_exception_throw' are automatically generated by the + compiler: an Objective-C "@throw exception;" statement gets + compiled into the equivalent of "objc_exception_throw + (exception);". + + 'objc_exception_throw' searches for a @catch() that can catch the + exception. By default, @catch (MyClass object) will catch all + exception objects that are of class MyClass or of a subclass of + MyClass; if the exception object is 'nil', then the exception can + only be caught with a catch-all exception handler where no + exception class is specified (such as @catch(id object)). This + behaviour can be customized by setting an 'objc_exception_matcher' + function (using objc_set_exception_matcher(), see below); if one is + set, it is used instead of the default one. + + If the exception is uncaught (there is no @catch() to catch it), + the program aborts. It is possible to customize this behaviour by + setting an 'objc_uncaught_exception_handler' function (using + objc_set_uncaught_exception_handler(), see below); if one is set, + it is executed before abort() is called. An uncaught exception + handler is expected to never return. + */ +void objc_exception_throw (id exception); + +/* PS: the Apple runtime seems to also have objc_exception_rethrow(), + objc_begin_catch() and objc_end_catch(). Currently the GNU runtime + does not use them. +*/ + +/* The following functions allow customizing to a certain extent the + exception handling. They are not thread safe and should be called + during the program initialization before threads are started. They + are mostly reserved for "Foundation" libraries; in the case of + GNUstep, gnustep-base may be using these functions to improve the + standard exception handling. You probably shouldn't use these + functions unless you are writing your own Foundation library. +*/ + +/* PS: objc_set_exception_preprocessor() (available on the Apple + runtime) is not supported on the GNU runtime. */ + +/* An 'objc_exception_matcher' function is used to match an exception + to a @catch clause. 'catch_class' is the class of objects caught + by the @catch clause (for example, in "@catch (Object *o)", the + catch_class is Object). It should return 1 if the exception should + be caught by a @catch with a catch_class argument, and 0 if + not. */ +typedef int (*objc_exception_matcher)(Class catch_class, id exception); + +/* Sets a new exception matcher function, and returns the previous + exception matcher function. This function is not safe to call in a + multi-threaded environment because other threads may be trying to + invoke the exception matcher while you change it! */ +objc_exception_matcher +objc_set_exception_matcher (objc_exception_matcher new_matcher); + + +/* An 'objc_uncaught_exception_handler' function is a function that + handles uncaught exceptions. It should never return. */ +typedef void (*objc_uncaught_exception_handler)(id exception); + +/* Sets a new uncaught exception handler function, and returns the + previous exception handler function. This function is not safe to + call in a multi-threaded environment because other threads may be + trying to invoke the uncaught exception handler while you change + it. +*/ +objc_uncaught_exception_handler +objc_set_uncaught_exception_handler (objc_uncaught_exception_handler new_handler); + + +/* For compatibility with the Apple runtime. */ +#define objc_setExceptionMatcher objc_set_exception_matcher +#define objc_setUncaughtExceptionHandler objc_set_uncaught_exception_handler + +#ifdef __cplusplus +} +#endif + +#endif /* not __objc_exception_INCLUDE_GNU */ -- 2.7.4