diff options
Diffstat (limited to 'libjava/exception.cc')
-rw-r--r-- | libjava/exception.cc | 118 |
1 files changed, 108 insertions, 10 deletions
diff --git a/libjava/exception.cc b/libjava/exception.cc index 4875dfd..3a8fe46 100644 --- a/libjava/exception.cc +++ b/libjava/exception.cc @@ -58,6 +58,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<java_exception_header *>(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' @@ -75,6 +90,7 @@ get_exception_header_from_ue (_Unwind_Exception *exc) { return reinterpret_cast<java_exception_header *>(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. */ @@ -89,7 +105,8 @@ _Jv_Throw (jthrowable value) 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 @@ -159,6 +176,21 @@ parse_lsda_header (_Unwind_Context *context, const unsigned char *p, return p; } +#ifdef __ARM_EABI_UNWINDER__ + +static void ** +get_ttype_entry(_Unwind_Context *, lsda_header_info* info, _uleb128_t i) +{ + _Unwind_Ptr ptr; + + ptr = (_Unwind_Ptr) (info->TType - (i * 4)); + ptr = _Unwind_decode_target2(ptr); + + return reinterpret_cast<void **>(ptr); +} + +#else + static void ** get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) { @@ -170,6 +202,7 @@ get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) return reinterpret_cast<void **>(ptr); } +#endif // Using a different personality function name causes link failures // when trying to mix code using different exception handling models. @@ -180,12 +213,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); @@ -197,16 +251,56 @@ 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; @@ -227,17 +321,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); #ifdef HAVE_GETIPINFO ip = _Unwind_GetIPInfo (context, &ip_before_insn); - if (! ip_before_insn) - --ip; #else ip = _Unwind_GetIP (context) - 1; #endif + if (! ip_before_insn) + --ip; landing_pad = 0; action_record = 0; handler_switch_value = 0; @@ -296,7 +390,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; @@ -334,7 +428,7 @@ 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) @@ -374,15 +468,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; @@ -396,5 +490,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; } |