22
22
23
23
void test_cxx_eh_implementation ();
24
24
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
+
25
32
26
33
/**
27
34
* Class of exceptions to distinguish between this and other exception types.
@@ -75,6 +82,35 @@ typedef enum
75
82
handler_class
76
83
} handler_type ;
77
84
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
+
78
114
/**
79
115
* Saves the result of the landing pad that we have found. For ARM, this is
80
116
* 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)
147
183
unwindHeader)));
148
184
*/
149
185
}
186
+
187
+ void objc_exception_rethrow (struct _Unwind_Exception * e );
188
+
150
189
/**
151
190
* Throws an Objective-C exception. This function is, unfortunately, used for
152
191
* rethrowing caught exceptions too, even in @finally() blocks. Unfortunately,
153
192
* this means that we have some problems if the exception is boxed.
154
193
*/
155
194
void objc_exception_throw (id object )
156
195
{
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
+ }
157
215
158
216
SEL rethrow_sel = sel_registerName ("rethrow" );
159
217
if ((nil != object ) &&
@@ -175,6 +233,9 @@ void objc_exception_throw(id object)
175
233
176
234
ex -> object = object ;
177
235
236
+ td -> lastThrownObject = object ;
237
+ td -> cxxCaughtException = NO ;
238
+
178
239
_Unwind_Reason_Code err = _Unwind_RaiseException (& ex -> unwindHeader );
179
240
free (ex );
180
241
if (_URC_END_OF_STACK == err && 0 != _objc_unexpected_exception )
@@ -480,6 +541,7 @@ static inline _Unwind_Reason_Code internal_objc_personality(int version,
480
541
_Unwind_SetGR (context , __builtin_eh_return_data_regno (1 ), selector );
481
542
482
543
DEBUG_LOG ("Installing context, selector %d\n" , (int )selector );
544
+ get_thread_data ()-> cxxCaughtException = NO ;
483
545
return _URC_INSTALL_CONTEXT ;
484
546
}
485
547
@@ -513,48 +575,20 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
513
575
int ret = CALL_PERSONALITY_FUNCTION (__gxx_personality_v0 );
514
576
exceptionObject -> private_1 = ex -> cxx_exception -> private_1 ;
515
577
exceptionObject -> private_2 = ex -> cxx_exception -> private_2 ;
578
+ if (ret == _URC_INSTALL_CONTEXT )
579
+ {
580
+ get_thread_data ()-> cxxCaughtException = YES ;
581
+ }
516
582
return ret ;
517
583
}
518
584
return CALL_PERSONALITY_FUNCTION (__gxx_personality_v0 );
519
585
}
520
586
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
-
554
587
id objc_begin_catch (struct _Unwind_Exception * exceptionObject )
555
588
{
556
589
struct thread_data * td = get_thread_data ();
557
590
DEBUG_LOG ("Beginning catch %p\n" , exceptionObject );
591
+ td -> cxxCaughtException = NO ;
558
592
if (exceptionObject -> exception_class == objc_exception_class )
559
593
{
560
594
td -> current_exception_type = OBJC ;
0 commit comments