OSDN Git Service

PR c/10175
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index 472e84d..7cdb187 100644 (file)
@@ -49,6 +49,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -100,20 +102,18 @@ tree (*lang_eh_runtime_type) PARAMS ((tree));
 
 /* A hash table of label to region number.  */
 
-struct ehl_map_entry
+struct ehl_map_entry GTY(())
 {
   rtx label;
   struct eh_region *region;
 };
 
-static htab_t exception_handler_label_map;
-
 static int call_site_base;
-static unsigned int sjlj_funcdef_number;
-static htab_t type_to_runtime_map;
+static GTY ((param_is (union tree_node)))
+  htab_t type_to_runtime_map;
 
 /* Describe the SjLj_Function_Context structure.  */
-static tree sjlj_fc_type_node;
+static GTY(()) tree sjlj_fc_type_node;
 static int sjlj_fc_call_site_ofs;
 static int sjlj_fc_data_ofs;
 static int sjlj_fc_personality_ofs;
@@ -121,7 +121,7 @@ static int sjlj_fc_lsda_ofs;
 static int sjlj_fc_jbuf_ofs;
 \f
 /* Describes one exception region.  */
-struct eh_region
+struct eh_region GTY(())
 {
   /* The immediately surrounding region.  */
   struct eh_region *outer;
@@ -151,50 +151,51 @@ struct eh_region
   } type;
 
   /* Holds the action to perform based on the preceding type.  */
-  union {
+  union eh_region_u {
     /* A list of catch blocks, a surrounding try block,
        and the label for continuing after a catch.  */
-    struct {
+    struct eh_region_u_try {
       struct eh_region *catch;
       struct eh_region *last_catch;
       struct eh_region *prev_try;
       rtx continue_label;
-    } try;
+    } GTY ((tag ("ERT_TRY"))) try;
 
     /* The list through the catch handlers, the list of type objects
        matched, and the list of associated filters.  */
-    struct {
+    struct eh_region_u_catch {
       struct eh_region *next_catch;
       struct eh_region *prev_catch;
       tree type_list;
       tree filter_list;
-    } catch;
+    } GTY ((tag ("ERT_CATCH"))) catch;
 
     /* A tree_list of allowed types.  */
-    struct {
+    struct eh_region_u_allowed {
       tree type_list;
       int filter;
-    } allowed;
+    } GTY ((tag ("ERT_ALLOWED_EXCEPTIONS"))) allowed;
 
     /* The type given by a call to "throw foo();", or discovered
        for a throw.  */
-    struct {
+    struct eh_region_u_throw {
       tree type;
-    } throw;
+    } GTY ((tag ("ERT_THROW"))) throw;
 
     /* Retain the cleanup expression even after expansion so that
        we can match up fixup regions.  */
-    struct {
+    struct eh_region_u_cleanup {
       tree exp;
-    } cleanup;
+      struct eh_region *prev_try;
+    } GTY ((tag ("ERT_CLEANUP"))) cleanup;
 
     /* The real region (by expression and by pointer) that fixup code
        should live in.  */
-    struct {
+    struct eh_region_u_fixup {
       tree cleanup_exp;
       struct eh_region *real_region;
-    } fixup;
-  } u;
+    } GTY ((tag ("ERT_FIXUP"))) fixup;
+  } GTY ((desc ("%0.type"))) u;
 
   /* Entry point for this region's handler before landing pads are built.  */
   rtx label;
@@ -210,14 +211,20 @@ struct eh_region
   rtx resume;
 };
 
+struct call_site_record GTY(())
+{
+  rtx landing_pad;
+  int action;
+};
+
 /* Used to save exception status for each function.  */
-struct eh_status
+struct eh_status GTY(())
 {
   /* The tree of all regions for this function.  */
   struct eh_region *region_tree;
 
   /* The same information as an indexable array.  */
-  struct eh_region **region_array;
+  struct eh_region ** GTY ((length ("%h.last_region_number"))) region_array;
 
   /* The most recently open region.  */
   struct eh_region *cur_region;
@@ -235,11 +242,10 @@ struct eh_status
   varray_type ehspec_data;
   varray_type action_record_data;
 
-  struct call_site_record
-  {
-    rtx landing_pad;
-    int action;
-  } *call_site_data;
+  htab_t GTY ((param_is (struct ehl_map_entry))) exception_handler_label_map;
+
+  struct call_site_record * GTY ((length ("%h.call_site_data_used"))) 
+    call_site_data;
   int call_site_data_used;
   int call_site_data_size;
 
@@ -252,17 +258,9 @@ struct eh_status
 };
 
 \f
-static void mark_eh_region                     PARAMS ((struct eh_region *));
-static int mark_ehl_map_entry                  PARAMS ((PTR *, PTR));
-static void mark_ehl_map                       PARAMS ((void *));
-
-static void free_region                                PARAMS ((struct eh_region *));
-
 static int t2r_eq                              PARAMS ((const PTR,
                                                         const PTR));
 static hashval_t t2r_hash                      PARAMS ((const PTR));
-static int t2r_mark_1                          PARAMS ((PTR *, PTR));
-static void t2r_mark                           PARAMS ((PTR));
 static void add_type_for_runtime               PARAMS ((tree));
 static tree lookup_type_for_runtime            PARAMS ((tree));
 
