1/* Exception handling semantics and decomposition for trees. 2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 2, or (at your option) 9any later version. 10 11GCC is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with GCC; see the file COPYING. If not, write to 18the Free Software Foundation, 51 Franklin Street, Fifth Floor, 19Boston, MA 02110-1301, USA. */ 20 21#include "config.h" 22#include "system.h" 23#include "coretypes.h" 24#include "tm.h" 25#include "tree.h" 26#include "rtl.h" 27#include "tm_p.h" 28#include "flags.h" 29#include "function.h" 30#include "except.h" 31#include "tree-flow.h" 32#include "tree-dump.h" 33#include "tree-inline.h" 34#include "tree-iterator.h" 35#include "tree-pass.h" 36#include "timevar.h" 37#include "langhooks.h" 38#include "ggc.h" 39#include "toplev.h" 40 41 42/* Nonzero if we are using EH to handle cleanups. */ 43static int using_eh_for_cleanups_p = 0; 44 45void 46using_eh_for_cleanups (void) 47{ 48 using_eh_for_cleanups_p = 1; 49} 50 51/* Misc functions used in this file. */ 52 53/* Compare and hash for any structure which begins with a canonical 54 pointer. Assumes all pointers are interchangeable, which is sort 55 of already assumed by gcc elsewhere IIRC. */ 56 57static int 58struct_ptr_eq (const void *a, const void *b) 59{ 60 const void * const * x = a; 61 const void * const * y = b; 62 return *x == *y; 63} 64 65static hashval_t 66struct_ptr_hash (const void *a) 67{ 68 const void * const * x = a; 69 return (size_t)*x >> 4; 70} 71 72 73/* Remember and lookup EH region data for arbitrary statements. 74 Really this means any statement that could_throw_p. We could 75 stuff this information into the stmt_ann data structure, but: 76 77 (1) We absolutely rely on this information being kept until 78 we get to rtl. Once we're done with lowering here, if we lose 79 the information there's no way to recover it! 80 81 (2) There are many more statements that *cannot* throw as 82 compared to those that can. We should be saving some amount 83 of space by only allocating memory for those that can throw. */ 84 85static void 86record_stmt_eh_region (struct eh_region *region, tree t) 87{ 88 if (!region) 89 return; 90 91 add_stmt_to_eh_region (t, get_eh_region_number (region)); 92} 93 94void 95add_stmt_to_eh_region_fn (struct function *ifun, tree t, int num) 96{ 97 struct throw_stmt_node *n; 98 void **slot; 99 100 gcc_assert (num >= 0); 101 gcc_assert (TREE_CODE (t) != RESX_EXPR); 102 103 n = ggc_alloc (sizeof (*n)); 104 n->stmt = t; 105 n->region_nr = num; 106 107 if (!get_eh_throw_stmt_table (ifun)) 108 set_eh_throw_stmt_table (ifun, htab_create_ggc (31, struct_ptr_hash, 109 struct_ptr_eq, 110 ggc_free)); 111 112 slot = htab_find_slot (get_eh_throw_stmt_table (ifun), n, INSERT); 113 gcc_assert (!*slot); 114 *slot = n; 115 /* ??? For the benefit of calls.c, converting all this to rtl, 116 we need to record the call expression, not just the outer 117 modify statement. */ 118 if (TREE_CODE (t) == MODIFY_EXPR 119 && (t = get_call_expr_in (t))) 120 add_stmt_to_eh_region_fn (ifun, t, num); 121} 122 123void 124add_stmt_to_eh_region (tree t, int num) 125{ 126 add_stmt_to_eh_region_fn (cfun, t, num); 127} 128 129bool 130remove_stmt_from_eh_region_fn (struct function *ifun, tree t) 131{ 132 struct throw_stmt_node dummy; 133 void **slot; 134 135 if (!get_eh_throw_stmt_table (ifun)) 136 return false; 137 138 dummy.stmt = t; 139 slot = htab_find_slot (get_eh_throw_stmt_table (ifun), &dummy, 140 NO_INSERT); 141 if (slot) 142 { 143 htab_clear_slot (get_eh_throw_stmt_table (ifun), slot); 144 /* ??? For the benefit of calls.c, converting all this to rtl, 145 we need to record the call expression, not just the outer 146 modify statement. */ 147 if (TREE_CODE (t) == MODIFY_EXPR 148 && (t = get_call_expr_in (t))) 149 remove_stmt_from_eh_region_fn (ifun, t); 150 return true; 151 } 152 else 153 return false; 154} 155 156bool 157remove_stmt_from_eh_region (tree t) 158{ 159 return remove_stmt_from_eh_region_fn (cfun, t); 160} 161 162int 163lookup_stmt_eh_region_fn (struct function *ifun, tree t) 164{ 165 struct throw_stmt_node *p, n; 166 167 if (!get_eh_throw_stmt_table (ifun)) 168 return -2; 169 170 n.stmt = t; 171 p = htab_find (get_eh_throw_stmt_table (ifun), &n); 172 173 return (p ? p->region_nr : -1); 174} 175 176int 177lookup_stmt_eh_region (tree t) 178{ 179 /* We can get called from initialized data when -fnon-call-exceptions 180 is on; prevent crash. */ 181 if (!cfun) 182 return -1; 183 return lookup_stmt_eh_region_fn (cfun, t); 184} 185 186 187/* First pass of EH node decomposition. Build up a tree of TRY_FINALLY_EXPR 188 nodes and LABEL_DECL nodes. We will use this during the second phase to 189 determine if a goto leaves the body of a TRY_FINALLY_EXPR node. */ 190 191struct finally_tree_node 192{ 193 tree child, parent; 194}; 195 196/* Note that this table is *not* marked GTY. It is short-lived. */ 197static htab_t finally_tree; 198 199static void 200record_in_finally_tree (tree child, tree parent) 201{ 202 struct finally_tree_node *n; 203 void **slot; 204 205 n = xmalloc (sizeof (*n)); 206 n->child = child; 207 n->parent = parent; 208 209 slot = htab_find_slot (finally_tree, n, INSERT); 210 gcc_assert (!*slot); 211 *slot = n; 212} 213 214static void 215collect_finally_tree (tree t, tree region) 216{ 217 tailrecurse: 218 switch (TREE_CODE (t)) 219 { 220 case LABEL_EXPR: 221 record_in_finally_tree (LABEL_EXPR_LABEL (t), region); 222 break; 223 224 case TRY_FINALLY_EXPR: 225 record_in_finally_tree (t, region); 226 collect_finally_tree (TREE_OPERAND (t, 0), t); 227 t = TREE_OPERAND (t, 1); 228 goto tailrecurse; 229 230 case TRY_CATCH_EXPR: 231 collect_finally_tree (TREE_OPERAND (t, 0), region); 232 t = TREE_OPERAND (t, 1); 233 goto tailrecurse; 234 235 case CATCH_EXPR: 236 t = CATCH_BODY (t); 237 goto tailrecurse; 238 239 case EH_FILTER_EXPR: 240 t = EH_FILTER_FAILURE (t); 241 goto tailrecurse; 242 243 case STATEMENT_LIST: 244 { 245 tree_stmt_iterator i; 246 for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) 247 collect_finally_tree (tsi_stmt (i), region); 248 } 249 break; 250 251 default: 252 /* A type, a decl, or some kind of statement that we're not 253 interested in. Don't walk them. */ 254 break; 255 } 256} 257 258/* Use the finally tree to determine if a jump from START to TARGET 259 would leave the try_finally node that START lives in. */ 260 261static bool 262outside_finally_tree (tree start, tree target) 263{ 264 struct finally_tree_node n, *p; 265 266 do 267 { 268 n.child = start; 269 p = htab_find (finally_tree, &n); 270 if (!p) 271 return true; 272 start = p->parent; 273 } 274 while (start != target); 275 276 return false; 277} 278 279/* Second pass of EH node decomposition. Actually transform the TRY_FINALLY 280 and TRY_CATCH nodes into a set of gotos, magic labels, and eh regions. 281 The eh region creation is straight-forward, but frobbing all the gotos 282 and such into shape isn't. */ 283 284/* State of the world while lowering. */ 285 286struct leh_state 287{ 288 /* What's "current" while constructing the eh region tree. These 289 correspond to variables of the same name in cfun->eh, which we 290 don't have easy access to. */ 291 struct eh_region *cur_region; 292 struct eh_region *prev_try; 293 294 /* Processing of TRY_FINALLY requires a bit more state. This is 295 split out into a separate structure so that we don't have to 296 copy so much when processing other nodes. */ 297 struct leh_tf_state *tf; 298}; 299 300struct leh_tf_state 301{ 302 /* Pointer to the TRY_FINALLY node under discussion. The try_finally_expr 303 is the original TRY_FINALLY_EXPR. We need to retain this so that 304 outside_finally_tree can reliably reference the tree used in the 305 collect_finally_tree data structures. */ 306 tree try_finally_expr; 307 tree *top_p; 308 309 /* The state outside this try_finally node. */ 310 struct leh_state *outer; 311 312 /* The exception region created for it. */ 313 struct eh_region *region; 314 315 /* The GOTO_QUEUE is is an array of GOTO_EXPR and RETURN_EXPR statements 316 that are seen to escape this TRY_FINALLY_EXPR node. */ 317 struct goto_queue_node { 318 tree stmt; 319 tree repl_stmt; 320 tree cont_stmt; 321 int index; 322 } *goto_queue; 323 size_t goto_queue_size; 324 size_t goto_queue_active; 325 326 /* The set of unique labels seen as entries in the goto queue. */ 327 VEC(tree,heap) *dest_array; 328 329 /* A label to be added at the end of the completed transformed 330 sequence. It will be set if may_fallthru was true *at one time*, 331 though subsequent transformations may have cleared that flag. */ 332 tree fallthru_label; 333 334 /* A label that has been registered with except.c to be the 335 landing pad for this try block. */ 336 tree eh_label; 337 338 /* True if it is possible to fall out the bottom of the try block. 339 Cleared if the fallthru is converted to a goto. */ 340 bool may_fallthru; 341 342 /* True if any entry in goto_queue is a RETURN_EXPR. */ 343 bool may_return; 344 345 /* True if the finally block can receive an exception edge. 346 Cleared if the exception case is handled by code duplication. */ 347 bool may_throw; 348}; 349 350static void lower_eh_filter (struct leh_state *, tree *); 351static void lower_eh_constructs_1 (struct leh_state *, tree *); 352 353/* Comparison function for qsort/bsearch. We're interested in 354 searching goto queue elements for source statements. */ 355 356static int 357goto_queue_cmp (const void *x, const void *y) 358{ 359 tree a = ((const struct goto_queue_node *)x)->stmt; 360 tree b = ((const struct goto_queue_node *)y)->stmt; 361 return (a == b ? 0 : a < b ? -1 : 1); 362} 363 364/* Search for STMT in the goto queue. Return the replacement, 365 or null if the statement isn't in the queue. */ 366 367static tree 368find_goto_replacement (struct leh_tf_state *tf, tree stmt) 369{ 370 struct goto_queue_node tmp, *ret; 371 tmp.stmt = stmt; 372 ret = bsearch (&tmp, tf->goto_queue, tf->goto_queue_active, 373 sizeof (struct goto_queue_node), goto_queue_cmp); 374 return (ret ? ret->repl_stmt : NULL); 375} 376 377/* A subroutine of replace_goto_queue_1. Handles the sub-clauses of a 378 lowered COND_EXPR. If, by chance, the replacement is a simple goto, 379 then we can just splat it in, otherwise we add the new stmts immediately 380 after the COND_EXPR and redirect. */ 381 382static void 383replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf, 384 tree_stmt_iterator *tsi) 385{ 386 tree new, one, label; 387 388 new = find_goto_replacement (tf, *tp); 389 if (!new) 390 return; 391 392 one = expr_only (new); 393 if (one && TREE_CODE (one) == GOTO_EXPR) 394 { 395 *tp = one; 396 return; 397 } 398 399 label = build1 (LABEL_EXPR, void_type_node, NULL_TREE); 400 *tp = build_and_jump (&LABEL_EXPR_LABEL (label)); 401 402 tsi_link_after (tsi, label, TSI_CONTINUE_LINKING); 403 tsi_link_after (tsi, new, TSI_CONTINUE_LINKING); 404} 405 406/* The real work of replace_goto_queue. Returns with TSI updated to 407 point to the next statement. */ 408 409static void replace_goto_queue_stmt_list (tree, struct leh_tf_state *); 410 411static void 412replace_goto_queue_1 (tree t, struct leh_tf_state *tf, tree_stmt_iterator *tsi) 413{ 414 switch (TREE_CODE (t)) 415 { 416 case GOTO_EXPR: 417 case RETURN_EXPR: 418 t = find_goto_replacement (tf, t); 419 if (t) 420 { 421 tsi_link_before (tsi, t, TSI_SAME_STMT); 422 tsi_delink (tsi); 423 return; 424 } 425 break; 426 427 case COND_EXPR: 428 replace_goto_queue_cond_clause (&COND_EXPR_THEN (t), tf, tsi); 429 replace_goto_queue_cond_clause (&COND_EXPR_ELSE (t), tf, tsi); 430 break; 431 432 case TRY_FINALLY_EXPR: 433 case TRY_CATCH_EXPR: 434 replace_goto_queue_stmt_list (TREE_OPERAND (t, 0), tf); 435 replace_goto_queue_stmt_list (TREE_OPERAND (t, 1), tf); 436 break; 437 case CATCH_EXPR: 438 replace_goto_queue_stmt_list (CATCH_BODY (t), tf); 439 break; 440 case EH_FILTER_EXPR: 441 replace_goto_queue_stmt_list (EH_FILTER_FAILURE (t), tf); 442 break; 443 444 case STATEMENT_LIST: 445 gcc_unreachable (); 446 447 default: 448 /* These won't have gotos in them. */ 449 break; 450 } 451 452 tsi_next (tsi); 453} 454 455/* A subroutine of replace_goto_queue. Handles STATEMENT_LISTs. */ 456 457static void 458replace_goto_queue_stmt_list (tree t, struct leh_tf_state *tf) 459{ 460 tree_stmt_iterator i = tsi_start (t); 461 while (!tsi_end_p (i)) 462 replace_goto_queue_1 (tsi_stmt (i), tf, &i); 463} 464 465/* Replace all goto queue members. */ 466 467static void 468replace_goto_queue (struct leh_tf_state *tf) 469{ 470 if (tf->goto_queue_active == 0) 471 return; 472 replace_goto_queue_stmt_list (*tf->top_p, tf); 473} 474 475/* For any GOTO_EXPR or RETURN_EXPR, decide whether it leaves a try_finally 476 node, and if so record that fact in the goto queue associated with that 477 try_finally node. */ 478 479static void 480maybe_record_in_goto_queue (struct leh_state *state, tree stmt) 481{ 482 struct leh_tf_state *tf = state->tf; 483 struct goto_queue_node *q; 484 size_t active, size; 485 int index; 486 487 if (!tf) 488 return; 489 490 switch (TREE_CODE (stmt)) 491 { 492 case GOTO_EXPR: 493 { 494 tree lab = GOTO_DESTINATION (stmt); 495 496 /* Computed and non-local gotos do not get processed. Given 497 their nature we can neither tell whether we've escaped the 498 finally block nor redirect them if we knew. */ 499 if (TREE_CODE (lab) != LABEL_DECL) 500 return; 501 502 /* No need to record gotos that don't leave the try block. */ 503 if (! outside_finally_tree (lab, tf->try_finally_expr)) 504 return; 505 506 if (! tf->dest_array) 507 { 508 tf->dest_array = VEC_alloc (tree, heap, 10); 509 VEC_quick_push (tree, tf->dest_array, lab); 510 index = 0; 511 } 512 else 513 { 514 int n = VEC_length (tree, tf->dest_array); 515 for (index = 0; index < n; ++index) 516 if (VEC_index (tree, tf->dest_array, index) == lab) 517 break; 518 if (index == n) 519 VEC_safe_push (tree, heap, tf->dest_array, lab); 520 } 521 } 522 break; 523 524 case RETURN_EXPR: 525 tf->may_return = true; 526 index = -1; 527 break; 528 529 default: 530 gcc_unreachable (); 531 } 532 533 active = tf->goto_queue_active; 534 size = tf->goto_queue_size; 535 if (active >= size) 536 { 537 size = (size ? size * 2 : 32); 538 tf->goto_queue_size = size; 539 tf->goto_queue 540 = xrealloc (tf->goto_queue, size * sizeof (struct goto_queue_node)); 541 } 542 543 q = &tf->goto_queue[active]; 544 tf->goto_queue_active = active + 1; 545 546 memset (q, 0, sizeof (*q)); 547 q->stmt = stmt; 548 q->index = index; 549} 550 551#ifdef ENABLE_CHECKING 552/* We do not process SWITCH_EXPRs for now. As long as the original source 553 was in fact structured, and we've not yet done jump threading, then none 554 of the labels will leave outer TRY_FINALLY_EXPRs. Verify this. */ 555 556static void 557verify_norecord_switch_expr (struct leh_state *state, tree switch_expr) 558{ 559 struct leh_tf_state *tf = state->tf; 560 size_t i, n; 561 tree vec; 562 563 if (!tf) 564 return; 565 566 vec = SWITCH_LABELS (switch_expr); 567 n = TREE_VEC_LENGTH (vec); 568 569 for (i = 0; i < n; ++i) 570 { 571 tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i)); 572 gcc_assert (!outside_finally_tree (lab, tf->try_finally_expr)); 573 } 574} 575#else 576#define verify_norecord_switch_expr(state, switch_expr) 577#endif 578 579/* Redirect a RETURN_EXPR pointed to by STMT_P to FINLAB. Place in CONT_P 580 whatever is needed to finish the return. If MOD is non-null, insert it 581 before the new branch. RETURN_VALUE_P is a cache containing a temporary 582 variable to be used in manipulating the value returned from the function. */ 583 584static void 585do_return_redirection (struct goto_queue_node *q, tree finlab, tree mod, 586 tree *return_value_p) 587{ 588 tree ret_expr = TREE_OPERAND (q->stmt, 0); 589 tree x; 590 591 if (ret_expr) 592 { 593 /* The nasty part about redirecting the return value is that the 594 return value itself is to be computed before the FINALLY block 595 is executed. e.g. 596 597 int x; 598 int foo (void) 599 { 600 x = 0; 601 try { 602 return x; 603 } finally { 604 x++; 605 } 606 } 607 608 should return 0, not 1. Arrange for this to happen by copying 609 computed the return value into a local temporary. This also 610 allows us to redirect multiple return statements through the 611 same destination block; whether this is a net win or not really 612 depends, I guess, but it does make generation of the switch in 613 lower_try_finally_switch easier. */ 614 615 switch (TREE_CODE (ret_expr)) 616 { 617 case RESULT_DECL: 618 if (!*return_value_p) 619 *return_value_p = ret_expr; 620 else 621 gcc_assert (*return_value_p == ret_expr); 622 q->cont_stmt = q->stmt; 623 break; 624 625 case MODIFY_EXPR: 626 { 627 tree result = TREE_OPERAND (ret_expr, 0); 628 tree new, old = TREE_OPERAND (ret_expr, 1); 629 630 if (!*return_value_p) 631 { 632 if (aggregate_value_p (TREE_TYPE (result), 633 TREE_TYPE (current_function_decl))) 634 /* If this function returns in memory, copy the argument 635 into the return slot now. Otherwise, we might need to 636 worry about magic return semantics, so we need to use a 637 temporary to hold the value until we're actually ready 638 to return. */ 639 new = result; 640 else 641 new = create_tmp_var (TREE_TYPE (old), "rettmp"); 642 *return_value_p = new; 643 } 644 else 645 new = *return_value_p; 646 647 x = build (MODIFY_EXPR, TREE_TYPE (new), new, old); 648 append_to_statement_list (x, &q->repl_stmt); 649 650 if (new == result) 651 x = result; 652 else 653 x = build (MODIFY_EXPR, TREE_TYPE (result), result, new); 654 q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x); 655 } 656 657 default: 658 gcc_unreachable (); 659 } 660 } 661 else 662 { 663 /* If we don't return a value, all return statements are the same. */ 664 q->cont_stmt = q->stmt; 665 } 666 667 if (mod) 668 append_to_statement_list (mod, &q->repl_stmt); 669 670 x = build1 (GOTO_EXPR, void_type_node, finlab); 671 append_to_statement_list (x, &q->repl_stmt); 672} 673 674/* Similar, but easier, for GOTO_EXPR. */ 675 676static void 677do_goto_redirection (struct goto_queue_node *q, tree finlab, tree mod) 678{ 679 tree x; 680 681 q->cont_stmt = q->stmt; 682 if (mod) 683 append_to_statement_list (mod, &q->repl_stmt); 684 685 x = build1 (GOTO_EXPR, void_type_node, finlab); 686 append_to_statement_list (x, &q->repl_stmt); 687} 688 689/* We want to transform 690 try { body; } catch { stuff; } 691 to 692 body; goto over; lab: stuff; over: 693 694 T is a TRY_FINALLY or TRY_CATCH node. LAB is the label that 695 should be placed before the second operand, or NULL. OVER is 696 an existing label that should be put at the exit, or NULL. */ 697 698static void 699frob_into_branch_around (tree *tp, tree lab, tree over) 700{ 701 tree x, op1; 702 703 op1 = TREE_OPERAND (*tp, 1); 704 *tp = TREE_OPERAND (*tp, 0); 705 706 if (block_may_fallthru (*tp)) 707 { 708 if (!over) 709 over = create_artificial_label (); 710 x = build1 (GOTO_EXPR, void_type_node, over); 711 append_to_statement_list (x, tp); 712 } 713 714 if (lab) 715 { 716 x = build1 (LABEL_EXPR, void_type_node, lab); 717 append_to_statement_list (x, tp); 718 } 719 720 append_to_statement_list (op1, tp); 721 722 if (over) 723 { 724 x = build1 (LABEL_EXPR, void_type_node, over); 725 append_to_statement_list (x, tp); 726 } 727} 728 729/* A subroutine of lower_try_finally. Duplicate the tree rooted at T. 730 Make sure to record all new labels found. */ 731 732static tree 733lower_try_finally_dup_block (tree t, struct leh_state *outer_state) 734{ 735 tree region = NULL; 736 737 t = unsave_expr_now (t); 738 739 if (outer_state->tf) 740 region = outer_state->tf->try_finally_expr; 741 collect_finally_tree (t, region); 742 743 return t; 744} 745 746/* A subroutine of lower_try_finally. Create a fallthru label for 747 the given try_finally state. The only tricky bit here is that 748 we have to make sure to record the label in our outer context. */ 749 750static tree 751lower_try_finally_fallthru_label (struct leh_tf_state *tf) 752{ 753 tree label = tf->fallthru_label; 754 if (!label) 755 { 756 label = create_artificial_label (); 757 tf->fallthru_label = label; 758 if (tf->outer->tf) 759 record_in_finally_tree (label, tf->outer->tf->try_finally_expr); 760 } 761 return label; 762} 763 764/* A subroutine of lower_try_finally. If lang_protect_cleanup_actions 765 returns non-null, then the language requires that the exception path out 766 of a try_finally be treated specially. To wit: the code within the 767 finally block may not itself throw an exception. We have two choices here. 768 First we can duplicate the finally block and wrap it in a must_not_throw 769 region. Second, we can generate code like 770 771 try { 772 finally_block; 773 } catch { 774 if (fintmp == eh_edge) 775 protect_cleanup_actions; 776 } 777 778 where "fintmp" is the temporary used in the switch statement generation 779 alternative considered below. For the nonce, we always choose the first 780 option. 781 782 THIS_STATE may be null if this is a try-cleanup, not a try-finally. */ 783 784static void 785honor_protect_cleanup_actions (struct leh_state *outer_state, 786 struct leh_state *this_state, 787 struct leh_tf_state *tf) 788{ 789 tree protect_cleanup_actions, finally, x; 790 tree_stmt_iterator i; 791 bool finally_may_fallthru; 792 793 /* First check for nothing to do. */ 794 if (lang_protect_cleanup_actions) 795 protect_cleanup_actions = lang_protect_cleanup_actions (); 796 else 797 protect_cleanup_actions = NULL; 798 799 finally = TREE_OPERAND (*tf->top_p, 1); 800 801 /* If the EH case of the finally block can fall through, this may be a 802 structure of the form 803 try { 804 try { 805 throw ...; 806 } cleanup { 807 try { 808 throw ...; 809 } catch (...) { 810 } 811 } 812 } catch (...) { 813 yyy; 814 } 815 E.g. with an inline destructor with an embedded try block. In this 816 case we must save the runtime EH data around the nested exception. 817 818 This complication means that any time the previous runtime data might 819 be used (via fallthru from the finally) we handle the eh case here, 820 whether or not protect_cleanup_actions is active. */ 821 822 finally_may_fallthru = block_may_fallthru (finally); 823 if (!finally_may_fallthru && !protect_cleanup_actions) 824 return; 825 826 /* Duplicate the FINALLY block. Only need to do this for try-finally, 827 and not for cleanups. */ 828 if (this_state) 829 finally = lower_try_finally_dup_block (finally, outer_state); 830 831 /* Resume execution after the exception. Adding this now lets 832 lower_eh_filter not add unnecessary gotos, as it is clear that 833 we never fallthru from this copy of the finally block. */ 834 if (finally_may_fallthru) 835 { 836 tree save_eptr, save_filt; 837 838 save_eptr = create_tmp_var (ptr_type_node, "save_eptr"); 839 save_filt = create_tmp_var (integer_type_node, "save_filt"); 840 841 i = tsi_start (finally); 842 x = build (EXC_PTR_EXPR, ptr_type_node); 843 x = build (MODIFY_EXPR, void_type_node, save_eptr, x); 844 tsi_link_before (&i, x, TSI_CONTINUE_LINKING); 845 846 x = build (FILTER_EXPR, integer_type_node); 847 x = build (MODIFY_EXPR, void_type_node, save_filt, x); 848 tsi_link_before (&i, x, TSI_CONTINUE_LINKING); 849 850 i = tsi_last (finally); 851 x = build (EXC_PTR_EXPR, ptr_type_node); 852 x = build (MODIFY_EXPR, void_type_node, x, save_eptr); 853 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 854 855 x = build (FILTER_EXPR, integer_type_node); 856 x = build (MODIFY_EXPR, void_type_node, x, save_filt); 857 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 858 859 x = build_resx (get_eh_region_number (tf->region)); 860 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 861 } 862 863 /* Wrap the block with protect_cleanup_actions as the action. */ 864 if (protect_cleanup_actions) 865 { 866 x = build (EH_FILTER_EXPR, void_type_node, NULL, NULL); 867 append_to_statement_list (protect_cleanup_actions, &EH_FILTER_FAILURE (x)); 868 EH_FILTER_MUST_NOT_THROW (x) = 1; 869 finally = build (TRY_CATCH_EXPR, void_type_node, finally, x); 870 lower_eh_filter (outer_state, &finally); 871 } 872 else 873 lower_eh_constructs_1 (outer_state, &finally); 874 875 /* Hook this up to the end of the existing try block. If we 876 previously fell through the end, we'll have to branch around. 877 This means adding a new goto, and adding it to the queue. */ 878 879 i = tsi_last (TREE_OPERAND (*tf->top_p, 0)); 880 881 if (tf->may_fallthru) 882 { 883 x = lower_try_finally_fallthru_label (tf); 884 x = build1 (GOTO_EXPR, void_type_node, x); 885 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 886 887 if (this_state) 888 maybe_record_in_goto_queue (this_state, x); 889 890 tf->may_fallthru = false; 891 } 892 893 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); 894 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 895 tsi_link_after (&i, finally, TSI_CONTINUE_LINKING); 896 897 /* Having now been handled, EH isn't to be considered with 898 the rest of the outgoing edges. */ 899 tf->may_throw = false; 900} 901 902/* A subroutine of lower_try_finally. We have determined that there is 903 no fallthru edge out of the finally block. This means that there is 904 no outgoing edge corresponding to any incoming edge. Restructure the 905 try_finally node for this special case. */ 906 907static void 908lower_try_finally_nofallthru (struct leh_state *state, struct leh_tf_state *tf) 909{ 910 tree x, finally, lab, return_val; 911 struct goto_queue_node *q, *qe; 912 913 if (tf->may_throw) 914 lab = tf->eh_label; 915 else 916 lab = create_artificial_label (); 917 918 finally = TREE_OPERAND (*tf->top_p, 1); 919 *tf->top_p = TREE_OPERAND (*tf->top_p, 0); 920 921 x = build1 (LABEL_EXPR, void_type_node, lab); 922 append_to_statement_list (x, tf->top_p); 923 924 return_val = NULL; 925 q = tf->goto_queue; 926 qe = q + tf->goto_queue_active; 927 for (; q < qe; ++q) 928 if (q->index < 0) 929 do_return_redirection (q, lab, NULL, &return_val); 930 else 931 do_goto_redirection (q, lab, NULL); 932 933 replace_goto_queue (tf); 934 935 lower_eh_constructs_1 (state, &finally); 936 append_to_statement_list (finally, tf->top_p); 937} 938 939/* A subroutine of lower_try_finally. We have determined that there is 940 exactly one destination of the finally block. Restructure the 941 try_finally node for this special case. */ 942 943static void 944lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) 945{ 946 struct goto_queue_node *q, *qe; 947 tree x, finally, finally_label; 948 949 finally = TREE_OPERAND (*tf->top_p, 1); 950 *tf->top_p = TREE_OPERAND (*tf->top_p, 0); 951 952 lower_eh_constructs_1 (state, &finally); 953 954 if (tf->may_throw) 955 { 956 /* Only reachable via the exception edge. Add the given label to 957 the head of the FINALLY block. Append a RESX at the end. */ 958 959 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); 960 append_to_statement_list (x, tf->top_p); 961 962 append_to_statement_list (finally, tf->top_p); 963 964 x = build_resx (get_eh_region_number (tf->region)); 965 966 append_to_statement_list (x, tf->top_p); 967 968 return; 969 } 970 971 if (tf->may_fallthru) 972 { 973 /* Only reachable via the fallthru edge. Do nothing but let 974 the two blocks run together; we'll fall out the bottom. */ 975 append_to_statement_list (finally, tf->top_p); 976 return; 977 } 978 979 finally_label = create_artificial_label (); 980 x = build1 (LABEL_EXPR, void_type_node, finally_label); 981 append_to_statement_list (x, tf->top_p); 982 983 append_to_statement_list (finally, tf->top_p); 984 985 q = tf->goto_queue; 986 qe = q + tf->goto_queue_active; 987 988 if (tf->may_return) 989 { 990 /* Reachable by return expressions only. Redirect them. */ 991 tree return_val = NULL; 992 for (; q < qe; ++q) 993 do_return_redirection (q, finally_label, NULL, &return_val); 994 replace_goto_queue (tf); 995 } 996 else 997 { 998 /* Reachable by goto expressions only. Redirect them. */ 999 for (; q < qe; ++q) 1000 do_goto_redirection (q, finally_label, NULL); 1001 replace_goto_queue (tf); 1002 1003 if (VEC_index (tree, tf->dest_array, 0) == tf->fallthru_label) 1004 { 1005 /* Reachable by goto to fallthru label only. Redirect it 1006 to the new label (already created, sadly), and do not 1007 emit the final branch out, or the fallthru label. */ 1008 tf->fallthru_label = NULL; 1009 return; 1010 } 1011 } 1012 1013 append_to_statement_list (tf->goto_queue[0].cont_stmt, tf->top_p); 1014 maybe_record_in_goto_queue (state, tf->goto_queue[0].cont_stmt); 1015} 1016 1017/* A subroutine of lower_try_finally. There are multiple edges incoming 1018 and outgoing from the finally block. Implement this by duplicating the 1019 finally block for every destination. */ 1020 1021static void 1022lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf) 1023{ 1024 tree finally, new_stmt; 1025 tree x; 1026 1027 finally = TREE_OPERAND (*tf->top_p, 1); 1028 *tf->top_p = TREE_OPERAND (*tf->top_p, 0); 1029 1030 new_stmt = NULL_TREE; 1031 1032 if (tf->may_fallthru) 1033 { 1034 x = lower_try_finally_dup_block (finally, state); 1035 lower_eh_constructs_1 (state, &x); 1036 append_to_statement_list (x, &new_stmt); 1037 1038 x = lower_try_finally_fallthru_label (tf); 1039 x = build1 (GOTO_EXPR, void_type_node, x); 1040 append_to_statement_list (x, &new_stmt); 1041 } 1042 1043 if (tf->may_throw) 1044 { 1045 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); 1046 append_to_statement_list (x, &new_stmt); 1047 1048 x = lower_try_finally_dup_block (finally, state); 1049 lower_eh_constructs_1 (state, &x); 1050 append_to_statement_list (x, &new_stmt); 1051 1052 x = build_resx (get_eh_region_number (tf->region)); 1053 append_to_statement_list (x, &new_stmt); 1054 } 1055 1056 if (tf->goto_queue) 1057 { 1058 struct goto_queue_node *q, *qe; 1059 tree return_val = NULL; 1060 int return_index, index; 1061 struct 1062 { 1063 struct goto_queue_node *q; 1064 tree label; 1065 } *labels; 1066 1067 return_index = VEC_length (tree, tf->dest_array); 1068 labels = xcalloc (sizeof (*labels), return_index + 1); 1069 1070 q = tf->goto_queue; 1071 qe = q + tf->goto_queue_active; 1072 for (; q < qe; q++) 1073 { 1074 index = q->index < 0 ? return_index : q->index; 1075 1076 if (!labels[index].q) 1077 labels[index].q = q; 1078 } 1079 1080 for (index = 0; index < return_index + 1; index++) 1081 { 1082 tree lab; 1083 1084 q = labels[index].q; 1085 if (! q) 1086 continue; 1087 1088 lab = labels[index].label = create_artificial_label (); 1089 1090 if (index == return_index) 1091 do_return_redirection (q, lab, NULL, &return_val); 1092 else 1093 do_goto_redirection (q, lab, NULL); 1094 1095 x = build1 (LABEL_EXPR, void_type_node, lab); 1096 append_to_statement_list (x, &new_stmt); 1097 1098 x = lower_try_finally_dup_block (finally, state); 1099 lower_eh_constructs_1 (state, &x); 1100 append_to_statement_list (x, &new_stmt); 1101 1102 append_to_statement_list (q->cont_stmt, &new_stmt); 1103 maybe_record_in_goto_queue (state, q->cont_stmt); 1104 } 1105 1106 for (q = tf->goto_queue; q < qe; q++) 1107 { 1108 tree lab; 1109 1110 index = q->index < 0 ? return_index : q->index; 1111 1112 if (labels[index].q == q) 1113 continue; 1114 1115 lab = labels[index].label; 1116 1117 if (index == return_index) 1118 do_return_redirection (q, lab, NULL, &return_val); 1119 else 1120 do_goto_redirection (q, lab, NULL); 1121 } 1122 1123 replace_goto_queue (tf); 1124 free (labels); 1125 } 1126 1127 /* Need to link new stmts after running replace_goto_queue due 1128 to not wanting to process the same goto stmts twice. */ 1129 append_to_statement_list (new_stmt, tf->top_p); 1130} 1131 1132/* A subroutine of lower_try_finally. There are multiple edges incoming 1133 and outgoing from the finally block. Implement this by instrumenting 1134 each incoming edge and creating a switch statement at the end of the 1135 finally block that branches to the appropriate destination. */ 1136 1137static void 1138lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) 1139{ 1140 struct goto_queue_node *q, *qe; 1141 tree return_val = NULL; 1142 tree finally, finally_tmp, finally_label; 1143 int return_index, eh_index, fallthru_index; 1144 int nlabels, ndests, j, last_case_index; 1145 tree case_label_vec, switch_stmt, last_case, switch_body; 1146 tree x; 1147 1148 /* Mash the TRY block to the head of the chain. */ 1149 finally = TREE_OPERAND (*tf->top_p, 1); 1150 *tf->top_p = TREE_OPERAND (*tf->top_p, 0); 1151 1152 /* Lower the finally block itself. */ 1153 lower_eh_constructs_1 (state, &finally); 1154 1155 /* Prepare for switch statement generation. */ 1156 nlabels = VEC_length (tree, tf->dest_array); 1157 return_index = nlabels; 1158 eh_index = return_index + tf->may_return; 1159 fallthru_index = eh_index + tf->may_throw; 1160 ndests = fallthru_index + tf->may_fallthru; 1161 1162 finally_tmp = create_tmp_var (integer_type_node, "finally_tmp"); 1163 finally_label = create_artificial_label (); 1164 1165 case_label_vec = make_tree_vec (ndests); 1166 switch_stmt = build (SWITCH_EXPR, integer_type_node, finally_tmp, 1167 NULL_TREE, case_label_vec); 1168 switch_body = NULL; 1169 last_case = NULL; 1170 last_case_index = 0; 1171 1172 /* Begin inserting code for getting to the finally block. Things 1173 are done in this order to correspond to the sequence the code is 1174 layed out. */ 1175 1176 if (tf->may_fallthru) 1177 { 1178 x = build (MODIFY_EXPR, void_type_node, finally_tmp, 1179 build_int_cst (NULL_TREE, fallthru_index)); 1180 append_to_statement_list (x, tf->top_p); 1181 1182 if (tf->may_throw) 1183 { 1184 x = build1 (GOTO_EXPR, void_type_node, finally_label); 1185 append_to_statement_list (x, tf->top_p); 1186 } 1187 1188 1189 last_case = build (CASE_LABEL_EXPR, void_type_node, 1190 build_int_cst (NULL_TREE, fallthru_index), NULL, 1191 create_artificial_label ()); 1192 TREE_VEC_ELT (case_label_vec, last_case_index) = last_case; 1193 last_case_index++; 1194 1195 x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case)); 1196 append_to_statement_list (x, &switch_body); 1197 1198 x = lower_try_finally_fallthru_label (tf); 1199 x = build1 (GOTO_EXPR, void_type_node, x); 1200 append_to_statement_list (x, &switch_body); 1201 } 1202 1203 if (tf->may_throw) 1204 { 1205 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); 1206 append_to_statement_list (x, tf->top_p); 1207 1208 x = build (MODIFY_EXPR, void_type_node, finally_tmp, 1209 build_int_cst (NULL_TREE, eh_index)); 1210 append_to_statement_list (x, tf->top_p); 1211 1212 last_case = build (CASE_LABEL_EXPR, void_type_node, 1213 build_int_cst (NULL_TREE, eh_index), NULL, 1214 create_artificial_label ()); 1215 TREE_VEC_ELT (case_label_vec, last_case_index) = last_case; 1216 last_case_index++; 1217 1218 x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case)); 1219 append_to_statement_list (x, &switch_body); 1220 x = build_resx (get_eh_region_number (tf->region)); 1221 append_to_statement_list (x, &switch_body); 1222 } 1223 1224 x = build1 (LABEL_EXPR, void_type_node, finally_label); 1225 append_to_statement_list (x, tf->top_p); 1226 1227 append_to_statement_list (finally, tf->top_p); 1228 1229 /* Redirect each incoming goto edge. */ 1230 q = tf->goto_queue; 1231 qe = q + tf->goto_queue_active; 1232 j = last_case_index + tf->may_return; 1233 for (; q < qe; ++q) 1234 { 1235 tree mod; 1236 int switch_id, case_index; 1237 1238 if (q->index < 0) 1239 { 1240 mod = build (MODIFY_EXPR, void_type_node, finally_tmp, 1241 build_int_cst (NULL_TREE, return_index)); 1242 do_return_redirection (q, finally_label, mod, &return_val); 1243 switch_id = return_index; 1244 } 1245 else 1246 { 1247 mod = build (MODIFY_EXPR, void_type_node, finally_tmp, 1248 build_int_cst (NULL_TREE, q->index)); 1249 do_goto_redirection (q, finally_label, mod); 1250 switch_id = q->index; 1251 } 1252 1253 case_index = j + q->index; 1254 if (!TREE_VEC_ELT (case_label_vec, case_index)) 1255 TREE_VEC_ELT (case_label_vec, case_index) 1256 = build (CASE_LABEL_EXPR, void_type_node, 1257 build_int_cst (NULL_TREE, switch_id), NULL, 1258 /* We store the cont_stmt in the 1259 CASE_LABEL, so that we can recover it 1260 in the loop below. We don't create 1261 the new label while walking the 1262 goto_queue because pointers don't 1263 offer a stable order. */ 1264 q->cont_stmt); 1265 } 1266 for (j = last_case_index; j < last_case_index + nlabels; j++) 1267 { 1268 tree label; 1269 tree cont_stmt; 1270 1271 last_case = TREE_VEC_ELT (case_label_vec, j); 1272 1273 gcc_assert (last_case); 1274 1275 cont_stmt = CASE_LABEL (last_case); 1276 1277 label = create_artificial_label (); 1278 CASE_LABEL (last_case) = label; 1279 1280 x = build (LABEL_EXPR, void_type_node, label); 1281 append_to_statement_list (x, &switch_body); 1282 append_to_statement_list (cont_stmt, &switch_body); 1283 maybe_record_in_goto_queue (state, cont_stmt); 1284 } 1285 replace_goto_queue (tf); 1286 1287 /* Make sure that the last case is the default label, as one is required. 1288 Then sort the labels, which is also required in GIMPLE. */ 1289 CASE_LOW (last_case) = NULL; 1290 sort_case_labels (case_label_vec); 1291 1292 /* Need to link switch_stmt after running replace_goto_queue due 1293 to not wanting to process the same goto stmts twice. */ 1294 append_to_statement_list (switch_stmt, tf->top_p); 1295 append_to_statement_list (switch_body, tf->top_p); 1296} 1297 1298/* Decide whether or not we are going to duplicate the finally block. 1299 There are several considerations. 1300 1301 First, if this is Java, then the finally block contains code 1302 written by the user. It has line numbers associated with it, 1303 so duplicating the block means it's difficult to set a breakpoint. 1304 Since controlling code generation via -g is verboten, we simply 1305 never duplicate code without optimization. 1306 1307 Second, we'd like to prevent egregious code growth. One way to 1308 do this is to estimate the size of the finally block, multiply 1309 that by the number of copies we'd need to make, and compare against 1310 the estimate of the size of the switch machinery we'd have to add. */ 1311 1312static bool 1313decide_copy_try_finally (int ndests, tree finally) 1314{ 1315 int f_estimate, sw_estimate; 1316 1317 if (!optimize) 1318 return false; 1319 1320 /* Finally estimate N times, plus N gotos. */ 1321 f_estimate = estimate_num_insns (finally); 1322 f_estimate = (f_estimate + 1) * ndests; 1323 1324 /* Switch statement (cost 10), N variable assignments, N gotos. */ 1325 sw_estimate = 10 + 2 * ndests; 1326 1327 /* Optimize for size clearly wants our best guess. */ 1328 if (optimize_size) 1329 return f_estimate < sw_estimate; 1330 1331 /* ??? These numbers are completely made up so far. */ 1332 if (optimize > 1) 1333 return f_estimate < 100 || f_estimate < sw_estimate * 2; 1334 else 1335 return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3; 1336} 1337 1338/* A subroutine of lower_eh_constructs_1. Lower a TRY_FINALLY_EXPR nodes 1339 to a sequence of labels and blocks, plus the exception region trees 1340 that record all the magic. This is complicated by the need to 1341 arrange for the FINALLY block to be executed on all exits. */ 1342 1343static void 1344lower_try_finally (struct leh_state *state, tree *tp) 1345{ 1346 struct leh_tf_state this_tf; 1347 struct leh_state this_state; 1348 int ndests; 1349 1350 /* Process the try block. */ 1351 1352 memset (&this_tf, 0, sizeof (this_tf)); 1353 this_tf.try_finally_expr = *tp; 1354 this_tf.top_p = tp; 1355 this_tf.outer = state; 1356 if (using_eh_for_cleanups_p) 1357 this_tf.region 1358 = gen_eh_region_cleanup (state->cur_region, state->prev_try); 1359 else 1360 this_tf.region = NULL; 1361 1362 this_state.cur_region = this_tf.region; 1363 this_state.prev_try = state->prev_try; 1364 this_state.tf = &this_tf; 1365 1366 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); 1367 1368 /* Determine if the try block is escaped through the bottom. */ 1369 this_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0)); 1370 1371 /* Determine if any exceptions are possible within the try block. */ 1372 if (using_eh_for_cleanups_p) 1373 this_tf.may_throw = get_eh_region_may_contain_throw (this_tf.region); 1374 if (this_tf.may_throw) 1375 { 1376 this_tf.eh_label = create_artificial_label (); 1377 set_eh_region_tree_label (this_tf.region, this_tf.eh_label); 1378 honor_protect_cleanup_actions (state, &this_state, &this_tf); 1379 } 1380 1381 /* Sort the goto queue for efficient searching later. */ 1382 if (this_tf.goto_queue_active > 1) 1383 qsort (this_tf.goto_queue, this_tf.goto_queue_active, 1384 sizeof (struct goto_queue_node), goto_queue_cmp); 1385 1386 /* Determine how many edges (still) reach the finally block. Or rather, 1387 how many destinations are reached by the finally block. Use this to 1388 determine how we process the finally block itself. */ 1389 1390 ndests = VEC_length (tree, this_tf.dest_array); 1391 ndests += this_tf.may_fallthru; 1392 ndests += this_tf.may_return; 1393 ndests += this_tf.may_throw; 1394 1395 /* If the FINALLY block is not reachable, dike it out. */ 1396 if (ndests == 0) 1397 *tp = TREE_OPERAND (*tp, 0); 1398 1399 /* If the finally block doesn't fall through, then any destination 1400 we might try to impose there isn't reached either. There may be 1401 some minor amount of cleanup and redirection still needed. */ 1402 else if (!block_may_fallthru (TREE_OPERAND (*tp, 1))) 1403 lower_try_finally_nofallthru (state, &this_tf); 1404 1405 /* We can easily special-case redirection to a single destination. */ 1406 else if (ndests == 1) 1407 lower_try_finally_onedest (state, &this_tf); 1408 1409 else if (decide_copy_try_finally (ndests, TREE_OPERAND (*tp, 1))) 1410 lower_try_finally_copy (state, &this_tf); 1411 else 1412 lower_try_finally_switch (state, &this_tf); 1413 1414 /* If someone requested we add a label at the end of the transformed 1415 block, do so. */ 1416 if (this_tf.fallthru_label) 1417 { 1418 tree x = build1 (LABEL_EXPR, void_type_node, this_tf.fallthru_label); 1419 append_to_statement_list (x, tp); 1420 } 1421 1422 VEC_free (tree, heap, this_tf.dest_array); 1423 if (this_tf.goto_queue) 1424 free (this_tf.goto_queue); 1425} 1426 1427/* A subroutine of lower_eh_constructs_1. Lower a TRY_CATCH_EXPR with a 1428 list of CATCH_EXPR nodes to a sequence of labels and blocks, plus the 1429 exception region trees that record all the magic. */ 1430 1431static void 1432lower_catch (struct leh_state *state, tree *tp) 1433{ 1434 struct eh_region *try_region; 1435 struct leh_state this_state; 1436 tree_stmt_iterator i; 1437 tree out_label; 1438 1439 try_region = gen_eh_region_try (state->cur_region); 1440 this_state.cur_region = try_region; 1441 this_state.prev_try = try_region; 1442 this_state.tf = state->tf; 1443 1444 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); 1445 1446 if (!get_eh_region_may_contain_throw (try_region)) 1447 { 1448 *tp = TREE_OPERAND (*tp, 0); 1449 return; 1450 } 1451 1452 out_label = NULL; 1453 for (i = tsi_start (TREE_OPERAND (*tp, 1)); !tsi_end_p (i); ) 1454 { 1455 struct eh_region *catch_region; 1456 tree catch, x, eh_label; 1457 1458 catch = tsi_stmt (i); 1459 catch_region = gen_eh_region_catch (try_region, CATCH_TYPES (catch)); 1460 1461 this_state.cur_region = catch_region; 1462 this_state.prev_try = state->prev_try; 1463 lower_eh_constructs_1 (&this_state, &CATCH_BODY (catch)); 1464 1465 eh_label = create_artificial_label (); 1466 set_eh_region_tree_label (catch_region, eh_label); 1467 1468 x = build1 (LABEL_EXPR, void_type_node, eh_label); 1469 tsi_link_before (&i, x, TSI_SAME_STMT); 1470 1471 if (block_may_fallthru (CATCH_BODY (catch))) 1472 { 1473 if (!out_label) 1474 out_label = create_artificial_label (); 1475 1476 x = build1 (GOTO_EXPR, void_type_node, out_label); 1477 append_to_statement_list (x, &CATCH_BODY (catch)); 1478 } 1479 1480 tsi_link_before (&i, CATCH_BODY (catch), TSI_SAME_STMT); 1481 tsi_delink (&i); 1482 } 1483 1484 frob_into_branch_around (tp, NULL, out_label); 1485} 1486 1487/* A subroutine of lower_eh_constructs_1. Lower a TRY_CATCH_EXPR with a 1488 EH_FILTER_EXPR to a sequence of labels and blocks, plus the exception 1489 region trees that record all the magic. */ 1490 1491static void 1492lower_eh_filter (struct leh_state *state, tree *tp) 1493{ 1494 struct leh_state this_state; 1495 struct eh_region *this_region; 1496 tree inner = expr_first (TREE_OPERAND (*tp, 1)); 1497 tree eh_label; 1498 1499 if (EH_FILTER_MUST_NOT_THROW (inner)) 1500 this_region = gen_eh_region_must_not_throw (state->cur_region); 1501 else 1502 this_region = gen_eh_region_allowed (state->cur_region, 1503 EH_FILTER_TYPES (inner)); 1504 this_state = *state; 1505 this_state.cur_region = this_region; 1506 1507 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); 1508 1509 if (!get_eh_region_may_contain_throw (this_region)) 1510 { 1511 *tp = TREE_OPERAND (*tp, 0); 1512 return; 1513 } 1514 1515 lower_eh_constructs_1 (state, &EH_FILTER_FAILURE (inner)); 1516 TREE_OPERAND (*tp, 1) = EH_FILTER_FAILURE (inner); 1517 1518 eh_label = create_artificial_label (); 1519 set_eh_region_tree_label (this_region, eh_label); 1520 1521 frob_into_branch_around (tp, eh_label, NULL); 1522} 1523 1524/* Implement a cleanup expression. This is similar to try-finally, 1525 except that we only execute the cleanup block for exception edges. */ 1526 1527static void 1528lower_cleanup (struct leh_state *state, tree *tp) 1529{ 1530 struct leh_state this_state; 1531 struct eh_region *this_region; 1532 struct leh_tf_state fake_tf; 1533 1534 /* If not using eh, then exception-only cleanups are no-ops. */ 1535 if (!flag_exceptions) 1536 { 1537 *tp = TREE_OPERAND (*tp, 0); 1538 lower_eh_constructs_1 (state, tp); 1539 return; 1540 } 1541 1542 this_region = gen_eh_region_cleanup (state->cur_region, state->prev_try); 1543 this_state = *state; 1544 this_state.cur_region = this_region; 1545 1546 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); 1547 1548 if (!get_eh_region_may_contain_throw (this_region)) 1549 { 1550 *tp = TREE_OPERAND (*tp, 0); 1551 return; 1552 } 1553 1554 /* Build enough of a try-finally state so that we can reuse 1555 honor_protect_cleanup_actions. */ 1556 memset (&fake_tf, 0, sizeof (fake_tf)); 1557 fake_tf.top_p = tp; 1558 fake_tf.outer = state; 1559 fake_tf.region = this_region; 1560 fake_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0)); 1561 fake_tf.may_throw = true; 1562 1563 fake_tf.eh_label = create_artificial_label (); 1564 set_eh_region_tree_label (this_region, fake_tf.eh_label); 1565 1566 honor_protect_cleanup_actions (state, NULL, &fake_tf); 1567 1568 if (fake_tf.may_throw) 1569 { 1570 /* In this case honor_protect_cleanup_actions had nothing to do, 1571 and we should process this normally. */ 1572 lower_eh_constructs_1 (state, &TREE_OPERAND (*tp, 1)); 1573 frob_into_branch_around (tp, fake_tf.eh_label, fake_tf.fallthru_label); 1574 } 1575 else 1576 { 1577 /* In this case honor_protect_cleanup_actions did nearly all of 1578 the work. All we have left is to append the fallthru_label. */ 1579 1580 *tp = TREE_OPERAND (*tp, 0); 1581 if (fake_tf.fallthru_label) 1582 { 1583 tree x = build1 (LABEL_EXPR, void_type_node, fake_tf.fallthru_label); 1584 append_to_statement_list (x, tp); 1585 } 1586 } 1587} 1588 1589/* Main loop for lowering eh constructs. */ 1590 1591static void 1592lower_eh_constructs_1 (struct leh_state *state, tree *tp) 1593{ 1594 tree_stmt_iterator i; 1595 tree t = *tp; 1596 1597 switch (TREE_CODE (t)) 1598 { 1599 case COND_EXPR: 1600 lower_eh_constructs_1 (state, &COND_EXPR_THEN (t)); 1601 lower_eh_constructs_1 (state, &COND_EXPR_ELSE (t)); 1602 break; 1603 1604 case CALL_EXPR: 1605 /* Look for things that can throw exceptions, and record them. */ 1606 if (state->cur_region && tree_could_throw_p (t)) 1607 { 1608 record_stmt_eh_region (state->cur_region, t); 1609 note_eh_region_may_contain_throw (state->cur_region); 1610 } 1611 break; 1612 1613 case MODIFY_EXPR: 1614 /* Look for things that can throw exceptions, and record them. */ 1615 if (state->cur_region && tree_could_throw_p (t)) 1616 { 1617 record_stmt_eh_region (state->cur_region, t); 1618 note_eh_region_may_contain_throw (state->cur_region); 1619 } 1620 break; 1621 1622 case GOTO_EXPR: 1623 case RETURN_EXPR: 1624 maybe_record_in_goto_queue (state, t); 1625 break; 1626 case SWITCH_EXPR: 1627 verify_norecord_switch_expr (state, t); 1628 break; 1629 1630 case TRY_FINALLY_EXPR: 1631 lower_try_finally (state, tp); 1632 break; 1633 1634 case TRY_CATCH_EXPR: 1635 i = tsi_start (TREE_OPERAND (t, 1)); 1636 switch (TREE_CODE (tsi_stmt (i))) 1637 { 1638 case CATCH_EXPR: 1639 lower_catch (state, tp); 1640 break; 1641 case EH_FILTER_EXPR: 1642 lower_eh_filter (state, tp); 1643 break; 1644 default: 1645 lower_cleanup (state, tp); 1646 break; 1647 } 1648 break; 1649 1650 case STATEMENT_LIST: 1651 for (i = tsi_start (t); !tsi_end_p (i); ) 1652 { 1653 lower_eh_constructs_1 (state, tsi_stmt_ptr (i)); 1654 t = tsi_stmt (i); 1655 if (TREE_CODE (t) == STATEMENT_LIST) 1656 { 1657 tsi_link_before (&i, t, TSI_SAME_STMT); 1658 tsi_delink (&i); 1659 } 1660 else 1661 tsi_next (&i); 1662 } 1663 break; 1664 1665 default: 1666 /* A type, a decl, or some kind of statement that we're not 1667 interested in. Don't walk them. */ 1668 break; 1669 } 1670} 1671 1672static void 1673lower_eh_constructs (void) 1674{ 1675 struct leh_state null_state; 1676 tree *tp = &DECL_SAVED_TREE (current_function_decl); 1677 1678 finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free); 1679 1680 collect_finally_tree (*tp, NULL); 1681 1682 memset (&null_state, 0, sizeof (null_state)); 1683 lower_eh_constructs_1 (&null_state, tp); 1684 1685 htab_delete (finally_tree); 1686 1687 collect_eh_region_array (); 1688} 1689 1690struct tree_opt_pass pass_lower_eh = 1691{ 1692 "eh", /* name */ 1693 NULL, /* gate */ 1694 lower_eh_constructs, /* execute */ 1695 NULL, /* sub */ 1696 NULL, /* next */ 1697 0, /* static_pass_number */ 1698 TV_TREE_EH, /* tv_id */ 1699 PROP_gimple_lcf, /* properties_required */ 1700 PROP_gimple_leh, /* properties_provided */ 1701 PROP_gimple_lcf, /* properties_destroyed */ 1702 0, /* todo_flags_start */ 1703 TODO_dump_func, /* todo_flags_finish */ 1704 0 /* letter */ 1705}; 1706 1707 1708/* Construct EH edges for STMT. */ 1709 1710static void 1711make_eh_edge (struct eh_region *region, void *data) 1712{ 1713 tree stmt, lab; 1714 basic_block src, dst; 1715 1716 stmt = data; 1717 lab = get_eh_region_tree_label (region); 1718 1719 src = bb_for_stmt (stmt); 1720 dst = label_to_block (lab); 1721 1722 make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH); 1723} 1724 1725void 1726make_eh_edges (tree stmt) 1727{ 1728 int region_nr; 1729 bool is_resx; 1730 1731 if (TREE_CODE (stmt) == RESX_EXPR) 1732 { 1733 region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)); 1734 is_resx = true; 1735 } 1736 else 1737 { 1738 region_nr = lookup_stmt_eh_region (stmt); 1739 if (region_nr < 0) 1740 return; 1741 is_resx = false; 1742 } 1743 1744 foreach_reachable_handler (region_nr, is_resx, make_eh_edge, stmt); 1745} 1746 1747static bool mark_eh_edge_found_error; 1748 1749/* Mark edge make_eh_edge would create for given region by setting it aux 1750 field, output error if something goes wrong. */ 1751static void 1752mark_eh_edge (struct eh_region *region, void *data) 1753{ 1754 tree stmt, lab; 1755 basic_block src, dst; 1756 edge e; 1757 1758 stmt = data; 1759 lab = get_eh_region_tree_label (region); 1760 1761 src = bb_for_stmt (stmt); 1762 dst = label_to_block (lab); 1763 1764 e = find_edge (src, dst); 1765 if (!e) 1766 { 1767 error ("EH edge %i->%i is missing", src->index, dst->index); 1768 mark_eh_edge_found_error = true; 1769 } 1770 else if (!(e->flags & EDGE_EH)) 1771 { 1772 error ("EH edge %i->%i miss EH flag", src->index, dst->index); 1773 mark_eh_edge_found_error = true; 1774 } 1775 else if (e->aux) 1776 { 1777 /* ??? might not be mistake. */ 1778 error ("EH edge %i->%i has duplicated regions", src->index, dst->index); 1779 mark_eh_edge_found_error = true; 1780 } 1781 else 1782 e->aux = (void *)1; 1783} 1784 1785/* Verify that BB containing stmt as last stmt has precisely the edges 1786 make_eh_edges would create. */ 1787bool 1788verify_eh_edges (tree stmt) 1789{ 1790 int region_nr; 1791 bool is_resx; 1792 basic_block bb = bb_for_stmt (stmt); 1793 edge_iterator ei; 1794 edge e; 1795 1796 FOR_EACH_EDGE (e, ei, bb->succs) 1797 gcc_assert (!e->aux); 1798 mark_eh_edge_found_error = false; 1799 if (TREE_CODE (stmt) == RESX_EXPR) 1800 { 1801 region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)); 1802 is_resx = true; 1803 } 1804 else 1805 { 1806 region_nr = lookup_stmt_eh_region (stmt); 1807 if (region_nr < 0) 1808 { 1809 FOR_EACH_EDGE (e, ei, bb->succs) 1810 if (e->flags & EDGE_EH) 1811 { 1812 error ("BB %i can not throw but has EH edges", bb->index); 1813 return true; 1814 } 1815 return false; 1816 } 1817 if (!tree_could_throw_p (stmt)) 1818 { 1819 error ("BB %i last statement has incorrectly set region", bb->index); 1820 return true; 1821 } 1822 is_resx = false; 1823 } 1824 1825 foreach_reachable_handler (region_nr, is_resx, mark_eh_edge, stmt); 1826 FOR_EACH_EDGE (e, ei, bb->succs) 1827 { 1828 if ((e->flags & EDGE_EH) && !e->aux) 1829 { 1830 error ("unnecessary EH edge %i->%i", bb->index, e->dest->index); 1831 mark_eh_edge_found_error = true; 1832 return true; 1833 } 1834 e->aux = NULL; 1835 } 1836 return mark_eh_edge_found_error; 1837} 1838 1839 1840/* Return true if the expr can trap, as in dereferencing an invalid pointer 1841 location or floating point arithmetic. C.f. the rtl version, may_trap_p. 1842 This routine expects only GIMPLE lhs or rhs input. */ 1843 1844bool 1845tree_could_trap_p (tree expr) 1846{ 1847 enum tree_code code = TREE_CODE (expr); 1848 bool honor_nans = false; 1849 bool honor_snans = false; 1850 bool fp_operation = false; 1851 bool honor_trapv = false; 1852 tree t, base; 1853 1854 if (TREE_CODE_CLASS (code) == tcc_comparison 1855 || TREE_CODE_CLASS (code) == tcc_unary 1856 || TREE_CODE_CLASS (code) == tcc_binary) 1857 { 1858 t = TREE_TYPE (expr); 1859 fp_operation = FLOAT_TYPE_P (t); 1860 if (fp_operation) 1861 { 1862 honor_nans = flag_trapping_math && !flag_finite_math_only; 1863 honor_snans = flag_signaling_nans != 0; 1864 } 1865 else if (INTEGRAL_TYPE_P (t) && TYPE_TRAP_SIGNED (t)) 1866 honor_trapv = true; 1867 } 1868 1869 restart: 1870 switch (code) 1871 { 1872 case TARGET_MEM_REF: 1873 /* For TARGET_MEM_REFs use the information based on the original 1874 reference. */ 1875 expr = TMR_ORIGINAL (expr); 1876 code = TREE_CODE (expr); 1877 goto restart; 1878 1879 case COMPONENT_REF: 1880 case REALPART_EXPR: 1881 case IMAGPART_EXPR: 1882 case BIT_FIELD_REF: 1883 case WITH_SIZE_EXPR: 1884 expr = TREE_OPERAND (expr, 0); 1885 code = TREE_CODE (expr); 1886 goto restart; 1887 1888 case ARRAY_RANGE_REF: 1889 /* Let us be conservative here for now. We might be checking bounds of 1890 the access similarly to the case below. */ 1891 if (!TREE_THIS_NOTRAP (expr)) 1892 return true; 1893 1894 base = TREE_OPERAND (expr, 0); 1895 return tree_could_trap_p (base); 1896 1897 case ARRAY_REF: 1898 base = TREE_OPERAND (expr, 0); 1899 if (tree_could_trap_p (base)) 1900 return true; 1901 1902 if (TREE_THIS_NOTRAP (expr)) 1903 return false; 1904 1905 return !in_array_bounds_p (expr); 1906 1907 case INDIRECT_REF: 1908 case ALIGN_INDIRECT_REF: 1909 case MISALIGNED_INDIRECT_REF: 1910 return !TREE_THIS_NOTRAP (expr); 1911 1912 case ASM_EXPR: 1913 return TREE_THIS_VOLATILE (expr); 1914 1915 case TRUNC_DIV_EXPR: 1916 case CEIL_DIV_EXPR: 1917 case FLOOR_DIV_EXPR: 1918 case ROUND_DIV_EXPR: 1919 case EXACT_DIV_EXPR: 1920 case CEIL_MOD_EXPR: 1921 case FLOOR_MOD_EXPR: 1922 case ROUND_MOD_EXPR: 1923 case TRUNC_MOD_EXPR: 1924 case RDIV_EXPR: 1925 if (honor_snans || honor_trapv) 1926 return true; 1927 if (fp_operation) 1928 return flag_trapping_math; 1929 t = TREE_OPERAND (expr, 1); 1930 if (!TREE_CONSTANT (t) || integer_zerop (t)) 1931 return true; 1932 return false; 1933 1934 case LT_EXPR: 1935 case LE_EXPR: 1936 case GT_EXPR: 1937 case GE_EXPR: 1938 case LTGT_EXPR: 1939 /* Some floating point comparisons may trap. */ 1940 return honor_nans; 1941 1942 case EQ_EXPR: 1943 case NE_EXPR: 1944 case UNORDERED_EXPR: 1945 case ORDERED_EXPR: 1946 case UNLT_EXPR: 1947 case UNLE_EXPR: 1948 case UNGT_EXPR: 1949 case UNGE_EXPR: 1950 case UNEQ_EXPR: 1951 return honor_snans; 1952 1953 case CONVERT_EXPR: 1954 case FIX_TRUNC_EXPR: 1955 case FIX_CEIL_EXPR: 1956 case FIX_FLOOR_EXPR: 1957 case FIX_ROUND_EXPR: 1958 /* Conversion of floating point might trap. */ 1959 return honor_nans; 1960 1961 case NEGATE_EXPR: 1962 case ABS_EXPR: 1963 case CONJ_EXPR: 1964 /* These operations don't trap with floating point. */ 1965 if (honor_trapv) 1966 return true; 1967 return false; 1968 1969 case PLUS_EXPR: 1970 case MINUS_EXPR: 1971 case MULT_EXPR: 1972 /* Any floating arithmetic may trap. */ 1973 if (fp_operation && flag_trapping_math) 1974 return true; 1975 if (honor_trapv) 1976 return true; 1977 return false; 1978 1979 case CALL_EXPR: 1980 t = get_callee_fndecl (expr); 1981 /* Assume that calls to weak functions may trap. */ 1982 if (!t || !DECL_P (t) || DECL_WEAK (t)) 1983 return true; 1984 return false; 1985 1986 default: 1987 /* Any floating arithmetic may trap. */ 1988 if (fp_operation && flag_trapping_math) 1989 return true; 1990 return false; 1991 } 1992} 1993 1994bool 1995tree_could_throw_p (tree t) 1996{ 1997 if (!flag_exceptions) 1998 return false; 1999 if (TREE_CODE (t) == MODIFY_EXPR) 2000 { 2001 if (flag_non_call_exceptions 2002 && tree_could_trap_p (TREE_OPERAND (t, 0))) 2003 return true; 2004 t = TREE_OPERAND (t, 1); 2005 } 2006 2007 if (TREE_CODE (t) == WITH_SIZE_EXPR) 2008 t = TREE_OPERAND (t, 0); 2009 if (TREE_CODE (t) == CALL_EXPR) 2010 return (call_expr_flags (t) & ECF_NOTHROW) == 0; 2011 if (flag_non_call_exceptions) 2012 return tree_could_trap_p (t); 2013 return false; 2014} 2015 2016bool 2017tree_can_throw_internal (tree stmt) 2018{ 2019 int region_nr; 2020 bool is_resx = false; 2021 2022 if (TREE_CODE (stmt) == RESX_EXPR) 2023 region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)), is_resx = true; 2024 else 2025 region_nr = lookup_stmt_eh_region (stmt); 2026 if (region_nr < 0) 2027 return false; 2028 return can_throw_internal_1 (region_nr, is_resx); 2029} 2030 2031bool 2032tree_can_throw_external (tree stmt) 2033{ 2034 int region_nr; 2035 bool is_resx = false; 2036 2037 if (TREE_CODE (stmt) == RESX_EXPR) 2038 region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)), is_resx = true; 2039 else 2040 region_nr = lookup_stmt_eh_region (stmt); 2041 if (region_nr < 0) 2042 return tree_could_throw_p (stmt); 2043 else 2044 return can_throw_external_1 (region_nr, is_resx); 2045} 2046 2047/* Given a statement OLD_STMT and a new statement NEW_STMT that has replaced 2048 OLD_STMT in the function, remove OLD_STMT from the EH table and put NEW_STMT 2049 in the table if it should be in there. Return TRUE if a replacement was 2050 done that my require an EH edge purge. */ 2051 2052bool 2053maybe_clean_or_replace_eh_stmt (tree old_stmt, tree new_stmt) 2054{ 2055 int region_nr = lookup_stmt_eh_region (old_stmt); 2056 2057 if (region_nr >= 0) 2058 { 2059 bool new_stmt_could_throw = tree_could_throw_p (new_stmt); 2060 2061 if (new_stmt == old_stmt && new_stmt_could_throw) 2062 return false; 2063 2064 remove_stmt_from_eh_region (old_stmt); 2065 if (new_stmt_could_throw) 2066 { 2067 add_stmt_to_eh_region (new_stmt, region_nr); 2068 return false; 2069 } 2070 else 2071 return true; 2072 } 2073 2074 return false; 2075} 2076