[RS6000] PR72802 part 2, reload ICE
[official-gcc.git] / libcilkrts / runtime / except-gcc.cpp
blob4940acb41f7a1789988f30962924c153a78fdf2c
1 /* except-gcc.cpp -*-C++-*-
3 *************************************************************************
5 * Copyright (C) 2009-2016, Intel Corporation
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * * Neither the name of Intel Corporation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
32 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
35 * *********************************************************************
37 * PLEASE NOTE: This file is a downstream copy of a file mainitained in
38 * a repository at cilkplus.org. Changes made to this file that are not
39 * submitted through the contribution process detailed at
40 * http://www.cilkplus.org/submit-cilk-contribution will be lost the next
41 * time that a new version is released. Changes only submitted to the
42 * GNU compiler collection or posted to the git repository at
43 * https://bitbucket.org/intelcilkruntime/intel-cilk-runtime.git are
44 * not tracked.
46 * We welcome your contributions to this open source project. Thank you
47 * for your assistance in helping us improve Cilk Plus.
48 **************************************************************************/
50 #include "except-gcc.h"
51 #include "except.h"
52 #include "sysdep.h"
53 #include "bug.h"
54 #include "local_state.h"
55 #include "full_frame.h"
56 #include "scheduler.h"
57 #include "frame_malloc.h"
58 #include "pedigrees.h"
60 #include <stdint.h>
61 #include <typeinfo>
63 #define DEBUG_EXCEPTIONS 0
65 struct pending_exception_info
67 void make(__cxa_eh_globals *, _Unwind_Exception *, bool);
68 void destruct();
69 bool empty() const;
70 void check() const;
71 /* Active exception at time of suspend. */
72 _Unwind_Exception *active;
73 /* If true the most recently caught exception is to be rethrown
74 on resume. This handling is technically incorrect but allows
75 running without compiler support; the proper standards-compliant
76 method is to save the exception in the previous field. */
77 bool rethrow;
78 struct __cxa_eh_globals runtime_state;
81 void pending_exception_info::check() const
83 if (active)
84 CILK_ASSERT((int)runtime_state.uncaughtExceptions > 0);
87 void pending_exception_info::make(__cxa_eh_globals *state_in,
88 _Unwind_Exception *exc_in, bool rethrow_in)
90 active = exc_in;
91 rethrow = rethrow_in;
92 runtime_state = *state_in;
93 /* Read and clear C++ runtime state. */
94 state_in->caughtExceptions = 0;
95 state_in->uncaughtExceptions = 0;
96 #if CILK_LIB_DEBUG
97 check();
98 #endif
101 bool
102 pending_exception_info::empty() const
104 return !active && !rethrow && !runtime_state.caughtExceptions &&
105 !runtime_state.uncaughtExceptions;
108 #if DEBUG_EXCEPTIONS
109 #include <stdio.h>
110 static void
111 decode_exceptions(char *out, size_t len, struct pending_exception_info *info)
113 if (info->empty())
114 cilk_snprintf_s(out, len, "%s", "[empty]");
115 else if (info->rethrow)
116 cilk_snprintf_l(out, len, "[rethrow %p]",
117 info->runtime_state.caughtExceptions);
118 else
119 cilk_snprintf_l(out, len, "[throw %p]", (void *)info->active);
121 #endif
123 static void
124 save_exception_info(__cilkrts_worker *w,
125 __cxa_eh_globals *state,
126 _Unwind_Exception *exc,
127 bool rethrow,
128 const char *why)
130 struct pending_exception_info *info =
131 (struct pending_exception_info *)__cilkrts_frame_malloc(w, sizeof (struct pending_exception_info));
132 CILK_ASSERT(info);
133 info->make(state, exc, rethrow);
135 #if DEBUG_EXCEPTIONS
137 char buf[40];
138 decode_exceptions(buf, sizeof buf, info);
139 fprintf(stderr, "make exception info W%u %p %s (%s)\n",
140 w->self, info, buf, why);
142 #endif
144 CILK_ASSERT(w->l->pending_exception == 0);
145 w->l->pending_exception = info;
148 #if DEBUG_EXCEPTIONS
149 #include <stdio.h> /* DEBUG */
151 static void decode_flags(int flags, char out[9])
153 out[0] = (flags & CILK_FRAME_STOLEN) ? 'S' : '_';
154 out[1] = (flags & CILK_FRAME_UNSYNCHED) ? 'U' : '_';
155 out[2] = (flags & CILK_FRAME_DETACHED) ? 'D' : '_';
156 out[3] = (flags & CILK_FRAME_EXCEPTING) ? 'X' : '_';
157 out[4] = '\0';
159 #endif
161 /* __cilkrts_save_except is called from the runtime epilogue
162 when a function is returning with an exception pending.
164 If the function has a parent to which it could return normally,
165 return and have the caller call _Unwind_Resume, the same as if
166 an exception filter had not matched.
168 Otherwise save the exception in the worker.
170 If this is a return from a ordinary call that must go through
171 the runtime, the assembly epilogue must have saved the call-saved
172 register state in the parent frame. */
174 extern "C"
175 CILK_ABI_THROWS_VOID
176 __cilkrts_return_exception(__cilkrts_stack_frame *sf)
178 __cilkrts_worker *w = sf->worker;
179 _Unwind_Exception *exc = (_Unwind_Exception *)sf->except_data;
181 CILK_ASSERT(sf->flags & CILK_FRAME_DETACHED);
182 sf->flags &= ~CILK_FRAME_DETACHED;
185 * If we are in replay mode, and a steal occurred during the recording
186 * phase, stall till a steal actually occurs.
188 replay_wait_for_steal_if_parent_was_stolen(w);
190 /* If this is to be an abnormal return, save the active exception. */
191 if (!__cilkrts_pop_tail(w)) {
192 /* Write a record to the replay log for an attempt to return to a
193 stolen parent. This must be done before the exception handler
194 invokes __cilkrts_leave_frame which will bump the pedigree so
195 the replay_wait_for_steal_if_parent_was_stolen() above will match on
196 replay */
197 replay_record_orphaned(w);
199 /* Now that the record/replay stuff is done, update the pedigree */
200 update_pedigree_on_leave_frame(w, sf);
202 /* Inline pop_frame; this may not be needed. */
203 w->current_stack_frame = sf->call_parent;
204 sf->call_parent = 0;
205 __cxa_eh_globals *state = __cxa_get_globals();
207 #if DEBUG_EXCEPTIONS
208 fflush(stdout);
209 char decoded[9];
210 decode_flags(sf->flags, decoded);
211 fprintf(stderr, "__cilkrts_save_except W%u sf %p/%s exc %p [%u %p] suspend\n",
212 w->self, sf, decoded, exc,
213 state->uncaughtExceptions,
214 state->caughtExceptions);
215 #endif
217 /* Like __cilkrts_save_exception_state except for setting the
218 rethrow flag. */
219 save_exception_info(w, state, exc, exc == NULL, "save_except");
221 full_frame *ff = w->l->frame_ff;
222 CILK_ASSERT(NULL == ff->pending_exception);
223 ff->pending_exception = w->l->pending_exception;
224 w->l->pending_exception = NULL;
226 __cilkrts_exception_from_spawn(w, sf); /* does not return */
228 /* This code path is taken when the parent is attached. It is on
229 the same stack and part of the same full frame. The caller is
230 cleaning up the Cilk frame during unwind and will reraise the
231 exception */
233 /* Now that the record/replay stuff is done, update the pedigree */
234 update_pedigree_on_leave_frame(w, sf);
236 #if DEBUG_EXCEPTIONS /* DEBUG ONLY */
238 __cxa_eh_globals *state = __cxa_get_globals();
240 fflush(stdout);
241 char decoded[9];
242 decode_flags(sf->flags, decoded);
243 fprintf(stderr, "__cilkrts_save_except W%d %p/%s %p->%p [%u %p] escape\n",
244 w->self, sf, decoded, exc,
245 exc ? to_cxx(exc)->nextException : 0,
246 state->uncaughtExceptions,
247 state->caughtExceptions);
249 /* XXX This is triggering in the user thread which gets an exception
250 from somewhere but does not get the corresponding runtime exception
251 state.
252 XXX There might be two or more uncaught exceptions. Test could be
253 (uncaught != 0) == (exc != 0). First, design tests to see if that
254 case is otherwise handled correctly. And what if there's an uncaught
255 exception that does not belong to this function? I.e. this is a return
256 from spawn in a destructor. */
257 if (exc)
258 CILK_ASSERT((int)state->uncaughtExceptions > 0);
259 /*CILK_ASSERT(state->uncaughtExceptions == (exc != 0));*/
261 #endif
263 /* The parent is attached so this exception can be propagated normally. */
264 return;
267 /* Save the exception state into the full frame, which is exiting
268 or suspending. */
269 extern "C"
270 void __cilkrts_save_exception_state(__cilkrts_worker *w, full_frame *ff)
272 save_exception_info(w, __cxa_get_globals(), 0, false, "undo-detach");
273 CILK_ASSERT(NULL == ff->pending_exception);
274 ff->pending_exception = w->l->pending_exception;
275 w->l->pending_exception = NULL;
278 /* __cilkrts_c_sync_except is like __cilkrts_c_sync except that it
279 saves exception state. __cilkrts_c_sync never returns here and
280 always reinstalls the saved exception state.
282 This function must be used because a parent of this function may
283 be propagating an uncaught exception. The uncaught exception
284 count must be saved by the child and passed back to the parent. */
286 extern "C"
287 NORETURN __cilkrts_c_sync_except (__cilkrts_worker *w, __cilkrts_stack_frame *sf)
289 __cxa_eh_globals *state = __cxa_get_globals();
290 _Unwind_Exception *exc = (_Unwind_Exception *)sf->except_data;
292 CILK_ASSERT((sf->flags & (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING)) ==
293 (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING));
294 sf->flags &= ~CILK_FRAME_EXCEPTING;
296 #if DEBUG_EXCEPTIONS
297 fflush(stdout);
298 char decoded[9];
299 decode_flags(sf->flags, decoded);
300 if (exc)
301 fprintf(stderr, "__cilkrts_sync_except W%u %p/%s %p->%p [%u %p]\n",
302 w->self, sf, decoded, exc,
303 to_cxx(exc)->nextException,
304 state->uncaughtExceptions,
305 state->caughtExceptions);
306 else
307 fprintf(stderr, "__cilkrts_sync_except W%d %p/%s none [%u %p]\n",
308 w->self, sf, decoded,
309 state->uncaughtExceptions,
310 state->caughtExceptions);
311 #endif
313 /* Here the identity of an rethrown exception is always known.
314 If exc is NULL this call is only to preserve parent state. */
315 save_exception_info(w, state, exc, false, "sync_except");
316 #if 0
318 full_frame *ff = w->l->frame_ff;
319 CILK_ASSERT(NULL == ff->pending_exception);
320 ff->pending_exception = w->l->pending_exception;
321 w->l->pending_exception = NULL;
323 #endif
324 CILK_ASSERT(!std::uncaught_exception());
325 __cilkrts_c_sync(w, sf);
328 void
329 pending_exception_info::destruct()
331 if (active) {
332 #if DEBUG_EXCEPTIONS
333 fprintf(stderr, "destroy exception info %p %p\n", this, active);
334 #endif
335 _Unwind_DeleteException(active);
336 active = 0;
337 } else {
338 #if DEBUG_EXCEPTIONS
339 fprintf(stderr, "destroy exception info %p\n", this);
340 #endif
342 while (runtime_state.caughtExceptions) {
343 __cxa_exception *exc = runtime_state.caughtExceptions;
344 runtime_state.caughtExceptions = exc->nextException;
345 #if DEBUG_EXCEPTIONS
346 fprintf(stderr, "destroy caught exception %p\n", this);
347 #endif
348 _Unwind_DeleteException(&exc->unwindHeader);
353 * __cilkrts_merge_pending_exceptions
355 * Merge the right exception record into the left. The left is logically
356 * earlier.
358 * The active exception of E is
359 * E->active if it is non-NULL (in which case E->rethrow is false)
360 * unresolved if E->active is NULL and E->rethrow is true
361 * nil if E->active is NULL and E->rethrow is false
363 * The merged active exception is left active exception if it is not
364 * nil, otherwise the right.
366 * On entry the left state is synched and can not have an unresolved
367 * exception. The merge may result in an unresolved exception.
369 * Due to scoping rules at most one of the caught exception lists is
370 * non-NULL.
373 struct pending_exception_info *
374 __cilkrts_merge_pending_exceptions (
375 __cilkrts_worker *w,
376 struct pending_exception_info *left,
377 struct pending_exception_info *right)
379 /* If we've only got one exception, return it */
381 if (NULL == left) {
382 #if DEBUG_EXCEPTIONS
383 if (right) {
384 char buf[40];
385 decode_exceptions(buf, sizeof buf, right);
386 fprintf(stderr, "__cilkrts merge W%u nil %p -> %p %s\n",
387 w->self, right, right, buf);
389 #endif
390 return right;
393 if (NULL == right) {
394 #if DEBUG_EXCEPTIONS
395 if (left) {
396 char buf[40];
397 decode_exceptions(buf, sizeof buf, left);
398 fprintf(stderr, "__cilkrts merge W%u %p nil -> %p %s\n",
399 w->self, left, left, buf);
401 #endif
402 return left;
405 #if CILK_LIB_DEBUG
406 /*volatile struct pending_exception_info left_in = *left, right_in = *right;*/
407 left->check();
408 right->check();
409 #endif
411 #if DEBUG_EXCEPTIONS
413 char buf1[40], buf2[40];
414 decode_exceptions(buf1, sizeof buf1, left);
415 decode_exceptions(buf2, sizeof buf2, right);
416 fprintf(stderr, "__cilkrts merge W%u %p %s %p %s\n",
417 w->self, left, buf1, right, buf2);
419 #endif
421 /* It should not be possible for both left and right to
422 have accumulated catch blocks.
424 The left exception record may always have a catch
425 chain it kept when its parent was stolen.
427 If they are siblings, the right sibling should not
428 have accumulated any net catches. (Catch is lexically
429 scoped.)
431 If the right frame is a parent, it should not have entered
432 a catch block without syncing first. If it spawned in a
433 catch block, the child got its catch. */
434 __cxa_exception *caught = left->runtime_state.caughtExceptions;
435 if (caught)
436 CILK_ASSERT(!right->runtime_state.caughtExceptions);
437 else {
438 CILK_ASSERT(!left->rethrow);
439 left->rethrow = right->rethrow;
440 left->runtime_state.caughtExceptions = caught = right->runtime_state.caughtExceptions;
441 right->runtime_state.caughtExceptions = NULL;
444 /* Merge the uncaught exception and count of uncaught exceptions. */
445 const unsigned int right_uncaught = right->runtime_state.uncaughtExceptions;
446 if (!left->active){
447 left->active = right->active; /* could be NULL */
448 right->active = 0;
449 left->runtime_state.uncaughtExceptions += right_uncaught;
450 if (left->active)
451 /* assert is C++ exception */
452 /*CILK_ASSERT(__cxxabiv1::__is_gxx_exception_class(left->active->exception_class))*/;
453 } else {
454 /* Subtract 1 if the right exception is being destructed. */
455 left->runtime_state.uncaughtExceptions += right_uncaught - (right->active != 0);
458 right->destruct();
459 __cilkrts_frame_free(w, right, sizeof *right);
461 /* If there is no state left, return NULL. */
462 if (left->empty()) {
463 left->destruct();
464 __cilkrts_frame_free(w, left, sizeof *left);
465 left = NULL;
468 #if CILK_LIB_DEBUG
469 if (left)
470 left->check();
471 #endif
473 return left;
476 #if 0
477 /* __cilkrts_c_resume_except is called from the assembly language
478 restart code when a resumed frame has a pending exception.
480 The handler count negation on rethrow was done when the throw was
481 resolved.
483 The assembly language runtime must make the throw unwind to
484 the sync, spawn, or other location where the exception should
485 be injected. (This should not happen after a spawn but nothing
486 here depends on there being no exception on steal.)
488 This function is unused in the Intel stack based system. */
489 extern "C"
490 void __cilkrts_c_resume_except (_Unwind_Exception *exc)
492 #if DEBUG_EXCEPTIONS
493 fprintf(stderr, "resume exception %p\n", exc);
494 #endif
495 _Unwind_Reason_Code why = _Unwind_RaiseException(exc);
496 __cilkrts_bug ("Cilk runtime error: failed to reinstate suspended exception %p (%d)\n", exc, why);
498 #endif
500 /* Restore the caught exception chain. This assumes no C++ exception
501 code will run before the frame is resumed. If there is no exception
502 to be resumed free the object. */
504 extern "C"
505 void __cilkrts_setup_for_execution_sysdep(__cilkrts_worker *w, full_frame *ff)
507 // ASSERT: We own w->lock and ff->lock || P == 1
509 __cxa_eh_globals *state = __cxa_get_globals ();
510 struct pending_exception_info *info = w->l->pending_exception;
512 if (info == NULL)
513 return;
515 w->l->pending_exception = 0;
517 #if DEBUG_EXCEPTIONS
518 _Unwind_Exception *exc = info->active;
519 if (exc) {
520 fflush(stdout);
521 fprintf(stderr, "__cilkrts_resume_except W%u %p->%p [%u %p]\n",
522 w->self, exc,
523 to_cxx(exc)->nextException,
524 info->runtime_state.uncaughtExceptions,
525 info->runtime_state.caughtExceptions);
526 /*CILK_ASSERT(info->runtime_state.uncaughtExceptions > 0);*/
528 #endif
530 if (state->uncaughtExceptions || state->caughtExceptions)
531 __cilkrts_bug("W%u: resuming with non-empty prior exception state %u %p\n", state->uncaughtExceptions, state->caughtExceptions);
533 *state = info->runtime_state;
534 info->runtime_state.caughtExceptions = 0;
535 info->runtime_state.uncaughtExceptions = 0;
537 if (info->rethrow) {
538 info->rethrow = false;
539 /* Resuming function will rethrow. Runtime calls
540 std::terminate if there is no caught exception. */
541 ff->call_stack->flags |= CILK_FRAME_EXCEPTING;
543 if (info->active) {
544 ff->call_stack->flags |= CILK_FRAME_EXCEPTING;
545 ff->call_stack->except_data = info->active;
546 info->active = 0;
549 if (info->empty()) {
550 info->destruct();
551 __cilkrts_frame_free(w, info, sizeof *info);
552 w->l->pending_exception = NULL;
555 #if CILK_LIB_DEBUG
556 if (ff->call_stack->except_data)
557 CILK_ASSERT(std::uncaught_exception());
558 #endif
561 #if 0
562 extern "C"
563 struct pending_exception_info *__cilkrts_get_exception(__cilkrts_worker *w,
564 __cilkrts_stack_frame *sf)
566 struct pending_exception_info *info = w->l->pending_exception;
568 if (info == NULL) {
569 sf->flags &= ~CILK_FRAME_EXCEPTING;
570 return 0;
573 w->l->pending_exception = NULL;
575 /* This exception goes into the frame. */
577 _Unwind_Exception *exc = info->active;
578 info->active = NULL;
579 info->destruct();
580 __cilkrts_frame_free(w, info, sizeof *info);
581 info = 0;
582 sf->flags |= CILK_FRAME_EXCEPTING;
583 sf->exception = exc;
584 return 0;
586 #endif
588 extern "C"
589 void __attribute__((nonnull)) __cilkrts_gcc_rethrow(__cilkrts_stack_frame *sf)
591 #ifdef __CYGWIN__
592 // Cygwin doesn't support exceptions, so _Unwind_Resume isn't available
593 // Which means we can't support exceptions either
594 __cilkrts_bug("The Cygwin implementation of the Intel Cilk Plus runtime doesn't support exceptions\n");
595 #else
596 if (sf->except_data) {
597 #if CILK_LIB_DEBUG
598 CILK_ASSERT(std::uncaught_exception());
599 #endif
600 _Unwind_Resume ((_Unwind_Exception *)sf->except_data);
601 } else {
602 throw;
604 #endif // __CYGWIN__
607 /* End except-gcc.cpp */