@@ -310,7 +308,6 @@ static void sjlj_build_landing_pads         PARAMS ((void));
 static hashval_t ehl_hash                      PARAMS ((const PTR));
 static int ehl_eq                              PARAMS ((const PTR,
                                                         const PTR));
-static void ehl_free                           PARAMS ((PTR));
 static void add_ehl_entry                      PARAMS ((rtx,
                                                         struct eh_region *));
 static void remove_exception_handler_label     PARAMS ((rtx));
@@ -359,7 +356,7 @@ static void sjlj_output_call_site_table             PARAMS ((void));
 
 \f
 /* Routine to see if exception handling is turned on.
-   DO_WARN is non-zero if we want to inform the user that exception
+   DO_WARN is nonzero if we want to inform the user that exception
    handling is turned off.
 
    This is used to ensure that -fexceptions has been specified if the
@@ -386,13 +383,10 @@ doing_eh (do_warn)
 void
 init_eh ()
 {
-  ggc_add_root (&exception_handler_label_map, 1, 1, mark_ehl_map);
-
   if (! flag_exceptions)
     return;
 
-  type_to_runtime_map = htab_create (31, t2r_hash, t2r_eq, NULL);
-  ggc_add_root (&type_to_runtime_map, 1, sizeof (htab_t), t2r_mark);
+  type_to_runtime_map = htab_create_ggc (31, t2r_hash, t2r_eq, NULL);
 
   /* Create the SjLj_Function_Context structure.  This should match
      the definition in unwind-sjlj.c.  */
@@ -401,7 +395,6 @@ init_eh ()
       tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
 
       sjlj_fc_type_node = (*lang_hooks.types.make_type) (RECORD_TYPE);
-      ggc_add_tree_root (&sjlj_fc_type_node, 1);
 
       f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"),
                           build_pointer_type (sjlj_fc_type_node));
@@ -484,209 +477,9 @@ init_eh ()
 void
 init_eh_for_function ()
 {
-  cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status));
-}
-
-/* Mark EH for GC.  */
-
-static void
-mark_eh_region (region)
-     struct eh_region *region;
-{
-  if (! region)
-    return;
-
-  switch (region->type)
-    {
-    case ERT_UNKNOWN:
-      /* This can happen if a nested function is inside the body of a region
-        and we do a GC as part of processing it.  */
-      break;
-    case ERT_CLEANUP:
-      ggc_mark_tree (region->u.cleanup.exp);
-      break;
-    case ERT_TRY:
-      ggc_mark_rtx (region->u.try.continue_label);
-      break;
-    case ERT_CATCH:
-      ggc_mark_tree (region->u.catch.type_list);
-      ggc_mark_tree (region->u.catch.filter_list);
-      break;
-    case ERT_ALLOWED_EXCEPTIONS:
-      ggc_mark_tree (region->u.allowed.type_list);
-      break;
-    case ERT_MUST_NOT_THROW:
-      break;
-    case ERT_THROW:
-      ggc_mark_tree (region->u.throw.type);
-      break;
-    case ERT_FIXUP:
-      ggc_mark_tree (region->u.fixup.cleanup_exp);
-      break;
-    default:
-      abort ();
-    }
-
-  ggc_mark_rtx (region->label);
-  ggc_mark_rtx (region->resume);
-  ggc_mark_rtx (region->landing_pad);
-  ggc_mark_rtx (region->post_landing_pad);
-}
-
-static int
-mark_ehl_map_entry (pentry, data)
-     PTR *pentry;
-     PTR data ATTRIBUTE_UNUSED;
-{
-  struct ehl_map_entry *entry = *(struct ehl_map_entry **) pentry;
-  ggc_mark_rtx (entry->label);
-  return 1;
-}
-
-static void
-mark_ehl_map (pp)
-    void *pp;
-{
-  htab_t map = *(htab_t *) pp;
-  if (map)
-    htab_traverse (map, mark_ehl_map_entry, NULL);
-}
-
-void
-mark_eh_status (eh)
-     struct eh_status *eh;
-{
-  int i;
-
-  if (eh == 0)
-    return;
-
-  /* If we've called collect_eh_region_array, use it.  Otherwise walk
-     the tree non-recursively.  */
-  if (eh->region_array)
-    {
-      for (i = eh->last_region_number; i > 0; --i)
-       {
-         struct eh_region *r = eh->region_array[i];
-         if (r && r->region_number == i)
-           mark_eh_region (r);
-       }
-    }
-  else if (eh->region_tree)
-    {
-      struct eh_region *r = eh->region_tree;
-      while (1)
-       {
-         mark_eh_region (r);
-         if (r->inner)
-           r = r->inner;
-         else if (r->next_peer)
-           r = r->next_peer;
-         else
-           {
-             do {
-               r = r->outer;
-               if (r == NULL)
-                 goto tree_done;
-             } while (r->next_peer == NULL);
-             r = r->next_peer;
-           }
-       }
-    tree_done:;
-    }
-
-  ggc_mark_rtx (eh->filter);
-  ggc_mark_rtx (eh->exc_ptr);
-  ggc_mark_tree_varray (eh->ttype_data);
-
-  if (eh->call_site_data)
-    {
-      for (i = eh->call_site_data_used - 1; i >= 0; --i)
-       ggc_mark_rtx (eh->call_site_data[i].landing_pad);
-    }
-
-  ggc_mark_rtx (eh->ehr_stackadj);
-  ggc_mark_rtx (eh->ehr_handler);
-  ggc_mark_rtx (eh->ehr_label);
-
-  ggc_mark_rtx (eh->sjlj_fc);
-  ggc_mark_rtx (eh->sjlj_exit_after);
-}
-
-static inline void
-free_region (r)
-     struct eh_region *r;
-{
-  /* Note that the aka bitmap is freed by regset_release_memory.  But if
-     we ever replace with a non-obstack implementation, this would be
-     the place to do it.  */
-  free (r);
-}
-
-void
-free_eh_status (f)
-     struct function *f;
-{
-  struct eh_status *eh = f->eh;
-
-  if (eh->region_array)
-    {
-      int i;
-      for (i = eh->last_region_number; i > 0; --i)
-       {
-         struct eh_region *r = eh->region_array[i];
-         /* Mind we don't free a region struct more than once.  */
-         if (r && r->region_number == i)
-           free_region (r);
-       }
-      free (eh->region_array);
-    }
-  else if (eh->region_tree)
-    {
-      struct eh_region *next, *r = eh->region_tree;
-      while (1)
-       {
-         if (r->inner)
-           r = r->inner;
-         else if (r->next_peer)
-           {
-             next = r->next_peer;
-             free_region (r);
-             r = next;
-           }
-         else
-           {
-             do {
-               next = r->outer;
-               free_region (r);
-               r = next;
-               if (r == NULL)
-                 goto tree_done;
-             } while (r->next_peer == NULL);
-             next = r->next_peer;
-             free_region (r);
-             r = next;
-           }
-       }
-    tree_done:;
-    }
-
-  VARRAY_FREE (eh->ttype_data);
-  VARRAY_FREE (eh->ehspec_data);
-  VARRAY_FREE (eh->action_record_data);
-  if (eh->call_site_data)
-    free (eh->call_site_data);
-
-  free (eh);
-  f->eh = NULL;
-
-  if (exception_handler_label_map)
-    {
-      htab_delete (exception_handler_label_map);
-      exception_handler_label_map = NULL;
-    }
+  cfun->eh = (struct eh_status *) 
+    ggc_alloc_cleared (sizeof (struct eh_status));
 }
