2002-11-21 Phil Edwards <pme@gcc.gnu.org>
[official-gcc.git] / libjava / exception.cc
blob917d6e10a76e502dfb40bd2e48b24fa6fd250f2f
1 // Functions for Exception Support for Java.
3 /* Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 #include <config.h>
13 #include <stddef.h>
14 #include <stdlib.h>
16 #include <java/lang/Class.h>
17 #include <java/lang/NullPointerException.h>
18 #include <gcj/cni.h>
19 #include <jvm.h>
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().
24 namespace std
26 static __attribute__ ((__noreturn__)) void
27 abort ()
29 ::abort ();
32 #include "unwind.h"
34 struct alignment_test_struct
36 char space;
37 char end[0] __attribute__((aligned));
40 struct java_exception_header
42 /* Cache handler details between Phase 1 and Phase 2. */
43 _Unwind_Ptr landingPad;
44 int handlerSwitchValue;
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)). */
50 char pad[sizeof(jthrowable) < sizeof(alignment_test_struct)
51 ? sizeof(alignment_test_struct) - sizeof(jthrowable) : 0]
52 __attribute__((aligned));
54 jthrowable value;
56 /* The generic exception header. */
57 _Unwind_Exception unwindHeader;
60 // This is the exception class we report -- "GNUCJAVA".
61 const _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');
72 static inline java_exception_header *
73 get_exception_header_from_ue (_Unwind_Exception *exc)
75 return reinterpret_cast<java_exception_header *>(exc + 1) - 1;
78 /* Perform a throw, Java style. Throw will unwind through this call,
79 so there better not be any handlers or exception thrown here. */
81 extern "C" void
82 _Jv_Throw (jthrowable value)
84 java_exception_header *xh
85 = static_cast<java_exception_header *>(_Jv_AllocRawObj (sizeof (*xh)));
87 if (value == NULL)
88 value = new java::lang::NullPointerException ();
89 xh->value = value;
91 xh->unwindHeader.exception_class = __gcj_exception_class;
92 xh->unwindHeader.exception_cleanup = NULL;
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
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();
114 #include "unwind-pe.h"
116 struct lsda_header_info
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;
126 static const unsigned char *
127 parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
128 lsda_header_info *info)
130 _Unwind_Word tmp;
131 unsigned char lpstart_encoding;
133 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
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;
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)
146 p = read_uleb128 (p, &tmp);
147 info->TType = p + tmp;
149 else
150 info->TType = 0;
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;
158 return p;
161 static jclass
162 get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
164 _Unwind_Ptr ptr;
166 i *= size_of_encoded_value (info->ttype_encoding);
167 read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
169 return reinterpret_cast<jclass>(ptr);
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
182 extern "C" _Unwind_Reason_Code
183 PERSONALITY_FUNCTION (int version,
184 _Unwind_Action actions,
185 _Unwind_Exception_Class exception_class,
186 struct _Unwind_Exception *ue_header,
187 struct _Unwind_Context *context)
189 java_exception_header *xh = get_exception_header_from_ue (ue_header);
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;
201 // Interface version check.
202 if (version != 1)
203 return _URC_FATAL_PHASE1_ERROR;
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)
209 handler_switch_value = xh->handlerSwitchValue;
210 landing_pad = xh->landingPad;
211 goto install_context;
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.
223 language_specific_data = (const unsigned char *)
224 _Unwind_GetLanguageSpecificData (context);
226 // If no LSDA, then there are no handlers or cleanups.
227 if (! language_specific_data)
228 return _URC_CONTINUE_UNWIND;
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;
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
246 _Unwind_Word cs_lp, cs_action;
249 p = read_uleb128 (p, &cs_lp);
250 p = read_uleb128 (p, &cs_action);
252 while (--ip);
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;
261 #else
262 // Search the call-site table for the action associated with this IP.
263 while (p < info.action_table)
265 _Unwind_Ptr cs_start, cs_len, cs_lp;
266 _Unwind_Word cs_action;
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);
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)
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;
286 #endif // SJLJ_EXCEPTIONS
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;
293 found_something:
294 saw_cleanup = false;
295 saw_handler = false;
297 if (landing_pad == 0)
299 // If ip is present, and has a null landing pad, there are
300 // no cleanups or handlers to be run.
302 else if (action_record == 0)
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;
309 else
311 // Otherwise we have a catch handler.
312 _Unwind_Sword ar_filter, ar_disp;
314 while (1)
316 p = action_record;
317 p = read_sleb128 (p, &ar_filter);
318 read_sleb128 (p, &ar_disp);
320 if (ar_filter == 0)
322 // Zero filter values are cleanups.
323 saw_cleanup = true;
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)
332 else if (ar_filter > 0)
334 // Positive filter values are handlers.
336 jclass catch_type = get_ttype_entry (context, &info, ar_filter);
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);
343 if (_Jv_IsInstanceOf (xh->value, catch_type))
345 handler_switch_value = ar_filter;
346 saw_handler = true;
347 break;
350 else
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 ();
360 if (ar_disp == 0)
361 break;
362 action_record = p + ar_disp;
366 if (! saw_handler && ! saw_cleanup)
367 return _URC_CONTINUE_UNWIND;
369 if (actions & _UA_SEARCH_PHASE)
371 if (! saw_handler)
372 return _URC_CONTINUE_UNWIND;
374 // For domestic exceptions, we cache data from phase 1 for phase 2.
375 if (exception_class == __gcj_exception_class)
377 xh->handlerSwitchValue = handler_switch_value;
378 xh->landingPad = landing_pad;
380 return _URC_HANDLER_FOUND;
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;