diff --git a/ChangeLog b/ChangeLog index e52412498bd..0926f4e71c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-05-30 Julian Brown + + * configure.ac (arm*-*-linux-gnueabi): Don't disable building + of libobjc for ARM EABI Linux. + * configure: Regenerate. 2008-05-18 Xinliang David Li diff --git a/configure b/configure index 92f62a34d7a..213befb5751 100755 --- a/configure +++ b/configure @@ -2309,7 +2309,6 @@ case "${target}" in ;; arm*-*-linux-gnueabi) noconfigdirs="$noconfigdirs target-qthreads" - noconfigdirs="$noconfigdirs target-libobjc" case ${with_newlib} in no) noconfigdirs="$noconfigdirs target-newlib target-libgloss" esac diff --git a/configure.ac b/configure.ac index 13a7cc1c092..3b443e5a509 100644 --- a/configure.ac +++ b/configure.ac @@ -563,7 +563,6 @@ case "${target}" in ;; arm*-*-linux-gnueabi) noconfigdirs="$noconfigdirs target-qthreads" - noconfigdirs="$noconfigdirs target-libobjc" case ${with_newlib} in no) noconfigdirs="$noconfigdirs target-newlib target-libgloss" esac diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index df30eaae50c..fa0e059e089 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,3 +1,16 @@ +2008-05-30 Julian Brown + + * exception.c (__objc_exception_class): Initialise as constant + array for ARM EABI. Change macro to static const for non-ARM EABI. + (ObjcException): Add note about structure layout. Remove landingPad + and handlerSwitchValue for ARM EABI. + (get_ttype_entry): Add __ARM_EABI_UNWINDER__ version + of function. + (CONTINUE_UNWINDING): Define for ARM EABI/otherwise cases. + (PERSONALITY_FUNCTION): Use ARM EABI-specific arguments, and add + ARM EABI unwinding support. + (objc_exception_throw): Use memcpy to initialise exception class. + 2008-05-25 Alan Modra * encoding.c (strip_array_types): Rename from get_inner_array_type. diff --git a/libobjc/exception.c b/libobjc/exception.c index 4777c3bdd41..1a6b9dab4d1 100644 --- a/libobjc/exception.c +++ b/libobjc/exception.c @@ -31,16 +31,25 @@ Boston, MA 02110-1301, USA. */ #include "unwind-pe.h" +#ifdef __ARM_EABI_UNWINDER__ + +const _Unwind_Exception_Class __objc_exception_class + = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'}; + +#else + /* This is the exception class we report -- "GNUCOBJC". */ -#define __objc_exception_class \ - ((((((((_Unwind_Exception_Class) 'G' \ - << 8 | (_Unwind_Exception_Class) 'N') \ - << 8 | (_Unwind_Exception_Class) 'U') \ - << 8 | (_Unwind_Exception_Class) 'C') \ - << 8 | (_Unwind_Exception_Class) 'O') \ - << 8 | (_Unwind_Exception_Class) 'B') \ - << 8 | (_Unwind_Exception_Class) 'J') \ - << 8 | (_Unwind_Exception_Class) 'C') +static const _Unwind_Exception_Class __objc_exception_class + = ((((((((_Unwind_Exception_Class) 'G' + << 8 | (_Unwind_Exception_Class) 'N') + << 8 | (_Unwind_Exception_Class) 'U') + << 8 | (_Unwind_Exception_Class) 'C') + << 8 | (_Unwind_Exception_Class) 'O') + << 8 | (_Unwind_Exception_Class) 'B') + << 8 | (_Unwind_Exception_Class) 'J') + << 8 | (_Unwind_Exception_Class) 'C'); + +#endif /* This is the object that is passed around by the Objective C runtime to represent the exception in flight. */ @@ -50,12 +59,18 @@ struct ObjcException /* This bit is needed in order to interact with the unwind runtime. */ struct _Unwind_Exception base; - /* The actual object we want to throw. */ + /* The actual object we want to throw. Note: must come immediately after + unwind header. */ id value; +#ifdef __ARM_EABI_UNWINDER__ + /* Note: we use the barrier cache defined in the unwind control block for + ARM EABI. */ +#else /* Cache some internal unwind data between phase 1 and phase 2. */ _Unwind_Ptr landingPad; int handlerSwitchValue; +#endif }; @@ -106,6 +121,24 @@ parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, return p; } +#ifdef __ARM_EABI_UNWINDER__ + +static Class +get_ttype_entry (struct lsda_header_info *info, _uleb128_t i) +{ + _Unwind_Ptr ptr; + + ptr = (_Unwind_Ptr) (info->TType - (i * 4)); + ptr = _Unwind_decode_target2 (ptr); + + if (ptr) + return objc_get_class ((const char *) ptr); + else + return 0; +} + +#else + static Class get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i) { @@ -122,6 +155,8 @@ get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i) return 0; } +#endif + /* Like unto the method of the same name on Object, but takes an id. */ /* ??? Does this bork the meta-type system? Can/should we look up an isKindOf method on the id? */ @@ -150,12 +185,32 @@ isKindOf (id value, Class target) #define PERSONALITY_FUNCTION __gnu_objc_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) + +_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 + _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 { struct ObjcException *xh = (struct ObjcException *) ue_header; @@ -165,19 +220,65 @@ PERSONALITY_FUNCTION (int version, const unsigned char *p; _Unwind_Ptr landing_pad, ip; int handler_switch_value; - int saw_cleanup = 0, saw_handler; + int saw_cleanup = 0, saw_handler, foreign_exception; void *return_object; + 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: + abort(); + } + actions |= state & _US_FORCE_UNWIND; + + /* TODO: Foreign exceptions need some attention (e.g. rethrowing doesn't + work). */ + foreign_exception = 0; + + /* 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 /* !__ARM_EABI_UNWINDER. */ /* Interface version check. */ if (version != 1) return _URC_FATAL_PHASE1_ERROR; + + foreign_exception = (exception_class != __objc_exception_class); +#endif /* Shortcut for phase 2 found handler for domestic exception. */ if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) - && exception_class == __objc_exception_class) + && !foreign_exception) { +#ifdef __ARM_EABI_UNWINDER__ + handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1]; + landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3]; +#else handler_switch_value = xh->handlerSwitchValue; landing_pad = xh->landingPad; +#endif goto install_context; } @@ -186,12 +287,18 @@ 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); info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); +#ifdef HAVE_GETIPINFO + ip = _Unwind_GetIPInfo (context, &ip_before_insn); +#else ip = _Unwind_GetIP (context) - 1; +#endif + if (!ip_before_insn) + --ip; landing_pad = 0; action_record = 0; handler_switch_value = 0; @@ -250,7 +357,7 @@ PERSONALITY_FUNCTION (int version, /* If ip is not present in the table, C++ would call terminate. */ /* ??? As with Java, it's perhaps better to tweek the LSDA to that no-action is mapped to no-entry. */ - return _URC_CONTINUE_UNWIND; + CONTINUE_UNWINDING; found_something: saw_cleanup = 0; @@ -287,8 +394,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 != __objc_exception_class) + else if ((actions & _UA_FORCE_UNWIND) || foreign_exception) ; else if (ar_filter > 0) @@ -318,18 +424,24 @@ 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 == __objc_exception_class) + if (!foreign_exception) { +#ifdef __ARM_EABI_UNWINDER__ + ue_header->barrier_cache.sp = _Unwind_GetGR (context, 13); + ue_header->barrier_cache.bitpattern[1] = (_uw) handler_switch_value; + ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad; +#else xh->handlerSwitchValue = handler_switch_value; xh->landingPad = landing_pad; +#endif } return _URC_HANDLER_FOUND; } @@ -361,7 +473,9 @@ void objc_exception_throw (id value) { struct ObjcException *header = calloc (1, sizeof (*header)); - header->base.exception_class = __objc_exception_class; + + memcpy (&header->base.exception_class, &__objc_exception_class, + sizeof (__objc_exception_class)); header->base.exception_cleanup = __objc_exception_cleanup; header->value = value;