@@ -287,13 +287,7 @@ void __cxa_end_catch() {
287
287
}
288
288
// Destroy the primary exception only if its referenceCount goes to 0
289
289
// (this decrement must be atomic)
290
- if (__sync_sub_and_fetch (¤t_exception->referenceCount , size_t (1 )) == 0 )
291
- {
292
- void * thrown_object = thrown_object_from_exception (current_exception);
293
- if (NULL != current_exception->exceptionDestructor )
294
- current_exception->exceptionDestructor (thrown_object);
295
- __cxa_free_exception (thrown_object);
296
- }
290
+ __cxa_decrement_exception_refcount (thrown_object_from_exception (current_exception));
297
291
}
298
292
}
299
293
}
@@ -347,6 +341,111 @@ extern LIBCXXABI_NORETURN void __cxa_rethrow() {
347
341
failed_throw (exception );
348
342
}
349
343
344
+ /*
345
+ If p is not null, atomically increment the referenceCount field of the
346
+ __cxa_exception header associated with the thrown object referred to by p.
347
+ */
348
+ void
349
+ __cxa_increment_exception_refcount (void * p) throw()
350
+ {
351
+ if (p != NULL )
352
+ {
353
+ __cxa_exception* header = exception_from_thrown_object (p);
354
+ __sync_add_and_fetch (&header->referenceCount , 1 );
355
+ }
356
+ }
357
+
358
+ /*
359
+ If p is not null, atomically decrement the referenceCount field of the
360
+ __cxa_exception header associated with the thrown object referred to by p.
361
+ If the referenceCount drops to zero, destroy and deallocate the exception.
362
+ */
363
+ void
364
+ __cxa_decrement_exception_refcount (void * thrown_object) throw()
365
+ {
366
+ if (thrown_object != NULL )
367
+ {
368
+ __cxa_exception* header = exception_from_thrown_object (thrown_object);
369
+ if (__sync_sub_and_fetch (&header->referenceCount , size_t (1 )) == 0 )
370
+ {
371
+ if (NULL != header->exceptionDestructor )
372
+ header->exceptionDestructor (thrown_object);
373
+ __cxa_free_exception (thrown_object);
374
+ }
375
+ }
376
+ }
377
+
378
+ /*
379
+ Returns a pointer to the thrown object (if any) at the top of the
380
+ caughtExceptions stack. Atommically increment the exception's referenceCount.
381
+ If there is no such thrown object, returns null.
382
+ */
383
+ void *
384
+ __cxa_current_primary_exception () throw()
385
+ {
386
+ // get the current exception
387
+ __cxa_eh_globals* globals = __cxa_get_globals ();
388
+ __cxa_exception* current_exception = globals->caughtExceptions ;
389
+ if (NULL == current_exception)
390
+ return NULL ; // No current exception
391
+ if (isDependentException (¤t_exception->unwindHeader )) {
392
+ __cxa_dependent_exception* deh =
393
+ reinterpret_cast <__cxa_dependent_exception*>(current_exception + 1 ) - 1 ;
394
+ current_exception = static_cast <__cxa_exception*>(deh->primaryException ) - 1 ;
395
+ }
396
+ void * thrown_object = thrown_object_from_exception (current_exception);
397
+ __cxa_increment_exception_refcount (thrown_object);
398
+ return thrown_object;
399
+ }
400
+
401
+ /*
402
+ If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
403
+ stored in exc is called. Otherwise the referenceCount stored in the
404
+ primary exception is decremented, destroying the primary if necessary.
405
+ Finally the dependent exception is destroyed.
406
+ */
407
+ static
408
+ void
409
+ dependent_exception_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception * exc)
410
+ {
411
+ __cxa_dependent_exception* deh =
412
+ reinterpret_cast <__cxa_dependent_exception*>(exc + 1 ) - 1 ;
413
+ if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
414
+ std::__terminate (deh->terminateHandler );
415
+ __cxa_decrement_exception_refcount (deh->primaryException );
416
+ __cxa_free_dependent_exception (deh);
417
+ }
418
+
419
+ /*
420
+ If thrown_object is not null, allocate, initialize and thow a dependent
421
+ exception.
422
+ */
423
+ void
424
+ __cxa_rethrow_primary_exception (void * thrown_object)
425
+ {
426
+ if ( thrown_object != NULL )
427
+ {
428
+ __cxa_exception* header = exception_from_thrown_object (thrown_object);
429
+ __cxa_dependent_exception* deh =
430
+ (__cxa_dependent_exception*)__cxa_allocate_dependent_exception ();
431
+ deh->primaryException = thrown_object;
432
+ __cxa_increment_exception_refcount (thrown_object);
433
+ deh->exceptionType = header->exceptionType ;
434
+ deh->unexpectedHandler = std::get_unexpected ();
435
+ deh->terminateHandler = std::get_terminate ();
436
+ setDependentExceptionClass (&deh->unwindHeader );
437
+ deh->unwindHeader .exception_cleanup = dependent_exception_cleanup;
438
+ #if __arm__
439
+ _Unwind_SjLj_RaiseException (&deh->unwindHeader );
440
+ #else
441
+ _Unwind_RaiseException (&deh->unwindHeader );
442
+ #endif
443
+ // Some sort of unwinding error. Note that terminate is a handler.
444
+ __cxa_begin_catch (&deh->unwindHeader );
445
+ }
446
+ // If we return client will call terminate()
447
+ }
448
+
350
449
} // extern "C"
351
450
352
451
} // abi
0 commit comments