-
 \f
 /* Start an exception handling region.  All instructions emitted
    after this point are considered to be part of the region until
@@ -703,7 +496,7 @@ expand_eh_region_start ()
     return;
 
   /* Insert a new blank region as a leaf in the tree.  */
-  new_region = (struct eh_region *) xcalloc (1, sizeof (*new_region));
+  new_region = (struct eh_region *) ggc_alloc_cleared (sizeof (*new_region));
   cur_region = cfun->eh->cur_region;
   new_region->outer = cur_region;
   if (cur_region)
@@ -761,6 +554,7 @@ expand_eh_region_end_cleanup (handler)
   region->type = ERT_CLEANUP;
   region->label = gen_label_rtx ();
   region->u.cleanup.exp = handler;
+  region->u.cleanup.prev_try = cfun->eh->try_region;
 
   around_label = gen_label_rtx ();
   emit_jump (around_label);
@@ -779,7 +573,7 @@ expand_eh_region_end_cleanup (handler)
 
   /* In case this cleanup involves an inline destructor with a try block in
      it, we need to save the EH return data registers around it.  */
-  data_save[0] = gen_reg_rtx (Pmode);
+  data_save[0] = gen_reg_rtx (ptr_mode);
   emit_move_insn (data_save[0], get_exception_pointer (cfun));
   data_save[1] = gen_reg_rtx (word_mode);
   emit_move_insn (data_save[1], get_exception_filter (cfun));
@@ -851,11 +645,11 @@ expand_start_catch (type_or_list)
       tree type_node;
 
       if (TREE_CODE (type_or_list) != TREE_LIST)
-        type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
+       type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
 
       type_node = type_list;
       for (; type_node; type_node = TREE_CHAIN (type_node))
-        add_type_for_runtime (TREE_VALUE (type_node));
+       add_type_for_runtime (TREE_VALUE (type_node));
     }
 
   expand_eh_region_start ();
