]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-exception.m
objc4-266.tar.gz
[apple/objc4.git] / runtime / objc-exception.m
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 //
26 // objc_exception.m
27 // Support minimal stand-alone implementation plus hooks for swapping
28 // in a richer implementation.
29 //
30 // Created by Blaine Garst on Fri Nov 01 2002.
31 // Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
32 //
33
34 #undef _BUILDING_OBJC
35
36 #import "objc-exception.h"
37
38 static objc_exception_functions_t xtab;
39
40 // forward declaration
41 static void set_default_handlers();
42
43
44 /*
45 * Exported functions
46 */
47
48 // get table; version tells how many
49 void objc_exception_get_functions(objc_exception_functions_t *table) {
50 // only version 0 supported at this point
51 if (table && table->version == 0)
52 *table = xtab;
53 }
54
55 // set table
56 void objc_exception_set_functions(objc_exception_functions_t *table) {
57 // only version 0 supported at this point
58 if (table && table->version == 0)
59 xtab = *table;
60 }
61
62 /*
63 * The following functions are
64 * synthesized by the compiler upon encountering language constructs
65 */
66
67 void objc_exception_throw(id exception) {
68 if (!xtab.throw_exc) {
69 set_default_handlers();
70 }
71 xtab.throw_exc(exception);
72 }
73
74 void objc_exception_try_enter(void *localExceptionData) {
75 if (!xtab.throw_exc) {
76 set_default_handlers();
77 }
78 xtab.try_enter(localExceptionData);
79 }
80
81
82 void objc_exception_try_exit(void *localExceptionData) {
83 if (!xtab.throw_exc) {
84 set_default_handlers();
85 }
86 xtab.try_exit(localExceptionData);
87 }
88
89
90 id objc_exception_extract(void *localExceptionData) {
91 if (!xtab.throw_exc) {
92 set_default_handlers();
93 }
94 return xtab.extract(localExceptionData);
95 }
96
97
98 int objc_exception_match(Class exceptionClass, id exception) {
99 if (!xtab.throw_exc) {
100 set_default_handlers();
101 }
102 return xtab.match(exceptionClass, exception);
103 }
104
105
106 // quick and dirty exception handling code
107 // default implementation - mostly a toy for use outside/before Foundation
108 // provides its implementation
109 // Perhaps the default implementation should just complain loudly and quit
110
111
112
113 #import <pthread.h>
114 #import <setjmp.h>
115
116 extern void _objc_inform(const char *fmt, ...);
117
118 typedef struct { jmp_buf buf; void *pointers[4]; } LocalData_t;
119
120 typedef struct _threadChain {
121 LocalData_t *topHandler;
122 void *perThreadID;
123 struct _threadChain *next;
124 }
125 ThreadChainLink_t;
126
127 #define _ExceptionDebug 0
128
129 static ThreadChainLink_t ThreadChainLink;
130
131 static ThreadChainLink_t *getChainLink() {
132 // follow links until thread_self() found (someday) XXX
133 pthread_t self = pthread_self();
134 ThreadChainLink_t *walker = &ThreadChainLink;
135 while (walker->perThreadID != (void *)self) {
136 if (walker->next != NULL) {
137 walker = walker->next;
138 continue;
139 }
140 // create a new one
141 // XXX not thread safe (!)
142 // XXX Also, we don't register to deallocate on thread death
143 walker->next = (ThreadChainLink_t *)malloc(sizeof(ThreadChainLink_t));
144 walker = walker->next;
145 walker->next = NULL;
146 walker->topHandler = NULL;
147 walker->perThreadID = self;
148 }
149 return walker;
150 }
151
152 static void default_try_enter(void *localExceptionData) {
153 ThreadChainLink_t *chainLink = getChainLink();
154 ((LocalData_t *)localExceptionData)->pointers[1] = chainLink->topHandler;
155 chainLink->topHandler = localExceptionData;
156 if (_ExceptionDebug) _objc_inform("entered try block %x\n", chainLink->topHandler);
157 }
158
159 static void default_throw(id value) {
160 ThreadChainLink_t *chainLink = getChainLink();
161 if (value == nil) {
162 if (_ExceptionDebug) _objc_inform("objc_exception_throw with nil value\n");
163 return;
164 }
165 if (chainLink == NULL) {
166 if (_ExceptionDebug) _objc_inform("No handler in place!\n");
167 return;
168 }
169 if (_ExceptionDebug) _objc_inform("exception thrown, going to handler block %x\n", chainLink->topHandler);
170 LocalData_t *led = chainLink->topHandler;
171 chainLink->topHandler = led->pointers[1]; // pop top handler
172 led->pointers[0] = value; // store exception that is thrown
173 _longjmp(led->buf, 1);
174 }
175
176 static void default_try_exit(void *led) {
177 ThreadChainLink_t *chainLink = getChainLink();
178 if (!chainLink || led != chainLink->topHandler) {
179 if (_ExceptionDebug) _objc_inform("!!! mismatched try block exit handlers !!!\n");
180 return;
181 }
182 if (_ExceptionDebug) _objc_inform("removing try block handler %x\n", chainLink->topHandler);
183 chainLink->topHandler = chainLink->topHandler->pointers[1]; // pop top handler
184 }
185
186 static id default_extract(void *localExceptionData) {
187 LocalData_t *led = (LocalData_t *)localExceptionData;
188 return (id)led->pointers[0];
189 }
190
191 static int default_match(Class exceptionClass, id exception) {
192 //return [exception isKindOfClass:exceptionClass];
193 Class cls;
194 for (cls = exception->isa; nil != cls; cls = cls->super_class)
195 if (cls == exceptionClass) return 1;
196 return 0;
197 }
198
199 static void set_default_handlers() {
200 objc_exception_functions_t default_functions = {
201 0, default_throw, default_try_enter, default_try_exit, default_extract, default_match };
202
203 // should this always print?
204 if (_ExceptionDebug) _objc_inform("*** Setting default (non-Foundation) exception mechanism\n");
205 objc_exception_set_functions(&default_functions);
206 }
207