OSDN Git Service

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