@@ -882,12 +676,12 @@ expand_start_catch (type_or_list)
 void
 expand_end_catch ()
 {
-  struct eh_region *try_region, *catch_region;
+  struct eh_region *try_region;
 
   if (! doing_eh (0))
     return;
 
-  catch_region = expand_eh_region_end ();
+  expand_eh_region_end ();
   try_region = cfun->eh->try_region;
 
   emit_jump (try_region->u.try.continue_label);
@@ -1039,7 +833,7 @@ get_exception_pointer (fun)
   rtx exc_ptr = fun->eh->exc_ptr;
   if (fun == cfun && ! exc_ptr)
     {
-      exc_ptr = gen_reg_rtx (Pmode);
+      exc_ptr = gen_reg_rtx (ptr_mode);
       fun->eh->exc_ptr = exc_ptr;
     }
   return exc_ptr;
@@ -1076,7 +870,8 @@ collect_eh_region_array ()
   if (! i)
     return;
 
-  array = xcalloc (cfun->eh->last_region_number + 1, sizeof (*array));
+  array = ggc_alloc_cleared ((cfun->eh->last_region_number + 1)
+                            * sizeof (*array));
   cfun->eh->region_array = array;
 
   while (1)
@@ -1165,7 +960,7 @@ remove_fixup_regions ()
 
       /* Allow GC to maybe free some memory.  */
       if (fixup->type == ERT_CLEANUP)
-        fixup->u.cleanup.exp = NULL_TREE;
+       fixup->u.cleanup.exp = NULL_TREE;
 
       if (fixup->type != ERT_FIXUP)
        continue;
@@ -1221,23 +1016,23 @@ remove_unreachable_regions (insns)
        continue;
 
       if (r->resume)
-        {
+       {
          if (uid_region_num[INSN_UID (r->resume)])
            abort ();
          uid_region_num[INSN_UID (r->resume)] = i;
-        }
+       }
       if (r->label)
-        {
+       {
          if (uid_region_num[INSN_UID (r->label)])
            abort ();
          uid_region_num[INSN_UID (r->label)] = i;
-        }
+       }
       if (r->type == ERT_TRY && r->u.try.continue_label)
-        {
+       {
          if (uid_region_num[INSN_UID (r->u.try.continue_label)])
            abort ();
          uid_region_num[INSN_UID (r->u.try.continue_label)] = i;
-        }
+       }
     }
 
   for (insn = insns; insn; insn = NEXT_INSN (insn))
@@ -1316,21 +1111,40 @@ convert_from_eh_region_ranges_1 (pinsns, orig_sp, cur)
        }
       else if (INSN_P (insn))
        {
-         if (cur > 0
-             && ! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
-             /* Calls can always potentially throw exceptions, unless
-                they have a REG_EH_REGION note with a value of 0 or less.
-                Which should be the only possible kind so far.  */
-             && (GET_CODE (insn) == CALL_INSN
-                 /* If we wanted exceptions for non-call insns, then
-                    any may_trap_p instruction could throw.  */
-                 || (flag_non_call_exceptions
-                     && GET_CODE (PATTERN (insn)) != CLOBBER
-                     && GET_CODE (PATTERN (insn)) != USE
-                     && may_trap_p (PATTERN (insn)))))
+         rtx note;
+         switch (cur)
            {
-             REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur),
+           default:
+             /* An existing region note may be present to suppress
+                exception handling.  Anything with a note value of -1
+                cannot throw an exception of any kind.  A note value
+                of 0 means that "normal" exceptions are suppressed,
+                but not necessarily "forced unwind" exceptions.  */
+             note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+             if (note)
+               {
+                 if (flag_forced_unwind_exceptions
+                     && INTVAL (XEXP (note, 0)) >= 0)
+                   XEXP (note, 0) = GEN_INT (cur);
+                 break;
+               }
+
+             /* Calls can always potentially throw exceptions; if we wanted
+                exceptions for non-call insns, then any may_trap_p
+                instruction can throw.  */
+             if (GET_CODE (insn) != CALL_INSN
+                 && (!flag_non_call_exceptions
+                     || GET_CODE (PATTERN (insn)) == CLOBBER
+                     || GET_CODE (PATTERN (insn)) == USE
+                     || !may_trap_p (PATTERN (insn))))
+               break;
+
+             REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION,
+                                                 GEN_INT (cur),
                                                  REG_NOTES (insn));
+
+           case 0:
+             break;
            }
 
          if (GET_CODE (insn) == CALL_INSN
@@ -1377,12 +1191,12 @@ add_ehl_entry (label, region)
 
   LABEL_PRESERVE_P (label) = 1;
 
-  entry = (struct ehl_map_entry *) xmalloc (sizeof (*entry));
+  entry = (struct ehl_map_entry *) ggc_alloc (sizeof (*entry));
   entry->label = label;
   entry->region = region;
 
   slot = (struct ehl_map_entry **)
-    htab_find_slot (exception_handler_label_map, entry, INSERT);
+    htab_find_slot (cfun->eh->exception_handler_label_map, entry, INSERT);
 
   /* Before landing pad creation, each exception handler has its own
      label.  After landing pad creation, the exception handlers may
@@ -1394,29 +1208,20 @@ add_ehl_entry (label, region)
   *slot = entry;
 }
 
-static void
-ehl_free (pentry)
-     PTR pentry;
-{
-  struct ehl_map_entry *entry = (struct ehl_map_entry *)pentry;
-  LABEL_PRESERVE_P (entry->label) = 0;
-  free (entry);
-}
-
 void
 find_exception_handler_labels ()
 {
   int i;
 
-  if (exception_handler_label_map)
-    htab_empty (exception_handler_label_map);
+  if (cfun->eh->exception_handler_label_map)
+    htab_empty (cfun->eh->exception_handler_label_map);
   else
     {
       /* ??? The expansion factor here (3/2) must be greater than the htab
         occupancy factor (4/3) to avoid unnecessary resizing.  */
-      exception_handler_label_map
-        = htab_create (cfun->eh->last_region_number * 3 / 2,
-                      ehl_hash, ehl_eq, ehl_free);
+      cfun->eh->exception_handler_label_map
+        = htab_create_ggc (cfun->eh->last_region_number * 3 / 2,
+                          ehl_hash, ehl_eq, NULL);
     }
 
   if (cfun->eh->region_tree == NULL)
