OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libobjc/] [exception.c] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* The implementation of exception handling primitives for Objective-C.
2
   Copyright (C) 2004 Free Software Foundation, Inc.
3
 
4
This file is part of GCC.
5
 
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.
10
 
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.
15
 
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, 51 Franklin Street, Fifth Floor,
19
Boston, MA 02110-1301, USA.  */
20
 
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. */
26
 
27
#include <stdlib.h>
28
#include "config.h"
29
#include "objc/objc-api.h"
30
#include "unwind.h"
31
#include "unwind-pe.h"
32
 
33
 
34
/* This is the exception class we report -- "GNUCOBJC".  */
35
#define __objc_exception_class                  \
36
  ((((((((_Unwind_Exception_Class) 'G'          \
37
         << 8 | (_Unwind_Exception_Class) 'N')  \
38
        << 8 | (_Unwind_Exception_Class) 'U')   \
39
       << 8 | (_Unwind_Exception_Class) 'C')    \
40
      << 8 | (_Unwind_Exception_Class) 'O')     \
41
     << 8 | (_Unwind_Exception_Class) 'B')      \
42
    << 8 | (_Unwind_Exception_Class) 'J')       \
43
   << 8 | (_Unwind_Exception_Class) 'C')
44
 
45
/* This is the object that is passed around by the Objective C runtime
46
   to represent the exception in flight.  */
47
 
48
struct ObjcException
49
{
50
  /* This bit is needed in order to interact with the unwind runtime.  */
51
  struct _Unwind_Exception base;
52
 
53
  /* The actual object we want to throw.  */
54
  id value;
55
 
56
  /* Cache some internal unwind data between phase 1 and phase 2.  */
57
  _Unwind_Ptr landingPad;
58
  int handlerSwitchValue;
59
};
60
 
61
 
62
 
63
struct lsda_header_info
64
{
65
  _Unwind_Ptr Start;
66
  _Unwind_Ptr LPStart;
67
  _Unwind_Ptr ttype_base;
68
  const unsigned char *TType;
69
  const unsigned char *action_table;
70
  unsigned char ttype_encoding;
71
  unsigned char call_site_encoding;
72
};
73
 
74
static const unsigned char *
75
parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
76
                   struct lsda_header_info *info)
77
{
78
  _Unwind_Word tmp;
79
  unsigned char lpstart_encoding;
80
 
81
  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
82
 
83
  /* Find @LPStart, the base to which landing pad offsets are relative.  */
84
  lpstart_encoding = *p++;
85
  if (lpstart_encoding != DW_EH_PE_omit)
86
    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
87
  else
88
    info->LPStart = info->Start;
89
 
90
  /* Find @TType, the base of the handler and exception spec type data.  */
91
  info->ttype_encoding = *p++;
92
  if (info->ttype_encoding != DW_EH_PE_omit)
93
    {
94
      p = read_uleb128 (p, &tmp);
95
      info->TType = p + tmp;
96
    }
97
  else
98
    info->TType = 0;
99
 
100
  /* The encoding and length of the call-site table; the action table
101
     immediately follows.  */
102
  info->call_site_encoding = *p++;
103
  p = read_uleb128 (p, &tmp);
104
  info->action_table = p + tmp;
105
 
106
  return p;
107
}
108
 
109
static Class
110
get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
111
{
112
  _Unwind_Ptr ptr;
113
 
114
  i *= size_of_encoded_value (info->ttype_encoding);
115
  read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
116
                                info->TType - i, &ptr);
117
 
118
  /* NULL ptr means catch-all.  */
119
  if (ptr)
120
    return objc_get_class ((const char *) ptr);
121
  else
122
    return 0;
123
}
124
 
125
/* Like unto the method of the same name on Object, but takes an id.  */
126
/* ??? Does this bork the meta-type system?  Can/should we look up an
127
   isKindOf method on the id?  */
128
 
129
static int
130
isKindOf (id value, Class target)
131
{
132
  Class c;
133
 
134
  /* NULL target is catch-all.  */
135
  if (target == 0)
136
    return 1;
137
 
138
  for (c = value->class_pointer; c; c = class_get_super_class (c))
139
    if (c == target)
140
      return 1;
141
  return 0;
142
}
143
 
