X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fexception.cc;h=56f25ad44be5adb6198676bfa6c9743e4981fc07;hb=3928e1673550207936e709c225102087b0ddc6cb;hp=41f7676063e4f755a16c0d0f60bbbdd12c46eb0d;hpb=df4b504cae7856b864a073ab9e6e61cf2ad23a97;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/exception.cc b/libjava/exception.cc index 41f7676063e..56f25ad44be 100644 --- a/libjava/exception.cc +++ b/libjava/exception.cc @@ -1,6 +1,7 @@ // Functions for Exception Support for Java. -/* Copyright (C) 1998, 1999, 2001 Free Software Foundation +/* Copyright (C) 1998, 1999, 2001, 2002, 2006, 2010, 2011 + Free Software Foundation This file is part of libgcj. @@ -15,25 +16,23 @@ details. */ #include #include +#include #include #include -#include "unwind.h" - - -// More nastiness: the GC wants to define TRUE and FALSE. We don't -// need the Java definitions (themselves a hack), so we undefine them. -#undef TRUE -#undef FALSE - -extern "C" +// unwind-pe.h uses std::abort(), but sometimes we compile libjava +// without libstdc++-v3. The following hack forces it to use +// stdlib.h's abort(). +namespace std { -#include -#include -#include -}; + __attribute__ ((__noreturn__)) void + abort () + { + ::abort (); + } +} +#include "unwind.h" - struct alignment_test_struct { char space; @@ -60,6 +59,21 @@ struct java_exception_header _Unwind_Exception unwindHeader; }; +#ifdef __ARM_EABI_UNWINDER__ +// This is the exception class we report -- "GNUCJAVA". + +const _Unwind_Exception_Class __gcj_exception_class + = {'G', 'N', 'U', 'C', 'J', 'A', 'V', 'A'}; + +static inline java_exception_header * +get_exception_header_from_ue (_Unwind_Exception *exc) +{ + return reinterpret_cast(exc + 1) - 1; +} + +extern "C" void __cxa_begin_cleanup (_Unwind_Exception*); + +#else // !__ARM_EABI_UNWINDER__ // This is the exception class we report -- "GNUCJAVA". const _Unwind_Exception_Class __gcj_exception_class = ((((((((_Unwind_Exception_Class) 'G' @@ -77,6 +91,7 @@ get_exception_header_from_ue (_Unwind_Exception *exc) { return reinterpret_cast(exc + 1) - 1; } +#endif // !__ARM_EABI_UNWINDER__ /* Perform a throw, Java style. Throw will unwind through this call, so there better not be any handlers or exception thrown here. */ @@ -84,206 +99,37 @@ get_exception_header_from_ue (_Unwind_Exception *exc) extern "C" void _Jv_Throw (jthrowable value) { - /* FIXME: Use the proper API to the collector. */ java_exception_header *xh - = static_cast(GC_malloc (sizeof (*xh))); + = static_cast(_Jv_AllocRawObj (sizeof (*xh))); if (value == NULL) value = new java::lang::NullPointerException (); xh->value = value; - xh->unwindHeader.exception_class = __gcj_exception_class; + memcpy (&xh->unwindHeader.exception_class, &__gcj_exception_class, + sizeof xh->unwindHeader.exception_class); xh->unwindHeader.exception_cleanup = NULL; /* We're happy with setjmp/longjmp exceptions or region-based exception handlers: entry points are provided here for both. */ - _Unwind_Reason_Code code; #ifdef SJLJ_EXCEPTIONS - code = _Unwind_SjLj_RaiseException (&xh->unwindHeader); + _Unwind_SjLj_RaiseException (&xh->unwindHeader); #else - code = _Unwind_RaiseException (&xh->unwindHeader); + _Unwind_RaiseException (&xh->unwindHeader); #endif - /* FIXME: If code == _URC_END_OF_STACK, then we reached top of - stack without finding a handler for the exception. I seem to - recall that Java has specific rules to handle this. - - If code is something else, we encountered some sort of heinous - lossage, from which we could not recover. As is the way of such - things we'll almost certainly have crashed before now, rather - than actually being able to diagnose the problem. */ - abort (); + /* If code == _URC_END_OF_STACK, then we reached top of stack without + finding a handler for the exception. Since each thread is run in + a try/catch, this oughtn't happen. If code is something else, we + encountered some sort of heinous lossage from which we could not + recover. As is the way of such things, almost certainly we will have + crashed before now, rather than actually being able to diagnose the + problem. */ + abort(); } -// ??? These ought to go somewhere else dwarf2 or dwarf2eh related. - -// Pointer encodings. -#define DW_EH_PE_absptr 0x00 -#define DW_EH_PE_omit 0xff - -#define DW_EH_PE_uleb128 0x01 -#define DW_EH_PE_udata2 0x02 -#define DW_EH_PE_udata4 0x03 -#define DW_EH_PE_udata8 0x04 -#define DW_EH_PE_sleb128 0x09 -#define DW_EH_PE_sdata2 0x0A -#define DW_EH_PE_sdata4 0x0B -#define DW_EH_PE_sdata8 0x0C -#define DW_EH_PE_signed 0x08 - -#define DW_EH_PE_pcrel 0x10 -#define DW_EH_PE_textrel 0x20 -#define DW_EH_PE_datarel 0x30 -#define DW_EH_PE_funcrel 0x40 - -static unsigned int -size_of_encoded_value (unsigned char encoding) -{ - switch (encoding & 0x07) - { - case DW_EH_PE_absptr: - return sizeof (void *); - case DW_EH_PE_udata2: - return 2; - case DW_EH_PE_udata4: - return 4; - case DW_EH_PE_udata8: - return 8; - } - abort (); -} - -static const unsigned char * -read_encoded_value (_Unwind_Context *context, unsigned char encoding, - const unsigned char *p, _Unwind_Ptr *val) -{ - union unaligned - { - void *ptr; - unsigned u2 __attribute__ ((mode (HI))); - unsigned u4 __attribute__ ((mode (SI))); - unsigned u8 __attribute__ ((mode (DI))); - signed s2 __attribute__ ((mode (HI))); - signed s4 __attribute__ ((mode (SI))); - signed s8 __attribute__ ((mode (DI))); - } __attribute__((__packed__)); - - union unaligned *u = (union unaligned *) p; - _Unwind_Ptr result; - - switch (encoding & 0x0f) - { - case DW_EH_PE_absptr: - result = (_Unwind_Ptr) u->ptr; - p += sizeof (void *); - break; - - case DW_EH_PE_uleb128: - { - unsigned int shift = 0; - unsigned char byte; - - result = 0; - do - { - byte = *p++; - result |= (_Unwind_Ptr)(byte & 0x7f) << shift; - shift += 7; - } - while (byte & 0x80); - } - break; - - case DW_EH_PE_sleb128: - { - unsigned int shift = 0; - unsigned char byte; - - result = 0; - do - { - byte = *p++; - result |= (_Unwind_Ptr)(byte & 0x7f) << shift; - shift += 7; - } - while (byte & 0x80); - - if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) - result |= -(1L << shift); - } - break; - - case DW_EH_PE_udata2: - result = u->u2; - p += 2; - break; - case DW_EH_PE_udata4: - result = u->u4; - p += 4; - break; - case DW_EH_PE_udata8: - result = u->u8; - p += 8; - break; - - case DW_EH_PE_sdata2: - result = u->s2; - p += 2; - break; - case DW_EH_PE_sdata4: - result = u->s4; - p += 4; - break; - case DW_EH_PE_sdata8: - result = u->s8; - p += 8; - break; - - default: - abort (); - } - - if (result != 0) - switch (encoding & 0xf0) - { - case DW_EH_PE_absptr: - break; - - case DW_EH_PE_pcrel: - // Define as relative to the beginning of the pointer. - result += (_Unwind_Ptr) u; - break; - - case DW_EH_PE_textrel: - case DW_EH_PE_datarel: - // FIXME. - abort (); - - case DW_EH_PE_funcrel: - result += _Unwind_GetRegionStart (context); - break; - - default: - abort (); - } - - *val = result; - return p; -} - -static inline const unsigned char * -read_uleb128 (const unsigned char *p, _Unwind_Ptr *val) -{ - return read_encoded_value (0, DW_EH_PE_uleb128, p, val); -} - -static inline const unsigned char * -read_sleb128 (const unsigned char *p, _Unwind_Ptr *val) -{ - return read_encoded_value (0, DW_EH_PE_sleb128, p, val); -} - +#include "unwind-pe.h" struct lsda_header_info { @@ -299,7 +145,7 @@ static const unsigned char * parse_lsda_header (_Unwind_Context *context, const unsigned char *p, lsda_header_info *info) { - _Unwind_Ptr tmp; + _uleb128_t tmp; unsigned char lpstart_encoding; info->Start = (context ? _Unwind_GetRegionStart (context) : 0); @@ -315,6 +161,11 @@ parse_lsda_header (_Unwind_Context *context, const unsigned char *p, info->ttype_encoding = *p++; if (info->ttype_encoding != DW_EH_PE_omit) { +#if _GLIBCXX_OVERRIDE_TTYPE_ENCODING + /* Older ARM EABI toolchains set this value incorrectly, so use a + hardcoded OS-specific format. */ + info->ttype_encoding = _GLIBCXX_OVERRIDE_TTYPE_ENCODING; +#endif p = read_uleb128 (p, &tmp); info->TType = p + tmp; } @@ -330,7 +181,7 @@ parse_lsda_header (_Unwind_Context *context, const unsigned char *p, return p; } -static jclass +static void ** get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) { _Unwind_Ptr ptr; @@ -338,10 +189,9 @@ get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) i *= size_of_encoded_value (info->ttype_encoding); read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr); - return reinterpret_cast(ptr); + return reinterpret_cast(ptr); } - // Using a different personality function name causes link failures // when trying to mix code using different exception handling models. #ifdef SJLJ_EXCEPTIONS @@ -351,12 +201,33 @@ get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) #define PERSONALITY_FUNCTION __gcj_personality_v0 #endif +#ifdef __ARM_EABI_UNWINDER__ + +#define CONTINUE_UNWINDING \ + do \ + { \ + if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \ + return _URC_FAILURE; \ + return _URC_CONTINUE_UNWIND; \ + } \ + while (0) + +extern "C" _Unwind_Reason_Code +PERSONALITY_FUNCTION (_Unwind_State state, + struct _Unwind_Exception* ue_header, + struct _Unwind_Context* context) +#else + +#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND + extern "C" _Unwind_Reason_Code PERSONALITY_FUNCTION (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) + +#endif { java_exception_header *xh = get_exception_header_from_ue (ue_header); @@ -368,25 +239,66 @@ PERSONALITY_FUNCTION (int version, int handler_switch_value; bool saw_cleanup; bool saw_handler; + bool foreign_exception; + int ip_before_insn = 0; + +#ifdef __ARM_EABI_UNWINDER__ + _Unwind_Action actions; + + switch (state & _US_ACTION_MASK) + { + case _US_VIRTUAL_UNWIND_FRAME: + actions = _UA_SEARCH_PHASE; + break; + + case _US_UNWIND_FRAME_STARTING: + actions = _UA_CLEANUP_PHASE; + if (!(state & _US_FORCE_UNWIND) + && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13)) + actions |= _UA_HANDLER_FRAME; + break; + + case _US_UNWIND_FRAME_RESUME: + CONTINUE_UNWINDING; + break; + + default: + std::abort(); + } + actions |= state & _US_FORCE_UNWIND; + + // We don't know which runtime we're working with, so can't check this. + // However the ABI routines hide this from us, and we don't actually need + // to know. + foreign_exception = false; + // The dwarf unwinder assumes the context structure holds things like the + // function and LSDA pointers. The ARM implementation caches these in + // the exception header (UCB). To avoid rewriting everything we make the + // virtual IP register point at the UCB. + ip = (_Unwind_Ptr) ue_header; + _Unwind_SetGR(context, 12, ip); +#else // Interface version check. if (version != 1) return _URC_FATAL_PHASE1_ERROR; + foreign_exception = exception_class != __gcj_exception_class; +#endif // Shortcut for phase 2 found handler for domestic exception. if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) - && exception_class == __gcj_exception_class) + && !foreign_exception) { handler_switch_value = xh->handlerSwitchValue; landing_pad = xh->landingPad; goto install_context; } - // FIXME: In Phase 1, record _Unwind_GetIP in xh->obj as a part of + // FIXME: In Phase 1, record _Unwind_GetIPInfo in xh->obj as a part of // the stack trace for this exception. This will only collect Java // frames, but perhaps that is acceptable. - // FIXME2: _Unwind_GetIP is nonsensical for SJLJ, being a call-site + // FIXME2: _Unwind_GetIPInfo is nonsensical for SJLJ, being a call-site // index instead of a PC value. We could perhaps arrange for // _Unwind_GetRegionStart to return context->fc->jbuf[1], which // is the address of the handler label for __builtin_longjmp, but @@ -397,11 +309,17 @@ PERSONALITY_FUNCTION (int version, // If no LSDA, then there are no handlers or cleanups. if (! language_specific_data) - return _URC_CONTINUE_UNWIND; + CONTINUE_UNWINDING; // Parse the LSDA header. p = parse_lsda_header (context, language_specific_data, &info); - ip = _Unwind_GetIP (context) - 1; +#ifdef HAVE_GETIPINFO + ip = _Unwind_GetIPInfo (context, &ip_before_insn); +#else + ip = _Unwind_GetIP (context); +#endif + if (! ip_before_insn) + --ip; landing_pad = 0; action_record = 0; handler_switch_value = 0; @@ -415,7 +333,7 @@ PERSONALITY_FUNCTION (int version, return _URC_CONTINUE_UNWIND; else { - _Unwind_Ptr cs_lp, cs_action; + _uleb128_t cs_lp, cs_action; do { p = read_uleb128 (p, &cs_lp); @@ -434,7 +352,8 @@ PERSONALITY_FUNCTION (int version, // Search the call-site table for the action associated with this IP. while (p < info.action_table) { - _Unwind_Ptr cs_start, cs_len, cs_lp, cs_action; + _Unwind_Ptr cs_start, cs_len, cs_lp; + _uleb128_t cs_action; // Note that all call-site encodings are "absolute" displacements. p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); @@ -459,7 +378,7 @@ PERSONALITY_FUNCTION (int version, // If ip is not present in the table, C++ would call terminate. // ??? It is perhaps better to tweek the LSDA so that no-action // is mapped to no-entry for Java. - return _URC_CONTINUE_UNWIND; + CONTINUE_UNWINDING; found_something: saw_cleanup = false; @@ -480,15 +399,13 @@ PERSONALITY_FUNCTION (int version, else { // Otherwise we have a catch handler. - signed long ar_filter, ar_disp; + _sleb128_t ar_filter, ar_disp; while (1) { - _Unwind_Ptr tmp; - p = action_record; - p = read_sleb128 (p, &tmp); ar_filter = tmp; - read_sleb128 (p, &tmp); ar_disp = tmp; + p = read_sleb128 (p, &ar_filter); + read_sleb128 (p, &ar_disp); if (ar_filter == 0) { @@ -499,19 +416,21 @@ PERSONALITY_FUNCTION (int version, // During forced unwinding, we only run cleanups. With a // foreign exception class, we have no class info to match. else if ((actions & _UA_FORCE_UNWIND) - || exception_class != __gcj_exception_class) + || foreign_exception) ; else if (ar_filter > 0) { // Positive filter values are handlers. - jclass catch_type = get_ttype_entry (context, &info, ar_filter); + void **catch_word = get_ttype_entry (context, &info, ar_filter); + jclass catch_type = (jclass)*catch_word; - // The catch_type is either a (java::lang::Class*) or - // is one more than a (Utf8Const*). - if ((size_t)catch_type & 1) - catch_type = _Jv_FindClass ((Utf8Const*)catch_type - 1, NULL); + // FIXME: This line is a kludge to work around exception + // handlers written in C++, which don't yet use indirect + // dispatch. + if (catch_type == *(void **)&java::lang::Class::class$) + catch_type = (jclass)catch_word; if (_Jv_IsInstanceOf (xh->value, catch_type)) { @@ -537,15 +456,15 @@ PERSONALITY_FUNCTION (int version, } if (! saw_handler && ! saw_cleanup) - return _URC_CONTINUE_UNWIND; + CONTINUE_UNWINDING; if (actions & _UA_SEARCH_PHASE) { if (! saw_handler) - return _URC_CONTINUE_UNWIND; + CONTINUE_UNWINDING; // For domestic exceptions, we cache data from phase 1 for phase 2. - if (exception_class == __gcj_exception_class) + if (! foreign_exception) { xh->handlerSwitchValue = handler_switch_value; xh->landingPad = landing_pad; @@ -559,5 +478,9 @@ PERSONALITY_FUNCTION (int version, _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), handler_switch_value); _Unwind_SetIP (context, landing_pad); +#ifdef __ARM_EABI_UNWINDER__ + if (saw_cleanup) + __cxa_begin_cleanup(ue_header); +#endif return _URC_INSTALL_CONTEXT; }