@@ -1468,7 +1273,7 @@ duplicate_eh_region_1 (o, map)
      struct inline_remap *map;
 {
   struct eh_region *n
-    = (struct eh_region *) xcalloc (1, sizeof (struct eh_region));
+    = (struct eh_region *) ggc_alloc_cleared (sizeof (struct eh_region));
 
   n->region_number = o->region_number + cfun->eh->last_region_number;
   n->type = o->type;
@@ -1529,9 +1334,9 @@ duplicate_eh_region_2 (o, n_array)
 
     case ERT_CATCH:
       if (o->u.catch.next_catch)
-        n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
+       n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
       if (o->u.catch.prev_catch)
-        n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
+       n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
       break;
 
     default:
@@ -1633,23 +1438,6 @@ t2r_hash (pentry)
   return TYPE_HASH (TREE_PURPOSE (entry));
 }
 
-static int
-t2r_mark_1 (slot, data)
-     PTR *slot;
-     PTR data ATTRIBUTE_UNUSED;
-{
-  tree contents = (tree) *slot;
-  ggc_mark_tree (contents);
-  return 1;
-}
-
-static void
-t2r_mark (addr)
-     PTR addr;
-{
-  htab_traverse (*(htab_t *)addr, t2r_mark_1, NULL);
-}
-
 static void
 add_type_for_runtime (type)
      tree type;
@@ -1681,7 +1469,7 @@ lookup_type_for_runtime (type)
 \f
 /* Represent an entry in @TTypes for either catch actions
    or exception filter actions.  */
-struct ttypes_filter
+struct ttypes_filter GTY(())
 {
   tree t;
   int filter;
@@ -1914,9 +1702,15 @@ build_post_landing_pads ()
            struct eh_region *c;
            for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
              {
-               /* ??? _Unwind_ForcedUnwind wants no match here.  */
                if (c->u.catch.type_list == NULL)
-                 emit_jump (c->label);
+                 {
+                   if (flag_forced_unwind_exceptions)
+                     emit_cmp_and_jump_insns
+                       (cfun->eh->filter, const0_rtx, GT, NULL_RTX,
+                        word_mode, 0, c->label);
+                   else
+                     emit_jump (c->label);
+                 }
                else
                  {
                    /* Need for one cmp/jump per type caught. Each type
@@ -1949,7 +1743,7 @@ build_post_landing_pads ()
          seq = get_insns ();
          end_sequence ();
 
-         emit_insns_before (seq, region->u.try.catch->label);
+         emit_insn_before (seq, region->u.try.catch->label);
          break;
 
        case ERT_ALLOWED_EXCEPTIONS:
@@ -1973,14 +1767,39 @@ build_post_landing_pads ()
          seq = get_insns ();
          end_sequence ();
 
-         emit_insns_before (seq, region->label);
+         emit_insn_before (seq, region->label);
          break;
 
        case ERT_CLEANUP:
-       case ERT_MUST_NOT_THROW:
          region->post_landing_pad = region->label;
          break;
 
+       case ERT_MUST_NOT_THROW:
+         /* See maybe_remove_eh_handler about removing region->label.  */
+         if (flag_forced_unwind_exceptions && region->label)
+           {
+             region->post_landing_pad = gen_label_rtx ();
+
+             start_sequence ();
+
+             emit_label (region->post_landing_pad);
+             emit_cmp_and_jump_insns (cfun->eh->filter, const0_rtx, GT,
+                                      NULL_RTX, word_mode, 0, region->label);
+
+             region->resume
+               = emit_jump_insn (gen_rtx_RESX (VOIDmode,
+                                               region->region_number));
+             emit_barrier ();
+
+             seq = get_insns ();
+             end_sequence ();
+
+             emit_insn_before (seq, region->label);
+           }
+         else
+           region->post_landing_pad = region->label;
+         break;
+
        case ERT_CATCH:
        case ERT_THROW:
          /* Nothing to do.  */
@@ -2026,11 +1845,11 @@ connect_post_landing_pads ()
        emit_jump (outer->post_landing_pad);
       else
        emit_library_call (unwind_resume_libfunc, LCT_THROW,
-                          VOIDmode, 1, cfun->eh->exc_ptr, Pmode);
+                          VOIDmode, 1, cfun->eh->exc_ptr, ptr_mode);
 
       seq = get_insns ();
       end_sequence ();
-      emit_insns_before (seq, region->resume);
+      emit_insn_before (seq, region->resume);
       delete_insn (region->resume);
     }
 }
@@ -2099,14 +1918,14 @@ dw2_build_landing_pads ()
        }
 
       emit_move_insn (cfun->eh->exc_ptr,
-                     gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (0)));
+                     gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
       emit_move_insn (cfun->eh->filter,
                      gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1)));
 
       seq = get_insns ();
       end_sequence ();
 
