OSDN Git Service

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