OSDN Git Service

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