-      emit_insns_before (seq, region->post_landing_pad);
+      emit_insn_before (seq, region->post_landing_pad);
     }
 }
 
@@ -2158,6 +1977,21 @@ sjlj_find_directly_reachable_regions (lp_info)
          if (rc != RNL_NOT_CAUGHT)
            break;
        }
+
+      /* Forced unwind exceptions aren't blocked.  */
+      if (flag_forced_unwind_exceptions && rc == RNL_BLOCKED)
+       {
+          struct eh_region *r;
+         for (r = region->outer; r ; r = r->outer)
+           if (r->type == ERT_CLEANUP)
+             {
+               rc = RNL_MAYBE_CAUGHT;
+               if (! region->label)
+                 region = r;
+               break;
+             }
+       }
+
       if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT)
        {
          lp_info[region->region_number].directly_reachable = 1;
@@ -2281,7 +2115,7 @@ sjlj_mark_call_sites (lp_info)
       /* Don't separate a call from it's argument loads.  */
       before = insn;
       if (GET_CODE (insn) == CALL_INSN)
-         before = find_first_parameter_load (insn, NULL_RTX);
+       before = find_first_parameter_load (insn, NULL_RTX);
 
       start_sequence ();
       mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
@@ -2290,7 +2124,7 @@ sjlj_mark_call_sites (lp_info)
       p = get_insns ();
       end_sequence ();
 
-      emit_insns_before (p, before);
+      emit_insn_before (p, before);
       last_call_site = this_call_site;
     }
 }
@@ -2318,7 +2152,7 @@ sjlj_emit_function_enter (dispatch_label)
   if (cfun->uses_eh_lsda)
     {
       char buf[20];
-      ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", sjlj_funcdef_number);
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", current_function_funcdef_no);
       emit_move_insn (mem, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)));
     }
   else
@@ -2357,7 +2191,7 @@ sjlj_emit_function_enter (dispatch_label)
     if (GET_CODE (fn_begin) == NOTE
        && NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
       break;
-  emit_insns_after (seq, fn_begin);
+  emit_insn_after (seq, fn_begin);
 }
 
 /* Call back from expand_function_end to know where we should put
@@ -2387,7 +2221,7 @@ sjlj_emit_function_exit ()
      post-dominates all can_throw_internal instructions.  This is
      the last possible moment.  */
 
-  emit_insns_after (seq, cfun->eh->sjlj_exit_after);
+  emit_insn_after (seq, cfun->eh->sjlj_exit_after);
 }
 
 static void
@@ -2451,8 +2285,8 @@ sjlj_emit_dispatch_table (dispatch_label, lp_info)
   seq = get_insns ();
   end_sequence ();
 
-  emit_insns_before (seq, (cfun->eh->region_array[first_reachable]
-                          ->post_landing_pad));
+  emit_insn_before (seq, (cfun->eh->region_array[first_reachable]
+                         ->post_landing_pad));
 }
 
 static void
@@ -2499,8 +2333,6 @@ finish_eh_generation ()
      connect many of the handlers, and then type information will not
      be effective.  Still, this is a win over previous implementations.  */
 
-  rebuild_jump_labels (get_insns ());
-  find_basic_blocks (get_insns (), max_reg_num (), 0);
   cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
 
   /* These registers are used by the landing pads.  Make sure they
@@ -2561,16 +2393,16 @@ remove_exception_handler_label (label)
 
   /* If exception_handler_label_map was not built yet,
      there is nothing to do.  */
-  if (exception_handler_label_map == NULL)
+  if (cfun->eh->exception_handler_label_map == NULL)
     return;
 
   tmp.label = label;
   slot = (struct ehl_map_entry **)
-    htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT);
+    htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT);
   if (! slot)
     abort ();
 
-  htab_clear_slot (exception_handler_label_map, (void **) slot);
+  htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot);
 }
 
 /* Splice REGION from the region tree etc.  */
@@ -2600,7 +2432,7 @@ remove_eh_handler (region)
   if (outer)
     {
       if (!outer->aka)
-        outer->aka = BITMAP_XMALLOC ();
+        outer->aka = BITMAP_GGC_ALLOC ();
       if (region->aka)
        bitmap_a_or_b (outer->aka, outer->aka, region->aka);
       bitmap_set_bit (outer->aka, region->region_number);
@@ -2659,8 +2491,6 @@ remove_eh_handler (region)
            remove_eh_handler (try);
        }
     }
-
-  free_region (region);
 }
 
 /* LABEL heads a basic block that is about to be deleted.  If this
@@ -2683,7 +2513,7 @@ maybe_remove_eh_handler (label)
 
   tmp.label = label;
   slot = (struct ehl_map_entry **)
-    htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT);
+    htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT);
   if (! slot)
     return;
   region = (*slot)->region;
@@ -2696,7 +2526,7 @@ maybe_remove_eh_handler (label)
      are no more contained calls, which we don't see here.  */
   if (region->type == ERT_MUST_NOT_THROW)
     {
-      htab_clear_slot (exception_handler_label_map, (void **) slot);
+      htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot);
       region->label = NULL_RTX;
     }
   else
