* cp-tree.h (enum cp_storage_class): Remove trailing comma.
[official-gcc.git] / libobjc / exception.c
blobd788c412ace0729beb41cc8e4b6bddba2a37126f
1 /* The implementation of exception handling primitives for Objective-C.
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* As a special exception, if you link this library with files compiled
22 with GCC to produce an executable, this does not cause the resulting
23 executable to be covered by the GNU General Public License. This
24 exception does not however invalidate any other reasons why the
25 executable file might be covered by the GNU General Public License. */
27 #include <stdlib.h>
28 #include "objc/objc-api.h"
29 #include "unwind.h"
30 #include "unwind-pe.h"
33 /* This is the exception class we report -- "GNUCOBJC". */
34 #define __objc_exception_class \
35 ((((((((_Unwind_Exception_Class) 'G' \
36 << 8 | (_Unwind_Exception_Class) 'N') \
37 << 8 | (_Unwind_Exception_Class) 'U') \
38 << 8 | (_Unwind_Exception_Class) 'C') \
39 << 8 | (_Unwind_Exception_Class) 'O') \
40 << 8 | (_Unwind_Exception_Class) 'B') \
41 << 8 | (_Unwind_Exception_Class) 'J') \
42 << 8 | (_Unwind_Exception_Class) 'C')
44 /* This is the object that is passed around by the Objective C runtime
45 to represent the exception in flight. */
47 struct ObjcException
49 /* This bit is needed in order to interact with the unwind runtime. */
50 struct _Unwind_Exception base;
52 /* The actual object we want to throw. */
53 id value;
55 /* Cache some internal unwind data between phase 1 and phase 2. */
56 _Unwind_Ptr landingPad;
57 int handlerSwitchValue;
62 struct lsda_header_info
64 _Unwind_Ptr Start;
65 _Unwind_Ptr LPStart;
66 _Unwind_Ptr ttype_base;
67 const unsigned char *TType;
68 const unsigned char *action_table;
69 unsigned char ttype_encoding;
70 unsigned char call_site_encoding;
73 static const unsigned char *
74 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
75 struct lsda_header_info *info)
77 _Unwind_Word tmp;
78 unsigned char lpstart_encoding;
80 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
82 /* Find @LPStart, the base to which landing pad offsets are relative. */
83 lpstart_encoding = *p++;
84 if (lpstart_encoding != DW_EH_PE_omit)
85 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
86 else
87 info->LPStart = info->Start;
89 /* Find @TType, the base of the handler and exception spec type data. */
90 info->ttype_encoding = *p++;
91 if (info->ttype_encoding != DW_EH_PE_omit)
93 p = read_uleb128 (p, &tmp);
94 info->TType = p + tmp;
96 else
97 info->TType = 0;
99 /* The encoding and length of the call-site table; the action table
100 immediately follows. */
101 info->call_site_encoding = *p++;
102 p = read_uleb128 (p, &tmp);
103 info->action_table = p + tmp;
105 return p;
108 static Class
109 get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
111 _Unwind_Ptr ptr;
113 i *= size_of_encoded_value (info->ttype_encoding);
114 read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
115 info->TType - i, &ptr);
117 /* NULL ptr means catch-all. */
118 if (ptr)
119 return objc_get_class ((const char *) ptr);
120 else
121 return 0;
124 /* Like unto the method of the same name on Object, but takes an id. */
125 /* ??? Does this bork the meta-type system? Can/should we look up an
126 isKindOf method on the id? */
128 static int
129 isKindOf (id value, Class target)
131 Class c;
133 /* NULL target is catch-all. */
134 if (target == 0)
135 return 1;
137 for (c = value->class_pointer; c; c = class_get_super_class (c))
138 if (c == target)
139 return 1;
140 return 0;
143 /* Using a different personality function name causes link failures
144 when trying to mix code using different exception handling models. */
145 #ifdef SJLJ_EXCEPTIONS
146 #define PERSONALITY_FUNCTION __gnu_objc_personality_sj0
147 #define __builtin_eh_return_data_regno(x) x
148 #else
149 #define PERSONALITY_FUNCTION __gnu_objc_personality_v0
150 #endif
152 _Unwind_Reason_Code
153 PERSONALITY_FUNCTION (int version,
154 _Unwind_Action actions,
155 _Unwind_Exception_Class exception_class,
156 struct _Unwind_Exception *ue_header,
157 struct _Unwind_Context *context)
159 struct ObjcException *xh = (struct ObjcException *) ue_header;
161 struct lsda_header_info info;
162 const unsigned char *language_specific_data;
163 const unsigned char *action_record;
164 const unsigned char *p;
165 _Unwind_Ptr landing_pad, ip;
166 int handler_switch_value;
167 int saw_cleanup, saw_handler;
169 /* Interface version check. */
170 if (version != 1)
171 return _URC_FATAL_PHASE1_ERROR;
173 /* Shortcut for phase 2 found handler for domestic exception. */
174 if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
175 && exception_class == __objc_exception_class)
177 handler_switch_value = xh->handlerSwitchValue;
178 landing_pad = xh->landingPad;
179 goto install_context;
182 language_specific_data = (const unsigned char *)
183 _Unwind_GetLanguageSpecificData (context);
185 /* If no LSDA, then there are no handlers or cleanups. */
186 if (! language_specific_data)
187 return _URC_CONTINUE_UNWIND;
189 /* Parse the LSDA header. */
190 p = parse_lsda_header (context, language_specific_data, &info);
191 info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
192 ip = _Unwind_GetIP (context) - 1;
193 landing_pad = 0;
194 action_record = 0;
195 handler_switch_value = 0;
197 #ifdef SJLJ_EXCEPTIONS
198 /* The given "IP" is an index into the call-site table, with two
199 exceptions -- -1 means no-action, and 0 means terminate. But
200 since we're using uleb128 values, we've not got random access
201 to the array. */
202 if ((int) ip < 0)
203 return _URC_CONTINUE_UNWIND;
204 else
206 _Unwind_Word cs_lp, cs_action;
209 p = read_uleb128 (p, &cs_lp);
210 p = read_uleb128 (p, &cs_action);
212 while (--ip);
214 /* Can never have null landing pad for sjlj -- that would have
215 been indicated by a -1 call site index. */
216 landing_pad = cs_lp + 1;
217 if (cs_action)
218 action_record = info.action_table + cs_action - 1;
219 goto found_something;
221 #else
222 /* Search the call-site table for the action associated with this IP. */
223 while (p < info.action_table)
225 _Unwind_Ptr cs_start, cs_len, cs_lp;
226 _Unwind_Word cs_action;
228 /* Note that all call-site encodings are "absolute" displacements. */
229 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
230 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
231 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
232 p = read_uleb128 (p, &cs_action);
234 /* The table is sorted, so if we've passed the ip, stop. */
235 if (ip < info.Start + cs_start)
236 p = info.action_table;
237 else if (ip < info.Start + cs_start + cs_len)
239 if (cs_lp)
240 landing_pad = info.LPStart + cs_lp;
241 if (cs_action)
242 action_record = info.action_table + cs_action - 1;
243 goto found_something;
246 #endif /* SJLJ_EXCEPTIONS */
248 /* If ip is not present in the table, C++ would call terminate. */
249 /* ??? As with Java, it's perhaps better to tweek the LSDA to
250 that no-action is mapped to no-entry. */
251 return _URC_CONTINUE_UNWIND;
253 found_something:
254 saw_cleanup = 0;
255 saw_handler = 0;
257 if (landing_pad == 0)
259 /* If ip is present, and has a null landing pad, there are
260 no cleanups or handlers to be run. */
262 else if (action_record == 0)
264 /* If ip is present, has a non-null landing pad, and a null
265 action table offset, then there are only cleanups present.
266 Cleanups use a zero switch value, as set above. */
267 saw_cleanup = 1;
269 else
271 /* Otherwise we have a catch handler. */
272 _Unwind_Sword ar_filter, ar_disp;
274 while (1)
276 p = action_record;
277 p = read_sleb128 (p, &ar_filter);
278 read_sleb128 (p, &ar_disp);
280 if (ar_filter == 0)
282 /* Zero filter values are cleanups. */
283 saw_cleanup = 1;
286 /* During forced unwinding, we only run cleanups. With a
287 foreign exception class, we have no class info to match. */
288 else if ((actions & _UA_FORCE_UNWIND)
289 || exception_class != __objc_exception_class)
292 else if (ar_filter > 0)
294 /* Positive filter values are handlers. */
296 Class catch_type = get_ttype_entry (&info, ar_filter);
298 if (isKindOf (xh->value, catch_type))
300 handler_switch_value = ar_filter;
301 saw_handler = 1;
302 break;
305 else
307 /* Negative filter values are exception specifications,
308 which Objective-C does not use. */
309 abort ();
312 if (ar_disp == 0)
313 break;
314 action_record = p + ar_disp;
318 if (! saw_handler && ! saw_cleanup)
319 return _URC_CONTINUE_UNWIND;
321 if (actions & _UA_SEARCH_PHASE)
323 if (!saw_handler)
324 return _URC_CONTINUE_UNWIND;
326 /* For domestic exceptions, we cache data from phase 1 for phase 2. */
327 if (exception_class == __objc_exception_class)
329 xh->handlerSwitchValue = handler_switch_value;
330 xh->landingPad = landing_pad;
332 return _URC_HANDLER_FOUND;
335 install_context:
336 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
337 __builtin_extend_pointer (xh->value));
338 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
339 handler_switch_value);
340 _Unwind_SetIP (context, landing_pad);
341 return _URC_INSTALL_CONTEXT;
344 static void
345 __objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)),
346 struct _Unwind_Exception *exc)
348 free (exc);
351 void
352 objc_exception_throw (id value)
354 struct ObjcException *header = calloc (1, sizeof (*header));
355 header->base.exception_class = __objc_exception_class;
356 header->base.exception_cleanup = __objc_exception_cleanup;
357 header->value = value;
359 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
360 _Unwind_SjLj_RaiseException (&header->base);
361 #else
362 _Unwind_RaiseException (&header->base);
363 #endif
365 /* Some sort of unwinding error. */
366 abort ();