source: trunk/third/gcc/libjava/exception.cc @ 18474

Revision 18474, 11.1 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18473, which included commits to RCS files with non-trunk default branches.
Line 
1// Functions for Exception Support for Java.
2
3/* Copyright (C) 1998, 1999, 2001, 2002  Free Software Foundation
4
5   This file is part of libgcj.
6
7This software is copyrighted work licensed under the terms of the
8Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9details.  */
10
11#include <config.h>
12
13#include <stddef.h>
14#include <stdlib.h>
15
16#include <java/lang/Class.h>
17#include <java/lang/NullPointerException.h>
18#include <gcj/cni.h>
19#include <jvm.h>
20
21// unwind-pe.h uses std::abort(), but sometimes we compile libjava
22// without libstdc++-v3. The following hack forces it to use
23// stdlib.h's abort().
24namespace std
25{
26  static __attribute__ ((__noreturn__)) void
27  abort ()
28  {
29    ::abort ();
30  }
31}
32#include "unwind.h"
33
34struct alignment_test_struct
35{
36  char space;
37  char end[0] __attribute__((aligned));
38};
39
40struct java_exception_header
41{
42  /* Cache handler details between Phase 1 and Phase 2.  */
43  _Unwind_Ptr landingPad;
44  int handlerSwitchValue;
45
46  /* The object being thrown.  Compiled code expects this to be immediately
47     before the generic exception header.  Which is complicated by the fact
48     that _Unwind_Exception is ((aligned)).  */
49
50  char pad[sizeof(jthrowable) < sizeof(alignment_test_struct)
51           ? sizeof(alignment_test_struct) - sizeof(jthrowable) : 0]
52    __attribute__((aligned));
53
54  jthrowable value;
55
56  /* The generic exception header.  */
57  _Unwind_Exception unwindHeader;
58};
59
60// This is the exception class we report -- "GNUCJAVA".
61const _Unwind_Exception_Class __gcj_exception_class
62= ((((((((_Unwind_Exception_Class) 'G'
63         << 8 | (_Unwind_Exception_Class) 'N')
64        << 8 | (_Unwind_Exception_Class) 'U')
65       << 8 | (_Unwind_Exception_Class) 'C')
66      << 8 | (_Unwind_Exception_Class) 'J')
67     << 8 | (_Unwind_Exception_Class) 'A')
68    << 8 | (_Unwind_Exception_Class) 'V')
69   << 8 | (_Unwind_Exception_Class) 'A');
70
71
72static inline java_exception_header *
73get_exception_header_from_ue (_Unwind_Exception *exc)
74{
75  return reinterpret_cast<java_exception_header *>(exc + 1) - 1;
76}
77
78/* Perform a throw, Java style. Throw will unwind through this call,
79   so there better not be any handlers or exception thrown here. */
80
81extern "C" void
82_Jv_Throw (jthrowable value)
83{
84  java_exception_header *xh
85    = static_cast<java_exception_header *>(_Jv_AllocRawObj (sizeof (*xh)));
86
87  if (value == NULL)
88    value = new java::lang::NullPointerException ();
89  xh->value = value;
90
91  xh->unwindHeader.exception_class = __gcj_exception_class;
92  xh->unwindHeader.exception_cleanup = NULL;
93
94  /* We're happy with setjmp/longjmp exceptions or region-based
95     exception handlers: entry points are provided here for both.  */
96  _Unwind_Reason_Code code;
97#ifdef SJLJ_EXCEPTIONS
98  code = _Unwind_SjLj_RaiseException (&xh->unwindHeader);
99#else
100  code = _Unwind_RaiseException (&xh->unwindHeader);
101#endif
102
103  /* If code == _URC_END_OF_STACK, then we reached top of stack without
104     finding a handler for the exception.  Since each thread is run in
105     a try/catch, this oughtn't happen.  If code is something else, we
106     encountered some sort of heinous lossage from which we could not
107     recover.  As is the way of such things, almost certainly we will have
108     crashed before now, rather than actually being able to diagnose the
109     problem.  */
110  abort();
111}
112
113
114#include "unwind-pe.h"
115
116struct lsda_header_info
117{
118  _Unwind_Ptr Start;
119  _Unwind_Ptr LPStart;
120  const unsigned char *TType;
121  const unsigned char *action_table;
122  unsigned char ttype_encoding;
123  unsigned char call_site_encoding;
124};
125
126static const unsigned char *
127parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
128                   lsda_header_info *info)
129{
130  _Unwind_Word tmp;
131  unsigned char lpstart_encoding;
132
133  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
134
135  // Find @LPStart, the base to which landing pad offsets are relative.
136  lpstart_encoding = *p++;
137  if (lpstart_encoding != DW_EH_PE_omit)
138    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
139  else
140    info->LPStart = info->Start;
141
142  // Find @TType, the base of the handler and exception spec type data.
143  info->ttype_encoding = *p++;
144  if (info->ttype_encoding != DW_EH_PE_omit)
145    {
146      p = read_uleb128 (p, &tmp);
147      info->TType = p + tmp;
148    }
149  else
150    info->TType = 0;
151
152  // The encoding and length of the call-site table; the action table
153  // immediately follows.
154  info->call_site_encoding = *p++;
155  p = read_uleb128 (p, &tmp);
156  info->action_table = p + tmp;
157
158  return p;
159}
160
161static jclass
162get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
163{
164  _Unwind_Ptr ptr;
165
166  i *= size_of_encoded_value (info->ttype_encoding);
167  read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
168
169  return reinterpret_cast<jclass>(ptr);
170}
171
172
173// Using a different personality function name causes link failures
174// when trying to mix code using different exception handling models.
175#ifdef SJLJ_EXCEPTIONS
176#define PERSONALITY_FUNCTION    __gcj_personality_sj0
177#define __builtin_eh_return_data_regno(x) x
178#else
179#define PERSONALITY_FUNCTION    __gcj_personality_v0
180#endif
181
182extern "C" _Unwind_Reason_Code
183PERSONALITY_FUNCTION (int version,
184                      _Unwind_Action actions,
185                      _Unwind_Exception_Class exception_class,
186                      struct _Unwind_Exception *ue_header,
187                      struct _Unwind_Context *context)
188{
189  java_exception_header *xh = get_exception_header_from_ue (ue_header);
190
191  lsda_header_info info;
192  const unsigned char *language_specific_data;
193  const unsigned char *action_record;
194  const unsigned char *p;
195  _Unwind_Ptr landing_pad, ip;
196  int handler_switch_value;
197  bool saw_cleanup;
198  bool saw_handler;
199
200
201  // Interface version check.
202  if (version != 1)
203    return _URC_FATAL_PHASE1_ERROR;
204
205  // Shortcut for phase 2 found handler for domestic exception.
206  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
207      && exception_class == __gcj_exception_class)
208    {
209      handler_switch_value = xh->handlerSwitchValue;
210      landing_pad = xh->landingPad;
211      goto install_context;
212    }
213
214  // FIXME: In Phase 1, record _Unwind_GetIP in xh->obj as a part of
215  // the stack trace for this exception.  This will only collect Java
216  // frames, but perhaps that is acceptable.
217  // FIXME2: _Unwind_GetIP is nonsensical for SJLJ, being a call-site
218  // index instead of a PC value.  We could perhaps arrange for
219  // _Unwind_GetRegionStart to return context->fc->jbuf[1], which
220  // is the address of the handler label for __builtin_longjmp, but
221  // there is no solution for DONT_USE_BUILTIN_SETJMP.
222
223  language_specific_data = (const unsigned char *)
224    _Unwind_GetLanguageSpecificData (context);
225
226  // If no LSDA, then there are no handlers or cleanups.
227  if (! language_specific_data)
228    return _URC_CONTINUE_UNWIND;
229
230  // Parse the LSDA header.
231  p = parse_lsda_header (context, language_specific_data, &info);
232  ip = _Unwind_GetIP (context) - 1;
233  landing_pad = 0;
234  action_record = 0;
235  handler_switch_value = 0;
236
237#ifdef SJLJ_EXCEPTIONS
238  // The given "IP" is an index into the call-site table, with two
239  // exceptions -- -1 means no-action, and 0 means terminate.  But
240  // since we're using uleb128 values, we've not got random access
241  // to the array.
242  if ((int) ip <= 0)
243    return _URC_CONTINUE_UNWIND;
244  else
245    {
246      _Unwind_Word cs_lp, cs_action;
247      do
248        {
249          p = read_uleb128 (p, &cs_lp);
250          p = read_uleb128 (p, &cs_action);
251        }
252      while (--ip);
253
254      // Can never have null landing pad for sjlj -- that would have
255      // been indicated by a -1 call site index.
256      landing_pad = cs_lp + 1;
257      if (cs_action)
258        action_record = info.action_table + cs_action - 1;
259      goto found_something;
260    }
261#else
262  // Search the call-site table for the action associated with this IP.
263  while (p < info.action_table)
264    {
265      _Unwind_Ptr cs_start, cs_len, cs_lp;
266      _Unwind_Word cs_action;
267
268      // Note that all call-site encodings are "absolute" displacements.
269      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
270      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
271      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
272      p = read_uleb128 (p, &cs_action);
273
274      // The table is sorted, so if we've passed the ip, stop.
275      if (ip < info.Start + cs_start)
276        p = info.action_table;
277      else if (ip < info.Start + cs_start + cs_len)
278        {
279          if (cs_lp)
280            landing_pad = info.LPStart + cs_lp;
281          if (cs_action)
282            action_record = info.action_table + cs_action - 1;
283          goto found_something;
284        }
285    }
286#endif // SJLJ_EXCEPTIONS
287
288  // If ip is not present in the table, C++ would call terminate.
289  // ??? It is perhaps better to tweek the LSDA so that no-action
290  // is mapped to no-entry for Java.
291  return _URC_CONTINUE_UNWIND;
292
293 found_something:
294  saw_cleanup = false;
295  saw_handler = false;
296
297  if (landing_pad == 0)
298    {
299      // If ip is present, and has a null landing pad, there are
300      // no cleanups or handlers to be run.
301    }
302  else if (action_record == 0)
303    {
304      // If ip is present, has a non-null landing pad, and a null
305      // action table offset, then there are only cleanups present.
306      // Cleanups use a zero switch value, as set above.
307      saw_cleanup = true;
308    }
309  else
310    {
311      // Otherwise we have a catch handler.
312      _Unwind_Sword ar_filter, ar_disp;
313
314      while (1)
315        {
316          p = action_record;
317          p = read_sleb128 (p, &ar_filter);
318          read_sleb128 (p, &ar_disp);
319
320          if (ar_filter == 0)
321            {
322              // Zero filter values are cleanups.
323              saw_cleanup = true;
324            }
325
326          // During forced unwinding, we only run cleanups.  With a
327          // foreign exception class, we have no class info to match.
328          else if ((actions & _UA_FORCE_UNWIND)
329              || exception_class != __gcj_exception_class)
330            ;
331
332          else if (ar_filter > 0)
333            {
334              // Positive filter values are handlers.
335
336              jclass catch_type = get_ttype_entry (context, &info, ar_filter);
337
338              // The catch_type is either a (java::lang::Class*) or
339              // is one more than a (Utf8Const*).
340              if ((size_t)catch_type & 1)
341                catch_type = _Jv_FindClass ((Utf8Const*)catch_type - 1, NULL);
342
343              if (_Jv_IsInstanceOf (xh->value, catch_type))
344                {
345                  handler_switch_value = ar_filter;
346                  saw_handler = true;
347                  break;
348                }
349            }
350          else
351            {
352              // Negative filter values are exception specifications,
353              // which Java does not use.
354              // ??? Perhaps better to make them an index into a table
355              // of null-terminated strings instead of playing games
356              // with Utf8Const+1 as above.
357              abort ();
358            }
359
360          if (ar_disp == 0)
361            break;
362          action_record = p + ar_disp;
363        }
364    }
365
366  if (! saw_handler && ! saw_cleanup)
367    return _URC_CONTINUE_UNWIND;
368
369  if (actions & _UA_SEARCH_PHASE)
370    {
371      if (! saw_handler)
372        return _URC_CONTINUE_UNWIND;
373
374      // For domestic exceptions, we cache data from phase 1 for phase 2.
375      if (exception_class == __gcj_exception_class)
376        {
377          xh->handlerSwitchValue = handler_switch_value;
378          xh->landingPad = landing_pad;
379        }
380      return _URC_HANDLER_FOUND;
381    }
382
383 install_context:
384  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
385                 (_Unwind_Ptr) &xh->unwindHeader);
386  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
387                 handler_switch_value);
388  _Unwind_SetIP (context, landing_pad);
389  return _URC_INSTALL_CONTEXT;
390}
Note: See TracBrowser for help on using the repository browser.