tree-eh.c File Reference

#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.

Data Structures

struct  finally_tree_node
struct  leh_state
struct  leh_tf_state
struct  leh_tf_state::goto_queue_node

Defines

#define verify_norecord_switch_expr(state, switch_expr)

Functions

void using_eh_for_cleanups ()
static int struct_ptr_eq ()
static hashval_t struct_ptr_hash ()
static void record_stmt_eh_region ()
void add_stmt_to_eh_region_fn ()
void add_stmt_to_eh_region ()
bool remove_stmt_from_eh_region_fn ()
bool remove_stmt_from_eh_region ()
int lookup_stmt_eh_region_fn ()
int lookup_stmt_eh_region ()
static void record_in_finally_tree ()
static void collect_finally_tree ()
static bool outside_finally_tree ()
static void lower_eh_filter (struct leh_state *, tree *)
static void lower_eh_constructs_1 (struct leh_state *, tree *)
static int goto_queue_cmp ()
static tree find_goto_replacement ()
static void replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf, tree_stmt_iterator *tsi)
static void replace_goto_queue_stmt_list (tree, struct leh_tf_state *)
static void replace_goto_queue_1 ()
static void replace_goto_queue_stmt_list ()
static void replace_goto_queue ()
static void maybe_record_in_goto_queue ()
static void do_return_redirection (struct goto_queue_node *q, tree finlab, tree mod, tree *return_value_p)
static void do_goto_redirection ()
static void frob_into_branch_around ()
static tree lower_try_finally_dup_block ()
static tree lower_try_finally_fallthru_label ()
static void honor_protect_cleanup_actions (struct leh_state *outer_state, struct leh_state *this_state, struct leh_tf_state *tf)
static void lower_try_finally_nofallthru ()
static void lower_try_finally_onedest ()
static void lower_try_finally_copy ()
static void lower_try_finally_switch ()
static bool decide_copy_try_finally ()
static void lower_try_finally ()
static void lower_catch ()
static void lower_eh_filter ()
static void lower_cleanup ()
static void lower_eh_constructs_1 ()
static unsigned int lower_eh_constructs ()
static void make_eh_edge ()
void make_eh_edges ()
static void mark_eh_edge ()
bool verify_eh_edges ()
bool tree_could_trap_p ()
bool tree_could_throw_p ()
bool tree_can_throw_internal ()
bool tree_can_throw_external ()
bool maybe_clean_or_replace_eh_stmt ()

Variables

static int using_eh_for_cleanups_p = 0
static htab_t finally_tree
tree_opt_pass pass_lower_eh
static bool mark_eh_edge_found_error


Define Documentation

#define verify_norecord_switch_expr state,
switch_expr   ) 
 

Definition at line 578 of file tree-eh.c.

Referenced by lower_eh_constructs_1().


Function Documentation

void add_stmt_to_eh_region  ) 
 

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 }

void add_stmt_to_eh_region_fn  ) 
 

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 }

static void collect_finally_tree  )  [static]
 

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 }

static bool decide_copy_try_finally  )  [static]
 

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 }

static void do_goto_redirection  )  [static]
 

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 }

static void do_return_redirection struct goto_queue_node *  q,
tree  finlab,
tree  mod,
tree *  return_value_p
[static]
 

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 }

static tree find_goto_replacement  )  [static]
 

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 }

static void frob_into_branch_around  )  [static]
 

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 }

static int goto_queue_cmp  )  [static]
 

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 }

static void honor_protect_cleanup_actions struct leh_state outer_state,
struct leh_state this_state,
struct leh_tf_state tf
[static]
 

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 }

int lookup_stmt_eh_region  ) 
 

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 }

int lookup_stmt_eh_region_fn  ) 
 

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 }

static void lower_catch  )  [static]
 

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 }

static void lower_cleanup  )  [static]
 

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 }

static unsigned int lower_eh_constructs  )  [static]
 

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 }

static void lower_eh_constructs_1  )  [static]
 

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 }

static void lower_eh_constructs_1 struct leh_state ,
tree * 
[static]
 

Referenced by honor_protect_cleanup_actions(), lower_catch(), lower_cleanup(), lower_eh_constructs(), lower_eh_constructs_1(), lower_eh_filter(), lower_try_finally(), lower_try_finally_copy(), lower_try_finally_nofallthru(), lower_try_finally_onedest(), and lower_try_finally_switch().

static void lower_eh_filter  )  [static]
 

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 }

static void lower_eh_filter struct leh_state ,
tree * 
[static]
 

Referenced by honor_protect_cleanup_actions(), and lower_eh_constructs_1().

static void lower_try_finally  )  [static]
 

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 }