@@ -2710,7 +2540,7 @@ void
 for_each_eh_label (callback)
      void (*callback) PARAMS ((rtx));
 {
-  htab_traverse (exception_handler_label_map, for_each_eh_label_1,
+  htab_traverse (cfun->eh->exception_handler_label_map, for_each_eh_label_1,
                 (void *)callback);
 }
 
@@ -2729,7 +2559,7 @@ for_each_eh_label_1 (pentry, data)
 /* This section describes CFG exception edges for flow.  */
 
 /* For communicating between calls to reachable_next_level.  */
-struct reachable_info
+struct reachable_info GTY(())
 {
   tree types_caught;
   tree types_allowed;
@@ -2816,8 +2646,6 @@ reachable_next_level (region, type_thrown, info)
        for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
          {
            /* A catch-all handler ends the search.  */
-           /* ??? _Unwind_ForcedUnwind will want outer cleanups
-              to be run as well.  */
            if (c->u.catch.type_list == NULL)
              {
                add_reachable_handler (info, region, c);
@@ -2930,7 +2758,7 @@ reachable_next_level (region, type_thrown, info)
       return RNL_MAYBE_CAUGHT;
 
     case ERT_CATCH:
-      /* Catch regions are handled by their controling try region.  */
+      /* Catch regions are handled by their controlling try region.  */
       return RNL_NOT_CAUGHT;
 
     case ERT_MUST_NOT_THROW:
@@ -2941,7 +2769,7 @@ reachable_next_level (region, type_thrown, info)
       if (info && info->handlers)
        {
          add_reachable_handler (info, region, region);
-          return RNL_CAUGHT;
+         return RNL_CAUGHT;
        }
       else
        return RNL_BLOCKED;
@@ -2999,10 +2827,34 @@ reachable_handlers (insn)
       region = region->outer;
     }
 
-  for (; region; region = region->outer)
-    if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
-      break;
+  while (region)
+    {
+      if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
+       {
+         /* Forced unwind exceptions are neither BLOCKED nor CAUGHT.
+            Make sure the cleanup regions are reachable.  */
+         if (flag_forced_unwind_exceptions)
+           {
+             while ((region = region->outer) != NULL)
+               if (region->type == ERT_CLEANUP)
+                 {
+                   add_reachable_handler (&info, region, region);
+                   break;
+                 }
+           }
+         break;
+       }
 
+      /* If we have processed one cleanup, there is no point in
+        processing any more of them.  Each cleanup will have an edge
+        to the next outer cleanup region, so the flow graph will be
+        accurate.  */
+      if (region->type == ERT_CLEANUP)
+       region = region->u.cleanup.prev_try;
+      else
+       region = region->outer;
+    }
+    
   return info.handlers;
 }
 
@@ -3061,7 +2913,7 @@ can_throw_internal (insn)
       if (how == RNL_BLOCKED)
        return false;
       if (how != RNL_NOT_CAUGHT)
-        return true;
+       return true;
     }
 
   return false;
@@ -3114,6 +2966,10 @@ can_throw_external (insn)
   if (INTVAL (XEXP (note, 0)) <= 0)
     return false;
 
+  /* Forced unwind excptions are not catchable.  */
+  if (flag_forced_unwind_exceptions && GET_CODE (insn) == CALL_INSN)
+    return true;
+
   region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
 
   type_thrown = NULL_TREE;
@@ -3132,25 +2988,50 @@ can_throw_external (insn)
   return true;
 }
 
-/* True if nothing in this function can throw outside this function.  */
+/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls.  */
 
-bool
-nothrow_function_p ()
+void
+set_nothrow_function_flags ()
 {
   rtx insn;
+  
+  current_function_nothrow = 1;
 
-  if (! flag_exceptions)
-    return true;
+  /* Assume cfun->all_throwers_are_sibcalls until we encounter
+     something that can throw an exception.  We specifically exempt
+     CALL_INSNs that are SIBLING_CALL_P, as these are really jumps,
+     and can't throw.  Most CALL_INSNs are not SIBLING_CALL_P, so this
+     is optimistic.  */
 
+  cfun->all_throwers_are_sibcalls = 1;
+
+  if (! flag_exceptions)
+    return;
+  
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     if (can_throw_external (insn))
-      return false;
+      {
+       current_function_nothrow = 0;
+
+       if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
+         {
+           cfun->all_throwers_are_sibcalls = 0;
+           return;
+         }
+      }
+
   for (insn = current_function_epilogue_delay_list; insn;
        insn = XEXP (insn, 1))
-    if (can_throw_external (XEXP (insn, 0)))
-      return false;
+    if (can_throw_external (insn))
+      {
+       current_function_nothrow = 0;
 
-  return true;
+       if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
+         {
+           cfun->all_throwers_are_sibcalls = 0;
+           return;
+         }
+      }
 }
 
 \f
