2014-07-29 Ed Smith-Rowland <3dw4rd@verizon.net>
[official-gcc.git] / libcilkrts / runtime / except-gcc.cpp
blobbd08d1826b3f981fec67e50df2fb257d08915010
1 /* except-gcc.cpp -*-C++-*-
3 *************************************************************************
5 * @copyright
6 * Copyright (C) 2009-2013, Intel Corporation
7 * All rights reserved.
8 *
9 * @copyright
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 * * Neither the name of Intel Corporation nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * @copyright
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
32 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
33 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
35 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 **************************************************************************/
39 #include "except-gcc.h"
40 #include "except.h"
41 #include "sysdep.h"
42 #include "bug.h"
43 #include "local_state.h"
44 #include "full_frame.h"
45 #include "scheduler.h"
46 #include "frame_malloc.h"
47 #include "pedigrees.h"
49 #include <stdint.h>
50 #include <typeinfo>
52 #define DEBUG_EXCEPTIONS 0
54 struct pending_exception_info
56 void make(__cxa_eh_globals *, _Unwind_Exception *, bool);
57 void destruct();
58 bool empty() const;
59 void check() const;
60 /* Active exception at time of suspend. */
61 _Unwind_Exception *active;
62 /* If true the most recently caught exception is to be rethrown
63 on resume. This handling is technically incorrect but allows
64 running without compiler support; the proper standards-compliant
65 method is to save the exception in the previous field. */
66 bool rethrow;
67 struct __cxa_eh_globals runtime_state;
70 void pending_exception_info::check() const
72 if (active)
73 CILK_ASSERT((int)runtime_state.uncaughtExceptions > 0);
76 void pending_exception_info::make(__cxa_eh_globals *state_in,
77 _Unwind_Exception *exc_in, bool rethrow_in)
79 active = exc_in;
80 rethrow = rethrow_in;
81 runtime_state = *state_in;
82 /* Read and clear C++ runtime state. */
83 state_in->caughtExceptions = 0;
84 state_in->uncaughtExceptions = 0;
85 #if CILK_LIB_DEBUG
86 check();
87 #endif
90 bool
91 pending_exception_info::empty() const
93 return !active && !rethrow && !runtime_state.caughtExceptions &&
94 !runtime_state.uncaughtExceptions;
97 #if DEBUG_EXCEPTIONS
98 #include <stdio.h>
99 static void
100 decode_exceptions(char *out, size_t len, struct pending_exception_info *info)
102 if (info->empty())
103 snprintf(out, len, "[empty]");
104 else if (info->rethrow)
105 snprintf(out, len, "[rethrow %p]",
106 info->runtime_state.caughtExceptions);
107 else
108 snprintf(out, len, "[throw %p]", (void *)info->active);
110 #endif
112 static void
113 save_exception_info(__cilkrts_worker *w,
114 __cxa_eh_globals *state,
115 _Unwind_Exception *exc,
116 bool rethrow,
117 const char *why)
119 struct pending_exception_info *info =
120 (struct pending_exception_info *)__cilkrts_frame_malloc(w, sizeof (struct pending_exception_info));
121 CILK_ASSERT(info);
122 info->make(state, exc, rethrow);
124 #if DEBUG_EXCEPTIONS
126 char buf[40];
127 decode_exceptions(buf, sizeof buf, info);
128 fprintf(stderr, "make exception info W%u %p %s (%s)\n",
129 w->self, info, buf, why);
131 #endif
133 CILK_ASSERT(w->l->pending_exception == 0);
134 w->l->pending_exception = info;
137 #if DEBUG_EXCEPTIONS
138 #include <stdio.h> /* DEBUG */
140 static void decode_flags(int flags, char out[9])
142 out[0] = (flags & CILK_FRAME_STOLEN) ? 'S' : '_';
143 out[1] = (flags & CILK_FRAME_UNSYNCHED) ? 'U' : '_';
144 out[2] = (flags & CILK_FRAME_DETACHED) ? 'D' : '_';
145 out[3] = (flags & CILK_FRAME_EXCEPTING) ? 'X' : '_';
146 out[4] = '\0';
148 #endif
150 /* __cilkrts_save_except is called from the runtime epilogue
151 when a function is returning with an exception pending.
153 If the function has a parent to which it could return normally,
154 return and have the caller call _Unwind_Resume, the same as if
155 an exception filter had not matched.
157 Otherwise save the exception in the worker.
159 If this is a return from a ordinary call that must go through
160 the runtime, the assembly epilogue must have saved the call-saved
161 register state in the parent frame. */
163 extern "C"
164 CILK_ABI_THROWS_VOID
165 __cilkrts_return_exception(__cilkrts_stack_frame *sf)
167 __cilkrts_worker *w = sf->worker;
168 _Unwind_Exception *exc = (_Unwind_Exception *)sf->except_data;
170 CILK_ASSERT(sf->flags & CILK_FRAME_DETACHED);
171 sf->flags &= ~CILK_FRAME_DETACHED;
174 * If we are in replay mode, and a steal occurred during the recording
175 * phase, stall till a steal actually occurs.
177 replay_wait_for_steal_if_parent_was_stolen(w);
179 /* If this is to be an abnormal return, save the active exception. */
180 if (!__cilkrts_pop_tail(w)) {
181 /* Write a record to the replay log for an attempt to return to a
182 stolen parent. This must be done before the exception handler
183 invokes __cilkrts_leave_frame which will bump the pedigree so
184 the replay_wait_for_steal_if_parent_was_stolen() above will match on
185 replay */
186 replay_record_orphaned(w);
188 /* Now that the record/replay stuff is done, update the pedigree */
189 update_pedigree_on_leave_frame(w, sf);
191 /* Inline pop_frame; this may not be needed. */
192 w->current_stack_frame = sf->call_parent;
193 sf->call_parent = 0;
194 __cxa_eh_globals *state = __cxa_get_globals();
196 #if DEBUG_EXCEPTIONS
197 fflush(stdout);
198 char decoded[9];
199 decode_flags(sf->flags, decoded);
200 fprintf(stderr, "__cilkrts_save_except W%u sf %p/%s exc %p [%u %p] suspend\n",
201 w->self, sf, decoded, exc,
202 state->uncaughtExceptions,
203 state->caughtExceptions);
204 #endif
206 /* Like __cilkrts_save_exception_state except for setting the
207 rethrow flag. */
208 save_exception_info(w, state, exc, exc == NULL, "save_except");
210 full_frame *ff = w->l->frame_ff;
211 CILK_ASSERT(NULL == ff->pending_exception);
212 ff->pending_exception = w->l->pending_exception;
213 w->l->pending_exception = NULL;
215 __cilkrts_exception_from_spawn(w, sf); /* does not return */
217 /* This code path is taken when the parent is attached. It is on
218 the same stack and part of the same full frame. The caller is
219 cleaning up the Cilk frame during unwind and will reraise the
220 exception */
222 /* Now that the record/replay stuff is done, update the pedigree */
223 update_pedigree_on_leave_frame(w, sf);
225 #if DEBUG_EXCEPTIONS /* DEBUG ONLY */
227 __cxa_eh_globals *state = __cxa_get_globals();
229 fflush(stdout);
230 char decoded[9];
231 decode_flags(sf->flags, decoded);
232 fprintf(stderr, "__cilkrts_save_except W%d %p/%s %p->%p [%u %p] escape\n",
233 w->self, sf, decoded, exc,
234 exc ? to_cxx(exc)->nextException : 0,
235 state->uncaughtExceptions,
236 state->caughtExceptions);
238 /* XXX This is triggering in the user thread which gets an exception
239 from somewhere but does not get the corresponding runtime exception
240 state.
241 XXX There might be two or more uncaught exceptions. Test could be
242 (uncaught != 0) == (exc != 0). First, design tests to see if that
243 case is otherwise handled correctly. And what if there's an uncaught
244 exception that does not belong to this function? I.e. this is a return
245 from spawn in a destructor. */
246 if (exc)
247 CILK_ASSERT((int)state->uncaughtExceptions > 0);
248 /*CILK_ASSERT(state->uncaughtExceptions == (exc != 0));*/
250 #endif
252 /* The parent is attached so this exception can be propagated normally. */
253 return;
256 /* Save the exception state into the full frame, which is exiting
257 or suspending. */
258 extern "C"
259 void __cilkrts_save_exception_state(__cilkrts_worker *w, full_frame *ff)
261 save_exception_info(w, __cxa_get_globals(), 0, false, "undo-detach");
262 CILK_ASSERT(NULL == ff->pending_exception);
263 ff->pending_exception = w->l->pending_exception;
264 w->l->pending_exception = NULL;
267 /* __cilkrts_c_sync_except is like __cilkrts_c_sync except that it
268 saves exception state. __cilkrts_c_sync never returns here and
269 always reinstalls the saved exception state.
271 This function must be used because a parent of this function may
272 be propagating an uncaught exception. The uncaught exception
273 count must be saved by the child and passed back to the parent. */
275 extern "C"
276 NORETURN __cilkrts_c_sync_except (__cilkrts_worker *w, __cilkrts_stack_frame *sf)
278 __cxa_eh_globals *state = __cxa_get_globals();
279 _Unwind_Exception *exc = (_Unwind_Exception *)sf->except_data;
281 CILK_ASSERT((sf->flags & (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING)) ==
282 (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING));
283 sf->flags &= ~CILK_FRAME_EXCEPTING;
285 #if DEBUG_EXCEPTIONS
286 fflush(stdout);
287 char decoded[9];
288 decode_flags(sf->flags, decoded);
289 if (exc)
290 fprintf(stderr, "__cilkrts_sync_except W%u %p/%s %p->%p [%u %p]\n",
291 w->self, sf, decoded, exc,
292 to_cxx(exc)->nextException,
293 state->uncaughtExceptions,
294 state->caughtExceptions);
295 else
296 fprintf(stderr, "__cilkrts_sync_except W%d %p/%s none [%u %p]\n",
297 w->self, sf, decoded,
298 state->uncaughtExceptions,
299 state->caughtExceptions);
300 #endif
302 /* Here the identity of an rethrown exception is always known.
303 If exc is NULL this call is only to preserve parent state. */
304 save_exception_info(w, state, exc, false, "sync_except");
305 #if 0
307 full_frame *ff = w->l->frame_ff;
308 CILK_ASSERT(NULL == ff->pending_exception);
309 ff->pending_exception = w->l->pending_exception;
310 w->l->pending_exception = NULL;
312 #endif
313 CILK_ASSERT(!std::uncaught_exception());
314 __cilkrts_c_sync(w, sf);
317 void
318 pending_exception_info::destruct()
320 if (active) {
321 #if DEBUG_EXCEPTIONS
322 fprintf(stderr, "destroy exception info %p %p\n", this, active);
323 #endif
324 _Unwind_DeleteException(active);
325 active = 0;
326 } else {
327 #if DEBUG_EXCEPTIONS
328 fprintf(stderr, "destroy exception info %p\n", this);
329 #endif
331 while (runtime_state.caughtExceptions) {
332 __cxa_exception *exc = runtime_state.caughtExceptions;
333 runtime_state.caughtExceptions = exc->nextException;
334 #if DEBUG_EXCEPTIONS
335 fprintf(stderr, "destroy caught exception %p\n", this);
336 #endif
337 _Unwind_DeleteException(&exc->unwindHeader);
342 * __cilkrts_merge_pending_exceptions
344 * Merge the right exception record into the left. The left is logically
345 * earlier.
347 * The active exception of E is
348 * E->active if it is non-NULL (in which case E->rethrow is false)
349 * unresolved if E->active is NULL and E->rethrow is true
350 * nil if E->active is NULL and E->rethrow is false
352 * The merged active exception is left active exception if it is not
353 * nil, otherwise the right.
355 * On entry the left state is synched and can not have an unresolved
356 * exception. The merge may result in an unresolved exception.
358 * Due to scoping rules at most one of the caught exception lists is
359 * non-NULL.
362 struct pending_exception_info *
363 __cilkrts_merge_pending_exceptions (
364 __cilkrts_worker *w,
365 struct pending_exception_info *left,
366 struct pending_exception_info *right)
368 /* If we've only got one exception, return it */
370 if (NULL == left) {
371 #if DEBUG_EXCEPTIONS
372 if (right) {
373 char buf[40];
374 decode_exceptions(buf, sizeof buf, right);
375 fprintf(stderr, "__cilkrts merge W%u nil %p -> %p %s\n",
376 w->self, right, right, buf);
378 #endif
379 return right;
382 if (NULL == right) {
383 #if DEBUG_EXCEPTIONS
384 if (left) {
385 char buf[40];
386 decode_exceptions(buf, sizeof buf, left);
387 fprintf(stderr, "__cilkrts merge W%u %p nil -> %p %s\n",
388 w->self, left, left, buf);
390 #endif
391 return left;
394 #if CILK_LIB_DEBUG
395 /*volatile struct pending_exception_info left_in = *left, right_in = *right;*/
396 left->check();
397 right->check();
398 #endif
400 #if DEBUG_EXCEPTIONS
402 char buf1[40], buf2[40];
403 decode_exceptions(buf1, sizeof buf1, left);
404 decode_exceptions(buf2, sizeof buf2, right);
405 fprintf(stderr, "__cilkrts merge W%u %p %s %p %s\n",
406 w->self, left, buf1, right, buf2);
408 #endif
410 /* It should not be possible for both left and right to
411 have accumulated catch blocks.
413 The left exception record may always have a catch
414 chain it kept when its parent was stolen.
416 If they are siblings, the right sibling should not
417 have accumulated any net catches. (Catch is lexically
418 scoped.)
420 If the right frame is a parent, it should not have entered
421 a catch block without syncing first. If it spawned in a
422 catch block, the child got its catch. */
423 __cxa_exception *caught = left->runtime_state.caughtExceptions;
424 if (caught)
425 CILK_ASSERT(!right->runtime_state.caughtExceptions);
426 else {
427 CILK_ASSERT(!left->rethrow);
428 left->rethrow = right->rethrow;
429 left->runtime_state.caughtExceptions = caught = right->runtime_state.caughtExceptions;
430 right->runtime_state.caughtExceptions = NULL;
433 /* Merge the uncaught exception and count of uncaught exceptions. */
434 const unsigned int right_uncaught = right->runtime_state.uncaughtExceptions;
435 if (!left->active){
436 left->active = right->active; /* could be NULL */
437 right->active = 0;
438 left->runtime_state.uncaughtExceptions += right_uncaught;
439 if (left->active)
440 /* assert is C++ exception */
441 /*CILK_ASSERT(__cxxabiv1::__is_gxx_exception_class(left->active->exception_class))*/;
442 } else {
443 /* Subtract 1 if the right exception is being destructed. */
444 left->runtime_state.uncaughtExceptions += right_uncaught - (right->active != 0);
447 right->destruct();
448 __cilkrts_frame_free(w, right, sizeof *right);
450 /* If there is no state left, return NULL. */
451 if (left->empty()) {
452 left->destruct();
453 __cilkrts_frame_free(w, left, sizeof *left);
454 left = NULL;
457 #if CILK_LIB_DEBUG
458 if (left)
459 left->check();
460 #endif
462 return left;
465 #if 0
466 /* __cilkrts_c_resume_except is called from the assembly language
467 restart code when a resumed frame has a pending exception.
469 The handler count negation on rethrow was done when the throw was
470 resolved.
472 The assembly language runtime must make the throw unwind to
473 the sync, spawn, or other location where the exception should
474 be injected. (This should not happen after a spawn but nothing
475 here depends on there being no exception on steal.)
477 This function is unused in the Intel stack based system. */
478 extern "C"
479 void __cilkrts_c_resume_except (_Unwind_Exception *exc)
481 #if DEBUG_EXCEPTIONS
482 fprintf(stderr, "resume exception %p\n", exc);
483 #endif
484 _Unwind_Reason_Code why = _Unwind_RaiseException(exc);
485 __cilkrts_bug ("Cilk runtime error: failed to reinstate suspended exception %p (%d)\n", exc, why);
487 #endif
489 /* Restore the caught exception chain. This assumes no C++ exception
490 code will run before the frame is resumed. If there is no exception
491 to be resumed free the object. */
493 extern "C"
494 void __cilkrts_setup_for_execution_sysdep(__cilkrts_worker *w, full_frame *ff)
496 // ASSERT: We own w->lock and ff->lock || P == 1
498 __cxa_eh_globals *state = __cxa_get_globals ();
499 struct pending_exception_info *info = w->l->pending_exception;
501 if (info == NULL)
502 return;
504 w->l->pending_exception = 0;
506 #if DEBUG_EXCEPTIONS
507 _Unwind_Exception *exc = info->active;
508 if (exc) {
509 fflush(stdout);
510 fprintf(stderr, "__cilkrts_resume_except W%u %p->%p [%u %p]\n",
511 w->self, exc,
512 to_cxx(exc)->nextException,
513 info->runtime_state.uncaughtExceptions,
514 info->runtime_state.caughtExceptions);
515 /*CILK_ASSERT(info->runtime_state.uncaughtExceptions > 0);*/
517 #endif
519 if (state->uncaughtExceptions || state->caughtExceptions)
520 __cilkrts_bug("W%u: resuming with non-empty prior exception state %u %p\n", state->uncaughtExceptions, state->caughtExceptions);
522 *state = info->runtime_state;
523 info->runtime_state.caughtExceptions = 0;
524 info->runtime_state.uncaughtExceptions = 0;
526 if (info->rethrow) {
527 info->rethrow = false;
528 /* Resuming function will rethrow. Runtime calls
529 std::terminate if there is no caught exception. */
530 ff->call_stack->flags |= CILK_FRAME_EXCEPTING;
532 if (info->active) {
533 ff->call_stack->flags |= CILK_FRAME_EXCEPTING;
534 ff->call_stack->except_data = info->active;
535 info->active = 0;
538 if (info->empty()) {
539 info->destruct();
540 __cilkrts_frame_free(w, info, sizeof *info);
541 w->l->pending_exception = NULL;
544 #if CILK_LIB_DEBUG
545 if (ff->call_stack->except_data)
546 CILK_ASSERT(std::uncaught_exception());
547 #endif
550 #if 0
551 extern "C"
552 struct pending_exception_info *__cilkrts_get_exception(__cilkrts_worker *w,
553 __cilkrts_stack_frame *sf)
555 struct pending_exception_info *info = w->l->pending_exception;
557 if (info == NULL) {
558 sf->flags &= ~CILK_FRAME_EXCEPTING;
559 return 0;
562 w->l->pending_exception = NULL;
564 /* This exception goes into the frame. */
566 _Unwind_Exception *exc = info->active;
567 info->active = NULL;
568 info->destruct();
569 __cilkrts_frame_free(w, info, sizeof *info);
570 info = 0;
571 sf->flags |= CILK_FRAME_EXCEPTING;
572 sf->exception = exc;
573 return 0;
575 #endif
577 extern "C"
578 void __attribute__((nonnull)) __cilkrts_gcc_rethrow(__cilkrts_stack_frame *sf)
580 #ifdef __CYGWIN__
581 // Cygwin doesn't support exceptions, so _Unwind_Resume isn't available
582 // Which means we can't support exceptions either
583 __cilkrts_bug("The Cygwin implementation of the Intel Cilk Plus runtime doesn't support exceptions\n");
584 #else
585 if (sf->except_data) {
586 #if CILK_LIB_DEBUG
587 CILK_ASSERT(std::uncaught_exception());
588 #endif
589 _Unwind_Resume ((_Unwind_Exception *)sf->except_data);
590 } else {
591 throw;
593 #endif // __CYGWIN__
596 /* End except-gcc.cpp */