OSDN Git Service

2001-04-02 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
[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 <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 #include "unwind.h"
22
23 \f
24 // More nastiness: the GC wants to define TRUE and FALSE.  We don't
25 // need the Java definitions (themselves a hack), so we undefine them.
26 #undef TRUE
27 #undef FALSE
28
29 extern "C"
30 {
31 #include <gc_priv.h>
32 #include <gc_mark.h>
33 #include <include/gc_gcj.h>
34 };
35
36 \f
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   /* FIXME: Use the proper API to the collector.  */
88   java_exception_header *xh
89     = static_cast<java_exception_header *>(GC_malloc (sizeof (*xh)));
90
91   if (value == NULL)
92     value = new java::lang::NullPointerException ();
93   xh->value = value;
94
95   xh->unwindHeader.exception_class = __gcj_exception_class;
96   xh->unwindHeader.exception_cleanup = NULL;
97
98   /* We're happy with setjmp/longjmp exceptions or region-based
99      exception handlers: entry points are provided here for both.  */
100   _Unwind_Reason_Code code;
101 #ifdef SJLJ_EXCEPTIONS
102   code = _Unwind_SjLj_RaiseException (&xh->unwindHeader);
103 #else
104   code = _Unwind_RaiseException (&xh->unwindHeader);
105 #endif
106
107   /* FIXME: If code == _URC_END_OF_STACK, then we reached top of
108      stack without finding a handler for the exception.  I seem to
109      recall that Java has specific rules to handle this. 
110
111      If code is something else, we encountered some sort of heinous
112      lossage, from which we could not recover.  As is the way of such
113      things we'll almost certainly have crashed before now, rather
114      than actually being able to diagnose the problem.  */
115   abort ();
116 }
117
118 \f
119 // ??? These ought to go somewhere else dwarf2 or dwarf2eh related.
120
121 // Pointer encodings.
122 #define DW_EH_PE_absptr         0x00
123 #define DW_EH_PE_omit           0xff
124
125 #define DW_EH_PE_uleb128        0x01
126 #define DW_EH_PE_udata2         0x02
127 #define DW_EH_PE_udata4         0x03
128 #define DW_EH_PE_udata8         0x04
129 #define DW_EH_PE_sleb128        0x09
130 #define DW_EH_PE_sdata2         0x0A
131 #define DW_EH_PE_sdata4         0x0B
132 #define DW_EH_PE_sdata8         0x0C
133 #define DW_EH_PE_signed         0x08
134
135 #define DW_EH_PE_pcrel          0x10
136 #define DW_EH_PE_textrel        0x20
137 #define DW_EH_PE_datarel        0x30
138 #define DW_EH_PE_funcrel        0x40
139
140 static unsigned int
141 size_of_encoded_value (unsigned char encoding)
142 {
143   switch (encoding & 0x07)
144     {
145     case DW_EH_PE_absptr:
146       return sizeof (void *);
147     case DW_EH_PE_udata2:
148       return 2;
149     case DW_EH_PE_udata4:
150       return 4;
151     case DW_EH_PE_udata8:
152       return 8;
153     }
154   abort ();
155 }
156
157 static const unsigned char *
158 read_encoded_value (_Unwind_Context *context, unsigned char encoding,
159                     const unsigned char *p, _Unwind_Ptr *val)
160 {
161   union unaligned
162     {
163       void *ptr;
164       unsigned u2 __attribute__ ((mode (HI)));
165       unsigned u4 __attribute__ ((mode (SI)));
166       unsigned u8 __attribute__ ((mode (DI)));
167       signed s2 __attribute__ ((mode (HI)));
168       signed s4 __attribute__ ((mode (SI)));
169       signed s8 __attribute__ ((mode (DI)));
170     } __attribute__((__packed__));
171
172   union unaligned *u = (union unaligned *) p;
173   _Unwind_Ptr result;
174
175   switch (encoding & 0x0f)
176     {
177     case DW_EH_PE_absptr:
178       result = (_Unwind_Ptr) u->ptr;
179       p += sizeof (void *);
180       break;
181
182     case DW_EH_PE_uleb128:
183       {
184         unsigned int shift = 0;
185         unsigned char byte;
186
187         result = 0;
188         do
189           {
190             byte = *p++;
191             result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
192             shift += 7;
193           }
194         while (byte & 0x80);
195       }
196       break;
197
198     case DW_EH_PE_sleb128:
199       {
200         unsigned int shift = 0;
201         unsigned char byte;
202
203         result = 0;
204         do
205           {
206             byte = *p++;
207             result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
208             shift += 7;
209           }
210         while (byte & 0x80);
211
212         if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
213           result |= -(1L << shift);
214       }
215       break;
216
217     case DW_EH_PE_udata2:
218       result = u->u2;
219       p += 2;
220       break;
221     case DW_EH_PE_udata4:
222       result = u->u4;
223       p += 4;
224       break;
225     case DW_EH_PE_udata8:
226       result = u->u8;
227       p += 8;
228       break;
229
230     case DW_EH_PE_sdata2:
231       result = u->s2;
232       p += 2;
233       break;
234     case DW_EH_PE_sdata4:
235       result = u->s4;
236       p += 4;
237       break;
238     case DW_EH_PE_sdata8:
239       result = u->s8;
240       p += 8;
241       break;
242
243     default:
244       abort ();
245     }
246
247   if (result != 0)
248     switch (encoding & 0xf0)
249       {
250       case DW_EH_PE_absptr:
251         break;
252
253       case DW_EH_PE_pcrel:
254         // Define as relative to the beginning of the pointer.
255         result += (_Unwind_Ptr) u;
256         break;
257
258       case DW_EH_PE_textrel:
259       case DW_EH_PE_datarel:
260         // FIXME.
261         abort ();
262
263       case DW_EH_PE_funcrel:
264         result += _Unwind_GetRegionStart (context);
265         break;
266
267       default:
268         abort ();
269       }
270
271   *val = result;
272   return p;
273 }
274
275 static inline const unsigned char *
276 read_uleb128 (const unsigned char *p, _Unwind_Ptr *val)
277 {
278   return read_encoded_value (0, DW_EH_PE_uleb128, p, val);
279 }
280
281 static inline const unsigned char *
282 read_sleb128 (const unsigned char *p, _Unwind_Ptr *val)
283 {
284   return read_encoded_value (0, DW_EH_PE_sleb128, p, val);
285 }
286
287 \f
288 struct lsda_header_info
289 {
290   _Unwind_Ptr Start;
291   _Unwind_Ptr LPStart;
292   const unsigned char *TType;
293   const unsigned char *action_table;
294   unsigned char ttype_encoding;
295   unsigned char call_site_encoding;
296 };
297
298 static const unsigned char *
299 parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
300                    lsda_header_info *info)
301 {
302   _Unwind_Ptr tmp;
303   unsigned char lpstart_encoding;
304
305   info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
306
307   // Find @LPStart, the base to which landing pad offsets are relative.
308   lpstart_encoding = *p++;
309   if (lpstart_encoding != DW_EH_PE_omit)
310     p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
311   else
312     info->LPStart = info->Start;
313
314   // Find @TType, the base of the handler and exception spec type data.
315   info->ttype_encoding = *p++;
316   if (info->ttype_encoding != DW_EH_PE_omit)
317     {
318       p = read_uleb128 (p, &tmp);
319       info->TType = p + tmp;
320     }
321   else
322     info->TType = 0;
323
324   // The encoding and length of the call-site table; the action table
325   // immediately follows.
326   info->call_site_encoding = *p++;
327   p = read_uleb128 (p, &tmp);
328   info->action_table = p + tmp;
329
330   return p;
331 }
332
333 static jclass
334 get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
335 {
336   _Unwind_Ptr ptr;
337
338   i *= size_of_encoded_value (info->ttype_encoding);
339   read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
340
341   return reinterpret_cast<jclass>(ptr);
342 }
343
344
345 // Using a different personality function name causes link failures
346 // when trying to mix code using different exception handling models.
347 #ifdef SJLJ_EXCEPTIONS
348 #define PERSONALITY_FUNCTION    __gcj_personality_sj0
349 #define __builtin_eh_return_data_regno(x) x
350 #else
351 #define PERSONALITY_FUNCTION    __gcj_personality_v0
352 #endif
353
354 extern "C" _Unwind_Reason_Code
355 PERSONALITY_FUNCTION (int version,
356                       _Unwind_Action actions,
357                       _Unwind_Exception_Class exception_class,
358                       struct _Unwind_Exception *ue_header,
359                       struct _Unwind_Context *context)
360 {
361   java_exception_header *xh = get_exception_header_from_ue (ue_header);
362
363   lsda_header_info info;
364   const unsigned char *language_specific_data;
365   const unsigned char *action_record;
366   const unsigned char *p;
367   _Unwind_Ptr landing_pad, ip;
368   int handler_switch_value;
369   bool saw_cleanup;
370   bool saw_handler;
371
372
373   // Interface version check.
374   if (version != 1)
375     return _URC_FATAL_PHASE1_ERROR;
376
377   // Shortcut for phase 2 found handler for domestic exception.
378   if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
379       && exception_class == __gcj_exception_class)
380     {
381       handler_switch_value = xh->handlerSwitchValue;
382       landing_pad = xh->landingPad;
383       goto install_context;
384     }
385
386   // FIXME: In Phase 1, record _Unwind_GetIP in xh->obj as a part of
387   // the stack trace for this exception.  This will only collect Java
388   // frames, but perhaps that is acceptable.
389   // FIXME2: _Unwind_GetIP is nonsensical for SJLJ, being a call-site
390   // index instead of a PC value.  We could perhaps arrange for
391   // _Unwind_GetRegionStart to return context->fc->jbuf[1], which
392   // is the address of the handler label for __builtin_longjmp, but
393   // there is no solution for DONT_USE_BUILTIN_SETJMP.
394
395   language_specific_data = (const unsigned char *)
396     _Unwind_GetLanguageSpecificData (context);
397
398   // If no LSDA, then there are no handlers or cleanups.
399   if (! language_specific_data)
400     return _URC_CONTINUE_UNWIND;
401
402   // Parse the LSDA header.
403   p = parse_lsda_header (context, language_specific_data, &info);
404   ip = _Unwind_GetIP (context) - 1;
405   landing_pad = 0;
406   action_record = 0;
407   handler_switch_value = 0;
408
409 #ifdef SJLJ_EXCEPTIONS
410   // The given "IP" is an index into the call-site table, with two
411   // exceptions -- -1 means no-action, and 0 means terminate.  But
412   // since we're using uleb128 values, we've not got random access
413   // to the array.
414   if ((int) ip <= 0)
415     return _URC_CONTINUE_UNWIND;
416   else
417     {
418       _Unwind_Ptr cs_lp, cs_action;
419       do
420         {
421           p = read_uleb128 (p, &cs_lp);
422           p = read_uleb128 (p, &cs_action);
423         }
424       while (--ip);
425
426       // Can never have null landing pad for sjlj -- that would have
427       // been indicated by a -1 call site index.
428       landing_pad = cs_lp + 1;
429       if (cs_action)
430         action_record = info.action_table + cs_action - 1;
431       goto found_something;
432     }
433 #else
434   // Search the call-site table for the action associated with this IP.
435   while (p < info.action_table)
436     {
437       _Unwind_Ptr cs_start, cs_len, cs_lp, cs_action;
438
439       // Note that all call-site encodings are "absolute" displacements.
440       p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
441       p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
442       p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
443       p = read_uleb128 (p, &cs_action);
444
445       // The table is sorted, so if we've passed the ip, stop.
446       if (ip < info.Start + cs_start)
447         p = info.action_table;
448       else if (ip < info.Start + cs_start + cs_len)
449         {
450           if (cs_lp)
451             landing_pad = info.LPStart + cs_lp;
452           if (cs_action)
453             action_record = info.action_table + cs_action - 1;
454           goto found_something;
455         }
456     }
457 #endif // SJLJ_EXCEPTIONS
458
459   // If ip is not present in the table, C++ would call terminate.
460   // ??? It is perhaps better to tweek the LSDA so that no-action
461   // is mapped to no-entry for Java.
462   return _URC_CONTINUE_UNWIND;
463
464  found_something:
465   saw_cleanup = false;
466   saw_handler = false;
467
468   if (landing_pad == 0)
469     {
470       // If ip is present, and has a null landing pad, there are
471       // no cleanups or handlers to be run.
472     }
473   else if (action_record == 0)
474     {
475       // If ip is present, has a non-null landing pad, and a null
476       // action table offset, then there are only cleanups present.
477       // Cleanups use a zero switch value, as set above.
478       saw_cleanup = true;
479     }
480   else
481     {
482       // Otherwise we have a catch handler.
483       signed long ar_filter, ar_disp;
484
485       while (1)
486         {
487           _Unwind_Ptr tmp;
488
489           p = action_record;
490           p = read_sleb128 (p, &tmp); ar_filter = tmp;
491           read_sleb128 (p, &tmp); ar_disp = tmp;
492
493           if (ar_filter == 0)
494             {
495               // Zero filter values are cleanups.
496               saw_cleanup = true;
497             }
498
499           // During forced unwinding, we only run cleanups.  With a
500           // foreign exception class, we have no class info to match.
501           else if ((actions & _UA_FORCE_UNWIND)
502               || exception_class != __gcj_exception_class)
503             ;
504
505           else if (ar_filter > 0)
506             {
507               // Positive filter values are handlers.
508
509               jclass catch_type = get_ttype_entry (context, &info, ar_filter);
510
511               // The catch_type is either a (java::lang::Class*) or
512               // is one more than a (Utf8Const*).
513               if ((size_t)catch_type & 1)
514                 catch_type = _Jv_FindClass ((Utf8Const*)catch_type - 1, NULL);
515
516               if (_Jv_IsInstanceOf (xh->value, catch_type))
517                 {
518                   handler_switch_value = ar_filter;
519                   saw_handler = true;
520                   break;
521                 }
522             }
523           else
524             {
525               // Negative filter values are exception specifications,
526               // which Java does not use.
527               // ??? Perhaps better to make them an index into a table
528               // of null-terminated strings instead of playing games
529               // with Utf8Const+1 as above.
530               abort ();
531             }
532
533           if (ar_disp == 0)
534             break;
535           action_record = p + ar_disp;
536         }
537     }
538
539   if (! saw_handler && ! saw_cleanup)
540     return _URC_CONTINUE_UNWIND;
541
542   if (actions & _UA_SEARCH_PHASE)
543     {
544       if (! saw_handler)
545         return _URC_CONTINUE_UNWIND;
546
547       // For domestic exceptions, we cache data from phase 1 for phase 2.
548       if (exception_class == __gcj_exception_class)
549         {
550           xh->handlerSwitchValue = handler_switch_value;
551           xh->landingPad = landing_pad;
552         }
553       return _URC_HANDLER_FOUND;
554     }
555
556  install_context:
557   _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
558                  (_Unwind_Ptr) &xh->unwindHeader);
559   _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
560                  handler_switch_value);
561   _Unwind_SetIP (context, landing_pad);
562   return _URC_INSTALL_CONTEXT;
563 }