@@ -3207,6 +3088,16 @@ expand_builtin_extract_return_addr (addr_tree)
 {
   rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
 
+  if (GET_MODE (addr) != Pmode
+      && GET_MODE (addr) != VOIDmode)
+    {
+#ifdef POINTERS_EXTEND_UNSIGNED
+      addr = convert_memory_address (Pmode, addr);
+#else
+      addr = convert_to_mode (Pmode, addr, 0);
+#endif
+    }
+
   /* First mask out any unwanted bits.  */
 #ifdef MASK_RETURN_ADDR
   expand_and (Pmode, addr, MASK_RETURN_ADDR, addr);
@@ -3433,12 +3324,26 @@ collect_one_action_chain (ar_hash, region)
        {
          if (c->u.catch.type_list == NULL)
            {
+             int filter;
+
+             /* Forced exceptions run cleanups, always.  Record them if
+                they exist.  */
+             next = 0;
+             if (flag_forced_unwind_exceptions)
+               {
+                 struct eh_region *r;
+                 for (r = c->outer; r ; r = r->outer)
+                   if (r->type == ERT_CLEANUP)
+                     {
+                       next = add_action_record (ar_hash, 0, 0);
+                       break;
+                     }
+               }
+
              /* Retrieve the filter from the head of the filter list
                 where we have stored it (see assign_filter_values).  */
-             int filter
-               = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
-
-             next = add_action_record (ar_hash, filter, 0);
+             filter = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
+             next = add_action_record (ar_hash, filter, next);
            }
          else
            {
@@ -3483,6 +3388,13 @@ collect_one_action_chain (ar_hash, region)
         requires no call-site entry.  Note that this differs from
         the no handler or cleanup case in that we do require an lsda
         to be generated.  Return a magic -2 value to record this.  */
+      if (flag_forced_unwind_exceptions)
+       {
+         struct eh_region *r;
+         for (r = region->outer; r ; r = r->outer)
+           if (r->type == ERT_CLEANUP)
+             return 0;
+       }
       return -2;
 
     case ERT_CATCH:
@@ -3509,7 +3421,7 @@ add_call_site (landing_pad, action)
     {
       size = (size ? size * 2 : 64);
       data = (struct call_site_record *)
-       xrealloc (data, sizeof (*data) * size);
+       ggc_realloc (data, sizeof (*data) * size);
       cfun->eh->call_site_data = data;
       cfun->eh->call_site_data_size = size;
     }
@@ -3793,6 +3705,33 @@ sjlj_output_call_site_table ()
   call_site_base += n;
 }
 
+/* Tell assembler to switch to the section for the exception handling
+   table.  */
+
+void
+default_exception_section ()
+{
+  if (targetm.have_named_sections)
+    {
+      int flags;
+#ifdef HAVE_LD_RO_RW_SECTION_MIXING
+      int tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
+
+      flags = (! flag_pic
+              || ((tt_format & 0x70) != DW_EH_PE_absptr
+                  && (tt_format & 0x70) != DW_EH_PE_aligned))
+             ? 0 : SECTION_WRITE;
+#else
+      flags = SECTION_WRITE;
+#endif
+      named_section_flags (".gcc_except_table", flags);
+    }
+  else if (flag_pic)
+    data_section ();
+  else
+    readonly_data_section ();
+}
+
 void
 output_function_exception_table ()
 {
@@ -3805,17 +3744,12 @@ output_function_exception_table ()
   int call_site_len;
 #endif
   int have_tt_data;
-  int funcdef_number;
   int tt_format_size = 0;
 
   /* Not all functions need anything.  */
   if (! cfun->uses_eh_lsda)
     return;
 
-  funcdef_number = (USING_SJLJ_EXCEPTIONS
-                   ? sjlj_funcdef_number
-                   : current_funcdef_number);
-
 #ifdef IA64_UNWIND_INFO
   fputs ("\t.personality\t", asm_out_file);
   output_addr_const (asm_out_file, eh_personality_libfunc);
@@ -3836,14 +3770,16 @@ output_function_exception_table ()
     {
       tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
 #ifdef HAVE_AS_LEB128
-      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number);
+      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT",
+                                  current_function_funcdef_no);
 #endif
       tt_format_size = size_of_encoded_value (tt_format);
 
       assemble_align (tt_format_size * BITS_PER_UNIT);
     }
 
-  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number);
+  (*targetm.asm_out.internal_label) (asm_out_file, "LLSDA",
+                            current_function_funcdef_no);
 
   /* The LSDA header.  */
 
@@ -3875,7 +3811,7 @@ output_function_exception_table ()
 #ifdef HAVE_AS_LEB128
       char ttype_after_disp_label[32];
       ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD",
-                                  funcdef_number);
+                                  current_function_funcdef_no);
       dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
                                    "@TType base offset");
       ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
@@ -3921,9 +3857,9 @@ output_function_exception_table ()
 
 #ifdef HAVE_AS_LEB128
   ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
-                              funcdef_number);
+                              current_function_funcdef_no);
   ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE",
-                              funcdef_number);
+                              current_function_funcdef_no);
   dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
                                "Call-site table length");
   ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
@@ -3965,7 +3901,7 @@ output_function_exception_table ()
        assemble_integer (value, tt_format_size,
                          tt_format_size * BITS_PER_UNIT, 1);
       else
-        dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL);
+       dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL);
     }
 
 #ifdef HAVE_AS_LEB128
@@ -3980,7 +3916,6 @@ output_function_exception_table ()
                         (i ? NULL : "Exception specification table"));
 
   function_section (current_function_decl);
-
-  if (USING_SJLJ_EXCEPTIONS)
-    sjlj_funcdef_number += 1;
 }
+
+#include "gt-except.h"