2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 // Support minimal stand-alone implementation plus hooks for swapping
28 // in a richer implementation.
30 // Created by Blaine Garst on Fri Nov 01 2002.
31 // Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
36 #import "objc-exception.h"
38 static objc_exception_functions_t xtab;
40 // forward declaration
41 static void set_default_handlers();
44 extern void objc_raise_error(const char *);
51 // get table; version tells how many
52 void objc_exception_get_functions(objc_exception_functions_t *table) {
53 // only version 0 supported at this point
54 if (table && table->version == 0)
59 void objc_exception_set_functions(objc_exception_functions_t *table) {
60 // only version 0 supported at this point
61 if (table && table->version == 0)
66 * The following functions are
67 * synthesized by the compiler upon encountering language constructs
70 void objc_exception_throw(id exception) {
71 if (!xtab.throw_exc) {
72 set_default_handlers();
74 xtab.throw_exc(exception);
77 void objc_exception_try_enter(void *localExceptionData) {
78 if (!xtab.throw_exc) {
79 set_default_handlers();
81 xtab.try_enter(localExceptionData);
85 void objc_exception_try_exit(void *localExceptionData) {
86 if (!xtab.throw_exc) {
87 set_default_handlers();
89 xtab.try_exit(localExceptionData);
93 id objc_exception_extract(void *localExceptionData) {
94 if (!xtab.throw_exc) {
95 set_default_handlers();
97 return xtab.extract(localExceptionData);
101 int objc_exception_match(Class exceptionClass, id exception) {
102 if (!xtab.throw_exc) {
103 set_default_handlers();
105 return xtab.match(exceptionClass, exception);
109 // quick and dirty exception handling code
110 // default implementation - mostly a toy for use outside/before Foundation
111 // provides its implementation
112 // Perhaps the default implementation should just complain loudly and quit
119 extern void _objc_inform(const char *fmt, ...);
121 typedef struct { jmp_buf buf; void *pointers[4]; } LocalData_t;
123 typedef struct _threadChain {
124 LocalData_t *topHandler;
126 struct _threadChain *next;
130 #define _ExceptionDebug 0
132 static ThreadChainLink_t ThreadChainLink;
134 static ThreadChainLink_t *getChainLink() {
135 // follow links until thread_self() found (someday) XXX
136 pthread_t self = pthread_self();
137 ThreadChainLink_t *walker = &ThreadChainLink;
138 while (walker->perThreadID != (void *)self) {
139 if (walker->next != NULL) {
140 walker = walker->next;
144 // XXX not thread safe (!)
145 // XXX Also, we don't register to deallocate on thread death
146 walker->next = (ThreadChainLink_t *)malloc(sizeof(ThreadChainLink_t));
147 walker = walker->next;
149 walker->topHandler = NULL;
150 walker->perThreadID = self;
155 static void default_try_enter(void *localExceptionData) {
156 ThreadChainLink_t *chainLink = getChainLink();
157 ((LocalData_t *)localExceptionData)->pointers[1] = chainLink->topHandler;
158 chainLink->topHandler = localExceptionData;
159 if (_ExceptionDebug) _objc_inform("entered try block %x\n", chainLink->topHandler);
162 static void default_throw(id value) {
163 ThreadChainLink_t *chainLink = getChainLink();
165 if (_ExceptionDebug) _objc_inform("objc_exception_throw with nil value\n");
168 if (chainLink == NULL) {
169 if (_ExceptionDebug) _objc_inform("No handler in place!\n");
172 if (_ExceptionDebug) _objc_inform("exception thrown, going to handler block %x\n", chainLink->topHandler);
173 LocalData_t *led = chainLink->topHandler;
174 chainLink->topHandler = led->pointers[1]; // pop top handler
175 led->pointers[0] = value; // store exception that is thrown
176 _longjmp(led->buf, 1);
179 static void default_try_exit(void *led) {
180 ThreadChainLink_t *chainLink = getChainLink();
181 if (!chainLink || led != chainLink->topHandler) {
182 if (_ExceptionDebug) _objc_inform("!!! mismatched try block exit handlers !!!\n");
185 if (_ExceptionDebug) _objc_inform("removing try block handler %x\n", chainLink->topHandler);
186 chainLink->topHandler = chainLink->topHandler->pointers[1]; // pop top handler
189 static id default_extract(void *localExceptionData) {
190 LocalData_t *led = (LocalData_t *)localExceptionData;
191 return (id)led->pointers[0];
194 static int default_match(Class exceptionClass, id exception) {
195 //return [exception isKindOfClass:exceptionClass];
197 for (cls = exception->isa; nil != cls; cls = cls->super_class)
198 if (cls == exceptionClass) return 1;
202 static void set_default_handlers() {
203 objc_exception_functions_t default_functions = {
204 0, default_throw, default_try_enter, default_try_exit, default_extract, default_match };
206 // should this always print?
207 if (_ExceptionDebug) _objc_inform("*** Setting default (non-Foundation) exception mechanism\n");
208 objc_exception_set_functions(&default_functions);