2222
2323void test_cxx_eh_implementation ();
2424
25+ // Weak references to C++ runtime functions. We don't bother testing that
26+ // these are 0 before calling them, because if they are not resolved then we
27+ // should not be in a code path that involves a C++ exception.
28+ __attribute__((weak )) void * __cxa_begin_catch (void * e );
29+ __attribute__((weak )) void __cxa_end_catch (void );
30+ __attribute__((weak )) void __cxa_rethrow (void );
31+
2532
2633/**
2734 * Class of exceptions to distinguish between this and other exception types.
@@ -75,6 +82,35 @@ typedef enum
7582 handler_class
7683} handler_type ;
7784
85+ enum exception_type
86+ {
87+ NONE ,
88+ CXX ,
89+ OBJC ,
90+ FOREIGN ,
91+ BOXED_FOREIGN
92+ };
93+ struct thread_data
94+ {
95+ enum exception_type current_exception_type ;
96+ id lastThrownObject ;
97+ BOOL cxxCaughtException ;
98+ struct objc_exception * caughtExceptions ;
99+ };
100+
101+ static __thread struct thread_data thread_data ;
102+
103+ static struct thread_data * get_thread_data (void )
104+ {
105+ return & thread_data ;
106+ }
107+
108+ static struct thread_data * get_thread_data_fast (void )
109+ {
110+ return & thread_data ;
111+ }
112+
113+
78114/**
79115 * Saves the result of the landing pad that we have found. For ARM, this is
80116 * stored in the generic unwind structure, while on other platforms it is
@@ -147,13 +183,35 @@ static void cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *e)
147183 unwindHeader)));
148184 */
149185}
186+
187+ void objc_exception_rethrow (struct _Unwind_Exception * e );
188+
150189/**
151190 * Throws an Objective-C exception. This function is, unfortunately, used for
152191 * rethrowing caught exceptions too, even in @finally() blocks. Unfortunately,
153192 * this means that we have some problems if the exception is boxed.
154193 */
155194void objc_exception_throw (id object )
156195{
196+ struct thread_data * td = get_thread_data ();
197+ fprintf (stderr , "Throwing %p, in flight exception: %p\n" , object , td -> lastThrownObject );
198+ fprintf (stderr , "Exception caught by C++: %d\n" , td -> cxxCaughtException );
199+ // If C++ caught the exception, then we may need to make C++ rethrow it if
200+ // we want to preserve exception state. Rethrows should be handled with
201+ // objc_exception_rethrow, but clang appears to do the wrong thing for some
202+ // cases.
203+ if (td -> cxxCaughtException )
204+ {
205+ // For catchalls, we may result in our being passed the pointer to the
206+ // object, not the object.
207+ if ((object == td -> lastThrownObject ) ||
208+ ((object != nil ) &&
209+ !isSmallObject (object ) &&
210+ (* (id * )object == td -> lastThrownObject )))
211+ {
212+ __cxa_rethrow ();
213+ }
214+ }
157215
158216 SEL rethrow_sel = sel_registerName ("rethrow" );
159217 if ((nil != object ) &&
@@ -175,6 +233,9 @@ void objc_exception_throw(id object)
175233
176234 ex -> object = object ;
177235
236+ td -> lastThrownObject = object ;
237+ td -> cxxCaughtException = NO ;
238+
178239 _Unwind_Reason_Code err = _Unwind_RaiseException (& ex -> unwindHeader );
179240 free (ex );
180241 if (_URC_END_OF_STACK == err && 0 != _objc_unexpected_exception )
@@ -480,6 +541,7 @@ static inline _Unwind_Reason_Code internal_objc_personality(int version,
480541 _Unwind_SetGR (context , __builtin_eh_return_data_regno (1 ), selector );
481542
482543 DEBUG_LOG ("Installing context, selector %d\n" , (int )selector );
544+ get_thread_data ()-> cxxCaughtException = NO ;
483545 return _URC_INSTALL_CONTEXT ;
484546}
485547
@@ -513,48 +575,20 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
513575 int ret = CALL_PERSONALITY_FUNCTION (__gxx_personality_v0 );
514576 exceptionObject -> private_1 = ex -> cxx_exception -> private_1 ;
515577 exceptionObject -> private_2 = ex -> cxx_exception -> private_2 ;
578+ if (ret == _URC_INSTALL_CONTEXT )
579+ {
580+ get_thread_data ()-> cxxCaughtException = YES ;
581+ }
516582 return ret ;
517583 }
518584 return CALL_PERSONALITY_FUNCTION (__gxx_personality_v0 );
519585}
520586
521- // Weak references to C++ runtime functions. We don't bother testing that
522- // these are 0 before calling them, because if they are not resolved then we
523- // should not be in a code path that involves a C++ exception.
524- __attribute__((weak )) void * __cxa_begin_catch (void * e );
525- __attribute__((weak )) void __cxa_end_catch (void );
526- __attribute__((weak )) void __cxa_rethrow (void );
527-
528- enum exception_type
529- {
530- NONE ,
531- CXX ,
532- OBJC ,
533- FOREIGN ,
534- BOXED_FOREIGN
535- };
536- struct thread_data
537- {
538- enum exception_type current_exception_type ;
539- struct objc_exception * caughtExceptions ;
540- };
541-
542- static __thread struct thread_data thread_data ;
543-
544- static struct thread_data * get_thread_data (void )
545- {
546- return & thread_data ;
547- }
548-
549- static struct thread_data * get_thread_data_fast (void )
550- {
551- return & thread_data ;
552- }
553-
554587id objc_begin_catch (struct _Unwind_Exception * exceptionObject )
555588{
556589 struct thread_data * td = get_thread_data ();
557590 DEBUG_LOG ("Beginning catch %p\n" , exceptionObject );
591+ td -> cxxCaughtException = NO ;
558592 if (exceptionObject -> exception_class == objc_exception_class )
559593 {
560594 td -> current_exception_type = OBJC ;
0 commit comments