#include "config.h"#include "system.h"#include "coretypes.h"#include "tm.h"#include "tree.h"#include "rtl.h"#include "tm_p.h"#include "flags.h"#include "function.h"#include "except.h"#include "tree-flow.h"#include "tree-dump.h"#include "tree-inline.h"#include "tree-iterator.h"#include "tree-pass.h"#include "timevar.h"#include "langhooks.h"#include "ggc.h"#include "toplev.h"Include dependency graph for tree-eh.c:

Go to the source code of this file.
|
|
Definition at line 578 of file tree-eh.c. Referenced by lower_eh_constructs_1(). |
|
|
Definition at line 124 of file tree-eh.c. References add_stmt_to_eh_region_fn(). Referenced by bsi_replace(), copy_bb(), maybe_clean_or_replace_eh_stmt(), and record_stmt_eh_region(). 00125 { 00126 add_stmt_to_eh_region_fn (cfun, t, num); 00127 }
|
|
|
Definition at line 95 of file tree-eh.c. References get_call_expr_in(), struct_ptr_eq(), struct_ptr_hash(), and TREE_CODE. Referenced by add_stmt_to_eh_region(), and move_block_to_fn(). 00096 { 00097 struct throw_stmt_node *n; 00098 void **slot; 00099 00100 gcc_assert (num >= 0); 00101 gcc_assert (TREE_CODE (t) != RESX_EXPR); 00102 00103 n = GGC_NEW (struct throw_stmt_node); 00104 n->stmt = t; 00105 n->region_nr = num; 00106 00107 if (!get_eh_throw_stmt_table (ifun)) 00108 set_eh_throw_stmt_table (ifun, htab_create_ggc (31, struct_ptr_hash, 00109 struct_ptr_eq, 00110 ggc_free)); 00111 00112 slot = htab_find_slot (get_eh_throw_stmt_table (ifun), n, INSERT); 00113 gcc_assert (!*slot); 00114 *slot = n; 00115 /* ??? For the benefit of calls.c, converting all this to rtl, 00116 we need to record the call expression, not just the outer 00117 modify statement. */ 00118 if (TREE_CODE (t) == MODIFY_EXPR 00119 && (t = get_call_expr_in (t))) 00120 add_stmt_to_eh_region_fn (ifun, t, num); 00121 }
|
|
|
Definition at line 216 of file tree-eh.c. References CATCH_BODY, EH_FILTER_FAILURE, LABEL_EXPR_LABEL, record_in_finally_tree(), TREE_CODE, TREE_OPERAND, tsi_end_p(), tsi_next(), tsi_start(), and tsi_stmt(). Referenced by lower_eh_constructs(), and lower_try_finally_dup_block(). 00217 { 00218 tailrecurse: 00219 switch (TREE_CODE (t)) 00220 { 00221 case LABEL_EXPR: 00222 record_in_finally_tree (LABEL_EXPR_LABEL (t), region); 00223 break; 00224 00225 case TRY_FINALLY_EXPR: 00226 record_in_finally_tree (t, region); 00227 collect_finally_tree (TREE_OPERAND (t, 0), t); 00228 t = TREE_OPERAND (t, 1); 00229 goto tailrecurse; 00230 00231 case TRY_CATCH_EXPR: 00232 collect_finally_tree (TREE_OPERAND (t, 0), region); 00233 t = TREE_OPERAND (t, 1); 00234 goto tailrecurse; 00235 00236 case CATCH_EXPR: 00237 t = CATCH_BODY (t); 00238 goto tailrecurse; 00239 00240 case EH_FILTER_EXPR: 00241 t = EH_FILTER_FAILURE (t); 00242 goto tailrecurse; 00243 00244 case STATEMENT_LIST: 00245 { 00246 tree_stmt_iterator i; 00247 for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) 00248 collect_finally_tree (tsi_stmt (i), region); 00249 } 00250 break; 00251 00252 default: 00253 /* A type, a decl, or some kind of statement that we're not 00254 interested in. Don't walk them. */ 00255 break; 00256 } 00257 }
|
|
|
Decide whether or not we are going to duplicate the finally block. There are several considerations. First, if this is Java, then the finally block contains code written by the user. It has line numbers associated with it, so duplicating the block means it's difficult to set a breakpoint. Since controlling code generation via -g is verboten, we simply never duplicate code without optimization. Second, we'd like to prevent egregious code growth. One way to do this is to estimate the size of the finally block, multiply that by the number of copies we'd need to make, and compare against the estimate of the size of the switch machinery we'd have to add. Definition at line 1315 of file tree-eh.c. References estimate_num_insns(). Referenced by lower_try_finally(). 01316 { 01317 int f_estimate, sw_estimate; 01318 01319 if (!optimize) 01320 return false; 01321 01322 /* Finally estimate N times, plus N gotos. */ 01323 f_estimate = estimate_num_insns (finally); 01324 f_estimate = (f_estimate + 1) * ndests; 01325 01326 /* Switch statement (cost 10), N variable assignments, N gotos. */ 01327 sw_estimate = 10 + 2 * ndests; 01328 01329 /* Optimize for size clearly wants our best guess. */ 01330 if (optimize_size) 01331 return f_estimate < sw_estimate; 01332 01333 /* ??? These numbers are completely made up so far. */ 01334 if (optimize > 1) 01335 return f_estimate < 100 || f_estimate < sw_estimate * 2; 01336 else 01337 return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3; 01338 }
|
|
|
Similar, but easier, for GOTO_EXPR. Definition at line 679 of file tree-eh.c. References append_to_statement_list(), build1, and void_type_node. Referenced by lower_try_finally_copy(), lower_try_finally_nofallthru(), and lower_try_finally_onedest(). 00680 { 00681 tree x; 00682 00683 q->cont_stmt = q->stmt; 00684 if (mod) 00685 append_to_statement_list (mod, &q->repl_stmt); 00686 00687 x = build1 (GOTO_EXPR, void_type_node, finlab); 00688 append_to_statement_list (x, &q->repl_stmt); 00689 }
|
|
||||||||||||||||||||
|
Redirect a RETURN_EXPR pointed to by STMT_P to FINLAB. Place in CONT_P whatever is needed to finish the return. If MOD is non-null, insert it before the new branch. RETURN_VALUE_P is a cache containing a temporary variable to be used in manipulating the value returned from the function. Definition at line 587 of file tree-eh.c. References aggregate_value_p(), append_to_statement_list(), build1, build2, create_tmp_var, current_function_decl, TREE_CODE, TREE_OPERAND, TREE_TYPE, and void_type_node. Referenced by lower_try_finally_copy(), lower_try_finally_nofallthru(), lower_try_finally_onedest(), and lower_try_finally_switch(). 00589 { 00590 tree ret_expr = TREE_OPERAND (q->stmt, 0); 00591 tree x; 00592 00593 if (ret_expr) 00594 { 00595 /* The nasty part about redirecting the return value is that the 00596 return value itself is to be computed before the FINALLY block 00597 is executed. e.g. 00598 00599 int x; 00600 int foo (void) 00601 { 00602 x = 0; 00603 try { 00604 return x; 00605 } finally { 00606 x++; 00607 } 00608 } 00609 00610 should return 0, not 1. Arrange for this to happen by copying 00611 computed the return value into a local temporary. This also 00612 allows us to redirect multiple return statements through the 00613 same destination block; whether this is a net win or not really 00614 depends, I guess, but it does make generation of the switch in 00615 lower_try_finally_switch easier. */ 00616 00617 switch (TREE_CODE (ret_expr)) 00618 { 00619 case RESULT_DECL: 00620 if (!*return_value_p) 00621 *return_value_p = ret_expr; 00622 else 00623 gcc_assert (*return_value_p == ret_expr); 00624 q->cont_stmt = q->stmt; 00625 break; 00626 00627 case MODIFY_EXPR: 00628 { 00629 tree result = TREE_OPERAND (ret_expr, 0); 00630 tree new, old = TREE_OPERAND (ret_expr, 1); 00631 00632 if (!*return_value_p) 00633 { 00634 if (aggregate_value_p (TREE_TYPE (result), 00635 TREE_TYPE (current_function_decl))) 00636 /* If this function returns in memory, copy the argument 00637 into the return slot now. Otherwise, we might need to 00638 worry about magic return semantics, so we need to use a 00639 temporary to hold the value until we're actually ready 00640 to return. */ 00641 new = result; 00642 else 00643 new = create_tmp_var (TREE_TYPE (old), "rettmp"); 00644 *return_value_p = new; 00645 } 00646 else 00647 new = *return_value_p; 00648 00649 x = build2 (MODIFY_EXPR, TREE_TYPE (new), new, old); 00650 append_to_statement_list (x, &q->repl_stmt); 00651 00652 if (new == result) 00653 x = result; 00654 else 00655 x = build2 (MODIFY_EXPR, TREE_TYPE (result), result, new); 00656 q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x); 00657 } 00658 00659 default: 00660 gcc_unreachable (); 00661 } 00662 } 00663 else 00664 { 00665 /* If we don't return a value, all return statements are the same. */ 00666 q->cont_stmt = q->stmt; 00667 } 00668 00669 if (mod) 00670 append_to_statement_list (mod, &q->repl_stmt); 00671 00672 x = build1 (GOTO_EXPR, void_type_node, finlab); 00673 append_to_statement_list (x, &q->repl_stmt); 00674 }
|
|
|
Search for STMT in the goto queue. Return the replacement, or null if the statement isn't in the queue. Definition at line 369 of file tree-eh.c. References leh_tf_state::goto_queue, leh_tf_state::goto_queue_active, and goto_queue_cmp(). Referenced by replace_goto_queue_1(), and replace_goto_queue_cond_clause(). 00370 { 00371 struct goto_queue_node tmp, *ret; 00372 tmp.stmt = stmt; 00373 ret = (struct goto_queue_node *) 00374 bsearch (&tmp, tf->goto_queue, tf->goto_queue_active, 00375 sizeof (struct goto_queue_node), goto_queue_cmp); 00376 return (ret ? ret->repl_stmt : NULL); 00377 }
|
|
|
We want to transform
try { body; } catch { stuff; }
to
body; goto over; lab: stuff; over:
T is a TRY_FINALLY or TRY_CATCH node. LAB is the label that
should be placed before the second operand, or NULL. OVER is
an existing label that should be put at the exit, or NULL. Definition at line 701 of file tree-eh.c. References append_to_statement_list(), block_may_fallthru(), build1, create_artificial_label(), TREE_OPERAND, and void_type_node. Referenced by lower_cleanup(), and lower_eh_filter(). 00702 { 00703 tree x, op1; 00704 00705 op1 = TREE_OPERAND (*tp, 1); 00706 *tp = TREE_OPERAND (*tp, 0); 00707 00708 if (block_may_fallthru (*tp)) 00709 { 00710 if (!over) 00711 over = create_artificial_label (); 00712 x = build1 (GOTO_EXPR, void_type_node, over); 00713 append_to_statement_list (x, tp); 00714 } 00715 00716 if (lab) 00717 { 00718 x = build1 (LABEL_EXPR, void_type_node, lab); 00719 append_to_statement_list (x, tp); 00720 } 00721 00722 append_to_statement_list (op1, tp); 00723 00724 if (over) 00725 { 00726 x = build1 (LABEL_EXPR, void_type_node, over); 00727 append_to_statement_list (x, tp); 00728 } 00729 }
|
|
|
Comparison function for qsort/bsearch. We're interested in searching goto queue elements for source statements. Definition at line 358 of file tree-eh.c. Referenced by find_goto_replacement(), and lower_try_finally(). 00359 { 00360 tree a = ((const struct goto_queue_node *)x)->stmt; 00361 tree b = ((const struct goto_queue_node *)y)->stmt; 00362 return (a == b ? 0 : a < b ? -1 : 1); 00363 }
|
|
||||||||||||||||
|
A subroutine of lower_try_finally. If lang_protect_cleanup_actions
returns non-null, then the language requires that the exception path out
of a try_finally be treated specially. To wit: the code within the
finally block may not itself throw an exception. We have two choices here.
First we can duplicate the finally block and wrap it in a must_not_throw
region. Second, we can generate code like
try {
finally_block;
} catch {
if (fintmp == eh_edge)
protect_cleanup_actions;
}
where "fintmp" is the temporary used in the switch statement generation
alternative considered below. For the nonce, we always choose the first
option.
THIS_STATE may be null if this is a try-cleanup, not a try-finally. Definition at line 787 of file tree-eh.c. References append_to_statement_list(), block_may_fallthru(), build0, build1, build2, build_resx(), create_tmp_var, EH_FILTER_FAILURE, EH_FILTER_MUST_NOT_THROW, integer_type_node, lower_eh_constructs_1(), lower_eh_filter(), lower_try_finally_dup_block(), lower_try_finally_fallthru_label(), maybe_record_in_goto_queue(), ptr_type_node, leh_tf_state::region, leh_tf_state::top_p, TREE_OPERAND, TSI_CONTINUE_LINKING, tsi_last(), tsi_link_after(), tsi_link_before(), tsi_start(), and void_type_node. Referenced by lower_cleanup(), and lower_try_finally(). 00790 { 00791 tree protect_cleanup_actions, finally, x; 00792 tree_stmt_iterator i; 00793 bool finally_may_fallthru; 00794 00795 /* First check for nothing to do. */ 00796 if (lang_protect_cleanup_actions) 00797 protect_cleanup_actions = lang_protect_cleanup_actions (); 00798 else 00799 protect_cleanup_actions = NULL; 00800 00801 finally = TREE_OPERAND (*tf->top_p, 1); 00802 00803 /* If the EH case of the finally block can fall through, this may be a 00804 structure of the form 00805 try { 00806 try { 00807 throw ...; 00808 } cleanup { 00809 try { 00810 throw ...; 00811 } catch (...) { 00812 } 00813 } 00814 } catch (...) { 00815 yyy; 00816 } 00817 E.g. with an inline destructor with an embedded try block. In this 00818 case we must save the runtime EH data around the nested exception. 00819 00820 This complication means that any time the previous runtime data might 00821 be used (via fallthru from the finally) we handle the eh case here, 00822 whether or not protect_cleanup_actions is active. */ 00823 00824 finally_may_fallthru = block_may_fallthru (finally); 00825 if (!finally_may_fallthru && !protect_cleanup_actions) 00826 return; 00827 00828 /* Duplicate the FINALLY block. Only need to do this for try-finally, 00829 and not for cleanups. */ 00830 if (this_state) 00831 finally = lower_try_finally_dup_block (finally, outer_state); 00832 00833 /* Resume execution after the exception. Adding this now lets 00834 lower_eh_filter not add unnecessary gotos, as it is clear that 00835 we never fallthru from this copy of the finally block. */ 00836 if (finally_may_fallthru) 00837 { 00838 tree save_eptr, save_filt; 00839 00840 save_eptr = create_tmp_var (ptr_type_node, "save_eptr"); 00841 save_filt = create_tmp_var (integer_type_node, "save_filt"); 00842 00843 i = tsi_start (finally); 00844 x = build0 (EXC_PTR_EXPR, ptr_type_node); 00845 x = build2 (MODIFY_EXPR, void_type_node, save_eptr, x); 00846 tsi_link_before (&i, x, TSI_CONTINUE_LINKING); 00847 00848 x = build0 (FILTER_EXPR, integer_type_node); 00849 x = build2 (MODIFY_EXPR, void_type_node, save_filt, x); 00850 tsi_link_before (&i, x, TSI_CONTINUE_LINKING); 00851 00852 i = tsi_last (finally); 00853 x = build0 (EXC_PTR_EXPR, ptr_type_node); 00854 x = build2 (MODIFY_EXPR, void_type_node, x, save_eptr); 00855 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 00856 00857 x = build0 (FILTER_EXPR, integer_type_node); 00858 x = build2 (MODIFY_EXPR, void_type_node, x, save_filt); 00859 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 00860 00861 x = build_resx (get_eh_region_number (tf->region)); 00862 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 00863 } 00864 00865 /* Wrap the block with protect_cleanup_actions as the action. */ 00866 if (protect_cleanup_actions) 00867 { 00868 x = build2 (EH_FILTER_EXPR, void_type_node, NULL, NULL); 00869 append_to_statement_list (protect_cleanup_actions, &EH_FILTER_FAILURE (x)); 00870 EH_FILTER_MUST_NOT_THROW (x) = 1; 00871 finally = build2 (TRY_CATCH_EXPR, void_type_node, finally, x); 00872 lower_eh_filter (outer_state, &finally); 00873 } 00874 else 00875 lower_eh_constructs_1 (outer_state, &finally); 00876 00877 /* Hook this up to the end of the existing try block. If we 00878 previously fell through the end, we'll have to branch around. 00879 This means adding a new goto, and adding it to the queue. */ 00880 00881 i = tsi_last (TREE_OPERAND (*tf->top_p, 0)); 00882 00883 if (tf->may_fallthru) 00884 { 00885 x = lower_try_finally_fallthru_label (tf); 00886 x = build1 (GOTO_EXPR, void_type_node, x); 00887 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 00888 00889 if (this_state) 00890 maybe_record_in_goto_queue (this_state, x); 00891 00892 tf->may_fallthru = false; 00893 } 00894 00895 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); 00896 tsi_link_after (&i, x, TSI_CONTINUE_LINKING); 00897 tsi_link_after (&i, finally, TSI_CONTINUE_LINKING); 00898 00899 /* Having now been handled, EH isn't to be considered with 00900 the rest of the outgoing edges. */ 00901 tf->may_throw = false; 00902 }
|
|
|
Definition at line 178 of file tree-eh.c. References lookup_stmt_eh_region_fn(). Referenced by bsi_replace(), execute_fixup_cfg(), expand_call_inline(), make_eh_edges(), maybe_clean_or_replace_eh_stmt(), move_block_to_fn(), tree_can_throw_external(), tree_can_throw_internal(), verify_eh_edges(), and verify_stmt(). 00179 { 00180 /* We can get called from initialized data when -fnon-call-exceptions 00181 is on; prevent crash. */ 00182 if (!cfun) 00183 return -1; 00184 return lookup_stmt_eh_region_fn (cfun, t); 00185 }
|
|
|
Definition at line 163 of file tree-eh.c. Referenced by copy_bb(), find_outermost_region_in_block(), and lookup_stmt_eh_region(). 00164 { 00165 struct throw_stmt_node *p, n; 00166 00167 if (!get_eh_throw_stmt_table (ifun)) 00168 return -2; 00169 00170 n.stmt = t; 00171 p = (struct throw_stmt_node *) htab_find (get_eh_throw_stmt_table (ifun), 00172 &n); 00173 00174 return (p ? p->region_nr : -1); 00175 }
|
|
|
A subroutine of lower_eh_constructs_1. Lower a TRY_CATCH_EXPR with a list of CATCH_EXPR nodes to a sequence of labels and blocks, plus the exception region trees that record all the magic. Definition at line 1434 of file tree-eh.c. References append_to_statement_list(), block_may_fallthru(), build1, CATCH_BODY, CATCH_TYPES, create_artificial_label(), leh_state::cur_region, lower_eh_constructs_1(), leh_state::prev_try, leh_state::tf, TREE_OPERAND, tsi_delink(), tsi_end_p(), tsi_link_before(), TSI_SAME_STMT, tsi_start(), tsi_stmt(), and void_type_node. Referenced by lower_eh_constructs_1(). 01435 { 01436 struct eh_region *try_region; 01437 struct leh_state this_state; 01438 tree_stmt_iterator i; 01439 tree out_label; 01440 01441 try_region = gen_eh_region_try (state->cur_region); 01442 this_state.cur_region = try_region; 01443 this_state.prev_try = try_region; 01444 this_state.tf = state->tf; 01445 01446 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); 01447 01448 if (!get_eh_region_may_contain_throw (try_region)) 01449 { 01450 *tp = TREE_OPERAND (*tp, 0); 01451 return; 01452 } 01453 01454 out_label = NULL; 01455 for (i = tsi_start (TREE_OPERAND (*tp, 1)); !tsi_end_p (i); ) 01456 { 01457 struct eh_region *catch_region; 01458 tree catch, x, eh_label; 01459 01460 catch = tsi_stmt (i); 01461 catch_region = gen_eh_region_catch (try_region, CATCH_TYPES (catch)); 01462 01463 this_state.cur_region = catch_region; 01464 this_state.prev_try = state->prev_try; 01465 lower_eh_constructs_1 (&this_state, &CATCH_BODY (catch)); 01466 01467 eh_label = create_artificial_label (); 01468 set_eh_region_tree_label (catch_region, eh_label); 01469 01470 x = build1 (LABEL_EXPR, void_type_node, eh_label); 01471 tsi_link_before (&i, x, TSI_SAME_STMT); 01472 01473 if (block_may_fallthru (CATCH_BODY (catch))) 01474 { 01475 if (!out_label) 01476 out_label = create_artificial_label (); 01477 01478 x = build1 (GOTO_EXPR, void_type_node, out_label); 01479 append_to_statement_list (x, &CATCH_BODY (catch)); 01480 } 01481 01482 tsi_link_before (&i, CATCH_BODY (catch), TSI_SAME_STMT); 01483 tsi_delink (&i); 01484 } 01485 01486 frob_into_branch_around (tp, NULL, out_label); 01487 }
|
|
|
Implement a cleanup expression. This is similar to try-finally, except that we only execute the cleanup block for exception edges. Definition at line 1530 of file tree-eh.c. References append_to_statement_list(), block_may_fallthru(), build1, create_artificial_label(), leh_state::cur_region, frob_into_branch_around(), honor_protect_cleanup_actions(), lower_eh_constructs_1(), leh_state::prev_try, TREE_OPERAND, and void_type_node. Referenced by lower_eh_constructs_1(). 01531 { 01532 struct leh_state this_state; 01533 struct eh_region *this_region; 01534 struct leh_tf_state fake_tf; 01535 01536 /* If not using eh, then exception-only cleanups are no-ops. */ 01537 if (!flag_exceptions) 01538 { 01539 *tp = TREE_OPERAND (*tp, 0); 01540 lower_eh_constructs_1 (state, tp); 01541 return; 01542 } 01543 01544 this_region = gen_eh_region_cleanup (state->cur_region, state->prev_try); 01545 this_state = *state; 01546 this_state.cur_region = this_region; 01547 01548 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); 01549 01550 if (!get_eh_region_may_contain_throw (this_region)) 01551 { 01552 *tp = TREE_OPERAND (*tp, 0); 01553 return; 01554 } 01555 01556 /* Build enough of a try-finally state so that we can reuse 01557 honor_protect_cleanup_actions. */ 01558 memset (&fake_tf, 0, sizeof (fake_tf)); 01559 fake_tf.top_p = tp; 01560 fake_tf.outer = state; 01561 fake_tf.region = this_region; 01562 fake_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0)); 01563 fake_tf.may_throw = true; 01564 01565 fake_tf.eh_label = create_artificial_label (); 01566 set_eh_region_tree_label (this_region, fake_tf.eh_label); 01567 01568 honor_protect_cleanup_actions (state, NULL, &fake_tf); 01569 01570 if (fake_tf.may_throw) 01571 { 01572 /* In this case honor_protect_cleanup_actions had nothing to do, 01573 and we should process this normally. */ 01574 lower_eh_constructs_1 (state, &TREE_OPERAND (*tp, 1)); 01575 frob_into_branch_around (tp, fake_tf.eh_label, fake_tf.fallthru_label); 01576 } 01577 else 01578 { 01579 /* In this case honor_protect_cleanup_actions did nearly all of 01580 the work. All we have left is to append the fallthru_label. */ 01581 01582 *tp = TREE_OPERAND (*tp, 0); 01583 if (fake_tf.fallthru_label) 01584 { 01585 tree x = build1 (LABEL_EXPR, void_type_node, fake_tf.fallthru_label); 01586 append_to_statement_list (x, tp); 01587 } 01588 } 01589 }
|
|
|
Definition at line 1675 of file tree-eh.c. References collect_finally_tree(), current_function_decl, DECL_SAVED_TREE, finally_tree, lower_eh_constructs_1(), struct_ptr_eq(), and struct_ptr_hash(). 01676 { 01677 struct leh_state null_state; 01678 tree *tp = &DECL_SAVED_TREE (current_function_decl); 01679 01680 finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free); 01681 01682 collect_finally_tree (*tp, NULL); 01683 01684 memset (&null_state, 0, sizeof (null_state)); 01685 lower_eh_constructs_1 (&null_state, tp); 01686 01687 htab_delete (finally_tree); 01688 01689 collect_eh_region_array (); 01690 return 0; 01691 }
|
|
|
Main loop for lowering eh constructs. Definition at line 1594 of file tree-eh.c. References COND_EXPR_ELSE, COND_EXPR_THEN, lower_catch(), lower_cleanup(), lower_eh_constructs_1(), lower_eh_filter(), lower_try_finally(), maybe_record_in_goto_queue(), record_stmt_eh_region(), TREE_CODE, tree_could_throw_p(), TREE_OPERAND, tsi_delink(), tsi_end_p(), tsi_link_before(), tsi_next(), TSI_SAME_STMT, tsi_start(), tsi_stmt(), tsi_stmt_ptr(), and verify_norecord_switch_expr. 01595 { 01596 tree_stmt_iterator i; 01597 tree t = *tp; 01598 01599 switch (TREE_CODE (t)) 01600 { 01601 case COND_EXPR: 01602 lower_eh_constructs_1 (state, &COND_EXPR_THEN (t)); 01603 lower_eh_constructs_1 (state, &COND_EXPR_ELSE (t)); 01604 break; 01605 01606 case CALL_EXPR: 01607 /* Look for things that can throw exceptions, and record them. */ 01608 if (state->cur_region && tree_could_throw_p (t)) 01609 { 01610 record_stmt_eh_region (state->cur_region, t); 01611 note_eh_region_may_contain_throw (state->cur_region); 01612 } 01613 break; 01614 01615 case MODIFY_EXPR: 01616 /* Look for things that can throw exceptions, and record them. */ 01617 if (state->cur_region && tree_could_throw_p (t)) 01618 { 01619 record_stmt_eh_region (state->cur_region, t); 01620 note_eh_region_may_contain_throw (state->cur_region); 01621 } 01622 break; 01623 01624 case GOTO_EXPR: 01625 case RETURN_EXPR: 01626 maybe_record_in_goto_queue (state, t); 01627 break; 01628 case SWITCH_EXPR: 01629 verify_norecord_switch_expr (state, t); 01630 break; 01631 01632 case TRY_FINALLY_EXPR: 01633 lower_try_finally (state, tp); 01634 break; 01635 01636 case TRY_CATCH_EXPR: 01637 i = tsi_start (TREE_OPERAND (t, 1)); 01638 switch (TREE_CODE (tsi_stmt (i))) 01639 { 01640 case CATCH_EXPR: 01641 lower_catch (state, tp); 01642 break; 01643 case EH_FILTER_EXPR: 01644 lower_eh_filter (state, tp); 01645 break; 01646 default: 01647 lower_cleanup (state, tp); 01648 break; 01649 } 01650 break; 01651 01652 case STATEMENT_LIST: 01653 for (i = tsi_start (t); !tsi_end_p (i); ) 01654 { 01655 lower_eh_constructs_1 (state, tsi_stmt_ptr (i)); 01656 t = tsi_stmt (i); 01657 if (TREE_CODE (t) == STATEMENT_LIST) 01658 { 01659 tsi_link_before (&i, t, TSI_SAME_STMT); 01660 tsi_delink (&i); 01661 } 01662 else 01663 tsi_next (&i); 01664 } 01665 break; 01666 01667 default: 01668 /* A type, a decl, or some kind of statement that we're not 01669 interested in. Don't walk them. */ 01670 break; 01671 } 01672 }
|
|
||||||||||||
|
|
A subroutine of lower_eh_constructs_1. Lower a TRY_CATCH_EXPR with a EH_FILTER_EXPR to a sequence of labels and blocks, plus the exception region trees that record all the magic. Definition at line 1494 of file tree-eh.c. References create_artificial_label(), leh_state::cur_region, EH_FILTER_FAILURE, EH_FILTER_MUST_NOT_THROW, EH_FILTER_TYPES, expr_first(), frob_into_branch_around(), lower_eh_constructs_1(), and TREE_OPERAND. 01495 { 01496 struct leh_state this_state; 01497 struct eh_region *this_region; 01498 tree inner = expr_first (TREE_OPERAND (*tp, 1)); 01499 tree eh_label; 01500 01501 if (EH_FILTER_MUST_NOT_THROW (inner)) 01502 this_region = gen_eh_region_must_not_throw (state->cur_region); 01503 else 01504 this_region = gen_eh_region_allowed (state->cur_region, 01505 EH_FILTER_TYPES (inner)); 01506 this_state = *state; 01507 this_state.cur_region = this_region; 01508 01509 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); 01510 01511 if (!get_eh_region_may_contain_throw (this_region)) 01512 { 01513 *tp = TREE_OPERAND (*tp, 0); 01514 return; 01515 } 01516 01517 lower_eh_constructs_1 (state, &EH_FILTER_FAILURE (inner)); 01518 TREE_OPERAND (*tp, 1) = EH_FILTER_FAILURE (inner); 01519 01520 eh_label = create_artificial_label (); 01521 set_eh_region_tree_label (this_region, eh_label); 01522 01523 frob_into_branch_around (tp, eh_label, NULL); 01524 }
|
|
||||||||||||
|
Referenced by honor_protect_cleanup_actions(), and lower_eh_constructs_1(). |
|
|
A subroutine of lower_eh_constructs_1. Lower a TRY_FINALLY_EXPR nodes to a sequence of labels and blocks, plus the exception region trees that record all the magic. This is complicated by the need to arrange for the FINALLY block to be executed on all exits. Definition at line 1346 of file tree-eh.c. References append_to_statement_list(), block_may_fallthru(), build1, create_artificial_label(), leh_state::cur_region, decide_copy_try_finally(), goto_queue_cmp(), honor_protect_cleanup_actions(), lower_eh_constructs_1(), lower_try_finally_copy(), lower_try_finally_nofallthru(), lower_try_finally_onedest(), lower_try_finally_switch(), leh_state::prev_try, leh_state::tf, TREE_OPERAND, using_eh_for_cleanups_p, and void_type_node. Referenced by lower_eh_constructs_1(). 01347 { 01348 struct leh_tf_state this_tf; 01349 struct leh_state this_state; 01350 int ndests; 01351 01352 /* Process the try block. */ 01353 01354 memset (&this_tf, 0, sizeof (this_tf)); 01355 this_tf.try_finally_expr = *tp; 01356 this_tf.top_p = tp; 01357 this_tf.outer = state; 01358 if (using_eh_for_cleanups_p) 01359 this_tf.region 01360 = gen_eh_region_cleanup (state->cur_region, state->prev_try); 01361 else 01362 this_tf.region = NULL; 01363 01364 this_state.cur_region = this_tf.region; 01365 this_state.prev_try = state->prev_try; 01366 this_state.tf = &this_tf; 01367 01368 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); 01369 01370 /* Determine if the try block is escaped through the bottom. */ 01371 this_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0)); 01372 01373 /* Determine if any exceptions are possible within the try block. */ 01374 if (using_eh_for_cleanups_p) 01375 this_tf.may_throw = get_eh_region_may_contain_throw (this_tf.region); 01376 if (this_tf.may_throw) 01377 { 01378 this_tf.eh_label = create_artificial_label (); 01379 set_eh_region_tree_label (this_tf.region, this_tf.eh_label); 01380 honor_protect_cleanup_actions (state, &this_state, &this_tf); 01381 } 01382 01383 /* Sort the goto queue for efficient searching later. */ 01384 if (this_tf.goto_queue_active > 1) 01385 qsort (this_tf.goto_queue, this_tf.goto_queue_active, 01386 sizeof (struct goto_queue_node), goto_queue_cmp); 01387 01388 /* Determine how many edges (still) reach the finally block. Or rather, 01389 how many destinations are reached by the finally block. Use this to 01390 determine how we process the finally block itself. */ 01391 01392 ndests = VEC_length (tree, this_tf.dest_array); 01393 ndests += this_tf.may_fallthru; 01394 ndests += this_tf.may_return; 01395 ndests += this_tf.may_throw; 01396 01397 /* If the FINALLY block is not reachable, dike it out. */ 01398 if (ndests == 0) 01399 *tp = TREE_OPERAND (*tp, 0); 01400 01401 /* If the finally block doesn't fall through, then any destination 01402 we might try to impose there isn't reached either. There may be 01403 some minor amount of cleanup and redirection still needed. */ 01404 else if (!block_may_fallthru (TREE_OPERAND (*tp, 1))) 01405 lower_try_finally_nofallthru (state, &this_tf); 01406 01407 /* We can easily special-case redirection to a single destination. */ 01408 else if (ndests == 1) 01409 lower_try_finally_onedest (state, &this_tf); 01410 01411 else if (decide_copy_try_finally (ndests, TREE_OPERAND (*tp, 1))) 01412 lower_try_finally_copy (state, &this_tf); 01413 else 01414 lower_try_finally_switch (state, &this_tf); 01415 01416 /* If someone requested we add a label at the end of the transformed 01417 block, do so. */ 01418 if (this_tf.fallthru_label) 01419 { 01420 tree x = build1 (LABEL_EXPR, void_type_node, this_tf.fallthru_label); 01421 append_to_statement_list (x, tp); 01422 } 01423 01424 VEC_free (tree, heap, this_tf.dest_array); 01425 if (this_tf.goto_queue) 01426 free (this_tf.goto_queue); 01427 }
|
|
|