144
/* Using a different personality function name causes link failures
145
   when trying to mix code using different exception handling models.  */
146
#ifdef SJLJ_EXCEPTIONS
147
#define PERSONALITY_FUNCTION    __gnu_objc_personality_sj0
148
#define __builtin_eh_return_data_regno(x) x
149
#else
150
#define PERSONALITY_FUNCTION    __gnu_objc_personality_v0
151
#endif
152
 
153
_Unwind_Reason_Code
154
PERSONALITY_FUNCTION (int version,
155
                      _Unwind_Action actions,
156
                      _Unwind_Exception_Class exception_class,
157
                      struct _Unwind_Exception *ue_header,
158
                      struct _Unwind_Context *context)
159
{
160
  struct ObjcException *xh = (struct ObjcException *) ue_header;
161
 
162
  struct lsda_header_info info;
163
  const unsigned char *language_specific_data;
164
  const unsigned char *action_record;
165
  const unsigned char *p;
166
  _Unwind_Ptr landing_pad, ip;
167
  int handler_switch_value;
168
  int saw_cleanup = 0, saw_handler;
169
  void *return_object;
170
 
171
  /* Interface version check.  */
172
  if (version != 1)
173
    return _URC_FATAL_PHASE1_ERROR;
174
 
175
  /* Shortcut for phase 2 found handler for domestic exception.  */
176
  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
177
      && exception_class == __objc_exception_class)
178
    {
179
      handler_switch_value = xh->handlerSwitchValue;
180
      landing_pad = xh->landingPad;
181
      goto install_context;
182
    }
183
 
184
  language_specific_data = (const unsigned char *)
185
    _Unwind_GetLanguageSpecificData (context);
186
 
187
  /* If no LSDA, then there are no handlers or cleanups.  */
188
  if (! language_specific_data)
189
    return _URC_CONTINUE_UNWIND;
190
 
191
  /* Parse the LSDA header.  */
192
  p = parse_lsda_header (context, language_specific_data, &info);
193
  info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
194
  ip = _Unwind_GetIP (context) - 1;
195
  landing_pad = 0;
196
  action_record = 0;
197
  handler_switch_value = 0;
198
 
199
#ifdef SJLJ_EXCEPTIONS
200
  /* The given "IP" is an index into the call-site table, with two
201
     exceptions -- -1 means no-action, and 0 means terminate.  But
202
     since we're using uleb128 values, we've not got random access
203
     to the array.  */
204
  if ((int) ip < 0)
205
    return _URC_CONTINUE_UNWIND;
206
  else
207
    {
208
      _Unwind_Word cs_lp, cs_action;
209
      do
210
        {
211
          p = read_uleb128 (p, &cs_lp);
212
          p = read_uleb128 (p, &cs_action);
213
        }
214
      while (--ip);
215
 
216
      /* Can never have null landing pad for sjlj -- that would have
217
         been indicated by a -1 call site index.  */
218
      landing_pad = cs_lp + 1;
219
      if (cs_action)
220
        action_record = info.action_table + cs_action - 1;
221
      goto found_something;
222
    }
223
#else
224
  /* Search the call-site table for the action associated with this IP.  */
225
  while (p < info.action_table)
226
    {
227
      _Unwind_Ptr cs_start, cs_len, cs_lp;
228
      _Unwind_Word cs_action;
229
 
230
      /* Note that all call-site encodings are "absolute" displacements.  */
231
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
232
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
233
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
234
      p = read_uleb128 (p, &cs_action);
235
 
236
      /* The table is sorted, so if we've passed the ip, stop.  */
237
      if (ip < info.Start + cs_start)
238
        p = info.action_table;
239
      else if (ip < info.Start + cs_start + cs_len)
240
        {
241
          if (cs_lp)
242
            landing_pad = info.LPStart + cs_lp;
243
          if (cs_action)
244
            action_record = info.action_table + cs_action - 1;
245
          goto found_something;
246
        }
247
    }
248
#endif /* SJLJ_EXCEPTIONS  */
249
 
