]> git.ipfire.org Git - thirdparty/gcc.git/blame - libitm/eh_cpp.cc
[PATCH 1/1] RISC-V: Add Zfbfmin extension to the -march= option
[thirdparty/gcc.git] / libitm / eh_cpp.cc
CommitLineData
a945c346 1/* Copyright (C) 2009-2024 Free Software Foundation, Inc.
0a35513e
AH
2 Contributed by Richard Henderson <rth@redhat.com>.
3
4 This file is part of the GNU Transactional Memory Library (libitm).
5
6 Libitm is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 Libitm is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
24
25#include "libitm_i.h"
26
27using namespace GTM;
28
258c1d07
TR
29/* Exceptions can exist in three phases: (1) after having been allocated by
30 __cxa_allocate_exception but before being handed off to __cxa_throw,
31 (2) when they are in flight, so between __cxa_throw and __cxa_begin_catch,
32 and (3) when they are being handled (between __cxa_begin_catch and
33 __cxa_end_catch). Note that when an exception is re-thrown in (3), it is
34 not moving back to (2) but handled as a special case of (3) by the EH
35 runtime.
36
37 We can get aborts in all three phases, for example in (1) during
38 construction of the exception object, or in (2) in destructors called
39 while unwinding the stack. The transaction that created an exception
40 object can only commit in phase (3) by re-throwing the exception; it cannot
41 commit in other phases because throw expressions and catch clauses are
42 properly nested wrt transactions and because the compiler wraps
43 transaction bodies in a try/catch-all construct.
44
45 We handle phase (1) by dealing with exception objects similar to how we
46 deal with other (de)allocations, which also ensures that we can have more
47 than one exception object allocated at the same time (e.g., if the
48 throw expression itself throws an exception and thus calls
49 __cxa_allocate_exception). However, on the call to __cxa_begin_catch
50 we hand off the exception to the special handling of phase (3) and
51 remove the undo log entry of the allocation. Note that if the allocation
52 happened outside of this transaction, we do not need to do anything.
53
54 When an exception reaches phase (2) due to a call to __cxa_throw, the count
55 of uncaught exceptions is incremented. We roll back this effect by saving
56 and restoring this number in the structure returned from __cxa_get_globals.
57 This also takes care of increments of this count when re-throwing an
58 exception.
59
60 For phase (3), we keep track of the number of times __cxa_begin_catch
61 has been called without a matching call to __cxa_end_catch. This count
62 is then used by __cxa_tm_cleanup to roll back the exception handling state
63 by calling __cxa_end_catch for the exceptions that have not been finished
64 yet (without running destructors though because we roll back the memory
65 anyway).
66 Once an exception that was allocated in this transaction enters phase (3),
67 it does not need to be deallocated on abort anymore because the calls to
68 __cxa_end_catch will take care of that.
69
70 We require all code executed by the transaction to be transaction_safe (or
71 transaction_pure, or to have wrappers) if the transaction is to be rolled
72 back. However, we take care to not require this for transactions that
73 just commit; this way, transactions that enter serial mode and then call
74 uninstrumented code continue to work.
75 */
76
0a35513e
AH
77/* Everything from libstdc++ is weak, to avoid requiring that library
78 to be linked into plain C applications using libitm.so. */
79
80#define WEAK __attribute__((weak))
81
82extern "C" {
83
258c1d07
TR
84struct __cxa_eh_globals
85{
86 void * caughtExceptions;
87 unsigned int uncaughtExceptions;
88};
89
f0de5d83
NS
90extern void *__cxa_allocate_exception (size_t) _ITM_NOTHROW WEAK;
91extern void __cxa_free_exception (void *) _ITM_NOTHROW WEAK;
784417d1 92extern void __cxa_throw (void *, void *, void (*) (void *)) WEAK;
f0de5d83 93extern void *__cxa_begin_catch (void *) _ITM_NOTHROW WEAK;
f2f9a097 94extern void __cxa_end_catch (void) WEAK;
f0de5d83
NS
95extern void __cxa_tm_cleanup (void *, void *, unsigned int) throw () WEAK;
96extern __cxa_eh_globals *__cxa_get_globals (void) _ITM_NOTHROW WEAK;
0a35513e 97
6c59ffd1 98#if !defined (HAVE_ELF_STYLE_WEAKREF)
f0de5d83
NS
99void *__cxa_allocate_exception (size_t) _ITM_NOTHROW { return NULL; }
100void __cxa_free_exception (void *) _ITM_NOTHROW { return; }
784417d1 101void __cxa_throw (void *, void *, void (*) (void *)) { return; }
f0de5d83 102void *__cxa_begin_catch (void *) _ITM_NOTHROW { return NULL; }
f2f9a097 103void __cxa_end_catch (void) { return; }
f0de5d83 104void __cxa_tm_cleanup (void *, void *, unsigned int) throw () { return; }
8377e5e5 105void _Unwind_DeleteException (_Unwind_Exception *) { return; }
f0de5d83 106__cxa_eh_globals *__cxa_get_globals (void) _ITM_NOTHROW { return NULL; }
8cf36bb3 107#endif /* HAVE_ELF_STYLE_WEAKREF */
d846e425 108
0a35513e
AH
109}
110
258c1d07
TR
111static void
112free_any_exception (void *exc_ptr)
113{
114 // The exception could be in phase (2) and thus calling just
115 // _cxa_free_exception might not be sufficient.
116 __cxa_tm_cleanup (NULL, exc_ptr, 0);
117}
0a35513e
AH
118
119void *
f0de5d83 120_ITM_cxa_allocate_exception (size_t size) _ITM_NOTHROW
0a35513e
AH
121{
122 void *r = __cxa_allocate_exception (size);
258c1d07 123 gtm_thr()->record_allocation (r, free_any_exception);
0a35513e
AH
124 return r;
125}
126
258c1d07 127void
f0de5d83 128_ITM_cxa_free_exception (void *exc_ptr) _ITM_NOTHROW
258c1d07
TR
129{
130 // __cxa_free_exception can be called from user code directly if
131 // construction of an exception object throws another exception, in which
132 // case we need to roll back the initial exception. We handle this similar
133 // to dead allocations in that we deallocate the exception on both commit
134 // and abort of an outermost transaction.
135 gtm_thr()->forget_allocation (exc_ptr, free_any_exception);
136}
137
0a35513e 138void
784417d1 139_ITM_cxa_throw (void *obj, void *tinfo, void (*dest) (void *))
0a35513e 140{
258c1d07 141 // This used to be instrumented, but does not need to be anymore.
0a35513e
AH
142 __cxa_throw (obj, tinfo, dest);
143}
144
145void *
f0de5d83 146_ITM_cxa_begin_catch (void *exc_ptr) _ITM_NOTHROW
0a35513e 147{
258c1d07
TR
148 // If this exception object has been allocated by this transaction, we
149 // discard the undo log entry for the allocation; we are entering phase (3)
150 // now and will handle this exception specially.
151 // Note that this exception cannot have been allocated in a parent
152 // transaction or enclosing nontransactional block because an atomic block
153 // cannot contain just a catch clause but not the associated try clause.
154 // The exception can have been allocated in a nested transaction, in which
155 // case the commit of the nested transaction will have inserted the undo
156 // log entry of the allocation in our undo log.
157 // The exception can also have been allocated in a nested nontransactional
158 // block, but then this transaction cannot abort anymore; functions that
159 // are marked transaction_pure, for example, must not side-step the
160 // transactional exception handling we implement here.
161 gtm_thread *t = gtm_thr ();
162 t->discard_allocation (exc_ptr);
163 // Keep track of the number of unfinished catch handlers.
164 t->cxa_catch_count++;
0a35513e
AH
165 return __cxa_begin_catch (exc_ptr);
166}
167
168void
169_ITM_cxa_end_catch (void)
170{
258c1d07 171 // Keep track of the number of unfinished catch handlers.
0a35513e
AH
172 gtm_thr()->cxa_catch_count--;
173 __cxa_end_catch ();
174}
175
258c1d07
TR
176void
177GTM::gtm_thread::init_cpp_exceptions ()
178{
179 // Only save and restore the number of uncaught exceptions if this is
180 // actually used in the program.
caa04517
IS
181 if (
182#if HAVE_ELF_STYLE_WEAKREF
183 __cxa_get_globals != NULL &&
184#endif
185 __cxa_get_globals () != 0)
258c1d07
TR
186 cxa_uncaught_count_ptr = &__cxa_get_globals ()->uncaughtExceptions;
187 else
188 cxa_uncaught_count_ptr = 0;
189}
190
0a35513e
AH
191void
192GTM::gtm_thread::revert_cpp_exceptions (gtm_transaction_cp *cp)
193{
194 if (cp)
195 {
258c1d07
TR
196 // If rolling back a nested transaction, only clean up incompletely
197 // caught exceptions since the last checkpoint.
0a35513e
AH
198 assert (cxa_catch_count >= cp->cxa_catch_count);
199 uint32_t catch_count = cxa_catch_count - cp->cxa_catch_count;
258c1d07 200 if (catch_count)
0a35513e 201 {
258c1d07 202 __cxa_tm_cleanup (NULL, NULL, catch_count);
0a35513e 203 cxa_catch_count = cp->cxa_catch_count;
0a35513e
AH
204 }
205 }
206 else
207 {
208 // Both cxa_catch_count and cxa_unthrown are maximal because EH regions
209 // and transactions are properly nested.
258c1d07 210 if (cxa_catch_count)
0a35513e 211 {
258c1d07
TR
212 __cxa_tm_cleanup (NULL, NULL, cxa_catch_count);
213 cxa_catch_count = 0;
0a35513e
AH
214 }
215 }
258c1d07
TR
216 // Reset the number of uncaught exceptions. Any allocations for these
217 // exceptions have been rolled back already, if necessary.
218 if (cxa_uncaught_count_ptr != 0)
219 *cxa_uncaught_count_ptr = cxa_uncaught_count;
220 // Always reset eh_in_flight because it just contains the argument provided
221 // to _ITM_commitTransactionEH.
222 eh_in_flight = NULL;
0a35513e 223}