250
  /* If ip is not present in the table, C++ would call terminate.  */
251
  /* ??? As with Java, it's perhaps better to tweek the LSDA to
252
     that no-action is mapped to no-entry.  */
253
  return _URC_CONTINUE_UNWIND;
254
 
255
 found_something:
256
  saw_cleanup = 0;
257
  saw_handler = 0;
258
 
259
  if (landing_pad == 0)
260
    {
261
      /* If ip is present, and has a null landing pad, there are
262
         no cleanups or handlers to be run.  */
263
    }
264
  else if (action_record == 0)
265
    {
266
      /* If ip is present, has a non-null landing pad, and a null
267
         action table offset, then there are only cleanups present.
268
         Cleanups use a zero switch value, as set above.  */
269
      saw_cleanup = 1;
270
    }
271
  else
272
    {
273
      /* Otherwise we have a catch handler.  */
274
      _Unwind_Sword ar_filter, ar_disp;
275
 
276
      while (1)
277
        {
278
          p = action_record;
279
          p = read_sleb128 (p, &ar_filter);
280
          read_sleb128 (p, &ar_disp);
281
 
282
          if (ar_filter == 0)
283
            {
284
              /* Zero filter values are cleanups.  */
285
              saw_cleanup = 1;
286
            }
287
 
288
          /* During forced unwinding, we only run cleanups.  With a
289
             foreign exception class, we have no class info to match.  */
290
          else if ((actions & _UA_FORCE_UNWIND)
291
                   || exception_class != __objc_exception_class)
292
            ;
293
 
294
          else if (ar_filter > 0)
295
            {
296
              /* Positive filter values are handlers.  */
297
 
298
              Class catch_type = get_ttype_entry (&info, ar_filter);
299
 
300
              if (isKindOf (xh->value, catch_type))
301
                {
302
                  handler_switch_value = ar_filter;
303
                  saw_handler = 1;
304
                  break;
305
                }
306
            }
307
          else
308
            {
309
              /* Negative filter values are exception specifications,
310
                 which Objective-C does not use.  */
311
              abort ();
312
            }
313
 
314
          if (ar_disp == 0)
315
            break;
316
          action_record = p + ar_disp;
317
        }
318
    }
319
 
320
  if (! saw_handler && ! saw_cleanup)
321
    return _URC_CONTINUE_UNWIND;
322
 
323
  if (actions & _UA_SEARCH_PHASE)
324
    {
325
      if (!saw_handler)
326
        return _URC_CONTINUE_UNWIND;
327
 
328
      /* For domestic exceptions, we cache data from phase 1 for phase 2.  */
329
      if (exception_class == __objc_exception_class)
330
        {
331
          xh->handlerSwitchValue = handler_switch_value;
332
          xh->landingPad = landing_pad;
333
        }
334
      return _URC_HANDLER_FOUND;
335
    }
336
 
337
 install_context:
338
  if (saw_cleanup == 0)
339
    {
340
      return_object = xh->value;
341
      if (!(actions & _UA_SEARCH_PHASE))
342
        _Unwind_DeleteException(&xh->base);
343
    }
344
 
345
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
346
                 __builtin_extend_pointer (saw_cleanup ? xh : return_object));
347
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
348
                 handler_switch_value);
349
  _Unwind_SetIP (context, landing_pad);
350
  return _URC_INSTALL_CONTEXT;
351
}
352
 
353
static void
354
__objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)),
355
                          struct _Unwind_Exception *exc)
356
{
357
  free (exc);
358
}
359
 
360
void
361
objc_exception_throw (id value)
362
{
363
  struct ObjcException *header = calloc (1, sizeof (*header));
364
  header->base.exception_class = __objc_exception_class;
365
  header->base.exception_cleanup = __objc_exception_cleanup;
366
  header->value = value;
367
 
368
#ifdef SJLJ_EXCEPTIONS
369
  _Unwind_SjLj_RaiseException (&header->base);
370
#else
371
  _Unwind_RaiseException (&header->base);
372
#endif
373
 
374
  /* Some sort of unwinding error.  */
375
  abort ();
376
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.